* [PATCH] Linux loader for OLPC @ 2008-03-27 23:23 Bean 2008-03-31 19:47 ` Bean 2008-04-13 11:14 ` Robert Millan 0 siblings, 2 replies; 9+ messages in thread From: Bean @ 2008-03-27 23:23 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 1407 bytes --] Hi, This patch add support for the linux loader in OLPC. 2008-03-28 Bean <bean123ch@gmail.com> * conf/i386-ieee1275.rmk (pkglib_MODULES): Add _linux.mod and linux.mod. (_linux_mod_SOURCES): New variable. (_linux_mod_CFLAGS): Likewise. (_linux_mod_LDFLAGS): Likewise. (linux_mod_SOURCES): Likewise. (linux_mod_CFLAGS): Likewise. (linux_mod_LDFLAGS): Likewise. * include/grub/i386/ieee1275/loader.h (grub_rescue_cmd_linux): New function prototype. (grub_rescue_cmd_initrd): Likewise. * include/grub/i386/linux.h (GRUB_LINUX_OFW_SIGNATURE): New macro. (linux_kernel_params): Add new member ofw_signature, ofw_num_items, ofw_cif_handler and ofw_idt, adjust padding number. * include/grub/i386/pc/memory.h (grub_upper_mem): Export it if GRUB_MACHINE_IEEE1275 is defined. * include/grub/ieee1275/ieee1275.h (grub_available_iterate): Use NESTED_FUNC_ATTR attribute on the hook parameter. * kern/powerpc/ieee1275/init.c (grub_claim_heap): Use NESTED_FUNC_ATTR on nested function heap_init. (grub_upper_mem): New variable for i386-ieee1275. (grub_get_extended_memory): New function for i386-ieee1275. (grub_machine_init): Call grub_get_extended_memory for i386-ieee1275. * kern/powerpc/ieee1275/openfw.c (grub_available_iterate): Use NESTED_FUNC_ATTR on the hook parameter. * loader/i386/ieee1275/linux.c: New file. * loader/i386/ieee1275/linux_normal.c: New file. -- Bean [-- Attachment #2: olpc.diff --] [-- Type: text/plain, Size: 15293 bytes --] diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index 80d2037..ee91b23 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 # For normal.mod. normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c \ @@ -151,4 +152,14 @@ 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) + include $(srcdir)/conf/common.mk 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..02e2ad2 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..5ab2be5 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/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..ce435d3 100644 --- a/kern/powerpc/ieee1275/openfw.c +++ b/kern/powerpc/ieee1275/openfw.c @@ -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..45a8bc5 --- /dev/null +++ b/loader/i386/ieee1275/linux.c @@ -0,0 +1,271 @@ +/* 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/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 grub_err_t +grub_linux_boot (void) +{ + struct linux_kernel_params *params; + struct linux_kernel_header *lh; + char *prot_code; + + 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->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..69fcebb --- /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"); +} ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] Linux loader for OLPC 2008-03-27 23:23 [PATCH] Linux loader for OLPC Bean @ 2008-03-31 19:47 ` Bean 2008-04-03 15:19 ` Bean 2008-04-13 11:14 ` Robert Millan 1 sibling, 1 reply; 9+ messages in thread From: Bean @ 2008-03-31 19:47 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 366 bytes --] Hi, Small bug fix for the loader, now I can boot the internal linux system using the following commands: set root=nand linux (sd,1)/vmlinuz ro root=mtd0 fbcon=font:SUN12x22 initrd (sd,1)/olpcrd.img boot The root variable is used to set the bootpath. If root device is usb, it should be set to /pci/usbxxx, if root device is sd, it should be /pci/sdxxx. -- Bean [-- Attachment #2: olpc2.diff --] [-- Type: text/plain, Size: 15727 bytes --] diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index 5f37eb5..37da3dd 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 # For normal.mod. normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c \ @@ -151,4 +152,14 @@ 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) + include $(srcdir)/conf/common.mk 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/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..ce435d3 100644 --- a/kern/powerpc/ieee1275/openfw.c +++ b/kern/powerpc/ieee1275/openfw.c @@ -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..69fcebb --- /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"); +} ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] Linux loader for OLPC 2008-03-31 19:47 ` Bean @ 2008-04-03 15:19 ` Bean 2008-04-13 11:41 ` Robert Millan 0 siblings, 1 reply; 9+ messages in thread From: Bean @ 2008-04-03 15:19 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 560 bytes --] 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 [-- Attachment #2: olpc3.diff --] [-- Type: text/plain, Size: 30636 bytes --] 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"); +} ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] Linux loader for OLPC 2008-04-03 15:19 ` Bean @ 2008-04-13 11:41 ` Robert Millan 2008-04-13 15:18 ` Bean 0 siblings, 1 reply; 9+ messages in thread From: Robert Millan @ 2008-04-13 11:41 UTC (permalink / raw) To: The development of GRUB 2 On Thu, Apr 03, 2008 at 11:19:32PM +0800, Bean wrote: > 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'm surprised that the nand works via ieee1275 calls. See my comment in cmain.c: if (is_olpc) { /* OLPC / XO laptops have three kinds of storage devices: - NAND flash. These are accessible via OFW callbacks, but: - Follow strange semantics, imposed by hardware constraints. - Its ABI is undocumented, and not stable. They lack "device_type" property, which conveniently makes GRUB skip them. - USB drives. Not accessible, because OFW shuts down the controller in order to prevent collisions with applications accessing it directly. Even worse, attempts to access it will NOT return control to the caller, so we have to avoid probing them. - SD cards. These work fine. To avoid brekage, we only need to skip USB probing. However, since detecting SD cards is more reliable, we do that instead. */ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY); } but your patch doesn't seem to disable the GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY hack. Also, I'm not sure how stable this will be. Perhaps it breaks in the future with firmware updates :-( > 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. That sounds very useful. But I'm not sure if it's a good idea to put it in kernel. Perhaps a "crypt" module would be better? (so that we can add more crypto-related functions when we support LUKS, etc). -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] Linux loader for OLPC 2008-04-13 11:41 ` Robert Millan @ 2008-04-13 15:18 ` Bean 2008-04-13 15:52 ` Robert Millan 0 siblings, 1 reply; 9+ messages in thread From: Bean @ 2008-04-13 15:18 UTC (permalink / raw) To: The development of GRUB 2 On Sun, Apr 13, 2008 at 7:41 PM, Robert Millan <rmh@aybabtu.com> wrote: > On Thu, Apr 03, 2008 at 11:19:32PM +0800, Bean wrote: > > 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'm surprised that the nand works via ieee1275 calls. See my comment in > cmain.c: > > if (is_olpc) > { > /* OLPC / XO laptops have three kinds of storage devices: > > - NAND flash. These are accessible via OFW callbacks, but: > - Follow strange semantics, imposed by hardware constraints. > - Its ABI is undocumented, and not stable. > They lack "device_type" property, which conveniently makes GRUB > skip them. > > - USB drives. Not accessible, because OFW shuts down the controller > in order to prevent collisions with applications accessing it > directly. Even worse, attempts to access it will NOT return > control to the caller, so we have to avoid probing them. > > - SD cards. These work fine. > > To avoid brekage, we only need to skip USB probing. However, > since detecting SD cards is more reliable, we do that instead. > */ > > grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY); > } > > but your patch doesn't seem to disable the GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY > hack. > > Also, I'm not sure how stable this will be. Perhaps it breaks in the future > with firmware updates :-( nand access is different from normal disk, it uses pio-read to read a page which is normally 2048 bytes. : pio-read ( adr len page# offset -- ) nand device doesn't have device_type property, it won't be detected by ofdisk.c, so i put it in a separate module nand.c. as for GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY, perhaps we can rename it GRUB_IEEE1275_FLAG_OLPC to indicate OLPC platform, we might need to use it for other things. > > > > 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. > > That sounds very useful. But I'm not sure if it's a good idea to put it in > kernel. Perhaps a "crypt" module would be better? (so that we can add more > crypto-related functions when we support LUKS, etc). That's a good idea. -- Bean ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] Linux loader for OLPC 2008-04-13 15:18 ` Bean @ 2008-04-13 15:52 ` Robert Millan 2008-04-18 14:56 ` Bean 0 siblings, 1 reply; 9+ messages in thread From: Robert Millan @ 2008-04-13 15:52 UTC (permalink / raw) To: The development of GRUB 2 On Sun, Apr 13, 2008 at 11:18:31PM +0800, Bean wrote: > > /* OLPC / XO laptops have three kinds of storage devices: > > > > - NAND flash. These are accessible via OFW callbacks, but: > > - Follow strange semantics, imposed by hardware constraints. > > - Its ABI is undocumented, and not stable. > > They lack "device_type" property, which conveniently makes GRUB > > skip them. > > > > - USB drives. Not accessible, because OFW shuts down the controller > > in order to prevent collisions with applications accessing it > > directly. Even worse, attempts to access it will NOT return > > control to the caller, so we have to avoid probing them. > > > > - SD cards. These work fine. > > > > To avoid brekage, we only need to skip USB probing. However, > > since detecting SD cards is more reliable, we do that instead. > > */ > > > > grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY); > > } > > > > but your patch doesn't seem to disable the GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY > > hack. > > > > Also, I'm not sure how stable this will be. Perhaps it breaks in the future > > with firmware updates :-( > > nand access is different from normal disk, it uses pio-read to read a > page which is normally 2048 bytes. > > : pio-read ( adr len page# offset -- ) I see. As for the "strange semantics" I mentioned, IIRC they're applicable to write operations. It might turn out to produce funny effects when writing, but fortunately we don't do that too often :-) > as for GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY, perhaps we can rename it > GRUB_IEEE1275_FLAG_OLPC to indicate OLPC platform, we might need to > use it for other things. Using flags to describe specific problems has the advantage that if they're fixed in a more recent version of the firmware, we just need to check for that in grub_ieee1275_find_options() (the SmartFirmware check there is a nice example of how nasty it gets). -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] Linux loader for OLPC 2008-04-13 15:52 ` Robert Millan @ 2008-04-18 14:56 ` Bean 2008-04-18 15:01 ` Bean 0 siblings, 1 reply; 9+ messages in thread From: Bean @ 2008-04-18 14:56 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 185 bytes --] Hi, This is the new patch which takes into account the location change of files in kern/powerpc/ieee1275. Also, the crc part is removed, it's better to use a separate patch. -- Bean [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: olpc4.diff --] [-- Type: text/x-diff; name=olpc4.diff, Size: 15404 bytes --] 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/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"); +} ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] Linux loader for OLPC 2008-04-18 14:56 ` Bean @ 2008-04-18 15:01 ` Bean 0 siblings, 0 replies; 9+ messages in thread From: Bean @ 2008-04-18 15:01 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 341 bytes --] On Fri, Apr 18, 2008 at 10:56 PM, Bean <bean123ch@gmail.com> wrote: > Hi, > > This is the new patch which takes into account the location change of > files in kern/powerpc/ieee1275. Also, the crc part is removed, it's > better to use a separate patch. > > -- > Bean > Oh, I forget to add some files, this is the right patch. -- Bean [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: olpc4.diff --] [-- Type: text/x-diff; name=olpc4.diff, Size: 26031 bytes --] diff --git a/Makefile.in b/Makefile.in index afe53a3..c29c5fd 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/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/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index 08ff664..0c62aea 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/kern/ieee1275/init.c b/kern/ieee1275/init.c index 6d08140..89c2b62 100644 --- a/kern/ieee1275/init.c +++ b/kern/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/ieee1275/openfw.c b/kern/ieee1275/openfw.c index 69164a6..ac97a59 100644 --- a/kern/ieee1275/openfw.c +++ b/kern/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"); +} ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] Linux loader for OLPC 2008-03-27 23:23 [PATCH] Linux loader for OLPC Bean 2008-03-31 19:47 ` Bean @ 2008-04-13 11:14 ` Robert Millan 1 sibling, 0 replies; 9+ messages in thread From: Robert Millan @ 2008-04-13 11:14 UTC (permalink / raw) To: The development of GRUB 2 On Fri, Mar 28, 2008 at 07:23:07AM +0800, Bean wrote: > Hi, > > This patch add support for the linux loader in OLPC. Just in 2 days! You're truly impressive :-) Note that the following files you modify were recently moved out of their powerpc/ directories: kern/powerpc/ieee1275/init.c kern/powerpc/ieee1275/openfw.c -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2008-04-18 15:01 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-03-27 23:23 [PATCH] Linux loader for OLPC Bean 2008-03-31 19:47 ` Bean 2008-04-03 15:19 ` Bean 2008-04-13 11:41 ` Robert Millan 2008-04-13 15:18 ` Bean 2008-04-13 15:52 ` Robert Millan 2008-04-18 14:56 ` Bean 2008-04-18 15:01 ` Bean 2008-04-13 11:14 ` Robert Millan
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.