Hi, The new patch add support for the nand flash device in OLPC. However, the flash use jffs2 file system, so you can't list file in it yet, but you can dump the disk with hexdump.
This patch also include an improvement for hexdump that would allow it to dump device as well as file, for example: hexdump (nand) I also add a new function grub_getcrc32 in kern/misc.c, this function is useful in many places, for example, jffs2 use it to verify data. A new command crc is also included that would allow user to calculate the crc checksum of file. -- Bean
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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/normal.h> +#include <grub/dl.h> +#include <grub/arg.h> +#include <grub/disk.h> +#include <grub/file.h> +#include <grub/misc.h> + +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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/misc.h> +#include <grub/disk.h> +#include <grub/mm.h> +#include <grub/dl.h> +#include <grub/ieee1275/ieee1275.h> + +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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/machine/loader.h> +#include <grub/machine/memory.h> +#include <grub/file.h> +#include <grub/err.h> +#include <grub/disk.h> +#include <grub/misc.h> +#include <grub/types.h> +#include <grub/rescue.h> +#include <grub/mm.h> +#include <grub/dl.h> +#include <grub/env.h> +#include <grub/term.h> +#include <grub/cpu/linux.h> +#include <grub/ieee1275/ieee1275.h> + +#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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/machine/loader.h> +#include <grub/err.h> +#include <grub/normal.h> +#include <grub/dl.h> + +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"); +}
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel