2016-10-02 2 views
3

Я пишу пользовательские os в виртуальном боксе и затрудняюсь писать и читать из регистра IOAPIC mmio. т. е. он, как представляется, игнорирует запись в индексном регистре. После загрузки R8 с базовым адресом IOAPIC (определяется из ACPI перечисления быть 0xFEC00000), я использую следующие процедуры для чтения/записи:Как избежать кэширования при записи в регистры mmio?

; ----------------------------------------------------------------------------- 
; 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 успешно идентифицирован.

Похоже, что все еще происходит кеширование. Что мне не хватает?

EDIT

Я обнаружил, что это не проблема кэширования, но что-то много незнакомец - по крайней мере, на мой невежественный мозг. Мой идентификационный пейджинг работает по требованию, так что ошибка страницы приведет к созданию правильной физической страницы в таблицах.

Это похоже на работу, но в случае регистров 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 
+0

Являются ли эти функции 'ioapic_read' и' ioapic_write' вызванными из _C_? –

+0

Нет, все в сборе – poby

+0

Является ли область памяти отмеченной не кешируемой? http://stackoverflow.com/questions/90204/why-would-a-region-of-memory-be-marked-non-cached – stark

ответ

7

Учитывая исходный код он выглядел так, как будто вы устанавливали биты входа каталога страницы правильно, чтобы отметить MMIO область uncachable. Я был убежден, что есть еще одна проблема. С вашего последующего редактирования вы показали нам свою страницу обработчика ошибок pageFault_identity_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 
+0

Я потратил 2 дня на всю жизнь, пытаясь найти это. Я отлаживал эту процедуру подкачки так тщательно, что был уверен, что это не преступник. Но почему-то я пропустил этот поп R8. Это проблема с моего ума :) – poby

+1

Не проблема, я очень рад, что вы добавили код обработчика ошибок страницы. У меня было подозрение, что это проблема. Рад, что он работает для вас сейчас. Разработка ядра и отладка могут быть сложным делом. Вероятно, вам просто нужен был свежий набор глаз, чтобы посмотреть на него. –

2

Майкл решил это, но в интересах полноты, я после моего окончательного осуществления.

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 

EDIT: Редактировать, чтобы удалить xchg.

+3

Я избегал использования XCHG с операндом памяти в основном потому, что это приведет к неявной блокировке, которая приведет к исключительной собственности на соответствующую строку кэша и штраф за производительность. XCHG с двумя регистрами, хотя и не имеет этой проблемы. Руководство по оптимизации Intel имеет это предложение «свести к минимуму использование инструкций xchg в ячейках памяти» –

+0

Cheers. Я этого не знал. Исправьте это. – poby