diff options
author | Johannes Stoelp <johannes.stoelp@gmail.com> | 2025-03-14 02:13:23 +0100 |
---|---|---|
committer | Johannes Stoelp <johannes.stoelp@gmail.com> | 2025-03-14 02:14:56 +0100 |
commit | 3ebd8b163dc8d5679d90927de1c2fcd639882362 (patch) | |
tree | f9a8c33265371606d93ddf5b350fe4e095afb3f8 | |
parent | b16851fb799b880c31cc65a9fa1aba592b4ce5b4 (diff) | |
download | mini-kvm-rs-3ebd8b163dc8d5679d90927de1c2fcd639882362.tar.gz mini-kvm-rs-3ebd8b163dc8d5679d90927de1c2fcd639882362.zip |
Guest to toy with msr register and the swapgs instruction.
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | examples/long_mode.rs | 20 | ||||
-rw-r--r-- | guest/Makefile | 12 | ||||
-rw-r--r-- | guest/guest64-msr.S | 91 | ||||
-rw-r--r-- | guest/guest64.S | 4 |
5 files changed, 118 insertions, 10 deletions
@@ -3,3 +3,4 @@ Cargo.lock sysdeps/kvm guest/guest16 guest/guest64 +guest/guest64-msr diff --git a/examples/long_mode.rs b/examples/long_mode.rs index 03a77a4..bba9751 100644 --- a/examples/long_mode.rs +++ b/examples/long_mode.rs @@ -4,6 +4,8 @@ use kvm_rs::vcpu::KvmExit; use kvm_rs::x86_64::*; use kvm_rs::{PhysAddr, UserMem}; +use std::convert::TryInto; + fn setup_long_mode_segments(sregs: &mut kvm_sys::kvm_sregs) { let code_seg = |seg: &mut kvm_sys::kvm_segment| { // Segment base address (unused in 64bit). @@ -153,6 +155,8 @@ fn main() -> std::io::Result<()> { let mut regs = vcpu.get_regs()?; // Set `rip` to 0 as we want to start executing from virtual address 0. regs.rip = 0; + // Set `rsp` (stack pointer) to the end of the guests virtual address space. + regs.rsp = 0x4000; regs.rflags = 0x2; vcpu.set_regs(regs)?; @@ -172,9 +176,19 @@ fn main() -> std::io::Result<()> { // Provide some input data. data.fill(0xaa); } - KvmExit::IoOut(_port, data) => { - let s = std::str::from_utf8(data).unwrap(); - print!("{}", s); + KvmExit::IoOut(port, data) => { + if port == 0x42 { + // Magic port to interpret any input as string. + let s = std::str::from_utf8(data).unwrap(); + print!("{}", s); + } else { + // By default format print bytes as hex string. + let val = match data.len() { + 4 => u32::from_le_bytes(data.try_into().unwrap()) as u64, + _ => todo!("unknown size {}", data.len()), + }; + println!("{:x}", val); + } } KvmExit::MmioRead(addr, data) => { println!("MMIO_READ: addr={:#x} len={}", addr, data.len()); diff --git a/guest/Makefile b/guest/Makefile index 635759a..61d7790 100644 --- a/guest/Makefile +++ b/guest/Makefile @@ -1,14 +1,16 @@ ARCH16 := i8086 ARCH64 := i386:x86-64 -guest: guest16 guest64 -disasm: disasm16 disasm64 +bits = $(word 1, $(subst -, ,$(1))) + +guest: guest16 guest64 guest64-msr +disasm: disasm16 disasm64 disasm64-msr guest%: guest.ld guest%.S - $(CC) $(CFLAGS) -m$* -o $@ -nostdlib -ffreestanding -Wpedantic -Wall -Wextra -Werror -T guest.ld guest$*.S + $(CC) $(CFLAGS) -m$(call bits, $*) -o $@ -nostdlib -ffreestanding -Wpedantic -Wall -Wextra -Werror -T guest.ld guest$*.S disasm%: guest% - objdump -D -b binary -m $(ARCH$*) -M intel $^ + objdump -D -b binary -m $(ARCH$(call bits, $*)) -M intel $^ clean: - $(RM) guest16 guest64 + $(RM) guest16 guest64 guest64-msr diff --git a/guest/guest64-msr.S b/guest/guest64-msr.S new file mode 100644 index 0000000..8e7d4a4 --- /dev/null +++ b/guest/guest64-msr.S @@ -0,0 +1,91 @@ +.intel_syntax noprefix + +// Define a string literal. +.macro defstr name str +\name: + .ascii "\str" +\name\()_len: + .8byte . - \name +.endm + +// Print a string literal. +.macro pstr name + mov dx, 0x42 // Magic IO port for strings. + lea rsi, [rip + \name] // Address of string. + mov rcx, [rip + \name\()_len] // Len of string. + rep outsb // Write ds:rsi to output port rdx. +.endm + +.section .boot, "ax", @progbits + // -- SWAPGS test ----------------------------------------------------------- + + // Setup IA32_GS_BASE. + mov rcx, 0xc0000101 + mov rax, 0xbbbbbbbb + call wrmsr + + // Setup IA32_KERNEL_GS_BASE. + mov rcx, 0xc0000102 + mov rax, 0xaaaaaaaa + call wrmsr + + // Print IA32_GS_BASE. + pstr gsbase + mov rcx, 0xc0000101 + call rdmsr + call pu64 + + // Print IA32_KERNEL_GS_BASE. + pstr kgsbase + mov rcx, 0xc0000102 + call rdmsr + call pu64 + + pstr swapgs + // Swap IA32_GS_BASE and IA32_KERNEL_GS_BASE. + swapgs + + // Print IA32_GS_BASE. + pstr gsbase + mov rcx, 0xc0000101 + call rdmsr + call pu64 + + // Print IA32_KERNEL_GS_BASE. + pstr kgsbase + mov rcx, 0xc0000102 + call rdmsr + call pu64 + + // Trigger `KVM_EXIT_HLT`. + hlt + +// in : ecx address of msr register +// out: rax value of msr register +rdmsr: + rdmsr + shl rdx, 32 + or rax, rdx + ret + +// in: ecx address of msr register +// in: rax value to write into msr register +wrmsr: + mov rdx, rax + shr rdx, 32 + wrmsr + ret + +// in: rax holds 64bit word to be printed +pu64: + xor dx, dx // Port to print values. + out dx, eax // Print lower-half (u32) of rax. + //shr rax, 32 + //out dx, eax // Print upper-half (u32) of rax. + ret + +.section .rodata, "a", @progbits +defstr fsbase, "fsbase: " +defstr gsbase, "gsbase: " +defstr kgsbase, "kernel_gsbase: " +defstr swapgs, "-- swapgs --\n" diff --git a/guest/guest64.S b/guest/guest64.S index 1ca91a5..dc3e986 100644 --- a/guest/guest64.S +++ b/guest/guest64.S @@ -2,7 +2,7 @@ .section .boot, "ax", @progbits // Trigger `KVM_EXIT_IO:KVM_EXIT_IO_OUT` by writing string to output port. - mov rdx, 0x1000 // Output port. + mov rdx, 0x42 // Output port (magic for string fmt). lea rsi, [rip + msg] // Address of string. mov rcx, [rip + msg_len] // Len of string. rep outsb // Write ds:rsi to output port rdx. @@ -30,7 +30,7 @@ .section .rodata, "a", @progbits msg: - .asciz "Hello from Long Mode!\n" + .ascii "Hello from Long Mode!\n" msg_len: .byte .-msg |