Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
2d0db85574 | |||
df56e251e4 | |||
b215f0010f | |||
ecad19bb5e | |||
94cbcd6a1f | |||
de21059b53 | |||
7fb000f5ce | |||
fc93be3043 | |||
4a44cdea8d | |||
a0a204b43c | |||
52098ee0e9 | |||
26db917d24 | |||
eec02f141a | |||
8672e49912 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,5 +2,7 @@ nel_os_bootloader/target
|
|||||||
nel_os_kernel/target
|
nel_os_kernel/target
|
||||||
nel_os_common/target
|
nel_os_common/target
|
||||||
nel_os_bootloader/fat.img
|
nel_os_bootloader/fat.img
|
||||||
|
nel_os_bootloader/myOSimage.img
|
||||||
nel_os_bootloader/iso/
|
nel_os_bootloader/iso/
|
||||||
nel_os_bootloader/nel_os.iso
|
nel_os_bootloader/nel_os.iso
|
||||||
|
nel_os_bootloader/vmlinux
|
||||||
|
1
README.md
Normal file
1
README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|

|
BIN
nel_os_bootloader/OVMF-pure-efi.fd
Normal file
BIN
nel_os_bootloader/OVMF-pure-efi.fd
Normal file
Binary file not shown.
BIN
nel_os_bootloader/OVMF.fd
Normal file
BIN
nel_os_bootloader/OVMF.fd
Normal file
Binary file not shown.
408
nel_os_bootloader/bochs.out
Normal file
408
nel_os_bootloader/bochs.out
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
00000000000i[ ] Bochs x86 Emulator 3.0.devel
|
||||||
|
00000000000i[ ] Built from GitHub snapshot after release 3.0
|
||||||
|
00000000000i[ ] Compiled on Aug 21 2025 at 19:02:35
|
||||||
|
00000000000i[ ] System configuration
|
||||||
|
00000000000i[ ] processors: 1 (cores=1, HT threads=1)
|
||||||
|
00000000000i[ ] A20 line support: yes
|
||||||
|
00000000000i[ ] IPS is set to 4000000
|
||||||
|
00000000000i[ ] CPU configuration
|
||||||
|
00000000000i[ ] SMP support: no
|
||||||
|
00000000000i[ ] Using pre-defined CPU configuration: corei7_sandy_bridge_2600k
|
||||||
|
00000000000i[ ] Optimization configuration
|
||||||
|
00000000000i[ ] RepeatSpeedups support: no
|
||||||
|
00000000000i[ ] Fast function calls: no
|
||||||
|
00000000000i[ ] Handlers Chaining speedups: no
|
||||||
|
00000000000i[ ] Devices configuration
|
||||||
|
00000000000i[ ] PCI support: i440FX i430FX i440BX
|
||||||
|
00000000000i[ ] Networking: no
|
||||||
|
00000000000i[ ] Sound support: no
|
||||||
|
00000000000i[ ] USB support: no
|
||||||
|
00000000000i[ ] VGA extension support: vbe
|
||||||
|
00000000000i[IMG ] Disk image modules
|
||||||
|
00000000000i[IMG ] flat concat sparse dll growing undoable volatile vmware3
|
||||||
|
00000000000i[IMG ] vmware4 vbox vpc vvfat
|
||||||
|
00000000000i[MEM0 ] allocated memory at 0x7d9025bdd010. after alignment, vector=0x7d9025bde000, block_size = 128K
|
||||||
|
00000000000i[MEM0 ] 256.00MB
|
||||||
|
00000000000i[MEM0 ] mem block size = 0x00020000, blocks=2048
|
||||||
|
00000000000i[MEM0 ] rom at 0xffe00000/2097152 ('./OVMF-pure-efi.fd')
|
||||||
|
00000000000i[CPU0 ] initialized CPU model corei7_sandy_bridge_2600k
|
||||||
|
00000000000i[DEV ] will paste characters every 100 iodev timer ticks
|
||||||
|
00000000000i[PLUGIN] init_dev of 'pci' plugin device by virtual method
|
||||||
|
00000000000i[DEV ] i440FX PMC present at device 0, function 0
|
||||||
|
00000000000i[PLUGIN] init_dev of 'pci2isa' plugin device by virtual method
|
||||||
|
00000000000i[DEV ] PIIX3 PCI-to-ISA bridge present at device 1, function 0
|
||||||
|
00000000000i[PLUGIN] init_dev of 'cmos' plugin device by virtual method
|
||||||
|
00000000000i[CMOS ] Using local time for initial clock
|
||||||
|
00000000000i[CMOS ] Setting initial clock to: Fri Aug 22 15:03:30 2025 tz=utc (time0=1755875010)
|
||||||
|
00000000000i[PLUGIN] init_dev of 'dma' plugin device by virtual method
|
||||||
|
00000000000i[DMA ] channel 4 used by cascade
|
||||||
|
00000000000i[PLUGIN] init_dev of 'pic' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] init_dev of 'pit' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] init_dev of 'vga' plugin device by virtual method
|
||||||
|
00000000000i[MEM0 ] Register memory access handlers: 0x0000000a0000 - 0x0000000bffff
|
||||||
|
00000000000i[VGA ] interval=100000, mode=realtime
|
||||||
|
00000000000i[VGA ] Setting VGA update interval to 100000 (10.0 Hz)
|
||||||
|
00000000000i[VGA ] VSYNC using standard mode
|
||||||
|
00000000000i[BXVGA ] VBE Bochs Display Extension Enabled (16 MB)
|
||||||
|
00000000000i[DEV ] PCI slot #1 used by plugin 'pcivga'
|
||||||
|
00000000000i[DEV ] Experimental PCI VGA present at device 2, function 0
|
||||||
|
00000000000i[BXVGA ] loaded PCI ROM '/usr/local/share/bochs/VGABIOS-lgpl-latest-cirrus.bin' (size=33792 / PCI=64k)
|
||||||
|
00000000000i[PLUGIN] init_dev of 'floppy' plugin device by virtual method
|
||||||
|
00000000000i[DMA ] channel 2 used by Floppy Drive
|
||||||
|
00000000000i[FLOPPY] Using boot sequence disk, none, none
|
||||||
|
00000000000i[FLOPPY] Floppy boot signature check is enabled
|
||||||
|
00000000000i[PLUGIN] init_dev of 'acpi' plugin device by virtual method
|
||||||
|
00000000000i[DEV ] ACPI Controller present at device 1, function 3
|
||||||
|
00000000000i[PLUGIN] init_dev of 'hpet' plugin device by virtual method
|
||||||
|
00000000000i[HPET ] initializing HPET
|
||||||
|
00000000000i[MEM0 ] Register memory access handlers: 0x0000fed00000 - 0x0000fed003ff
|
||||||
|
00000000000i[PLUGIN] init_dev of 'ioapic' plugin device by virtual method
|
||||||
|
00000000000i[IOAPIC] initializing I/O APIC
|
||||||
|
00000000000i[MEM0 ] Register memory access handlers: 0x0000fec00000 - 0x0000fec00fff
|
||||||
|
00000000000i[IOAPIC] IOAPIC enabled (base address = 0xfec00000)
|
||||||
|
00000000000i[PLUGIN] init_dev of 'keyboard' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] init_dev of 'pci_ide' plugin device by virtual method
|
||||||
|
00000000000i[DEV ] PIIX3 PCI IDE controller present at device 1, function 1
|
||||||
|
00000000000i[PLUGIN] init_dev of 'harddrv' plugin device by virtual method
|
||||||
|
00000000000i[HD ] HD on ata0-0: './myOSimage.img', 'flat' mode
|
||||||
|
00000000000i[IMG ] hd_size: 67108864
|
||||||
|
00000000000i[HD ] ata0-0: autodetect geometry: CHS=130/16/63 (sector size=512)
|
||||||
|
00000000000i[HD ] ata0-0: extra data outside of CHS address range
|
||||||
|
00000000000i[HD ] translation on ata0-0 set to 'none'
|
||||||
|
00000000000i[PLUGIN] init_dev of 'unmapped' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] init_dev of 'biosdev' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] init_dev of 'speaker' plugin device by virtual method
|
||||||
|
00000000000e[PCSPK ] Failed to open /dev/console: 許可がありません
|
||||||
|
00000000000e[PCSPK ] Deactivating beep on console
|
||||||
|
00000000000i[PLUGIN] init_dev of 'extfpuirq' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] init_dev of 'parallel' plugin device by virtual method
|
||||||
|
00000000000i[PAR ] parallel port 1 at 0x0378 irq 7
|
||||||
|
00000000000i[PLUGIN] init_dev of 'serial' plugin device by virtual method
|
||||||
|
00000000000i[SER ] com1 at 0x03f8 irq 4 (mode: null)
|
||||||
|
00000000000i[PLUGIN] init_dev of 'iodebug' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'pci' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'pci2isa' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'cmos' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'dma' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'pic' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'pit' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'vga' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'floppy' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'unmapped' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'biosdev' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'speaker' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'extfpuirq' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'parallel' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'serial' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'iodebug' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'acpi' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'hpet' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'ioapic' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'keyboard' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'pci_ide' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] register state of 'harddrv' plugin device by virtual method
|
||||||
|
00000000000i[SYS ] bx_pc_system_c::Reset(HARDWARE) called
|
||||||
|
00000000000i[CPU0 ] cpu hardware reset
|
||||||
|
00000000000i[APIC0 ] allocate APIC id=0 (MMIO enabled) to 0x0000fee00000
|
||||||
|
00000000000i[CPU0 ] CPUID[0x00000000]: 0000000d 756e6547 6c65746e 49656e69
|
||||||
|
00000000000i[CPU0 ] CPUID[0x00000001]: 000206a7 00010800 079ae3bf afebfbff
|
||||||
|
00000000000i[CPU0 ] CPUID[0x00000002]: 76035a01 00f0b0ff 00000000 00ca0000
|
||||||
|
00000000000i[CPU0 ] CPUID[0x00000003]: 00000000 00000000 00000000 00000000
|
||||||
|
00000000000i[CPU0 ] CPUID[0x00000004]: 1c004121 01c0003f 0000003f 00000000
|
||||||
|
00000000000i[CPU0 ] CPUID[0x00000005]: 00000040 00000040 00000003 00001120
|
||||||
|
00000000000i[CPU0 ] CPUID[0x00000006]: 00000077 00000002 0000000b 00000000
|
||||||
|
00000000000i[CPU0 ] CPUID[0x00000007]: 00000000 00000000 00000000 00000000
|
||||||
|
00000000000i[CPU0 ] CPUID[0x00000008]: 00000000 00000000 00000000 00000000
|
||||||
|
00000000000i[CPU0 ] CPUID[0x00000009]: 00000000 00000000 00000000 00000000
|
||||||
|
00000000000i[CPU0 ] WARNING: Architectural Performance Monitoring is not implemented
|
||||||
|
00000000000i[CPU0 ] CPUID[0x0000000a]: 07300803 00000000 00000000 00000603
|
||||||
|
00000000000i[CPU0 ] CPUID[0x0000000b]: 00000000 00000000 00000000 00000000
|
||||||
|
00000000000i[CPU0 ] CPUID[0x0000000c]: 00000000 00000000 00000000 00000000
|
||||||
|
00000000000i[CPU0 ] CPUID[0x0000000d]: 00000003 00000240 00000240 00000000
|
||||||
|
00000000000i[CPU0 ] CPUID[0x80000000]: 80000008 00000000 00000000 00000000
|
||||||
|
00000000000i[CPU0 ] CPUID[0x80000001]: 00000000 00000000 00000001 28100000
|
||||||
|
00000000000i[CPU0 ] CPUID[0x80000002]: 20202020 49202020 6c65746e 20295228
|
||||||
|
00000000000i[CPU0 ] CPUID[0x80000003]: 65726f43 294d5428 2d376920 30303632
|
||||||
|
00000000000i[CPU0 ] CPUID[0x80000004]: 5043204b 20402055 30342e33 007a4847
|
||||||
|
00000000000i[CPU0 ] CPUID[0x80000005]: 00000000 00000000 00000000 00000000
|
||||||
|
00000000000i[CPU0 ] CPUID[0x80000006]: 00000000 00000000 01006040 00000000
|
||||||
|
00000000000i[CPU0 ] CPUID[0x80000007]: 00000000 00000000 00000000 00000100
|
||||||
|
00000000000i[CPU0 ] CPUID[0x80000008]: 00003028 00000200 00000000 00000000
|
||||||
|
00000000000i[CPU0 ] CPU Features supported:
|
||||||
|
00000000000i[CPU0 ] x87
|
||||||
|
00000000000i[CPU0 ] 486ni
|
||||||
|
00000000000i[CPU0 ] pentium_ni
|
||||||
|
00000000000i[CPU0 ] p6ni
|
||||||
|
00000000000i[CPU0 ] mmx
|
||||||
|
00000000000i[CPU0 ] debugext
|
||||||
|
00000000000i[CPU0 ] vme
|
||||||
|
00000000000i[CPU0 ] pse
|
||||||
|
00000000000i[CPU0 ] pae
|
||||||
|
00000000000i[CPU0 ] pge
|
||||||
|
00000000000i[CPU0 ] mtrr
|
||||||
|
00000000000i[CPU0 ] pat
|
||||||
|
00000000000i[CPU0 ] sysenter_sysexit
|
||||||
|
00000000000i[CPU0 ] clflush
|
||||||
|
00000000000i[CPU0 ] sse
|
||||||
|
00000000000i[CPU0 ] sse2
|
||||||
|
00000000000i[CPU0 ] sse3
|
||||||
|
00000000000i[CPU0 ] ssse3
|
||||||
|
00000000000i[CPU0 ] sse4_1
|
||||||
|
00000000000i[CPU0 ] sse4_2
|
||||||
|
00000000000i[CPU0 ] popcnt
|
||||||
|
00000000000i[CPU0 ] mwait
|
||||||
|
00000000000i[CPU0 ] longmode
|
||||||
|
00000000000i[CPU0 ] lm_lahf_sahf
|
||||||
|
00000000000i[CPU0 ] nx
|
||||||
|
00000000000i[CPU0 ] cmpxhg16b
|
||||||
|
00000000000i[CPU0 ] rdtscp
|
||||||
|
00000000000i[CPU0 ] xsave
|
||||||
|
00000000000i[CPU0 ] xsaveopt
|
||||||
|
00000000000i[CPU0 ] aes_pclmulqdq
|
||||||
|
00000000000i[CPU0 ] vmx
|
||||||
|
00000000000i[CPU0 ] xapic
|
||||||
|
00000000000i[CPU0 ] pcid
|
||||||
|
00000000000i[CPU0 ] tsc_deadline
|
||||||
|
00000000000i[PLUGIN] reset of 'pci' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'pci2isa' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'cmos' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'dma' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'pic' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'pit' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'vga' plugin device by virtual method
|
||||||
|
00000000000i[DDC ] Using default EDID for resolution 1920x1200
|
||||||
|
00000000000i[PLUGIN] reset of 'floppy' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'acpi' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'hpet' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'ioapic' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'keyboard' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'pci_ide' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'harddrv' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'unmapped' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'biosdev' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'speaker' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'extfpuirq' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'parallel' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'serial' plugin device by virtual method
|
||||||
|
00000000000i[PLUGIN] reset of 'iodebug' plugin device by virtual method
|
||||||
|
00000055493i[ACPI ] new PM base address: 0xb000
|
||||||
|
00000055938i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00000056097i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00000056270i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00000056429i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00000056598i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00000056757i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00000056929i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00000057088i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00000057261i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00000057420i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00000057589i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00000057748i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00000057919i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00000058078i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404699010i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404699261i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404699420i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404699586i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404699747i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404699909e[CPU0 ] RDMSR: Unknown register 0x17
|
||||||
|
00404701729i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404701888i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404702065i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404702224i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404702404i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404702563i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404702739i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404702898i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404703078i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404703237i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404703414i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404703573i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404706952i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404707111i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404707287i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404707446i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404707627i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404707786i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404707962i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404708121i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404708293i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404708452i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404708665i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404708836i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404749196i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404749367i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404750562i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404750733i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404953225i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404955765i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404956646i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404957662i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404957821i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404957987i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404958148i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404959043i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404959921i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404960937i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404961096i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404961262i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404961423i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00404962673i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455692544i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455721201i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455721452i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455721612i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455721802i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455721963i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455722125e[CPU0 ] RDMSR: Unknown register 0x17
|
||||||
|
00455727961i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455728121i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455728322i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455728482i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455728686i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455728846i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455729046i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455729206i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455729410i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455729570i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455729771i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455729931i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455731779i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455731939i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455732129i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455732290i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455733787i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455733947i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455734137i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00455734298i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461046195i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461046350i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461046524i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461046679i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461047124i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461047279i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461047448i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461047603i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461047777i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461047932i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461047952i[APIC0 ] set timer divide factor to 1
|
||||||
|
00461048098i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461048253i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461048427i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461048582i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461048753i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461048908i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461049074i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461049229i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461049402i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00461049557i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00471049475i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00471049630i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00477485335e[CMOS ] write to control register 0x0d ignored (read-only)
|
||||||
|
00481049475i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00481049630i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00491049475i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00491049630i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00501049476i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00501049631i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00511049475i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00511049630i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00521049475i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00521049630i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00531049476i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00531049631i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00541049476i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00541049631i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00550634745i[PIDE ] BAR #4: i/o base address = 0xc000
|
||||||
|
00550635289i[MEM0 ] Register memory access handlers: 0x000080000000 - 0x000080ffffff
|
||||||
|
00550635289i[BXVGA ] BAR #0: mem base address = 0x80000000
|
||||||
|
00550637278i[MEM0 ] Register memory access handlers: 0x000081000000 - 0x00008100ffff
|
||||||
|
00550637278i[BXVGA ] new ROM address = 0x81000000
|
||||||
|
00551049475i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00551049630i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00556732034i[SER ] com1: FIFO enabled
|
||||||
|
00558548658i[SER ] com1: FIFO enabled
|
||||||
|
00561049475i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00561049630i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00562088041i[KBD ] Switched to scancode set 2
|
||||||
|
00571052468i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00571052623i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00581052467i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00581052622i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00581767851i[P2ISA ] PCI IRQ routing: PIRQA# set to 0x0a
|
||||||
|
00581767938i[P2ISA ] PCI IRQ routing: PIRQB# set to 0x0a
|
||||||
|
00581768025i[P2ISA ] PCI IRQ routing: PIRQC# set to 0x0b
|
||||||
|
00581768112i[P2ISA ] PCI IRQ routing: PIRQD# set to 0x0b
|
||||||
|
00591052467i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00591052622i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00601052467i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00601052622i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00611053746i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00611053901i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00621053540i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00621053695i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00631052467i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00631052622i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00641052467i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00641052622i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00651052467i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00651052622i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00661053540i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00661053695i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00671052467i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00671052622i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00681052467i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00681052622i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00691053746i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00691053901i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00701053540i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00701053695i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00711053746i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00711053901i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00721052468i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00721052623i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00731052468i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00731052623i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00741058328i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00741058483i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00751053746i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00751053901i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00761053540i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00761053695i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00764170096i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00764170251i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00764170425i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
00764170580i[CPU0 ] RDMSR: Read 00000000:fee00900 from MSR_APICBASE
|
||||||
|
02367208064p[IOAPIC] >>PANIC<< I/O APIC read at address 0x0000fec00008 spans 32-bit boundary !
|
||||||
|
02367208064i[CPU0 ] CPU is in long mode (active)
|
||||||
|
02367208064i[CPU0 ] CS.mode = 64 bit
|
||||||
|
02367208064i[CPU0 ] SS.mode = 64 bit
|
||||||
|
02367208064i[CPU0 ] EFER = 0x00000d00: ffxsr NXE LMA LME sce
|
||||||
|
02367208064i[CPU0 ] XCR0=0x00000001: tiledata tilecfg hwp lbr uintr hdc cet_s cet_u pasid pkru pt hi_zmm zmm_hi256 opmask bndcfg bndregs ymm sse FPU
|
||||||
|
02367208064i[CPU0 ] | RAX=0000000000000000 RBX=0000000000232188
|
||||||
|
02367208064i[CPU0 ] | RCX=ffffffffffffffff RDX=00000000fec00000
|
||||||
|
02367208064i[CPU0 ] | RSP=0000000000232060 RBP=000000000fd7e518
|
||||||
|
02367208064i[CPU0 ] | RSI=ffffffffffffffff RDI=0000000000232188
|
||||||
|
02367208064i[CPU0 ] | R8=0000000000000000 R9=0000000000000001
|
||||||
|
02367208064i[CPU0 ] | R10=0000000000000000 R11=0000000000000002
|
||||||
|
02367208064i[CPU0 ] | R12=0000000000000000 R13=0000000000000000
|
||||||
|
02367208064i[CPU0 ] | R14=00000000002320c0 R15=00000000001297e0
|
||||||
|
02367208064i[CPU0 ] | EFLAGS=00000087: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af PF CF
|
||||||
|
02367208064i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
|
||||||
|
02367208064i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 ffffffff 1 0
|
||||||
|
02367208064i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
|
||||||
|
02367208064i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
|
||||||
|
02367208064i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 ffffffff 1 1
|
||||||
|
02367208064i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
|
||||||
|
02367208064i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
|
||||||
|
02367208064i[CPU0 ] | MSR_FS_BASE:0000000000000000
|
||||||
|
02367208064i[CPU0 ] | MSR_GS_BASE:0000000000000000
|
||||||
|
02367208064i[CPU0 ] | RIP=0000000000110ed5 (0000000000110ed0)
|
||||||
|
02367208064i[CPU0 ] | CR0=0x80010033: PG cd nw ac WP NE ET ts em MP PE
|
||||||
|
02367208064i[CPU0 ] | CR2=0x0000000000000000
|
||||||
|
02367208064i[CPU0 ] | CR3=0x000000000fa01000
|
||||||
|
02367208064i[CPU0 ] | CR4=0x00000668: lass uintr pks cet pke smap smep keylock osxsave pcid fsgsbase smx vmx la57 umip OSXMMEXCPT OSFXSR pce pge MCE PAE pse DE tsd pvi vme
|
||||||
|
02367208064i[CPU0 ] 0x0000000000110ed0>> mov rsi, qword ptr ds:[r13+rdx+8] : 498B741508
|
||||||
|
02367208064i[CMOS ] Last time: 1755875601 tz=utc (Fri Aug 22 15:13:21 2025)
|
||||||
|
02367208064i[ ] restoring default signal behavior
|
||||||
|
02367208064i[SIM ] quit_sim called with exit code 1
|
20
nel_os_bootloader/bochsrc
Normal file
20
nel_os_bootloader/bochsrc
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# ---- 画面/入力 ----
|
||||||
|
display_library: sdl2
|
||||||
|
vga: extension=cirrus
|
||||||
|
pci: enabled=1, chipset=i440fx, slot1=pcivga
|
||||||
|
vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest-cirrus.bin
|
||||||
|
|
||||||
|
romimage: file="./OVMF-pure-efi.fd", address=0x0, options=none
|
||||||
|
|
||||||
|
# ---- メモリ/CPU ----
|
||||||
|
memory: guest=256
|
||||||
|
cpu: count=1, model=corei7_sandy_bridge_2600k, reset_on_triple_fault=1
|
||||||
|
|
||||||
|
# ---- ストレージ(UEFI ESP を作った “本物のディスク” )----
|
||||||
|
ata0: enabled=1
|
||||||
|
ata0-master: type=disk, mode=flat, path="./myOSimage.img", status=inserted
|
||||||
|
boot: disk
|
||||||
|
|
||||||
|
# ---- ログ ----
|
||||||
|
log: bochs.out
|
||||||
|
|
BIN
nel_os_bootloader/esp/NvVars
Normal file
BIN
nel_os_bootloader/esp/NvVars
Normal file
Binary file not shown.
0
nel_os_bootloader/esp/vvfat_attr.cfg
Normal file
0
nel_os_bootloader/esp/vvfat_attr.cfg
Normal file
BIN
nel_os_bootloader/myOSimage.img
Normal file
BIN
nel_os_bootloader/myOSimage.img
Normal file
Binary file not shown.
@ -6,7 +6,7 @@ EFI_BINARY="$1"
|
|||||||
./create-iso.sh "$EFI_BINARY"
|
./create-iso.sh "$EFI_BINARY"
|
||||||
|
|
||||||
qemu-system-x86_64 -enable-kvm \
|
qemu-system-x86_64 -enable-kvm \
|
||||||
-m 4G \
|
-m 2G \
|
||||||
-serial mon:stdio \
|
-serial mon:stdio \
|
||||||
-nographic \
|
-nographic \
|
||||||
-no-reboot \
|
-no-reboot \
|
||||||
|
@ -131,9 +131,20 @@ fn load_elf(bin: Box<[u8]>) -> u64 {
|
|||||||
elf.entry
|
elf.entry
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_frame_buffer() -> gop::FrameBuffer {
|
fn get_frame_buffer() -> Option<gop::FrameBuffer> {
|
||||||
let gop_handle = uefi::boot::get_handle_for_protocol::<GraphicsOutput>().unwrap();
|
let gop_handle = if let Ok(gop_handle) = uefi::boot::get_handle_for_protocol::<GraphicsOutput>()
|
||||||
let mut gop = boot::open_protocol_exclusive::<GraphicsOutput>(gop_handle).unwrap();
|
{
|
||||||
|
gop_handle
|
||||||
|
} else {
|
||||||
|
println!("GraphicsOutput protocol not found");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let mut gop = if let Ok(gop) = boot::open_protocol_exclusive::<GraphicsOutput>(gop_handle) {
|
||||||
|
gop
|
||||||
|
} else {
|
||||||
|
println!("Failed to open GraphicsOutput protocol");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
let info = gop.current_mode_info();
|
let info = gop.current_mode_info();
|
||||||
let (width, height) = info.resolution();
|
let (width, height) = info.resolution();
|
||||||
@ -141,7 +152,7 @@ fn get_frame_buffer() -> gop::FrameBuffer {
|
|||||||
let stride = info.stride();
|
let stride = info.stride();
|
||||||
let pixel_format = info.pixel_format();
|
let pixel_format = info.pixel_format();
|
||||||
|
|
||||||
gop::FrameBuffer {
|
Some(gop::FrameBuffer {
|
||||||
frame_buffer,
|
frame_buffer,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
@ -151,15 +162,15 @@ fn get_frame_buffer() -> gop::FrameBuffer {
|
|||||||
PixelFormat::Bgr => gop::PixelFormat::Bgr,
|
PixelFormat::Bgr => gop::PixelFormat::Bgr,
|
||||||
format => panic!("Unsupported pixel_format: {:?}", format),
|
format => panic!("Unsupported pixel_format: {:?}", format),
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rsdp() -> u64 {
|
fn get_rsdp() -> Option<u64> {
|
||||||
uefi::system::with_config_table(move |c| {
|
uefi::system::with_config_table(move |c| {
|
||||||
c.iter()
|
c.iter()
|
||||||
.find(|config| config.guid == uefi::table::cfg::ACPI_GUID)
|
.find(|config| config.guid == uefi::table::cfg::ACPI_GUID)
|
||||||
.map(|config| config.address as u64)
|
.map(|config| config.address as u64)
|
||||||
.expect("Failed to find RSDP in config table")
|
.or(None)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
nel_os_bootloader/update_img.sh
Executable file
6
nel_os_bootloader/update_img.sh
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
cargo b -r
|
||||||
|
sudo mount /dev/loop0 /mnt
|
||||||
|
sudo cp ./target/x86_64-unknown-uefi/release/nel_os_bootloader.efi /mnt/EFI/BOOT/BOOTX64.EFI
|
||||||
|
sudo sync
|
||||||
|
sudo umount /mnt
|
@ -7,8 +7,8 @@ pub mod memory;
|
|||||||
|
|
||||||
pub struct BootInfo {
|
pub struct BootInfo {
|
||||||
pub usable_memory: UsableMemory,
|
pub usable_memory: UsableMemory,
|
||||||
pub frame_buffer: FrameBuffer,
|
pub frame_buffer: Option<FrameBuffer>,
|
||||||
pub rsdp: u64,
|
pub rsdp: Option<u64>,
|
||||||
pub bzimage_addr: u64,
|
pub bzimage_addr: u64,
|
||||||
pub bzimage_size: u64,
|
pub bzimage_size: u64,
|
||||||
pub rootfs_addr: u64,
|
pub rootfs_addr: u64,
|
||||||
|
@ -13,7 +13,4 @@ pub const HEAP_START: usize = 0x4444_4444_0000;
|
|||||||
pub const HEAP_SIZE: usize = 128 * 1024;
|
pub const HEAP_SIZE: usize = 128 * 1024;
|
||||||
|
|
||||||
pub const PAGE_SIZE: usize = 4096;
|
pub const PAGE_SIZE: usize = 4096;
|
||||||
pub const MAX_MEMORY: usize = 256 * 1024 * 1024 * 1024;
|
|
||||||
pub const FRAME_COUNT: usize = MAX_MEMORY / PAGE_SIZE;
|
|
||||||
pub const BITS_PER_ENTRY: usize = 8 * core::mem::size_of::<usize>();
|
pub const BITS_PER_ENTRY: usize = 8 * core::mem::size_of::<usize>();
|
||||||
pub const ENTRY_COUNT: usize = FRAME_COUNT / BITS_PER_ENTRY;
|
|
||||||
|
@ -5,6 +5,7 @@ use crate::{
|
|||||||
interrupt::{
|
interrupt::{
|
||||||
apic::{EOI, LAPIC},
|
apic::{EOI, LAPIC},
|
||||||
gdt,
|
gdt,
|
||||||
|
subscriber::InterruptContext,
|
||||||
},
|
},
|
||||||
time, warn,
|
time, warn,
|
||||||
};
|
};
|
||||||
@ -40,6 +41,17 @@ pub fn init_idt() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
|
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
|
||||||
|
let context = InterruptContext {
|
||||||
|
vector: 3,
|
||||||
|
instruction_pointer: stack_frame.instruction_pointer.as_u64(),
|
||||||
|
code_segment: stack_frame.code_segment.0 as u64,
|
||||||
|
cpu_flags: stack_frame.cpu_flags.bits(),
|
||||||
|
stack_pointer: stack_frame.stack_pointer.as_u64(),
|
||||||
|
stack_segment: stack_frame.stack_segment.0 as u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
crate::interrupt::subscriber::dispatch_to_subscribers(&context);
|
||||||
|
|
||||||
warn!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
warn!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +59,17 @@ extern "x86-interrupt" fn double_fault_handler(
|
|||||||
stack_frame: InterruptStackFrame,
|
stack_frame: InterruptStackFrame,
|
||||||
_error_code: u64,
|
_error_code: u64,
|
||||||
) -> ! {
|
) -> ! {
|
||||||
|
let context = InterruptContext {
|
||||||
|
vector: 8,
|
||||||
|
instruction_pointer: stack_frame.instruction_pointer.as_u64(),
|
||||||
|
code_segment: stack_frame.code_segment.0 as u64,
|
||||||
|
cpu_flags: stack_frame.cpu_flags.bits(),
|
||||||
|
stack_pointer: stack_frame.stack_pointer.as_u64(),
|
||||||
|
stack_segment: stack_frame.stack_segment.0 as u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
crate::interrupt::subscriber::dispatch_to_subscribers(&context);
|
||||||
|
|
||||||
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +79,17 @@ extern "x86-interrupt" fn page_fault_handler(
|
|||||||
) {
|
) {
|
||||||
use x86_64::registers::control::Cr2;
|
use x86_64::registers::control::Cr2;
|
||||||
|
|
||||||
|
let context = InterruptContext {
|
||||||
|
vector: 14,
|
||||||
|
instruction_pointer: stack_frame.instruction_pointer.as_u64(),
|
||||||
|
code_segment: stack_frame.code_segment.0 as u64,
|
||||||
|
cpu_flags: stack_frame.cpu_flags.bits(),
|
||||||
|
stack_pointer: stack_frame.stack_pointer.as_u64(),
|
||||||
|
stack_segment: stack_frame.stack_segment.0 as u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
crate::interrupt::subscriber::dispatch_to_subscribers(&context);
|
||||||
|
|
||||||
panic!(
|
panic!(
|
||||||
"EXCEPTION: PAGE FAULT\n{:#?}\nAccessed address: {:#x}",
|
"EXCEPTION: PAGE FAULT\n{:#?}\nAccessed address: {:#x}",
|
||||||
stack_frame,
|
stack_frame,
|
||||||
@ -63,7 +97,18 @@ extern "x86-interrupt" fn page_fault_handler(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn timer_handler(_stack_frame: InterruptStackFrame) {
|
extern "x86-interrupt" fn timer_handler(stack_frame: InterruptStackFrame) {
|
||||||
|
let context = InterruptContext {
|
||||||
|
vector: IRQ_TIMER as u8,
|
||||||
|
instruction_pointer: stack_frame.instruction_pointer.as_u64(),
|
||||||
|
code_segment: stack_frame.code_segment.0 as u64,
|
||||||
|
cpu_flags: stack_frame.cpu_flags.bits(),
|
||||||
|
stack_pointer: stack_frame.stack_pointer.as_u64(),
|
||||||
|
stack_segment: stack_frame.stack_segment.0 as u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
crate::interrupt::subscriber::dispatch_to_subscribers(&context);
|
||||||
|
|
||||||
time::tick();
|
time::tick();
|
||||||
LAPIC.get().unwrap().write(EOI, 0);
|
LAPIC.get().unwrap().write(EOI, 0);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
pub mod apic;
|
pub mod apic;
|
||||||
pub mod gdt;
|
pub mod gdt;
|
||||||
pub mod idt;
|
pub mod idt;
|
||||||
|
pub mod subscriber;
|
||||||
|
68
nel_os_kernel/src/interrupt/subscriber.rs
Normal file
68
nel_os_kernel/src/interrupt/subscriber.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InterruptContext {
|
||||||
|
pub vector: u8,
|
||||||
|
pub instruction_pointer: u64,
|
||||||
|
pub code_segment: u64,
|
||||||
|
pub cpu_flags: u64,
|
||||||
|
pub stack_pointer: u64,
|
||||||
|
pub stack_segment: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type SubscriberCallback = fn(*mut core::ffi::c_void, &InterruptContext);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Subscriber {
|
||||||
|
pub callback: SubscriberCallback,
|
||||||
|
pub context: *mut core::ffi::c_void,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for Subscriber {}
|
||||||
|
unsafe impl Sync for Subscriber {}
|
||||||
|
|
||||||
|
const MAX_SUBSCRIBERS: usize = 10;
|
||||||
|
|
||||||
|
static SUBSCRIBERS: Mutex<[Option<Subscriber>; MAX_SUBSCRIBERS]> =
|
||||||
|
Mutex::new([None; MAX_SUBSCRIBERS]);
|
||||||
|
|
||||||
|
pub fn subscribe(
|
||||||
|
callback: SubscriberCallback,
|
||||||
|
context: *mut core::ffi::c_void,
|
||||||
|
) -> Result<(), &'static str> {
|
||||||
|
let mut subscribers = SUBSCRIBERS.lock();
|
||||||
|
|
||||||
|
for slot in subscribers.iter_mut() {
|
||||||
|
if slot.is_none() {
|
||||||
|
*slot = Some(Subscriber { callback, context });
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err("No available subscriber slots")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unsubscribe(callback: SubscriberCallback) -> Result<(), &'static str> {
|
||||||
|
let mut subscribers = SUBSCRIBERS.lock();
|
||||||
|
|
||||||
|
for slot in subscribers.iter_mut() {
|
||||||
|
if let Some(subscriber) = slot {
|
||||||
|
if core::ptr::fn_addr_eq(subscriber.callback, callback) {
|
||||||
|
*slot = None;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err("Subscriber not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dispatch_to_subscribers(context: &InterruptContext) {
|
||||||
|
let subscribers = SUBSCRIBERS.lock();
|
||||||
|
|
||||||
|
for subscriber in subscribers.iter() {
|
||||||
|
if let Some(subscriber) = subscriber {
|
||||||
|
(subscriber.callback)(subscriber.context, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -82,6 +82,8 @@ fn hlt_loop() -> ! {
|
|||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub extern "sysv64" fn main(boot_info: &nel_os_common::BootInfo) {
|
pub extern "sysv64" fn main(boot_info: &nel_os_common::BootInfo) {
|
||||||
|
serial::disable_screen_output();
|
||||||
|
|
||||||
interrupt::gdt::init();
|
interrupt::gdt::init();
|
||||||
interrupt::idt::init_idt();
|
interrupt::idt::init_idt();
|
||||||
|
|
||||||
@ -96,10 +98,13 @@ pub extern "sysv64" fn main(boot_info: &nel_os_common::BootInfo) {
|
|||||||
|
|
||||||
let ranges = boot_info.usable_memory.ranges();
|
let ranges = boot_info.usable_memory.ranges();
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
|
let mut max_range = 0;
|
||||||
for range in ranges {
|
for range in ranges {
|
||||||
count += range.end - range.start;
|
count += range.end - range.start;
|
||||||
|
max_range = max_range.max(range.end);
|
||||||
}
|
}
|
||||||
info!("Usable memory: {}MiB", count / 1024 / 1024);
|
info!("Usable memory: {}MiB", count / 1024 / 1024);
|
||||||
|
memory::memory::MAX_MEMORY.call_once(|| max_range as usize * 2);
|
||||||
|
|
||||||
let mut bitmap_table = BitmapMemoryTable::init(&boot_info.usable_memory);
|
let mut bitmap_table = BitmapMemoryTable::init(&boot_info.usable_memory);
|
||||||
info!(
|
info!(
|
||||||
@ -126,10 +131,15 @@ pub extern "sysv64" fn main(boot_info: &nel_os_common::BootInfo) {
|
|||||||
|
|
||||||
allocator::init_heap(&mut mapper, &mut bitmap_table).unwrap();
|
allocator::init_heap(&mut mapper, &mut bitmap_table).unwrap();
|
||||||
|
|
||||||
let frame_buffer = FrameBuffer::from_raw_buffer(&boot_info.frame_buffer, (64, 64, 64));
|
if boot_info.frame_buffer.is_some() {
|
||||||
frame_buffer.clear();
|
let frame_buffer =
|
||||||
|
FrameBuffer::from_raw_buffer(&boot_info.frame_buffer.as_ref().unwrap(), (64, 64, 64));
|
||||||
|
frame_buffer.clear();
|
||||||
|
|
||||||
FRAME_BUFFER.lock().replace(frame_buffer);
|
FRAME_BUFFER.lock().replace(frame_buffer);
|
||||||
|
} else {
|
||||||
|
error!("No frame buffer found");
|
||||||
|
}
|
||||||
|
|
||||||
println!("");
|
println!("");
|
||||||
info!("Kernel initialized successfully");
|
info!("Kernel initialized successfully");
|
||||||
@ -150,20 +160,20 @@ pub extern "sysv64" fn main(boot_info: &nel_os_common::BootInfo) {
|
|||||||
usable_frame as f64 * 4. / 1024. / 1024.
|
usable_frame as f64 * 4. / 1024. / 1024.
|
||||||
);
|
);
|
||||||
|
|
||||||
info!("RSDP: {:#x}", boot_info.rsdp);
|
if let Some(rsdp) = boot_info.rsdp {
|
||||||
|
info!("RSDP: {:#x}", rsdp);
|
||||||
|
|
||||||
let acpi_tables =
|
let acpi_tables =
|
||||||
unsafe { AcpiTables::from_rsdp(KernelAcpiHandler, boot_info.rsdp as usize) }.unwrap();
|
unsafe { AcpiTables::from_rsdp(KernelAcpiHandler, rsdp as usize) }.unwrap();
|
||||||
let platform_info = acpi_tables.platform_info().unwrap();
|
let platform_info = acpi_tables.platform_info().unwrap();
|
||||||
|
|
||||||
apic::init_local_apic(platform_info);
|
apic::init_local_apic(platform_info);
|
||||||
info!("Local APIC initialized",);
|
info!("Local APIC initialized",);
|
||||||
|
|
||||||
x86_64::instructions::interrupts::enable();
|
x86_64::instructions::interrupts::enable();
|
||||||
|
|
||||||
info!("Interrupts enabled");
|
info!("Interrupts enabled");
|
||||||
|
}
|
||||||
serial::disable_screen_output();
|
|
||||||
|
|
||||||
BZIMAGE_ADDR.call_once(|| boot_info.bzimage_addr);
|
BZIMAGE_ADDR.call_once(|| boot_info.bzimage_addr);
|
||||||
BZIMAGE_SIZE.call_once(|| boot_info.bzimage_size);
|
BZIMAGE_SIZE.call_once(|| boot_info.bzimage_size);
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
use core::slice;
|
use core::slice;
|
||||||
|
|
||||||
use nel_os_common::memory::{self, UsableMemory};
|
use nel_os_common::memory::{self, UsableMemory};
|
||||||
|
use spin::Once;
|
||||||
use x86_64::{
|
use x86_64::{
|
||||||
structures::paging::{FrameAllocator, PhysFrame, Size4KiB},
|
structures::paging::{FrameAllocator, PhysFrame, Size4KiB},
|
||||||
PhysAddr,
|
PhysAddr,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::constant::{BITS_PER_ENTRY, ENTRY_COUNT, PAGE_SIZE};
|
use crate::constant::{BITS_PER_ENTRY, PAGE_SIZE};
|
||||||
|
|
||||||
|
pub static MAX_MEMORY: Once<usize> = Once::new();
|
||||||
|
|
||||||
|
pub fn get_entry_count() -> usize {
|
||||||
|
MAX_MEMORY.get().unwrap_or(&0) / PAGE_SIZE / BITS_PER_ENTRY
|
||||||
|
}
|
||||||
|
|
||||||
pub struct BitmapMemoryTable {
|
pub struct BitmapMemoryTable {
|
||||||
pub used_map: &'static mut [usize],
|
pub used_map: &'static mut [usize],
|
||||||
@ -21,16 +28,17 @@ impl BitmapMemoryTable {
|
|||||||
max_addr = max_addr.max(range.end);
|
max_addr = max_addr.max(range.end);
|
||||||
}
|
}
|
||||||
|
|
||||||
let bitmap_size = ENTRY_COUNT * core::mem::size_of::<usize>();
|
let entry_count = get_entry_count();
|
||||||
|
let bitmap_size = entry_count * core::mem::size_of::<usize>();
|
||||||
|
|
||||||
let bitmap_addr = ((max_addr as usize).saturating_sub(bitmap_size)) & !(PAGE_SIZE - 1);
|
let bitmap_addr = ((max_addr as usize).saturating_sub(bitmap_size)) & !(PAGE_SIZE - 1);
|
||||||
|
|
||||||
let used_map = unsafe {
|
let used_map = unsafe {
|
||||||
let ptr = bitmap_addr as *mut usize;
|
let ptr = bitmap_addr as *mut usize;
|
||||||
slice::from_raw_parts_mut(ptr, ENTRY_COUNT)
|
slice::from_raw_parts_mut(ptr, entry_count)
|
||||||
};
|
};
|
||||||
|
|
||||||
(0..ENTRY_COUNT).for_each(|i| {
|
(0..entry_count).for_each(|i| {
|
||||||
used_map[i] = 0;
|
used_map[i] = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -50,8 +58,8 @@ impl BitmapMemoryTable {
|
|||||||
table.set_frame(bitmap_start_frame + i, false);
|
table.set_frame(bitmap_start_frame + i, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0..ENTRY_COUNT {
|
for i in 0..entry_count {
|
||||||
let index = ENTRY_COUNT - i - 1;
|
let index = entry_count - i - 1;
|
||||||
if table.used_map[index] != 0 {
|
if table.used_map[index] != 0 {
|
||||||
let offset = 63 - table.used_map[index].leading_zeros();
|
let offset = 63 - table.used_map[index].leading_zeros();
|
||||||
table.end = index * BITS_PER_ENTRY + (BITS_PER_ENTRY - offset as usize);
|
table.end = index * BITS_PER_ENTRY + (BITS_PER_ENTRY - offset as usize);
|
||||||
|
@ -10,6 +10,12 @@ pub fn load_kernel(vcpu: &mut dyn VCpu) -> Result<(), &'static str> {
|
|||||||
let kernel =
|
let kernel =
|
||||||
unsafe { core::slice::from_raw_parts(*kernel_addr as *const u8, *kernel_size as usize) };
|
unsafe { core::slice::from_raw_parts(*kernel_addr as *const u8, *kernel_size as usize) };
|
||||||
|
|
||||||
|
let initrd_addr = crate::ROOTFS_ADDR.get().unwrap();
|
||||||
|
let initrd_size = crate::ROOTFS_SIZE.get().unwrap();
|
||||||
|
|
||||||
|
let initrd =
|
||||||
|
unsafe { core::slice::from_raw_parts(*initrd_addr as *const u8, *initrd_size as usize) };
|
||||||
|
|
||||||
info!("Creating boot parameters");
|
info!("Creating boot parameters");
|
||||||
let guest_mem_size = vcpu.get_guest_memory_size();
|
let guest_mem_size = vcpu.get_guest_memory_size();
|
||||||
let mut bp = BootParams::from_bytes(kernel)?;
|
let mut bp = BootParams::from_bytes(kernel)?;
|
||||||
@ -23,6 +29,8 @@ pub fn load_kernel(vcpu: &mut dyn VCpu) -> Result<(), &'static str> {
|
|||||||
bp.hdr.loadflags.set_keep_segments(true);
|
bp.hdr.loadflags.set_keep_segments(true);
|
||||||
bp.hdr.cmd_line_ptr = LAYOUT_CMDLINE as u32;
|
bp.hdr.cmd_line_ptr = LAYOUT_CMDLINE as u32;
|
||||||
bp.hdr.vid_mode = 0xFFFF;
|
bp.hdr.vid_mode = 0xFFFF;
|
||||||
|
bp.hdr.ramdisk_image = LAYOUT_INITRD as u32;
|
||||||
|
bp.hdr.ramdisk_size = initrd.len() as u32;
|
||||||
|
|
||||||
bp.add_e820_entry(0, LAYOUT_KERNEL_BASE, E820Type::Ram);
|
bp.add_e820_entry(0, LAYOUT_KERNEL_BASE, E820Type::Ram);
|
||||||
bp.add_e820_entry(
|
bp.add_e820_entry(
|
||||||
@ -65,6 +73,9 @@ pub fn load_kernel(vcpu: &mut dyn VCpu) -> Result<(), &'static str> {
|
|||||||
LAYOUT_KERNEL_BASE as usize,
|
LAYOUT_KERNEL_BASE as usize,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
info!("Loading initrd image into guest memory");
|
||||||
|
load_image(vcpu, initrd, LAYOUT_INITRD as usize)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,14 @@ use x86::{msr, vmx::vmcs};
|
|||||||
|
|
||||||
use crate::vmm::x86_64::{
|
use crate::vmm::x86_64::{
|
||||||
common::read_msr,
|
common::read_msr,
|
||||||
intel::{self, vmread},
|
intel::{
|
||||||
|
self,
|
||||||
|
vmcs::controls::{
|
||||||
|
PinBasedVmExecutionControls, PrimaryProcessorBasedVmExecutionControls,
|
||||||
|
SecondaryProcessorBasedVmExecutionControls,
|
||||||
|
},
|
||||||
|
vmread,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn check_vmcs_control_fields() -> Result<(), &'static str> {
|
pub fn check_vmcs_control_fields() -> Result<(), &'static str> {
|
||||||
@ -21,10 +28,160 @@ pub fn check_vmcs_control_fields() -> Result<(), &'static str> {
|
|||||||
check_cr3_target()?;
|
check_cr3_target()?;
|
||||||
|
|
||||||
check_io_bitmap()?;
|
check_io_bitmap()?;
|
||||||
|
check_msr_bitmap()?;
|
||||||
|
|
||||||
|
check_nmi()?;
|
||||||
|
|
||||||
|
check_vmcs_shadowing()?;
|
||||||
|
check_ept_violation_exception_info()?;
|
||||||
|
check_interrupt()?;
|
||||||
|
|
||||||
|
check_ept()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_valid_ept_ptr(ept_ptr: u64) -> Result<(), &'static str> {
|
||||||
|
let memory_type = ept_ptr & 0b111;
|
||||||
|
if memory_type != 0 && memory_type != 6 {
|
||||||
|
return Err("VMCS EPT pointer memory type is not valid (must be 0 or 6)");
|
||||||
|
}
|
||||||
|
|
||||||
|
let walk_length = (ept_ptr >> 3) & 0b111;
|
||||||
|
if walk_length != 3 {
|
||||||
|
return Err("VMCS EPT pointer walk length is not valid (must be 3)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ept_ptr & 0xf00 != 0 {
|
||||||
|
return Err("VMCS EPT pointer reserved bits are not zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
if !is_valid_phys_addr(ept_ptr) {
|
||||||
|
return Err("VMCS EPT pointer is not a valid physical address");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_ept() -> Result<(), &'static str> {
|
||||||
|
let secondary_exec_ctrl = SecondaryProcessorBasedVmExecutionControls::read()?;
|
||||||
|
|
||||||
|
if secondary_exec_ctrl.ept() {
|
||||||
|
let ept_ptr = vmread(vmcs::control::EPTP_FULL)?;
|
||||||
|
is_valid_ept_ptr(ept_ptr)?;
|
||||||
|
} else {
|
||||||
|
if secondary_exec_ctrl.unrestricted_guest() {
|
||||||
|
return Err(
|
||||||
|
"VMCS Secondary processor-based execution controls field: EPT is not set while unrestricted guest is set",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if secondary_exec_ctrl.mode_based_control_ept() {
|
||||||
|
return Err(
|
||||||
|
"VMCS Secondary processor-based execution controls field: EPT is not set while mode-based control for EPT is set",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_interrupt() -> Result<(), &'static str> {
|
||||||
|
let primary_exec_ctrl = PrimaryProcessorBasedVmExecutionControls::read()?;
|
||||||
|
let secondary_exec_ctrl = SecondaryProcessorBasedVmExecutionControls::read()?;
|
||||||
|
let pin_ctrl = PinBasedVmExecutionControls::read()?;
|
||||||
|
|
||||||
|
if primary_exec_ctrl.use_tpr_shadow() {
|
||||||
|
let virtual_apic_page_addr = vmread(vmcs::control::VIRT_APIC_ADDR_FULL)?;
|
||||||
|
if !is_valid_page_aligned_phys_addr(virtual_apic_page_addr) {
|
||||||
|
return Err(
|
||||||
|
"VMCS virtual APIC page address is not a valid page-aligned physical address",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !secondary_exec_ctrl.virtual_interrupt_delivery() {
|
||||||
|
if !pin_ctrl.external_interrupt_exiting() {
|
||||||
|
return Err(
|
||||||
|
"VMCS Pin-based execution controls field: External interrupt exiting is not set while virtual interrupt delivery is set",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if secondary_exec_ctrl.virtualize_x2apic_mode()
|
||||||
|
|| secondary_exec_ctrl.apic_register_virtualization()
|
||||||
|
|| secondary_exec_ctrl.virtual_interrupt_delivery()
|
||||||
|
{
|
||||||
|
return Err(
|
||||||
|
"VMCS Primary processor-based execution controls field: Use TPR shadow is not set while virtualize x2APIC mode, APIC register virtualization, or virtual interrupt delivery is set",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_ept_violation_exception_info() -> Result<(), &'static str> {
|
||||||
|
let secondary_exec_ctrl = SecondaryProcessorBasedVmExecutionControls::read()?;
|
||||||
|
|
||||||
|
if secondary_exec_ctrl.ept_violation() {
|
||||||
|
let exception_info = vmread(vmcs::control::VIRT_EXCEPTION_INFO_ADDR_FULL)?;
|
||||||
|
|
||||||
|
if is_valid_page_aligned_phys_addr(exception_info) {
|
||||||
|
return Err("VMCS EPT violation exception info address is not a valid page-aligned physical address");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_vmcs_shadowing() -> Result<(), &'static str> {
|
||||||
|
let secondary_exec_ctrl = SecondaryProcessorBasedVmExecutionControls::read()?;
|
||||||
|
|
||||||
|
if !secondary_exec_ctrl.vmcs_shadowing() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let vmcs_vmread_bitmap = vmread(vmcs::control::VMREAD_BITMAP_ADDR_FULL)?;
|
||||||
|
let vmcs_vmwrite_bitmap = vmread(vmcs::control::VMWRITE_BITMAP_ADDR_FULL)?;
|
||||||
|
|
||||||
|
if !is_valid_page_aligned_phys_addr(vmcs_vmread_bitmap) {
|
||||||
|
return Err("VMCS VMREAD bitmap address is not a valid page-aligned physical address");
|
||||||
|
}
|
||||||
|
|
||||||
|
if !is_valid_page_aligned_phys_addr(vmcs_vmwrite_bitmap) {
|
||||||
|
return Err("VMCS VMWRITE bitmap address is not a valid page-aligned physical address");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_nmi() -> Result<(), &'static str> {
|
||||||
|
let pin_ctrl = PinBasedVmExecutionControls::read()?;
|
||||||
|
|
||||||
|
if !pin_ctrl.nmi_exiting() && pin_ctrl.virtual_nmi() {
|
||||||
|
return Err(
|
||||||
|
"VMCS Pin-based execution controls field: NMI exiting and virtual NMI are both set",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let exec_ctrl = PrimaryProcessorBasedVmExecutionControls::read()?;
|
||||||
|
|
||||||
|
if !pin_ctrl.virtual_nmi() && exec_ctrl.nmi_window() {
|
||||||
|
return Err(
|
||||||
|
"VMCS Pin-based execution controls field: Interrupt-window exiting and virtual NMI are both not set",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_valid_phys_addr(addr: u64) -> bool {
|
||||||
|
(addr & !((1 << 40) - 1)) == 0
|
||||||
|
}
|
||||||
|
|
||||||
fn is_valid_page_aligned_phys_addr(addr: u64) -> bool {
|
fn is_valid_page_aligned_phys_addr(addr: u64) -> bool {
|
||||||
(addr & (!((1 << 40) - 1) | 0xfff)) == 0
|
(addr & (!((1 << 40) - 1) | 0xfff)) == 0
|
||||||
}
|
}
|
||||||
@ -39,6 +196,16 @@ fn check_cr3_target() -> Result<(), &'static str> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_msr_bitmap() -> Result<(), &'static str> {
|
||||||
|
let vmcs_msr_bitmap = vmread(vmcs::control::MSR_BITMAPS_ADDR_FULL)?;
|
||||||
|
|
||||||
|
if !is_valid_page_aligned_phys_addr(vmcs_msr_bitmap) {
|
||||||
|
return Err("VMCS MSR bitmap address is not a valid page-aligned physical address");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn check_io_bitmap() -> Result<(), &'static str> {
|
fn check_io_bitmap() -> Result<(), &'static str> {
|
||||||
let vmcs_io_bitmap_a = vmread(vmcs::control::IO_BITMAP_A_ADDR_FULL)?;
|
let vmcs_io_bitmap_a = vmread(vmcs::control::IO_BITMAP_A_ADDR_FULL)?;
|
||||||
let vmcs_io_bitmap_b = vmread(vmcs::control::IO_BITMAP_B_ADDR_FULL)?;
|
let vmcs_io_bitmap_b = vmread(vmcs::control::IO_BITMAP_B_ADDR_FULL)?;
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use crate::vmm::x86_64::{common, intel::vmcs};
|
use crate::vmm::x86_64::{
|
||||||
|
common,
|
||||||
|
intel::{vmcs, vmwrite},
|
||||||
|
};
|
||||||
|
|
||||||
pub fn setup_exec_controls() -> Result<(), &'static str> {
|
pub fn setup_exec_controls() -> Result<(), &'static str> {
|
||||||
let basic_msr = common::read_msr(0x480);
|
let basic_msr = common::read_msr(0x480);
|
||||||
@ -12,8 +15,8 @@ pub fn setup_exec_controls() -> Result<(), &'static str> {
|
|||||||
raw_pin_exec_ctrl |= (reserved_bits & 0xFFFFFFFF) as u32;
|
raw_pin_exec_ctrl |= (reserved_bits & 0xFFFFFFFF) as u32;
|
||||||
raw_pin_exec_ctrl &= (reserved_bits >> 32) as u32;
|
raw_pin_exec_ctrl &= (reserved_bits >> 32) as u32;
|
||||||
|
|
||||||
let pin_exec_ctrl = vmcs::controls::PinBasedVmExecutionControls::from(raw_pin_exec_ctrl);
|
let mut pin_exec_ctrl = vmcs::controls::PinBasedVmExecutionControls::from(raw_pin_exec_ctrl);
|
||||||
//pin_exec_ctrl.set_external_interrupt_exiting(false);
|
pin_exec_ctrl.set_external_interrupt_exiting(true);
|
||||||
|
|
||||||
pin_exec_ctrl.write()?;
|
pin_exec_ctrl.write()?;
|
||||||
|
|
||||||
@ -33,6 +36,8 @@ pub fn setup_exec_controls() -> Result<(), &'static str> {
|
|||||||
primary_exec_ctrl.set_hlt(true);
|
primary_exec_ctrl.set_hlt(true);
|
||||||
primary_exec_ctrl.set_activate_secondary_controls(true);
|
primary_exec_ctrl.set_activate_secondary_controls(true);
|
||||||
primary_exec_ctrl.set_use_msr_bitmap(false);
|
primary_exec_ctrl.set_use_msr_bitmap(false);
|
||||||
|
primary_exec_ctrl.set_unconditional_io(false);
|
||||||
|
primary_exec_ctrl.set_use_io_bitmap(true);
|
||||||
|
|
||||||
primary_exec_ctrl.write()?;
|
primary_exec_ctrl.write()?;
|
||||||
|
|
||||||
@ -55,6 +60,9 @@ pub fn setup_exec_controls() -> Result<(), &'static str> {
|
|||||||
|
|
||||||
secondary_exec_ctrl.write()?;
|
secondary_exec_ctrl.write()?;
|
||||||
|
|
||||||
|
vmwrite(x86::vmx::vmcs::control::CR0_GUEST_HOST_MASK, u64::MAX)?;
|
||||||
|
vmwrite(x86::vmx::vmcs::control::CR4_GUEST_HOST_MASK, u64::MAX)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +109,7 @@ pub fn setup_exit_controls() -> Result<(), &'static str> {
|
|||||||
|
|
||||||
exit_ctrl.write()?;
|
exit_ctrl.write()?;
|
||||||
|
|
||||||
//vmwrite(0x4004, 1u64 << 6)?; // EXCEPTION_BITMAP
|
vmwrite(0x4004, 1u64 << x86::irq::INVALID_OPCODE_VECTOR)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
166
nel_os_kernel/src/vmm/x86_64/intel/cr.rs
Normal file
166
nel_os_kernel/src/vmm/x86_64/intel/cr.rs
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
use x86::vmx::vmcs;
|
||||||
|
|
||||||
|
use crate::vmm::x86_64::{
|
||||||
|
common::read_msr,
|
||||||
|
intel::{
|
||||||
|
qual::{AccessType, QualCr, Register},
|
||||||
|
vcpu::IntelVCpu,
|
||||||
|
vmread, vmwrite,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn handle_cr_access(vcpu: &mut IntelVCpu, qual: &QualCr) -> Result<(), &'static str> {
|
||||||
|
match qual.access_type() {
|
||||||
|
AccessType::MovTo => match qual.index() {
|
||||||
|
0 | 4 => {
|
||||||
|
passthrough_write(vcpu, qual)?;
|
||||||
|
update_ia32e(vcpu)?;
|
||||||
|
}
|
||||||
|
_ => panic!("Unsupported CR index: {}", qual.index()),
|
||||||
|
},
|
||||||
|
AccessType::MovFrom => passthrough_read(vcpu, qual)?,
|
||||||
|
_ => {
|
||||||
|
panic!("Unsupported CR access type: {:?}", qual.access_type());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn passthrough_read(vcpu: &mut IntelVCpu, qual: &QualCr) -> Result<(), &'static str> {
|
||||||
|
let value = match qual.index() {
|
||||||
|
3 => vmread(x86::vmx::vmcs::guest::CR3)?,
|
||||||
|
_ => panic!("Unsupported CR index: {}", qual.index()),
|
||||||
|
};
|
||||||
|
|
||||||
|
set_value(vcpu, qual, value)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn passthrough_write(vcpu: &mut IntelVCpu, qual: &QualCr) -> Result<(), &'static str> {
|
||||||
|
let value = get_value(vcpu, qual)?;
|
||||||
|
match qual.index() {
|
||||||
|
0 => {
|
||||||
|
vmwrite(vmcs::guest::CR0, adjust_cr0(value))?;
|
||||||
|
vmwrite(vmcs::control::CR0_READ_SHADOW, value)?;
|
||||||
|
}
|
||||||
|
4 => {
|
||||||
|
vmwrite(vmcs::guest::CR4, adjust_cr4(value))?;
|
||||||
|
vmwrite(vmcs::control::CR4_READ_SHADOW, value)?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Unsupported CR index: {}", qual.index());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_ia32e(vcpu: &mut IntelVCpu) -> Result<(), &'static str> {
|
||||||
|
let cr0 = vmread(x86::vmx::vmcs::guest::CR0)?;
|
||||||
|
let cr4 = vmread(x86::vmx::vmcs::guest::CR4)?;
|
||||||
|
let ia32e_enabled = (cr0 & 1 << 31) != 0 && (cr4 & 1 << 5) != 0;
|
||||||
|
|
||||||
|
vcpu.ia32e_enabled = ia32e_enabled;
|
||||||
|
|
||||||
|
let mut entry_ctrl = super::vmcs::controls::EntryControls::read()?;
|
||||||
|
entry_ctrl.set_ia32e_mode_guest(ia32e_enabled);
|
||||||
|
entry_ctrl.write()?;
|
||||||
|
|
||||||
|
let mut efer = vmread(x86::vmx::vmcs::guest::IA32_EFER_FULL)?;
|
||||||
|
|
||||||
|
let lma = (vcpu.ia32e_enabled as u64) << 10;
|
||||||
|
if lma != 0 {
|
||||||
|
efer |= lma;
|
||||||
|
} else {
|
||||||
|
efer &= !lma;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lme = if cr0 & (1 << 31) != 0 {
|
||||||
|
efer & (1 << 10)
|
||||||
|
} else {
|
||||||
|
efer & !(1 << 8)
|
||||||
|
};
|
||||||
|
if lme != 0 {
|
||||||
|
efer |= lme;
|
||||||
|
} else {
|
||||||
|
efer &= lme;
|
||||||
|
}
|
||||||
|
|
||||||
|
vmwrite(x86::vmx::vmcs::guest::IA32_EFER_FULL, efer)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn adjust_cr0(value: u64) -> u64 {
|
||||||
|
let mut result = value;
|
||||||
|
|
||||||
|
let cr0_fixed0 = read_msr(x86::msr::IA32_VMX_CR0_FIXED0);
|
||||||
|
let cr0_fixed1 = read_msr(x86::msr::IA32_VMX_CR0_FIXED1);
|
||||||
|
|
||||||
|
result |= cr0_fixed0;
|
||||||
|
result &= cr0_fixed1;
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn adjust_cr4(value: u64) -> u64 {
|
||||||
|
let mut result = value;
|
||||||
|
|
||||||
|
let cr4_fixed0 = read_msr(x86::msr::IA32_VMX_CR4_FIXED0);
|
||||||
|
let cr4_fixed1 = read_msr(x86::msr::IA32_VMX_CR4_FIXED1);
|
||||||
|
|
||||||
|
result |= cr4_fixed0;
|
||||||
|
result &= cr4_fixed1;
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_value(vcpu: &mut IntelVCpu, qual: &QualCr, value: u64) -> Result<(), &'static str> {
|
||||||
|
let guest_regs = &mut vcpu.guest_registers;
|
||||||
|
|
||||||
|
match qual.register() {
|
||||||
|
Register::Rax => guest_regs.rax = value,
|
||||||
|
Register::Rcx => guest_regs.rcx = value,
|
||||||
|
Register::Rdx => guest_regs.rdx = value,
|
||||||
|
Register::Rbx => guest_regs.rbx = value,
|
||||||
|
Register::Rbp => guest_regs.rbp = value,
|
||||||
|
Register::Rsi => guest_regs.rsi = value,
|
||||||
|
Register::Rdi => guest_regs.rdi = value,
|
||||||
|
Register::R8 => guest_regs.r8 = value,
|
||||||
|
Register::R9 => guest_regs.r9 = value,
|
||||||
|
Register::R10 => guest_regs.r10 = value,
|
||||||
|
Register::R11 => guest_regs.r11 = value,
|
||||||
|
Register::R12 => guest_regs.r12 = value,
|
||||||
|
Register::R13 => guest_regs.r13 = value,
|
||||||
|
Register::R14 => guest_regs.r14 = value,
|
||||||
|
Register::R15 => guest_regs.r15 = value,
|
||||||
|
Register::Rsp => vmwrite(x86::vmx::vmcs::guest::RSP, value)?,
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_value(vcpu: &mut IntelVCpu, qual: &QualCr) -> Result<u64, &'static str> {
|
||||||
|
let guest_regs = &mut vcpu.guest_registers;
|
||||||
|
|
||||||
|
Ok(match qual.register() {
|
||||||
|
Register::Rax => guest_regs.rax,
|
||||||
|
Register::Rcx => guest_regs.rcx,
|
||||||
|
Register::Rdx => guest_regs.rdx,
|
||||||
|
Register::Rbx => guest_regs.rbx,
|
||||||
|
Register::Rbp => guest_regs.rbp,
|
||||||
|
Register::Rsi => guest_regs.rsi,
|
||||||
|
Register::Rdi => guest_regs.rdi,
|
||||||
|
Register::R8 => guest_regs.r8,
|
||||||
|
Register::R9 => guest_regs.r9,
|
||||||
|
Register::R10 => guest_regs.r10,
|
||||||
|
Register::R11 => guest_regs.r11,
|
||||||
|
Register::R12 => guest_regs.r12,
|
||||||
|
Register::R13 => guest_regs.r13,
|
||||||
|
Register::R14 => guest_regs.r14,
|
||||||
|
Register::R15 => guest_regs.r15,
|
||||||
|
Register::Rsp => vmread(x86::vmx::vmcs::guest::RSP)?,
|
||||||
|
})
|
||||||
|
}
|
67
nel_os_kernel/src/vmm/x86_64/intel/fpu.rs
Normal file
67
nel_os_kernel/src/vmm/x86_64/intel/fpu.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
use modular_bitfield::{bitfield, prelude::B44};
|
||||||
|
|
||||||
|
use crate::vmm::x86_64::intel::vcpu::IntelVCpu;
|
||||||
|
|
||||||
|
#[bitfield]
|
||||||
|
#[repr(u64)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct XCR0 {
|
||||||
|
pub x87: bool,
|
||||||
|
pub sse: bool,
|
||||||
|
pub avx: bool,
|
||||||
|
pub bndreg: bool,
|
||||||
|
pub bndcsr: bool,
|
||||||
|
pub opmask: bool,
|
||||||
|
pub zmm_hi256: bool,
|
||||||
|
pub hi16_zmm: bool,
|
||||||
|
pub pt: bool,
|
||||||
|
pub pkru: bool,
|
||||||
|
pub pasid: bool,
|
||||||
|
pub cet_u: bool,
|
||||||
|
pub cet_s: bool,
|
||||||
|
pub hdc: bool,
|
||||||
|
pub intr: bool,
|
||||||
|
pub lbr: bool,
|
||||||
|
pub hwp: bool,
|
||||||
|
pub xtilecfg: bool,
|
||||||
|
pub xtiledata: bool,
|
||||||
|
pub apx: bool,
|
||||||
|
#[skip]
|
||||||
|
_reserved: B44,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_xcr(vcpu: &mut IntelVCpu, index: u32, xcr: u64) -> Result<(), &'static str> {
|
||||||
|
if index != 0 {
|
||||||
|
return Err("Invalid XCR index");
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(xcr & 0b1 != 0) {
|
||||||
|
return Err("X87 is not enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xcr & 0b100 != 0) && !(xcr & 0b10 != 0) {
|
||||||
|
return Err("SSE is not enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(xcr & 0b1000) != (!(xcr & 0b10000)) {
|
||||||
|
return Err("BNDREGS and BNDCSR are not both enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if xcr & 0b11100000 != 0 {
|
||||||
|
if !(xcr & 0b100 != 0) {
|
||||||
|
return Err("YMM bits are not enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xcr & 0b11100000) != 0b11100000 {
|
||||||
|
return Err("Invalid bits set in XCR0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xcr & 0b1000000000000 != 0) && (xcr & 0b1000000000000 != 0b1000000000000) {
|
||||||
|
return Err("xtile bits are not both enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
vcpu.guest_xcr0 = XCR0::from(xcr);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
367
nel_os_kernel/src/vmm/x86_64/intel/io.rs
Normal file
367
nel_os_kernel/src/vmm/x86_64/intel/io.rs
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
use x86::vmx::{self, vmcs};
|
||||||
|
use x86_64::structures::paging::{FrameAllocator, PhysFrame, Size4KiB};
|
||||||
|
|
||||||
|
use super::qual::QualIo;
|
||||||
|
use crate::{
|
||||||
|
info,
|
||||||
|
interrupt::subscriber::InterruptContext,
|
||||||
|
vmm::x86_64::intel::{
|
||||||
|
register::GuestRegisters, vmcs::controls::EntryIntrInfo, vmread, vmwrite,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn vmm_interrupt_subscriber(vcpu_ptr: *mut core::ffi::c_void, context: &InterruptContext) {
|
||||||
|
if vcpu_ptr.is_null() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let vcpu = unsafe { &mut *(vcpu_ptr as *mut super::vcpu::IntelVCpu) };
|
||||||
|
|
||||||
|
if 0x20 <= context.vector && context.vector <= 0x20 + 16 {
|
||||||
|
let irq = context.vector - 0x20;
|
||||||
|
vcpu.pending_irq |= 1 << irq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum InitPhase {
|
||||||
|
Uninitialized,
|
||||||
|
Phase1,
|
||||||
|
Phase2,
|
||||||
|
Phase3,
|
||||||
|
Initialized,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ReadSel {
|
||||||
|
IRR,
|
||||||
|
ISR,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PIC {
|
||||||
|
pub primary_mask: u8,
|
||||||
|
pub secondary_mask: u8,
|
||||||
|
pub primary_phase: InitPhase,
|
||||||
|
pub secondary_phase: InitPhase,
|
||||||
|
pub primary_base: u8,
|
||||||
|
pub secondary_base: u8,
|
||||||
|
pub primary_irr: u8,
|
||||||
|
pub primary_isr: u8,
|
||||||
|
pub secondary_irr: u8,
|
||||||
|
pub secondary_isr: u8,
|
||||||
|
pub primary_read_sel: ReadSel,
|
||||||
|
pub secondary_read_sel: ReadSel,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PIC {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
primary_mask: 0xFF,
|
||||||
|
secondary_mask: 0xFF,
|
||||||
|
primary_phase: InitPhase::Uninitialized,
|
||||||
|
secondary_phase: InitPhase::Uninitialized,
|
||||||
|
primary_base: 0,
|
||||||
|
secondary_base: 0,
|
||||||
|
primary_irr: 0,
|
||||||
|
primary_isr: 0,
|
||||||
|
secondary_irr: 0,
|
||||||
|
secondary_isr: 0,
|
||||||
|
primary_read_sel: ReadSel::IRR,
|
||||||
|
secondary_read_sel: ReadSel::IRR,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_io(&mut self, regs: &mut GuestRegisters, qual: QualIo) {
|
||||||
|
match qual.direction() {
|
||||||
|
0 => {
|
||||||
|
self.handle_io_out(regs, qual);
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
self.handle_io_in(regs, qual);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inject_external_interrupt(
|
||||||
|
&mut self,
|
||||||
|
pending_irq: &mut u16,
|
||||||
|
) -> Result<bool, &'static str> {
|
||||||
|
let pending = *pending_irq;
|
||||||
|
|
||||||
|
if pending == 0 {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.primary_phase != InitPhase::Initialized {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let eflags = vmread(vmx::vmcs::guest::RFLAGS)?;
|
||||||
|
if eflags >> 9 & 1 == 0 {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let interruptibility = vmread(vmx::vmcs::guest::INTERRUPTIBILITY_STATE)?;
|
||||||
|
if interruptibility & 0x3 != 0 {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_secondary_masked = (self.primary_mask >> 2) & 1 != 0;
|
||||||
|
|
||||||
|
for i in 0..16 {
|
||||||
|
if is_secondary_masked && i >= 8 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let irq_bit = 1 << i;
|
||||||
|
if pending & irq_bit == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let delta = if i < 8 { i } else { i - 8 };
|
||||||
|
let is_masked = if i < 8 {
|
||||||
|
(self.primary_mask >> delta) & 1 != 0
|
||||||
|
} else {
|
||||||
|
let is_irq_masked = (self.secondary_mask >> delta) & 1 != 0;
|
||||||
|
is_secondary_masked || is_irq_masked
|
||||||
|
};
|
||||||
|
|
||||||
|
if is_masked {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let interrupt_info = EntryIntrInfo::new()
|
||||||
|
.with_vector(
|
||||||
|
delta as u8
|
||||||
|
+ if i < 8 {
|
||||||
|
self.primary_base
|
||||||
|
} else {
|
||||||
|
self.secondary_base
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.with_typ(0)
|
||||||
|
.with_ec_available(false)
|
||||||
|
.with_valid(true);
|
||||||
|
|
||||||
|
vmwrite(
|
||||||
|
vmx::vmcs::control::VMENTRY_INTERRUPTION_INFO_FIELD,
|
||||||
|
u32::from(interrupt_info) as u64,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
*pending_irq &= !irq_bit;
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inject_exception(
|
||||||
|
&mut self,
|
||||||
|
vector: u32,
|
||||||
|
error_code: Option<u32>,
|
||||||
|
) -> Result<(), &'static str> {
|
||||||
|
let has_error_code = match vector {
|
||||||
|
8 | 10..=14 | 17 | 21 => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let interrupt_info = EntryIntrInfo::new()
|
||||||
|
.with_vector(vector as u8)
|
||||||
|
.with_typ(3)
|
||||||
|
.with_ec_available(has_error_code)
|
||||||
|
.with_valid(true);
|
||||||
|
|
||||||
|
vmwrite(
|
||||||
|
vmx::vmcs::control::VMENTRY_INTERRUPTION_INFO_FIELD,
|
||||||
|
u32::from(interrupt_info) as u64,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if has_error_code {
|
||||||
|
let ec = error_code.unwrap_or(0);
|
||||||
|
vmwrite(vmx::vmcs::control::VMENTRY_EXCEPTION_ERR_CODE, ec as u64)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_io_in(&self, regs: &mut GuestRegisters, qual: QualIo) {
|
||||||
|
match qual.port() {
|
||||||
|
0x0CF8..=0x0CFF => regs.rax = 0,
|
||||||
|
0xC000..=0xCFFF => {} //ignore
|
||||||
|
0x20..=0x21 => self.handle_pic_in(regs, qual),
|
||||||
|
0xA0..=0xA1 => self.handle_pic_in(regs, qual),
|
||||||
|
0x0070..=0x0071 => regs.rax = 0,
|
||||||
|
_ => regs.rax = 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_io_out(&mut self, regs: &mut GuestRegisters, qual: QualIo) {
|
||||||
|
match qual.port() {
|
||||||
|
0x0CF8..=0x0CFF => {} //ignore
|
||||||
|
0xC000..=0xCFFF => {} //ignore
|
||||||
|
0x20..=0x21 => self.handle_pic_out(regs, qual),
|
||||||
|
0xA0..=0xA1 => self.handle_pic_out(regs, qual),
|
||||||
|
0x0070..=0x0071 => {} //ignore
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_pic_in(&self, regs: &mut GuestRegisters, qual: QualIo) {
|
||||||
|
match qual.port() {
|
||||||
|
0x20 => {
|
||||||
|
let v = match self.primary_read_sel {
|
||||||
|
ReadSel::IRR => self.primary_irr,
|
||||||
|
ReadSel::ISR => self.primary_isr,
|
||||||
|
};
|
||||||
|
regs.rax = v as u64;
|
||||||
|
}
|
||||||
|
0xA0 => {
|
||||||
|
let v = match self.secondary_read_sel {
|
||||||
|
ReadSel::IRR => self.secondary_irr,
|
||||||
|
ReadSel::ISR => self.secondary_isr,
|
||||||
|
};
|
||||||
|
regs.rax = v as u64;
|
||||||
|
}
|
||||||
|
0x21 => match self.primary_phase {
|
||||||
|
InitPhase::Uninitialized | InitPhase::Initialized => {
|
||||||
|
regs.rax = self.primary_mask as u64;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
0xA1 => match self.secondary_phase {
|
||||||
|
InitPhase::Uninitialized | InitPhase::Initialized => {
|
||||||
|
regs.rax = self.secondary_mask as u64;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_pic_out(&mut self, regs: &mut GuestRegisters, qual: QualIo) {
|
||||||
|
let pic = self;
|
||||||
|
let dx = regs.rax as u8;
|
||||||
|
match qual.port() {
|
||||||
|
0x20 => match dx {
|
||||||
|
0x11 => pic.primary_phase = InitPhase::Phase1,
|
||||||
|
0x0A => pic.primary_read_sel = ReadSel::ISR,
|
||||||
|
0x0B => pic.primary_read_sel = ReadSel::IRR,
|
||||||
|
0x20 => {
|
||||||
|
pic.primary_isr = 0;
|
||||||
|
}
|
||||||
|
0x60..=0x67 => {
|
||||||
|
let irq = dx & 0x7;
|
||||||
|
pic.primary_isr &= !(1 << irq);
|
||||||
|
}
|
||||||
|
_ => panic!("Primary PIC command: {:#x}", dx),
|
||||||
|
},
|
||||||
|
0x21 => match pic.primary_phase {
|
||||||
|
InitPhase::Uninitialized | InitPhase::Initialized => pic.primary_mask = dx,
|
||||||
|
InitPhase::Phase1 => {
|
||||||
|
pic.primary_base = dx;
|
||||||
|
pic.primary_phase = InitPhase::Phase2;
|
||||||
|
}
|
||||||
|
InitPhase::Phase2 => {
|
||||||
|
pic.primary_phase = InitPhase::Phase3;
|
||||||
|
}
|
||||||
|
InitPhase::Phase3 => {
|
||||||
|
info!("Primary PIC Initialized");
|
||||||
|
pic.primary_phase = InitPhase::Initialized
|
||||||
|
}
|
||||||
|
},
|
||||||
|
0xA0 => match dx {
|
||||||
|
0x11 => pic.secondary_phase = InitPhase::Phase1,
|
||||||
|
0x0A => pic.secondary_read_sel = ReadSel::ISR,
|
||||||
|
0x0B => pic.secondary_read_sel = ReadSel::IRR,
|
||||||
|
0x20 => {
|
||||||
|
pic.secondary_isr = 0;
|
||||||
|
}
|
||||||
|
0x60..=0x67 => {
|
||||||
|
let irq = dx & 0x7;
|
||||||
|
pic.secondary_isr &= !(1 << irq);
|
||||||
|
}
|
||||||
|
_ => panic!("Secondary PIC command: {:#x}", dx),
|
||||||
|
},
|
||||||
|
0xA1 => match pic.secondary_phase {
|
||||||
|
InitPhase::Uninitialized | InitPhase::Initialized => pic.secondary_mask = dx,
|
||||||
|
InitPhase::Phase1 => {
|
||||||
|
pic.secondary_base = dx;
|
||||||
|
pic.secondary_phase = InitPhase::Phase2;
|
||||||
|
}
|
||||||
|
InitPhase::Phase2 => {
|
||||||
|
pic.secondary_phase = InitPhase::Phase3;
|
||||||
|
}
|
||||||
|
InitPhase::Phase3 => {
|
||||||
|
info!("Secondary PIC Initialized");
|
||||||
|
pic.secondary_phase = InitPhase::Initialized
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IOBitmap {
|
||||||
|
pub bitmap_a: PhysFrame,
|
||||||
|
pub bitmap_b: PhysFrame,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IOBitmap {
|
||||||
|
pub fn new(frame_allocator: &mut impl FrameAllocator<Size4KiB>) -> Self {
|
||||||
|
let bitmap_a = frame_allocator
|
||||||
|
.allocate_frame()
|
||||||
|
.expect("Failed to allocate I/O bitmap A");
|
||||||
|
let bitmap_b = frame_allocator
|
||||||
|
.allocate_frame()
|
||||||
|
.expect("Failed to allocate I/O bitmap B");
|
||||||
|
|
||||||
|
Self { bitmap_a, bitmap_b }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup(&mut self) -> Result<(), &'static str> {
|
||||||
|
let bitmap_a_addr = self.bitmap_a.start_address().as_u64() as usize;
|
||||||
|
let bitmap_b_addr = self.bitmap_b.start_address().as_u64() as usize;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
core::ptr::write_bytes(bitmap_a_addr as *mut u8, u8::MAX, 4096);
|
||||||
|
core::ptr::write_bytes(bitmap_b_addr as *mut u8, u8::MAX, 4096);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_io_ports(0x02F8..=0x03FF);
|
||||||
|
self.set_io_ports(0x0040..=0x0047);
|
||||||
|
|
||||||
|
vmwrite(vmcs::control::IO_BITMAP_A_ADDR_FULL, bitmap_a_addr as u64)?;
|
||||||
|
vmwrite(vmcs::control::IO_BITMAP_B_ADDR_FULL, bitmap_b_addr as u64)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_io_ports(&mut self, ports: core::ops::RangeInclusive<u16>) {
|
||||||
|
for port in ports {
|
||||||
|
if port <= 0x7FFF {
|
||||||
|
let byte_index = port as usize / 8;
|
||||||
|
let bit_index = port as usize % 8;
|
||||||
|
|
||||||
|
self.get_bitmap_a()[byte_index] &= !(1 << bit_index);
|
||||||
|
} else {
|
||||||
|
let adjusted_port = port - 0x8000;
|
||||||
|
let byte_index = adjusted_port as usize / 8;
|
||||||
|
let bit_index = adjusted_port as usize % 8;
|
||||||
|
|
||||||
|
self.get_bitmap_b()[byte_index] &= !(1 << bit_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_bitmap_a(&self) -> &mut [u8] {
|
||||||
|
unsafe {
|
||||||
|
core::slice::from_raw_parts_mut(self.bitmap_a.start_address().as_u64() as *mut u8, 4096)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_bitmap_b(&self) -> &mut [u8] {
|
||||||
|
unsafe {
|
||||||
|
core::slice::from_raw_parts_mut(self.bitmap_b.start_address().as_u64() as *mut u8, 4096)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,12 @@ pub mod asm;
|
|||||||
mod auditor;
|
mod auditor;
|
||||||
mod controls;
|
mod controls;
|
||||||
mod cpuid;
|
mod cpuid;
|
||||||
|
mod cr;
|
||||||
mod ept;
|
mod ept;
|
||||||
|
mod fpu;
|
||||||
|
mod io;
|
||||||
mod msr;
|
mod msr;
|
||||||
|
mod qual;
|
||||||
mod register;
|
mod register;
|
||||||
pub mod vcpu;
|
pub mod vcpu;
|
||||||
mod vmcs;
|
mod vmcs;
|
||||||
|
@ -92,7 +92,7 @@ pub fn register_msrs(vcpu: &mut IntelVCpu) -> Result<(), MsrError> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_msrs(vcpu: &mut IntelVCpu) -> Result<(), MsrError> {
|
pub fn _update_msrs(vcpu: &mut IntelVCpu) -> Result<(), MsrError> {
|
||||||
info!("updating MSRs");
|
info!("updating MSRs");
|
||||||
let indices_to_update: alloc::vec::Vec<u32> = vcpu
|
let indices_to_update: alloc::vec::Vec<u32> = vcpu
|
||||||
.host_msr
|
.host_msr
|
||||||
@ -101,8 +101,6 @@ pub fn update_msrs(vcpu: &mut IntelVCpu) -> Result<(), MsrError> {
|
|||||||
.map(|entry| entry.index)
|
.map(|entry| entry.index)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
info!("1");
|
|
||||||
|
|
||||||
for index in indices_to_update {
|
for index in indices_to_update {
|
||||||
info!("{}", index);
|
info!("{}", index);
|
||||||
let value = read_msr(index);
|
let value = read_msr(index);
|
||||||
@ -110,25 +108,21 @@ pub fn update_msrs(vcpu: &mut IntelVCpu) -> Result<(), MsrError> {
|
|||||||
vcpu.host_msr.set_by_index(index, value).unwrap();
|
vcpu.host_msr.set_by_index(index, value).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("2");
|
|
||||||
vmwrite(
|
vmwrite(
|
||||||
vmcs::control::VMEXIT_MSR_LOAD_COUNT,
|
vmcs::control::VMEXIT_MSR_LOAD_COUNT,
|
||||||
vcpu.host_msr.saved_ents().len() as u64,
|
vcpu.host_msr.saved_ents().len() as u64,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
info!("3");
|
|
||||||
vmwrite(
|
vmwrite(
|
||||||
vmcs::control::VMEXIT_MSR_STORE_COUNT,
|
vmcs::control::VMEXIT_MSR_STORE_COUNT,
|
||||||
vcpu.guest_msr.saved_ents().len() as u64,
|
vcpu.guest_msr.saved_ents().len() as u64,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
info!("4");
|
|
||||||
vmwrite(
|
vmwrite(
|
||||||
vmcs::control::VMENTRY_MSR_LOAD_COUNT,
|
vmcs::control::VMENTRY_MSR_LOAD_COUNT,
|
||||||
vcpu.guest_msr.saved_ents().len() as u64,
|
vcpu.guest_msr.saved_ents().len() as u64,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
info!("5");
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
124
nel_os_kernel/src/vmm/x86_64/intel/qual.rs
Normal file
124
nel_os_kernel/src/vmm/x86_64/intel/qual.rs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use core::convert::TryFrom;
|
||||||
|
use core::fmt::Debug;
|
||||||
|
|
||||||
|
use modular_bitfield::prelude::{B1, B16, B32, B4, B8};
|
||||||
|
use modular_bitfield::{bitfield, Specifier};
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Specifier, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum AccessType {
|
||||||
|
MovTo = 0,
|
||||||
|
MovFrom = 1,
|
||||||
|
Clts = 2,
|
||||||
|
Lmsw = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for AccessType {
|
||||||
|
type Error = &'static str;
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0 => Ok(AccessType::MovTo),
|
||||||
|
1 => Ok(AccessType::MovFrom),
|
||||||
|
2 => Ok(AccessType::Clts),
|
||||||
|
3 => Ok(AccessType::Lmsw),
|
||||||
|
_ => Err("Invalid AccessType value"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Specifier, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum LmswOperandType {
|
||||||
|
Reg = 0,
|
||||||
|
Mem = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for LmswOperandType {
|
||||||
|
type Error = &'static str;
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0 => Ok(LmswOperandType::Reg),
|
||||||
|
1 => Ok(LmswOperandType::Mem),
|
||||||
|
_ => Err("Invalid LmswOperandType value"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Specifier, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Register {
|
||||||
|
Rax = 0,
|
||||||
|
Rcx = 1,
|
||||||
|
Rdx = 2,
|
||||||
|
Rbx = 3,
|
||||||
|
Rsp = 4,
|
||||||
|
Rbp = 5,
|
||||||
|
Rsi = 6,
|
||||||
|
Rdi = 7,
|
||||||
|
R8 = 8,
|
||||||
|
R9 = 9,
|
||||||
|
R10 = 10,
|
||||||
|
R11 = 11,
|
||||||
|
R12 = 12,
|
||||||
|
R13 = 13,
|
||||||
|
R14 = 14,
|
||||||
|
R15 = 15,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for Register {
|
||||||
|
type Error = &'static str;
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0 => Ok(Register::Rax),
|
||||||
|
1 => Ok(Register::Rcx),
|
||||||
|
2 => Ok(Register::Rdx),
|
||||||
|
3 => Ok(Register::Rbx),
|
||||||
|
4 => Ok(Register::Rsp),
|
||||||
|
5 => Ok(Register::Rbp),
|
||||||
|
6 => Ok(Register::Rsi),
|
||||||
|
7 => Ok(Register::Rdi),
|
||||||
|
8 => Ok(Register::R8),
|
||||||
|
9 => Ok(Register::R9),
|
||||||
|
10 => Ok(Register::R10),
|
||||||
|
11 => Ok(Register::R11),
|
||||||
|
12 => Ok(Register::R12),
|
||||||
|
13 => Ok(Register::R13),
|
||||||
|
14 => Ok(Register::R14),
|
||||||
|
15 => Ok(Register::R15),
|
||||||
|
_ => Err("Invalid Register value"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield]
|
||||||
|
#[repr(u64)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct QualCr {
|
||||||
|
pub index: B4,
|
||||||
|
#[bits = 2]
|
||||||
|
pub access_type: AccessType,
|
||||||
|
#[bits = 1]
|
||||||
|
pub lmsw_operand_type: LmswOperandType,
|
||||||
|
_reserved1: B1,
|
||||||
|
#[bits = 4]
|
||||||
|
pub register: Register,
|
||||||
|
_reserved2: B4,
|
||||||
|
pub lmsw_source: B16,
|
||||||
|
_reseved3: B32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield]
|
||||||
|
#[repr(u64)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct QualIo {
|
||||||
|
pub size: B4,
|
||||||
|
pub direction: B1,
|
||||||
|
pub string: B1,
|
||||||
|
pub rep: B1,
|
||||||
|
pub operand_encoding: B1,
|
||||||
|
_reserved1: B8,
|
||||||
|
pub port: B16,
|
||||||
|
_reserved2: B32,
|
||||||
|
}
|
@ -1,4 +1,10 @@
|
|||||||
|
use core::arch::{
|
||||||
|
asm,
|
||||||
|
x86_64::{_xgetbv, _xsetbv},
|
||||||
|
};
|
||||||
|
|
||||||
use raw_cpuid::cpuid;
|
use raw_cpuid::cpuid;
|
||||||
|
use x86::controlregs::cr4;
|
||||||
use x86_64::{
|
use x86_64::{
|
||||||
registers::control::Cr4Flags,
|
registers::control::Cr4Flags,
|
||||||
structures::paging::{FrameAllocator, Size4KiB},
|
structures::paging::{FrameAllocator, Size4KiB},
|
||||||
@ -6,13 +12,16 @@ use x86_64::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
info,
|
info, interrupt,
|
||||||
vmm::{
|
vmm::{
|
||||||
x86_64::{
|
x86_64::{
|
||||||
common::{self, read_msr},
|
common::{self, read_msr},
|
||||||
intel::{
|
intel::{
|
||||||
auditor, controls, cpuid, ept,
|
auditor, controls, cpuid, ept,
|
||||||
|
fpu::{self, XCR0},
|
||||||
|
io::{vmm_interrupt_subscriber, IOBitmap},
|
||||||
msr::{self, ShadowMsr},
|
msr::{self, ShadowMsr},
|
||||||
|
qual::{QualCr, QualIo},
|
||||||
register::GuestRegisters,
|
register::GuestRegisters,
|
||||||
vmcs::{
|
vmcs::{
|
||||||
self,
|
self,
|
||||||
@ -42,6 +51,12 @@ pub struct IntelVCpu {
|
|||||||
guest_memory_size: u64,
|
guest_memory_size: u64,
|
||||||
pub host_msr: ShadowMsr,
|
pub host_msr: ShadowMsr,
|
||||||
pub guest_msr: ShadowMsr,
|
pub guest_msr: ShadowMsr,
|
||||||
|
pub ia32e_enabled: bool,
|
||||||
|
pic: super::io::PIC,
|
||||||
|
io_bitmap: IOBitmap,
|
||||||
|
pub pending_irq: u16,
|
||||||
|
pub host_xcr0: u64,
|
||||||
|
pub guest_xcr0: XCR0,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntelVCpu {
|
impl IntelVCpu {
|
||||||
@ -72,11 +87,25 @@ impl IntelVCpu {
|
|||||||
|
|
||||||
match exit_reason {
|
match exit_reason {
|
||||||
VmxExitReason::HLT => {
|
VmxExitReason::HLT => {
|
||||||
info!("VM hlt");
|
let injected = self
|
||||||
|
.pic
|
||||||
|
.inject_external_interrupt(&mut self.pending_irq)
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if !injected {
|
||||||
|
unsafe {
|
||||||
|
asm!("sti");
|
||||||
|
asm!("nop");
|
||||||
|
asm!("cli");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vmwrite(vmcs::guest::ACTIVITY_STATE, 0)?;
|
||||||
|
vmwrite(vmcs::guest::INTERRUPTIBILITY_STATE, 0)?;
|
||||||
|
|
||||||
self.step_next_inst()?;
|
self.step_next_inst()?;
|
||||||
}
|
}
|
||||||
VmxExitReason::CPUID => {
|
VmxExitReason::CPUID => {
|
||||||
info!("VM exit reason: CPUID");
|
|
||||||
cpuid::handle_cpuid_vmexit(self);
|
cpuid::handle_cpuid_vmexit(self);
|
||||||
self.step_next_inst()?;
|
self.step_next_inst()?;
|
||||||
}
|
}
|
||||||
@ -88,11 +117,124 @@ impl IntelVCpu {
|
|||||||
msr::ShadowMsr::handle_wrmsr_vmexit(self);
|
msr::ShadowMsr::handle_wrmsr_vmexit(self);
|
||||||
self.step_next_inst()?;
|
self.step_next_inst()?;
|
||||||
}
|
}
|
||||||
|
VmxExitReason::CONTROL_REGISTER_ACCESSES => {
|
||||||
|
let qual = vmread(vmcs::ro::EXIT_QUALIFICATION)?;
|
||||||
|
let qual = QualCr::from(qual);
|
||||||
|
|
||||||
|
super::cr::handle_cr_access(self, &qual)?;
|
||||||
|
|
||||||
|
self.step_next_inst()?;
|
||||||
|
}
|
||||||
|
VmxExitReason::XSETBV => {
|
||||||
|
fpu::set_xcr(
|
||||||
|
self,
|
||||||
|
self.guest_registers.rcx as u32,
|
||||||
|
self.guest_registers.rax,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.step_next_inst()?;
|
||||||
|
}
|
||||||
|
VmxExitReason::IO_INSTRUCTION => {
|
||||||
|
let qual = vmread(vmcs::ro::EXIT_QUALIFICATION)?;
|
||||||
|
let qual_io = QualIo::from(qual);
|
||||||
|
|
||||||
|
self.pic.handle_io(&mut self.guest_registers, qual_io);
|
||||||
|
|
||||||
|
self.step_next_inst()?;
|
||||||
|
}
|
||||||
|
VmxExitReason::EXTERNAL_INTERRUPT => {
|
||||||
|
vmwrite(vmcs::ro::VMEXIT_INTERRUPTION_INFO, 0)?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
asm!("sti");
|
||||||
|
asm!("nop");
|
||||||
|
asm!("cli");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.pic.inject_external_interrupt(&mut self.pending_irq)?;
|
||||||
|
}
|
||||||
VmxExitReason::EPT_VIOLATION => {
|
VmxExitReason::EPT_VIOLATION => {
|
||||||
let guest_address = vmread(vmcs::ro::GUEST_PHYSICAL_ADDR_FULL)?;
|
let guest_address = vmread(vmcs::ro::GUEST_PHYSICAL_ADDR_FULL)?;
|
||||||
info!("EPT Violation at guest address: {:#x}", guest_address);
|
info!("EPT Violation at guest address: {:#x}", guest_address);
|
||||||
return Err("EPT Violation");
|
return Err("EPT Violation");
|
||||||
}
|
}
|
||||||
|
VmxExitReason::TRIPLE_FAULT => {
|
||||||
|
info!("Triple fault detected");
|
||||||
|
return Err("Triple fault");
|
||||||
|
}
|
||||||
|
VmxExitReason::EXCEPTION => {
|
||||||
|
let vmexit_intr_info = vmread(vmcs::ro::VMEXIT_INTERRUPTION_INFO).unwrap();
|
||||||
|
let vector = (vmexit_intr_info & 0xFF) as u32;
|
||||||
|
let has_error_code = (vmexit_intr_info & (1 << 11)) != 0;
|
||||||
|
|
||||||
|
let error_code = if has_error_code {
|
||||||
|
Some(vmread(vmcs::ro::VMEXIT_INTERRUPTION_ERR_CODE).unwrap() as u32)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let rip = vmread(vmcs::guest::RIP).unwrap();
|
||||||
|
|
||||||
|
let mut instruction_bytes = [0u8; 16];
|
||||||
|
let mut valid_bytes = 0;
|
||||||
|
|
||||||
|
match self.translate_guest_address(rip) {
|
||||||
|
Ok(guest_phys_addr) => {
|
||||||
|
for i in 0..16 {
|
||||||
|
match self.ept.get(guest_phys_addr + i) {
|
||||||
|
Ok(byte) => {
|
||||||
|
instruction_bytes[i as usize] = byte;
|
||||||
|
valid_bytes = i + 1;
|
||||||
|
}
|
||||||
|
Err(_) => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
info!(
|
||||||
|
"Failed to get physical address for RIP: {:#x}, {:?}",
|
||||||
|
rip, e
|
||||||
|
);
|
||||||
|
return Err("Failed to get physical address for RIP");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if valid_bytes > 0 {
|
||||||
|
match instruction_bytes[0] {
|
||||||
|
0x0F => {
|
||||||
|
if valid_bytes > 1 {
|
||||||
|
match instruction_bytes[1] {
|
||||||
|
0x01 => match instruction_bytes[2] {
|
||||||
|
0xCA => {
|
||||||
|
let rflags = vmread(vmcs::guest::RFLAGS).unwrap();
|
||||||
|
vmwrite(vmcs::guest::RFLAGS, rflags & !(1 << 18))
|
||||||
|
.unwrap();
|
||||||
|
self.step_next_inst().unwrap();
|
||||||
|
}
|
||||||
|
0xCB => {
|
||||||
|
let rflags = vmread(vmcs::guest::RFLAGS).unwrap();
|
||||||
|
vmwrite(vmcs::guest::RFLAGS, rflags | (1 << 18))
|
||||||
|
.unwrap();
|
||||||
|
self.step_next_inst().unwrap();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.pic
|
||||||
|
.inject_exception(vector, error_code)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
self.pic.inject_exception(vector, error_code).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.pic.inject_exception(vector, error_code).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
info!("VM exit reason: {:?}", exit_reason);
|
info!("VM exit reason: {:?}", exit_reason);
|
||||||
return Err("Unhandled VM exit reason");
|
return Err("Unhandled VM exit reason");
|
||||||
@ -103,6 +245,48 @@ impl IntelVCpu {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_guest_xcr0(&mut self) -> Result<(), &'static str> {
|
||||||
|
let host_cr4 = unsafe { cr4() };
|
||||||
|
if (host_cr4.bits() & Cr4Flags::OSXSAVE.bits() as usize) == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.host_xcr0 == 0 {
|
||||||
|
self.host_xcr0 = unsafe { _xgetbv(0) };
|
||||||
|
}
|
||||||
|
|
||||||
|
let guest_cr4 = vmread(x86::vmx::vmcs::guest::CR4)?;
|
||||||
|
|
||||||
|
if guest_cr4 & Cr4Flags::OSXSAVE.bits() != 0 && u64::from(self.guest_xcr0) != self.host_xcr0
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
_xsetbv(0, u64::from(self.guest_xcr0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_host_xcr0(&mut self) -> Result<(), &'static str> {
|
||||||
|
let host_cr4 = unsafe { cr4() };
|
||||||
|
if (host_cr4.bits() & Cr4Flags::OSXSAVE.bits() as usize) == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let guest_cr4 = vmread(x86::vmx::vmcs::guest::CR4)?;
|
||||||
|
|
||||||
|
if guest_cr4 & Cr4Flags::OSXSAVE.bits() != 0 {
|
||||||
|
let current_xcr0 = unsafe { _xgetbv(0) };
|
||||||
|
if current_xcr0 != self.host_xcr0 {
|
||||||
|
unsafe {
|
||||||
|
_xsetbv(0, self.host_xcr0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn step_next_inst(&mut self) -> Result<(), &'static str> {
|
fn step_next_inst(&mut self) -> Result<(), &'static str> {
|
||||||
use x86::vmx::vmcs;
|
use x86::vmx::vmcs;
|
||||||
let rip = vmread(vmcs::guest::RIP)?;
|
let rip = vmread(vmcs::guest::RIP)?;
|
||||||
@ -114,15 +298,17 @@ impl IntelVCpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn vmentry(&mut self) -> Result<(), InstructionError> {
|
fn vmentry(&mut self) -> Result<(), InstructionError> {
|
||||||
msr::update_msrs(self).unwrap();
|
|
||||||
|
|
||||||
auditor::controls::check_vmcs_control_fields().unwrap();
|
auditor::controls::check_vmcs_control_fields().unwrap();
|
||||||
|
|
||||||
let success = {
|
let success = {
|
||||||
let result: u16;
|
let result: u16;
|
||||||
|
|
||||||
|
self.load_guest_xcr0().unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
result = crate::vmm::x86_64::intel::asm::asm_vm_entry(self as *mut _);
|
result = crate::vmm::x86_64::intel::asm::asm_vm_entry(self as *mut _);
|
||||||
};
|
};
|
||||||
|
self.load_host_xcr0().unwrap();
|
||||||
|
|
||||||
result == 0
|
result == 0
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -152,6 +338,12 @@ impl IntelVCpu {
|
|||||||
controls::setup_exit_controls()?;
|
controls::setup_exit_controls()?;
|
||||||
Self::setup_host_state()?;
|
Self::setup_host_state()?;
|
||||||
self.setup_guest_state()?;
|
self.setup_guest_state()?;
|
||||||
|
self.io_bitmap.setup()?;
|
||||||
|
|
||||||
|
interrupt::subscriber::subscribe(
|
||||||
|
vmm_interrupt_subscriber,
|
||||||
|
self as &mut IntelVCpu as *mut IntelVCpu as *mut core::ffi::c_void,
|
||||||
|
)?;
|
||||||
|
|
||||||
self.init_guest_memory(frame_allocator)?;
|
self.init_guest_memory(frame_allocator)?;
|
||||||
|
|
||||||
@ -233,14 +425,18 @@ impl IntelVCpu {
|
|||||||
|
|
||||||
fn setup_guest_state(&mut self) -> Result<(), &'static str> {
|
fn setup_guest_state(&mut self) -> Result<(), &'static str> {
|
||||||
use x86::{controlregs::*, vmx::vmcs};
|
use x86::{controlregs::*, vmx::vmcs};
|
||||||
let cr0 = Cr0::empty()
|
let cr0 = (Cr0::empty()
|
||||||
| Cr0::CR0_PROTECTED_MODE
|
| Cr0::CR0_PROTECTED_MODE
|
||||||
| Cr0::CR0_NUMERIC_ERROR & !Cr0::CR0_ENABLE_PAGING;
|
| Cr0::CR0_NUMERIC_ERROR
|
||||||
|
| Cr0::CR0_EXTENSION_TYPE)
|
||||||
|
& !Cr0::CR0_ENABLE_PAGING;
|
||||||
vmwrite(vmcs::guest::CR0, cr0.bits() as u64)?;
|
vmwrite(vmcs::guest::CR0, cr0.bits() as u64)?;
|
||||||
vmwrite(vmcs::guest::CR3, unsafe { cr3() })?;
|
vmwrite(vmcs::guest::CR3, 0)?;
|
||||||
vmwrite(
|
vmwrite(
|
||||||
vmcs::guest::CR4,
|
vmcs::guest::CR4,
|
||||||
vmread(vmcs::guest::CR4)? & !Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS.bits(),
|
vmread(vmcs::guest::CR4)?
|
||||||
|
| Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS.bits()
|
||||||
|
& !Cr4Flags::PHYSICAL_ADDRESS_EXTENSION.bits(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
vmwrite(vmcs::guest::CS_BASE, 0)?;
|
vmwrite(vmcs::guest::CS_BASE, 0)?;
|
||||||
@ -341,6 +537,77 @@ impl IntelVCpu {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn translate_guest_address(&mut self, vaddr: u64) -> Result<u64, &'static str> {
|
||||||
|
let cr3 = vmread(x86::vmx::vmcs::guest::CR3).map_err(|_| "Failed to read guest CR3")?;
|
||||||
|
let pml4_base = cr3 & !0xFFF; // Clear lower 12 bits to get page table base
|
||||||
|
|
||||||
|
let efer = vmread(x86::vmx::vmcs::guest::IA32_EFER_FULL).unwrap_or(0);
|
||||||
|
let is_long_mode = (efer & (1 << 8)) != 0; // LME bit
|
||||||
|
|
||||||
|
if !is_long_mode {
|
||||||
|
return Ok(vaddr & 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
let pml4_idx = ((vaddr >> 39) & 0x1FF) as u64;
|
||||||
|
let pdpt_idx = ((vaddr >> 30) & 0x1FF) as u64;
|
||||||
|
let pd_idx = ((vaddr >> 21) & 0x1FF) as u64;
|
||||||
|
let pt_idx = ((vaddr >> 12) & 0x1FF) as u64;
|
||||||
|
let page_offset = (vaddr & 0xFFF) as u64;
|
||||||
|
|
||||||
|
let pml4_entry_addr = pml4_base + (pml4_idx * 8);
|
||||||
|
let pml4_entry = self.read_guest_phys_u64(pml4_entry_addr)?;
|
||||||
|
if (pml4_entry & 1) == 0 {
|
||||||
|
return Err("PML4 entry not present");
|
||||||
|
}
|
||||||
|
let pdpt_base = pml4_entry & 0x000FFFFFFFFFF000;
|
||||||
|
|
||||||
|
let pdpt_entry_addr = pdpt_base + (pdpt_idx * 8);
|
||||||
|
let pdpt_entry = self.read_guest_phys_u64(pdpt_entry_addr)?;
|
||||||
|
if (pdpt_entry & 1) == 0 {
|
||||||
|
return Err("PDPT entry not present");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdpt_entry & (1 << 7)) != 0 {
|
||||||
|
let page_base = pdpt_entry & 0x000FFFFFC0000000;
|
||||||
|
return Ok(page_base | (vaddr & 0x3FFFFFFF));
|
||||||
|
}
|
||||||
|
let pd_base = pdpt_entry & 0x000FFFFFFFFFF000;
|
||||||
|
|
||||||
|
let pd_entry_addr = pd_base + (pd_idx * 8);
|
||||||
|
let pd_entry = self.read_guest_phys_u64(pd_entry_addr)?;
|
||||||
|
if (pd_entry & 1) == 0 {
|
||||||
|
return Err("PD entry not present");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pd_entry & (1 << 7)) != 0 {
|
||||||
|
let page_base = pd_entry & 0x000FFFFFFFE00000;
|
||||||
|
return Ok(page_base | (vaddr & 0x1FFFFF));
|
||||||
|
}
|
||||||
|
let pt_base = pd_entry & 0x000FFFFFFFFFF000;
|
||||||
|
|
||||||
|
let pt_entry_addr = pt_base + (pt_idx * 8);
|
||||||
|
let pt_entry = self.read_guest_phys_u64(pt_entry_addr)?;
|
||||||
|
if (pt_entry & 1) == 0 {
|
||||||
|
return Err("PT entry not present");
|
||||||
|
}
|
||||||
|
let page_base = pt_entry & 0x000FFFFFFFFFF000;
|
||||||
|
|
||||||
|
Ok(page_base | page_offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_guest_phys_u64(&mut self, gpa: u64) -> Result<u64, &'static str> {
|
||||||
|
let mut result_bytes = [0u8; 8];
|
||||||
|
|
||||||
|
for i in 0..8 {
|
||||||
|
match self.ept.get(gpa + i) {
|
||||||
|
Ok(byte) => result_bytes[i as usize] = byte,
|
||||||
|
Err(_) => return Err("Failed to read from EPT"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(u64::from_le_bytes(result_bytes))
|
||||||
|
}
|
||||||
|
|
||||||
fn dump_vmcs_settings(&self) -> Result<(), &'static str> {
|
fn dump_vmcs_settings(&self) -> Result<(), &'static str> {
|
||||||
info!("=== VMCS Control Fields ===");
|
info!("=== VMCS Control Fields ===");
|
||||||
|
|
||||||
@ -638,6 +905,12 @@ impl VCpu for IntelVCpu {
|
|||||||
guest_memory_size: 1024 * 1024 * 256, // 256 MiB
|
guest_memory_size: 1024 * 1024 * 256, // 256 MiB
|
||||||
host_msr: ShadowMsr::new(),
|
host_msr: ShadowMsr::new(),
|
||||||
guest_msr: ShadowMsr::new(),
|
guest_msr: ShadowMsr::new(),
|
||||||
|
ia32e_enabled: false,
|
||||||
|
pic: super::io::PIC::new(),
|
||||||
|
io_bitmap: IOBitmap::new(frame_allocator),
|
||||||
|
pending_irq: 0,
|
||||||
|
host_xcr0: 0,
|
||||||
|
guest_xcr0: XCR0::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,3 +208,14 @@ impl PrimaryExitControls {
|
|||||||
vmcs::VmcsControl32::PRIMARY_VM_EXIT_CONTROLS.write(u32::from(*self))
|
vmcs::VmcsControl32::PRIMARY_VM_EXIT_CONTROLS.write(u32::from(*self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[bitfield]
|
||||||
|
#[repr(u32)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct EntryIntrInfo {
|
||||||
|
pub vector: B8,
|
||||||
|
pub typ: B3,
|
||||||
|
pub ec_available: bool,
|
||||||
|
_reserved: B19,
|
||||||
|
pub valid: bool,
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user