2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2015, The V3VEE Project <http://www.v3vee.org>
11 * All rights reserved.
13 * Author: Peter Dinda <pdinda@northwestern.edu>
15 * This is free software. You are permitted to use,
16 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
19 #include <palacios/vmm_mem.h>
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_util.h>
22 #include <palacios/vmm_emulator.h>
23 #include <palacios/vm_guest.h>
24 #include <palacios/vmm_debug.h>
25 #include <palacios/vmm_hypercall.h>
27 #include <palacios/vmm_xml.h>
29 #include <palacios/vm_guest_mem.h>
31 #include <palacios/vmm_debug.h>
39 <file id="multibootelf" filename="multibootelf.o" />
42 <multiboot enable="y" file_id="multibootelf" />
47 #ifndef V3_CONFIG_DEBUG_MULTIBOOT
49 #define PrintDebug(fmt, args...)
53 int v3_init_multiboot()
55 PrintDebug(VM_NONE,VCORE_NONE, "multiboot: init\n");
59 int v3_deinit_multiboot()
61 PrintDebug(VM_NONE,VCORE_NONE, "multiboot: deinit\n");
67 #define CEIL_DIV(x,y) (((x)/(y)) + !!((x)%(y)))
69 int v3_init_multiboot_vm(struct v3_vm_info *vm, struct v3_xml *config)
71 v3_cfg_tree_t *mb_config;
75 PrintDebug(vm, VCORE_NONE, "multiboot: vm init\n");
77 memset(&vm->mb_state,0,sizeof(struct v3_vm_multiboot));
78 vm->mb_state.is_multiboot=0;
80 if (!config || !(mb_config=v3_cfg_subtree(config,"multiboot"))) {
81 PrintDebug(vm,VCORE_NONE,"multiboot: no multiboot configuration found - normal boot will occur\n");
85 if (!(enable=v3_cfg_val(mb_config,"enable")) || strcasecmp(enable,"y")) {
86 PrintDebug(vm,VCORE_NONE,"multiboot: multiboot configuration disabled\n");
90 if (!(mb_file_id=v3_cfg_val(mb_config,"file_id"))) {
91 PrintError(vm,VCORE_NONE,"multiboot: multiboot block without file_id...\n");
95 vm->mb_state.mb_file = v3_cfg_get_file(vm,mb_file_id);
97 if (!vm->mb_state.mb_file) {
98 PrintError(vm,VCORE_NONE,"multiboot: multiboot block contains bad file_id (%s)\n",mb_file_id);
102 vm->mb_state.is_multiboot=1;
105 if (vm->mb_state.is_multiboot) {
106 V3_Print(vm,VCORE_NONE,"multiboot: file_id=%s (tag %s)]\n",
108 vm->mb_state.mb_file->tag);
110 V3_Print(vm,VCORE_NONE,"multiboot: This is not a multiboot VM\n");
117 int v3_deinit_multiboot_vm(struct v3_vm_info *vm)
119 PrintDebug(vm, VCORE_NONE, "multiboot: multiboot VM deinit\n");
124 int v3_init_multiboot_core(struct guest_info *core)
126 PrintDebug(core->vm_info, VCORE_NONE, "multiboot: multiboot core init\n");
128 // Nothing to do at this point
133 int v3_deinit_multiboot_core(struct guest_info *core)
135 PrintDebug(core->vm_info, VCORE_NONE, "multiboot: multiboot core deinit\n");
143 #define ERROR(fmt, args...) PrintError(VM_NONE,VCORE_NONE,"multiboot: " fmt,##args)
144 #define INFO(fmt, args...) PrintDebug(VM_NONE,VCORE_NONE,"multiboot: " fmt,##args)
148 /******************************************************************
149 Data contained in the ELF file we will attempt to boot
150 ******************************************************************/
152 #define ELF_MAGIC 0x464c457f
153 #define MB2_MAGIC 0xe85250d6
156 /******************************************************************
157 Data we will pass to the kernel via rbx
158 ******************************************************************/
160 #define MB2_INFO_MAGIC 0x36d76289
162 typedef struct mb_info_header {
165 } __attribute__((packed)) mb_info_header_t;
167 // A tag of type 0, size 8 indicates last value
169 typedef struct mb_info_tag {
172 } __attribute__((packed)) mb_info_tag_t;
175 #define MB_INFO_MEM_TAG 4
176 typedef struct mb_info_mem {
178 uint32_t mem_lower; // 0..640K in KB
179 uint32_t mem_upper; // in KB to first hole - 1 MB
180 } __attribute__((packed)) mb_info_mem_t;
182 #define MB_INFO_CMDLINE_TAG 1
183 // note alignment of 8 bytes required for each...
184 typedef struct mb_info_cmdline {
186 uint32_t size; // includes zero termination
187 uint8_t string[]; // zero terminated
188 } __attribute__((packed)) mb_info_cmdline_t;
195 typedef struct mb_info_memmap_entry {
200 } __attribute__((packed)) mb_info_memmap_entry_t;
202 #define MB_INFO_MEMMAP_TAG 6
203 // note alignment of 8 bytes required for each...
204 typedef struct mb_info_memmap {
206 uint32_t entry_size; // multiple of 8
207 uint32_t entry_version; // 0
208 mb_info_memmap_entry_t entries[];
209 } __attribute__((packed)) mb_info_memmap_t;
211 #define MB_INFO_HRT_TAG 0xf00df00d
212 typedef struct mb_info_hrt {
214 // apic ids are 0..num_apics-1
215 // apic and ioapic addresses are the well known places
216 uint32_t total_num_apics;
217 uint32_t first_hrt_apic_id;
218 uint32_t have_hrt_ioapic;
219 uint32_t first_hrt_ioapic_entry;
220 } __attribute__((packed)) mb_info_hrt_t;
228 // - Boot Loader name
231 // - Framebuffer info
234 static int is_elf(uint8_t *data, uint64_t size)
236 if (*((uint32_t*)data)==ELF_MAGIC) {
243 static mb_header_t *find_mb_header(uint8_t *data, uint64_t size)
245 uint64_t limit = size > 32768 ? 32768 : size;
248 // Scan for the .boot magic cookie
249 // must be in first 32K, assume 4 byte aligned
250 for (i=0;i<limit;i+=4) {
251 if (*((uint32_t*)&data[i])==MB2_MAGIC) {
252 INFO("Found multiboot header at offset 0x%llx\n",i);
253 return (mb_header_t *) &data[i];
259 static int checksum4_ok(uint32_t *data, uint64_t size)
264 for (i=0;i<size;i++) {
271 static int parse_multiboot_kernel(uint8_t *data, uint64_t size, mb_data_t *mb)
275 mb_header_t *mb_header=0;
278 mb_addr_t *mb_addr=0;
279 mb_entry_t *mb_entry=0;
280 mb_flags_t *mb_flags=0;
281 mb_framebuf_t *mb_framebuf=0;
282 mb_modalign_t *mb_modalign=0;
283 mb_mb64_hrt_t *mb_mb64_hrt=0;
286 if (!is_elf(data,size)) {
287 ERROR("HRT is not an ELF\n");
291 mb_header = find_mb_header(data,size);
294 ERROR("No multiboot header found\n");
298 // Checksum applies only to the header itself, not to
299 // the subsequent tags...
300 if (!checksum4_ok((uint32_t*)mb_header,4)) {
301 ERROR("Multiboot header has bad checksum\n");
305 INFO("Multiboot header: arch=0x%x, headerlen=0x%x\n", mb_header->arch, mb_header->headerlen);
307 mb_tag = (mb_tag_t*)((void*)mb_header+16);
309 while (!(mb_tag->type==0 && mb_tag->size==8)) {
310 INFO("tag: type 0x%x flags=0x%x size=0x%x\n",mb_tag->type, mb_tag->flags,mb_tag->size);
311 switch (mb_tag->type) {
314 ERROR("Multiple info tags found!\n");
317 mb_inf = (mb_info_t*)mb_tag;
318 INFO(" info request - types follow\n");
319 for (i=0;(mb_tag->size-8)/4;i++) {
320 INFO(" %llu: type 0x%x\n", i, mb_inf->types[i]);
325 case MB_TAG_ADDRESS: {
327 ERROR("Multiple address tags found!\n");
330 mb_addr = (mb_addr_t*)mb_tag;
332 INFO(" header_addr = 0x%x\n", mb_addr->header_addr);
333 INFO(" load_addr = 0x%x\n", mb_addr->load_addr);
334 INFO(" load_end_addr = 0x%x\n", mb_addr->load_end_addr);
335 INFO(" bss_end_addr = 0x%x\n", mb_addr->bss_end_addr);
341 ERROR("Multiple entry tags found!\n");
344 mb_entry=(mb_entry_t*)mb_tag;
346 INFO(" entry_addr = 0x%x\n", mb_entry->entry_addr);
352 ERROR("Multiple flags tags found!\n");
355 mb_flags = (mb_flags_t*)mb_tag;
357 INFO(" console_flags = 0x%x\n", mb_flags->console_flags);
361 case MB_TAG_FRAMEBUF: {
363 ERROR("Multiple framebuf tags found!\n");
366 mb_framebuf = (mb_framebuf_t*)mb_tag;
368 INFO(" width = 0x%x\n", mb_framebuf->width);
369 INFO(" height = 0x%x\n", mb_framebuf->height);
370 INFO(" depth = 0x%x\n", mb_framebuf->depth);
374 case MB_TAG_MODALIGN: {
376 ERROR("Multiple modalign tags found!\n");
379 mb_modalign = (mb_modalign_t*)mb_tag;
381 INFO(" size = 0x%x\n", mb_modalign->size);
385 case MB_TAG_MB64_HRT: {
387 ERROR("Multiple mb64_hrt tags found!\n");
390 mb_mb64_hrt = (mb_mb64_hrt_t*)mb_tag;
397 INFO("Unknown tag... Skipping...\n");
400 mb_tag = (mb_tag_t *)(((void*)mb_tag) + mb_tag->size);
403 // copy out to caller
404 mb->header=mb_header;
409 mb->framebuf=mb_framebuf;
410 mb->modalign=mb_modalign;
411 mb->mb64_hrt=mb_mb64_hrt;
417 int v3_parse_multiboot_header(struct v3_cfg_file *file, mb_data_t *result)
419 return parse_multiboot_kernel(file->data,file->size,result);
423 #define APIC_BASE 0xfee00000
424 #define IOAPIC_BASE 0xfec00000
428 MB_HRT (if this is an HVM
433 1024..ioapic_base RAM
434 ioapic_base to ioapic_base+page reserved
435 ioapic_base+page to apic_base ram
436 apic_base oto apic_base+page reserved
437 apic_base+page to total RAM
440 The multiboot structure that is written reflects the
441 perspective of the core given the kind of VM it is part of.
444 - core does not matter
449 - only ROS memory visible
450 - regular multiboot or bios boot assumed
452 - full HRT memory visible
453 - HRT64 multiboot assumed
457 uint64_t v3_build_multiboot_table(struct guest_info *core, uint8_t *dest, uint64_t size)
459 struct v3_vm_info *vm = core->vm_info;
460 mb_info_header_t *header;
465 mb_info_memmap_t *memmap;
467 uint64_t num_mem, cur_mem;
469 uint64_t total_mem = vm->mem_size;
472 if (vm->hvm_state.is_hvm) {
473 if (v3_is_hvm_ros_core(core)) {
474 PrintDebug(core->vm_info,core,"multiboot: hvm: building mb table from ROS core perspective\n");
475 total_mem = v3_get_hvm_ros_memsize(vm);
477 PrintDebug(core->vm_info,core,"multiboot: hvm: building mb table from HRT core perspective\n");
478 total_mem = v3_get_hvm_hrt_memsize(vm);
483 // assume we have > 1 MB + apic+ioapic
485 if (total_mem>IOAPIC_BASE+PAGE_SIZE) {
488 if (total_mem>APIC_BASE+PAGE_SIZE) {
494 sizeof(mb_info_header_t) +
496 core->vm_info->hvm_state.is_hvm && core->hvm_state.is_hrt ? sizeof(mb_info_hrt_t) : 0
499 sizeof(mb_info_mem_t) +
500 sizeof(mb_info_memmap_t) +
501 sizeof(mb_info_memmap_entry_t) * num_mem +
502 sizeof(mb_info_tag_t);
511 ERROR("Cannot fit MB info in needed space\n");
517 header = (mb_info_header_t*)next;
518 next += sizeof(mb_info_header_t);
521 if (core->vm_info->hvm_state.is_hvm && v3_is_hvm_hrt_core(core)) {
522 hrt = (mb_info_hrt_t*)next;
523 next += sizeof(mb_info_hrt_t);
527 mem = (mb_info_mem_t*)next;
528 next += sizeof(mb_info_mem_t);
530 memmap = (mb_info_memmap_t*)next;
531 next += sizeof(mb_info_memmap_t) + num_mem * sizeof(mb_info_memmap_entry_t);
533 tag = (mb_info_tag_t*)next;
534 next += sizeof(mb_info_tag_t);
536 header->totalsize = (uint32_t)(next - dest);
537 header->reserved = 0;
540 if (core->vm_info->hvm_state.is_hvm && v3_is_hvm_hrt_core(core)) {
541 hrt->tag.type = MB_INFO_HRT_TAG;
542 hrt->tag.size = sizeof(mb_info_hrt_t);
543 hrt->total_num_apics = vm->num_cores;
544 hrt->first_hrt_apic_id = vm->hvm_state.first_hrt_core;
545 hrt->have_hrt_ioapic=0;
546 hrt->first_hrt_ioapic_entry=0;
550 mem->tag.type = MB_INFO_MEM_TAG;
551 mem->tag.size = sizeof(mb_info_mem_t);
552 mem->mem_lower = 640; // thank you, bill gates
553 mem->mem_upper = (total_mem - 1024 * 1024) / 1024;
555 memmap->tag.type = MB_INFO_MEMMAP_TAG;
556 memmap->tag.size = sizeof(mb_info_memmap_t) + num_mem * sizeof(mb_info_memmap_entry_t);
557 memmap->entry_size = 24;
558 memmap->entry_version = 0;
563 memmap->entries[cur_mem].base_addr = 0;
564 memmap->entries[cur_mem].length = 640*1024;
565 memmap->entries[cur_mem].type = MEM_RAM;
566 memmap->entries[cur_mem].reserved = 0;
569 // legacy io (640K->1 MB)
570 memmap->entries[cur_mem].base_addr = 640*1024;
571 memmap->entries[cur_mem].length = 384*1024;
572 memmap->entries[cur_mem].type = MEM_RESV;
573 memmap->entries[cur_mem].reserved = 1;
576 // first meg to ioapic
577 memmap->entries[cur_mem].base_addr = 1024*1024;
578 memmap->entries[cur_mem].length = (total_mem < IOAPIC_BASE ? total_mem : IOAPIC_BASE) - 1024*1024;
579 memmap->entries[cur_mem].type = MEM_RAM;
580 memmap->entries[cur_mem].reserved = 0;
583 // ioapic reservation
584 memmap->entries[cur_mem].base_addr = IOAPIC_BASE;
585 memmap->entries[cur_mem].length = PAGE_SIZE;
586 memmap->entries[cur_mem].type = MEM_RESV;
587 memmap->entries[cur_mem].reserved = 1;
590 if (total_mem > (IOAPIC_BASE + PAGE_SIZE)) {
591 // memory between ioapic and apic
592 memmap->entries[cur_mem].base_addr = IOAPIC_BASE+PAGE_SIZE;
593 memmap->entries[cur_mem].length = (total_mem < APIC_BASE ? total_mem : APIC_BASE) - (IOAPIC_BASE+PAGE_SIZE);;
594 memmap->entries[cur_mem].type = MEM_RAM;
595 memmap->entries[cur_mem].reserved = 0;
600 memmap->entries[cur_mem].base_addr = APIC_BASE;
601 memmap->entries[cur_mem].length = PAGE_SIZE;
602 memmap->entries[cur_mem].type = MEM_RESV;
603 memmap->entries[cur_mem].reserved = 1;
606 if (total_mem > (APIC_BASE + PAGE_SIZE)) {
608 memmap->entries[cur_mem].base_addr = APIC_BASE+PAGE_SIZE;
609 memmap->entries[cur_mem].length = total_mem - (APIC_BASE+PAGE_SIZE);
610 memmap->entries[cur_mem].type = MEM_RAM;
611 memmap->entries[cur_mem].reserved = 0;
615 for (cur_mem=0;cur_mem<num_mem;cur_mem++) {
616 PrintDebug(vm, VCORE_NONE,
617 "multiboot: entry %llu: %p (%llx bytes) - type %x %s\n",
619 (void*) memmap->entries[cur_mem].base_addr,
620 memmap->entries[cur_mem].length,
621 memmap->entries[cur_mem].type,
622 memmap->entries[cur_mem].reserved ? "reserved" : "");
627 // This demarcates end of list
631 return header->totalsize;
636 int v3_write_multiboot_kernel(struct v3_vm_info *vm, mb_data_t *mb, struct v3_cfg_file *file,
637 void *base, uint64_t limit)
641 if (!mb->addr || !mb->entry) {
642 PrintError(vm,VCORE_NONE, "multiboot: kernel is missing address or entry point\n");
646 if (((void*)(uint64_t)(mb->addr->header_addr) < base ) ||
647 ((void*)(uint64_t)(mb->addr->load_end_addr) > base+limit) ||
648 ((void*)(uint64_t)(mb->addr->bss_end_addr) > base+limit)) {
649 PrintError(vm,VCORE_NONE, "multiboot: kernel is not within the allowed portion of VM\n");
653 offset = mb->addr->load_addr - mb->addr->header_addr;
655 // Skip the ELF header - assume 1 page... weird....
656 // We are trying to do as little ELF loading here as humanly possible
657 v3_write_gpa_memory(&vm->cores[0],
658 (addr_t)(mb->addr->load_addr),
659 file->size-PAGE_SIZE-offset,
660 file->data+PAGE_SIZE+offset);
662 PrintDebug(vm,VCORE_NONE,
663 "multiboot: wrote 0x%llx bytes starting at offset 0x%llx to %p\n",
664 (uint64_t) file->size-PAGE_SIZE-offset,
665 (uint64_t) PAGE_SIZE+offset,
666 (void*)(addr_t)(mb->addr->load_addr));
673 static int setup_multiboot_kernel(struct v3_vm_info *vm)
676 uint64_t limit = vm->mem_size;
679 if (vm->mb_state.mb_file->size > limit) {
680 PrintError(vm,VCORE_NONE,"multiboot: Cannot map kernel because it is too big (%llu bytes, but only have %llu space\n", vm->mb_state.mb_file->size, (uint64_t)limit);
684 if (!is_elf(vm->mb_state.mb_file->data,vm->mb_state.mb_file->size)) {
685 PrintError(vm,VCORE_NONE,"multiboot: supplied kernel is not an ELF\n");
688 if (find_mb_header(vm->mb_state.mb_file->data,vm->mb_state.mb_file->size)) {
689 PrintDebug(vm,VCORE_NONE,"multiboot: appears to be a multiboot kernel\n");
690 if (v3_parse_multiboot_header(vm->mb_state.mb_file,&vm->mb_state.mb_data)) {
691 PrintError(vm,VCORE_NONE,"multiboot: cannot parse multiboot kernel header\n");
694 if (v3_write_multiboot_kernel(vm, &(vm->mb_state.mb_data),vm->mb_state.mb_file,base,limit)) {
695 PrintError(vm,VCORE_NONE,"multiboot: multiboot kernel setup failed\n");
699 PrintError(vm,VCORE_NONE,"multiboot: multiboot kernel has no header\n");
708 // 32 bit GDT entries
710 // base24-31 flags2 limit16-19 access8 base16-23 base0-15 limit0-15
711 // null 0 0 0 0 0 0 0
712 // code 0 1100 f 10011010 0 0 ffff
713 // data 0 1100 f 10010010 0 0 ffff
715 // null = 00 00 00 00 00 00 00 00
716 // code = 00 cf 9a 00 00 00 ff ff
717 // data = 00 cf 92 00 00 00 ff ff
719 static uint64_t gdt32[3] = {
720 0x0000000000000000, /* null */
721 0x00cf9a000000ffff, /* code (note lme=0) */
722 0x00cf92000000ffff, /* data */
725 static void write_gdt(struct v3_vm_info *vm, void *base, uint64_t limit)
727 v3_write_gpa_memory(&vm->cores[0],(addr_t)base,limit,(uint8_t*) gdt32);
729 PrintDebug(vm,VCORE_NONE,"multiboot: wrote GDT at %p\n",base);
733 static void write_tss(struct v3_vm_info *vm, void *base, uint64_t limit)
736 uint64_t tss_data=0x0;
738 for (i=0;i<limit/8;i++) {
739 v3_write_gpa_memory(&vm->cores[0],(addr_t)(base+8*i),8,(uint8_t*) &tss_data);
742 PrintDebug(vm,VCORE_NONE,"multiboot: wrote TSS at %p\n",base);
745 static void write_table(struct v3_vm_info *vm, void *base, uint64_t limit)
750 limit = limit < 256 ? limit : 256;
752 size = v3_build_multiboot_table(&vm->cores[0], buf, limit);
754 if (size>256 || size==0) {
755 PrintError(vm,VCORE_NONE,"multiboot: cannot build multiboot table\n");
759 v3_write_gpa_memory(&vm->cores[0],(addr_t)base,size,buf);
771 Kernel at its desired load address (or error)
776 int v3_setup_multiboot_vm_for_boot(struct v3_vm_info *vm)
778 void *kernel_start_gpa;
779 void *kernel_end_gpa;
784 if (!vm->mb_state.is_multiboot) {
785 PrintDebug(vm,VCORE_NONE,"multiboot: skipping multiboot setup for boot as this is not a multiboot VM\n");
790 if (setup_multiboot_kernel(vm)) {
791 PrintError(vm,VCORE_NONE,"multiboot: failed to setup kernel\n");
795 kernel_start_gpa = (void*) (uint64_t) (vm->mb_state.mb_data.addr->load_addr);
796 kernel_end_gpa = (void*) (uint64_t) (vm->mb_state.mb_data.addr->bss_end_addr);
798 // Is there room below the kernel?
799 if ((uint64_t)kernel_start_gpa > 19*4096 ) {
800 // at least 3 pages between 64K and start of kernel
802 mb_gpa=(void*)(16*4096);
804 // is there room above the kernel?
805 if ((uint64_t)kernel_end_gpa < vm->mem_size-4*4096) {
806 if (((uint64_t)kernel_end_gpa + 4 * 4096) <= 0xffffffff) {
807 mb_gpa=(void*) (4096*((uint64_t)kernel_end_gpa/4096 + 1));
809 PrintError(vm,VCORE_NONE,"multiboot: no room for mb data below 4 GB\n");
813 PrintError(vm,VCORE_NONE,"multiboot: no room for mb data above kernel\n");
818 PrintDebug(vm,VCORE_NONE,"multiboot: mb data will start at %p\n",mb_gpa);
820 vm->mb_state.mb_data_gpa=mb_gpa;
822 tss_gpa = mb_gpa + 1 * 4096;
823 gdt_gpa = mb_gpa + 2 * 4096;
825 write_table(vm,mb_gpa,4096);
827 write_tss(vm,tss_gpa,4096);
829 write_gdt(vm,gdt_gpa,4096);
831 PrintDebug(vm,VCORE_NONE,"multiboot: setup of memory done\n");
840 GDTR points to stub GDT
841 TR points to stub TSS
842 CR0 has PE and not PG
843 EIP is entry point to kernel
844 EBX points to multiboot info
845 EAX multiboot magic cookie
848 int v3_setup_multiboot_core_for_boot(struct guest_info *core)
853 if (!core->vm_info->mb_state.is_multiboot) {
854 PrintDebug(core->vm_info,core,"multiboot: skipping mb core setup as this is not an mb VM\n");
858 if (core->vcpu_id != 0) {
859 PrintDebug(core->vm_info,core,"multiboot: skipping mb core setup as this is not the BSP core\n");
864 PrintDebug(core->vm_info, core, "multiboot: setting up MB BSP core for boot\n");
867 memset(&core->vm_regs,0,sizeof(core->vm_regs));
868 memset(&core->ctrl_regs,0,sizeof(core->ctrl_regs));
869 memset(&core->dbg_regs,0,sizeof(core->dbg_regs));
870 memset(&core->segments,0,sizeof(core->segments));
871 memset(&core->msrs,0,sizeof(core->msrs));
872 memset(&core->fp_state,0,sizeof(core->fp_state));
874 // We need to be in protected mode at ring zero
875 core->cpl = 0; // we are going right into the kernel
876 core->cpu_mode = PROTECTED;
877 core->mem_mode = PHYSICAL_MEM;
878 // default run-state is fine, we are core zero
879 // core->core_run_state = CORE_RUNNING ;
881 // right into the kernel
882 core->rip = (uint64_t) core->vm_info->mb_state.mb_data.entry->entry_addr;
884 // Setup CRs for protected mode
885 // CR0: PE (but no PG)
886 core->ctrl_regs.cr0 = 0x1;
887 core->shdw_pg_state.guest_cr0 = core->ctrl_regs.cr0;
889 // CR2: don't care (output from #PF)
890 // CR3: don't care (no paging)
891 core->ctrl_regs.cr3 = 0;
892 core->shdw_pg_state.guest_cr3 = core->ctrl_regs.cr3;
895 core->ctrl_regs.cr4 = 0x0;
896 core->shdw_pg_state.guest_cr4 = core->ctrl_regs.cr4;
898 // RFLAGS zeroed is fine: come in with interrupts off
899 // EFER needs SVME and LME but not LMA (last 16 bits: 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0
900 core->ctrl_regs.efer = 0x1400;
901 core->shdw_pg_state.guest_efer.value = core->ctrl_regs.efer;
907 selector is 13 bits of index, 1 bit table indicator
910 index is scaled by 8, even in long mode, where some entries
911 are 16 bytes long....
912 -> code, data descriptors have 8 byte format
913 because base, limit, etc, are ignored (no segmentation)
914 -> interrupt/trap gates have 16 byte format
915 because offset needs to be 64 bits
918 // There is no IDTR set and interrupts are disabled
920 // Install our stub GDT
921 core->segments.gdtr.selector = 0;
922 core->segments.gdtr.base = (addr_t) core->vm_info->mb_state.mb_data_gpa+2*4096;
923 core->segments.gdtr.limit = 4096-1;
924 core->segments.gdtr.type = 0x6;
925 core->segments.gdtr.system = 1;
926 core->segments.gdtr.dpl = 0;
927 core->segments.gdtr.present = 1;
928 core->segments.gdtr.long_mode = 0;
931 core->segments.tr.selector = 0;
932 core->segments.tr.base = (addr_t) core->vm_info->mb_state.mb_data_gpa+1*4096;
933 core->segments.tr.limit = 4096-1;
934 core->segments.tr.type = 0x6;
935 core->segments.tr.system = 1;
936 core->segments.tr.dpl = 0;
937 core->segments.tr.present = 1;
938 core->segments.tr.long_mode = 0;
944 core->segments.cs.selector = 0x8 ; // entry 1 of GDT (RPL=0)
945 core->segments.cs.base = (addr_t) base;
946 core->segments.cs.limit = limit;
947 core->segments.cs.type = 0xe;
948 core->segments.cs.system = 0;
949 core->segments.cs.dpl = 0;
950 core->segments.cs.present = 1;
951 core->segments.cs.long_mode = 0;
953 // DS, SS, etc are identical
954 core->segments.ds.selector = 0x10; // entry 2 of GDT (RPL=0)
955 core->segments.ds.base = (addr_t) base;
956 core->segments.ds.limit = limit;
957 core->segments.ds.type = 0x6;
958 core->segments.ds.system = 0;
959 core->segments.ds.dpl = 0;
960 core->segments.ds.present = 1;
961 core->segments.ds.long_mode = 0;
963 memcpy(&core->segments.ss,&core->segments.ds,sizeof(core->segments.ds));
964 memcpy(&core->segments.es,&core->segments.ds,sizeof(core->segments.ds));
965 memcpy(&core->segments.fs,&core->segments.ds,sizeof(core->segments.ds));
966 memcpy(&core->segments.gs,&core->segments.ds,sizeof(core->segments.ds));
970 // Now for our magic - this signals
971 // the kernel that a multiboot loader loaded it
972 // and that rbx points to its offered data
973 core->vm_regs.rax = MB2_INFO_MAGIC;
975 core->vm_regs.rbx = (uint64_t) (core->vm_info->mb_state.mb_data_gpa);
977 // reset paging here for shadow...
979 if (core->shdw_pg_mode != NESTED_PAGING) {
980 PrintError(core->vm_info, core, "multiboot: shadow paging guest... this will end badly\n");