Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xen PVH booting via multiboot protocol (from pvgrub2-pvh) #482

Merged
merged 3 commits into from
Nov 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 40 additions & 5 deletions bindings/xen/boot.S
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,29 @@

#include "../cpu_x86_64.h"
#include "xen/elfnote.h"
#include "../virtio/multiboot.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can leave this as-is, virtio needs some reverse consolidation with Xen anyway, so can do that then.


#define ENTRY(x) .text; .globl x; .type x,%function; x:
#define END(x) .size x, . - x

#define XEN_HVM_START_MAGIC_VALUE 0x336ec578

#define MYMULTIBOOT_FLAGS \
(MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_AOUT_KLUDGE)

.section .data.multiboot

.align 4
_multiboot_header:
.long MULTIBOOT_HEADER_MAGIC
.long MYMULTIBOOT_FLAGS
.long -(MULTIBOOT_HEADER_MAGIC+MYMULTIBOOT_FLAGS)
.long _multiboot_header
.long 0x100000
.long _edata
.long _ebss
.long _start32

/*
* Tell Xen that we are a PVH-capable kernel.
* See https://xenbits.xen.org/docs/unstable/misc/pvh.html.
Expand All @@ -42,19 +61,33 @@
/*
* Xen PVH entry point.
*
* Xen puts us only in 32bit flat protected mode, and passes a pointer to
* struct hvm_start_info in %ebx. It's our responsibility to install a page
* table and switch to long mode. Notably, we can't call C code until we've
* switched to long mode.
* When booted directly, Xen puts us only in 32bit flat protected mode, and
* passes a pointer to struct hvm_start_info in %ebx. When booted via grub's
* multiboot protocol, grub passes a pointer to struct multiboot_info in %ebx
* and sets a magic in %eax. Otherwise both boot modes works the same. The
* platform_init() differentiate the structure based on a magic at the
* beginning of hvm_start_info.
* It's our responsibility to install a page table and switch to long mode.
* Notably, we can't call C code until we've switched to long mode.
*/
ENTRY(_start32)
cld
movl $bootstack, %esp

/* Save Xen hvm_start_info pointer at top of stack, we pop it in 64bit */
/*
* Save Xen hvm_start_info or multiboot_info pointer (depending on boot
* mode) at top of stack, we pop it in 64bit
*/
pushl $0
pushl %ebx
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, %ebx is now either a (struct hvm_start_info *) with direct boot, OR a (struct multiboot_info *), right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, can you please update both the header comment for this entry point and the comment immediately above to make sense in the new arrangement?


cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax
je 1f
movl (%ebx), %eax
cmpl $XEN_HVM_START_MAGIC_VALUE, %eax
jne unknownboot

1:
/*
* Load bootstrap GDT and reload segment registers, with the exception of
* CS, which will be reloaded on jumping to _start64
Expand Down Expand Up @@ -104,6 +137,8 @@ ENTRY(_start32)
/* NOTREACHED */
jmp haltme

unknownboot:

haltme:
cli
hlt
Expand Down
87 changes: 81 additions & 6 deletions bindings/xen/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "xen/arch-x86/cpuid.h"
#include "xen/arch-x86/hvm/start_info.h"
#include "xen/hvm/params.h"
#include "../virtio/multiboot.h"

/*
* Xen shared_info page is mapped here.
Expand Down Expand Up @@ -227,19 +228,64 @@ static void hypercall_init(void)
assert(HYPERCALL_PAGE[0] != 0xc3);
}

void platform_init(const void *arg __attribute__((unused)))
static void parse_multiboot(const void *arg)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for the comment.

{
pagetable_init();
hypercall_init();
console_init();
/*
* The multiboot structures may be anywhere in memory, so take a copy of
* the command line before we initialise memory allocation.
*/
const struct multiboot_info *mi = (struct multiboot_info *)arg;

