Я пишу пользовательскую ОС в виртуальном боксе, и у меня возникают проблемы с записью и чтением из регистров IOAPIC mmio. т. е. кажется, что запись индексного регистра игнорируется. После загрузки R8
с базовым адресом IOAPIC (определенным из перечисления 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_read всегда будет возвращать последнее записанное значение (с помощью ioapic_write) независимо от используемого индекса. У меня есть настройка пейджинга для использования 0x9B, что, я думаю, должно отключить кеширование.
Я пытался использовать pause
после каждого из mov
. Не помогло. Пробовал mfence
s между mov
s. Не помогло.
Я подтвердил, что адрес 0xFEC00000
успешно сопоставлен.
Похоже, кэширование все еще происходит. Что мне не хватает?
РЕДАКТИРОВАТЬ
Я обнаружил, что это не проблема кэширования, а что-то очень странное - по крайней мере, для моего невежественного мозга. Моя подкачка удостоверений работает по запросу, так что ошибка страницы создает правильную физическую страницу в таблицах.
Кажется, это работает, но в случае регистров IOAPIC mmio мне нужно вызвать ошибку страницы, выполнив фиктивное чтение или запись по адресу 0xFEC00000, прежде чем пытаться его использовать. Еще более странно то, что мне нужно сделать этот манекен, предварительно прочитав достаточно инструкций, иначе он не сработает. например
Это работает!
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
ioapic_read
иioapic_write
вызываются из C? - person Michael Petch   schedule 03.10.2016r8
имеет то значение, которое, по вашему мнению, имеет значение? Вы случайно не прошли через отладчик? Я заметил в коде, который вы не разместили здесь, что у вас есть инструкцияmov r8, [IOAPICAddress]
. Как вы определилиIOAPICAddress
? - person Michael Petch   schedule 03.10.2016sfence
. - person Michael Petch   schedule 04.10.2016