2016-10-02 2 views
3

J'écris un os personnalisé dans virtualbox et j'ai du mal à écrire et lire avec succès depuis les registres IOAPIC mmio. c'est-à-dire qu'il semble ignorer l'écriture du registre d'index. Après le chargement R8 avec l'adresse de base IOAPIC (déterminée à partir de l'énumération ACPIà 0xFEC00000), j'utilise les routines suivantes en lecture/écriture:comment éviter la mise en cache lors de l'écriture sur des registres 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   

Mais un ioapic_read retournera toujours la dernière valeur écrite (par ioapic_write) quel que soit de l'indice utilisé. J'ai l'installation de pagination d'identité pour employer 0x9B qui je devrais devrait désactiver la mise en cache.

J'ai essayé d'utiliser pause après chacun des mov. N'a pas aidé. Essayé mfence s entre les mov s. N'a pas aidé.

J'ai confirmé que l'adresse 0xFEC00000 est correctement mappée.

Il semble qu'il y ait encore de la mise en cache. Qu'est-ce que je rate?

EDIT

Je l'ai découvert ce n'est pas un problème de mise en cache, mais quelque chose d'un étranger beaucoup - au moins à mon cerveau ignorant. Ma pagination d'identité fonctionne à la demande de sorte qu'une erreur de page génère la page physique correcte dans les tables.

Cela semble fonctionner mais dans le cas des registres IOAPIC mmio, je dois provoquer une erreur de page en faisant une lecture fictive ou écrire à l'adresse 0xFEC00000 avant de tenter de l'utiliser. La chose encore plus étrange est que j'ai besoin de faire ce mannequin lire suffisamment d'instructions avant ou cela ne fonctionne pas. par exemple.

Cela fonctionne!

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

... ceci NE FAIT PAS!

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

Je soupçonne un pipelining/question sérialisation mais j'aimerais vraiment apprendre à la fois pourquoi je dois défaut de page l'adresse dans les tables avant de l'utiliser dans un registre MMIO, et pourquoi je dois le faire assez loin en avance. Dans ce dernier cas, comment le réparer pour qu'il soit sérialisé de telle sorte que je n'ai pas besoin de m'inquiéter à ce sujet.

Mon identité de routine d'appel:

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

Ces fonctions 'ioapic_read' et' ioapic_write' sont-elles appelées depuis _C_? –

+0

Non, le tout est dans l'assembly – poby

+0

La zone de mémoire est-elle marquée comme étant non-cacheable? http://stackoverflow.com/questions/90204/why-would-a-region-of-memory-be-marked-non-cached – stark

Répondre

7

Vu le code d'origine, il avait l'air comme si vous mettiez les bits d'entrée de répertoire de page correctement pour marquer la région MMIO uncachable. J'étais convaincu qu'il y avait un autre problème. Avec votre édition suivante, vous nous avez montré votre gestionnaire de défaut de page pageFault_identity_0x0:

pageFault_identity_0x0E: 
    pop r8 
    push rsi rdi rax rcx rdx r9 

Lorsque les transferts de processeur contrôlent à la page gestionnaire d'exceptions de défaut, il passera un code d'erreur sur le dessus de la pile en tant que paramètre. Le problème est que vous remplacez le contenu de R8 avec le numéro d'erreur sans enregistrer puis en restaurant le registre.

Vous devez modifier votre gestionnaire d'exception pour préserver R8, déplacer le contenu de la pile appropriée décalage où le numéro d'erreur est en R8.N'oubliez pas de vous assurer que le numéro d'erreur ne se trouve plus en haut de la pile avant le IRETQ.

Probablement le comportement étrange que vous avez obtenu est directement lié à R8 ne pas être correctement restauré au retour d'une erreur de page.


Une solution qui peut fonctionner est:

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

J'ai perdu 2 jours de ma vie en essayant de trouver ceci. J'ai débuggé cette routine de pagination tellement j'étais sûr que ce n'était pas le coupable. Mais de toute façon j'ai raté cette pop R8. C'est une charge de mon esprit :) – poby

+1

Pas un problème, je suis vraiment heureux que vous avez ajouté le code de gestionnaire de défaut de page. J'ai eu un soupçon que c'était le problème. Content que cela fonctionne pour vous maintenant. Le développement du noyau et le débogage peuvent être une affaire délicate. Vous avez probablement juste besoin d'un nouvel ensemble d'yeux pour le regarder. –

2

Michael a résolu le problème, mais dans l'intérêt de l'exhaustivité, je posterai ma mise en œuvre finale.

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: vous avez modifié pour supprimer le xchg.

+3

J'ai évité d'utiliser XCHG avec un opérande de mémoire principalement parce que cela entraînerait un verrou implicite qui entraînerait la propriété exclusive de la ligne de cache correspondante et une pénalité de performance. XCHG avec deux registres n'a cependant pas ce problème. Guide Intel optimisations ont cette suggestion "minimiser l'utilisation des instructions xchg sur les emplacements de mémoire" –

+0

Cheers. Je ne le savais pas. Je l'ai réparé. – poby