📄 asm.s
字号:
/* * int set_vbe_mode (int mode_number) * * Set VBE mode. Don't support user-specified CRTC information. */ENTRY(set_vbe_mode) pushl %ebp movl %esp, %ebp pushl %ebx /* Save the mode number in %bx */ movl 0x8(%ebp), %ebx /* Clear bit D11 */ andl $0xF7FF, %ebx call EXT_C(prot_to_real) .code16 movw $0x4F02, %ax int $0x10 movw %ax, %bx DATA32 call EXT_C(real_to_prot) .code32 movzwl %bx, %eax popl %ebx popl %ebp ret /* * gateA20(int linear) * * Gate address-line 20 for high memory. * * This routine is probably overconservative in what it does, but so what? * * It also eats any keystrokes in the keyboard buffer. :-( */ENTRY(gateA20) /* first, try a BIOS call */ pushl %ebp movl 8(%esp), %edx call EXT_C(prot_to_real) .code16 movw $0x2400, %ax testw %dx, %dx jz 1f incw %ax1: stc int $0x15 jnc 2f /* set non-zero if failed */ movb $1, %ah /* save the status */2: movb %ah, %dl DATA32 call EXT_C(real_to_prot) .code32 popl %ebp testb %dl, %dl jnz 3f ret3: /* use keyboard controller */ pushl %eax call gloop1 movb $KC_CMD_WOUT, %al outb $K_CMDgloopint1: inb $K_STATUS andb $K_IBUF_FUL, %al jnz gloopint1 movb $KB_OUTPUT_MASK, %al cmpb $0, 0x8(%esp) jz gdoit orb $KB_A20_ENABLE, %algdoit: outb $K_RDWR call gloop1 /* output a dummy command (USB keyboard hack) */ movb $0xff, %al outb $K_CMD call gloop1 popl %eax retgloop1: inb $K_STATUS andb $K_IBUF_FUL, %al jnz gloop1gloop2: inb $K_STATUS andb $K_OBUF_FUL, %al jz gloop2ret inb $K_RDWR jmp gloop2gloop2ret: retENTRY(patch_code) /* labels start with "pc_" */ .code16 mov %cs, %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs ADDR32 movl $0, 0pc_stop: hlt DATA32 jmp pc_stopENTRY(patch_code_end) .code32/* * linux_boot() * * Does some funky things (including on the stack!), then jumps to the * entry point of the Linux setup code. */VARIABLE(linux_text_len) .long 0 VARIABLE(linux_data_tmp_addr) .long 0 VARIABLE(linux_data_real_addr) .long 0 ENTRY(linux_boot) /* don't worry about saving anything, we're committed at this point */ cld /* forward copying */ /* copy kernel */ movl EXT_C(linux_text_len), %ecx addl $3, %ecx shrl $2, %ecx movl $LINUX_BZIMAGE_ADDR, %esi movl $LINUX_ZIMAGE_ADDR, %edi rep movslENTRY(big_linux_boot) movl EXT_C(linux_data_real_addr), %ebx /* copy the real mode part */ movl EXT_C(linux_data_tmp_addr), %esi movl %ebx, %edi movl $LINUX_SETUP_MOVE_SIZE, %ecx cld rep movsb /* change %ebx to the segment address */ shrl $4, %ebx movl %ebx, %eax addl $0x20, %eax movl %eax, linux_setup_seg /* XXX new stack pointer in safe area for calling functions */ movl $0x4000, %esp call EXT_C(stop_floppy) /* final setup for linux boot */ call EXT_C(prot_to_real) .code16 /* final setup for linux boot */ cli movw %bx, %ss movw $LINUX_SETUP_STACK, %sp movw %bx, %ds movw %bx, %es movw %bx, %fs movw %bx, %gs /* jump to start */ /* ljmp */ .byte 0xea .word 0linux_setup_seg: .word 0 .code32/* * multi_boot(int start, int mb_info) * * This starts a kernel in the manner expected of the multiboot standard. */ENTRY(multi_boot) /* no need to save anything */ call EXT_C(stop_floppy) movl $0x2BADB002, %eax movl 0x8(%esp), %ebx /* boot kernel here (absolute address call) */ call *0x4(%esp) /* error */ call EXT_C(stop)#endif /* ! STAGE1_5 */ /* * void 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 OUPUT BIOS call doesn't * support setting a background attribute. */ENTRY(console_putchar) movl 0x4(%esp), %edx pusha#ifdef STAGE1_5 movb $0x07, %bl#else movl EXT_C(console_current_color), %ebx#endif call EXT_C(prot_to_real) .code16 movb %dl, %al xorb %bh, %bh#ifndef STAGE1_5 /* 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 3f#endif /* ! STAGE1_5 */ 1: movb $0xe, %ah int $0x10 3: DATA32 call EXT_C(real_to_prot) .code32 popa ret#ifndef STAGE1_5/* this table is used in translate_keycode below */translation_table: .word KEY_LEFT, 2 .word KEY_RIGHT, 6 .word KEY_UP, 16 .word KEY_DOWN, 14 .word KEY_HOME, 1 .word KEY_END, 5 .word KEY_DC, 4 .word KEY_BACKSPACE, 8 .word KEY_PPAGE, 7 .word 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 /* * remap_ascii_char remaps the ascii code %dl to another if the code is * contained in ASCII_KEY_MAP. */ .code16 remap_ascii_char: pushw %si movw $ABS(EXT_C(ascii_key_map)), %si1: lodsw /* check if this is the end */ testw %ax, %ax jz 2f /* check if this matches the ascii code */ cmpb %al, %dl jne 1b /* if so, perform the mapping */ movb %ah, %dl2: /* restore %si */ popw %si ret .code32 .align 4ENTRY(ascii_key_map) .space (KEY_MAP_SIZE + 1) * 2 /* * int 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 */ENTRY(console_getkey) push %ebp call EXT_C(prot_to_real) .code16 int $0x16 movw %ax, %dx /* real_to_prot uses %eax */ call translate_keycode call remap_ascii_char DATA32 call EXT_C(real_to_prot) .code32 movw %dx, %ax pop %ebp ret/* * int 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 */ENTRY(console_checkkey) push %ebp xorl %edx, %edx call EXT_C(prot_to_real) /* enter real mode */ .code16 movb $0x1, %ah int $0x16 DATA32 jz notpending movw %ax, %dx call translate_keycode call remap_ascii_char DATA32 jmp pendingnotpending: movl $0xFFFFFFFF, %edxpending: DATA32 call EXT_C(real_to_prot) .code32 mov %edx, %eax pop %ebp ret /* * int 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) */ENTRY(console_getxy) push %ebp push %ebx /* save EBX */ call EXT_C(prot_to_real) .code16 xorb %bh, %bh /* set page to 0 */ movb $0x3, %ah int $0x10 /* get cursor position */ DATA32 call EXT_C(real_to_prot) .code32 movb %dl, %ah movb %dh, %al pop %ebx pop %ebp ret/* * void console_gotoxy(int x, int 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) */ENTRY(console_gotoxy) push %ebp push %ebx /* save EBX */ movb 0xc(%esp), %dl /* %dl = x */ movb 0x10(%esp), %dh /* %dh = y */ call EXT_C(prot_to_real) .code16 xorb %bh, %bh /* set page to 0 */ movb $0x2, %ah int $0x10 /* set cursor position */ DATA32 call EXT_C(real_to_prot) .code32 pop %ebx pop %ebp ret /* * void 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) */ENTRY(console_cls) push %ebp push %ebx /* save EBX */ call EXT_C(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 EXT_C(real_to_prot) .code32 pop %ebx pop %ebp ret /* * int 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 1console_cursor_shape: .word 0 ENTRY(console_setcursor) push %ebp push %ebx /* check if the standard cursor shape has already been saved */ movw console_cursor_shape, %ax testw %ax, %ax jne 1f call EXT_C(prot_to_real) .code16 movb $0x03, %ah xorb %bh, %bh int $0x10 DATA32 call EXT_C(real_to_prot) .code32 movw %cx, console_cursor_shape1: /* set %cx to the designated cursor shape */ movw $0x2000, %cx movl 0xc(%esp), %ebx testl %ebx, %ebx jz 2f movw console_cursor_shape, %cx2: call EXT_C(prot_to_real) .code16 movb $0x1, %ah int $0x10 DATA32 call EXT_C(real_to_prot) .code32 movzbl console_cursor_state, %eax movb %bl, console_cursor_state pop %ebx pop %ebp ret /* * getrtsecs() * if a seconds value can be read, read it and return it (BCD), * otherwise return 0xFF * BIOS call "INT 1AH Function 02H" to check whether a character is pending * Call with %ah = 0x2 * Return: * If RT Clock can give correct values * %ch = hour (BCD) * %cl = minutes (BCD) * %dh = seconds (BCD) * %dl = daylight savings time (00h std, 01h daylight) * Carry flag = clear * else * Carry flag = set * (this indicates that the clock is updating, or * that it isn't running) */ENTRY(getrtsecs) push %ebp call EXT_C(prot_to_real) /* enter real mode */ .code16 movb $0x2, %ah int $0x1a DATA32 jnc gottime movb $0xff, %dhgottime: DATA32 call EXT_C(real_to_prot) .code32 movb %dh, %al pop %ebp ret /* * currticks() * return the real time in ticks, of which there are about * 18-20 per second */ENTRY(currticks) pushl %ebp call EXT_C(prot_to_real) /* enter real mode */ .code16 /* %ax is already zero */ int $0x1a DATA32 call EXT_C(real_to_prot) .code32 movl %ecx, %eax shll $16, %eax movw %dx, %ax popl %ebp ret#endif /* STAGE1_5 *//* * This is the area for all of the special variables. */ .p2align 2 /* force 4-byte alignment */protstack: .long PROTSTACKINITVARIABLE(boot_drive)#ifdef SUPPORT_DISKLESS .long NETWORK_DRIVE#else .long 0#endifVARIABLE(install_second_sector) .long 0 /* an address can only be long-jumped to if it is in memory, this is used by multiple routines */offset: .long 0x8000segment: .word 0VARIABLE(apm_bios_info) .word 0 /* version */ .word 0 /* cseg */ .long 0 /* offset */ .word 0 /* cseg_16 */ .word 0 /* dseg_16 */ .word 0 /* cseg_len */ .word 0 /* cseg_16_len */ .word 0 /* dseg_16_len */ /* * This is the Global Descriptor Table * * An entry, a "Segment Descriptor", looks like this: * * 31 24 19 16 7 0 * ------------------------------------------------------------ * | | |B| |A| | | |1|0|E|W|A| | * | BASE 31..24 |G|/|0|V| LIMIT |P|DPL| TYPE | BASE 23:16 | * | | |D| |L| 19..16| | |1|1|C|R|A| | * ------------------------------------------------------------ * | | | * | BASE 15..0 | LIMIT 15..0 | * | | | * ------------------------------------------------------------ * * Note the ordering of the data items is reversed from the above * description. */ .p2align 2 /* force 4-byte alignment */gdt: .word 0, 0 .byte 0, 0, 0, 0 /* code segment */ .word 0xFFFF, 0 .byte 0, 0x9A, 0xCF, 0 /* data segment */ .word 0xFFFF, 0 .byte 0, 0x92, 0xCF, 0 /* 16 bit real mode CS */ .word 0xFFFF, 0 .byte 0, 0x9E, 0, 0 /* 16 bit real mode DS */ .word 0xFFFF, 0 .byte 0, 0x92, 0, 0/* this is the GDT descriptor */gdtdesc: .word 0x27 /* limit */ .long gdt /* addr */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -