diff --git a/shared_src/stage2.c b/shared_src/stage2.c new file mode 100644 index 000000000..7995c2cbe --- /dev/null +++ b/shared_src/stage2.c @@ -0,0 +1,561 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "../shared_src/shared.h" + +char * +get_entry(char *list, int num, int nested) +{ + int i; + + for (i = 0; i < num; i++) + { + do + { + while (*(list++)); + } + while (nested && *(list++)); + } + + return list; +} + + +void +print_entries(int y, int size, int first, char *menu_entries) +{ + int i; + + gotoxy(77, y+1); + + if (first) + putchar(DISP_UP); + else + putchar(' '); + + get_entry(menu_entries, first, 0); + + for (i = 1; i <= size; i++) + { + int j = 0; + + gotoxy(3, y+i); + + while (*menu_entries) + { + if (j < 71) + { + putchar(*menu_entries); + j++; + } + + menu_entries++; + } + + if (*(menu_entries-1)) + menu_entries++; + + for (; j < 71; j++) + putchar(' '); + } + + gotoxy(77, y+size); + + if (*menu_entries) + putchar(DISP_DOWN); + else + putchar(' '); +} + + +void +print_border(int y, int size) +{ + int i; + + gotoxy(1, y); + + putchar(DISP_UL); + for (i = 0; i < 73; i++) + putchar(DISP_HORIZ); + putchar(DISP_UR); + + i = 1; + + while (1) + { + gotoxy(1, y+i); + + if (i > size) + break; + + putchar(DISP_VERT); + gotoxy(75, y+i); + putchar(DISP_VERT); + + i++; + } + + putchar(DISP_LL); + for (i = 0; i < 73; i++) + putchar(DISP_HORIZ); + putchar(DISP_LR); +} + +void +set_line(int y, int attr) +{ + int x; + + for (x = 2; x < 75; x++) + { + gotoxy(x, y); + set_attrib(attr); + } +} + + +int timeout = -1; + + +void +run_menu(char *menu_entries, char *config_entries, int num_entries, + char *heap, int entryno) +{ + int c, time1, time2 = -1, first_entry = 0; + char *cur_entry; + + /* + * Main loop for menu UI. + */ + +restart: + while (entryno > 11) + { + first_entry++; entryno--; + } + + init_page(); + + print_border(3, 12); + + printf("\n + Use the \x18 and \x19 keys for selecting which entry is highlighted.\n"); + + if (config_entries) + printf(" Press enter to boot the selected OS, \'e\' to edit the + commands before booting, or \'c\' for a command-line."); + else + printf( +" Press \'b\' to boot, enter to edit the selected command in the + boot sequence, \'c\' for a command-line, \'o\' to open a new line + after (\'O\' for before) the selected line, \'d\' to remove the + selected line, or escape to go back to the main menu."); + + print_entries(3, 12, first_entry, menu_entries); + + /* invert initial line */ + set_line(4+entryno, 0x70); + + /* XX using RT clock now, need to initialize value */ + while ((time1 = getrtsecs()) == 0xFF); + + while (1) + { + /* initilize to NULL just in case... */ + cur_entry = NULL; + + if (timeout >= 0 && (time1 = getrtsecs()) != time2 && time1 != 0xFF) + { + if (timeout <= 0) + { + timeout = -1; + break; + } + + /* else not booting yet! */ + time2 = time1; + gotoxy(3, 22); + printf("The highlighted entry will be booted automatically in %d seconds. ", timeout); + gotoxy(74, 4+entryno); + timeout--; + } + + if (checkkey() != -1) + { + c = getkey(); + + if (timeout >= 0) + { + gotoxy(3, 22); + printf(" "); + timeout = -1; + fallback = -1; + gotoxy(74, 4+entryno); + } + + if ((c == KEY_UP) || (ASCII_CHAR(c) == 16)) + { + if (entryno > 0) + { + set_line(4+entryno, 0x7); + entryno--; + set_line(4+entryno, 0x70); + } + else if (first_entry > 0) + { + first_entry--; + print_entries(3, 12, first_entry, menu_entries); + set_line(4, 0x70); + } + } + if ((c == KEY_DOWN) || (ASCII_CHAR(c) == 14) + && (first_entry+entryno+1) < num_entries) + { + if (entryno < 11) + { + set_line(4+entryno, 0x7); + entryno++; + set_line(4+entryno, 0x70); + } + else if (num_entries > 12+first_entry) + { + first_entry++; + print_entries(3, 12, first_entry, menu_entries); + set_line(15, 0x70); + } + } + + c = ASCII_CHAR(c); + + if (config_entries) + { + if ((c == '\n') || (c == '\r')) + break; + } + else + { + if ((c == 'd') || (c == 'o') || (c == 'O')) + { + set_line(4+entryno, 0x7); + /* insert after is almost exactly like insert before */ + if (c == 'o') + { + entryno++; + c = 'O'; + } + + cur_entry = get_entry(menu_entries, first_entry+entryno, 0); + + if (c == 'O') + { + bcopy(cur_entry, cur_entry+2, + ((int)heap) - ((int)cur_entry)); + + cur_entry[0] = ' '; + cur_entry[1] = 0; + + heap += 2; + + num_entries++; + } + else if (num_entries > 0) + { + char *ptr = get_entry(menu_entries, + first_entry+entryno+1, 0); + bcopy(ptr, cur_entry, ((int)heap) - ((int)ptr)); + heap -= (((int)ptr) - ((int)cur_entry)); + + num_entries--; + + if (entryno >= num_entries) + entryno--; + if (first_entry && num_entries < 12+first_entry) + first_entry--; + } + + print_entries(3, 12, first_entry, menu_entries); + set_line(4+entryno, 0x70); + } + + cur_entry = menu_entries; + if (c == 27) + return; + if (c == 'b') + break; + } + + if ((config_entries && (c == 'e')) + || (!config_entries && ((c == '\n') || (c == '\r')))) + { + int num_entries = 0, i = 0; + char *new_heap; + + if (config_entries) + { + new_heap = heap; + cur_entry = get_entry(config_entries, + first_entry+entryno, 1); + } + else + { + /* safe area! */ + new_heap = heap+1501; + cur_entry = get_entry(menu_entries, first_entry+entryno, 0); + } + + do + { + while (*(new_heap++) = cur_entry[i++]); + num_entries++; + } + while (config_entries && cur_entry[i]); + + /* this only needs to be done if config_entries is non-NULL, + but it doesn't hurt to do it always */ + *(new_heap++) = 0; + + if (config_entries) + run_menu(heap, NULL, num_entries, new_heap, 0); + else + { + cls(); + init_cmdline(); + + new_heap = heap+1501; + + saved_drive = boot_drive; + saved_partition = install_partition; + current_drive = 0xFF; + + if (!get_cmdline("editing> ", commands, new_heap, 1501)) + { + int j = 0; + + /* get length of new command */ + while (new_heap[j++]); + + if (j < 2) + { + j = 2; + new_heap[0] = ' '; + new_heap[1] = 0; + } + + /* align rest of commands properly */ + bcopy(cur_entry+i, cur_entry+j, + ((int)heap) - (((int)cur_entry) + i)); + + /* copy command to correct area */ + bcopy(new_heap, cur_entry, j); + + heap += (j - i); + } + } + + goto restart; + } + if (c == 'c') + { + enter_cmdline(NULL, heap); + goto restart; + } + } + } + + /* + * Attempt to boot an entry. + */ + + do + { + cls(); + + if (config_entries) + printf(" Booting \'%s\'\n\n", + get_entry(menu_entries, first_entry+entryno, 0)); + else + printf(" Booting command-list\n\n"); + + if (!cur_entry) + cur_entry = get_entry(config_entries, first_entry+entryno, 1); + + if (!(c = enter_cmdline(cur_entry, heap))) + { + cur_entry = NULL; + first_entry = 0; + entryno = fallback; + fallback = -1; + } + } + while (!c); + + goto restart; +} + + +static int +get_line_from_config(char *cmdline, int maxlen) +{ + int pos = 0, literal = 0, comment = 0; + char c; /* since we're loading it a byte at a time! */ + + while (read((int)&c, 1)) + { + /* translate characters first! */ + if (c == '\\') + { + literal = 1; + continue; + } + if (c == '\r') + continue; + if ((c == '\t') || (literal && (c == '\n'))) + c = ' '; + + literal = 0; + + if (comment) + { + if (c == '\n') + comment = 0; + } + else if (!pos) + { + if (c == '#') + comment = 1; + else if ((c != ' ') && (c != '\n')) + cmdline[pos++] = c; + } + else + { + if (c == '\n') + break; + + if (pos < maxlen) + cmdline[pos++] = c; + } + } + + cmdline[pos] = 0; + + return pos; +} + + +void +cmain(void) +{ + int config_len = 0, menu_len = 0; + int num_entries = 0, default_entry = 0; + char *config_entries = (char *)(mbi.mmap_addr + mbi.mmap_length); + char *menu_entries = (char *)(BUFFERADDR + (32 * 1024)); + + /* + * Here load the configuration file. + */ + + if (open(config_file)) + { + int state = 0, prev_config_len = 0, prev_menu_len = 0; + char cmdline[1502], *ptr; + + while (get_line_from_config(cmdline, 1500)) + { + ptr = skip_to(1, cmdline); + + if (strcmp("title", cmdline) < 1) + { + if (state > 1) + { + num_entries++; + config_entries[config_len++] = 0; + prev_menu_len = menu_len; + prev_config_len = config_len; + } + else + { + menu_len = prev_menu_len; + config_len = prev_config_len; + } + + state = 1; + + /* copy title into menu area */ + while (menu_entries[menu_len++] = *(ptr++)); + } + else if (!state) + { + if (strcmp("timeout", cmdline) < 1) + safe_parse_maxint(&ptr, &timeout); + if (strcmp("fallback", cmdline) < 1) + safe_parse_maxint(&ptr, &fallback); + if (strcmp("default", cmdline) < 1) + safe_parse_maxint(&ptr, &default_entry); + + errnum = 0; + } + else + { + int i = 0; + + state++; + + /* copy config file data to config area */ + while (config_entries[config_len++] = cmdline[i++]); + } + } + + if (state > 1) + { + num_entries++; + config_entries[config_len++] = 0; + } + else + { + menu_len = prev_menu_len; + config_len = prev_config_len; + } + + menu_entries[menu_len++] = 0; + config_entries[config_len++] = 0; + + bcopy(menu_entries, config_entries+config_len, menu_len); + + menu_entries = config_entries+config_len; + } + + /* + * If no acceptable config file, goto command-line, starting heap from + * where the config entries would have been stored if there were any. + */ + + if (!num_entries) + while (1) + enter_cmdline(NULL, config_entries); + + /* + * Run menu interface (this shouldn't return!). + */ + + run_menu(menu_entries, config_entries, num_entries, + menu_entries+menu_len, default_entry); +} + + diff --git a/stage1/stage1.S b/stage1/stage1.S new file mode 100644 index 000000000..a350bcf09 --- /dev/null +++ b/stage1/stage1.S @@ -0,0 +1,616 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * defines for the code go here + */ + +#define SIGNATURE 0xaa55 +#define BPBEND 0x3e +#define PARTSTART 0x1be /* starting address of partition table */ +#define PARTEND 0x1fe /* ending addres of the partition table */ +#define MINPARAMSIZ 18 /* size of extra data parameters */ +#define LISTSIZ 8 /* size of sector list */ +#define REALSTACK 0x2000 /* stack for this code and BIOS calls */ +#define BUFFERSEG 0x7000 /* segment address of disk buffer, the + disk buffer MUST be 32K long and cannot + straddle a 64K boundary */ +#define BIOS_HD_FLAG 0x80 /* bit set in BIOS drive number to designate + a hard disk vs. a floppy */ + + /* data for debugging */ +#define CHAR_1 '1' +#define CHAR_2 '2' +#define CHAR_3 '3' +#define CHAR_4 '4' +#define CHAR_5 '5' +#define CHAR_6 '6' +#define CHAR_a 'a' + + /* messages displayed at all times */ +#define CHAR_S 'S' +#define CHAR_J 'J' + + /* error messages */ + + /* Read error (trying to read non-existent sector, perhaps) */ +#define CHAR_R 'R' + /* Geometry translation error (off of probed geometry) */ +#define CHAR_G 'G' + /* Disk geometry probe failed! */ +#define CHAR_P 'P' + + /* Absolute addresses + This makes the assembler generate the address without support + from the linker. (ELF can't relocate 16bit addresses!) */ +#define ABS(x) (x-_start+0x7c00) + + /* Relative addresses (for jumps) + These macros use the local label 0, so start with your local + label at 1! */ +#define REL(x) .word x-0f; 0: +#define RELB(x) .byte x-0f; 0: + + /* Print message + movb $x, %al; call message */ +#define MSG(x) movb $x, %al; .byte 0xe8; REL(message) + + .file "stage1.S" + + .text + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + +.globl _start; _start: + /* + * _start is loaded at 0x7c00 and is jumped to with CS:IP 0:0x7c00 + */ + + /* + * Beginning of the sector is compatible with the FAT/HPFS BIOS + * parameter block. + */ + + /* jmp after_BPB */ + .byte 0xeb; RELB(after_BPB) + nop /* do I care about this ??? */ + + /* + * This space is for the BIOS parameter block!!!! Don't change + * the first jump, nor start the code anywhere but right after + * this area. + */ + + . = _start + 4 + + /* scratch space */ +sectors: + .word 0 +heads: + .word 0 +cylinders: + .word 0 + /* more space... */ + + . = _start + BPBEND + + /* + * End of BIOS parameter block. + */ + +after_BPB: + +/* general setup */ + + /* set up %ds and %ss as offset from 0 */ + xorw %ax, %ax + movw %ax, %ds + movw %ax, %es + + cld /* sets the copy direction to forward */ + + /* set up the REAL stack */ + movw %ax, %ss + movw $REALSTACK, %sp + + /* + * Check if we have a forced disk reference here + */ + /* movb firstlist, %al */ + .byte 0xa0; .word ABS(firstlist) + cmpb $0xff, %al + /* je 1f */ + .byte 0x74; RELB(1f) + movb %al, %dl +1: + /* save drive reference first thing! */ + pushw %dx + + /* tell the user that we're here before anything else! */ + MSG(CHAR_S) + +#ifndef BIOS_PROBE_ONLY + /* + * Jump to floppy probe instead of the hard disk probe ? + */ + movb %dl, %al + andb $BIOS_HD_FLAG, %al + + /* jz floppy_probe */ + .byte 0x0f, 0x84; REL(floppy_probe) +#endif + +#ifdef DEBUG + MSG(CHAR_6) +#endif + + /* + * Determine the hard disk geometry from the BIOS! + */ + movb $8, %ah + int $0x13 + + /* if BIOS geometry call fails, display error and die! */ + /* jc probe_error (16-bit)*/ + .byte 0x0f, 0x82; REL(probe_error) + +final_init: + xorb %ah, %ah + movb %dh, %al + incw %ax + + /* movw %ax, heads */ /* save num heads */ + .byte 0xA3; .word ABS(heads) + + xorw %dx, %dx + movb %cl, %dl + shlw $2, %dx + movb %ch, %al + movb %dh, %ah + + incw %ax + + /* movw %ax, cylinders */ /* save num cylinders */ + .byte 0xA3; .word ABS(cylinders) + + xorw %ax, %ax + movb %dl, %al + shrb $2, %al + + /* save a byte on addressing by moving this forward ?? */ + movw $ABS(sectors), %si + + /* movw %ax, (%si) */ /* save num sectors */ + .byte 0x89, 0x04 + + /* this sets up for the first run through "bootloop" */ + movw $ABS(firstlist), %di + + + /* this is the loop for reading the secondary boot-loader in */ +bootloop: + +#ifdef DEBUG + MSG(CHAR_2) +#endif + + /* update position to load from */ + subw $LISTSIZ, %di + + /* cmpw $0, 4(%di) */ /* check the number of sectors to read */ + .byte 0x81, 0x7d, 0x04; .word 0 + + /* je bootit (16-bit)*/ /* if zero, go to the start function */ + .byte 0x0f, 0x84; REL(bootit) + + /* movl (%di), %ax */ /* load logical sector start (bottom half) */ + .byte 0x8b, 0x05 + + /* movl 2(%di), %dx */ /* load logical sector start (top half) */ + .byte 0x8b, 0x55, 0x02 + + /* divw (%si), %dx:%ax */ /* divide by number of sectors */ + .byte 0xf7, 0x34 + + /* movb %dl, (%di) */ /* save sector start */ + .byte 0x88, 0x15 + + xorw %dx, %dx /* zero %dx */ + /* divw 2(%si), %dx:%ax */ /* divide by number of heads */ + .byte 0xf7, 0x74, 0x02 + + /* movb %dl, 1(%di) */ /* save head start */ + .byte 0x88, 0x55, 0x01 + + /* movw %ax, 2(%di) */ /* save cylinder start */ + .byte 0x89, 0x45, 0x02 + + /* cmpw 4(%si), %ax */ /* do we need too many cylinders? */ + .byte 0x3b, 0x44, 0x04 + + /* jge geometry_error (16-bit) */ + .byte 0x0f, 0x8d; REL(geometry_error) + +setup_sectors: + +#ifdef DEBUG + MSG(CHAR_3) +#endif + + /* determine the maximum sector length of this read */ + /* movw (%si), %ax */ /* get number of sectors per track/head */ + .byte 0x8b, 0x04 + + /* subb (%di), %al */ /* subtract sector start */ + .byte 0x2a, 0x05 + + /* how many do we really want to read? */ + /* cmpw %ax, 4(%di) */ /* compare against total number of sectors */ + .byte 0x39, 0x45, 0x04 + + /* jg more_sectors (8-bit)*/ /* which is greater? */ + .byte 0x7f; RELB(more_sectors) + + /* movw 4(%di), %ax */ /* if less than, set to total */ + .byte 0x8b, 0x45, 0x04 + +#ifdef DEBUG + pushw %ax + MSG(CHAR_4) + popw %ax +#endif + +more_sectors: + /* subw %ax, 4(%di) */ /* subtract from total */ + .byte 0x29, 0x45, 0x04 + + /* this is the loop for taking care of BIOS translation (ugh!) */ + +#ifdef DEBUG + pushw %ax + addb $CHAR_a, %al + /* call message */ + .byte 0xe8; REL(message) + popw %ax +#endif + + /* movb 3(%di), %dl */ /* get high bits of cylinder */ + .byte 0x8a, 0x55, 0x03 + + shlb $6, %dl /* shift left by 6 bits */ + /* movw (%di), %cl */ /* get sector */ + .byte 0x8b, 0x0d + + incb %cl /* normalize sector (sectors go + from 1-N, not 0-(N-1) ) */ + orb %dl, %cl /* composite together */ + /* movb 2(%di), %ch */ /* sector+hcyl in cl, cylinder in ch */ + .byte 0x8a, 0x6d, 0x02 + + /* restore %dx */ + popw %dx + pushw %dx + + /* movb 1(%di), %dh */ /* head num */ + .byte 0x8a, 0x75, 0x01 + + pushw %ax /* save %ax from destruction! */ + +/* + * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory + * Call with %ah = 0x2 + * %al = number of sectors + * %ch = cylinder + * %cl = sector (bits 6-7 are high bits of "cylinder") + * %dh = head + * %dl = drive (0x80 for hard disk, 0x0 for floppy disk) + * %es:%bx = segment:offset of buffer + * Return: + * %al = 0x0 on success; err code on failure + */ + + movw $BUFFERSEG, %bx + movw %bx, %es /* load %es segment with disk buffer */ + + xorw %bx, %bx /* %bx = 0, put it at 0 in the segment */ + movb $0x2, %ah /* function 2 */ + int $0x13 + + /* jc read_error */ + .byte 0x72 + RELB(read_error) + + /* load addresses for copy from disk buffer to destination */ + /* movw 6(%di), %es */ /* load destination segment */ + .byte 0x8e, 0x45, 0x06 + + movw $BUFFERSEG, %ax + movw %ax, %fs /* load source segment */ + + /* restore %ax */ + popw %ax + + /* determine the next possible destination address (presuming + 512 byte sectors!) */ + shlw $5, %ax /* shift %ax five bits to the left */ + /* addw %ax, 6(%di) */ /* add the corrected value to the destination + address for next time */ + .byte 0x01, 0x45, 0x06 + + /* get the copy length */ + shlw $4, %ax + movw %ax, %cx + + /* save addressing regs */ + pushw %si + pushw %di + + xorw %di, %di /* zero offset of destination addresses */ + xorw %si, %si /* zero offset of source addresses */ + + /* perform copy */ + rep /* sets a repeat */ + fs /* this overrides the source segment from %ds to %fs */ + movsb /* this runs the actual copy */ + + /* restore addressing regs */ + popw %di + popw %si + + /* check if finished with this dataset */ + /* cmpw $0, 4(%di) */ + .byte 0x81, 0x7d, 0x04; .word 0 + + /* je bootloop */ + .byte 0x0f, 0x84; REL(bootloop) + +#ifdef DEBUG + MSG(CHAR_5) +#endif + + /* find out the next BIOS set to load in */ + /* movb $0, (%di) */ /* set the sector start */ + .byte 0xc6, 0x05, 0 + + xorb %ah, %ah /* zero %ah */ + /* movb 1(%di), %al */ /* load head number into %al */ + .byte 0x8a, 0x45, 0x01 + + incw %ax /* increment current head number */ + /* cmpw 2(%si), %ax */ /* compare to total number of heads */ + .byte 0x3b, 0x44, 0x02 + + /* jne update_heads (8-bit)*/ + .byte 0x75; RELB(update_heads) + + /* movw 2(%di), %ax */ /* load cylinder number into %ax */ + .byte 0x8b, 0x45, 0x02 + + incw %ax /* increment current cylinder number */ + /* cmpw 4(%si), %ax */ /* compare to total number of cylinders */ + .byte 0x3b, 0x44, 0x04 + + /* je geometry_error */ /* display error and die if greater */ + .byte 0x74; RELB(geometry_error) + + /* movw %ax, 2(%di) */ /* store new cylinder number */ + .byte 0x89, 0x45, 0x02 + + movb $0, %al /* for storing new head number */ + +update_heads: + /* movb %al, 1(%di) */ /* store new head number */ + .byte 0x88, 0x45, 0x01 + +#ifdef DEBUG + addb $CHAR_a, %al + /* call message */ + .byte 0xe8; REL(message) + + /* movb 2(%di), %al */ + .byte 0x8a, 0x45, 0x02 + + addb $CHAR_a, %al + /* call message */ + .byte 0xe8; REL(message) +#endif + + /* jump to "setup_sectors" to determine length of the new read */ + /* jmp setup_sectors */ + .byte 0xe9; REL(setup_sectors) + +/* + * BIOS Geometry translation error (past the end of the disk geometry!). + */ +geometry_error: + movb $CHAR_G, %al + /* jmp display_error (8-bit) */ + .byte 0xeb; RELB(display_error) + +/* + * Disk probe failure. + */ +probe_error: + movb $CHAR_P, %al + /* jmp display_error (8-bit) */ + .byte 0xeb; RELB(display_error) + +/* + * Read error on the disk. + */ +read_error: + movb $CHAR_R, %al + +display_error: + /* call message */ + .byte 0xe8; REL(message) + +/* go here when you need to stop the machine hard after an error condition */ +stop: /* jmp stop (8-bit) */ + .byte 0xeb; RELB(stop) + + +/* + * message: write the character in %al to the console, %ah gets trashed. + */ +message: + /* + * Use BIOS "int 10H Function 0Eh" to write character in teletype mode + * %ah = 0xe %al = character + * %bh = page %bl = foreground color (graphics modes) + */ + + pushw %bx + movw $0x0001, %bx + movb $0xe, %ah + int $0x10 /* display a byte */ + popw %bx + + /* ret */ + .byte 0xc3 +lastlist: + + /* + * This data area is for keeping general parameters. + */ + . = _start + PARTSTART - MINPARAMSIZ - LISTSIZ + + /* this next data area before the partition area is specifically + sized, you should update "MINPARAMSIZ" to reflect any additions + or deletions to this area */ + + .word 0 + .word 0 + + /* fill the first data listing with the default */ +#ifdef FFS_STAGE1_5 + .long 2 /* this is the sector start parameter, in logical + sectors from the start of the disk, sector 0 */ + .word 14 /* this is the number of sectors to read */ + .word 0x0200 /* this is the segment of the starting address + to load the data into */ +#else + .long 1 /* this is the sector start parameter, in logical + sectors from the start of the disk, sector 0 */ + .word 64 /* this is the number of sectors to read */ + .word 0x0800 /* this is the segment of the starting address + to load the data into */ +#endif +firstlist: + .byte 0xff /* the disk to load stage2 from */ + /* 0xff means use the boot drive */ +/* the above label has to be after its data!!! */ + + /* + * Jump here when all data loading is done. + */ + +bootit: + + /* + * Tell the user we're going to the next stage... + */ + MSG(CHAR_J) + + popw %dx /* this makes sure %dl is our "boot" drive */ + + /* + * ljmp to the second stage boot loader. + */ + + /* ljmp $myoffset, $myseg */ + .byte 0xea +#ifdef STAGE1_5 + .word 0x2000, 0 +#else + .word 0x8000, 0 +#endif + + /* + * This is the compatibility version number. + * + * DO NOT MOVE THIS!!! + */ + .byte 1, 0 + + /* + * This is where an MBR would go if on a hard disk. The code + * here isn't even referenced unless we're on a floppy. Kinda + * sneaky, huh? + */ + + . = _start + PARTSTART + +#ifndef BIOS_PROBE_ONLY +probe_values: + .byte 36, 18, 15, 9, 0 + +floppy_probe: +/* + * Perform floppy probe! + */ + + movw $ABS(probe_values-1), %si + +probe_loop: + /* reset floppy controller INT 13h AH=0 */ + xorw %ax, %ax + int $0x13 + + incw %si + + /* movb (%si), %cl */ + .byte 0x8a, 0x0c + + /* if number of sectors is 0, display error and die */ + cmpb $0, %cl + + /* je probe_error (16-bit)*/ + .byte 0x0f, 0x84; REL(probe_error) + + /* perform read */ + movw $REALSTACK, %bx + movw $0x201, %ax + movb $0, %ch + movb $0, %dh + int $0x13 + + /* if error, jump to "probe_loop" */ + /* jc probe_loop (8-bit)*/ + .byte 0x72; RELB(probe_loop) + + /* %cl is already the correct value! */ + movb $1, %dh + movb $79, %ch + + /* jmp final_init */ + .byte 0xe9; REL(final_init) + +#endif /* !BIOS_PROBE_ONLY */ + + . = _start + PARTEND + +/* the last 2 bytes in the sector 0 contain the signature */ + .word SIGNATURE +