aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJohannes Stoelp <johannes.stoelp@gmail.com>2025-03-14 02:13:23 +0100
committerJohannes Stoelp <johannes.stoelp@gmail.com>2025-03-14 02:14:56 +0100
commit3ebd8b163dc8d5679d90927de1c2fcd639882362 (patch)
treef9a8c33265371606d93ddf5b350fe4e095afb3f8
parentb16851fb799b880c31cc65a9fa1aba592b4ce5b4 (diff)
downloadmini-kvm-rs-3ebd8b163dc8d5679d90927de1c2fcd639882362.tar.gz
mini-kvm-rs-3ebd8b163dc8d5679d90927de1c2fcd639882362.zip
guest: add 64bit guest to toy with msrHEADmain
Guest to toy with msr register and the swapgs instruction.
-rw-r--r--.gitignore1
-rw-r--r--examples/long_mode.rs20
-rw-r--r--guest/Makefile12
-rw-r--r--guest/guest64-msr.S91
-rw-r--r--guest/guest64.S4
5 files changed, 118 insertions, 10 deletions
diff --git a/.gitignore b/.gitignore
index 36ba112..8b62c5f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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