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' ]
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
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.
(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
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 ;
dup pagesize * to /hypage
dup to 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 ;
h# 1000 dup hybuf ! alloc-mem dup hybuf 4 + !
hybuf 9 d# 12 >hypercall (cxbxhypercall)
h# 7ff0 constant domid-self
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
1 hvm-param-get nip h# c lshift dup
2 hvm-param-get nip
: >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 ;
cr ." reqcons=" reqcons@ . cr ." reqprod=" reqprod@ .
cr ." rspcons=" rspcons@ . cr ." rspprod=" rspprod@ .
0 variable xid
: +xid xid @ dup 1+ xid ! ;
0req 2 req, +xid req,
0 req, word
: init-xen xen? if
['] xen-poweroff is power-off
['] xen-reboot is reset-all