x64: Prevent modified rdi in PageTableArchX64.zero_page()#89
Conversation
|
I didn't have time to comment on #87. But this seemed like an issue to me, and the boot is working on Q35 with it. Would like to get additional feedback. |
There was a problem hiding this comment.
@makubacki I was chatting with Wesley Wiser on this one, a couple things:
- He also pointed out that
inshould not be used here, but he said that if you doinoutthat should prevent the compiler from clobbering rdi, so the move in and out of r8 should be handled by the compiler, not needed manually. - However, as I noted in my PR, I want to eliminate this from asm at all. I believe we can find a path where it is not needed, per conversation with Wesley, so my PR was to fix the immediate issue and then do the longer term issue. I'm fine to update to this (although if we do this, let's remove the never inline on aarch64 also), but as I said I'm planning on removing this in the short term.
I also tried I understand we're dealing with temporary changes, but this still allows inlining and properly declares the registers modified. Not inlining puts it into its own stack frame where it can technically modify |
Was that just added because of the x86 issue? |
Sure, I think the idea is that the compiler, when inlining, will see the Regardless, after further conversation with the compiler folks, I am putting up a PR now to move these functions back to Rust. I am no longer concerned the compiler make optimize away the seemingly unused memory writes. So, fine for this to go in, but also I'll put up the PR soon to remove these functions.
Yes, just to keep parity. |
That's my understanding too. Because this is inlined it informs the compiler how to deal with the fact the register is being modified in a particular section of code. I just used
Sounds good. As discussed offline, we'll get this in as a fallback in case that doesn't go as planned for some reason.
In that case, I'll update to remove the never inline on it here too. |
Removed it in the latest update. |
da7d2d3 to
27086ff
Compare
Per Rust inline assembly docs (https://doc.rust-lang.org/reference/inline-assembly.html#operand-type), `in` states: - The allocated register will contain the value of <expr> at the start of the assembly code. - The allocated register must contain the same value at the end of the assembly code (except if a lateout is allocated to the same register). This code: ```rust unsafe fn zero_page(base: VirtualAddress) { let _page: u64 = base.into(); #[cfg(all(not(test), target_arch = "x86_64"))] unsafe { asm!( "cld", // Clear the direction flag so that we increment rdi with each store "rep stosq", // Repeat the store of qword in rax to [rdi] rcx times in("rcx") 0x200, // we write 512 qwords (4096 bytes) in("rdi") _page, // start at the page in("rax") 0, // store 0 options(nostack, preserves_flags) ); } } ``` Will capture the `_page` address at the start of the assembly code into `rdi`. However, it uses `rep stosq` which is going to: - Store the `rax` value in `[rdi]` (`0`) - Repat the quad word copy `rcx` times (`0x200`) - For each operation, `rdx` will be incremented by `8` (qword) - Going forward due to `cld` - Decrement `rcx` until it is zero At the end, `rdx` is now `_page` + (`rcx` * 8) = `_page` + `0x1000` I think it then makes sense, to manually restore the `rdi` value since the code is inlined. This uses `r8` with `out` to let the compiler know the register value is modified in the asembly block. Note: The `inline(never)` attribute in the aarch64 implementation is removed as well as that was mentioned as being added in response to the x64 issue as opposed to a specific aarch64 issue. Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
27086ff to
e65bd94
Compare
Description
Per Rust inline assembly docs (https://doc.rust-lang.org/reference/inline-assembly.html#operand-type),
instates:start of the assembly code.
the assembly code (except if a lateout is allocated to the same register).
This code:
Will capture the
_pageaddress at the start of the assembly codeinto
rdi. However, it usesrep stosqwhich is going to:raxvalue in[rdi](0)rcxtimes (0x200)rdxwill be incremented by8(qword)cldrcxuntil it is zeroAt the end,
rdxis now_page+ (rcx* 8) =_page+0x1000I think it then makes sense, to manually restore the
rdivaluesince the code is inlined. This uses
r8withoutto let thecompiler know the register value is modified in the assembly block.
How This Was Tested
releaseprofile image to EFI shell on QEMU Q35Integration Instructions