2016-10-02 1 views
3

Ich schreibe eine benutzerdefinierte os in virtualbox und Probleme beim Schreiben und Lesen erfolgreich aus den IOAPIC mmio-Registern. h. es scheint das Schreiben des Indexregisters zu ignorieren. Nach dem Laden R8 mit der IOAPIC Basisadresse (bestimmt von ACPI-Enumeration 0xFEC00000 zu sein), verwende ich die folgenden Routinen zum Lesen/Schreiben:Wie vermeidet man Caching beim Schreiben in mmio Register?

; ----------------------------------------------------------------------------- 
; 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   

Aber ein ioapic_read wird den letzten Wert geschrieben (von ioapic_write) immer wieder zurückkehren und zwar unabhängig des verwendeten Indexes. Ich habe Identity-Paging-Setup, um 0x9B verwenden, die ich denke, sollte Caching deaktivieren.

Ich habe versucht, pause nach jedem der mov s. Hat nicht geholfen. Versucht mfence s zwischen mov s. Hat nicht geholfen.

Ich habe bestätigt, dass die 0xFEC00000 Adresse erfolgreich Identität zugeordnet ist.

Es sieht so aus, als ob noch etwas Caching läuft. Was vermisse ich?

EDIT

ich entdeckt habe es kein Caching Problem ist aber etwas viel Fremde - zumindest für mein unwissend Gehirn. Mein Identitäts-Paging funktioniert bei Bedarf so, dass ein Seitenfehler die richtige physische Seite in den Tabellen generiert.

Dies scheint zu funktionieren, aber im Falle der IOAPIC mmio-Register muss ich einen Seitenfehler verursachen, indem ich einen Dummy-Lese- oder -Schreibvorgang an der Adresse 0xFEC00000 vor dem Versuch, es zu verwenden, mache. Die noch seltsamere Sache ist, dass ich diesen Dummy lesen muss, bevor ich genug Anweisungen gelesen habe oder es funktioniert nicht. z.B.

Das funktioniert!

mov eax, [os_IOAPICAddress] 
mov dword[rax], 0 
mov r8, rax 
. 
. 
. 
call ioapic_read 

... dies NICHT!

mov eax, [os_IOAPICAddress] 
mov r8, rax 
mov dword[rax], 0 
. 
. 
. 
call ioapic_read 

ich vermuten, dass ein Pipelining/Serialisierung Problem, aber ich würde wirklich lieben, beide zu erfahren, warum muss ich Seite bemängeln die Adresse in den Tabellen, bevor es in einem MMIO-Register verwendet wird, und warum muss ich es tun weit genug im Voraus. Im letzteren Fall, wie man es repariert, so dass es serialisiert wird, so dass ich mich nicht darum kümmern muss.

Meine Identität Paging-Routine:

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

Werden diese Funktionen 'ioapic_read' und' ioapic_write' von _C_ aufgerufen? –

+0

Nein, die ganze Sache ist in Assembly – poby

+0

Ist der Speicherbereich nicht cachefähig markiert? http://stackoverflow.com/questions/90204/why-would-a-region-of-memory-be-marked-non-cached – stark

Antwort

7

der ursprüngliche Code Da sah es aus, als ob Sie den Seitenverzeichniseintrag Bits richtig die MMIO Region uncachable markieren wurden Einstellung. Ich war überzeugt, dass es ein anderes Problem gab. Mit Ihrer nachfolgenden bearbeiten zeigten Sie uns Ihre Seitenfehlerbehandler pageFault_identity_0x0:

pageFault_identity_0x0E: 
    pop r8 
    push rsi rdi rax rcx rdx r9 

Wenn der Prozessor überträgt die Steuerung auf dieser Seite Fehler Exception-Handler wird es einen Fehlercode auf der Oberseite des Stapels als Parameter übergeben. Das Problem ist, dass Sie den Inhalt von R8 mit der Fehlernummer ersetzen, ohne zu speichern und dann das Register wiederherzustellen.

Sie haben werden Ihre Exception-Handler ändern R8, bewegen Sie den Inhalt aus dem richtigen Stapel zu bewahren versetzt, wo die Fehlernummer in R8.Denken Sie daran, dass die Fehlernummer vor dem IRETQ nicht mehr oben auf dem Stapel liegt.

Wahrscheinlich ist das seltsame Verhalten, das Sie bekommen haben, direkt mit R8 nicht ordnungsgemäß bei der Rückkehr von einem Seitenfehler wiederhergestellt.


Eine Lösung, die funktionieren kann, ist:

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

belohnen kann. Ich habe 2 Tage meines Lebens damit verschwendet, das zu finden. Ich habe diese Paging-Routine so gründlich getestet, dass ich mir sicher war, dass es nicht der Schuldige war. Aber irgendwie habe ich den Pop R8 vermisst. Es ist eine Last aus meinem Kopf :) – poby

+1

Kein Problem, ich bin wirklich froh, dass Sie den Seitenfehler-Handler-Code hinzugefügt haben. Ich hatte den Verdacht, dass es das Problem war. Schön, dass es jetzt für dich funktioniert. Kernel-Entwicklung und Debugging können knifflige Angelegenheit sein. Du brauchst wahrscheinlich nur frische Augen, um es anzusehen. –

2

Michael es gelöst, sondern im Interesse der Vollständigkeit, werde ich meine endgültige Umsetzung posten.

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: Hat die xchg entfernen bearbeitet.

+3

Ich vermied es, XCHG mit einem Speicheroperanden zu verwenden, hauptsächlich weil es zu einer impliziten Sperre führt, die zu einem exklusiven Besitz der entsprechenden Cachezeile und einer Leistungseinbuße führt. XCHG mit zwei Registern hat dieses Problem jedoch nicht. Intel optimizations guide haben diesen Vorschlag "minimieren Sie die Verwendung von xchg Anweisungen auf Speicherplätzen" –

+0

Prost. Das wusste ich nicht. Habe es behoben. – poby

Verwandte Themen