if (mi->flags & MULTIBOOT_INFO_CMDLINE) {
char *mi_cmdline = (char *)(uint64_t)mi->cmdline;
size_t cmdline_len = strlen(mi_cmdline);

/*
* Skip the first token in the cmdline as it is an opaque "name" for
* the kernel coming from the bootloader.
*/
for (; *mi_cmdline; mi_cmdline++, cmdline_len--) {
if (*mi_cmdline == ' ') {
mi_cmdline++;
cmdline_len--;
break;
}
}

if (cmdline_len >= sizeof(cmdline)) {
cmdline_len = sizeof(cmdline) - 1;
log(WARN, "Solo5: warning: command line too long, truncated\n");
}
memcpy(cmdline, mi_cmdline, cmdline_len);
} else {
cmdline[0] = 0;
}

/*
* Look for the first chunk of memory at PLATFORM_MEM_START.
*/
multiboot_memory_map_t *m = NULL;
uint32_t offset;

for (offset = 0; offset < mi->mmap_length;
offset += m->size + sizeof(m->size)) {
m = (void *)(uintptr_t)(mi->mmap_addr + offset);
if (m->addr == PLATFORM_MEM_START &&
m->type == MULTIBOOT_MEMORY_AVAILABLE) {
break;
}
}
assert(offset < mi->mmap_length);
mem_size = m->addr + m->len;
}

static void parse_hvm_start_info(const void *arg)
{
/*
* The Xen hvm_start_info may be anywhere in memory, so take a copy of
* the command line before we initialise memory allocation.
*/
const struct hvm_start_info *si = (struct hvm_start_info *)arg;
assert(si->magic == XEN_HVM_START_MAGIC_VALUE);

if (si->cmdline_paddr) {
char *hvm_cmdline = (char *)si->cmdline_paddr;
size_t cmdline_len = strlen(hvm_cmdline);
Expand Down Expand Up @@ -295,6 +341,35 @@ void platform_init(const void *arg __attribute__((unused)))
}
}
}
}

void platform_init(const void *arg)
{
bool is_direct_pvh_boot;

if (*((uint32_t*)arg) == XEN_HVM_START_MAGIC_VALUE)
is_direct_pvh_boot = true;
else
is_direct_pvh_boot = false;

/*
* If booted via multiboot, parse multiboot structure before setting up
* page tables as its location may not be mapped later.
*/
if (!is_direct_pvh_boot)
parse_multiboot(arg);

pagetable_init();
hypercall_init();
console_init();

/*
* If booted directly, parse the Xen hvm_start_info structure after setting
* up hypercalls
*/
if (is_direct_pvh_boot)
parse_hvm_start_info(arg);

assert(mem_size);

/*
Expand Down
9 changes: 5 additions & 4 deletions bindings/xen/solo5_xen.lds
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,17 @@ SECTIONS {
*/
_stext = .;

.interp : {
*(.interp)
} :interp :text

.text :
{
*(.data.multiboot)
*(.text)
*(.text.*)
} :text

.interp : {
*(.interp)
} :interp :text

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this need moving, exactly? It doesn't really matter for Xen, but I'd still like to understand what's going on.

Copy link
Contributor Author

@marmarek marmarek Nov 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The multiboot header needs to be in the first 8k of the file. Without this change, first 4k were program headers, then the second 4k were just this section, pushing multiboot header beyond the first 8k.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to accomplish the same thing without re-ordering by placing *(.data.multiboot) into the .text output section as is done in solo5_virtio.lds?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already here and it wasn't enough. .text was linked at 8k offset in the file - just beyond what we need. I'm not sure what's the difference with virtio, perhaps more notes here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, don't worry about it, leave it as-is (and in a separate commit). Thanks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(... looking at the linker scripts and readelf output, I actually think .interp doesn't belong in :text at all but I'm not going to muck with that now...)

. = ALIGN(CONSTANT(MAXPAGESIZE));
_etext = .;

Expand Down