diff -ru grub-0.92.orig/configure grub-0.92/configure --- grub-0.92.orig/configure 2002-04-28 21:13:07.000000000 -0300 +++ grub-0.92/configure 2002-06-17 21:19:23.000000000 -0300 @@ -843,6 +843,7 @@ --disable-vstafs disable VSTa FS support in Stage 2 --disable-jfs disable IBM JFS support in Stage 2 --disable-xfs disable SGI XFS support in Stage 2 + --disable-vga16 disable VGA graphics interface" --disable-gunzip disable decompression in Stage 2 --disable-md5-password disable MD5 password support in Stage 2 --disable-packet-retransmission @@ -4647,6 +4648,16 @@ FSYS_CFLAGS="$FSYS_CFLAGS -DNO_DECOMPRESSION=1" fi +# Check whether --enable-vga16 or --disable-vga16 was given. +if test "${enable_vga16+set}" = set; then + enableval="$enable_vga16" + : +fi + +if test x"$enable_vga16" != xno; then + STAGE2_CFLAGS="$STAGE2_CFLAGS -DVGA16=1" +fi + # Check whether --enable-md5-password or --disable-md5-password was given. if test "${enable_md5_password+set}" = set; then enableval="$enable_md5_password" diff -ru grub-0.92.orig/lib/device.c grub-0.92/lib/device.c --- grub-0.92.orig/lib/device.c 2001-10-13 01:20:05.000000000 -0300 +++ grub-0.92/lib/device.c 2002-06-17 21:19:23.000000000 -0300 @@ -664,8 +664,14 @@ if (strcmp (dev + strlen(dev) - 5, "/disc") == 0) strcpy (dev + strlen(dev) - 5, "/part"); } - sprintf (dev + strlen(dev), "%d", ((partition >> 16) & 0xFF) + 1); - + + sprintf (dev + strlen(dev), "%s%d", + /* Compaq smart and others */ + (strncmp(dev, "/dev/ida/", 9) == 0 || + strncmp(dev, "/dev/cciss/", 11) == 0 || + strncmp(dev, "/dev/rd/", 8) == 0) ? "p" : "", + ((partition >> 16) & 0xFF) + 1); + /* Open the partition. */ fd = open (dev, O_RDWR); if (fd < 0) diff -ru grub-0.92.orig/stage2/asm.S grub-0.92/stage2/asm.S --- grub-0.92.orig/stage2/asm.S 2001-11-12 04:57:29.000000000 -0200 +++ grub-0.92/stage2/asm.S 2002-06-17 21:19:23.000000000 -0300 @@ -1761,7 +1761,11 @@ VARIABLE(linux_text_len) .long 0 - +VARIABLE(linux_init_seg) + .word LINUX_INIT_SEG +VARIABLE(linux_setup_stack) + .word LINUX_SETUP_STACK + ENTRY(linux_boot) /* don't worry about saving anything, we're committed at this point */ cld /* forward copying */ @@ -1788,9 +1792,9 @@ /* final setup for linux boot */ cli - movw $LINUX_INIT_SEG, %ax + movw EXT_C(linux_init_seg), %ax movw %ax, %ss - movw $LINUX_SETUP_STACK, %sp + movw EXT_C(linux_setup_stack), %sp movw %ax, %ds movw %ax, %es @@ -1801,6 +1805,7 @@ /* ljmp */ .byte 0xea .word 0 +VARIABLE(linux_setup_seg) .word LINUX_SETUP_SEG .code32 @@ -1865,7 +1870,7 @@ * %cl = cursor ending scanline */ -ENTRY(nocursor) +ENTRY(grub_nocursor) push %ebp push %ebx /* save EBX */ @@ -2009,6 +2014,263 @@ pop %ebp ret +#ifdef VGA16 +VARIABLE(cursorX) +.word 0 +VARIABLE(cursorY) +.word 0 +VARIABLE(cursorWidth) +.word 0 +VARIABLE(cursorHeight) +.word 0 +VARIABLE(cursorCount) +.word 0 +VARIABLE(cursorBuf) +.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + +/* + * set_int1c_handler(void) + */ +ENTRY(set_int1c_handler) + pushl %edi + + /* save the original int1c handler */ + movl $0x70, %edi + movw (%edi), %ax + movw %ax, ABS(int1c_offset) + movw 2(%edi), %ax + movw %ax, ABS(int1c_segment) + + /* save the new int1c handler */ + movw $ABS(int1c_handler), %ax + movw %ax, (%edi) + xorw %ax, %ax + movw %ax, 2(%edi) + + popl %edi + ret + + +/* + * unset_int1c_handler(void) + */ +ENTRY(unset_int1c_handler) + pushl %edi + + /* check if int1c_handler is set */ + movl $0x70, %edi + movw $ABS(int1c_handler), %ax + cmpw %ax, (%edi) + jne int1c_1 + xorw %ax, %ax + cmpw %ax, 2(%edi) + jne int1c_1 + + /* restore the original */ + movw ABS(int1c_offset), %ax + movw %ax, (%edi) + movw ABS(int1c_segment), %ax + movw %ax, 2(%edi) + +int1c_1: + popl %edi + ret + +/* + * blinks graphics cursor + */ + .code16 +write_data: + movw $0, %ax + movw %ax, %ds + + mov $0xA000, %ax /* video in es:di */ + mov %ax, %es + mov $80, %ax + movw $ABS(cursorY), %si + mov %ds:(%si), %bx + mul %bx + movw $ABS(cursorX), %si + mov %ds:(%si), %bx + shr $3, %bx /* %bx /= 8 */ + add %bx, %ax + mov %ax, %di + + movw $ABS(cursorBuf), %si /* fontBuf in ds:si */ + + /* prepare for data moving */ + mov $16, %dx /* altura da fonte */ + mov $80, %bx /* bytes por linha */ + +write_loop: + movb %ds:(%si), %al + xorb $0xff, %al + movb %al, %ds:(%si) /* invert cursorBuf */ + movb %al, %es:(%di) /* write to video */ + add %bx, %di + inc %si + dec %dx + jg write_loop + ret + +int1c_handler: + pusha + mov $0, %ax + mov %ax, %ds + mov $ABS(cursorCount), %si + mov %ds:(%si), %ax + inc %ax + mov %ax, %ds:(%si) + cmp $9, %ax + jne int1c_done + + mov $0, %ax + mov %ax, %ds:(%si) +/* + movw $0x3c4, %dx + movb $0x020f, %ax + outw %ax, %dx +*/ + call write_data + +int1c_done: + popa + iret + /* call previous int1c handler */ + /* ljmp */ + .byte 0xea +int1c_offset: .word 0 +int1c_segment: .word 0 + .code32 + + +ENTRY(get_font) + push %ebp + push %ebx + push %ecx + push %edx + + call EXT_C(prot_to_real) + .code16 + + movw $0x1130, %ax + movb $6, %bh /* font 8x16 */ + int $0x10 + movw %bp, %dx + movw %es, %cx + + DATA32 call EXT_C(real_to_prot) + .code32 + + xorl %eax, %eax + movw %cx, %ax + shll $4, %eax + movw %dx, %ax + + pop %edx + pop %ecx + pop %ebx + pop %ebp + ret + +/* + * set_videomode(mode) + * BIOS call "INT 10H Function 0h" to set video mode + * Call with %ah = 0x0 + * %al = video mode + */ +ENTRY(set_videomode) + push %ebp + push %ebx + push %ecx + + movb 0x10(%esp), %cl + + call EXT_C(prot_to_real) + .code16 + + xorw %bx, %bx + movb $0xf, %ah + int $0x10 /* Get Current Video mode */ + movb %al, %ch + xorb %ah, %ah + movb %cl, %al + int $0x10 /* Set Video mode */ + + DATA32 call EXT_C(real_to_prot) + .code32 + + xorb %ah, %ah + movb %ch, %al + + pop %ecx + pop %ebx + pop %ebp + ret + +/* + * set_palette(index, red, green, blue) + * BIOS call "INT 10H Function 10h" to set individual dac register + * Call with %ah = 0x10 + * %bx = register number + * %ch = new value for green (0-63) + * %cl = new value for blue (0-63) + * %dh = new value for red (0-63) + */ + +ENTRY(set_palette) + push %ebp + push %eax + push %ebx + push %ecx + push %edx + + movw $0x3c8, %bx /* address write mode register */ + + /* wait vertical retrace */ + + movw $0x3da, %dx +l1b: inb %dx, %al /* wait vertical active display */ + test $8, %al + jnz l1b + +l2b: inb %dx, %al /* wait vertical retrace */ + test $8, %al + jnz l2b + + mov %bx, %dx + movb 0x18(%esp), %al /* index */ + outb %al, %dx + inc %dx + + movb 0x1c(%esp), %al /* red */ + outb %al, %dx + + movb 0x20(%esp), %al /* green */ + outb %al, %dx + + movb 0x24(%esp), %al /* blue */ + outb %al, %dx + + movw 0x18(%esp), %bx + + call EXT_C(prot_to_real) + .code16 + + movb %bl, %bh + movw $0x1000, %ax + int $0x10 + + DATA32 call EXT_C(real_to_prot) + .code32 + + pop %edx + pop %ecx + pop %ebx + pop %eax + pop %ebp + ret +#endif /* * getrtsecs() diff -ru grub-0.92.orig/stage2/boot.c grub-0.92/stage2/boot.c --- grub-0.92.orig/stage2/boot.c 2002-04-29 15:47:14.000000000 -0300 +++ grub-0.92/stage2/boot.c 2002-06-17 21:19:23.000000000 -0300 @@ -28,7 +28,26 @@ static int cur_addr; entry_func entry_addr; static struct mod_list mll[99]; -static int linux_mem_size; +unsigned int kernel_mem = 0; +#ifndef GRUB_UTIL +extern short linux_init_seg, linux_setup_seg, linux_setup_stack; +int linux_setup = LINUX_SETUP; +int cl_my_location = CL_MY_LOCATION; +int cl_my_end_addr = CL_MY_END_ADDR; +int cl_base_addr = CL_BASE_ADDR; +int linux_heap_end_offset = LINUX_HEAP_END_OFFSET; +#else +int linux_setup; +int cl_my_location; +int cl_my_end_addr; +int cl_base_addr; +int linux_heap_end_offset; +#endif +char save_kernel[128]; +char save_args[256]; +unsigned long save_load_flags; +kernel_t save_suggested_type; +static int ramdisk_image = 0, ramdisk_size = 0; /* * The next two functions, 'load_image' and 'load_module', are the building @@ -40,7 +59,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type, unsigned long load_flags) { - int len, i, exec_type = 0, align_4k = 1; + int len, i, exec_type = 0, align_4k = 1, will_fit = 1; entry_func real_entry_addr = 0; kernel_t type = KERNEL_TYPE_NONE; unsigned long flags = 0, text_len = 0, data_len = 0, bss_len = 0; @@ -57,6 +76,14 @@ executable header */ unsigned char buffer[MULTIBOOT_SEARCH]; +#ifdef GRUB_UTIL + linux_setup = LINUX_SETUP; + cl_my_location = CL_MY_LOCATION; + cl_my_end_addr = CL_MY_END_ADDR; + cl_base_addr = CL_BASE_ADDR; + linux_heap_end_offset = LINUX_HEAP_END_OFFSET; +#endif + /* sets the header pointer to point to the beginning of the buffer by default */ pu.aout = (struct exec *) buffer; @@ -211,32 +238,71 @@ int big_linux = 0; int setup_sects = lh->setup_sects; + if (!(load_flags & KERNEL_REALLY_LOAD)) + { + grub_strcpy(save_kernel, kernel); + grub_strcpy(save_args, arg); + save_load_flags = load_flags; + save_suggested_type = suggested_type; + } + if (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0200) { big_linux = (lh->loadflags & LINUX_FLAG_BIG_KERNEL); lh->type_of_loader = LINUX_BOOT_LOADER_TYPE; +#ifndef GRUB_UTIL + if (!(load_flags & KERNEL_REALLY_LOAD)) + { + /* FIXME: SETUP_SECTS should be supported up to 63. + But do you know there are >640KB conventional memory machines? */ + if (setup_sects < 60 && mbi.mem_lower < 608 && mbi.mem_lower >= 480) + { + int base_addr = ((mbi.mem_lower << 10) - 0x10000) & 0xffff00; + + grub_printf("\nLess than 608 Kb of conventional memory available.\n" + "This is not enough memory to load linux.\n" + "Will try a workaround.\n\n"); + linux_setup = cl_base_addr = base_addr; + cl_my_location = base_addr + 0x7f00; + cl_my_end_addr = cl_my_location + 0xff; + linux_init_seg = RAW_SEG(linux_setup) >> 4; + linux_setup_seg = linux_init_seg + 0x20; +#if 0 + linux_setup_stack = RAW_SEG(base_addr - 0x11000) >> 4; + linux_heap_end_offset = linux_setup_stack - 0x200; +#endif + } + else + { + will_fit = (setup_sects < 60); + if (will_fit) + load_flags |= KERNEL_REALLY_LOAD; + } + } +#endif + if (lh->version >= 0x0201) { - lh->heap_end_ptr = LINUX_HEAP_END_OFFSET; + lh->heap_end_ptr = linux_heap_end_offset; lh->loadflags |= LINUX_FLAG_CAN_USE_HEAP; } if (lh->version >= 0x0202) - lh->cmd_line_ptr = CL_MY_LOCATION; + lh->cmd_line_ptr = cl_my_location; else { lh->cl_magic = CL_MAGIC; - lh->cl_offset = CL_MY_LOCATION - CL_BASE_ADDR; + lh->cl_offset = cl_my_location - cl_base_addr; lh->setup_move_size - = (unsigned short) (CL_MY_END_ADDR - CL_BASE_ADDR + 1); + = (unsigned short) (cl_my_end_addr - cl_base_addr + 1); } } else { /* Your kernel is quite old... */ lh->cl_magic = CL_MAGIC; - lh->cl_offset = CL_MY_LOCATION - CL_BASE_ADDR; + lh->cl_offset = cl_my_location - cl_base_addr; setup_sects = LINUX_DEFAULT_SETUP_SECTS; } @@ -256,12 +322,12 @@ return KERNEL_TYPE_NONE; } - grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n", - (big_linux ? "bzImage" : "zImage"), data_len, text_len); + if (!(save_load_flags & KERNEL_REALLY_LOAD)) + grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n", + (big_linux ? "bzImage" : "zImage"), data_len, text_len); - /* FIXME: SETUP_SECTS should be supported up to 63. - But do you know there are >640KB conventional memory machines? */ - if (mbi.mem_lower >= 608 && setup_sects < 60) + save_load_flags = load_flags; + if (will_fit) { /* Video mode selection support. What a mess! */ /* NOTE: Even the word "mess" is not still enough to @@ -299,68 +365,25 @@ } } - /* Check the mem= option to limit memory used for initrd. */ - { - char *mem; - - mem = grub_strstr (arg, "mem="); - if (mem) - { - char *value = mem + 4; - - safe_parse_maxint (&value, &linux_mem_size); - switch (errnum) - { - case ERR_NUMBER_OVERFLOW: - /* If an overflow occurs, use the maximum address for - initrd instead. This is good, because MAXINT is - greater than LINUX_INITRD_MAX_ADDRESS. */ - linux_mem_size = LINUX_INITRD_MAX_ADDRESS; - errnum = ERR_NONE; - break; - - case ERR_NONE: - { - int shift = 0; - - switch (grub_tolower (*value)) - { - case 'g': - shift += 10; - case 'm': - shift += 10; - case 'k': - shift += 10; - default: - break; - } - - /* Check an overflow. */ - if (linux_mem_size > (MAXINT >> shift)) - linux_mem_size = LINUX_INITRD_MAX_ADDRESS; - else - linux_mem_size <<= shift; - } - break; - - default: - linux_mem_size = 0; - errnum = ERR_NONE; - break; - } - } - else - linux_mem_size = 0; - } - - memmove ((char *) LINUX_SETUP, buffer, data_len + SECTOR_SIZE); + if (load_flags & KERNEL_REALLY_LOAD) + { + if (ramdisk_size) + { + lh->ramdisk_image = ramdisk_image; + lh->ramdisk_size = ramdisk_size; + } + memmove ((char *) linux_setup, buffer, data_len + SECTOR_SIZE); + } if (lh->header != LINUX_MAGIC_SIGNATURE || lh->version < 0x0200) - /* Clear the heap space. */ - grub_memset ((char *) LINUX_SETUP + ((setup_sects - 1) << 9), - 0, - (64 - setup_sects - 1) << 9); + { + if (load_flags & KERNEL_REALLY_LOAD) + /* Clear the heap space. */ + grub_memset ((char *) linux_setup + ((setup_sects - 1) << 9), + 0, + (64 - setup_sects - 1) << 9); + } /* Copy command-line plus memory hack to staging area. NOTE: Linux has a bug that it doesn't handle multiple spaces @@ -372,25 +395,40 @@ avoid to copy spaces unnecessarily. Hell. */ { char *src = skip_to (0, arg); - char *dest = (char *) CL_MY_LOCATION; + char *mem; + char *dest = (char *) cl_my_location; - while (((int) dest) < CL_MY_END_ADDR && *src) + while (((int) dest) < cl_my_end_addr && *src) *(dest++) = *(src++); +/* don't add ``mem='' for 2.4 kernels : + +Newer machines have several regions of reserved memory outside and +inside these regions. grub's actions are suicide on newer laptops, +and machines like servers with lots of memory. Laptops have special +sections of memory above 1MB which must be reserved... Ditto for +ACPI tables. Using mem=XXX completely eliminates any information +that the BIOS has provided to the OS. + +*/ /* Add a mem option automatically only if the user doesn't specify it explicitly. */ - if (! grub_strstr (arg, "mem=") - && ! (load_flags & KERNEL_LOAD_NO_MEM_OPTION)) + mem = grub_strstr (arg, "mem=") + 4; + if (mem != (char*)4) + { + if (safe_parse_maxint(&mem, &kernel_mem)) { - if (dest != (char *) CL_MY_LOCATION) - *(dest++) = ' '; - - grub_memmove (dest, "mem=", 4); - dest += 4; - - dest = convert_to_ascii (dest, 'u', (extended_memory + 0x400)); - *(dest++) = 'K'; + if (*mem != 'K' && *mem != 'k') + kernel_mem *= 1024; } + else + { + /* ERRNUM is already set inside the function + safe_parse_maxint. */ + grub_close (); + return KERNEL_TYPE_NONE; + } + } *dest = 0; } @@ -399,9 +437,10 @@ grub_seek (data_len + SECTOR_SIZE); cur_addr = LINUX_STAGING_AREA + text_len; - grub_read ((char *) LINUX_STAGING_AREA, text_len); - - if (errnum == ERR_NONE) + + if (!(load_flags & KERNEL_REALLY_LOAD) || + grub_read ((char *) LINUX_STAGING_AREA, text_len) + >= (text_len - 16)) { grub_close (); @@ -420,7 +459,8 @@ return big_linux ? KERNEL_TYPE_BIG_LINUX : KERNEL_TYPE_LINUX; } - grub_close (); + else if (! errnum) + errnum = ERR_EXEC_FORMAT; } else errnum = ERR_WONT_FIT; @@ -759,7 +799,6 @@ { int len; unsigned long moveto; - struct linux_kernel_header *lh; #ifndef NO_DECOMPRESSION no_decompression = 1; @@ -775,28 +814,41 @@ goto fail; } - if (linux_mem_size) - moveto = linux_mem_size; - else - moveto = (mbi.mem_upper + 0x400) << 10; - - moveto = (moveto - len) & 0xfffff000; - if (moveto + len >= LINUX_INITRD_MAX_ADDRESS) - moveto = (LINUX_INITRD_MAX_ADDRESS - len) & 0xfffff000; + if (!kernel_mem) + kernel_mem = mbi.mem_upper; + + moveto = (kernel_mem * 0x400 - (len + (0x1000 - (len % 0x1000)))) & 0xfffff000; + if (moveto + len > LINUX_INITRD_MAX_ADDRESS) + moveto = LINUX_INITRD_MAX_ADDRESS - (len + (0x1000 - (len % 0x1000))); /* XXX: Linux 2.3.xx has a bug in the memory range check, so avoid the last page. XXX: Linux 2.2.xx has a bug in the memory range check, which is worse than that of Linux 2.3.xx, so avoid the last 64kb. *sigh* */ moveto -= 0x10000; + +#ifndef VGA16 memmove ((void *) RAW_ADDR (moveto), (void *) cur_addr, len); +#else + grub_memcpy ((void *) RAW_ADDR (moveto), (void *) cur_addr, len); +#endif printf (" [Linux-initrd @ 0x%x, 0x%x bytes]\n", moveto, len); /* FIXME: Should check if the kernel supports INITRD. */ - lh = (struct linux_kernel_header *) LINUX_SETUP; - lh->ramdisk_image = RAW_ADDR (moveto); - lh->ramdisk_size = len; + if (linux_setup == LINUX_SETUP) + { + struct linux_kernel_header *lh; + + lh = (struct linux_kernel_header *) linux_setup; + lh->ramdisk_image = RAW_ADDR (moveto); + lh->ramdisk_size = len; + } + else + { + ramdisk_image = RAW_ADDR (moveto); + ramdisk_size = len; + } grub_close (); diff -ru grub-0.92.orig/stage2/builtins.c grub-0.92/stage2/builtins.c --- grub-0.92.orig/stage2/builtins.c 2002-04-28 21:26:49.000000000 -0300 +++ grub-0.92/stage2/builtins.c 2002-06-17 21:21:02.000000000 -0300 @@ -80,6 +80,11 @@ /* The BIOS drive map. */ static unsigned short bios_drive_map[DRIVE_MAP_SIZE + 1]; +extern char save_kernel[128]; +extern char save_args[256]; +extern unsigned long save_load_flags; +extern kernel_t save_suggested_type; + /* Prototypes for allowing straightfoward calling of builtins functions inside other functions. */ static int configfile_func (char *arg, int flags); @@ -133,6 +138,36 @@ grub_printf ("[%d,%d,%d]", sector, offset, length); } +#ifdef VGA16 +/* background */ +static int +background_func(char *arg, int flags) +{ + if (grub_strlen(arg) == 6) { + int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2; + int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2; + int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2; + + background = (r << 16) | (g << 8) | b; + if (vga_inited) + set_palette(0, r, g, b); + return (0); + } + + return (1); +} + +static struct builtin builtin_background = +{ + "background", + background_func, + BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, + "background RRGGBB", + "Sets the background color when in graphics mode." + "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal." +}; +#endif + /* blocklist */ static int @@ -235,7 +270,7 @@ }; /* boot */ -static int +int boot_func (char *arg, int flags) { /* Clear the int15 handler if we can boot the kernel successfully. @@ -259,11 +294,25 @@ case KERNEL_TYPE_LINUX: /* Linux */ + if (!(save_load_flags & KERNEL_REALLY_LOAD)) + { + /* "really" load, and hope nothing fails, cannot return... */ + save_load_flags |= KERNEL_REALLY_LOAD; + load_image(save_kernel, save_args, + save_suggested_type, save_load_flags); + } linux_boot (); break; case KERNEL_TYPE_BIG_LINUX: /* Big Linux */ + if (!(save_load_flags & KERNEL_REALLY_LOAD)) + { + /* "really" load, and hope nothing fails, cannot return... */ + save_load_flags |= KERNEL_REALLY_LOAD; + load_image(save_kernel, save_args, + save_suggested_type, save_load_flags); + } big_linux_boot (); break; @@ -399,6 +448,39 @@ #endif /* SUPPORT_NETBOOT */ +#ifdef VGA16 + +/* foreground */ +static int +border_func(char *arg, int flags) +{ + if (grub_strlen(arg) == 6) { + int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2; + int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2; + int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2; + + border = (r << 16) | (g << 8) | b; + if (vga_inited) + set_palette(0x11, r, g, b); + + return (0); + } + + return (1); +} + +static struct builtin builtin_border = +{ + "border", + border_func, + BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, + "border RRGGBB", + "Sets the border video color when in graphics mode." + "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal." +}; + +#endif + /* cat */ static int cat_func (char *arg, int flags) @@ -409,7 +491,7 @@ return 1; while (grub_read (&c, 1)) - grub_putchar (c); + putchar (c); grub_close (); return 0; @@ -425,8 +507,24 @@ }; -/* chainloader */ static int +chainboot_func(char *arg, int flags) +{ + grub_strcpy(chainboot, arg); +} + +static struct builtin builtin_chainboot = +{ + "chainboot", + chainboot_func, + BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, + "chainboot device", + "This option should be used from an installer, if the user does not " + "select any option, try to chainload the specified hard disk." +}; + +/* chainloader */ +int chainloader_func (char *arg, int flags) { int force = 0; @@ -974,6 +1072,43 @@ }; +#ifdef VGA16 +/* display */ +static int +display_func(char *arg, int flags) +{ + int i; + + for (i = 0; i < MAX_DISPLAYS; i++) { + if (grub_strcmp(arg, display_entries[i].name) == 0) + break; + } + + if (i >= MAX_DISPLAYS) + return (1); + + display_idx = i; + if (display->End) + (*display->End)(); + display = &display_entries[display_idx]; + + /* Restart cmain */ + grub_longjmp (restart_env, 0); + /*NOTREACHED*/ + + return (0); +} + +static struct builtin builtin_display = +{ + "display", + display_func, + BUILTIN_CMDLINE | BUILTIN_HELP_LIST, + "display MODEL", + "Changes display type. Available modes are \"text\" and \"vga16\"." +}; +#endif + /* dump FROM TO */ #ifdef GRUB_UTIL static int @@ -1298,6 +1433,39 @@ " the devices which contain the file." }; +#ifdef VGA16 + +/* foreground */ +static int +foreground_func(char *arg, int flags) +{ + if (grub_strlen(arg) == 6) { + int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2; + int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2; + int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2; + + foreground = (r << 16) | (g << 8) | b; + if (vga_inited) + set_palette(15, r, g, b); + + return (0); + } + + return (1); +} + +static struct builtin builtin_foreground = +{ + "foreground", + foreground_func, + BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, + "foreground RRGGBB", + "Sets the foreground color when in graphics mode." + "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal." +}; + +#endif + /* fstest */ static int @@ -1450,12 +1618,11 @@ /* help */ -#define MAX_SHORT_DOC_LEN 39 -#define MAX_LONG_DOC_LEN 66 - static int help_func (char *arg, int flags) { + int MAX_SHORT_DOC_LEN = (view_x1 - view_x0 + 1) / 2 - 1; + int MAX_LONG_DOC_LEN = (view_x1 - view_x0) - 14; int all = 0; if (grub_memcmp (arg, "--all", sizeof ("--all") - 1) == 0) @@ -1491,13 +1658,13 @@ len = MAX_SHORT_DOC_LEN - 1; for (i = 0; i < len; i++) - grub_putchar ((*builtin)->short_doc[i]); + putchar ((*builtin)->short_doc[i]); for (; i < MAX_SHORT_DOC_LEN; i++) - grub_putchar (' '); + putchar (' '); if (! left) - grub_putchar ('\n'); + putchar ('\n'); left = ! left; } @@ -1505,7 +1672,7 @@ /* If the last entry was at the left column, no newline was printed at the end. */ if (! left) - grub_putchar ('\n'); + putchar ('\n'); } else { @@ -1552,8 +1719,8 @@ grub_printf (" "); for (i = 0; i < len; i++) - grub_putchar (*doc++); - grub_putchar ('\n'); + putchar (*doc++); + putchar ('\n'); } } } @@ -3097,7 +3264,7 @@ print_fsys_type (); } -static int +int root_func (char *arg, int flags) { int hdbias = 0; @@ -3965,6 +4132,74 @@ " to tell GRUB the file name under your OS." }; +#ifdef VGA16 +/*splashimage*/ +static int +splashimage_func(char *arg, int flags) +{ + if (strlen(arg) > 63) + return (1); + if (flags == BUILTIN_CMDLINE) { + if (!grub_open(arg)) + return (1); + grub_close(); + } + + if (flags == BUILTIN_CMDLINE || !splash_set) { + strcpy(splashimage, arg); + splash_set = 1; + } + + if (flags == BUILTIN_CMDLINE && vga_inited) { + display->End(); + display->Begin(); + cls(); +/* grub_longjmp(restart_env, 0);*/ + } + + return (0); +} + +static struct builtin builtin_splashimage = +{ + "splashimage", + splashimage_func, + BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, + "splashimage FILE", + "Load FILE as the background image when in graphics mode." +}; + +/*shade*/ +static int +shade_func(char *arg, int flags) +{ + int new_shade; + + if (!arg || safe_parse_maxint(&arg, &new_shade) == 0) + return (1); + + if (shade != new_shade) { + shade = new_shade; + if (flags == BUILTIN_CMDLINE && vga_inited) { + display->End(); + display->Begin(); + cls(); + } + } + + return (0); +} + +static struct builtin builtin_shade = +{ + "shade", + shade_func, + BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, + "shade INTEGER", + "If set to 0, disables the use of shaded text, else enables it." +}; +#endif + #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) /* terminal */ @@ -4287,6 +4522,11 @@ return 0; } +#ifdef VGA16 + if (display->End) + (*display->End)(); +#endif + /* Now trip to the graphics mode. */ if (set_vbe_mode (mode_number | (1 << 14)) != 0x004F) { @@ -4336,6 +4576,13 @@ /* Why?! */ grub_reboot (); } +#ifdef VGA16 + if (display->Begin) { + if (!(*display->Begin)()) + grub_reboot (); + cls(); + } +#endif return 0; } @@ -4573,15 +4820,79 @@ " the information about only the mode." }; +#ifdef VGA16 + +/* viewport */ +static int +viewport_func (char *arg, int flags) +{ + int i; + int x0 = 80, y0 = 25, x1 = 0, y1 = 0; + int *pos[4] = { &x0, &y0, &x1, &y1 }; + extern int viewport_set; + + if (!arg) + return (1); + for (i = 0; i < 4; i++) { + if (!*arg) + return (1); + while (*arg && (*arg == ' ' || *arg == '\t')) + ++arg; + if (!safe_parse_maxint(&arg, pos[i])) + return (1); + while (*arg && (*arg != ' ' && *arg != '\t')) + ++arg; + } + + x1 += x0; + y1 += y0; + + /* minimum size is 60 colums and 16 rows */ + if (x0 > x1 - 60 || y0 > y1 - 16 || x0 < 0 || y0 < 0 || x1 > 80 || y1 > 30) + return (1); + + viewport_set = 1; + view_x0 = x0; + view_y0 = y0; + view_x1 = x1; + view_y1 = y1; + + if (flags == BUILTIN_CMDLINE && vga_inited) { + display->End(); + display->Begin(); + cls(); + } + + return (0); +} + +static struct builtin builtin_viewport = +{ + "viewport", + viewport_func, + BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, + "viewport x y width height", + "Changes grub internals to output text in the window defined by" + " four parameters. The x and y parameters are 0 based. This option" + " only works with the vga interface." +}; +#endif + /* The table of builtin commands. Sorted in dictionary order. */ struct builtin *builtin_table[] = { +#ifdef VGA16 + &builtin_background, +#endif &builtin_blocklist, &builtin_boot, #ifdef SUPPORT_NETBOOT &builtin_bootp, #endif /* SUPPORT_NETBOOT */ +#ifdef VGA16 + &builtin_border, +#endif &builtin_cat, &builtin_chainloader, &builtin_cmp, @@ -4595,6 +4906,9 @@ #ifdef SUPPORT_NETBOOT &builtin_dhcp, #endif /* SUPPORT_NETBOOT */ +#ifdef VGA16 + &builtin_display, +#endif &builtin_displayapm, &builtin_displaymem, #ifdef GRUB_UTIL @@ -4603,6 +4917,9 @@ &builtin_embed, &builtin_fallback, &builtin_find, +#ifdef VGA16 + &builtin_foreground, +#endif &builtin_fstest, &builtin_geometry, &builtin_halt, @@ -4646,6 +4963,10 @@ #endif /* SUPPORT_SERIAL */ &builtin_setkey, &builtin_setup, +#ifdef VGA16 + &builtin_shade, + &builtin_splashimage, +#endif #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) &builtin_terminal, #endif /* SUPPORT_SERIAL || SUPPORT_HERCULES */ @@ -4659,5 +4980,8 @@ &builtin_unhide, &builtin_uppermem, &builtin_vbeprobe, +#ifdef VGA16 + &builtin_viewport, +#endif 0 }; diff -ru grub-0.92.orig/stage2/char_io.c grub-0.92/stage2/char_io.c --- grub-0.92.orig/stage2/char_io.c 2002-03-25 18:43:55.000000000 -0300 +++ grub-0.92/stage2/char_io.c 2002-06-17 21:19:23.000000000 -0300 @@ -33,6 +33,8 @@ int max_lines = 24; int count_lines = -1; int use_pager = 1; +#else +#define putchar grub_putchar #endif void @@ -265,9 +267,9 @@ /* XXX: These should be defined in shared.h, but I leave these here, until this code is freezed. */ -#define CMDLINE_WIDTH 78 -#define CMDLINE_MARGIN 10 - + int CMDLINE_WIDTH = (view_x1 - view_x0) - 2; + int CMDLINE_MARGIN = 10; + int xpos, lpos, c, section; /* The length of PROMPT. */ int plen; @@ -316,7 +318,7 @@ { int y = getxy () & 0xFF; - gotoxy (xpos, y); + gotoxy (xpos + view_x0, y); } # ifdef SUPPORT_SERIAL else if (! (terminal & TERMINAL_DUMB) && (count > 4)) @@ -328,7 +330,7 @@ int i; for (i = 0; i < count; i++) - grub_putchar ('\b'); + putchar ('\b'); } # endif /* SUPPORT_SERIAL */ } @@ -354,7 +356,7 @@ { int y = getxy () & 0xFF; - gotoxy (xpos, y); + gotoxy (xpos + view_x0, y); } # ifdef SUPPORT_SERIAL else if (! (terminal & TERMINAL_DUMB) && (count > 4)) @@ -368,9 +370,9 @@ for (i = lpos - count; i < lpos; i++) { if (! echo_char) - grub_putchar (buf[i]); + putchar (buf[i]); else - grub_putchar (echo_char); + putchar (echo_char); } } # endif /* SUPPORT_SERIAL */ @@ -398,7 +400,7 @@ /* From the start to the end. */ len = CMDLINE_WIDTH; pos = 0; - grub_putchar ('\r'); + putchar ('\r'); /* If SECTION is the first section, print the prompt, otherwise, print `<'. */ @@ -410,7 +412,7 @@ } else { - grub_putchar ('<'); + putchar ('<'); len--; pos++; } @@ -446,9 +448,9 @@ for (i = start; i < start + len && i < llen; i++) { if (! echo_char) - grub_putchar (buf[i]); + putchar (buf[i]); else - grub_putchar (echo_char); + putchar (echo_char); pos++; } @@ -467,9 +469,9 @@ if (pos == CMDLINE_WIDTH) { if (start + len < llen) - grub_putchar ('>'); + putchar ('>'); else - grub_putchar (' '); + putchar (' '); pos++; } @@ -483,7 +485,7 @@ { int y = getxy () & 0xFF; - gotoxy (xpos, y); + gotoxy (xpos + view_x0, y); } # ifdef SUPPORT_SERIAL else if (! (terminal & TERMINAL_SERIAL) && (pos - xpos > 4)) @@ -493,7 +495,7 @@ else { for (i = 0; i < pos - xpos; i++) - grub_putchar ('\b'); + putchar ('\b'); } # endif /* SUPPORT_SERIAL */ } @@ -503,7 +505,7 @@ void cl_init (void) { /* Distinguish us from other lines and error messages! */ - grub_putchar ('\n'); + putchar ('\n'); /* Print full line and set position here. */ cl_refresh (1, 0); @@ -634,7 +636,7 @@ /* There are more than one candidates, so print the list. */ - grub_putchar ('\n'); + putchar ('\n'); /* Enable the auto fill mode temporarily. */ auto_fill = 1; print_completions (is_filename, 0); @@ -776,7 +778,7 @@ } } - grub_putchar ('\n'); + putchar ('\n'); /* If ECHO_CHAR is NUL, remove the leading spaces. */ lpos = 0; @@ -1121,8 +1123,8 @@ else if (c >= ' ' && c <= '~') { /* Fold a line only if AUTO_FILL is true. */ - if (auto_fill && col >= 79) - grub_putchar ('\n'); + if (auto_fill && col >= view_x1 - view_x0) + putchar ('\n'); col++; } @@ -1173,7 +1175,7 @@ #ifndef STAGE1_5 void -gotoxy (int x, int y) +grub_gotoxy (int x, int y) { if (terminal & TERMINAL_CONSOLE) console_gotoxy (x, y); @@ -1197,7 +1199,7 @@ #endif /* SUPPORT_SERIAL */ int -getxy (void) +grub_getxy (void) { int ret = 0; @@ -1302,7 +1304,7 @@ #endif /* SUPPORT_SERIAL */ void -cls (void) +grub_cls (void) { if (terminal & TERMINAL_CONSOLE) console_cls (); @@ -1330,7 +1332,7 @@ #endif /* SUPPORT_SERIAL */ void -set_attrib (int attr) +grub_set_attrib (int attr) { #ifdef SUPPORT_HERCULES if (terminal & TERMINAL_HERCULES) @@ -1445,6 +1447,8 @@ || (addr >= RAW_ADDR (0x100000) && RAW_ADDR (mbi.mem_upper * 1024) < ((addr - 0x100000) + len))) errnum = ERR_WONT_FIT; + else + errnum = 0; return ! errnum; } diff -ru grub-0.92.orig/stage2/cmdline.c grub-0.92/stage2/cmdline.c --- grub-0.92.orig/stage2/cmdline.c 2002-03-24 09:28:54.000000000 -0300 +++ grub-0.92/stage2/cmdline.c 2002-06-17 21:19:23.000000000 -0300 @@ -125,7 +125,7 @@ init_page (); #ifdef SUPPORT_DISKLESS print_network_configuration (); - grub_putchar ('\n'); + putchar ('\n'); #endif print_cmdline_message (forever); diff -ru grub-0.92.orig/stage2/disk_io.c grub-0.92/stage2/disk_io.c --- grub-0.92.orig/stage2/disk_io.c 2001-11-28 16:43:56.000000000 -0200 +++ grub-0.92/stage2/disk_io.c 2002-06-17 21:19:23.000000000 -0300 @@ -1267,7 +1267,7 @@ } if (! is_completion) - grub_putchar ('\n'); + putchar ('\n'); print_error (); do_completion = 0; @@ -1334,7 +1334,7 @@ } if (! is_completion) - grub_putchar ('\n'); + putchar ('\n'); } else { @@ -1408,7 +1408,7 @@ } if (! is_completion) - grub_putchar ('\n'); + putchar ('\n'); } else errnum = ERR_BAD_FILENAME; diff -ru grub-0.92.orig/stage2/shared.h grub-0.92/stage2/shared.h --- grub-0.92.orig/stage2/shared.h 2002-03-25 18:43:55.000000000 -0300 +++ grub-0.92/stage2/shared.h 2002-06-17 21:19:23.000000000 -0300 @@ -368,7 +368,9 @@ #define printf grub_printf #define sprintf grub_sprintf #undef putchar -#define putchar grub_putchar +#ifdef GRUB_UTIL + #define putchar grub_putchar +#endif #define strncat grub_strncat #define strstr grub_strstr #define memcmp grub_memcmp @@ -383,6 +385,9 @@ /* * Below this should be ONLY defines and other constructs for C code. */ +#ifdef VGA16 +#define VIDEO 0xA0000 +#endif /* multiboot stuff */ @@ -779,26 +784,26 @@ int currticks (void); /* Clear the screen. */ -void cls (void); +void grub_cls (void); /* The console part of cls. */ void console_cls (void); #ifndef GRUB_UTIL /* Turn off cursor. */ -void nocursor (void); +void grub_nocursor (void); #endif /* Get the current cursor position (where 0,0 is the top left hand corner of the screen). Returns packed values, (RET >> 8) is x, (RET & 0xff) is y. */ -int getxy (void); +int grub_getxy (void); /* The console part of getxy. */ int console_getxy (void); /* Set the cursor position. */ -void gotoxy (int x, int y); +void grub_gotoxy (int x, int y); /* The console part of gotoxy. */ void console_gotoxy (int x, int y); @@ -826,11 +831,67 @@ /* Sets text mode character attribute at the cursor position. See A_* constants defined above. */ -void set_attrib (int attr); +void grub_set_attrib (int attr); /* The console part of set_attrib. */ void console_set_attrib (int attr); +extern int view_x0, view_y0, view_x1, view_y1; +#ifdef VGA16 +#define MAX_DISPLAYS 2 + +#define cls() (display->Cls ? (*display->Cls)() : 0) +#define gotoxy(x, y) (display->Gotoxy ? (*display->Gotoxy)(x, y) : 0) +#define putchar(c) (display->Putchar ? (*display->Putchar)(c) : 0) +#define set_attrib(a) (display->SetAttrib ? (*display->SetAttrib)(a) : 0) +#define getxy() (display->Getxy ? (*display->Getxy)() : 0) +#define nocursor() (display->Nocursor ? (*display->Nocursor)() : 0) +struct display_entry { + char *name; + int (*Begin)(void); + void (*End)(void); + void (*Cls)(void); + void (*Gotoxy)(int x, int y); + void (*Putchar)(int ch); + void (*SetAttrib)(int attr); + int (*Getxy)(void); + void (*Nocursor)(void); +}; +struct display_entry display_entries[MAX_DISPLAYS + 1]; +extern struct display_entry *display; + +extern int vga_inited, foreground, background, shade, border; +extern int display_idx, splash_set; +extern short cursorX, cursorY, cursorWidth, cursorHeight; +extern char cursorBuf[16], splashimage[64]; + +int vga16_begin(void); +void vga16_end(void); +void vga16_cls(void); +void vga16_gotoxy(int x, int y); +void vga16_putchar(int ch); +int vga16_getxy(void); +void vga16_nocursor(void); +void vga16_set_attrib(int attr); + +int read_image(); +void set_palette(int index, int red, int green, int blue); +void *get_font(void); +/* return previous video mode */ +int set_videomode(int mode); + +int hex(int); +void set_int1c_handler(); +void unset_int1c_handler(); +void cursor(int state); +#else +#define cls grub_cls +#define gotoxy grub_gotoxy +#define set_attrib grub_set_attrib +#define getxy grub_getxy +#define nocursor grub_nocursor +#endif + /* Low-level disk I/O */ int get_diskinfo (int drive, struct geometry *geometry); int biosdisk (int subfunc, int drive, struct geometry *geometry, @@ -840,6 +901,8 @@ /* Command-line interface functions. */ #ifndef STAGE1_5 +extern char chainboot[]; + /* The flags for the builtins. */ #define BUILTIN_CMDLINE 0x1 /* Run in the command-line. */ #define BUILTIN_MENU 0x2 /* Run in the menu. */ @@ -1018,6 +1081,7 @@ /* Define flags for load_image here. */ /* Don't pass a Linux's mem option automatically. */ #define KERNEL_LOAD_NO_MEM_OPTION (1 << 0) +#define KERNEL_REALLY_LOAD (1 << 16) kernel_t load_image (char *kernel, char *arg, kernel_t suggested_type, unsigned long load_flags); diff -ru grub-0.92.orig/stage2/stage2.c grub-0.92/stage2/stage2.c --- grub-0.92.orig/stage2/stage2.c 2002-03-24 09:28:54.000000000 -0300 +++ grub-0.92/stage2/stage2.c 2002-06-17 21:19:23.000000000 -0300 @@ -19,7 +19,13 @@ #include "shared.h" +char chainboot[16]; +int view_x0 = 0, view_y0 = 0, view_x1 = 80, view_y1 = 25; grub_jmp_buf restart_env; +#ifdef VGA16 +int vga_disabled = 0, viewport_set = 0; +int sx0, sy0, sx1, sy1; +#endif #if defined(PRESET_MENU_STRING) || defined(SUPPORT_DISKLESS) @@ -109,12 +115,12 @@ } #endif /* SUPPORT_SERIAL */ - gotoxy (77, y + 1); + gotoxy (view_x1 - 3, y + 1); if (first) - grub_putchar (disp_up); + putchar (disp_up); else - grub_putchar (' '); + putchar (' '); menu_entries = get_entry (menu_entries, first, 0); @@ -122,13 +128,13 @@ { int j = 0; - gotoxy (3, y + i); + gotoxy (view_x0 + 3, y + i); while (*menu_entries) { - if (j < 71) + if (j < (view_x1 - view_x0) - 9) { - grub_putchar (*menu_entries); + putchar (*menu_entries); j++; } @@ -138,16 +144,16 @@ if (*(menu_entries - 1)) menu_entries++; - for (; j < 71; j++) - grub_putchar (' '); + for (; j < (view_x1 - view_x0) - 9; j++) + putchar (' '); } - gotoxy (77, y + size); + gotoxy (view_x1 - 3, y + size); if (*menu_entries) - grub_putchar (disp_down); + putchar (disp_down); else - grub_putchar (' '); + putchar (' '); } @@ -159,20 +165,20 @@ #define LINE_LENGTH 67 for (i = 0; i < LINE_LENGTH; i++) - grub_putchar ('-'); - grub_putchar ('\n'); + putchar ('-'); + putchar ('\n'); for (i = first; i < size; i++) { /* grub's printf can't %02d so ... */ if (i < 10) - grub_putchar (' '); + putchar (' '); grub_printf ("%d: %s\n", i, get_entry (menu_entries, i, 0)); } for (i = 0; i < LINE_LENGTH; i++) - grub_putchar ('-'); - grub_putchar ('\n'); + putchar ('-'); + putchar ('\n'); #undef LINE_LENGTH } @@ -211,10 +217,10 @@ ) # endif { - for (i = 0; i < 14; i++) + for (i = 0; i < 12; i++) { int j; - for (j = 0; j < 75; j++) + for (j = view_x0; j < (view_x1 - view_x0) - 5; j++) { gotoxy (j + 1, i + y); set_attrib (normal_color); @@ -223,33 +229,33 @@ } #endif - gotoxy (1, y); + gotoxy (view_x0 + 1, y); - grub_putchar (disp_ul); - for (i = 0; i < 73; i++) - grub_putchar (disp_horiz); - grub_putchar (disp_ur); + putchar (disp_ul); + for (i = 0; i < view_x1 - 7; i++) + putchar (disp_horiz); + putchar (disp_ur); i = 1; while (1) { - gotoxy (1, y + i); + gotoxy (view_x0 + 1, y + i); if (i > size) break; - grub_putchar (disp_vert); - gotoxy (75, y + i); - grub_putchar (disp_vert); + putchar (disp_vert); + gotoxy (view_x1 - 5, y + i); + putchar (disp_vert); i++; } - grub_putchar (disp_ll); - for (i = 0; i < 73; i++) - grub_putchar (disp_horiz); - grub_putchar (disp_lr); + putchar (disp_ll); + for (i = view_x0; i < view_x1 - 7; i++) + putchar (disp_horiz); + putchar (disp_lr); } static void @@ -261,27 +267,27 @@ if (terminal & TERMINAL_SERIAL) { menu_entries = get_entry (menu_entries, entryno, 0); - gotoxy (2, y); - grub_putchar (' '); - for (x = 3; x < 75; x++) + gotoxy (view_x0 + 2, y); + putchar (' '); + for (x = view_x0 + 3; x < view_x1 - 5; x++) { - if (*menu_entries && x < 71) - grub_putchar (*menu_entries++); + if (*menu_entries && x < view_x1 - 9) + putchar (*menu_entries++); else - grub_putchar (' '); + putchar (' '); } } else #endif /* SUPPORT_SERIAL */ { - for (x = 2; x < 75; x++) + for (x = view_x0 + 2; x < view_x1 - 5; x++) { gotoxy (x, y); set_attrib (attr); } } - gotoxy (74, y); + gotoxy (view_x1 - 6, y); } /* Set the attribute of the line Y to normal state. */ @@ -320,6 +326,7 @@ run_menu (char *menu_entries, char *config_entries, int num_entries, char *heap, int entryno) { + int timeout = 1; int c, time1, time2 = -1, first_entry = 0; char *cur_entry = 0; int disp_up = DISP_UP; @@ -399,7 +406,7 @@ #endif /* ! GRUB_UTIL */ if (! (terminal & TERMINAL_DUMB)) - print_border (3, 12); + print_border (3 + view_y0, 12); #ifdef GRUB_UTIL /* In the grub shell, always use ACS_*. */ @@ -455,10 +462,10 @@ grub_printf ("\n\nThe selected entry is %d ", entryno); else { - print_entries (3, 12, first_entry, menu_entries); + print_entries (view_y0 + 3, 12, first_entry, menu_entries); /* highlight initial line */ - set_line_highlight (4 + entryno, first_entry + entryno, + set_line_highlight (view_y0 + 4 + entryno, first_entry + entryno, menu_entries); } } @@ -487,9 +494,9 @@ entryno, grub_timeout); else { - gotoxy (3, 22); - printf ("The highlighted entry will be booted automatically in %d seconds. ", grub_timeout); - gotoxy (74, 4 + entryno); + gotoxy (view_x0 + 3, view_y1 - 2); + printf ("Select an option to install (%d seconds left). ", grub_timeout); + gotoxy (view_x0 - 6, view_y0 + 4 + entryno); } grub_timeout--; @@ -513,14 +520,15 @@ if (grub_timeout >= 0) { if (terminal & TERMINAL_DUMB) - grub_putchar ('\r'); + putchar ('\r'); else - gotoxy (3, 22); + gotoxy (view_x0 + 3, view_y1 - 2); printf (" "); grub_timeout = -1; fallback_entry = -1; if (! (terminal & TERMINAL_DUMB)) - gotoxy (74, 4 + entryno); + gotoxy (view_x1 - 6, view_x0 + 4 + entryno); + timeout = 0; } /* We told them above (at least in SUPPORT_SERIAL) to use @@ -536,17 +544,17 @@ { if (entryno > 0) { - set_line_normal (4 + entryno, first_entry + entryno, + set_line_normal (view_y0 + 4 + entryno, first_entry + entryno, menu_entries); entryno--; - set_line_highlight (4 + entryno, first_entry + entryno, + set_line_highlight (view_y0 + 4 + entryno, first_entry + entryno, menu_entries); } else if (first_entry > 0) { first_entry--; - print_entries (3, 12, first_entry, menu_entries); - set_line_highlight (4, first_entry + entryno, + print_entries (view_y0 + 3, 12, first_entry, menu_entries); + set_line_highlight (view_y0 + 4, first_entry + entryno, menu_entries); } } @@ -558,17 +566,17 @@ else if (entryno < 11) { - set_line_normal (4 + entryno, first_entry + entryno, + set_line_normal (view_y0 + 4 + entryno, first_entry + entryno, menu_entries); entryno++; - set_line_highlight (4 + entryno, first_entry + entryno, + set_line_highlight (view_y0 + 4 + entryno, first_entry + entryno, menu_entries); } else if (num_entries > 12 + first_entry) { first_entry++; - print_entries (3, 12, first_entry, menu_entries); - set_line_highlight (15, first_entry + entryno, menu_entries); + print_entries (view_y0 + 3, 12, first_entry, menu_entries); + set_line_highlight (view_y0 + 15, first_entry + entryno, menu_entries); } } @@ -582,7 +590,7 @@ if ((c == 'd') || (c == 'o') || (c == 'O')) { if (! (terminal & TERMINAL_DUMB)) - set_line_normal (4 + entryno, first_entry + entryno, + set_line_normal (view_y0 + 4 + entryno, first_entry + entryno, menu_entries); /* insert after is almost exactly like insert before */ @@ -640,8 +648,8 @@ } else { - print_entries (3, 12, first_entry, menu_entries); - set_line_highlight (4 + entryno, first_entry + entryno, + print_entries (view_y0 + 3, 12, first_entry, menu_entries); + set_line_highlight (view_y0 + 4 + entryno, first_entry + entryno, menu_entries); } } @@ -664,7 +672,7 @@ if (terminal & TERMINAL_DUMB) grub_printf ("\r "); else - gotoxy (1, 21); + gotoxy (view_x0 + 1, view_y1 - 3); /* Wipe out the previously entered password */ memset (entered, 0, sizeof (entered)); @@ -807,11 +815,26 @@ boot_entry: /* Enable the auto fill mode. */ auto_fill = 1; - - cls (); + + if (timeout && *chainboot) { + errnum = 0; + if (root_func(chainboot, 0) == 0) { + /* If can set the new root device */ + if (chainloader_func("+1", 0) == 0) + /* If can load the new boot */ + boot_func("", 0); + } + } while (1) { + cls (); +#ifdef VGA16 + if (display->End) + (*display->End)(); + display = &display_entries[0]; +#endif + if (config_entries) printf (" Booting \'%s\'\n\n", get_entry (menu_entries, first_entry + entryno, 0)); @@ -840,6 +863,16 @@ break; } +#ifdef VGA16 + if (display_idx >= 0) + display = &display_entries[display_idx]; + else if (!vga_disabled) + display = &display_entries[1]; + + if (!display->Begin || !(*display->Begin)()) + display = &display_entries[0]; +#endif + show_menu = 1; goto restart; } @@ -904,6 +937,560 @@ return pos; } +#ifdef VGA16 +struct display_entry display_entries[MAX_DISPLAYS + 1] = { + {"text", 0, 0, grub_cls, grub_gotoxy, grub_putchar, grub_set_attrib, + grub_getxy, grub_nocursor}, + {"vga16", + vga16_begin, vga16_end, vga16_cls, vga16_gotoxy, vga16_putchar, + vga16_set_attrib, vga16_getxy, vga16_nocursor}, + {0, 0, 0, 0, 0, 0, 0, 0, 0} +}; +struct display_entry *display; +int display_idx = -1; + +/* default vga palette */ +char vga16pal[16][3] = { + { 0, 0, 0}, + { 0, 0, 42}, + { 0, 42, 0}, + { 0, 42, 42}, + {42, 0, 0}, + {42, 0, 42}, + {42, 21, 0}, + {42, 42, 42}, + {21, 21, 21}, + {21, 21, 63}, + {21, 63, 21}, + {21, 63, 63}, + {63, 21, 21}, + {63, 21, 63}, + {63, 63, 21}, + {63, 63, 63}, +}; + +int fontx, fonty; +unsigned char *font8x16; +int saved_videomode, no_scroll = 0, no_cursor = 0, shade = 1, vga_inited = 0; +unsigned short text[80 * 30]; +int foreground = (63 << 16) | (63 << 8) | (63), background = 0, border = 0; +int splash_set; +char splashimage[64]; +#define VSHADOW VSHADOW1 +unsigned char VSHADOW1[38400]; +unsigned char VSHADOW2[38400]; +unsigned char VSHADOW4[38400]; +unsigned char VSHADOW8[38400]; + +static inline void +outb(unsigned short port, unsigned char val) +{ + __asm __volatile ("outb %0,%1"::"a" (val), "d" (port)); +} + +static void +ModeReg(int value) +{ + outb(0x3ce, 5); + outb(0x3cf, value); +} + +static void +MapMask(int value) +{ + outb(0x3c4, 2); + outb(0x3c5, value); +} + +/* set/reset register */ +static void +SetRes(int value) +{ + outb(0x3ce, 0); + outb(0x3cf, value); +} + +/* enable set/reset register */ +static void +ESetRes(int value) +{ + outb(0x3ce, 1); + outb(0x3cf, value); +} + +static void +ReadMap(int value) +{ + outb(0x3ce, 4); + outb(0x3cf, value); +} + +/* bit mask register */ +static void +BitMask(int value) +{ + outb(0x3ce, 8); + outb(0x3cf, value); +} + +void +grub_memcpy(void *dest, const void *src, int len) +{ + int i; + register char *d = (char*)dest, *s = (char*)src; + + for (i = 0; i < len; i++) + d[i] = s[i]; +} + +int +hex(int v) +{ + if (v >= 'A' && v <= 'F') + return (v - 'A' + 10); + if (v >= 'a' && v <= 'f') + return (v - 'a' + 10); + return (v - '0'); +} + +static void +SetXY(int col, int row) +{ + if (col >= view_x0 && col < view_x1) { + fontx = col; + cursorX = col << 3; + } + if (row >= view_y0 && row < view_y1) { + fonty = row; + cursorY = row << 4; + } +} + +void +cursor(int set) +{ + unsigned char *pat, *mem, *ptr, chr[16 << 2]; + int i, ch, invert, offset; + + if (set && (no_cursor || no_scroll)) + return; + + offset = cursorY * 80 + fontx; + ch = text[fonty * 80 + fontx] & 0xff; + invert = (text[fonty * 80 + fontx] & 0xff00) != 0; + pat = font8x16 + (ch << 4); + + mem = (unsigned char*)VIDEO + offset; + + if (!set) { + for (i = 0; i < 16; i++) { + unsigned char mask = pat[i]; + + if (!invert) { + chr[i ] = ((unsigned char*)VSHADOW1)[offset]; + chr[16 + i] = ((unsigned char*)VSHADOW2)[offset]; + chr[32 + i] = ((unsigned char*)VSHADOW4)[offset]; + chr[48 + i] = ((unsigned char*)VSHADOW8)[offset]; + + if (shade) { + if (ch == DISP_VERT || ch == DISP_LL || + ch == DISP_UR || ch == DISP_LR) { + unsigned char pmask = ~(pat[i] >> 1); + + chr[i ] &= pmask; + chr[16 + i] &= pmask; + chr[32 + i] &= pmask; + chr[48 + i] &= pmask; + } + if (i > 0 && ch != DISP_VERT) { + unsigned char pmask = ~(pat[i - 1] >> 1); + + chr[i ] &= pmask; + chr[16 + i] &= pmask; + chr[32 + i] &= pmask; + chr[48 + i] &= pmask; + if (ch == DISP_HORIZ || ch == DISP_UR || ch == DISP_LR) { + pmask = ~pat[i - 1]; + + chr[i ] &= pmask; + chr[16 + i] &= pmask; + chr[32 + i] &= pmask; + chr[48 + i] &= pmask; + } + } + } + chr[i ] |= mask; + chr[16 + i] |= mask; + chr[32 + i] |= mask; + chr[48 + i] |= mask; + + offset += 80; + } + else { + chr[i ] = mask; + chr[16 + i] = mask; + chr[32 + i] = mask; + chr[48 + i] = mask; + } + } + } + else { + MapMask(15); + ptr = mem; + for (i = 0; i < 16; i++, ptr += 80) { + cursorBuf[i] = pat[i]; + *ptr = ~pat[i]; + } + return; + } + + offset = 0; + for (i = 1; i < 16; i <<= 1, offset += 16) { + int j; + + MapMask(i); + ptr = mem; + for (j = 0; j < 16; j++, ptr += 80) + *ptr = chr[j + offset]; + } + + MapMask(15); +} + +int +read_image(void) +{ + char buf[32], pal[16]; + unsigned char c, base, mask, *s1, *s2, *s4, *s8; + unsigned i, len, idx, colors, x, y, width, height; + + if (!grub_open(splashimage)) + return (0); + + /* read header */ + if (!grub_read((char*)&buf, 10) || grub_memcmp(buf, "/* XPM */\n", 10)) { + grub_close(); + return (0); + } + + /* parse info */ + while (grub_read(&c, 1)) { + if (c == '"') + break; + } + + while (grub_read(&c, 1) && (c == ' ' || c == '\t')) + ; + + i = 0; + width = c - '0'; + while (grub_read(&c, 1)) { + if (c >= '0' && c <= '9') + width = width * 10 + c - '0'; + else + break; + } + while (grub_read(&c, 1) && (c == ' ' || c == '\t')) + ; + + height = c - '0'; + while (grub_read(&c, 1)) { + if (c >= '0' && c <= '9') + height = height * 10 + c - '0'; + else + break; + } + while (grub_read(&c, 1) && (c == ' ' || c == '\t')) + ; + + colors = c - '0'; + while (grub_read(&c, 1)) { + if (c >= '0' && c <= '9') + colors = colors * 10 + c - '0'; + else + break; + } + + base = 0; + while (grub_read(&c, 1) && c != '"') + ; + + /* palette */ + for (i = 0, idx = 1; i < colors; i++) { + len = 0; + + while (grub_read(&c, 1) && c != '"') + ; + grub_read(&c, 1); /* char */ + base = c; + grub_read(buf, 4); /* \t c # */ + + while (grub_read(&c, 1) && c != '"') { + if (len < sizeof(buf)) + buf[len++] = c; + } + + if (len == 6 && idx < 15) { + int r = ((hex(buf[0]) << 4) | hex(buf[1])) >> 2; + int g = ((hex(buf[2]) << 4) | hex(buf[3])) >> 2; + int b = ((hex(buf[4]) << 4) | hex(buf[5])) >> 2; + + pal[idx] = base; + set_palette(idx, r, g, b); + ++idx; + } + } + + x = y = len = 0; + + s1 = (unsigned char*)VSHADOW1; + s2 = (unsigned char*)VSHADOW2; + s4 = (unsigned char*)VSHADOW4; + s8 = (unsigned char*)VSHADOW8; + + for (i = 0; i < 38400; i++) + s1[i] = s2[i] = s4[i] = s8[i] = 0; + + /* parse xpm data */ + while (y < height) { + while (1) { + if (!grub_read(&c, 1)) { + grub_close(); + return (0); + } + if (c == '"') + break; + } + + while (grub_read(&c, 1) && c != '"') { + for (i = 1; i < 15; i++) + if (pal[i] == c) { + c = i; + break; + } + + mask = 0x80 >> (x & 7); + if (c & 1) + s1[len + (x >> 3)] |= mask; + if (c & 2) + s2[len + (x >> 3)] |= mask; + if (c & 4) + s4[len + (x >> 3)] |= mask; + if (c & 8) + s8[len + (x >> 3)] |= mask; + + if (++x >= 640) { + x = 0; + + if (y < 480) + len += 80; + ++y; + } + } + } + + grub_close(); + + set_palette(0, (background >> 16), (background >> 8) & 63, background & 63); + set_palette(15, (foreground >> 16), (foreground >> 8) & 63, foreground & 63); + + set_palette(0x11, (border >> 16), (border >> 8) & 63, border & 63); + + return (1); +} + +int +vga16_begin(void) +{ + if (vga_inited) + return (1); + + if (!*splashimage) + grub_strcpy(splashimage, "/boot/grub/splash.xpm"); + + saved_videomode = set_videomode(0x12); + if (!read_image()) { + set_videomode(saved_videomode); + return (0); + } + + font8x16 = (unsigned char*)get_font(); + + cursorWidth = 8; + cursorHeight = 16; + + set_int1c_handler(); + + view_x0 = sx0; + view_y0 = sy0; + view_x1 = sx1; + view_y1 = sy1; + + return (vga_inited = 1); +} + +void +vga16_end(void) +{ + if (vga_inited) { + unset_int1c_handler(); + set_videomode(saved_videomode); + vga_inited = 0; + no_cursor = 0; + } + + sx0 = view_x0; + sy0 = view_y0; + sx1 = view_x1; + sy1 = view_y1; + view_x0 = 0; + view_x1 = 80; + view_y0 = 0; + view_y1 = 25; +} + +void +vga16_cls(void) +{ + int i; + unsigned char *mem, *s1, *s2, *s4, *s8; + + SetXY(view_x0, view_y0); + + mem = (unsigned char*)VIDEO; + s1 = (unsigned char*)VSHADOW1; + s2 = (unsigned char*)VSHADOW2; + s4 = (unsigned char*)VSHADOW4; + s8 = (unsigned char*)VSHADOW8; + + for (i = 0; i < 80 * 30; i++) + text[i] = ' '; + + BitMask(0xff); + + /* plano 1 */ + MapMask(1); + grub_memcpy(mem, s1, 38400); + + /* plano 2 */ + MapMask(2); + grub_memcpy(mem, s2, 38400); + + /* plano 3 */ + MapMask(4); + grub_memcpy(mem, s4, 38400); + + /* plano 4 */ + MapMask(8); + grub_memcpy(mem, s8, 38400); + + MapMask(15); + + if (no_cursor) { + no_cursor = 0; + set_int1c_handler(); + } +} + +void +vga16_gotoxy(int x, int y) +{ + cursor(0); + + SetXY(x, y); + + cursor(1); +} + +static void +scroll(void) +{ + int i, j; + + if (no_scroll) + return; + + no_scroll = 1; + + for (j = view_y0 + 1; j < view_y1; j++) { + gotoxy(view_x0, j - 1); + for (i = view_x0; i < view_x1; i++) + putchar(text[j * 80 + i]); + } + + gotoxy(view_x0, view_y1 - 1); + for (i = view_x0; i < view_x1; i++) + putchar(' '); + + SetXY(view_x0, view_y1 - 1); + + no_scroll = 0; +} + +void +vga16_putchar(int ch) +{ + ch &= 0xff; + + cursor(0); + + if (ch == '\n') { + SetXY(view_x0, fonty); + if (fonty + 1 < view_y1) + SetXY(view_x0, fonty + 1); + else + scroll(); + cursor(1); + return; + } + else if (ch == '\r') { + SetXY(view_x0, fonty); + cursor(1); + return; + } + + text[fonty * 80 + fontx] = ch; + + cursor(0); + + if ((fontx + 1) >= view_x1) { + SetXY(view_x0, fonty); + if (fonty + 1 < view_y1) + SetXY(view_x0, fonty + 1); + else + scroll(); + } + else + SetXY(fontx + 1, fonty); + + cursor(1); +} + +int +vga16_getxy() +{ + return ((fontx << 8) | fonty); +} + +void +vga16_nocursor() +{ + if (!no_cursor) { + no_cursor = 1; + unset_int1c_handler(); + cursor(0); + } +} + +void +vga16_set_attrib(int attrib) +{ + text[fonty * 80 + fontx] &= 0x00ff; + if (attrib & 0xf0) + text[fonty * 80 + fontx] |= 0x100; + cursor(0); +} +#endif /* This is the starting function in C. */ void @@ -924,7 +1511,15 @@ menu_entries = (char *) MENU_BUF; init_config (); } - + +#ifdef VGA16 + /* Make sure it points to a valid entry */ + display = &display_entries[0]; + + if (ASCII_CHAR(checkkey()) == 0x1b) + vga_disabled = 1; +#endif + /* Initialize the environment for restarting Stage 2. */ grub_setjmp (restart_env); @@ -1069,6 +1664,29 @@ while (is_preset); } +#ifdef VGA16 + if (display_idx >= 0) + display = &display_entries[display_idx]; + else if (!vga_disabled) { + display = &display_entries[1]; + } + if (!viewport_set) + view_y1 = 30; + sx0 = view_x0; + sy0 = view_y0; + sx1 = view_x1; + sy1 = view_y1; + + if (!display->Begin || !(*display->Begin)()) + display = &display_entries[0]; + + if (!vga_inited) { + sx0 = sy0 = view_x0 = view_y0 = 0; + sx1 = view_x1 = 80; + sy1 = view_y1 = 25; + } +#endif + if (! num_entries) { /* If no acceptable config file, goto command-line, starting