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)
147 static int is_elf(uint8_t *data, uint64_t size)
149 if (*((uint32_t*)data)==ELF_MAGIC) {
156 static mb_header_t *find_mb_header(uint8_t *data, uint64_t size)
158 uint64_t limit = size > 32768 ? 32768 : size;
161 // Scan for the .boot magic cookie
162 // must be in first 32K, assume 4 byte aligned
163 for (i=0;i<limit;i+=4) {
164 if (*((uint32_t*)&data[i])==MB2_MAGIC) {
165 INFO("Found multiboot header at offset 0x%llx\n",i);
166 return (mb_header_t *) &data[i];
172 static int checksum4_ok(uint32_t *data, uint64_t size)
177 for (i=0;i<size;i++) {
184 int v3_parse_multiboot_header(void *data, uint64_t size, mb_data_t *mb)
188 mb_header_t *mb_header=0;
191 mb_addr_t *mb_addr=0;
192 mb_entry_t *mb_entry=0;
193 mb_flags_t *mb_flags=0;
194 mb_framebuf_t *mb_framebuf=0;
195 mb_modalign_t *mb_modalign=0;
196 mb_mb64_hrt_t *mb_mb64_hrt=0;
199 if (!is_elf(data,size)) {
200 ERROR("HRT is not an ELF\n");
204 mb_header = find_mb_header(data,size);
207 ERROR("No multiboot header found\n");
211 // Checksum applies only to the header itself, not to
212 // the subsequent tags...
213 if (!checksum4_ok((uint32_t*)mb_header,4)) {
214 ERROR("Multiboot header has bad checksum\n");
218 INFO("Multiboot header: arch=0x%x, headerlen=0x%x\n", mb_header->arch, mb_header->headerlen);
220 mb_tag = (mb_tag_t*)((void*)mb_header+16);
222 while (!(mb_tag->type==0 && mb_tag->size==8)) {
223 INFO("tag: type 0x%x flags=0x%x size=0x%x\n",mb_tag->type, mb_tag->flags,mb_tag->size);
224 switch (mb_tag->type) {
227 ERROR("Multiple info tags found!\n");
230 mb_inf = (mb_info_t*)mb_tag;
231 INFO(" info request - types follow\n");
232 for (i=0;(mb_tag->size-8)/4;i++) {
233 INFO(" %llu: type 0x%x\n", i, mb_inf->types[i]);
238 case MB_TAG_ADDRESS: {
240 ERROR("Multiple address tags found!\n");
243 mb_addr = (mb_addr_t*)mb_tag;
245 INFO(" header_addr = 0x%x\n", mb_addr->header_addr);
246 INFO(" load_addr = 0x%x\n", mb_addr->load_addr);
247 INFO(" load_end_addr = 0x%x\n", mb_addr->load_end_addr);
248 INFO(" bss_end_addr = 0x%x\n", mb_addr->bss_end_addr);
254 ERROR("Multiple entry tags found!\n");
257 mb_entry=(mb_entry_t*)mb_tag;
259 INFO(" entry_addr = 0x%x\n", mb_entry->entry_addr);
265 ERROR("Multiple flags tags found!\n");
268 mb_flags = (mb_flags_t*)mb_tag;
270 INFO(" console_flags = 0x%x\n", mb_flags->console_flags);
274 case MB_TAG_FRAMEBUF: {
276 ERROR("Multiple framebuf tags found!\n");
279 mb_framebuf = (mb_framebuf_t*)mb_tag;
281 INFO(" width = 0x%x\n", mb_framebuf->width);
282 INFO(" height = 0x%x\n", mb_framebuf->height);
283 INFO(" depth = 0x%x\n", mb_framebuf->depth);
287 case MB_TAG_MODALIGN: {
289 ERROR("Multiple modalign tags found!\n");
292 mb_modalign = (mb_modalign_t*)mb_tag;
294 INFO(" size = 0x%x\n", mb_modalign->size);
299 case MB_TAG_MB64_HRT: {
301 ERROR("Multiple mb64_hrt tags found!\n");
304 mb_mb64_hrt = (mb_mb64_hrt_t*)mb_tag;
310 INFO("Unknown tag... Skipping...\n");
313 mb_tag = (mb_tag_t *)(((void*)mb_tag) + mb_tag->size);
316 // copy out to caller
317 mb->header=mb_header;
322 mb->framebuf=mb_framebuf;
323 mb->modalign=mb_modalign;
324 mb->mb64_hrt=mb_mb64_hrt;
331 #define APIC_BASE 0xfee00000
332 #define IOAPIC_BASE 0xfec00000
336 MB_HRT (if this is an HVM
341 1024..ioapic_base RAM
342 ioapic_base to ioapic_base+page reserved
343 ioapic_base+page to apic_base ram
344 apic_base oto apic_base+page reserved
345 apic_base+page to total RAM
348 The multiboot structure that is written reflects the
349 perspective of the core given the kind of VM it is part of.
352 - core does not matter
357 - only ROS memory visible
358 - regular multiboot or bios boot assumed
361 - HRT64 multiboot assumed
365 uint64_t v3_build_multiboot_table(struct guest_info *core, uint8_t *dest, uint64_t size)
367 struct v3_vm_info *vm = core->vm_info;
368 mb_info_header_t *header=0;
370 mb_info_hrt_t *hrt=0;
372 mb_info_mem_t *mem=0;
373 mb_info_memmap_t *memmap=0;
374 mb_info_tag_t *tag=0;
375 uint64_t num_mem=0, cur_mem=0;
377 uint64_t total_mem = vm->mem_size;
380 if (vm->hvm_state.is_hvm) {
381 if (v3_is_hvm_ros_core(core)) {
382 PrintDebug(core->vm_info,core,"multiboot: hvm: building mb table from ROS core perspective\n");
383 total_mem = v3_get_hvm_ros_memsize(vm);
385 PrintDebug(core->vm_info,core,"multiboot: hvm: building mb table from HRT core perspective\n");
386 total_mem = v3_get_hvm_hrt_memsize(vm);
391 // assume we have > 1 MB + apic+ioapic
393 if (total_mem>IOAPIC_BASE+PAGE_SIZE) {
396 if (total_mem>APIC_BASE+PAGE_SIZE) {
402 sizeof(mb_info_header_t) +
404 core->vm_info->hvm_state.is_hvm && core->hvm_state.is_hrt ? sizeof(mb_info_hrt_t) : 0
407 sizeof(mb_info_mem_t) +
408 sizeof(mb_info_memmap_t) +
409 sizeof(mb_info_memmap_entry_t) * num_mem +
410 sizeof(mb_info_tag_t);
419 ERROR("Cannot fit MB info in needed space\n");
425 header = (mb_info_header_t*)next;
426 next += sizeof(mb_info_header_t);
429 if (core->vm_info->hvm_state.is_hvm && v3_is_hvm_hrt_core(core)) {
430 hrt = (mb_info_hrt_t*)next;
431 next += sizeof(mb_info_hrt_t);
435 mem = (mb_info_mem_t*)next;
436 next += sizeof(mb_info_mem_t);
438 memmap = (mb_info_memmap_t*)next;
439 next += sizeof(mb_info_memmap_t) + num_mem * sizeof(mb_info_memmap_entry_t);
441 tag = (mb_info_tag_t*)next;
442 next += sizeof(mb_info_tag_t);
444 header->totalsize = (uint32_t)(next - dest);
445 header->reserved = 0;
448 if (core->vm_info->hvm_state.is_hvm && v3_is_hvm_hrt_core(core)) {
449 v3_build_hrt_multiboot_tag(core,hrt);
453 mem->tag.type = MB_INFO_MEM_TAG;
454 mem->tag.size = sizeof(mb_info_mem_t);
455 mem->mem_lower = 640; // thank you, bill gates
456 mem->mem_upper = (total_mem - 1024 * 1024) / 1024;
458 memmap->tag.type = MB_INFO_MEMMAP_TAG;
459 memmap->tag.size = sizeof(mb_info_memmap_t) + num_mem * sizeof(mb_info_memmap_entry_t);
460 memmap->entry_size = 24;
461 memmap->entry_version = 0;
466 memmap->entries[cur_mem].base_addr = 0;
467 memmap->entries[cur_mem].length = 640*1024;
468 memmap->entries[cur_mem].type = MEM_RAM;
469 memmap->entries[cur_mem].reserved = 0;
472 // legacy io (640K->1 MB)
473 memmap->entries[cur_mem].base_addr = 640*1024;
474 memmap->entries[cur_mem].length = 384*1024;
475 memmap->entries[cur_mem].type = MEM_RESV;
476 memmap->entries[cur_mem].reserved = 1;
479 // first meg to ioapic
480 memmap->entries[cur_mem].base_addr = 1024*1024;
481 memmap->entries[cur_mem].length = (total_mem < IOAPIC_BASE ? total_mem : IOAPIC_BASE) - 1024*1024;
482 memmap->entries[cur_mem].type = MEM_RAM;
483 memmap->entries[cur_mem].reserved = 0;
486 // ioapic reservation
487 memmap->entries[cur_mem].base_addr = IOAPIC_BASE;
488 memmap->entries[cur_mem].length = PAGE_SIZE;
489 memmap->entries[cur_mem].type = MEM_RESV;
490 memmap->entries[cur_mem].reserved = 1;
493 if (total_mem > (IOAPIC_BASE + PAGE_SIZE)) {
494 // memory between ioapic and apic
495 memmap->entries[cur_mem].base_addr = IOAPIC_BASE+PAGE_SIZE;
496 memmap->entries[cur_mem].length = (total_mem < APIC_BASE ? total_mem : APIC_BASE) - (IOAPIC_BASE+PAGE_SIZE);;
497 memmap->entries[cur_mem].type = MEM_RAM;
498 memmap->entries[cur_mem].reserved = 0;
503 memmap->entries[cur_mem].base_addr = APIC_BASE;
504 memmap->entries[cur_mem].length = PAGE_SIZE;
505 memmap->entries[cur_mem].type = MEM_RESV;
506 memmap->entries[cur_mem].reserved = 1;
509 if (total_mem > (APIC_BASE + PAGE_SIZE)) {
511 memmap->entries[cur_mem].base_addr = APIC_BASE+PAGE_SIZE;
512 memmap->entries[cur_mem].length = total_mem - (APIC_BASE+PAGE_SIZE);
513 memmap->entries[cur_mem].type = MEM_RAM;
514 memmap->entries[cur_mem].reserved = 0;
518 for (cur_mem=0;cur_mem<num_mem;cur_mem++) {
519 PrintDebug(vm, VCORE_NONE,
520 "multiboot: entry %llu: %p (%llx bytes) - type %x %s\n",
522 (void*) memmap->entries[cur_mem].base_addr,
523 memmap->entries[cur_mem].length,
524 memmap->entries[cur_mem].type,
525 memmap->entries[cur_mem].reserved ? "reserved" : "");
530 // This demarcates end of list
534 return header->totalsize;
539 int v3_write_multiboot_kernel(struct v3_vm_info *vm, mb_data_t *mb, void *data, uint64_t len,
540 void *base, uint64_t limit)
543 uint32_t header_offset = (uint32_t) ((uint64_t)(mb->header) - (uint64_t)(data));
546 if (!mb->addr || !mb->entry) {
547 PrintError(vm,VCORE_NONE, "multiboot: kernel is missing address or entry point\n");
551 if (((void*)(uint64_t)(mb->addr->header_addr) < base ) ||
552 ((void*)(uint64_t)(mb->addr->load_end_addr) > base+limit) ||
553 ((void*)(uint64_t)(mb->addr->bss_end_addr) > base+limit)) {
554 PrintError(vm,VCORE_NONE, "multiboot: kernel is not within the allowed portion of VM\n");
558 offset = header_offset - (mb->addr->header_addr - mb->addr->load_addr);
559 size = mb->addr->load_end_addr - mb->addr->load_addr;
561 if (size != len-offset) {
562 V3_Print(vm,VCORE_NONE,"multiboot: strange: size computed as %u, but len-offset = %llu\n",size,len-offset);
565 // We are trying to do as little ELF loading here as humanly possible
566 v3_write_gpa_memory(&vm->cores[0],
567 (addr_t)(mb->addr->load_addr),
571 PrintDebug(vm,VCORE_NONE,
572 "multiboot: wrote 0x%llx bytes starting at offset 0x%llx to %p\n",
575 (void*)(addr_t)(mb->addr->load_addr));
577 size = mb->addr->bss_end_addr - mb->addr->load_end_addr + 1;
579 // Now we need to zero the BSS
580 v3_set_gpa_memory(&vm->cores[0],
581 (addr_t)(mb->addr->load_end_addr),
585 PrintDebug(vm,VCORE_NONE,
586 "multiboot: zeroed 0x%llx bytes starting at %p\n",
588 (void*)(addr_t)(mb->addr->load_end_addr));
596 static int setup_multiboot_kernel(struct v3_vm_info *vm)
599 uint64_t limit = vm->mem_size;
602 if (vm->mb_state.mb_file->size > limit) {
603 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);
607 if (!is_elf(vm->mb_state.mb_file->data,vm->mb_state.mb_file->size)) {
608 PrintError(vm,VCORE_NONE,"multiboot: supplied kernel is not an ELF\n");
611 if (find_mb_header(vm->mb_state.mb_file->data,vm->mb_state.mb_file->size)) {
612 PrintDebug(vm,VCORE_NONE,"multiboot: appears to be a multiboot kernel\n");
613 if (v3_parse_multiboot_header(vm->mb_state.mb_file->data,vm->mb_state.mb_file->size,&vm->mb_state.mb_data)) {
614 PrintError(vm,VCORE_NONE,"multiboot: cannot parse multiboot kernel header\n");
617 if (v3_write_multiboot_kernel(vm, &(vm->mb_state.mb_data),vm->mb_state.mb_file->data,vm->mb_state.mb_file->size,base,limit)) {
618 PrintError(vm,VCORE_NONE,"multiboot: multiboot kernel setup failed\n");
622 PrintError(vm,VCORE_NONE,"multiboot: multiboot kernel has no header\n");
631 // 32 bit GDT entries
633 // base24-31 flags2 limit16-19 access8 base16-23 base0-15 limit0-15
634 // null 0 0 0 0 0 0 0
635 // code 0 1100 f 10011010 0 0 ffff
636 // data 0 1100 f 10010010 0 0 ffff
638 // null = 00 00 00 00 00 00 00 00
639 // code = 00 cf 9a 00 00 00 ff ff
640 // data = 00 cf 92 00 00 00 ff ff
642 static uint64_t gdt32[3] = {
643 0x0000000000000000, /* null */
644 0x00cf9a000000ffff, /* code (note lme=0) */
645 0x00cf92000000ffff, /* data */
648 static void write_gdt(struct v3_vm_info *vm, void *base, uint64_t limit)
650 v3_write_gpa_memory(&vm->cores[0],(addr_t)base,limit,(uint8_t*) gdt32);
652 PrintDebug(vm,VCORE_NONE,"multiboot: wrote GDT at %p\n",base);
656 static void write_tss(struct v3_vm_info *vm, void *base, uint64_t limit)
658 v3_set_gpa_memory(&vm->cores[0],(addr_t)base,limit,0);
660 PrintDebug(vm,VCORE_NONE,"multiboot: wrote TSS at %p\n",base);
663 static void write_table(struct v3_vm_info *vm, void *base, uint64_t limit)
668 limit = limit < 256 ? limit : 256;
670 size = v3_build_multiboot_table(&vm->cores[0], buf, limit);
672 if (size>256 || size==0) {
673 PrintError(vm,VCORE_NONE,"multiboot: cannot build multiboot table\n");
677 v3_write_gpa_memory(&vm->cores[0],(addr_t)base,size,buf);
689 Kernel at its desired load address (or error)
694 int v3_setup_multiboot_vm_for_boot(struct v3_vm_info *vm)
696 void *kernel_start_gpa;
697 void *kernel_end_gpa;
702 if (!vm->mb_state.is_multiboot) {
703 PrintDebug(vm,VCORE_NONE,"multiboot: skipping multiboot setup for boot as this is not a multiboot VM\n");
708 if (setup_multiboot_kernel(vm)) {
709 PrintError(vm,VCORE_NONE,"multiboot: failed to setup kernel\n");
713 kernel_start_gpa = (void*) (uint64_t) (vm->mb_state.mb_data.addr->load_addr);
714 kernel_end_gpa = (void*) (uint64_t) (vm->mb_state.mb_data.addr->bss_end_addr);
716 // Is there room below the kernel?
717 if ((uint64_t)kernel_start_gpa > 19*4096 ) {
718 // at least 3 pages between 64K and start of kernel
720 mb_gpa=(void*)(16*4096);
722 // is there room above the kernel?
723 if ((uint64_t)kernel_end_gpa < vm->mem_size-4*4096) {
724 if (((uint64_t)kernel_end_gpa + 4 * 4096) <= 0xffffffff) {
725 mb_gpa=(void*) (4096*((uint64_t)kernel_end_gpa/4096 + 1));
727 PrintError(vm,VCORE_NONE,"multiboot: no room for mb data below 4 GB\n");
731 PrintError(vm,VCORE_NONE,"multiboot: no room for mb data above kernel\n");
736 PrintDebug(vm,VCORE_NONE,"multiboot: mb data will start at %p\n",mb_gpa);
738 vm->mb_state.mb_data_gpa=mb_gpa;
740 tss_gpa = mb_gpa + 1 * 4096;
741 gdt_gpa = mb_gpa + 2 * 4096;
743 write_table(vm,mb_gpa,4096);
745 write_tss(vm,tss_gpa,4096);
747 write_gdt(vm,gdt_gpa,4096);
749 PrintDebug(vm,VCORE_NONE,"multiboot: setup of memory done\n");
758 GDTR points to stub GDT
759 TR points to stub TSS
760 CR0 has PE and not PG
761 EIP is entry point to kernel
762 EBX points to multiboot info
763 EAX multiboot magic cookie
766 int v3_setup_multiboot_core_for_boot(struct guest_info *core)
771 if (!core->vm_info->mb_state.is_multiboot) {
772 PrintDebug(core->vm_info,core,"multiboot: skipping mb core setup as this is not an mb VM\n");
776 if (core->vcpu_id != 0) {
777 PrintDebug(core->vm_info,core,"multiboot: skipping mb core setup as this is not the BSP core\n");
782 PrintDebug(core->vm_info, core, "multiboot: setting up MB BSP core for boot\n");
785 memset(&core->vm_regs,0,sizeof(core->vm_regs));
786 memset(&core->ctrl_regs,0,sizeof(core->ctrl_regs));
787 memset(&core->dbg_regs,0,sizeof(core->dbg_regs));
788 memset(&core->segments,0,sizeof(core->segments));
789 memset(&core->msrs,0,sizeof(core->msrs));
790 memset(&core->fp_state,0,sizeof(core->fp_state));
792 // We need to be in protected mode at ring zero
793 core->cpl = 0; // we are going right into the kernel
794 core->cpu_mode = PROTECTED;
795 core->mem_mode = PHYSICAL_MEM;
796 // default run-state is fine, we are core zero
797 // core->core_run_state = CORE_RUNNING ;
799 // right into the kernel
800 core->rip = (uint64_t) core->vm_info->mb_state.mb_data.entry->entry_addr;
802 // Setup CRs for protected mode
803 // CR0: PE (but no PG)
804 core->ctrl_regs.cr0 = 0x1;
805 core->shdw_pg_state.guest_cr0 = core->ctrl_regs.cr0;
807 // CR2: don't care (output from #PF)
808 // CR3: don't care (no paging)
809 core->ctrl_regs.cr3 = 0;
810 core->shdw_pg_state.guest_cr3 = core->ctrl_regs.cr3;
813 core->ctrl_regs.cr4 = 0x0;
814 core->shdw_pg_state.guest_cr4 = core->ctrl_regs.cr4;
816 // RFLAGS zeroed is fine: come in with interrupts off
817 // 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
818 core->ctrl_regs.efer = 0x1400;
819 core->shdw_pg_state.guest_efer.value = core->ctrl_regs.efer;
825 selector is 13 bits of index, 1 bit table indicator
828 index is scaled by 8, even in long mode, where some entries
829 are 16 bytes long....
830 -> code, data descriptors have 8 byte format
831 because base, limit, etc, are ignored (no segmentation)
832 -> interrupt/trap gates have 16 byte format
833 because offset needs to be 64 bits
836 // There is no IDTR set and interrupts are disabled
838 // Install our stub GDT
839 core->segments.gdtr.selector = 0;
840 core->segments.gdtr.base = (addr_t) core->vm_info->mb_state.mb_data_gpa+2*4096;
841 core->segments.gdtr.limit = 4096-1;
842 core->segments.gdtr.type = 0x6;
843 core->segments.gdtr.system = 1;
844 core->segments.gdtr.dpl = 0;
845 core->segments.gdtr.present = 1;
846 core->segments.gdtr.long_mode = 0;
849 core->segments.tr.selector = 0;
850 core->segments.tr.base = (addr_t) core->vm_info->mb_state.mb_data_gpa+1*4096;
851 core->segments.tr.limit = 4096-1;
852 core->segments.tr.type = 0x6;
853 core->segments.tr.system = 1;
854 core->segments.tr.dpl = 0;
855 core->segments.tr.present = 1;
856 core->segments.tr.long_mode = 0;
862 core->segments.cs.selector = 0x8 ; // entry 1 of GDT (RPL=0)
863 core->segments.cs.base = (addr_t) base;
864 core->segments.cs.limit = limit;
865 core->segments.cs.type = 0xa;
866 core->segments.cs.system = 1;
867 core->segments.cs.dpl = 0;
868 core->segments.cs.present = 1;
869 core->segments.cs.long_mode = 0;
870 core->segments.cs.db = 1; // 32 bit operand and address size
871 core->segments.cs.granularity = 1; // pages
873 // DS, SS, etc are identical
874 core->segments.ds.selector = 0x10; // entry 2 of GDT (RPL=0)
875 core->segments.ds.base = (addr_t) base;
876 core->segments.ds.limit = limit;
877 core->segments.ds.type = 0x2;
878 core->segments.ds.system = 1;
879 core->segments.ds.dpl = 0;
880 core->segments.ds.present = 1;
881 core->segments.ds.long_mode = 0;
882 core->segments.ds.db = 1; // 32 bit operand and address size
883 core->segments.ds.granularity = 1; // pages
885 memcpy(&core->segments.ss,&core->segments.ds,sizeof(core->segments.ds));
886 memcpy(&core->segments.es,&core->segments.ds,sizeof(core->segments.ds));
887 memcpy(&core->segments.fs,&core->segments.ds,sizeof(core->segments.ds));
888 memcpy(&core->segments.gs,&core->segments.ds,sizeof(core->segments.ds));
892 // Now for our magic - this signals
893 // the kernel that a multiboot loader loaded it
894 // and that rbx points to its offered data
895 core->vm_regs.rax = MB2_INFO_MAGIC;
897 core->vm_regs.rbx = (uint64_t) (core->vm_info->mb_state.mb_data_gpa);
899 // reset paging here for shadow...
901 if (core->shdw_pg_mode != NESTED_PAGING) {
902 PrintError(core->vm_info, core, "multiboot: shadow paging guest... this will end badly\n");
911 int v3_handle_multiboot_reset(struct guest_info *core)
915 if (core->core_run_state!=CORE_RESETTING) {
919 if (!core->vm_info->mb_state.is_multiboot) {
924 v3_counting_barrier(&core->vm_info->reset_barrier);
926 if (core->vcpu_id==0) {
927 // I am leader (this is true if I am a ROS core or this is a non-HVM)
928 core->vm_info->run_state = VM_RESETTING;
933 if (core->vcpu_id==0) {
934 // we will recopy the image
935 rc |= v3_setup_multiboot_vm_for_boot(core->vm_info);
938 rc |= v3_setup_multiboot_core_for_boot(core);
940 if (core->vcpu_id==0) {
941 core->core_run_state = CORE_RUNNING;
942 core->vm_info->run_state = VM_RUNNING;
944 // for APs, we need to bring them back to the init state
945 core->cpu_mode = REAL;
946 core->mem_mode = PHYSICAL_MEM;
947 core->core_run_state = CORE_STOPPED;
950 // sync on the way out
951 v3_counting_barrier(&core->vm_info->reset_barrier);