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

WIP: jump into the kernel #29

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ loader_main(struct loader_callbacks *cb, void *arg, int version, int ndisks)
if (multiboot_info_finalize(mb)) {
ERROR(ECANCELED, "Could not set up multiboot information structure");
}

if (multiboot_enter(mb)) {
ERROR(ECANCELED, "Could not set up machine state");
}
}

/* Cleanup. */
Expand Down
2 changes: 1 addition & 1 deletion loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

#include <userboot.h>

#define USERBOOT_VERSION 4
#define USERBOOT_VERSION 5
#define MALLOCSZ (64*1024*1024)

#define BOOTLOADER_NAME "bhyve-multiboot.so"
Expand Down
58 changes: 52 additions & 6 deletions multiboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,7 @@ multiboot_info_finalize(struct multiboot *mb)
if (error)
return error;

/*
* Multiboot specification, section 3.2:
* EBX Must contain the 32-bit physical address of the Multiboot information
* structure provided by the boot loader (see spec, section 3.3).
*/
error = CALLBACK(vm_set_register, 0, VM_REG_GUEST_RBX, p_addr);
mb->info_addr = p_addr;

return error;
}
Expand Down Expand Up @@ -605,4 +600,55 @@ multiboot_load(void* kernel, size_t kernsz, struct multiboot *mb)
}
}

#define SET_REG(reg, value) do {\
error = CALLBACK(vm_set_register, 0, VM_REG_GUEST_ ## reg, value); \
if (error) \
return error; \
} while (0);

#define SET_DESC(reg, base, limit, access) do { \
error = CALLBACK(vm_set_desc, 0, VM_REG_GUEST_ ## reg, base, limit, access); \
if (error) \
return error; \
} while (0);

uint32_t
multiboot_enter(struct multiboot* mb)
{
uint32_t error = 0;

CALLBACK(vm_set_unrestricted_guest, 0, 1);
CALLBACK(vcpu_reset, 0);

#define CR0_NE 0x20
#define CR0_PE 0x01

SET_REG(CR0, CR0_NE | CR0_PE);

SET_DESC(CS, 0, 0xffffffff, 0xc09b);
SET_DESC(DS, 0, 0xffffffff, 0xc093);
SET_DESC(ES, 0, 0xffffffff, 0xc093);
SET_DESC(FS, 0, 0xffffffff, 0xc093);
SET_DESC(GS, 0, 0xffffffff, 0xc093);
SET_DESC(SS, 0, 0xffffffff, 0xc093);

SET_REG(CS, 0x10);
SET_REG(DS, 0x18);
SET_REG(ES, 0x18);
SET_REG(FS, 0x18);
SET_REG(GS, 0x18);
SET_REG(SS, 0x18);

/*
* Multiboot specification, section 3.2:
* EBX Must contain the 32-bit physical address of the Multiboot information
* structure provided by the boot loader (see spec, section 3.3).
*/
SET_REG(RAX, MULTIBOOT1_BOOTLOADER_MAGIC);
SET_REG(RBX, mb->info_addr);
SET_REG(RIP, mb->entry);

return error;
}

/* vim: set noexpandtab ts=4 : */
10 changes: 10 additions & 0 deletions multiboot.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ struct multiboot {
void* entry;
Elf *kernel_elf;
struct multiboot_info info;
void* info_addr;
};

/**
Expand Down Expand Up @@ -302,4 +303,13 @@ uint32_t multiboot_info_finalize(struct multiboot *mb);
* @return uint32_t 0 on success, error code on failure
*/
uint32_t multiboot_load_modules(struct multiboot* mb, modules_list_t *modules);

/**
* @brief set up machine state to pass execution to the guest kernel
*
* @param mb pointer to the multiboot context
* @return uint32_t 0 on success, error code on failure
*/
uint32_t multiboot_enter(struct multiboot* mb);

/* vim: set noexpandtab ts=4 : */
6 changes: 1 addition & 5 deletions tests/test-multiboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -561,11 +561,7 @@ ATF_TC_BODY(info_finalize, tc)
error = multiboot_info_finalize(&mb);
ATF_CHECK_EQ_MSG(0, error, "multiboot_info_finalize failed");

error = vm_get_register(&ctx, 0, VM_REG_GUEST_RBX, &rbx);
ATF_CHECK_EQ_MSG(0, error, "vm_get_register failed");
ATF_CHECK_MSG(rbx, "RBX should point to the multiboo header");

callbacks->copyout(callbacks_arg, (uint32_t) rbx & 0xFFFFFFFF, test_buffer,
callbacks->copyout(callbacks_arg, (uint32_t) mb.info_addr, test_buffer,
sizeof(struct multiboot_info));

ATF_CHECK_EQ(0, memcmp(&mb.info, test_buffer,
Expand Down
14 changes: 14 additions & 0 deletions userboot.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,4 +259,18 @@ struct loader_callbacks {
int (*vm_set_register)(void *arg, int vcpu, int reg, uint64_t val);
int (*vm_set_desc)(void *arg, int vcpu, int reg, uint64_t base,
u_int limit, u_int access);

/*
* Version 5 additions.
*
* vm_get_unrestricted_guest checks support for the UNRESTRICTED_GUEST
* capability and if supported, sets 'retval'. If unsupported, an error
* code is returned.
*
* vm_set_unrestricted_guest sets the UNRESTRICTED_GUEST capability if
* supported, and returns an error code otherwise.
*/
int (*vm_get_unrestricted_guest)(void* arg, int vcpu, int *retval);
int (*vm_set_unrestricted_guest)(void* arg, int vcpu, int val);
int (*vcpu_reset)(void* arg, int vcpu);
};