diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 37c0ce970..ae604b3c6 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1146,6 +1146,13 @@ module = { enable = x86; }; +module = { + name = plan9; + i386_pc = loader/i386/pc/plan9.c; + enable = i386_pc; +}; + + module = { name = linux16; i386_pc = loader/i386/pc/linux.c; diff --git a/grub-core/loader/i386/pc/plan9.c b/grub-core/loader/i386/pc/plan9.c new file mode 100644 index 000000000..aa96ae83c --- /dev/null +++ b/grub-core/loader/i386/pc/plan9.c @@ -0,0 +1,219 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static grub_dl_t my_mod; +static struct grub_relocator *rel; +static grub_uint32_t eip = 0xffffffff; + +#define GRUB_PLAN9_TARGET 0x100000 +#define GRUB_PLAN9_CONFIG_ADDR 0x001200 +#define GRUB_PLAN9_CONFIG_PATH_SIZE 0x000040 +#define GRUB_PLAN9_CONFIG_MAGIC "ZORT 0\r\n" + +struct grub_plan9_header +{ + grub_uint32_t magic; +#define GRUB_PLAN9_MAGIC 0x1eb + grub_uint32_t text_size; + grub_uint32_t data_size; + grub_uint32_t bss_size; + grub_uint32_t zero1; + grub_uint32_t entry_addr; + grub_uint32_t zero2; + grub_uint32_t zero3; +}; + +static grub_err_t +grub_plan9_boot (void) +{ + struct grub_relocator32_state state = { + .eax = 0, + .eip = eip, + .ebx = 0, + .ecx = 0, + .edx = 0, + .edi = 0, + .esp = 0, + .ebp = 0, + .esi = 0 + /* grub_uint32_t ebp; + grub_uint32_t esi; +*/ + }; + grub_video_set_mode ("text", 0, 0); + + return grub_relocator32_boot (rel, state); +} + +static grub_err_t +grub_plan9_unload (void) +{ + grub_relocator_unload (rel); + rel = NULL; + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_plan9 (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file = 0; + grub_err_t err; + void *mem; + grub_uint8_t *ptr; + grub_size_t memsize, padsize; + struct grub_plan9_header hdr; + char *config, *configptr; + grub_size_t configsize; + int i; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified"); + + grub_dl_ref (my_mod); + + rel = grub_relocator_new (); + if (!rel) + goto fail; + + file = grub_file_open (argv[0]); + if (! file) + goto fail; + + if (grub_file_read (file, &hdr, sizeof (hdr)) != (grub_ssize_t) sizeof (hdr)) + goto fail; + + if (grub_be_to_cpu32 (hdr.magic) != GRUB_PLAN9_MAGIC + || hdr.zero1 || hdr.zero2 || hdr.zero3) + { + grub_error (GRUB_ERR_BAD_OS, "unsupported Plan9"); + goto fail; + } + + memsize = sizeof (hdr); + memsize += ALIGN_UP (grub_be_to_cpu32 (hdr.text_size), 16); + memsize += ALIGN_UP (grub_be_to_cpu32 (hdr.data_size), 16); + memsize += ALIGN_UP(grub_be_to_cpu32 (hdr.bss_size), 16); + eip = grub_be_to_cpu32 (hdr.entry_addr) & 0xfffffff; + + /* path */ + configsize = GRUB_PLAN9_CONFIG_PATH_SIZE; + /* magic */ + configsize += sizeof (GRUB_PLAN9_CONFIG_MAGIC) - 1; + for (i = 1; i < argc; i++) + configsize += grub_strlen (argv[i]) + 1; + /* Terminating \0. */ + configsize++; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_PLAN9_CONFIG_ADDR, + configsize); + if (err) + goto fail; + config = get_virtual_current_address (ch); + } + + grub_memset (config, 0, GRUB_PLAN9_CONFIG_PATH_SIZE); + configptr = config + GRUB_PLAN9_CONFIG_PATH_SIZE; + grub_memcpy (configptr, GRUB_PLAN9_CONFIG_MAGIC, + sizeof (GRUB_PLAN9_CONFIG_MAGIC) - 1); + configptr += sizeof (GRUB_PLAN9_CONFIG_MAGIC) - 1; + for (i = 1; i < argc; i++) + { + configptr = grub_stpcpy (configptr, argv[i]); + *configptr++ = '\n'; + } + *configptr = 0; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_PLAN9_TARGET, + memsize); + if (err) + goto fail; + mem = get_virtual_current_address (ch); + } + + ptr = mem; + grub_memcpy (ptr, &hdr, sizeof (hdr)); + ptr += sizeof (hdr); + + if (grub_file_read (file, ptr, grub_be_to_cpu32 (hdr.text_size)) + != (grub_ssize_t) grub_be_to_cpu32 (hdr.text_size)) + goto fail; + ptr += grub_be_to_cpu32 (hdr.text_size); + padsize = ALIGN_UP (grub_be_to_cpu32 (hdr.text_size), 16) + - grub_be_to_cpu32 (hdr.text_size); + + grub_memset (ptr, 0, padsize); + ptr += padsize; + + if (grub_file_read (file, ptr, grub_be_to_cpu32 (hdr.data_size)) + != (grub_ssize_t) grub_be_to_cpu32 (hdr.data_size)) + goto fail; + ptr += grub_be_to_cpu32 (hdr.data_size); + padsize = ALIGN_UP (grub_be_to_cpu32 (hdr.data_size), 16) + - grub_be_to_cpu32 (hdr.data_size); + + grub_memset (ptr, 0, padsize); + ptr += padsize; + grub_memset (ptr, 0, ALIGN_UP(grub_be_to_cpu32 (hdr.bss_size), 16)); + + grub_loader_set (grub_plan9_boot, grub_plan9_unload, 1); + return GRUB_ERR_NONE; + + fail: + + if (file) + grub_file_close (file); + + grub_plan9_unload (); + + return grub_errno; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(plan9) +{ + cmd = grub_register_command ("plan9", grub_cmd_plan9, + 0, N_("Load Plan9 kernel.")); + my_mod = mod; +} + +GRUB_MOD_FINI(plan9) +{ + grub_unregister_command (cmd); +}