I am experimenting with the Xen kernel a bit and I found out that having some interactive Forth to talk to it is really helpful. At the end of this email I enclose some words that I am using to talk to Xen. The file gets included in my config.fth but I have initialize it by hand by running "init-xen" first.
To try the code below just setup a HVM domain with an OFW floppy image:
------------ domain cfg begin ----------------- builder = "hvm" memory = 512 vcpus = 2 name = "ofw" vnc = 1 # vnclisten = '0.0.0.0' vif = [ 'bridge=bridge0,mac=00:16:3e:76:ff:49,model=ne2k_isa' ] device_model_args = [ '-fda', 'openfirmware/cpu/x86/pc/biosload/build/floppy.img' ] vga="stdvga" videoram=16 serial = [ "tcp::4445,server,nowait" ] xen_platform_pci = 1 ------------ domain cfg end -----------------
One can use the bga video adapter with vnc. I had to comment out "create virtual-mode" since apparently any attempt to access BIOS (in the biosload setup) caused a hang there (probably unrelated to Xen/SeaBIOS).
Once the basic Xen support is working we could get OFW to work as a fully paravirtualized guest. I think that OFW could also be used as a firmware to start HVM (fully emulated) domains. Currently Xen has a little stub called "hvmloader" that loads either SeaBIOS or TianoCore (UEFI firmware).
Xen detection works (actually the code can be used to detect other hypervisors: HyperV, KVM and VMware), hypercalls also seem to work. I'd like to replace assembler code words with something nicer (a defining work building machine code on the fly with asm8, maybe?).
XenStore initialization does work, but events are not working yet. I managed to get a simple response from XenStore in the ring buffer somehow though. XenStore is said to be inspired by OpenBoot PROM and could probably be used for nvram storage.
Should I use something thread local for "hybuf" or maybe just pad would do?
How to nicely set edi in the assembler word? Which registers should not be clobbered (apparently edi is the return address)? I wasn't sure how to nicely allocate a page aligned memory.
Xen provides a memory map to the guests in the BIOS E820 format (here with "xen-get-memmap"), how can I tell Openfirmware which memory areas are really available?
Sorry in advance for my poor Forth skills! I'd love your comments on this code and information how to integrate it into the OFW codebase.
Marcin (I also hang out as "saper" on #olpc-devel)
purpose: Basic Xen support
code get-cpuid eax pop cpuid eax push ebx push ecx push edx push c;
h# 4000000 dup value >cpuidreg h# 1000 + value -cpuidreg
: 0cpuidreg h# 40000000 dup to >cpuidreg h# 1000 + to -cpuidreg ;
cpuidreg h# 100 + dup to >cpuidreg
-cpuidreg >= ;
: this-xen? get-cpuid xor xor nip h# 7e7b7e7b = ;
: (xen?) begin >cpuidreg this-xen? if true exit then +cpuidreg not until false ;
: xen? 0cpuidreg (xen?) ;
-1 value hypage 0 value /hypage d# 10 buffer: hybuf
: msr/hypage >cpuidreg 2 + get-cpuid 2drop swap ( msr pages # ); : alloc-hypage 1+ pagesize * alloc-mem pagesize round-up ; : zero-hypage /hypage h# c3 fill ; : setup-hypage ( msr hypage -- ) 0 rot wrmsr ;
: init-hypercalls msr/hypage dup pagesize * to /hypage alloc-hypage dup to hypage dup zero-hypage setup-hypage ;
: +hypercall h# 20 * ;
: >hypercall hypage 0> if +hypercall hypage + else abort" Xen support not initialized" then ;
code (hypercall) eax pop eax call 1push c; code (bxhypercall) eax pop ebx pop eax call 1push c; code (cxbxhypercall) eax pop ebx pop ecx pop eax call 1push c; code (dxcxbxhypercall) eax pop ebx pop ecx pop edx pop eax call 1push c;
: xen-version hybuf 1 d# 17 >hypercall (cxbxhypercall) ;
: sched-op d# 29 >hypercall (cxbxhypercall) ; : xen-yield 0 0 sched-op ; : xen-block 0 1 sched-op ; : xen-shutdown hybuf ! hybuf 2 sched-op ; : xen-poweroff 0 xen-shutdown ; : xen-reboot 1 xen-shutdown ; : xen-crash 3 xen-shutdown ;
: xen-get-memmap h# 1000 dup hybuf ! alloc-mem dup hybuf 4 + ! hybuf 9 d# 12 >hypercall (cxbxhypercall) ;
h# 7ff0 constant domid-self
: hvm-param swap hybuf 4 + ! domid-self hybuf ! hybuf swap ( arg op -- ) h# 22 >hypercall (cxbxhypercall) 0> if abort" Cannot fetch HVM parameter " then hybuf 8 + 2@ ; : hvm-param-set 0 hvm-param ; : hvm-param-get 1 hvm-param ;
-1 value storebuf -1 value storeevt h# 400 constant /storebuf
: init-store 1 hvm-param-get nip h# c lshift dup to storebuf 2 hvm-param-get nip to storeevt ;
: >event hybuf ! hybuf d# 9 d# 32 >hypercall (cxbxhypercall) ;
: >reqring [ /storebuf 1- ] literal and storebuf + ; : >rspring >reqring /storebuf + ;
: storeptr storebuf [ /storebuf 2 * ] literal + ;
: ringptr@ create , does> @ storeptr + @ ; : ringptr! create , does> @ storeptr + ! ;
0 dup dup ringptr@ reqcons@ ringptr! reqcons! 4 + dup dup ringptr@ reqprod@ ringptr! reqprod! 4 + dup dup ringptr@ rspcons@ ringptr! rspcons! 4 + dup ringptr@ rspprod@ ringptr! rspprod!
0 value reqptr : 0req reqprod@ to reqptr ; : req, reqptr >reqring ! reqptr 4 + to reqptr ; : reqc, reqptr >reqring c! reqptr 1+ to reqptr ;
: .store cr ." reqcons=" reqcons@ . cr ." reqprod=" reqprod@ . cr ." rspcons=" rspcons@ . cr ." rspprod=" rspprod@ . ;
0 variable xid
: +xid xid @ dup 1+ xid ! ;
: xs-read 0req 2 req, +xid req, 0 req, word ;
: init-xen xen? if init-hypercalls init-store ['] xen-poweroff is power-off ['] xen-reboot is reset-all then ;