📄 startup.s
字号:
VARIABLE(grub_linux_tmp_addr) .long 0VARIABLE(grub_linux_real_addr) .long 0 FUNCTION(grub_linux_boot_zimage) /* copy the kernel */ movl EXT_C(grub_linux_prot_size), %ecx addl $3, %ecx shrl $2, %ecx movl $GRUB_LINUX_BZIMAGE_ADDR, %esi movl $GRUB_LINUX_ZIMAGE_ADDR, %edi cld rep movslFUNCTION(grub_linux_boot_bzimage) call EXT_C(grub_dl_unload_all) movl EXT_C(grub_linux_real_addr), %ebx /* copy the real mode code */ movl EXT_C(grub_linux_tmp_addr), %esi movl %ebx, %edi movl $GRUB_LINUX_SETUP_MOVE_SIZE, %ecx cld rep movsb /* change %ebx to the segment address */ shrl $4, %ebx movl %ebx, %eax addl $0x20, %eax movw %ax, linux_setup_seg /* XXX new stack pointer in safe area for calling functions */ movl $0x4000, %esp call EXT_C(grub_stop_floppy) /* final setup for linux boot */ call prot_to_real .code16 cli movw %bx, %ss movw $GRUB_LINUX_SETUP_STACK, %sp movw %bx, %ds movw %bx, %es movw %bx, %fs movw %bx, %gs /* ljmp */ .byte 0xea .word 0linux_setup_seg: .word 0 .code32 /* * This starts the multiboot kernel. */FUNCTION(grub_multiboot_real_boot) /* Push the entry address on the stack. */ pushl %eax /* Move the address of the multiboot information structure to ebx. */ movl %edx,%ebx /* Unload all modules and stop the floppy driver. */ call EXT_C(grub_dl_unload_all) call EXT_C(grub_stop_floppy) /* Interrupts should be disabled. */ cli /* Move the magic value into eax and jump to the kernel. */ movl $GRUB_MB_MAGIC2,%eax popl %ecx jmp *%ecx /* * int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap) * * Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP * is passed for disk address packet. If an error occurs, return * non-zero, otherwise zero. */FUNCTION(grub_biosdisk_rw_int13_extensions) pushl %ebp pushl %esi /* compute the address of disk_address_packet */ movw %cx, %si xorw %cx, %cx shrl $4, %ecx /* save the segment to cx */ /* ah */ movb %al, %dh /* enter real mode */ call prot_to_real .code16 movb %dh, %ah movw %cx, %ds int $0x13 /* do the operation */ movb %ah, %dl /* save return value */ /* clear the data segment */ xorw %ax, %ax movw %ax, %ds /* back to protected mode */ DATA32 call real_to_prot .code32 movb %dl, %al /* return value in %eax */ popl %esi popl %ebp ret /* * int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff, * int soff, int nsec, int segment) * * Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write * NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs, * return non-zero, otherwise zero. */FUNCTION(grub_biosdisk_rw_standard) pushl %ebp movl %esp, %ebp pushl %ebx pushl %edi pushl %esi /* set up CHS information */ /* set %ch to low eight bits of cylinder */ xchgb %cl, %ch /* set bits 6-7 of %cl to high two bits of cylinder */ shlb $6, %cl /* set bits 0-5 of %cl to sector */ addb 0xc(%ebp), %cl /* set %dh to head */ movb 0x8(%ebp), %dh /* set %ah to AH */ movb %al, %ah /* set %al to NSEC */ movb 0x10(%ebp), %al /* save %ax in %di */ movw %ax, %di /* save SEGMENT in %bx */ movw 0x14(%ebp), %bx /* enter real mode */ call prot_to_real .code16 movw %bx, %es xorw %bx, %bx movw $3, %si /* attempt at least three times */1: movw %di, %ax int $0x13 /* do the operation */ jnc 2f /* check if successful */ movb %ah, %bl /* save return value */ /* if fail, reset the disk system */ xorw %ax, %ax int $0x13 decw %si cmpw $0, %si je 2f xorb %bl, %bl jmp 1b /* retry */2: /* back to protected mode */ DATA32 call real_to_prot .code32 movb %bl, %al /* return value in %eax */ popl %esi popl %edi popl %ebx popl %ebp ret $(4 * 4)/* * int grub_biosdisk_check_int13_extensions (int drive) * * Check if LBA is supported for DRIVE. If it is supported, then return * the major version of extensions, otherwise zero. */FUNCTION(grub_biosdisk_check_int13_extensions) pushl %ebp pushl %ebx /* drive */ movb %al, %dl /* enter real mode */ call prot_to_real .code16 movb $0x41, %ah movw $0x55aa, %bx int $0x13 /* do the operation */ /* check the result */ jc 1f cmpw $0xaa55, %bx jne 1f movb %ah, %bl /* save the major version into %bl */ /* check if AH=0x42 is supported */ andw $1, %cx jnz 2f 1: xorb %bl, %bl2: /* back to protected mode */ DATA32 call real_to_prot .code32 movb %bl, %al /* return value in %eax */ popl %ebx popl %ebp ret/* * int grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp) * * Return the geometry of DRIVE in a drive parameters, DRP. If an error * occurs, then return non-zero, otherwise zero. */FUNCTION(grub_biosdisk_get_diskinfo_int13_extensions) pushl %ebp pushl %ebx pushl %esi /* compute the address of drive parameters */ movw %dx, %si xorw %dx, %dx shrl $4, %edx movw %dx, %bx /* save the segment into %bx */ /* drive */ movb %al, %dl /* enter real mode */ call prot_to_real .code16 movb $0x48, %ah movw %bx, %ds int $0x13 /* do the operation */ movb %ah, %bl /* save return value in %bl */ /* clear the data segment */ xorw %ax, %ax movw %ax, %ds /* back to protected mode */ DATA32 call real_to_prot .code32 movb %bl, %al /* return value in %eax */ popl %esi popl %ebx popl %ebp ret/* * int grub_biosdisk_get_diskinfo_standard (int drive, * unsigned long *cylinders, * unsigned long *heads, * unsigned long *sectors) * * Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an * error occurs, then return non-zero, otherwise zero. */FUNCTION(grub_biosdisk_get_diskinfo_standard) pushl %ebp pushl %ebx pushl %edi /* push CYLINDERS */ pushl %edx /* push HEADS */ pushl %ecx /* SECTORS is on the stack */ /* drive */ movb %al, %dl /* enter real mode */ call prot_to_real .code16 movb $0x8, %ah int $0x13 /* do the operation */ /* check if successful */ testb %ah, %ah jnz 1f /* bogus BIOSes may not return an error number */ testb $0x3f, %cl /* 0 sectors means no disk */ jnz 1f /* if non-zero, then succeed */ /* XXX 0x60 is one of the unused error numbers */ movb $0x60, %ah1: movb %ah, %bl /* save return value in %bl */ /* back to protected mode */ DATA32 call real_to_prot .code32 /* pop HEADS */ popl %edi movb %dh, %al incl %eax /* the number of heads is counted from zero */ movl %eax, (%edi) /* pop CYLINDERS */ popl %edi movb %ch, %al movb %cl, %ah shrb $6, %ah /* the number of cylinders is counted from zero */ incl %eax movl %eax, (%edi) /* SECTORS */ movl 0x10(%esp), %edi andb $0x3f, %cl movzbl %cl, %eax movl %eax, (%edi) xorl %eax, %eax movb %bl, %al /* return value in %eax */ popl %edi popl %ebx popl %ebp ret $4/* * int grub_biosdisk_get_num_floppies (void) */FUNCTION(grub_biosdisk_get_num_floppies) pushl %ebp xorl %edx, %edx call prot_to_real .code16 /* reset the disk system first */ int $0x131: stc /* call GET DISK TYPE */ movb $0x15, %ah int $0x13 jc 2f /* check if this drive exists */ testb $0x3, %ah jz 2f incb %dl cmpb $2, %dl jne 1b2: DATA32 call real_to_prot .code32 movl %edx, %eax popl %ebp ret /* * * grub_get_memsize(i) : return the memory size in KB. i == 0 for conventional * memory, i == 1 for extended memory * BIOS call "INT 12H" to get conventional memory size * BIOS call "INT 15H, AH=88H" to get extended memory size * Both have the return value in AX. * */FUNCTION(grub_get_memsize) pushl %ebp movl %eax, %edx call prot_to_real /* enter real mode */ .code16 testl %edx, %edx jnz xext int $0x12 jmp xdonexext: movb $0x88, %ah int $0x15xdone: movw %ax, %dx DATA32 call real_to_prot .code32 movw %dx, %ax popl %ebp ret/* * * grub_get_eisa_mmap() : return packed EISA memory map, lower 16 bits is * memory between 1M and 16M in 1K parts, upper 16 bits is * memory above 16M in 64K parts. If error, return zero. * BIOS call "INT 15H, AH=E801H" to get EISA memory map, * AX = memory between 1M and 16M in 1K parts. * BX = memory above 16M in 64K parts. * */FUNCTION(grub_get_eisa_mmap) pushl %ebp pushl %ebx call prot_to_real /* enter real mode */ .code16 movw $0xe801, %ax int $0x15 shll $16, %ebx movw %ax, %bx DATA32 call real_to_prot .code32 cmpb $0x86, %bh je xnoteisa movl %ebx, %eaxxnoteisa: popl %ebx popl %ebp ret/* * * grub_get_mmap_entry(addr, cont) : address and old continuation value (zero to * start), for the Query System Address Map BIOS call. * * Sets the first 4-byte int value of "addr" to the size returned by * the call. If the call fails, sets it to zero. * * Returns: new (non-zero) continuation value, 0 if done. */FUNCTION(grub_get_mmap_entry) pushl %ebp pushl %ebx pushl %edi pushl %esi /* push ADDR */ pushl %eax /* place address (+4) in ES:DI */ addl $4, %eax movl %eax, %edi andl $0xf, %edi shrl $4, %eax movl %eax, %esi /* set continuation value */ movl %edx, %ebx /* set default maximum buffer size */ movl $0x14, %ecx /* set EDX to 'SMAP' */ movl $0x534d4150, %edx call prot_to_real /* enter real mode */ .code16 movw %si, %es movl $0xe820, %eax int $0x15 DATA32 jc xnosmap cmpl $0x534d4150, %eax jne xnosmap cmpl $0x14, %ecx jl xnosmap cmpl $0x400, %ecx jg xnosmap jmp xsmapxnosmap: xorl %ecx, %ecxxsmap: DATA32 call real_to_prot .code32 /* write length of buffer (zero if error) into ADDR */ popl %eax movl %ecx, (%eax) /* set return value to continuation */ movl %ebx, %eax popl %esi popl %edi popl %ebx popl %ebp ret /* * void grub_console_real_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 OUPUT BIOS call doesn't * support setting a background attribute. */FUNCTION(grub_console_real_putchar) movl %eax, %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 $0x102: /* 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 3f1: movw $1, %bx movb $0xe, %ah int $0x10 3: DATA32 call real_to_prot .code32 popa ret /* * int grub_console_getkey (void) * BIOS call "INT 16H Function 00H" to read character from keyboard * Call with %ah = 0x0 * Return: %ah = keyboard scan code * %al = ASCII character *//* this table is used in translate_keycode below */translation_table: .word GRUB_CONSOLE_KEY_LEFT, 2 .word GRUB_CONSOLE_KEY_RIGHT, 6 .word GRUB_CONSOLE_KEY_UP, 16 .word GRUB_CONSOLE_KEY_DOWN, 14 .word GRUB_CONSOLE_KEY_HOME, 1 .word GRUB_CONSOLE_KEY_END, 5 .word GRUB_CONSOLE_KEY_DC, 4 .word GRUB_CONSOLE_KEY_BACKSPACE, 8 .word GRUB_CONSOLE_KEY_PPAGE, 7 .word GRUB_CONSOLE_KEY_NPAGE, 3 .word 0 /* * translate_keycode translates the key code %dx to an ascii code. */ .code16translate_keycode: pushw %bx pushw %si movw $ABS(translation_table), %si 1: lodsw /* check if this is the end */ testw %ax, %ax jz 2f /* load the ascii code into %ax */ movw %ax, %bx lodsw /* check if this matches the key code */ cmpw %bx, %dx jne 1b /* translate %dx, if successful */ movw %ax, %dx2: popw %si popw %bx ret .code32 FUNCTION(grub_console_getkey) pushl %ebp call prot_to_real .code16 int $0x16 movw %ax, %dx /* real_to_prot uses %eax */ call translate_keycode DATA32 call real_to_prot .code32 movw %dx, %ax popl %ebp ret/* * int grub_console_checkkey (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 */FUNCTION(grub_console_checkkey) pushl %ebp xorl %edx, %edx
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -