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
Ces fonctions 'ioapic_read' et' ioapic_write' sont-elles appelées depuis _C_? –
Non, le tout est dans l'assembly – poby
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