2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002,2004 Free Software Foundation, Inc.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * Note: These functions defined in this file may be called from C.
23 * Be careful of that you must not modify some registers. Quote
24 * from gcc-2.95.2/gcc/config/i386/i386.h:
26 1 for registers not available across function calls.
27 These must include the FIXED_REGISTERS and also any
28 registers that can be used without being saved.
29 The latter must include the registers where values are returned
30 and the register where structure-value addresses are passed.
31 Aside from that, you can include as many other registers as you like.
33 ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
34 { 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
42 # define ABS(x) ((x) - EXT_C(main) + 0x2200)
44 # define ABS(x) ((x) - EXT_C(main) + 0x8200)
51 /* Tell GAS to generate 16-bit instructions so that this code works
57 * In stage2, do not link start.S with the rest of the source
58 * files directly, so define the start symbols here just to
59 * force ld quiet. These are not referred anyway.
64 #endif /* ! STAGE1_5 */
68 * Guarantee that "main" is loaded at 0x0:0x8200 in stage2 and
69 * at 0x0:0x2200 in stage1.5.
71 ljmp $0, $ABS(codestart)
74 * Compatibility version number
76 * These MUST be at byte offset 6 and 7 of the executable
80 .byte COMPAT_VERSION_MAJOR, COMPAT_VERSION_MINOR
83 * This is a special data area 8 bytes from the beginning.
88 VARIABLE(install_partition)
90 /* This variable is here only because of a historical reason. */
91 VARIABLE(saved_entryno)
97 VARIABLE(version_string)
101 .string "/boot/pc/grub/menu.lst"
104 .string "/boot/pc/grub/stage2"
105 #endif /* STAGE1_5 */
108 * Leave some breathing room for the config file name.
111 . = EXT_C(main) + 0x70
113 /* the real mode code continues... */
115 cli /* we're not safe here! */
117 /* set up %ds, %ss, and %es */
123 #ifndef SUPPORT_DISKLESS
125 * Save the sector number of the second sector (i.e. this sector)
126 * in INSTALL_SECOND_SECTOR. See also "stage2/start.S".
128 ADDR32 movl %ebp, EXT_C(install_second_sector)
131 /* set up the real mode/BIOS stack */
135 sti /* we're safe again */
137 #ifndef SUPPORT_DISKLESS
138 /* save boot drive reference */
139 ADDR32 movb %dl, EXT_C(boot_drive)
141 /* reset disk system (%ah = 0) */
145 /* transition to protected mode */
146 DATA32 call EXT_C(real_to_prot)
148 /* The ".code32" directive takes GAS out of 16-bit mode. */
151 /* clean out the bss */
153 /* set %edi to the bss starting address */
154 #if defined(HAVE_USCORE_USCORE_BSS_START_SYMBOL)
155 movl $__bss_start, %edi
156 #elif defined(HAVE_USCORE_EDATA_SYMBOL)
158 #elif defined(HAVE_EDATA_SYMBOL)
162 /* set %ecx to the bss end */
163 #if defined(HAVE_END_SYMBOL)
165 #elif defined(HAVE_USCORE_END_SYMBOL)
169 /* compute the bss length */
175 /* set the direction */
183 * Call the start of main body of C code, which does some
184 * of it's own initialization before transferring to "cmain".
186 call EXT_C(init_bios_info)
190 * This call is special... it never returns... in fact it should simply
191 * hang at this point!
195 call EXT_C(prot_to_real)
198 * This next part is sort of evil. It takes advantage of the
199 * byte ordering on the x86 to work in either 16-bit or 32-bit
200 * mode, so think about it before changing it.
211 * Stops the floppy drive from spinning, so that other software is
212 * jumped to with a known state.
216 call EXT_C(prot_to_real)
220 DATA32 call EXT_C(real_to_prot)
228 * Reboot the system. At the moment, rely on BIOS.
231 call EXT_C(prot_to_real)
236 ljmp $0xFFFF, $0x0000
240 * grub_halt(int no_apm)
242 * Halt the system, using APM if possible. If NO_APM is true, don't use
243 * APM even if it is available.
246 /* get the argument */
253 call EXT_C(prot_to_real)
261 /* don't check %bx for buggy BIOSes... */
263 /* disconnect APM first */
274 /* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */
281 /* set the power state to off */
287 /* shouldn't reach here */
292 * track_int13(int drive)
294 * Track the int13 handler to probe I/O address space.
303 /* copy the original int13 handler segment:offset */
306 movl %eax, track_int13_addr
308 /* replace the int1 handler */
311 movl $ABS(int1_handler), %eax
314 /* read the MBR to call int13 successfully */
317 call EXT_C(prot_to_real)
320 movw $SCRATCHSEG, %ax
326 /* save FLAGS on the stack to emulate int13 */
329 /* set the TF flag */
330 /* FIXME: this can be simplified not to use AX */
339 .byte 0x9a /* lcall */
342 .word 0 /* segment */
344 /* TF is cleared here automatically */
346 DATA32 call EXT_C(real_to_prot)
349 /* restore the int1 handler */
361 * Check if the next instruction is I/O, and if this is true, add the
362 * port into the io map.
364 * Note: Probably this will make the execution of int13 very slow.
366 * Note2: In this implementation, all we can know is I/O-mapped I/O. It
367 * is impossible to detect memory-mapped I/O.
385 /* examine the next instruction */
387 /* skip this code if it is a prefix */
405 3: /* check if this code is out* or in* */
413 4: /* in? or out? (register operand version) */
419 6: /* in? or out? (immediate operand version) */
425 7: /* immediate has a port */
429 5: /* %dx has a port */
431 /* set %ds to zero */
435 /* set %si to the io map */
436 movw $ABS(EXT_C(io_map)), %si
439 9: /* check if the io map already has the port */
441 /* check if this is the end */
444 /* check if this matches the port */
447 /* if so, leave from this handler */
450 1: /* check for the buffer overrun */
451 cmpw $(ABS(EXT_C(io_map)) + (IO_MAP_SIZE + 1) * 2), %si
453 /* add the port into the io map */
456 8: /* restore registers */
468 .space (IO_MAP_SIZE + 1) * 2
472 * set_int15_handler(void)
474 * Set up int15_handler.
476 ENTRY(set_int15_handler)
479 /* save the original int15 handler */
482 movw %ax, ABS(int15_offset)
484 movw %ax, ABS(int15_segment)
486 /* save the new int15 handler */
487 movw $ABS(int15_handler), %ax
497 * unset_int15_handler(void)
499 * Restore the original int15 handler
501 ENTRY(unset_int15_handler)
504 /* check if int15_handler is set */
506 movw $ABS(int15_handler), %ax
513 /* restore the original */
514 movw ABS(int15_offset), %ax
516 movw ABS(int15_segment), %ax
525 * Translate a key code to another.
527 * Note: This implementation cannot handle more than one length
528 * scancodes (such as Right Ctrl).
532 /* if non-carrier, ignore it */
538 /* E0 and E1 are special */
542 /* this flag is actually the machine code (je or jmp) */
554 /* save bits 0-6 of %al in %dl */
557 /* save the highest bit in %bl */
563 /* set %si to the key map */
564 movw $ABS(EXT_C(bios_key_map)), %si
566 /* find the key code from the key map */
569 /* check if this is the end */
572 /* check if this matches the key code */
575 /* if so, perform the mapping */
581 /* make sure that CF is set */
583 /* restore other registers */
592 /* tricky: jmp (0x74) <-> je (0xeb) */
593 xorb $(0x74 ^ 0xeb), ABS(int15_skip_flag)
595 /* just cascade to the original */
598 int15_offset: .word 0
599 int15_segment: .word 0
605 .space (KEY_MAP_SIZE + 1) * 2
609 * set_int13_handler(map)
611 * Copy MAP to the drive map and set up int13_handler.
613 ENTRY(set_int13_handler)
620 /* copy MAP to the drive map */
621 movl $(DRIVE_MAP_SIZE * 2), %ecx
622 movl $ABS(drive_map), %edi
628 /* save the original int13 handler */
631 movw %ax, ABS(int13_offset)
633 movw %ax, ABS(int13_segment)
635 /* decrease the lower memory size and set it to the BIOS memory */
641 /* compute the segment */
644 /* save the new int13 handler */
650 /* copy int13_handler to the reserved area */
653 movl $ABS(int13_handler), %esi
654 movl $(int13_handler_end - int13_handler), %ecx
665 * Map a drive to another drive.
677 /* set %si to the drive map */
678 movw $(drive_map - int13_handler), %si
679 /* find the drive number from the drive map */
683 /* check if this is the end */
686 /* check if this matches the drive number */
689 /* if so, perform the mapping */
694 /* save %ax in the stack */
696 /* simulate the interrupt call */
698 /* set %ax and %bp to the original values */
703 int13_offset: .word 0
704 int13_segment: .word 0
711 /* set the flags in the stack to the value returned by int13 */
714 /* check if should map the drive number */
720 /* check if the mapping was performed */
724 /* perform the mapping */
733 drive_map: .space (DRIVE_MAP_SIZE + 1) * 2
740 * chain_stage1(segment, offset, part_table_addr)
742 * This starts another stage1 loader, at segment:offset.
746 /* no need to save anything, just use %esp */
748 /* store %ESI, presuming %ES is 0 */
751 /* store new offset */
755 /* store new segment */
759 /* set up to pass boot drive */
760 movb EXT_C(boot_drive), %dl
762 call EXT_C(prot_to_real)
765 #ifdef ABSOLUTE_WITHOUT_ASTERISK
766 DATA32 ADDR32 ljmp (offset)
768 DATA32 ADDR32 ljmp *(offset)
771 #endif /* STAGE1_5 */
776 * chain_stage2(segment, offset, second_sector)
778 * This starts another stage2 loader, at segment:offset. It presumes
779 * that the other one starts with this same "asm.S" file, and passes
780 * parameters by writing the embedded install variables.
784 /* no need to save anything, just use %esp */
786 /* store new offset */
791 /* store new segment */
796 /* generate linear address */
799 /* set up to pass the partition where stage2 is located in */
800 movl EXT_C(current_partition), %eax
801 movl %eax, (EXT_C(install_partition)-EXT_C(main))(%ebx)
803 /* set up to pass the drive where stage2 is located in */
804 movb EXT_C(current_drive), %dl
806 /* set up to pass the second sector of stage2 */
809 call EXT_C(prot_to_real)
814 #ifdef ABSOLUTE_WITHOUT_ASTERISK
815 DATA32 ADDR32 ljmp (offset)
817 DATA32 ADDR32 ljmp *(offset)
821 #endif /* STAGE1_5 */
824 * These next two routines, "real_to_prot" and "prot_to_real" are structured
825 * in a very specific way. Be very careful when changing them.
827 * NOTE: Use of either one messes up %eax and %ebp.
834 /* load the GDT register */
835 DATA32 ADDR32 lgdt gdtdesc
837 /* turn on protected mode */
842 /* jump to relocation, flush prefetch queue, and reload %cs */
843 DATA32 ljmp $PROT_MODE_CSEG, $protcseg
846 * The ".code32" directive only works in GAS, the GNU assembler!
847 * This gets out of "16-bit" mode.
852 /* reload other segment registers */
853 movw $PROT_MODE_DSEG, %ax
860 /* put the return address in a known safe location */
864 /* get protected mode stack */
869 /* get return address onto the right stack */
876 /* return on the old (or initialized) stack! */
881 /* just in case, set GDT */
884 /* save the protected mode stack */
888 /* get the return address */
892 /* set up new stack */
897 /* set up segment limits */
898 movw $PSEUDO_RM_DSEG, %ax
905 /* this might be an extra step */
906 ljmp $PSEUDO_RM_CSEG, $tmpcseg /* jump to a 16 bit segment */
911 /* clear the PE bit of CR0 */
913 andl $CR0_PE_OFF, %eax
916 /* flush prefetch queue, reload %cs */
917 DATA32 ljmp $0, $realcseg
920 /* we are in real mode now
921 * set up the real mode segment registers : DS, SS, ES
932 /* restore interrupts */
935 /* return on new stack! */
942 * int biosdisk_int13_extensions (int ax, int drive, void *dap)
944 * Call IBM/MS INT13 Extensions (int 13 %ax=AX) for DRIVE. DAP
945 * is passed for disk address packet. If an error occurs, return
946 * non-zero, otherwise zero.
949 ENTRY(biosdisk_int13_extensions)
956 /* compute the address of disk_address_packet */
957 movl 0x10(%ebp), %eax
961 movw %ax, %cx /* save the segment to cx */
967 /* enter real mode */
968 call EXT_C(prot_to_real)
973 int $0x13 /* do the operation */
974 movb %ah, %dl /* save return value */
975 /* clear the data segment */
978 /* back to protected mode */
979 DATA32 call EXT_C(real_to_prot)
982 movb %dl, %al /* return value in %eax */
991 * int biosdisk_standard (int ah, int drive, int coff, int hoff, int soff,
992 * int nsec, int segment)
994 * Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write
995 * NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs,
996 * return non-zero, otherwise zero.
999 ENTRY(biosdisk_standard)
1007 /* set up CHS information */
1008 movl 0x10(%ebp), %eax
1010 movb 0x18(%ebp), %al
1014 movb 0x14(%ebp), %dh
1018 movw 0x20(%ebp), %bx
1019 /* save nsec and ah to %di */
1021 movb 0x1c(%ebp), %al
1023 /* enter real mode */
1024 call EXT_C(prot_to_real)
1029 movw $3, %si /* attempt at least three times */
1033 int $0x13 /* do the operation */
1034 jnc 2f /* check if successful */
1036 movb %ah, %bl /* save return value */
1037 /* if fail, reset the disk system */
1047 /* back to protected mode */
1048 DATA32 call EXT_C(real_to_prot)
1051 movb %bl, %al /* return value in %eax */
1062 * int check_int13_extensions (int drive)
1064 * Check if LBA is supported for DRIVE. If it is supported, then return
1065 * the major version of extensions, otherwise zero.
1068 ENTRY(check_int13_extensions)
1076 /* enter real mode */
1077 call EXT_C(prot_to_real)
1082 int $0x13 /* do the operation */
1084 /* check the result */
1089 movb %ah, %bl /* save the major version into %bl */
1091 /* check if AH=0x42 is supported if FORCE_LBA is zero */
1092 movb EXT_C(force_lba), %al
1101 /* back to protected mode */
1102 DATA32 call EXT_C(real_to_prot)
1105 movb %bl, %al /* return value in %eax */
1114 * int get_diskinfo_standard (int drive, unsigned long *cylinders,
1115 * unsigned long *heads, unsigned long *sectors)
1117 * Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
1118 * error occurs, then return non-zero, otherwise zero.
1121 ENTRY(get_diskinfo_standard)
1130 /* enter real mode */
1131 call EXT_C(prot_to_real)
1135 int $0x13 /* do the operation */
1136 /* check if successful */
1139 /* bogus BIOSes may not return an error number */
1140 testb $0x3f, %cl /* 0 sectors means no disk */
1141 jnz 1f /* if non-zero, then succeed */
1142 /* XXX 0x60 is one of the unused error numbers */
1145 movb %ah, %bl /* save return value in %bl */
1146 /* back to protected mode */
1147 DATA32 call EXT_C(real_to_prot)
1151 leal 0x8(%esp), %ebp
1155 incl %eax /* the number of heads is counted from zero */
1156 movl 0x10(%ebp), %edi
1163 movl 0x14(%ebp), %edi
1170 incl %eax /* the number of cylinders is
1171 counted from zero */
1172 movl 0xc(%ebp), %edi
1176 movb %bl, %al /* return value in %eax */
1187 * int get_diskinfo_floppy (int drive, unsigned long *cylinders,
1188 * unsigned long *heads, unsigned long *sectors)
1190 * Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
1191 * error occurs, then return non-zero, otherwise zero.
1194 ENTRY(get_diskinfo_floppy)
1203 /* enter real mode */
1204 call EXT_C(prot_to_real)
1207 /* init probe value */
1208 movl $probe_values-1, %esi
1211 int $0x13 /* reset floppy controller */
1215 cmpb $0, %cl /* probe failed if zero */
1219 movw $SCRATCHSEG, %ax
1227 /* FIXME: Read from floppy may fail even if the geometry is correct.
1228 So should retry at least three times. */
1229 jc 1b /* next value */
1235 .byte 36, 18, 15, 9, 0
1238 /* back to protected mode */
1239 DATA32 call EXT_C(real_to_prot)
1243 leal 0x8(%esp), %ebp
1246 movl 0xc(%ebp), %eax
1250 movl 0x10(%ebp), %eax
1254 movl 0x14(%ebp), %eax
1258 /* return value in %eax */
1262 incl %eax /* %eax = 1 (non-zero) */
1272 /* Source files are splitted, as they have different copyrights. */
1274 # include "setjmp.S"
1276 #endif /* ! STAGE1_5 */
1281 /* get_code_end() : return the address of the end of the code
1282 * This is here so that it can be replaced by asmstub.c.
1285 /* will be the end of the bss */
1286 # if defined(HAVE_END_SYMBOL)
1288 # elif defined(HAVE_USCORE_END_SYMBOL)
1291 shrl $2, %eax /* Round up to the next word. */
1295 #endif /* ! STAGE1_5 */
1299 * get_memsize(i) : return the memory size in KB. i == 0 for conventional
1300 * memory, i == 1 for extended memory
1301 * BIOS call "INT 12H" to get conventional memory size
1302 * BIOS call "INT 15H, AH=88H" to get extended memory size
1303 * Both have the return value in AX.
1313 call EXT_C(prot_to_real) /* enter real mode */
1329 DATA32 call EXT_C(real_to_prot)
1342 * get_eisamemsize() : return packed EISA memory map, lower 16 bits is
1343 * memory between 1M and 16M in 1K parts, upper 16 bits is
1344 * memory above 16M in 64K parts. If error, return -1.
1345 * BIOS call "INT 15H, AH=E801H" to get EISA memory map,
1346 * AX = memory between 1M and 16M in 1K parts.
1347 * BX = memory above 16M in 64K parts.
1351 ENTRY(get_eisamemsize)
1355 call EXT_C(prot_to_real) /* enter real mode */
1364 DATA32 call EXT_C(real_to_prot)
1367 movl $0xFFFFFFFF, %eax
1380 * get_mmap_entry(addr, cont) : address and old continuation value (zero to
1381 * start), for the Query System Address Map BIOS call.
1383 * Sets the first 4-byte int value of "addr" to the size returned by
1384 * the call. If the call fails, sets it to zero.
1386 * Returns: new (non-zero) continuation value, 0 if done.
1388 * NOTE: Currently hard-coded for a maximum buffer length of 1024.
1391 ENTRY(get_mmap_entry)
1397 /* place address (+4) in ES:DI */
1398 movl 0x14(%esp), %eax
1405 /* set continuation value */
1406 movl 0x18(%esp), %ebx
1408 /* set default maximum buffer size */
1411 /* set EDX to 'SMAP' */
1412 movl $0x534d4150, %edx
1414 call EXT_C(prot_to_real) /* enter real mode */
1423 cmpl $0x534d4150, %eax
1438 DATA32 call EXT_C(real_to_prot)
1441 /* write length of buffer (zero if error) into "addr" */
1442 movl 0x14(%esp), %eax
1445 /* set return value to continuation */
1455 * get_rom_config_table()
1457 * Get the linear address of a ROM configuration table. Return zero,
1461 ENTRY(get_rom_config_table)
1465 /* zero %ebx for simplicity */
1468 call EXT_C(prot_to_real)
1486 DATA32 call EXT_C(real_to_prot)
1489 /* compute the linear address */
1500 * int get_vbe_controller_info (struct vbe_controller *controller_ptr)
1502 * Get VBE controller information.
1505 ENTRY(get_vbe_controller_info)
1512 /* Convert the linear address to segment:offset */
1515 andl $0x0000000f, %edi
1519 call EXT_C(prot_to_real)
1527 DATA32 call EXT_C(real_to_prot)
1539 * int get_vbe_mode_info (int mode_number, struct vbe_mode *mode_ptr)
1541 * Get VBE mode information.
1544 ENTRY(get_vbe_mode_info)
1551 /* Convert the linear address to segment:offset */
1552 movl 0xc(%ebp), %eax
1554 andl $0x0000000f, %edi
1558 /* Save the mode number in %cx */
1559 movl 0x8(%ebp), %ecx
1561 call EXT_C(prot_to_real)
1569 DATA32 call EXT_C(real_to_prot)
1581 * int set_vbe_mode (int mode_number)
1583 * Set VBE mode. Don't support user-specified CRTC information.
1592 /* Save the mode number in %bx */
1593 movl 0x8(%ebp), %ebx
1597 call EXT_C(prot_to_real)
1604 DATA32 call EXT_C(real_to_prot)
1615 * gateA20(int linear)
1617 * Gate address-line 20 for high memory.
1619 * This routine is probably overconservative in what it does, but so what?
1621 * It also eats any keystrokes in the keyboard buffer. :-(
1625 /* first, try a BIOS call */
1629 call EXT_C(prot_to_real)
1640 /* set non-zero if failed */
1643 /* save the status */
1646 DATA32 call EXT_C(real_to_prot)
1654 3: /* use keyboard controller */
1659 movb $KC_CMD_WOUT, %al
1664 andb $K_IBUF_FUL, %al
1667 movb $KB_OUTPUT_MASK, %al
1671 orb $KB_A20_ENABLE, %al
1677 /* output a dummy command (USB keyboard hack) */
1687 andb $K_IBUF_FUL, %al
1692 andb $K_OBUF_FUL, %al
1701 ENTRY(patch_code) /* labels start with "pc_" */
1713 ENTRY(patch_code_end)
1721 * Does some funky things (including on the stack!), then jumps to the
1722 * entry point of the Linux setup code.
1725 VARIABLE(linux_text_len)
1728 VARIABLE(linux_data_tmp_addr)
1731 VARIABLE(linux_data_real_addr)
1735 /* don't worry about saving anything, we're committed at this point */
1736 cld /* forward copying */
1739 movl EXT_C(linux_text_len), %ecx
1742 movl $LINUX_BZIMAGE_ADDR, %esi
1743 movl $LINUX_ZIMAGE_ADDR, %edi
1748 ENTRY(big_linux_boot)
1749 movl EXT_C(linux_data_real_addr), %ebx
1751 /* copy the real mode part */
1752 movl EXT_C(linux_data_tmp_addr), %esi
1754 movl $LINUX_SETUP_MOVE_SIZE, %ecx
1759 /* change %ebx to the segment address */
1763 movl %eax, linux_setup_seg
1765 /* XXX new stack pointer in safe area for calling functions */
1767 call EXT_C(stop_floppy)
1769 /* final setup for linux boot */
1771 call EXT_C(prot_to_real)
1774 /* final setup for linux boot */
1777 movw $LINUX_SETUP_STACK, %sp
1794 * multi_boot(int start, int mb_info)
1796 * This starts a kernel in the manner expected of the multiboot standard.
1800 /* no need to save anything */
1801 call EXT_C(stop_floppy)
1803 movl $0x2BADB002, %eax
1804 movl 0x8(%esp), %ebx
1806 /* boot kernel here (absolute address call) */
1812 #endif /* ! STAGE1_5 */
1815 * void console_putchar (int c)
1817 * Put the character C on the console. Because GRUB wants to write a
1818 * character with an attribute, this implementation is a bit tricky.
1819 * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh
1820 * (TELETYPE OUTPUT). Otherwise, save the original position, put a space,
1821 * save the current position, restore the original position, write the
1822 * character and the attribute, and restore the current position.
1824 * The reason why this is so complicated is that there is no easy way to
1825 * get the height of the screen, and the TELETYPE OUPUT BIOS call doesn't
1826 * support setting a background attribute.
1828 ENTRY(console_putchar)
1829 movl 0x4(%esp), %edx
1834 movl EXT_C(console_current_color), %ebx
1837 call EXT_C(prot_to_real)
1843 /* use teletype output if control character */
1853 /* save the character and the attribute on the stack */
1857 /* get the current position */
1861 /* check the column with the width */
1865 /* print CR and LF, if next write will exceed the width */
1871 /* get the current position */
1876 /* restore the character and the attribute */
1880 /* write the character with the attribute */
1885 /* move the cursor forward */
1891 #endif /* ! STAGE1_5 */
1896 3: DATA32 call EXT_C(real_to_prot)
1905 /* this table is used in translate_keycode below */
1914 .word KEY_BACKSPACE, 8
1920 * translate_keycode translates the key code %dx to an ascii code.
1928 movw $ABS(translation_table), %si
1931 /* check if this is the end */
1934 /* load the ascii code into %ax */
1937 /* check if this matches the key code */
1940 /* translate %dx, if successful */
1951 * remap_ascii_char remaps the ascii code %dl to another if the code is
1952 * contained in ASCII_KEY_MAP.
1959 movw $ABS(EXT_C(ascii_key_map)), %si
1962 /* check if this is the end */
1965 /* check if this matches the ascii code */
1968 /* if so, perform the mapping */
1979 ENTRY(ascii_key_map)
1980 .space (KEY_MAP_SIZE + 1) * 2
1984 * int console_getkey (void)
1985 * BIOS call "INT 16H Function 00H" to read character from keyboard
1986 * Call with %ah = 0x0
1987 * Return: %ah = keyboard scan code
1988 * %al = ASCII character
1991 ENTRY(console_getkey)
1994 call EXT_C(prot_to_real)
1999 movw %ax, %dx /* real_to_prot uses %eax */
2000 call translate_keycode
2001 call remap_ascii_char
2003 DATA32 call EXT_C(real_to_prot)
2013 * int console_checkkey (void)
2014 * if there is a character pending, return it; otherwise return -1
2015 * BIOS call "INT 16H Function 01H" to check whether a character is pending
2016 * Call with %ah = 0x1
2018 * If key waiting to be input:
2019 * %ah = keyboard scan code
2020 * %al = ASCII character
2025 ENTRY(console_checkkey)
2029 call EXT_C(prot_to_real) /* enter real mode */
2035 DATA32 jz notpending
2038 call translate_keycode
2039 call remap_ascii_char
2043 movl $0xFFFFFFFF, %edx
2046 DATA32 call EXT_C(real_to_prot)
2056 * int console_getxy (void)
2057 * BIOS call "INT 10H Function 03h" to get cursor position
2058 * Call with %ah = 0x03
2060 * Returns %ch = starting scan line
2061 * %cl = ending scan line
2062 * %dh = row (0 is top)
2063 * %dl = column (0 is left)
2067 ENTRY(console_getxy)
2069 push %ebx /* save EBX */
2071 call EXT_C(prot_to_real)
2074 xorb %bh, %bh /* set page to 0 */
2076 int $0x10 /* get cursor position */
2078 DATA32 call EXT_C(real_to_prot)
2090 * void console_gotoxy(int x, int y)
2091 * BIOS call "INT 10H Function 02h" to set cursor position
2092 * Call with %ah = 0x02
2094 * %dh = row (0 is top)
2095 * %dl = column (0 is left)
2099 ENTRY(console_gotoxy)
2101 push %ebx /* save EBX */
2103 movb 0xc(%esp), %dl /* %dl = x */
2104 movb 0x10(%esp), %dh /* %dh = y */
2106 call EXT_C(prot_to_real)
2109 xorb %bh, %bh /* set page to 0 */
2111 int $0x10 /* set cursor position */
2113 DATA32 call EXT_C(real_to_prot)
2122 * void console_cls (void)
2123 * BIOS call "INT 10H Function 09h" to write character and attribute
2124 * Call with %ah = 0x09
2126 * %bh = (page number)
2128 * %cx = (number of times)
2134 push %ebx /* save EBX */
2136 call EXT_C(prot_to_real)
2139 /* move the cursor to the beginning */
2145 /* write spaces to the entire screen */
2148 movw $(80 * 25), %cx
2151 /* move back the cursor */
2155 DATA32 call EXT_C(real_to_prot)
2164 * int console_setcursor (int on)
2165 * BIOS call "INT 10H Function 01h" to set cursor type
2166 * Call with %ah = 0x01
2167 * %ch = cursor starting scanline
2168 * %cl = cursor ending scanline
2171 console_cursor_state:
2173 console_cursor_shape:
2176 ENTRY(console_setcursor)
2180 /* check if the standard cursor shape has already been saved */
2181 movw console_cursor_shape, %ax
2185 call EXT_C(prot_to_real)
2192 DATA32 call EXT_C(real_to_prot)
2195 movw %cx, console_cursor_shape
2197 /* set %cx to the designated cursor shape */
2199 movl 0xc(%esp), %ebx
2202 movw console_cursor_shape, %cx
2204 call EXT_C(prot_to_real)
2210 DATA32 call EXT_C(real_to_prot)
2213 movzbl console_cursor_state, %eax
2214 movb %bl, console_cursor_state
2222 * if a seconds value can be read, read it and return it (BCD),
2223 * otherwise return 0xFF
2224 * BIOS call "INT 1AH Function 02H" to check whether a character is pending
2225 * Call with %ah = 0x2
2227 * If RT Clock can give correct values
2229 * %cl = minutes (BCD)
2230 * %dh = seconds (BCD)
2231 * %dl = daylight savings time (00h std, 01h daylight)
2232 * Carry flag = clear
2235 * (this indicates that the clock is updating, or
2236 * that it isn't running)
2241 call EXT_C(prot_to_real) /* enter real mode */
2251 DATA32 call EXT_C(real_to_prot)
2262 * return the real time in ticks, of which there are about
2268 call EXT_C(prot_to_real) /* enter real mode */
2271 /* %ax is already zero */
2274 DATA32 call EXT_C(real_to_prot)
2284 #endif /* STAGE1_5 */
2287 * This is the area for all of the special variables.
2290 .p2align 2 /* force 4-byte alignment */
2295 VARIABLE(boot_drive)
2296 #ifdef SUPPORT_DISKLESS
2302 VARIABLE(install_second_sector)
2305 /* an address can only be long-jumped to if it is in memory, this
2306 is used by multiple routines */
2312 VARIABLE(apm_bios_info)
2313 .word 0 /* version */
2315 .long 0 /* offset */
2316 .word 0 /* cseg_16 */
2317 .word 0 /* dseg_16 */
2318 .word 0 /* cseg_len */
2319 .word 0 /* cseg_16_len */
2320 .word 0 /* dseg_16_len */
2323 * This is the Global Descriptor Table
2325 * An entry, a "Segment Descriptor", looks like this:
2328 * ------------------------------------------------------------
2329 * | | |B| |A| | | |1|0|E|W|A| |
2330 * | BASE 31..24 |G|/|0|V| LIMIT |P|DPL| TYPE | BASE 23:16 |
2331 * | | |D| |L| 19..16| | |1|1|C|R|A| |
2332 * ------------------------------------------------------------
2334 * | BASE 15..0 | LIMIT 15..0 |
2336 * ------------------------------------------------------------
2338 * Note the ordering of the data items is reversed from the above
2342 .p2align 2 /* force 4-byte alignment */
2349 .byte 0, 0x9A, 0xCF, 0
2353 .byte 0, 0x92, 0xCF, 0
2355 /* 16 bit real mode CS */
2359 /* 16 bit real mode DS */
2364 /* this is the GDT descriptor */
2366 .word 0x27 /* limit */
2367 .long gdt /* addr */