Я сделал подтверждение концепции загрузчика, который записывает значение куда-то в памяти, а затем устанавливает регистр базового адреса устройства xhci так, чтобы он указывал на это местоположение, чтобы ранее записанное значение было перезаписано xhci при чтении через ММИО. Тем не менее, он работает только на VirtualBox, а не в qemu, и я понятия не имею, почему.
Это код (я сделал его настолько простым, насколько это возможно, но все еще кажется каким-то большим):
PCI_CONFIG_ADDRESS equ 0xCF8
PCI_CONFIG_DATA equ 0xCFC
PCI_BAR_0_OFFSET equ 0x10
PCI_BAR_1_OFFSET equ 0x14
%macro write_pci_register 0
mov dx, PCI_CONFIG_ADDRESS
out dx, eax
mov eax, ebx
mov dx, PCI_CONFIG_DATA
out dx, eax
%endmacro
; PCI_ADDRESS:
; ; Enable Bit Reserved Bus Number Device Number Function Number Register Offset
; ; 31 30 - 24 23 - 16 15 - 11 10 - 8 7 - 0
; QEMU: 1_0000000_00000000_00010_000_00000000b --> 0x8000_1000
; VBOX: 1_0000000_00000000_00110_000_00000000b --> 0x8000_3000
PCI_DEV_ADDRESS equ 0x8000_1000
; BAR_0:
; QEMU: 1111111111111111_1100000000000100
; VBOX: 1111111111111111_0000000000000000
org 0x7C00
bits 16
mov ax, 0x0500 >> 4
mov ss, ax
mov esp, 0x7C00 - 0x0500
mov ax, 0
mov ds, ax
; Disable cache
mov eax, cr0
and eax, 1011_1111_1111_1111__1111_1111_1111_1111b
mov cr0, eax
invd
; Write anything to the MMIO address space
mov ax, 0x1000
mov es, ax
mov byte [es:0x00], 0x7D
; Set MMIO
mov eax, PCI_DEV_ADDRESS | PCI_BAR_0_OFFSET
mov ebx, 0x10000
write_pci_register
mov eax, PCI_DEV_ADDRESS | PCI_BAR_1_OFFSET
mov ebx, 0x00
write_pci_register
; Read the value back
mov ax, 0x1000
mov es, ax
mov byte al, [es:0x00]
; Print anything to screen if the value changed
cmp al, 0x7D
je end
mov ax, 0xB800
mov es, ax
mov word [es:0x00], 0x3300 | 'X'
end:
cli
hlt
jmp end
times 510-($-$$) db 0
dw 0xAA55
Этот код должен печатать что-то на экране, если значение эффективно изменилось, что происходит только с virtualbox.
Это команды, которые я использую для проверки с помощью qemu:
nasm -l kernel.lst kernel.asm ; \
qemu-system-x86_64 \
-device qemu-xhci \
-drive format=raw,file=kernel
Вот команды, которые я использую для тестирования с VBox:
VBoxManage createvm \
--name "X" \
--ostype "Other" \
--register \
--basefolder "$(pwd)/vbox" \
--uuid "e0b08add-d834-4af5-89e8-05abec11aa78" \
--default ; \
VBoxManage modifyvm "e0b08add-d834-4af5-89e8-05abec11aa78" --usbxhci on ; \
nasm -l kernel.lst kernel.asm ; \
dd if=/dev/zero of=kernel.raw bs=1024 count=2048 ; \
dd if=kernel of=kernel.raw conv=notrunc ; \
VBoxManage convertfromraw kernel.raw kernel.vdi --format VDI ; \
VBoxManage storageattach "X" \
--storagectl "IDE" \
--port 0 \
--device 0 \
--type hdd \
--medium "$(pwd)"/kernel.vdi ; \
VBoxManage startvm "X"
Адрес устройства PCI жестко задан для упрощения кода.
Версия VBox: 6.1.0 r135406
Версия Qemu: 4.1.0