diff --git a/Makefile.in b/Makefile.in index c2f432f..b51dd09 100644 --- a/Makefile.in +++ b/Makefile.in @@ -91,7 +91,7 @@ enable_grub_fstest = @enable_grub_fstest@ ### General variables. RMKFILES = $(addprefix conf/,common.rmk i386-pc.rmk powerpc-ieee1275.rmk \ - sparc64-ieee1275.rmk i386-efi.rmk) + sparc64-ieee1275.rmk i386-efi.rmk i386-ieee1275.rmk i386-linuxbios.rmk) MKFILES = $(patsubst %.rmk,%.mk,$(RMKFILES)) PKGLIB = $(pkglib_IMAGES) $(pkglib_MODULES) $(pkglib_PROGRAMS) \ diff --git a/commands/crc.c b/commands/crc.c new file mode 100755 index 0000000..470de03 --- /dev/null +++ b/commands/crc.c @@ -0,0 +1,65 @@ +/* crc.c - command to calculate the crc32 checksum of a file */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 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 + +static grub_err_t +grub_cmd_crc (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) + +{ + grub_file_t file; + char buf[GRUB_DISK_SECTOR_SIZE]; + grub_ssize_t size; + grub_uint32_t crc; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + + file = grub_file_open (args[0]); + if (! file) + return 0; + + crc = 0; + while ((size = grub_file_read (file, buf, sizeof (buf))) > 0) + crc = grub_getcrc32 (crc, buf, size); + + grub_file_close (file); + + grub_printf ("%08x\n", crc); + + return 0; +} + +GRUB_MOD_INIT(crc) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("crc", grub_cmd_crc, GRUB_COMMAND_FLAG_BOTH, + "crc FILE", "Calculate the crc32 checksum of a file.", 0); +} + +GRUB_MOD_FINI(crc) +{ + grub_unregister_command ("crc"); +} diff --git a/commands/hexdump.c b/commands/hexdump.c index d353d5e..6d97fe4 100644 --- a/commands/hexdump.c +++ b/commands/hexdump.c @@ -82,26 +82,62 @@ hexdump (unsigned long bse, char *buf, int len) static grub_err_t grub_cmd_hexdump (struct grub_arg_list *state, int argc, char **args) { - grub_file_t file; - char buf[GRUB_DISK_SECTOR_SIZE]; + char buf[GRUB_DISK_SECTOR_SIZE * 4]; grub_ssize_t size, length; unsigned long skip; - int is_file; + int namelen; if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + namelen = grub_strlen (args[0]); skip = (state[0].set) ? grub_strtoul (state[0].arg, 0, 0) : 0; - length = (state[1].set) ? grub_strtoul (state[1].arg, 0, 0) : 0; + length = (state[1].set) ? grub_strtoul (state[1].arg, 0, 0) : 256; - is_file = (grub_strcmp (args[0], "(mem)")); - if ((!is_file) && (!length)) - length = 256; - - if (is_file) + if (!grub_strcmp (args[0], "(mem)")) + hexdump (skip, (char *) skip, length); + else if ((args[0][0] == '(') && (args[0][namelen - 1] == ')')) + { + grub_disk_t disk; + grub_disk_addr_t sector; + grub_size_t ofs; + + args[0][namelen - 1] = 0; + disk = grub_disk_open (&args[0][1]); + if (! disk) + return 0; + + sector = (skip >> (GRUB_DISK_SECTOR_BITS + 2)) * 4; + ofs = skip & (GRUB_DISK_SECTOR_SIZE * 4 - 1); + while (length) + { + grub_size_t len, n; + + len = length; + if (ofs + len > sizeof (buf)) + len = sizeof (buf) - ofs; + + n = ((ofs + len + GRUB_DISK_SECTOR_SIZE - 1) + >> GRUB_DISK_SECTOR_BITS); + if (disk->dev->read (disk, sector, n, buf)) + break; + + hexdump (skip, &buf[ofs], len); + + ofs = 0; + skip += len; + length -= len; + sector += 4; + } + + grub_disk_close (disk); + } + else { + grub_file_t file; + file = grub_gzfile_open (args[0], 1); - if (!file) + if (! file) return 0; file->offset = skip; @@ -123,8 +159,6 @@ grub_cmd_hexdump (struct grub_arg_list *state, int argc, char **args) grub_file_close (file); } - else - hexdump (skip, (char *) skip, length); return 0; } @@ -134,7 +168,7 @@ GRUB_MOD_INIT (hexdump) { (void) mod; /* To stop warning. */ grub_register_command ("hexdump", grub_cmd_hexdump, GRUB_COMMAND_FLAG_BOTH, - "hexdump [ -s offset ] [-n length] { FILE | (mem) }", + "hexdump [OPTIONS] FILE_OR_DEVICE", "Dump the contents of a file or memory.", options); } diff --git a/conf/common.rmk b/conf/common.rmk index 6e2d7aa..5de6f77 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -276,7 +276,7 @@ pkglib_MODULES += hello.mod boot.mod terminal.mod ls.mod \ cmp.mod cat.mod help.mod font.mod search.mod \ loopback.mod configfile.mod echo.mod \ terminfo.mod test.mod blocklist.mod hexdump.mod \ - read.mod sleep.mod + read.mod sleep.mod crc.mod # For hello.mod. hello_mod_SOURCES = hello/hello.c @@ -380,3 +380,8 @@ read_mod_LDFLAGS = $(COMMON_LDFLAGS) sleep_mod_SOURCES = commands/sleep.c sleep_mod_CFLAGS = $(COMMON_CFLAGS) sleep_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For crc.mod. +crc_mod_SOURCES = commands/crc.c +crc_mod_CFLAGS = $(COMMON_CFLAGS) +crc_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index 5f37eb5..ff3a54a 100644 --- a/conf/i386-ieee1275.rmk +++ b/conf/i386-ieee1275.rmk @@ -97,7 +97,8 @@ grub_emu_LDFLAGS = $(LIBCURSES) # Modules. pkglib_MODULES = normal.mod halt.mod reboot.mod suspend.mod cpuid.mod \ - multiboot.mod _multiboot.mod aout.mod serial.mod + multiboot.mod _multiboot.mod aout.mod serial.mod linux.mod \ + _linux.mod nand.mod # For normal.mod. normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c \ @@ -151,4 +152,19 @@ serial_mod_SOURCES = term/i386/pc/serial.c serial_mod_CFLAGS = $(COMMON_CFLAGS) serial_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For _linux.mod. +_linux_mod_SOURCES = loader/i386/ieee1275/linux.c +_linux_mod_CFLAGS = $(COMMON_CFLAGS) +_linux_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For linux.mod. +linux_mod_SOURCES = loader/i386/ieee1275/linux_normal.c +linux_mod_CFLAGS = $(COMMON_CFLAGS) +linux_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For nand.mod. +nand_mod_SOURCES = disk/ieee1275/nand.c +nand_mod_CFLAGS = $(COMMON_CFLAGS) +nand_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/common.mk diff --git a/disk/ieee1275/nand.c b/disk/ieee1275/nand.c new file mode 100755 index 0000000..ba79faa --- /dev/null +++ b/disk/ieee1275/nand.c @@ -0,0 +1,216 @@ +/* nand.c - NAND flash disk access. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 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 + +struct grub_nand_data +{ + grub_ieee1275_ihandle_t handle; + grub_uint32_t block_size; +}; + +static int +grub_nand_iterate (int (*hook) (const char *name)) +{ + auto int dev_iterate (struct grub_ieee1275_devalias *alias); + int dev_iterate (struct grub_ieee1275_devalias *alias) + { + if (! grub_strcmp (alias->name, "nand")) + { + hook (alias->name); + return 1; + } + + return 0; + } + + grub_devalias_iterate (dev_iterate); + return 0; +} + +static grub_err_t +grub_nand_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf); + +static grub_err_t +grub_nand_open (const char *name, grub_disk_t disk) +{ + grub_ieee1275_ihandle_t dev_ihandle = 0; + struct grub_nand_data *data = 0; + struct size_args + { + struct grub_ieee1275_common_hdr common; + char *method; + grub_ieee1275_ihandle_t ihandle; + grub_ieee1275_cell_t result; + grub_ieee1275_cell_t size1; + grub_ieee1275_cell_t size2; + } args; + + if (! grub_strstr (name, "nand")) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Not a nand device"); + + data = grub_malloc (sizeof (*data)); + if (! data) + goto fail; + + grub_ieee1275_open (name, &dev_ihandle); + if (! dev_ihandle) + { + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device"); + goto fail; + } + + data->handle = dev_ihandle; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 2, 2); + args.method = "block-size"; + args.ihandle = dev_ihandle; + args.result = 1; + + if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.result)) + { + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't get block size"); + goto fail; + } + + data->block_size = (args.size1 >> GRUB_DISK_SECTOR_BITS); + + INIT_IEEE1275_COMMON (&args.common, "call-method", 2, 3); + args.method = "size"; + args.ihandle = dev_ihandle; + args.result = 1; + + if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.result)) + { + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't get disk size"); + goto fail; + } + + disk->total_sectors = args.size1; + disk->total_sectors <<= 32; + disk->total_sectors += args.size2; + disk->total_sectors >>= GRUB_DISK_SECTOR_BITS; + + disk->id = dev_ihandle; + + disk->has_partitions = 0; + disk->data = data; + + return 0; + +fail: + if (dev_ihandle) + grub_ieee1275_close (dev_ihandle); + grub_free (data); + return grub_errno; +} + +static void +grub_nand_close (grub_disk_t disk) +{ + grub_ieee1275_close (((struct grub_nand_data *) disk->data)->handle); + grub_free (disk->data); +} + +static grub_err_t +grub_nand_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + struct grub_nand_data *data = disk->data; + grub_size_t bsize, ofs; + + struct read_args + { + struct grub_ieee1275_common_hdr common; + char *method; + grub_ieee1275_ihandle_t ihandle; + grub_ieee1275_cell_t ofs; + grub_ieee1275_cell_t page; + grub_ieee1275_cell_t len; + grub_ieee1275_cell_t buf; + grub_ieee1275_cell_t result; + } args; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 6, 1); + args.method = "pio-read"; + args.ihandle = data->handle; + args.buf = (grub_ieee1275_cell_t) buf; + args.page = (grub_ieee1275_cell_t) ((grub_size_t) sector / data->block_size); + + ofs = ((grub_size_t) sector % data->block_size) << GRUB_DISK_SECTOR_BITS; + size <<= GRUB_DISK_SECTOR_BITS; + bsize = (data->block_size << GRUB_DISK_SECTOR_BITS); + + do + { + grub_size_t len; + + len = (ofs + size > bsize) ? (bsize - ofs) : size; + + args.len = (grub_ieee1275_cell_t) len; + args.ofs = (grub_ieee1275_cell_t) ofs; + args.result = 1; + + if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.result)) + return grub_error (GRUB_ERR_READ_ERROR, "Read error"); + + ofs = 0; + size -= len; + args.buf += len; + args.page++; + } while (size); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_nand_write (grub_disk_t disk __attribute ((unused)), + grub_disk_addr_t sector __attribute ((unused)), + grub_size_t size __attribute ((unused)), + const char *buf __attribute ((unused))) +{ + return GRUB_ERR_NOT_IMPLEMENTED_YET; +} + +static struct grub_disk_dev grub_nand_dev = + { + .name = "nand", + .id = GRUB_DISK_DEVICE_NAND_ID, + .iterate = grub_nand_iterate, + .open = grub_nand_open, + .close = grub_nand_close, + .read = grub_nand_read, + .write = grub_nand_write, + .next = 0 + }; + +GRUB_MOD_INIT(nand) +{ + grub_disk_dev_register (&grub_nand_dev); +} + +GRUB_MOD_FINI(nand) +{ + grub_disk_dev_unregister (&grub_nand_dev); +} diff --git a/disk/ieee1275/ofdisk.c b/disk/ieee1275/ofdisk.c index d86d953..55b7d99 100644 --- a/disk/ieee1275/ofdisk.c +++ b/disk/ieee1275/ofdisk.c @@ -109,7 +109,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) if (grub_ieee1275_get_property (dev, "device_type", prop, sizeof (prop), &actual)) { - grub_error (GRUB_ERR_BAD_DEVICE, "Can't read the device type"); + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't read the device type"); goto fail; } diff --git a/include/grub/disk.h b/include/grub/disk.h index 2a79a0b..ca6424e 100644 --- a/include/grub/disk.h +++ b/include/grub/disk.h @@ -37,6 +37,7 @@ enum grub_disk_dev_id GRUB_DISK_DEVICE_HOST_ID, GRUB_DISK_DEVICE_ATA_ID, GRUB_DISK_DEVICE_MEMDISK_ID, + GRUB_DISK_DEVICE_NAND_ID, }; struct grub_disk; diff --git a/include/grub/i386/ieee1275/loader.h b/include/grub/i386/ieee1275/loader.h index 2937bb0..942242b 100644 --- a/include/grub/i386/ieee1275/loader.h +++ b/include/grub/i386/ieee1275/loader.h @@ -27,4 +27,7 @@ void EXPORT_FUNC(grub_multiboot2_real_boot) (grub_addr_t entry, struct grub_multiboot_info *mbi) __attribute__ ((noreturn)); +void grub_rescue_cmd_linux (int argc, char *argv[]); +void grub_rescue_cmd_initrd (int argc, char *argv[]); + #endif /* ! GRUB_LOADER_MACHINE_HEADER */ diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h index 444e57f..7a8e006 100644 --- a/include/grub/i386/linux.h +++ b/include/grub/i386/linux.h @@ -47,6 +47,9 @@ #define GRUB_LINUX_EFI_SIGNATURE \ ('E' << 24 | 'F' << 16 | 'I' << 8 | 'L') +#define GRUB_LINUX_OFW_SIGNATURE \ + (' ' << 24 | 'W' << 16 | 'F' << 8 | 'O') + #ifndef ASM_FILE /* For the Linux/i386 boot protocol version 2.03. */ @@ -154,7 +157,14 @@ struct linux_kernel_params grub_uint8_t hd1_drive_info[0x10]; /* 90 */ grub_uint16_t rom_config_len; /* a0 */ - grub_uint8_t padding6[0x1c0 - 0xa2]; + grub_uint8_t padding6[0xb0 - 0xa2]; + + grub_uint32_t ofw_signature; /* b0 */ + grub_uint32_t ofw_num_items; /* b4 */ + grub_uint32_t ofw_cif_handler; /* b8 */ + grub_uint32_t ofw_idt; /* bc */ + + grub_uint8_t padding7[0x1c0 - 0xc0]; grub_uint32_t efi_signature; /* 1c0 */ grub_uint32_t efi_system_table; /* 1c4 */ @@ -163,15 +173,15 @@ struct linux_kernel_params grub_uint32_t efi_mmap; /* 1d0 */ grub_uint32_t efi_mmap_size; /* 1d4 */ - grub_uint8_t padding7[0x1e0 - 0x1d8]; + grub_uint8_t padding8[0x1e0 - 0x1d8]; grub_uint32_t alt_mem; /* 1e0 */ - grub_uint8_t padding8[0x1e8 - 0x1e4]; + grub_uint8_t padding9[0x1e8 - 0x1e4]; grub_uint32_t mmap_size; /* 1e8 */ - grub_uint8_t padding9[0x1ff - 0x1ec]; + grub_uint8_t padding10[0x1ff - 0x1ec]; grub_uint8_t ps_mouse; /* 1ff */ } __attribute__ ((packed)); diff --git a/include/grub/i386/pc/memory.h b/include/grub/i386/pc/memory.h index 71132b0..a3e3ed7 100644 --- a/include/grub/i386/pc/memory.h +++ b/include/grub/i386/pc/memory.h @@ -76,11 +76,14 @@ /* The data segment of the pseudo real mode. */ #define GRUB_MEMORY_MACHINE_PSEUDO_REAL_DSEG 0x20 -#ifndef GRUB_MACHINE_IEEE1275 #ifndef ASM_FILE + +#ifndef GRUB_MACHINE_IEEE1275 extern grub_size_t EXPORT_VAR(grub_lower_mem); -extern grub_size_t EXPORT_VAR(grub_upper_mem); #endif + +extern grub_size_t EXPORT_VAR(grub_upper_mem); + #endif #endif /* ! GRUB_MEMORY_MACHINE_HEADER */ diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h index 463180d..e9fe13d 100644 --- a/include/grub/ieee1275/ieee1275.h +++ b/include/grub/ieee1275/ieee1275.h @@ -158,7 +158,7 @@ grub_err_t EXPORT_FUNC(grub_devalias_iterate) grub_err_t EXPORT_FUNC(grub_children_iterate) (char *devpath, int (*hook) (struct grub_ieee1275_devalias *alias)); grub_err_t EXPORT_FUNC(grub_available_iterate) - (int (*hook) (grub_uint64_t, grub_uint64_t)); + (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t)); int EXPORT_FUNC(grub_claimmap) (grub_addr_t addr, grub_size_t size); char *EXPORT_FUNC(grub_ieee1275_encode_devname) (const char *path); diff --git a/include/grub/misc.h b/include/grub/misc.h index 86bc456..0d4bff9 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -82,6 +82,8 @@ grub_ssize_t EXPORT_FUNC(grub_utf8_to_ucs4) (grub_uint32_t *dest, grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, grub_uint32_t d, grub_uint32_t *r); +grub_uint32_t EXPORT_FUNC(grub_getcrc32) (grub_uint32_t crc, void *buf, int size); + /* Inline functions. */ static inline unsigned int diff --git a/kern/misc.c b/kern/misc.c index e6d5c05..e70b0e3 100644 --- a/kern/misc.c +++ b/kern/misc.c @@ -1067,3 +1067,57 @@ grub_abort (void) } /* GCC emits references to abort(). */ void abort (void) __attribute__ ((alias ("grub_abort"))); + +static grub_uint32_t crc32_table [256]; + +static void +init_crc32_table (void) +{ + auto grub_uint32_t reflect (grub_uint32_t ref, int len); + grub_uint32_t reflect (grub_uint32_t ref, int len) + { + grub_uint32_t result = 0; + int i; + + for (i = 1; i <= len; i++) + { + if (ref & 1) + result |= 1 << (len - i); + ref >>= 1; + } + + return result; + } + + grub_uint32_t polynomial = 0x04c11db7; + int i, j; + + for(i = 0; i < 256; i++) + { + crc32_table[i] = reflect(i, 8) << 24; + for (j = 0; j < 8; j++) + crc32_table[i] = (crc32_table[i] << 1) ^ + (crc32_table[i] & (1 << 31) ? polynomial : 0); + crc32_table[i] = reflect(crc32_table[i], 32); + } +} + +grub_uint32_t +grub_getcrc32 (grub_uint32_t crc, void *buf, int size) +{ + int i; + grub_uint8_t *data = buf; + + if (! crc32_table[1]) + init_crc32_table (); + + crc^= 0xffffffff; + + for (i = 0; i < size; i++) + { + crc = (crc >> 8) ^ crc32_table[(crc & 0xFF) ^ *data]; + data++; + } + + return crc ^ 0xffffffff; +} diff --git a/kern/powerpc/ieee1275/init.c b/kern/powerpc/ieee1275/init.c index 6d08140..89c2b62 100644 --- a/kern/powerpc/ieee1275/init.c +++ b/kern/powerpc/ieee1275/init.c @@ -128,8 +128,8 @@ static void grub_claim_heap (void) { unsigned long total = 0; - auto int heap_init (grub_uint64_t addr, grub_uint64_t len); - int heap_init (grub_uint64_t addr, grub_uint64_t len) + auto int NESTED_FUNC_ATTR heap_init (grub_uint64_t addr, grub_uint64_t len); + int NESTED_FUNC_ATTR heap_init (grub_uint64_t addr, grub_uint64_t len) { len -= 1; /* Required for some firmware. */ @@ -174,6 +174,31 @@ static void grub_claim_heap (void) grub_available_iterate (heap_init); } +#ifdef __i386__ + +grub_uint32_t grub_upper_mem; + +/* We need to call this before grub_claim_memory. */ +static void +grub_get_extended_memory (void) +{ + auto int NESTED_FUNC_ATTR find_ext_mem (grub_uint64_t addr, grub_uint64_t len); + int NESTED_FUNC_ATTR find_ext_mem (grub_uint64_t addr, grub_uint64_t len) + { + if (addr == 0x100000) + { + grub_upper_mem = len; + return 1; + } + + return 0; + } + + grub_available_iterate (find_ext_mem); +} + +#endif + void grub_machine_init (void) { @@ -182,6 +207,7 @@ grub_machine_init (void) grub_console_init (); #ifdef __i386__ + grub_get_extended_memory (); grub_keyboard_controller_init (); #endif grub_claim_heap (); diff --git a/kern/powerpc/ieee1275/openfw.c b/kern/powerpc/ieee1275/openfw.c index 26ff3d5..dc36790 100644 --- a/kern/powerpc/ieee1275/openfw.c +++ b/kern/powerpc/ieee1275/openfw.c @@ -131,8 +131,8 @@ grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias)) if (grub_ieee1275_get_property (dev, "device_type", devtype, sizeof devtype, &actual)) { - grub_dprintf ("devalias", "get device type failed\n"); - goto nextprop; + /* NAND device don't have device_type property. */ + devtype[0] = 0; } alias.name = aliasname; @@ -147,7 +147,7 @@ nextprop: return 0; } -grub_err_t grub_available_iterate (int (*hook) (grub_uint64_t, grub_uint64_t)) +grub_err_t grub_available_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t)) { grub_ieee1275_phandle_t root; grub_ieee1275_phandle_t memory; diff --git a/loader/i386/ieee1275/linux.c b/loader/i386/ieee1275/linux.c new file mode 100755 index 0000000..bc4567e --- /dev/null +++ b/loader/i386/ieee1275/linux.c @@ -0,0 +1,289 @@ +/* linux.c - boot Linux zImage or bzImage */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008 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 +#include + +#define GRUB_OFW_LINUX_PARAMS_ADDR 0x90000 +#define GRUB_OFW_LINUX_KERNEL_ADDR 0x100000 +#define GRUB_OFW_LINUX_INITRD_ADDR 0x800000 + +#define GRUB_OFW_LINUX_CL_OFFSET 0x1e00 +#define GRUB_OFW_LINUX_CL_LENGTH 0x100 + +static grub_dl_t my_mod; + +static grub_size_t kernel_size; +static char *kernel_addr, *kernel_cmdline; +static grub_size_t initrd_size; + +static grub_err_t +grub_linux_unload (void) +{ + grub_free (kernel_cmdline); + grub_free (kernel_addr); + kernel_cmdline = 0; + kernel_addr = 0; + initrd_size = 0; + + grub_dl_unref (my_mod); + + return GRUB_ERR_NONE; +} + +/* +static int +grub_ieee1275_debug (void) +{ + struct enter_args + { + struct grub_ieee1275_common_hdr common; + } + args; + + INIT_IEEE1275_COMMON (&args.common, "enter", 0, 0); + + if (IEEE1275_CALL_ENTRY_FN (&args) == -1) + return -1; + + return 0; +} +*/ + +static void +grub_set_bootpath (void) +{ + +} + +static grub_err_t +grub_linux_boot (void) +{ + struct linux_kernel_params *params; + struct linux_kernel_header *lh; + char *prot_code; + char *bootpath; + grub_ssize_t len; + + bootpath = grub_env_get ("root"); + if (bootpath) + grub_ieee1275_set_property (grub_ieee1275_chosen, + "bootpath", bootpath, + grub_strlen (bootpath) + 1, + &len); + + params = (struct linux_kernel_params *) GRUB_OFW_LINUX_PARAMS_ADDR; + lh = (struct linux_kernel_header *) params; + + grub_memset ((char *) params, 0, GRUB_OFW_LINUX_CL_OFFSET); + + params->alt_mem = grub_upper_mem >> 10; + params->ext_mem = params->alt_mem; + + lh->cmd_line_ptr = (char *) + (GRUB_OFW_LINUX_PARAMS_ADDR + GRUB_OFW_LINUX_CL_OFFSET); + + params->cl_magic = GRUB_LINUX_CL_MAGIC; + params->cl_offset = GRUB_OFW_LINUX_CL_OFFSET; + + params->video_width = (grub_getwh () >> 8); + params->video_height = (grub_getwh () & 0xff); + params->font_size = 16; + + params->ofw_signature = GRUB_LINUX_OFW_SIGNATURE; + params->ofw_num_items = 1; + params->ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn; + params->ofw_idt = 0; + + if (initrd_size) + { + lh->type_of_loader = 1; + lh->ramdisk_image = GRUB_OFW_LINUX_INITRD_ADDR; + lh->ramdisk_size = initrd_size; + } + + if (kernel_cmdline) + grub_strcpy (lh->cmd_line_ptr, kernel_cmdline); + + prot_code = (char *) GRUB_OFW_LINUX_KERNEL_ADDR; + grub_memcpy (prot_code, kernel_addr, kernel_size); + + asm volatile ("movl %0, %%esi" : : "m" (params)); + asm volatile ("movl %%esi, %%esp" : : ); + asm volatile ("movl %0, %%ecx" : : "m" (prot_code)); + asm volatile ("xorl %%ebx, %%ebx" : : ); + asm volatile ("jmp *%%ecx" : : ); + + return GRUB_ERR_NONE; +} + +void +grub_rescue_cmd_linux (int argc, char *argv[]) +{ + grub_file_t file = 0; + struct linux_kernel_header lh; + grub_uint8_t setup_sects; + grub_size_t real_size, prot_size; + int i; + char *dest; + + grub_dl_ref (my_mod); + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); + goto fail; + } + + file = grub_file_open (argv[0]); + if (! file) + goto fail; + + if (grub_file_read (file, (char *) &lh, sizeof (lh)) != sizeof (lh)) + { + grub_error (GRUB_ERR_READ_ERROR, "cannot read the linux header"); + goto fail; + } + + if ((lh.boot_flag != grub_cpu_to_le16 (0xaa55)) || + (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE))) + { + grub_error (GRUB_ERR_BAD_OS, "invalid magic number"); + goto fail; + } + + setup_sects = lh.setup_sects; + if (! setup_sects) + setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS; + + real_size = setup_sects << GRUB_DISK_SECTOR_BITS; + prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE; + + grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n", + "bzImage", real_size, prot_size); + + grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE); + if (grub_errno) + goto fail; + + kernel_cmdline = grub_malloc (GRUB_OFW_LINUX_CL_LENGTH); + if (! kernel_cmdline) + goto fail; + + dest = kernel_cmdline; + for (i = 1; + i < argc + && dest + grub_strlen (argv[i]) + 1 < (kernel_cmdline + + GRUB_OFW_LINUX_CL_LENGTH); + i++) + { + *dest++ = ' '; + dest = grub_stpcpy (dest, argv[i]); + } + + kernel_addr = grub_malloc (prot_size); + if (! kernel_addr) + goto fail; + + kernel_size = prot_size; + if (grub_file_read (file, kernel_addr, prot_size) != (int) prot_size) + grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + + if (grub_errno == GRUB_ERR_NONE) + grub_loader_set (grub_linux_boot, grub_linux_unload, 1); + +fail: + + if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + { + grub_free (kernel_cmdline); + grub_free (kernel_addr); + kernel_cmdline = 0; + kernel_addr = 0; + + grub_dl_unref (my_mod); + } +} + +void +grub_rescue_cmd_initrd (int argc, char *argv[]) +{ + grub_file_t file = 0; + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified"); + goto fail; + } + + if (! kernel_addr) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first."); + goto fail; + } + + file = grub_file_open (argv[0]); + if (! file) + goto fail; + + initrd_size = grub_file_size (file); + if (grub_file_read (file, (char *) GRUB_OFW_LINUX_INITRD_ADDR, + initrd_size) != (int) initrd_size) + { + grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + goto fail; + } + +fail: + if (file) + grub_file_close (file); +} + +GRUB_MOD_INIT(linux) +{ + grub_rescue_register_command ("linux", + grub_rescue_cmd_linux, + "load linux"); + grub_rescue_register_command ("initrd", + grub_rescue_cmd_initrd, + "load initrd"); + my_mod = mod; +} + +GRUB_MOD_FINI(linux) +{ + grub_rescue_unregister_command ("linux"); + grub_rescue_unregister_command ("initrd"); +} diff --git a/loader/i386/ieee1275/linux_normal.c b/loader/i386/ieee1275/linux_normal.c new file mode 100755 index 0000000..0206f76 --- /dev/null +++ b/loader/i386/ieee1275/linux_normal.c @@ -0,0 +1,60 @@ +/* linux_normal.c - boot another boot loader */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2004,2005,2007 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 + +static grub_err_t +grub_normal_linux_command (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + grub_rescue_cmd_linux (argc, args); + return grub_errno; +} + + +static grub_err_t +grub_normal_initrd_command (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + grub_rescue_cmd_initrd (argc, args); + return grub_errno; +} + +GRUB_MOD_INIT(linux_normal) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("linux", grub_normal_linux_command, + GRUB_COMMAND_FLAG_BOTH, + "linux FILE [ARGS...]", + "Load a linux kernel.", 0); + + grub_register_command ("initrd", grub_normal_initrd_command, + GRUB_COMMAND_FLAG_BOTH, + "initrd FILE", + "Load an initrd.", 0); +} + +GRUB_MOD_FINI(linux_normal) +{ + grub_unregister_command ("linux"); + grub_unregister_command ("initrd"); +}