-
Notifications
You must be signed in to change notification settings - Fork 144
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,10 +20,29 @@ | |
|
||
#include "../cpu_x86_64.h" | ||
#include "xen/elfnote.h" | ||
#include "../virtio/multiboot.h" | ||
|
||
#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. | ||
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, exactly. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
@@ -104,6 +137,8 @@ ENTRY(_start32) | |
/* NOTREACHED */ | ||
jmp haltme | ||
|
||
unknownboot: | ||
|
||
haltme: | ||
cli | ||
hlt | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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. | ||
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
|
@@ -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); | ||
|
||
/* | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,16 +55,17 @@ SECTIONS { | |
*/ | ||
_stext = .; | ||
|
||
.interp : { | ||
*(.interp) | ||
} :interp :text | ||
|
||
.text : | ||
{ | ||
*(.data.multiboot) | ||
*(.text) | ||
*(.text.*) | ||
} :text | ||
|
||
.interp : { | ||
*(.interp) | ||
} :interp :text | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's already here and it wasn't enough. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (... looking at the linker scripts and readelf output, I actually think |
||
. = ALIGN(CONSTANT(MAXPAGESIZE)); | ||
_etext = .; | ||
|
||
|
There was a problem hiding this comment.
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.