diff --git a/ChangeLog b/ChangeLog index 7743aa2d4..3d8bd25e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +2011-11-12 Vladimir Serbinenko + + Move assembly code to C by using intwrap. It increases core size + by 88 bytes but improves compatibility and maintainability. + + * grub-core/kern/i386/pc/startup.S (grub_console_putchar): Moved to ... + * grub-core/term/i386/pc/console.c (grub_console_putchar_real): + ... here. Translated to C. + * grub-core/kern/i386/pc/startup.S (grub_console_getkey): Moved to ... + * grub-core/term/i386/pc/console.c (grub_console_getkey): + ... here. Translated to C. + * grub-core/kern/i386/pc/startup.S (grub_console_getxy): Moved to ... + * grub-core/term/i386/pc/console.c (grub_console_getxy): + ... here. Translated to C. + * grub-core/kern/i386/pc/startup.S (grub_console_gotoxy): Moved to ... + * grub-core/term/i386/pc/console.c (grub_console_gotoxy): + ... here. Translated to C. + * grub-core/kern/i386/pc/startup.S (grub_console_cls): Moved to ... + * grub-core/term/i386/pc/console.c (grub_console_cls): + ... here. Translated to C. + * grub-core/kern/i386/pc/startup.S (grub_console_setcursor): Moved to .. + * grub-core/term/i386/pc/console.c (grub_console_setcursor): + ... here. Translated to C. + * grub-core/kern/i386/pc/startup.S (grub_get_rtc): Moved to .. + * grub-core/kern/i386/pc/init.c (grub_get_rtc): ... here. + Translated to C. + * grub-core/term/i386/pc/console.c (int10_9): New function. + (grub_console_putchar): Likewise. + * include/grub/i386/pc/console.h: Removed the not anymore shared + functions. + 2011-11-12 Vladimir Serbinenko Move grub_chainloader_real_boot out of the kernel. diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c index be26fdea1..6fbfab3b8 100644 --- a/grub-core/kern/i386/pc/init.c +++ b/grub-core/kern/i386/pc/init.c @@ -47,6 +47,22 @@ static int num_regions; void (*grub_pc_net_config) (char **device, char **path); +/* + * return the real time in ticks, of which there are about + * 18-20 per second + */ +grub_uint32_t +grub_get_rtc (void) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x1a, ®s); + + return (regs.ecx << 16) | (regs.edx & 0xffff); +} + void grub_machine_get_bootlocation (char **device, char **path) { diff --git a/grub-core/kern/i386/pc/startup.S b/grub-core/kern/i386/pc/startup.S index df8992278..94d4f02ee 100644 --- a/grub-core/kern/i386/pc/startup.S +++ b/grub-core/kern/i386/pc/startup.S @@ -464,371 +464,6 @@ FUNCTION(grub_exit) ljmp $0xf000, $0xfff0 .code32 -/* - * void grub_console_putchar (int c) - * - * Put the character C on the console. Because GRUB wants to write a - * character with an attribute, this implementation is a bit tricky. - * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh - * (TELETYPE OUTPUT). Otherwise, save the original position, put a space, - * save the current position, restore the original position, write the - * character and the attribute, and restore the current position. - * - * The reason why this is so complicated is that there is no easy way to - * get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't - * support setting a background attribute. - */ -FUNCTION(grub_console_putchar) - /* Retrieve the base character. */ - movl 0(%edx), %edx - pusha - movb EXT_C(grub_console_cur_color), %bl - - call prot_to_real - .code16 - movb %dl, %al - xorb %bh, %bh - - /* use teletype output if control character */ - cmpb $0x7, %al - je 1f - cmpb $0x8, %al - je 1f - cmpb $0xa, %al - je 1f - cmpb $0xd, %al - je 1f - - /* save the character and the attribute on the stack */ - pushw %ax - pushw %bx - - /* get the current position */ - movb $0x3, %ah - int $0x10 - - /* check the column with the width */ - cmpb $79, %dl - jl 2f - - /* print CR and LF, if next write will exceed the width */ - movw $0x0e0d, %ax - int $0x10 - movb $0x0a, %al - int $0x10 - - /* get the current position */ - movb $0x3, %ah - int $0x10 - -2: - /* restore the character and the attribute */ - popw %bx - popw %ax - - /* write the character with the attribute */ - movb $0x9, %ah - movw $1, %cx - int $0x10 - - /* move the cursor forward */ - incb %dl - movb $0x2, %ah - int $0x10 - - jmp 3f - -1: movw $1, %bx - movb $0xe, %ah - int $0x10 - -3: DATA32 call real_to_prot - .code32 - - popa - ret - - -LOCAL(bypass_table): - .word 0x011b, 0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r' - .word 0x1c00 | '\n' -LOCAL(bypass_table_end): - -/* - * int grub_console_getkey (void) - * if there is a character pending, return it; otherwise return -1 - * BIOS call "INT 16H Function 01H" to check whether a character is pending - * Call with %ah = 0x1 - * Return: - * If key waiting to be input: - * %ah = keyboard scan code - * %al = ASCII character - * Zero flag = clear - * else - * Zero flag = set - * BIOS call "INT 16H Function 00H" to read character from keyboard - * Call with %ah = 0x0 - * Return: %ah = keyboard scan code - * %al = ASCII character - */ - -FUNCTION(grub_console_getkey) - pushl %ebp - pushl %edi - - call prot_to_real - .code16 - - /* - * Due to a bug in apple's bootcamp implementation, INT 16/AH = 0 would - * cause the machine to hang at the second keystroke. However, we can - * work around this problem by ensuring the presence of keystroke with - * INT 16/AH = 1 before calling INT 16/AH = 0. - */ - - movb $1, %ah - int $0x16 - jz notpending - - movb $0, %ah - int $0x16 - - xorl %edx, %edx - movw %ax, %dx /* real_to_prot uses %eax */ - - DATA32 call real_to_prot - .code32 - - movl $0xff, %eax - testl %eax, %edx - jz 1f - - andl %edx, %eax - cmpl $0x20, %eax - jae 2f - movl %edx, %eax - leal LOCAL(bypass_table), %edi - movl $((LOCAL(bypass_table_end) - LOCAL(bypass_table)) >> 1), %ecx - repne scasw - jz 3f - - andl $0xff, %eax - addl $(('a' - 1) | GRUB_TERM_CTRL), %eax - jmp 2f -3: - andl $0xff, %eax - jmp 2f - -1: movl %edx, %eax - shrl $8, %eax - orl $GRUB_TERM_EXTENDED, %eax -2: - popl %edi - popl %ebp - ret - -notpending: - .code16 - DATA32 call real_to_prot - .code32 -#if GRUB_TERM_NO_KEY != 0 -#error Fix this asm code -#endif - jmp 2b - - -/* - * grub_uint16_t grub_console_getxy (void) - * BIOS call "INT 10H Function 03h" to get cursor position - * Call with %ah = 0x03 - * %bh = page - * Returns %ch = starting scan line - * %cl = ending scan line - * %dh = row (0 is top) - * %dl = column (0 is left) - */ - - -FUNCTION(grub_console_getxy) - pushl %ebp - pushl %ebx /* save EBX */ - - call prot_to_real - .code16 - - xorb %bh, %bh /* set page to 0 */ - movb $0x3, %ah - int $0x10 /* get cursor position */ - - DATA32 call real_to_prot - .code32 - - movb %dl, %ah - movb %dh, %al - - popl %ebx - popl %ebp - ret - - -/* - * void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y) - * BIOS call "INT 10H Function 02h" to set cursor position - * Call with %ah = 0x02 - * %bh = page - * %dh = row (0 is top) - * %dl = column (0 is left) - */ - - -FUNCTION(grub_console_gotoxy) - pushl %ebp - pushl %ebx /* save EBX */ - - movb %cl, %dh /* %dh = y */ - /* %dl = x */ - - call prot_to_real - .code16 - - xorb %bh, %bh /* set page to 0 */ - movb $0x2, %ah - int $0x10 /* set cursor position */ - - DATA32 call real_to_prot - .code32 - - popl %ebx - popl %ebp - ret - - -/* - * void grub_console_cls (void) - * BIOS call "INT 10H Function 09h" to write character and attribute - * Call with %ah = 0x09 - * %al = (character) - * %bh = (page number) - * %bl = (attribute) - * %cx = (number of times) - */ - -FUNCTION(grub_console_cls) - pushl %ebp - pushl %ebx /* save EBX */ - - call prot_to_real - .code16 - - /* move the cursor to the beginning */ - movb $0x02, %ah - xorb %bh, %bh - xorw %dx, %dx - int $0x10 - - /* write spaces to the entire screen */ - movw $0x0920, %ax - movw $0x07, %bx - movw $(80 * 25), %cx - int $0x10 - - /* move back the cursor */ - movb $0x02, %ah - int $0x10 - - DATA32 call real_to_prot - .code32 - - popl %ebx - popl %ebp - ret - - -/* - * void grub_console_setcursor (int on) - * BIOS call "INT 10H Function 01h" to set cursor type - * Call with %ah = 0x01 - * %ch = cursor starting scanline - * %cl = cursor ending scanline - */ - -console_cursor_state: - .byte 1 -console_cursor_shape: - .word 0 - -FUNCTION(grub_console_setcursor) - pushl %ebp - pushl %ebx - - /* push ON */ - pushl %edx - - /* check if the standard cursor shape has already been saved */ - movw console_cursor_shape, %ax - testw %ax, %ax - jne 1f - - call prot_to_real - .code16 - - movb $0x03, %ah - xorb %bh, %bh - int $0x10 - - DATA32 call real_to_prot - .code32 - - cmp %cl, %ch - jb 3f - movw $0x0d0e, %cx -3: - movw %cx, console_cursor_shape -1: - /* set %cx to the designated cursor shape */ - movw $0x2000, %cx - popl %eax - testl %eax, %eax - jz 2f - movw console_cursor_shape, %cx -2: - call prot_to_real - .code16 - - movb $0x1, %ah - int $0x10 - - DATA32 call real_to_prot - .code32 - - popl %ebx - popl %ebp - ret - -/* - * grub_get_rtc() - * return the real time in ticks, of which there are about - * 18-20 per second - */ -FUNCTION(grub_get_rtc) - pushl %ebp - - call prot_to_real /* enter real mode */ - .code16 - - /* %ax is already zero */ - int $0x1a - - DATA32 call real_to_prot - .code32 - - movl %ecx, %eax - shll $16, %eax - movw %dx, %ax - - popl %ebp - ret - /* * int grub_pxe_call (int func, void* data, grub_uint32_t pxe_rm_entry); */ diff --git a/grub-core/term/i386/pc/console.c b/grub-core/term/i386/pc/console.c index 0efeafe4e..7cf5ffc5f 100644 --- a/grub-core/term/i386/pc/console.c +++ b/grub-core/term/i386/pc/console.c @@ -20,6 +20,225 @@ #include #include #include +#include + +static void +int10_9 (grub_uint8_t ch, grub_uint16_t n) +{ + struct grub_bios_int_registers regs; + + regs.eax = ch | 0x0900; + regs.ebx = grub_console_cur_color & 0xff; + regs.ecx = n; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); +} + +/* + * BIOS call "INT 10H Function 03h" to get cursor position + * Call with %ah = 0x03 + * %bh = page + * Returns %ch = starting scan line + * %cl = ending scan line + * %dh = row (0 is top) + * %dl = column (0 is left) + */ + + +static grub_uint16_t +grub_console_getxy (struct grub_term_output *term __attribute__ ((unused))) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x0300; + regs.ebx = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + + return ((regs.edx & 0xff) << 8) | ((regs.edx & 0xff00) >> 8); +} + +/* + * BIOS call "INT 10H Function 02h" to set cursor position + * Call with %ah = 0x02 + * %bh = page + * %dh = row (0 is top) + * %dl = column (0 is left) + */ +static void +grub_console_gotoxy (struct grub_term_output *term __attribute__ ((unused)), + grub_uint8_t x, grub_uint8_t y) +{ + struct grub_bios_int_registers regs; + + /* set page to 0 */ + regs.ebx = 0; + regs.eax = 0x0200; + regs.edx = (y << 8) | x; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); +} + +/* + * + * Put the character C on the console. Because GRUB wants to write a + * character with an attribute, this implementation is a bit tricky. + * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh + * (TELETYPE OUTPUT). Otherwise, save the original position, put a space, + * save the current position, restore the original position, write the + * character and the attribute, and restore the current position. + * + * The reason why this is so complicated is that there is no easy way to + * get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't + * support setting a background attribute. + */ +static void +grub_console_putchar_real (grub_uint8_t c) +{ + struct grub_bios_int_registers regs; + grub_uint16_t pos; + + if (c == 7 || c == 8 || c == 0xa || c == 0xd) + { + regs.eax = c | 0x0e00; + regs.ebx = 0x0001; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + return; + } + + /* get the current position */ + pos = grub_console_getxy (NULL); + + /* check the column with the width */ + if ((pos & 0xff00) >= (79 << 8)) + { + grub_console_putchar_real (0x0d); + grub_console_putchar_real (0x0a); + /* get the current position */ + pos = grub_console_getxy (NULL); + } + + /* write the character with the attribute */ + int10_9 (c, 1); + + grub_console_gotoxy (NULL, ((pos & 0xff00) >> 8) + 1, (pos & 0xff)); +} + +static void +grub_console_putchar (struct grub_term_output *term __attribute__ ((unused)), + const struct grub_unicode_glyph *c) +{ + grub_console_putchar_real (c->base); +} + +/* + * BIOS call "INT 10H Function 09h" to write character and attribute + * Call with %ah = 0x09 + * %al = (character) + * %bh = (page number) + * %bl = (attribute) + * %cx = (number of times) + */ +static void +grub_console_cls (struct grub_term_output *term) +{ + /* move the cursor to the beginning */ + grub_console_gotoxy (term, 0, 0); + + /* write spaces to the entire screen */ + int10_9 (' ', 80 * 25); + + /* move back the cursor */ + grub_console_gotoxy (term, 0, 0); +} + +/* + * void grub_console_setcursor (int on) + * BIOS call "INT 10H Function 01h" to set cursor type + * Call with %ah = 0x01 + * %ch = cursor starting scanline + * %cl = cursor ending scanline + */ +static void +grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)), + int on) +{ + static grub_uint16_t console_cursor_shape = 0; + struct grub_bios_int_registers regs; + + /* check if the standard cursor shape has already been saved */ + if (!console_cursor_shape) + { + regs.eax = 0x0300; + regs.ebx = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + console_cursor_shape = regs.ecx; + if ((console_cursor_shape >> 8) >= (console_cursor_shape & 0xff)) + console_cursor_shape = 0x0d0e; + } + /* set %cx to the designated cursor shape */ + regs.ecx = on ? console_cursor_shape : 0x2000; + regs.eax = 0x0100; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); +} + +/* + * if there is a character pending, return it; otherwise return -1 + * BIOS call "INT 16H Function 01H" to check whether a character is pending + * Call with %ah = 0x1 + * Return: + * If key waiting to be input: + * %ah = keyboard scan code + * %al = ASCII character + * Zero flag = clear + * else + * Zero flag = set + * BIOS call "INT 16H Function 00H" to read character from keyboard + * Call with %ah = 0x0 + * Return: %ah = keyboard scan code + * %al = ASCII character + */ + +static int +grub_console_getkey (struct grub_term_input *term __attribute__ ((unused))) +{ + const grub_uint16_t bypass_table[] = { + 0x0100 | '\e', 0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r', 0x1c00 | '\n' + }; + struct grub_bios_int_registers regs; + unsigned i; + + /* + * Due to a bug in apple's bootcamp implementation, INT 16/AH = 0 would + * cause the machine to hang at the second keystroke. However, we can + * work around this problem by ensuring the presence of keystroke with + * INT 16/AH = 1 before calling INT 16/AH = 0. + */ + + regs.eax = 0x0100; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x16, ®s); + if (regs.flags & GRUB_CPU_INT_FLAGS_ZERO) + return GRUB_TERM_NO_KEY; + + regs.eax = 0x0000; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x16, ®s); + if (!(regs.eax & 0xff)) + return ((regs.eax >> 8) & 0xff) | GRUB_TERM_EXTENDED; + + if ((regs.eax & 0xff) >= ' ') + return regs.eax & 0xff; + + for (i = 0; i < ARRAY_SIZE (bypass_table); i++) + if (bypass_table[i] == (regs.eax & 0xffff)) + return regs.eax & 0xff; + + return (regs.eax & 0xff) + (('a' - 1) | GRUB_TERM_CTRL); +} static const struct grub_machine_bios_data_area *bios_data_area = (struct grub_machine_bios_data_area *) GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR; diff --git a/include/grub/i386/pc/console.h b/include/grub/i386/pc/console.h index 1631a40ad..f752b9a25 100644 --- a/include/grub/i386/pc/console.h +++ b/include/grub/i386/pc/console.h @@ -26,16 +26,6 @@ #include #include -/* These are global to share code between C and asm. */ -int grub_console_getkey (struct grub_term_input *term); -grub_uint16_t grub_console_getxy (struct grub_term_output *term); -void grub_console_gotoxy (struct grub_term_output *term, - grub_uint8_t x, grub_uint8_t y); -void grub_console_cls (struct grub_term_output *term); -void grub_console_setcursor (struct grub_term_output *term, int on); -void grub_console_putchar (struct grub_term_output *term, - const struct grub_unicode_glyph *c); - /* Initialize the console system. */ void grub_console_init (void);