Caching 写入mmio寄存器时如何避免缓存?
我正在virtualbox中编写自定义操作系统,在从IOAPIC mmio寄存器成功写入和读取时遇到问题。i、 它似乎忽略了索引寄存器写入。在使用IOAPIC基址加载Caching 写入mmio寄存器时如何避免缓存?,caching,assembly,x86-64,osdev,apic,Caching,Assembly,X86 64,Osdev,Apic,我正在virtualbox中编写自定义操作系统,在从IOAPIC mmio寄存器成功写入和读取时遇到问题。i、 它似乎忽略了索引寄存器写入。在使用IOAPIC基址加载R8后(根据ACPI枚举确定为0xFEC00000),我使用以下例程进行读/写: ; ----------------------------------------------------------------------------- ; IN : RAX = ioapic address, EBX = index regi
R8
后(根据ACPI枚举确定为0xFEC00000),我使用以下例程进行读/写:
; -----------------------------------------------------------------------------
; IN : RAX = ioapic address, EBX = index register
; OUT: ECX = return value
ioapic_read:
mov [r8], ebx
mov ecx, [r8 + 0x10]
ret
; -----------------------------------------------------------------------------
; IN : RAX = ioapic address, EBX = index register, ECX = value
; OUT: -
ioapic_write:
mov [r8], ebx
mov [r8 + 0x10], ecx
ret
但ioapic_读取将始终返回(通过ioapic_写入)写入的最后一个值,而与所使用的索引无关。我有使用0x9B的身份分页设置,我认为应该禁用缓存
我尝试在每个mov
s之后使用pause
。没有帮助。在mov
s之间尝试了mfence
s。没有帮助
我已确认0xFEC00000
地址已成功进行身份映射
看起来仍有一些缓存在进行。我错过了什么
编辑
我发现这不是缓存问题,而是一个非常奇怪的问题——至少对我无知的大脑来说是如此。我的身份分页,按需工作,这样页面错误将在表中生成正确的物理页面
这似乎是可行的,但在IOAPIC mmio寄存器的情况下,我需要在尝试使用0xFEC000000地址之前,通过对其进行虚拟读取或写入来导致页面错误。更奇怪的是,我需要做这个假人,在之前阅读足够的指令,否则它就不能工作。e、 g
这管用
mov eax, [os_IOAPICAddress]
mov dword[rax], 0
mov r8, rax
.
.
.
call ioapic_read
。。。这可不行
mov eax, [os_IOAPICAddress]
mov r8, rax
mov dword[rax], 0
.
.
.
call ioapic_read
我怀疑存在管道/串行化问题,但我真的很想了解为什么在MMIO寄存器中使用地址之前需要将地址分页到表中,以及为什么需要提前这么做。在后一种情况下,如何修复它,使其序列化,这样我就不必担心它了
我的身份分页例程:
pageFault_identity_0x0E:
pop r8
push rsi rdi rax rcx rdx r9
test r8, 1
jnz exception_gate_14
mov rdx, cr2 ; faulting address
shr rdx, 39
and rdx, 0x1FF ; get 9 bit index
mov rdi, cr3
lea rsi, [rdi + rdx*8]
mov rdi, [rsi]
test rdi, 1
jnz @f
call set_new_page_table
@@:
shr rdi, 12 ; get rid of flags
shl rdi, 12
mov rdx, cr2
shr rdx, 30 ; get 9 bit index
and rdx, 0x1FF
lea rsi, [rdi + rdx*8]
mov rdi, [rsi]
test rdi, 1
jnz @f
call set_new_page_table
@@:
shr rdi, 12 ; get rid of flags
shl rdi, 12
mov rdx, cr2
shr rdx, 21
mov rax, rdx
and rdx, 0x1FF ; get 9 bit index
lea rsi, [rdi + rdx*8]
shl rax, 21
or rax, 0x83
mov [rsi], rax
shr rax, 21
shl rax, 21
pop r9 rdx rcx rax rdi rsi
iretq
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;
; IN: rsi = address of blank entry
; OUT: rdi = base address of new table, changes rax & rcx
;
set_new_page_table: ; make table, get it, zero it, insert base into previous table
movzx rdi, [page_table_count]
shl rdi, 12
add rdi, NEW_PAGE_TABLES
CLEAR_BLOCK rdi, 0x200 ; clears 4096 bytes in rdi, returns rdi + 4096
sub rdi, 0x1000
lea rax, [rdi + 0x3] ; table base address
mov [rsi], rax
inc [page_table_count]
ret
给定原始代码,看起来好像您正在正确设置页面目录条目位,以将MMIO区域标记为不可缓存。我确信还有其他问题。在随后的编辑中,您向我们显示了页面错误处理程序
pageFault\u identity\u 0x0
:
pageFault_identity_0x0E:
pop r8
push rsi rdi rax rcx rdx r9
当处理器将控制转移到此页面错误异常处理程序时,它将在堆栈顶部传递一个错误代码作为参数。问题是,您用错误号替换了R8的内容,而没有保存并恢复寄存器
您必须修改异常处理程序以保留R8,将内容从错误号所在的适当堆栈偏移量移动到R8中。请记住,确保错误号不再位于IRETQ之前的堆栈顶部
很可能您得到的奇怪行为与R8在从页面错误返回时未正确恢复直接相关
一个可行的解决方案是:
pageFault_identity_0x0E:
push rsi
push rdi
push rax
push rcx
push rdx
push r9
push r8
mov r8, [rsp+7*8] ; Error Code is at offset RSP+7*8 after all the pushes
; Do exception handling work here
pop r8
pop r9
pop rdx
pop rcx
pop rax
pop rdi
pop rsi
add rsp, 8 ; Remove the error code
iretq
Michael解决了这个问题,但为了完整起见,我将发布我的最终实现
pageFault_identity_0x0E:
test qword[rsp], 1
jnz exception_gate_14
add rsp, 8
push rsi rdi rax rcx rdx
mov rdx, cr2 ; faulting address
.
.
.
pop rdx rcx rax rdi rsi
iretq
编辑:已编辑以删除
xchg
这些函数是从C调用的ioapic\u read
和ioapic\u write
吗?不,整个过程都在汇编中如果在写入寄存器之前读取它们,会得到合理的值吗?大多数IOAPIC寄存器都是完全可写的,您是否尝试过编写像IOAPICVER或IOAPICARB这样的RO寄存器?我知道您可能有bug,或者使用了大于4kb的寄存器。你的问题没有说它只是说0x9b没有真正的上下文。看看你的页面错误处理程序。我弄错了,但你是在破坏R8的内容而不恢复它吗?您将错误代码弹出到R8中,但这意味着R8的先前值已被破坏。当您的错误处理程序终止R8时,R8很可能不再具有原始值。我浪费了2天的时间试图找到它。我彻底地调试了那个分页例程,我确信它不是罪魁祸首。但不知怎的,我错过了流行音乐R8。这是我的一个负担:)没问题,我真的很高兴你添加了页面错误处理程序代码。我怀疑这就是问题所在。很高兴现在对你有用。内核开发和调试可能是一项棘手的工作。您可能只是需要一组新的眼睛来观察它。我避免使用带有内存操作数的XCHG,主要是因为它将导致隐式锁,从而导致相应缓存线的独占所有权和性能损失。不过,带有两个寄存器的XCHG没有这个问题。《英特尔优化指南》有这样的建议:“尽量减少在内存位置上使用xchg指令”欢呼。我不知道。我已经修好了。