? commands/i386/pc/drivemap.c Index: conf/i386-pc.mk =================================================================== RCS file: /sources/grub/grub2/conf/i386-pc.mk,v retrieving revision 1.132 diff -u -r1.132 i386-pc.mk --- conf/i386-pc.mk 30 May 2008 04:20:47 -0000 1.132 +++ conf/i386-pc.mk 5 Jun 2008 20:08:20 -0000 @@ -842,7 +842,7 @@ vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \ videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod \ ata.mod vga.mod memdisk.mod jpeg.mod png.mod pci.mod lspci.mod \ - aout.mod _bsd.mod bsd.mod + aout.mod _bsd.mod bsd.mod drivemap.mod # For biosdisk.mod. biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c @@ -2970,4 +2970,60 @@ bsd_mod_CFLAGS = $(COMMON_CFLAGS) bsd_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For drivemap.mod. +drivemap_mod_SOURCES = commands/i386/pc/drivemap.c +CLEANFILES += drivemap.mod mod-drivemap.o mod-drivemap.c pre-drivemap.o drivemap_mod-commands_i386_pc_drivemap.o und-drivemap.lst +ifneq ($(drivemap_mod_EXPORTS),no) +CLEANFILES += def-drivemap.lst +DEFSYMFILES += def-drivemap.lst +endif +MOSTLYCLEANFILES += drivemap_mod-commands_i386_pc_drivemap.d +UNDSYMFILES += und-drivemap.lst + +drivemap.mod: pre-drivemap.o mod-drivemap.o + -rm -f $@ + $(TARGET_CC) $(drivemap_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ $^ + $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@ + +pre-drivemap.o: $(drivemap_mod_DEPENDENCIES) drivemap_mod-commands_i386_pc_drivemap.o + -rm -f $@ + $(TARGET_CC) $(drivemap_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ drivemap_mod-commands_i386_pc_drivemap.o + +mod-drivemap.o: mod-drivemap.c + $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(drivemap_mod_CFLAGS) -c -o $@ $< + +mod-drivemap.c: moddep.lst genmodsrc.sh + sh $(srcdir)/genmodsrc.sh 'drivemap' $< > $@ || (rm -f $@; exit 1) + +ifneq ($(drivemap_mod_EXPORTS),no) +def-drivemap.lst: pre-drivemap.o + $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 drivemap/' > $@ +endif + +und-drivemap.lst: pre-drivemap.o + echo 'drivemap' > $@ + $(NM) -u -P -p $< | cut -f1 -d' ' >> $@ + +drivemap_mod-commands_i386_pc_drivemap.o: commands/i386/pc/drivemap.c $(commands/i386/pc/drivemap.c_DEPENDENCIES) + $(TARGET_CC) -Icommands/i386/pc -I$(srcdir)/commands/i386/pc $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(drivemap_mod_CFLAGS) -MD -c -o $@ $< +-include drivemap_mod-commands_i386_pc_drivemap.d + +CLEANFILES += cmd-drivemap_mod-commands_i386_pc_drivemap.lst fs-drivemap_mod-commands_i386_pc_drivemap.lst partmap-drivemap_mod-commands_i386_pc_drivemap.lst +COMMANDFILES += cmd-drivemap_mod-commands_i386_pc_drivemap.lst +FSFILES += fs-drivemap_mod-commands_i386_pc_drivemap.lst +PARTMAPFILES += partmap-drivemap_mod-commands_i386_pc_drivemap.lst + +cmd-drivemap_mod-commands_i386_pc_drivemap.lst: commands/i386/pc/drivemap.c $(commands/i386/pc/drivemap.c_DEPENDENCIES) gencmdlist.sh + set -e; $(TARGET_CC) -Icommands/i386/pc -I$(srcdir)/commands/i386/pc $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(drivemap_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh drivemap > $@ || (rm -f $@; exit 1) + +fs-drivemap_mod-commands_i386_pc_drivemap.lst: commands/i386/pc/drivemap.c $(commands/i386/pc/drivemap.c_DEPENDENCIES) genfslist.sh + set -e; $(TARGET_CC) -Icommands/i386/pc -I$(srcdir)/commands/i386/pc $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(drivemap_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh drivemap > $@ || (rm -f $@; exit 1) + +partmap-drivemap_mod-commands_i386_pc_drivemap.lst: commands/i386/pc/drivemap.c $(commands/i386/pc/drivemap.c_DEPENDENCIES) genpartmaplist.sh + set -e; $(TARGET_CC) -Icommands/i386/pc -I$(srcdir)/commands/i386/pc $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(drivemap_mod_CFLAGS) -E $< | sh $(srcdir)/genpartmaplist.sh drivemap > $@ || (rm -f $@; exit 1) + + +drivemap_mod_CFLAGS = $(COMMON_CFLAGS) +drivemap_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/common.mk Index: conf/i386-pc.rmk =================================================================== RCS file: /sources/grub/grub2/conf/i386-pc.rmk,v retrieving revision 1.119 diff -u -r1.119 i386-pc.rmk --- conf/i386-pc.rmk 30 May 2008 04:20:47 -0000 1.119 +++ conf/i386-pc.rmk 5 Jun 2008 20:08:21 -0000 @@ -319,4 +319,9 @@ bsd_mod_CFLAGS = $(COMMON_CFLAGS) bsd_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For drivemap.mod. +drivemap_mod_SOURCES = commands/i386/pc/drivemap.c +drivemap_mod_CFLAGS = $(COMMON_CFLAGS) +drivemap_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/common.mk Index: include/grub/loader.h =================================================================== RCS file: /sources/grub/grub2/include/grub/loader.h,v retrieving revision 1.9 diff -u -r1.9 loader.h --- include/grub/loader.h 21 Jul 2007 23:32:22 -0000 1.9 +++ include/grub/loader.h 5 Jun 2008 20:08:21 -0000 @@ -37,6 +37,19 @@ /* Unset current loader, if any. */ void EXPORT_FUNC(grub_loader_unset) (void); +typedef struct hooklist_node *grub_preboot_hookid; + +/* Register a function to be called before the boot hook. Returns an id that + can be later used to unregister the preboot (i.e. if module unloaded). If + abort_on_error is set, the boot sequence will abort if any of the registered + functions return anything else than GRUB_ERR_NONE */ +grub_preboot_hookid EXPORT_FUNC(grub_loader_register_preboot) + (grub_err_t (*hook) (void), int abort_on_error); + +/* Unregister a preboot hook by the id returned by loader_register_preboot. + This functions becomes a no-op if no such function is registered */ +void EXPORT_FUNC(grub_loader_unregister_preboot) (grub_preboot_hookid id); + /* Call the boot hook in current loader. This may or may not return, depending on the setting by grub_loader_set. */ grub_err_t EXPORT_FUNC(grub_loader_boot) (void); Index: include/grub/i386/loader.h =================================================================== RCS file: /sources/grub/grub2/include/grub/i386/loader.h,v retrieving revision 1.4 diff -u -r1.4 loader.h --- include/grub/i386/loader.h 30 Mar 2008 18:04:39 -0000 1.4 +++ include/grub/i386/loader.h 5 Jun 2008 20:08:21 -0000 @@ -31,6 +31,15 @@ extern grub_addr_t EXPORT_VAR(grub_os_area_addr); extern grub_size_t EXPORT_VAR(grub_os_area_size); +extern grub_uint32_t EXPORT_VAR(grub_drivemap_int13_oldhandler); /* realm far ptr = 2 * 16b */ +extern grub_uint16_t EXPORT_VAR(grub_drivemap_int13_size); /* Size of the section to be copied */ +/* This is NOT a typo: we just want this "void" var in order to take its + * address with &var - used for relative addressing within the int13 handler */ +extern void EXPORT_VAR(grub_drivemap_int13_handler_base); +extern void EXPORT_VAR(grub_drivemap_int13_mapstart); + +void EXPORT_FUNC(grub_drivemap_int13_handler)(void); + grub_err_t EXPORT_FUNC(grub_linux_boot) (void); /* The asm part of the multiboot loader. */ Index: kern/loader.c =================================================================== RCS file: /sources/grub/grub2/kern/loader.c,v retrieving revision 1.9 diff -u -r1.9 loader.c --- kern/loader.c 21 Jul 2007 23:32:26 -0000 1.9 +++ kern/loader.c 5 Jun 2008 20:08:21 -0000 @@ -61,11 +61,78 @@ grub_loader_loaded = 0; } +struct hooklist_node +{ + grub_err_t (*hook) (void); + int abort_on_error; + struct hooklist_node *next; +}; + +static struct hooklist_node *preboot_hooks = 0; + +grub_preboot_hookid +grub_loader_register_preboot(grub_err_t (*hook) (void), int abort_on_error) +{ + if (0 == hook) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "preboot hoook must not be null"); + return 0; + } + grub_preboot_hookid newentry = grub_malloc (sizeof (struct hooklist_node)); + if (!newentry) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot alloc a hookinfo structure"); + return 0; + } + else + { + newentry->hook = hook; + newentry->abort_on_error = abort_on_error; + newentry->next = preboot_hooks; + preboot_hooks = newentry; + return newentry; + } +} + +void +grub_loader_unregister_preboot(grub_preboot_hookid id) +{ + if (0 == id) + return; + grub_preboot_hookid entry = 0, search = preboot_hooks, previous = 0; + while (search) + { + if (search == id) + { + entry = search; + break; + } + previous = search; + search = search->next; + } + if (entry) /* Found */ + { + if (previous) + previous->next = entry->next; + else preboot_hooks = entry->next; /* Entry was head of list */ + grub_free (entry); + } +} + grub_err_t grub_loader_boot (void) { if (! grub_loader_loaded) return grub_error (GRUB_ERR_NO_KERNEL, "no loaded kernel"); + + grub_preboot_hookid entry = preboot_hooks; + while (entry) + { + grub_err_t retVal = entry->hook(); + if (retVal != GRUB_ERR_NONE && entry->abort_on_error) + return retVal; + entry = entry->next; + } if (grub_loader_noreturn) grub_machine_fini (); Index: kern/i386/loader.S =================================================================== RCS file: /sources/grub/grub2/kern/i386/loader.S,v retrieving revision 1.3 diff -u -r1.3 loader.S --- kern/i386/loader.S 19 Feb 2008 16:40:44 -0000 1.3 +++ kern/i386/loader.S 5 Jun 2008 20:08:22 -0000 @@ -59,6 +59,142 @@ VARIABLE(grub_linux_is_bzimage) .long 0 + +#define GRUB_DRIVEMAP_INT13H_OFFSET(x) ((x) - grub_drivemap_int13_handler_base) +VARIABLE(grub_drivemap_int13_handler_base) /* When deployed, this tag must be segment-aligned */ +VARIABLE(grub_drivemap_int13_oldhandler) + .word 0xdead, 0xbeef +/* Drivemap module - INT 13h handler - BIOS HD map */ +/* Right now this function is just a passthrough to the old handler + * We need to use relative addressing, and with CS to top it all, since we + * must make as few changes to the registers as possible. Pity we're not on + * amd64: rIP-relative addressing would make life easier here. + */ +.code16 +FUNCTION(grub_drivemap_int13_handler) + push %bp + mov %sp, %bp + push %ax /* We'll need it later to determine the used BIOS function */ + + /* DEBUG: print requested drive (DL) */ + /*push %es + pushal + mov $4, %di + mov $0xb800, %bx + mov %bx, %es + + movb %dl, %bl + andb $0x0f, %bl + addb $0x30, %bl + shll $16, %ebx + movb %dl, %bl + shrb $4, %bl + addb $0x30, %bl + andl $0x00ff00ff, %ebx + orl $0x0f000f00, %ebx + movl %ebx, %es:(%di) + add $4, %di + popal + pop %es*/ + + /* Map the drive number (always in DL?) */ + push %ax + push %bx + push %si + mov $GRUB_DRIVEMAP_INT13H_OFFSET(grub_drivemap_int13_size), %bx + xor %si, %si +1:movw %cs:(%bx,%si), %ax + cmp %ah, %al + jz 3f /* DRV=DST => map end - drive not remapped, leave DL as-is */ + cmp %dl, %al + jz 2f /* Found - drive remapped, modify DL */ + add $2, %si + jmp 1b /* Not found, but more remaining, loop */ +2:mov %ah, %dl +3:pop %si + pop %bx + xchgw %ax, -4(%bp) /* Recover the old AX and save the map entry for later */ + + /* DEBUG: print map entry DRV (AL) and DST (AH) */ + /*push %es + pushal + mov $8, %di + mov $0xb800, %bx + mov %bx, %es + + movb -4(%bp), %bl + andb $0x0f, %bl + addb $0x30, %bl + shll $16, %ebx + movb -4(%bp), %bl + shrb $4, %bl + addb $0x30, %bl + andl $0x00ff00ff, %ebx + orl $0x0f000f00, %ebx + movl %ebx, %es:(%di) + add $4, %di + + movb -3(%bp), %bl + andb $0x0f, %bl + addb $0x30, %bl + shll $16, %ebx + movb -3(%bp), %bl + shrb $4, %bl + addb $0x30, %bl + andl $0x00ff00ff, %ebx + orl $0x0f000f00, %ebx + movl %ebx, %es:(%di) + add $4, %di + + popal + pop %es*/ + + + push %bp + /* Simulate interrupt call: push flags and do a far call in order to set + * the stack the way the old handler expects it so that its iret works */ + push 6(%bp) + movw (%bp), %bp /* Restore the caller BP (is this needed and/or sensible?) */ + lcall *%cs:GRUB_DRIVEMAP_INT13H_OFFSET(grub_drivemap_int13_oldhandler) + pop %bp /* The pushed flags were removed by iret */ + /* Set the saved flags to what the int13h handler returned */ + push %ax + pushf + pop %ax + movw %ax, 6(%bp) + pop %ax + + /* Reverse map any returned drive number if the data returned includes it. + * The only func that does this seems to be origAH = 0x08, but many BIOS + * refs say retDL = # of drives connected. However, the GRUB Legacy code + * treats this as the _drive number_ and "undoes" the remapping. Thus, + * this section has been disabled for testing if it's required */ +# cmpb $0x08, -1(%bp) /* Caller's AH */ +# jne 4f +# push %es +# pushal +# mov $0, %di +# mov $0xb800, %bx +# mov %bx, %es +# xchgw %ax, -4(%bp) /* Map entry used */ +# cmp %ah, %al /* DRV=DST => drive not remapped */ +# je 4f +# mov %ah, %dl /* Undo remap */ + +4:mov %bp, %sp + pop %bp + iret +/* This label MUST be at the end of the copied block, since the installer code + * reserves additional space for mappings at runtime and copies them over it */ +.align 2 +VARIABLE(grub_drivemap_int13_mapstart) + .space 0 +.code32 /* Copy stops here */ +VARIABLE(grub_drivemap_int13_size) + .word GRUB_DRIVEMAP_INT13H_OFFSET(grub_drivemap_int13_size) +#undef GRUB_DRIVEMAP_INT13H_OFFSET + + FUNCTION(grub_linux_boot) /* Must be done before zImage copy. */ call EXT_C(grub_dl_unload_all)