Index: grub2/conf/i386-efi.rmk =================================================================== diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index d9e74b3..c315811 100644 --- a/grub-core/loader/multiboot.c +++ b/grub-core/loader/multiboot.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -63,6 +65,8 @@ static int console_required; static grub_dl_t my_mod; +#include "xen.c" + /* Return the length of the Multiboot mmap that will be needed to allocate our platform's map. */ grub_uint32_t @@ -112,6 +116,34 @@ grub_multiboot_set_video_mode (void) } static grub_err_t +grub_xen_boot (void) +{ + grub_err_t err; + struct grub_relocator32_state state = MULTIBOOT_INITIAL_STATE; + + state.MULTIBOOT_ENTRY_REGISTER = grub_multiboot_payload_eip; + + err = grub_multiboot_make_mbi (&state.MULTIBOOT_MBI_REGISTER); + + if (err) + return err; + + xen_stop_dma(); + +#ifdef GRUB_MACHINE_EFI + err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); + if (err) + return err; +#endif + + grub_relocator32_boot (grub_multiboot_relocator, state); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + + +static grub_err_t grub_multiboot_boot (void) { grub_err_t err; @@ -213,6 +245,72 @@ grub_multiboot_set_console (int console_type, int accepted_consoles, } static grub_err_t +grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file = 0; + grub_err_t err; + + grub_loader_unset (); + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); + + file = grub_file_open (argv[0]); + if (! file) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file"); + + grub_dl_ref (my_mod); + + /* Skip filename. */ + grub_multiboot_init_mbi (argc - 1, argv + 1); + + grub_relocator_unload (grub_multiboot_relocator); + grub_multiboot_relocator = grub_relocator_new (); + + if (!grub_multiboot_relocator) + goto fail; + + err = grub_multiboot_load (file); + if (err) + goto fail; + + /* God awful hack to find the xen binary in memory */ + { + struct grub_relocator + { + struct grub_relocator_chunk *chunks; + grub_phys_addr_t postchunks; + grub_phys_addr_t highestaddr; + grub_phys_addr_t highestnonpostaddr; + grub_size_t relocators_size; + } *gr = (struct grub_relocator *) grub_multiboot_relocator; + + + void * xen_base=get_virtual_current_address (gr->chunks); + xen_setup(xen_base); + } + + grub_multiboot_set_bootdev (); + + grub_loader_set (grub_xen_boot, grub_multiboot_unload, 0); + + fail: + if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + { + grub_relocator_unload (grub_multiboot_relocator); + grub_multiboot_relocator = NULL; + grub_dl_unref (my_mod); + } + + return grub_errno; +} + + +static grub_err_t grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { @@ -329,23 +427,32 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), return GRUB_ERR_NONE;; } -static grub_command_t cmd_multiboot, cmd_module; +static grub_command_t cmd_multiboot, cmd_module, cmd_xen; GRUB_MOD_INIT(multiboot) { cmd_multiboot = #ifdef GRUB_USE_MULTIBOOT2 + grub_register_command ("multiboot2", grub_cmd_multiboot, 0, N_("Load a multiboot 2 kernel.")); cmd_module = grub_register_command ("module2", grub_cmd_module, 0, N_("Load a multiboot 2 module.")); + + cmd_xen = + grub_register_command ("xen2", grub_cmd_xen, + 0, N_("Load a multiboot 2 xen kernel.")); #else grub_register_command ("multiboot", grub_cmd_multiboot, 0, N_("Load a multiboot kernel.")); cmd_module = grub_register_command ("module", grub_cmd_module, 0, N_("Load a multiboot module.")); + + cmd_xen = + grub_register_command ("xen", grub_cmd_xen, + 0, N_("Load a multiboot xen kernel.")); #endif my_mod = mod; diff --git a/grub-core/loader/xen.c b/grub-core/loader/xen.c new file mode 100644 index 0000000..63ce927 --- /dev/null +++ b/grub-core/loader/xen.c @@ -0,0 +1,303 @@ + +#define XEN_EFI_MAGIC 0xdeadbeefef104eadULL +#define XEN_LOADER_GRUB_64 0x0034365f36387847ULL +#define XEN_LOADER_GRUB_32 0x0000003233616947ULL + +struct xen_efi_hdr +{ + grub_uint64_t magic; + grub_uint64_t efi_loader_signature; + grub_uint64_t efi_system_table_addr; + grub_uint64_t realmode_available; + grub_uint64_t boot_vid_mode; + grub_uint64_t boot_vid_info; +} __attribute__((packed)); + +struct xen_boot_video_info { + grub_uint8_t orig_x; /* 0x00 */ + grub_uint8_t orig_y; /* 0x01 */ + grub_uint8_t orig_video_mode; /* 0x02 */ + grub_uint8_t orig_video_cols; /* 0x03 */ + grub_uint8_t orig_video_lines; /* 0x04 */ + grub_uint8_t orig_video_isVGA; /* 0x05 */ + grub_uint16_t orig_video_points; /* 0x06 */ + + /* VESA graphic mode -- linear frame buffer */ + grub_uint32_t capabilities; /* 0x08 */ + grub_uint16_t lfb_linelength; /* 0x0c */ + grub_uint16_t lfb_width; /* 0x0e */ + grub_uint16_t lfb_height; /* 0x10 */ + grub_uint16_t lfb_depth; /* 0x12 */ + grub_uint32_t lfb_base; /* 0x14 */ + grub_uint32_t lfb_size; /* 0x18 */ + grub_uint8_t red_size; /* 0x1c */ + grub_uint8_t red_pos; /* 0x1d */ + grub_uint8_t green_size; /* 0x1e */ + grub_uint8_t green_pos; /* 0x1f */ + grub_uint8_t blue_size; /* 0x20 */ + grub_uint8_t blue_pos; /* 0x21 */ + grub_uint8_t rsvd_size; /* 0x22 */ + grub_uint8_t rsvd_pos; /* 0x23 */ + grub_uint16_t vesapm_seg; /* 0x24 */ + grub_uint16_t vesapm_off; /* 0x26 */ + grub_uint16_t vesa_attrib; /* 0x28 */ +} __attribute__((packed)); + +#ifdef GRUB_MACHINE_EFI + +static grub_efi_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID; +static grub_efi_guid_t acpi2_guid = GRUB_EFI_ACPI_20_TABLE_GUID; +static grub_efi_guid_t smbios_guid = GRUB_EFI_SMBIOS_TABLE_GUID; + +#define EBDA_SEG_ADDR 0x40e +#define LOW_MEM_ADDR 0x413 +#define FAKE_EBDA_SEG 0x7000 +#define FAKE_SMBIOS_SEG 0x7f00 + +static void +inject_bios_acpi (void) +{ + unsigned i; + void *acpi; + grub_uint16_t *ebda_seg_ptr, *low_mem_ptr; + + acpi = 0; + for (i = 0; i < grub_efi_system_table->num_table_entries; i++) + { + grub_efi_guid_t *guid = + &grub_efi_system_table->configuration_table[i].vendor_guid; + + if (!grub_memcmp (guid, &acpi2_guid, sizeof (grub_efi_guid_t))) + { + acpi = grub_efi_system_table->configuration_table[i].vendor_table; + grub_printf ("ACPI2: %p\n", acpi); + } + else if (!grub_memcmp (guid, &acpi_guid, sizeof (grub_efi_guid_t))) + { + void *t; + + t = grub_efi_system_table->configuration_table[i].vendor_table; + if (!acpi) + acpi = t; + grub_printf ("ACPI: %p\n", t); + } + } + + if (acpi == 0) + return; + + ebda_seg_ptr = (grub_uint16_t *) EBDA_SEG_ADDR; + low_mem_ptr = (grub_uint16_t *) LOW_MEM_ADDR; + + *ebda_seg_ptr = FAKE_EBDA_SEG; + *low_mem_ptr = FAKE_EBDA_SEG >> 6; + + grub_printf("Copying acpi %p to %x\n",acpi,(int) (FAKE_EBDA_SEG << 4)); + grub_memcpy ((char *) (FAKE_EBDA_SEG << 4), acpi, 0xf000); + +} + +static void +inject_bios_smbios(void) +{ + unsigned i; + void *smbios; + + smbios = 0; + for (i = 0; i < grub_efi_system_table->num_table_entries; i++) + { + grub_efi_guid_t *guid = + &grub_efi_system_table->configuration_table[i].vendor_guid; + + if (!grub_memcmp (guid, &smbios_guid, sizeof (grub_efi_guid_t))) + { + smbios = grub_efi_system_table->configuration_table[i].vendor_table; + grub_printf ("SMBIOS: %p\n", smbios); + } + } + + if (smbios == 0) + return; + + grub_printf("Copying smbios %p to %x\n",smbios,(int) (FAKE_SMBIOS_SEG << 4)); + grub_memcpy ((char *) (FAKE_SMBIOS_SEG << 4), smbios, 0x1000); +} + + +static void fake_bios_data(void) +{ + inject_bios_smbios(); + inject_bios_acpi(); +} + +#endif + +static void xen_stop_dma(void) +{ + + auto int NESTED_FUNC_ATTR stop_card_dma (grub_pci_device_t dev, + grub_pci_id_t pciid); + + int NESTED_FUNC_ATTR stop_card_dma (grub_pci_device_t dev, + grub_pci_id_t pciid) + { + grub_pci_address_t addr; + grub_uint16_t old_cmd,new_cmd; + + (void) pciid; + + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); + + switch (grub_pci_read (addr) >> 24) { + case 0x00: /*unknown*/ + case 0x03: /*GPU*/ + case 0x05: /*memory*/ + case 0x06: /*bridge*/ + case 0x07: /*firewire*/ + case 0x0b: /*cpu*/ + break; + default: /*everything else gets dma turned off*/ + + addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND); + old_cmd = grub_pci_read_word(addr); + new_cmd = old_cmd & ~GRUB_PCI_COMMAND_BUS_MASTER; + grub_pci_write_word(addr,new_cmd); + +#if 0 + if (old_cmd!=new_cmd) { + grub_printf ("Disabled DMA on: %02x:%02x.%x %04x -> %04x\n", + grub_pci_get_bus (dev), grub_pci_get_device (dev), + grub_pci_get_function (dev), (int) old_cmd,(int) new_cmd); + } +#endif + } + + return 0; + } + + grub_pci_iterate (stop_card_dma); +} + + +static int +xen_setup_video (struct xen_boot_video_info *bvi) +{ + struct grub_video_mode_info mode_info; + void *framebuffer; + grub_err_t err; + grub_video_driver_id_t driver_id; + + driver_id = grub_video_get_driver_id (); + + if (driver_id == GRUB_VIDEO_DRIVER_NONE) + return 1; + +// err = grub_video_get_info_and_fini (&mode_info, &framebuffer); + err = grub_video_get_info_and_carry_on (&mode_info, &framebuffer); + + if (err) + { + grub_errno = GRUB_ERR_NONE; + return 1; + } + + grub_printf("Frame buffer is %d (stride 0x%x) x %d @ %p\n",mode_info.width,mode_info.pitch,mode_info.height, framebuffer); + + bvi->orig_video_isVGA=0x23; /*XXX: what is 0x23? */ + + bvi->lfb_linelength=mode_info.pitch; + bvi->lfb_width=mode_info.width; + bvi->lfb_height=mode_info.height; + bvi->lfb_depth=mode_info.bpp; + + bvi->lfb_base=(grub_size_t) framebuffer; + bvi->lfb_size=ALIGN_UP ((unsigned int) mode_info.pitch * (unsigned int) mode_info.height, 65536); + + bvi->red_size=mode_info.red_mask_size; + bvi->red_pos=mode_info.red_field_pos; + + bvi->green_size=mode_info.green_mask_size; + bvi->green_pos=mode_info.green_field_pos; + + bvi->blue_size=mode_info.blue_mask_size; + bvi->blue_pos=mode_info.blue_field_pos; + + bvi->rsvd_size=mode_info.reserved_mask_size; + bvi->rsvd_pos=mode_info.reserved_field_pos; + + bvi->vesa_attrib=0x3; /*Possible(0x1) and has extended data(0x2)*/ + + + /* No protected mode*/ + bvi->vesapm_seg=0x0; + bvi->vesapm_off=0x0; + + bvi->vesa_attrib=0x1; /*Dac is 8 bit capable*/ + + + return GRUB_ERR_NONE; +} + + + + +static grub_err_t +xen_setup (grub_uint8_t * base) +{ + struct xen_efi_hdr *hdr; + grub_uint8_t *realmode_available; + grub_uint16_t *boot_vid_mode; + grub_uint64_t *efi_system_table_addr; + grub_uint64_t *efi_loader_signature; + struct xen_boot_video_info *bvi; + + int i; + + for (i = 0; i <0x200; i++) + { + hdr = (struct xen_efi_hdr *) (base + i); + if (hdr->magic == XEN_EFI_MAGIC) + break; + } + + if (hdr->magic != XEN_EFI_MAGIC) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "No EFI support in hypervisor"); + + grub_printf("\nbase addr is %p\nhdr found at %p\n",base,hdr); + + realmode_available=(grub_uint8_t *)(grub_size_t)hdr->realmode_available; + grub_printf("realmode_available was %x@%p\n",(int) *realmode_available,realmode_available); + *realmode_available=0; + + efi_loader_signature=(grub_uint64_t*)(grub_size_t)hdr->efi_loader_signature; + +#if defined(__x86_64__) + *efi_loader_signature=XEN_LOADER_GRUB_64; +#elif defined (__i386__) + *efi_loader_signature=XEN_LOADER_GRUB_32; +#else + *efi_loader_signature=0; +#endif + + efi_system_table_addr=(grub_uint64_t*)(grub_size_t)hdr->efi_system_table_addr; + + grub_printf("efi_system_table_addr was %llx@%p\n",(long long unsigned) *efi_system_table_addr, efi_system_table_addr); + + *efi_system_table_addr= (grub_uint64_t) (grub_size_t) grub_efi_system_table; + + boot_vid_mode=(grub_uint16_t *)(grub_size_t)hdr->boot_vid_mode; + grub_printf("boot_vid_mode was 0x%x@%p\n",(int) *boot_vid_mode,boot_vid_mode); + *boot_vid_mode=0xf00; + + bvi=(struct xen_boot_video_info *)(grub_size_t)hdr->boot_vid_info; + grub_printf("boot_vid_info @%p\n",bvi); + + xen_setup_video (bvi); + + fake_bios_data(); + + return GRUB_ERR_NONE; +} + + + diff --git a/grub-core/video/efi_gop.c b/grub-core/video/efi_gop.c index d14ae98..6045b21 100644 --- a/grub-core/video/efi_gop.c +++ b/grub-core/video/efi_gop.c @@ -378,6 +378,17 @@ grub_video_gop_set_active_render_target (struct grub_video_render_target *target } static grub_err_t +grub_video_gop_get_info_and_carry_on (struct grub_video_mode_info *mode_info, + void **framebuf) +{ + grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info)); + *framebuf = (char *) framebuffer.ptr; + + return GRUB_ERR_NONE; +} + + +static grub_err_t grub_video_gop_get_info_and_fini (struct grub_video_mode_info *mode_info, void **framebuf) { @@ -389,6 +400,7 @@ grub_video_gop_get_info_and_fini (struct grub_video_mode_info *mode_info, return GRUB_ERR_NONE; } + static struct grub_video_adapter grub_video_gop_adapter = { .name = "EFI GOP driver", @@ -400,6 +412,7 @@ static struct grub_video_adapter grub_video_gop_adapter = .fini = grub_video_gop_fini, .setup = grub_video_gop_setup, .get_info = grub_video_fb_get_info, + .get_info_and_carry_on = grub_video_gop_get_info_and_carry_on, .get_info_and_fini = grub_video_gop_get_info_and_fini, .set_palette = grub_video_fb_set_palette, .get_palette = grub_video_fb_get_palette, diff --git a/grub-core/video/efi_uga.c b/grub-core/video/efi_uga.c index 1e709a5..af26f99 100644 --- a/grub-core/video/efi_uga.c +++ b/grub-core/video/efi_uga.c @@ -289,6 +289,16 @@ grub_video_uga_set_active_render_target (struct grub_video_render_target *target } static grub_err_t +grub_video_uga_get_info_and_carry_on (struct grub_video_mode_info *mode_info, + void **framebuf) +{ + grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info)); + *framebuf = (char *) framebuffer.ptr; + + return GRUB_ERR_NONE; +} + +static grub_err_t grub_video_uga_get_info_and_fini (struct grub_video_mode_info *mode_info, void **framebuf) { @@ -311,6 +321,7 @@ static struct grub_video_adapter grub_video_uga_adapter = .fini = grub_video_uga_fini, .setup = grub_video_uga_setup, .get_info = grub_video_fb_get_info, + .get_info_and_carry_on = grub_video_uga_get_info_and_carry_on, .get_info_and_fini = grub_video_uga_get_info_and_fini, .set_palette = grub_video_fb_set_palette, .get_palette = grub_video_fb_get_palette, diff --git a/grub-core/video/video.c b/grub-core/video/video.c index 6a1d473..3fbfed8 100644 --- a/grub-core/video/video.c +++ b/grub-core/video/video.c @@ -72,6 +72,24 @@ grub_video_get_driver_id (void) /* Get information about active video mode. */ grub_err_t +grub_video_get_info_and_carry_on (struct grub_video_mode_info *mode_info, + void **framebuffer) +{ + grub_err_t err; + + if (! grub_video_adapter_active) + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); + + err = grub_video_adapter_active->get_info_and_carry_on (mode_info, framebuffer); + if (err) + return err; + + return GRUB_ERR_NONE; +} + + +/* Get information about active video mode. */ +grub_err_t grub_video_get_info_and_fini (struct grub_video_mode_info *mode_info, void **framebuffer) { diff --git a/include/grub/video.h b/include/grub/video.h index 97bd85b..8047512 100644 --- a/include/grub/video.h +++ b/include/grub/video.h @@ -255,6 +255,9 @@ struct grub_video_adapter grub_err_t (*get_info) (struct grub_video_mode_info *mode_info); + grub_err_t (*get_info_and_carry_on) (struct grub_video_mode_info *mode_info, + void **framebuffer); + grub_err_t (*get_info_and_fini) (struct grub_video_mode_info *mode_info, void **framebuffer); @@ -349,6 +352,9 @@ grub_err_t EXPORT_FUNC (grub_video_get_info) (struct grub_video_mode_info *mode_ sure that framebuffer address doesn't change. To ensure this abstraction grub_video_get_info_and_fini is the only function supplying framebuffer address. */ +grub_err_t EXPORT_FUNC (grub_video_get_info_and_carry_on) (struct grub_video_mode_info *mode_info, + void **framebuffer); + grub_err_t EXPORT_FUNC (grub_video_get_info_and_fini) (struct grub_video_mode_info *mode_info, void **framebuffer);