diff -urN grub-0.93/configure grub-0.93-os/configure --- grub-0.93/configure Fri Nov 29 21:28:30 2002 +++ grub-0.93-os/configure Mon Dec 30 10:49:20 2002 @@ -1551,7 +1551,7 @@ # Define the identity of the package. PACKAGE=grub -VERSION=0.93 +VERSION=0.93-os cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" diff -urN grub-0.93/configure.in grub-0.93-os/configure.in --- grub-0.93/configure.in Fri Nov 29 21:12:08 2002 +++ grub-0.93-os/configure.in Mon Dec 30 10:49:04 2002 @@ -13,7 +13,7 @@ dnl USE OF THIS SOFTWARE. AC_INIT(stage2/stage2.c) -AM_INIT_AUTOMAKE(grub, 0.93) +AM_INIT_AUTOMAKE(grub, 0.93-os) AM_CONFIG_HEADER(config.h) AC_PREREQ(2.13) diff -urN grub-0.93/grub/asmstub.c grub-0.93-os/grub/asmstub.c --- grub-0.93/grub/asmstub.c Tue Dec 3 00:20:45 2002 +++ grub-0.93-os/grub/asmstub.c Mon Dec 30 10:53:53 2002 @@ -628,9 +628,9 @@ case KEY_END: return 5; case KEY_PPAGE: - return 7; - case KEY_NPAGE: return 3; + case KEY_NPAGE: + return 7; default: break; } diff -urN grub-0.93/netboot/fsys_tftp.c grub-0.93-os/netboot/fsys_tftp.c --- grub-0.93/netboot/fsys_tftp.c Wed May 8 09:08:49 2002 +++ grub-0.93-os/netboot/fsys_tftp.c Mon Dec 30 10:42:51 2002 @@ -303,9 +303,20 @@ int tftp_mount (void) { + static int bootped = 0; + /* Check if the current drive is the network drive. */ if (current_drive != NETWORK_DRIVE) return 0; + + /* do automatic bootp only once */ + if (!bootped) + { + if (!bootp()) + return 0; + else + bootped = 1; + } /* If the drive is not initialized yet, abort. */ if (! network_ready) diff -urN grub-0.93/netboot/misc.c grub-0.93-os/netboot/misc.c --- grub-0.93/netboot/misc.c Tue Feb 5 00:01:38 2002 +++ grub-0.93-os/netboot/misc.c Mon Dec 30 16:08:53 2002 @@ -39,7 +39,7 @@ static const char tiddles[]="-\\|/"; unsigned long ticks; - if (debug) + /* if (debug) */ { if ((ticks = currticks ()) == lastticks) return; diff -urN grub-0.93/stage2/asm.S grub-0.93-os/stage2/asm.S --- grub-0.93/stage2/asm.S Tue Dec 3 00:18:56 2002 +++ grub-0.93-os/stage2/asm.S Mon Dec 30 16:50:50 2002 @@ -97,7 +97,8 @@ .string VERSION VARIABLE(config_file) #ifndef STAGE1_5 - .string "/boot/grub/menu.lst" + /* .string "/boot/grub/menu.lst" */ + .string "(nd)/tftpboot/adam/m" #else /* STAGE1_5 */ .long 0xffffffff .string "/boot/grub/stage2" @@ -1544,6 +1545,7 @@ pushl %ebp movl %esp, %ebp + pushl %esi pushl %edi pushl %ebx @@ -1569,6 +1571,7 @@ popl %ebx popl %edi + popl %esi popl %ebp ret @@ -1583,6 +1586,7 @@ pushl %ebp movl %esp, %ebp + pushl %esi pushl %edi pushl %ebx @@ -1611,6 +1615,7 @@ popl %ebx popl %edi + popl %esi popl %ebp ret @@ -1626,6 +1631,8 @@ movl %esp, %ebp pushl %ebx + pushl %esi + pushl %edi /* Save the mode number in %bx */ movl 0x8(%ebp), %ebx @@ -1644,6 +1651,69 @@ movzwl %bx, %eax + popl %edi + popl %esi + popl %ebx + popl %ebp + ret + + +ENTRY(reset_vbe_mode) + pushl %ebp + movl %esp, %ebp + pushl %ebx + + call EXT_C(prot_to_real) + .code16 + + movw $0x0003, %ax + int $0x10 + + DATA32 call EXT_C(real_to_prot) + .code32 + + popl %ebx + popl %ebp + ret + + +ENTRY(get_vbe_pmif) + pushl %ebp + movl %esp, %ebp + pushl %ebx + pushl %esi + pushl %edi + + pushl %ebp + + call EXT_C(prot_to_real) + .code16 + + movw $0x4F0A, %ax + xorw %bx,%bx + xorw %di,%di + int $0x10 + xorl %ebx,%ebx + cmpw $0x004F,%ax + jnz nopm + + movw %es,%bx + shll $16,%ebx + movw %di,%bx + +nopm: DATA32 call EXT_C(real_to_prot) + .code32 + + popl %ebp + + movl 0x8(%ebp),%eax + movl %ebx,(%eax) + movl 0xc(%ebp),%eax + andl $0xFFFF,%ecx + movl %ecx,(%eax) + + popl %edi + popl %esi popl %ebx popl %ebp ret @@ -1920,8 +1990,8 @@ .word KEY_END, 5 .word KEY_DC, 4 .word KEY_BACKSPACE, 8 - .word KEY_PPAGE, 7 - .word KEY_NPAGE, 3 + .word KEY_PPAGE, 3 + .word KEY_NPAGE, 7 .word 0 /* diff -urN grub-0.93/stage2/boot.c grub-0.93-os/stage2/boot.c --- grub-0.93/stage2/boot.c Sat Nov 30 18:29:16 2002 +++ grub-0.93-os/stage2/boot.c Mon Dec 30 09:33:44 2002 @@ -755,6 +755,15 @@ if (!grub_open (module)) return 0; + if ((cur_addr + filemax) >= (1024*(1024+mbi.mem_upper))) + { + printf("Want to load module to 0x%x len 0x%x but only have 0x%x RAM\n", + cur_addr, filemax, 1024*(1024+mbi.mem_upper)); + errnum = ERR_BADMODADDR; + grub_close (); + return 0; + } + len = grub_read ((char *) cur_addr, -1); if (! len) { @@ -781,6 +790,35 @@ return 1; } +void +create_vbe_module(void *ctrl_info, int ctrl_info_len, + void *mode_info, int mode_info_len, + int mode, int pmif, int pmif_len, + unsigned int version) +{ + /* if we are supposed to load on 4K boundaries */ + cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000; + + printf (" [VESA %d.%d info @ 0x%x, 0x%x bytes]\n", + version >> 8, version & 0xFF, + cur_addr, ctrl_info_len + mode_info_len); + + grub_memmove((char*)cur_addr, ctrl_info, ctrl_info_len); + mbi.vbe_control_info = (int)cur_addr; + cur_addr += ctrl_info_len; + + grub_memmove((char*)cur_addr, mode_info, mode_info_len); + mbi.vbe_mode_info = (int)cur_addr; + cur_addr += mode_info_len; + + mbi.flags |= MB_INFO_VIDEO_INFO; + + mbi.vbe_mode = mode; + mbi.vbe_interface_seg = (pmif >> 16) & 0xFFFF; + mbi.vbe_interface_off = pmif & 0xFFFF; + mbi.vbe_interface_len = pmif_len; +} + int load_initrd (char *initrd) { @@ -836,6 +874,12 @@ return ! errnum; } +void +set_load_addr (int addr) +{ + printf ("Setting module load address to 0x%x\n", addr); + cur_addr = addr; +} #ifdef GRUB_UTIL /* Dummy function to fake the *BSD boot. */ diff -urN grub-0.93/stage2/builtins.c grub-0.93-os/stage2/builtins.c --- grub-0.93/stage2/builtins.c Wed Dec 4 05:41:57 2002 +++ grub-0.93-os/stage2/builtins.c Mon Dec 30 09:39:54 2002 @@ -2537,6 +2537,41 @@ #endif /* USE_MD5_PASSWORDS */ +/* modaddr */ +static int +modaddr_func (char *arg, int flags) +{ + int addr; + + switch (kernel_type) + { + case KERNEL_TYPE_MULTIBOOT: + if (safe_parse_maxint(&arg, &addr)) + { + set_load_addr(addr); + break; + } + + /* else fallthrough */ + + default: + errnum = ERR_NEED_MB_KERNEL; + return 1; + } + + return 0; +} + +static struct builtin builtin_modaddr = +{ + "modaddr", + modaddr_func, + BUILTIN_CMDLINE | BUILTIN_HELP_LIST, + "modaddr ADDRESS", + "Set the load address for the next Multiboot module to ADDRESS" +}; + + /* module */ static int module_func (char *arg, int flags) @@ -4551,6 +4586,7 @@ struct vbe_controller controller; unsigned short *mode_list; int mode_number = -1; + int count = 1; auto unsigned long vbe_far_ptr_to_linear (unsigned long); @@ -4632,6 +4668,16 @@ if (mode_number != -1) break; + + count++; + + /* XXX: arbitrary. */ + if (count == 22) + { + grub_printf ("\nHit any key to continue.\n"); + count = 0; + getkey (); + } } } @@ -4650,7 +4696,91 @@ "Probe VBE information. If the mode number MODE is specified, show only" " the information about only the mode." }; - + + +/* vbeset MODE */ +static int +vbeset_func (char *arg, int flags) +{ +#ifndef GRUB_UTIL + int mode_number; + int pmif_segoff, pmif_len; + struct vbe_controller controller; + struct vbe_mode mode; + + if (kernel_type != KERNEL_TYPE_MULTIBOOT) + { + grub_printf("Multiboot kernel must be loaded before vbeset command\n"); + errnum = MAX_ERR_NUM; + return 1; + } + + if (! *arg) + { + reset_vbe_mode (); + return 0; + } + + if (! safe_parse_maxint (&arg, &mode_number)) + return 1; + + /* Preset `VBE2'. */ + grub_memmove (controller.signature, "VBE2", 4); + + /* Detect VBE BIOS. */ + if (get_vbe_controller_info (&controller) != 0x004F) + { + grub_printf (" VBE BIOS is not present.\n"); + return 1; + } + + if (controller.version < 0x0200) + { + grub_printf (" VBE version %d.%d is not supported.\n", + (int) (controller.version >> 8), + (int) (controller.version & 0xFF)); + errnum = MAX_ERR_NUM; + return 1; + } + + if (get_vbe_mode_info (mode_number, &mode) != 0x004F + || (mode.mode_attributes & 0x0091) != 0x0091) + { + grub_printf (" Mode 0x%x is not supported.\n", mode_number); + errnum = MAX_ERR_NUM; + return 1; + } + + /* Now trip to the graphics mode. */ + if (set_vbe_mode (mode_number | (1 << 14)) != 0x004F) + { + grub_printf (" Switching to Mode 0x%x failed.\n", mode_number); + errnum = MAX_ERR_NUM; + return 1; + } + + get_vbe_pmif(&pmif_segoff, &pmif_len); + create_vbe_module(&controller, sizeof(struct vbe_controller), + &mode, sizeof(struct vbe_mode), + mode_number, pmif_segoff, pmif_len, controller.version); + + /* mode setting was successful */ + return 0; +#else + errnum = ERR_BAD_ARGUMENT; + return 1; +#endif +} + +static struct builtin builtin_vbeset = +{ + "vbeset", + vbeset_func, + BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, + "vbeset [MODE]", + "Set the VBE mode MODE. If no MODE is given, switch back to text mode." +}; + /* The table of builtin commands. Sorted in dictionary order. */ struct builtin *builtin_table[] = @@ -4701,6 +4831,7 @@ #ifdef USE_MD5_PASSWORDS &builtin_md5crypt, #endif /* USE_MD5_PASSWORDS */ + &builtin_modaddr, &builtin_module, &builtin_modulenounzip, &builtin_pager, @@ -4740,5 +4871,6 @@ &builtin_unhide, &builtin_uppermem, &builtin_vbeprobe, + &builtin_vbeset, 0 }; diff -urN grub-0.93/stage2/common.c grub-0.93-os/stage2/common.c --- grub-0.93/stage2/common.c Tue Jun 4 15:04:55 2002 +++ grub-0.93-os/stage2/common.c Mon Dec 30 09:34:32 2002 @@ -87,6 +87,7 @@ [ERR_UNRECOGNIZED] = "Unrecognized command", [ERR_WONT_FIT] = "Selected item cannot fit into memory", [ERR_WRITE] = "Disk write error", + [ERR_BADMODADDR] = "Bad modaddr", }; diff -urN grub-0.93/stage2/shared.h grub-0.93-os/stage2/shared.h --- grub-0.93/stage2/shared.h Tue Dec 3 00:15:12 2002 +++ grub-0.93-os/stage2/shared.h Mon Dec 30 09:35:19 2002 @@ -533,6 +533,7 @@ ERR_DEV_NEED_INIT, ERR_NO_DISK_SPACE, ERR_NUMBER_OVERFLOW, + ERR_BADMODADDR, MAX_ERR_NUM } grub_error_t; @@ -754,6 +755,12 @@ /* Set VBE mode. */ int set_vbe_mode (int mode_number); +/* Switch to text mode */ +void reset_vbe_mode (void); + +/* Get VBE pm interface entry */ +void get_vbe_pmif (unsigned int *segoff, unsigned int *len); + /* Return the data area immediately following our code. */ int get_code_end (void); @@ -968,6 +975,11 @@ int load_module (char *module, char *arg); int load_initrd (char *initrd); +void set_load_addr (int addr); +void create_vbe_module(void *ctrl_info, int ctrl_info_len, + void *mode_info, int mode_info_len, + int mode, int pmif, int pmif_len, + unsigned int version); int check_password(char *entered, char* expected, password_t type); #endif diff -urN grub-0.93/stage2/stage2.c grub-0.93-os/stage2/stage2.c --- grub-0.93/stage2/stage2.c Wed Dec 4 01:54:23 2002 +++ grub-0.93-os/stage2/stage2.c Mon Dec 30 15:50:10 2002 @@ -76,6 +76,21 @@ #endif /* ! PRESET_MENU_STRING && ! SUPPORT_DISKLESS */ +/* config_file is 128 Bytes long (see grub/asmstub.c) */ +#define CONFIG_FILE_LEN 128 +#define CONFIG_FILE_HISTORY_ENTRIES 10 +struct config_file_history_struct { + char filename[CONFIG_FILE_LEN]; + int entryno; + int first_entry; +}; +static struct config_file_history_struct + config_file_history[CONFIG_FILE_HISTORY_ENTRIES]; +static int config_file_history_pos, config_file_history_start, + config_file_history_prev_pos; +static int config_file_history_menu_pos = -1; + + static char * get_entry (char *list, int num, int nested) { @@ -233,12 +248,25 @@ { int c, time1, time2 = -1, first_entry = 0; char *cur_entry = 0; + char shortcut_buf[5]; + int sc_matches; + + *shortcut_buf = 0; /* * Main loop for menu UI. */ restart: + + if (config_file_history_menu_pos != -1) + { + /* we're in a history back movement, set menu values to previous ones */ + entryno = config_file_history[config_file_history_menu_pos].entryno; + first_entry = config_file_history[config_file_history_menu_pos].first_entry; + config_file_history_menu_pos = -1; + } + /* Dumb terminal always use all entries for display invariant for TERM_DUMB: first_entry == 0 */ if (! (current_term->flags & TERM_DUMB)) @@ -318,8 +346,10 @@ { if (config_entries) printf ("\ - Press enter to boot the selected OS, \'e\' to edit the\n\ - commands before booting, or \'c\' for a command-line."); + Press enter or %c to boot the selected OS, \'e\' to edit the\n\ + commands before booting, \'r\' to reload, \'c\' for a command-line,\n\ + or %c to go back if possible.", + DISP_RIGHT, DISP_LEFT); else printf ("\ Press \'b\' to boot, \'e\' to edit the selected command in the\n\ @@ -367,6 +397,34 @@ grub_timeout--; } + /* Print the number of the current entry in the right upper corner of + * the menu, up to 999 entries are supported, modify the coordinates + * and putchar command to add more + * Additionally, print the shortcut buffer upper left if there's + * something in there */ + if (! (current_term->flags & TERM_DUMB)) + { + int x; + + /* current entry */ + gotoxy(69, 3); + grub_printf("[%d]", first_entry + entryno); + grub_putchar(DISP_HORIZ); + grub_putchar(DISP_HORIZ); + + + /* print shortcut buffer */ + gotoxy(5, 3); + if (shortcut_buf[0]) + grub_printf("<%s..>", shortcut_buf); + else + for (x = 0; x < 7; x++) + grub_putchar(DISP_HORIZ); + + gotoxy(74, 4 + entryno); + } + + /* Check for a keypress, however if TIMEOUT has been expired (GRUB_TIMEOUT == -1) relax in GETKEY even if no key has been pressed. @@ -397,7 +455,7 @@ /* We told them above (at least in SUPPORT_SERIAL) to use '^' or 'v' so accept these keys. */ - if (c == 16 || c == '^') + if (c == 16 || c == '^' || c == 'k') { if (current_term->flags & TERM_DUMB) { @@ -426,7 +484,7 @@ } } } - else if ((c == 14 || c == 'v') + else if ((c == 14 || c == 'v' || c == 'j') && first_entry + entryno + 1 < num_entries) { if (current_term->flags & TERM_DUMB) @@ -455,6 +513,35 @@ else if (c == 7) { /* Page Up */ + + if (first_entry > 11) + { + first_entry -= 12; + print_entries (3, 12, first_entry, entryno, menu_entries); + } + else if (first_entry) + { + if (entryno + first_entry - 12 < 0) + entryno = 0; + else + entryno = first_entry + entryno - 12; + first_entry = 0; + print_entries (3, 12, first_entry, entryno, menu_entries); + } + else if (entryno) + { + print_entry (4 + entryno, 0, + get_entry (menu_entries, + first_entry + entryno, + 0)); + entryno = 0; + print_entry (4, 1, + get_entry (menu_entries, + first_entry, + 0)); + } + +#if 0 first_entry -= 12; if (first_entry < 0) { @@ -464,10 +551,39 @@ entryno = 0; } print_entries (3, 12, first_entry, entryno, menu_entries); +#endif } else if (c == 3) { /* Page Down */ + if (first_entry + 12 < num_entries) + { + if (first_entry + 23 < num_entries) + first_entry += 12; + else + { + if (entryno + first_entry + 12 >= num_entries) + entryno = 11; + else + entryno += 24 + first_entry - num_entries; + first_entry = num_entries - 12; + } + print_entries (3, 12, first_entry, entryno, menu_entries); + } + else if (first_entry + entryno + 1 != num_entries) + { + print_entry (4 + entryno, 0, + get_entry (menu_entries, + first_entry + entryno, + 0)); + entryno = num_entries - first_entry - 1; + print_entry (4 + entryno, 1, + get_entry (menu_entries, + first_entry + entryno, + 0)); + } + +#if 0 first_entry += 12; if (first_entry + entryno + 1 >= num_entries) { @@ -477,12 +593,99 @@ entryno = num_entries - first_entry - 1; } print_entries (3, 12, first_entry, entryno, menu_entries); +#endif } + if (c >= '0' && c <= '9') + { + int inplen = grub_strlen(shortcut_buf); + int i; + + sc_matches = 0; + + shortcut_buf[inplen] = c; + shortcut_buf[++inplen] = 0; + + for (i = 0; i < num_entries; i++) + { + char buf[4]; + int a = 0; + + /* no strncmp in grub? do it ourselves */ + /* If shortcut_buf is entirely in the beginning + * of buf, mark it as the first valid entry, + * if the first entry is already set, we have at least + * two entries matching, bail out then */ + grub_sprintf(buf, "%d", i); + while (shortcut_buf[a] && buf[a] && + shortcut_buf[a] == buf[a]) + a++; + + if (a == inplen) + { + sc_matches++; + + if (sc_matches == 1) + { + first_entry = i - 5; + entryno = 5; + + if (first_entry < 0 || num_entries < 13) + { + entryno = i; + first_entry = 0; + } + else if (num_entries - i < 7) + { + first_entry = num_entries - 12; + entryno = i - first_entry; + } + + print_entries (3, 12, first_entry, + entryno, menu_entries); + } + else + break; + } + } + if (sc_matches <= 1) + shortcut_buf[0] = 0; + if (sc_matches == 1 && config_entries) + c = '\n'; /* Will hit the next check */ + } + else + shortcut_buf[0] = sc_matches = 0; + if (config_entries) { + if (c == 'r') + return; + if ((c == '\n') || (c == '\r') || (c == 6)) - break; + { + config_file_history[config_file_history_prev_pos].entryno = + entryno; + config_file_history[config_file_history_prev_pos].first_entry = + first_entry; + + break; + } + + if (c == 2) /* KEY_LEFT */ + { + /* go back in history if possible */ + int p = config_file_history_prev_pos; + if (p != config_file_history_start) + { + p = (p == 0) ? CONFIG_FILE_HISTORY_ENTRIES - 1 : p - 1; + memmove(config_file, config_file_history[p].filename, + CONFIG_FILE_LEN); + config_file_history_pos = p; + config_file_history_menu_pos = p; + + return; + } + } } else { @@ -985,6 +1188,17 @@ close_preset_menu (); else grub_close (); + + /* Save history for config_file */ + memmove(config_file_history[config_file_history_pos].filename, + config_file, + CONFIG_FILE_LEN); + config_file_history_prev_pos = config_file_history_pos; + if (++config_file_history_pos == CONFIG_FILE_HISTORY_ENTRIES) + config_file_history_pos = 0; + if (config_file_history_start == config_file_history_pos && + ++config_file_history_start == CONFIG_FILE_HISTORY_ENTRIES) + config_file_history_start = 0; } while (is_preset); }