I'm currently writing a patch for GRUB intended for the Qubes OS
project (though I may later try to upstream it if it proves to work
well downstream). [1] The patch's goal is to allow Xen hypervisor users
to pass data to GRUB via command line arguments. This data is exposed as
environment variables within GRUB itself, which can then be used in
grub.cfg for customizing various parts of the boot process as the user
desires. The patch is coming together pretty well (we're still
discussing the details downstream), but I have hit one particularly
tricky question that I don't know how to get a good answer to.

When booting a VM in PV mode, Xen simply passes a start_info structure
to the guest, which can then use it directly. This structure includes a
cmd_line member, which can then be parsed with minimal additional
effort. GRUB's startup code for Xen PV simply takes the start_info
struct address and places it in grub_xen_start_page_addr, so it's
already loaded with the existing GRUB code. Since Xen PV mode and GRUB
work together at all, I assume everything related to memory 

Unfortunately, this is not the case when using PVH mode - Xen seems to
pass an hvm_start_info struct instead, which also contains a pointer to
the command line passed by Xen... sorta. What it passes is a physical
address in the form of a 64-bit integer. Now I did test this on my
machine; in grub-core/kern/i386/xen/pvh.c:grub_xen_setup_pvh, I added
code that casts the address to a char * and then grub_strcpy's what it
points to into grub_xen_start_page_addr->cmd_line. This appears to work
without problems, the command line from Xen ends up accessible to my
parsing code elsewhere in GRUB. However, I feel like I'm playing with
fire here - I'm assuming that either paging is disabled or the pages I'm
working with are identity-mapped when I do this, and I'm assuming that
writing into the cmd_line array at this point is safe at all. (I
suspect the latter is safe given that grub_xen_start_page_addr is being
dereferenced and members of the struct written to in this very
function, but I'm really dubious about the former, just because it
happens to work for me now doesn't mean it will work anywhere else.)

I don't know how to determine for sure what state the page tables are
in at any given point in GRUB's codebase. I did spot some other code in
GRUB that assumes disabled paging or identity paging (specifically
grub-core/commands/i386/pc/drivemap.c:install_int13_handler), but
that's specifically for the i386-pc platform and I don't know if that
will apply on any other platform GRUB supports. I can't follow the bits
of assembly code that handle enabling and disabling of paging well
enough to know what exactly they affect (mostly because I don't know
x86 assembly, or any assembly language for that matter), I can tell
that there are situations where paging is used, and sometimes those
situations use identity paging, but that's about it.

Is what I'm doing with physical address handling safe? And is there a
good way (other than dissecting the assembly code) to determine what is
and isn't safe when dealing with these kinds of situations?

[1] https://github.com/QubesOS/qubes-linux-pvgrub2/pull/16

--
Aaron

Attachment: pgp_tjOO_ka1T.pgp
Description: OpenPGP digital signature

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to