📄 memdisk16.asm
字号:
;; -*- fundamental -*-;; $Id$;; -----------------------------------------------------------------------;; ;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved;;;; 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, Inc., 53 Temple Place Ste 330,;; Boston MA 02111-1307, USA; either version 2 of the License, or;; (at your option) any later version; incorporated herein by reference.;;;; -----------------------------------------------------------------------;;;; init16.asm;;;; Routine to initialize and to trampoline into 32-bit;; protected memory. This code is derived from bcopy32.inc and;; com32.inc in the main SYSLINUX distribution.;;MY_CS equ 0x0800 ; Segment address to useCS_BASE equ (MY_CS << 4) ; Corresponding address; Low memory bounce bufferBOUNCE_SEG equ (MY_CS+0x1000)%define DO_WBINVD 0%define STACK_HEAP_SIZE (128*1024) section .rodata align=16 section .data align=16 section .bss align=16;; -----------------------------------------------------------------------;; Kernel image header;; ----------------------------------------------------------------------- section .text ; Must be first in image bits 16cmdline times 497 db 0 ; We put the command line heresetup_sects db 0root_flags dw 0syssize dw 0swap_dev dw 0ram_size dw 0vid_mode dw 0root_dev dw 0boot_flag dw 0xAA55_start: jmp short start db "HdrS" ; Header signature dw 0x0203 ; Header version numberrealmode_swtch dw 0, 0 ; default_switch, SETUPSEGstart_sys_seg dw 0x1000 ; obsoleteversion_ptr dw memdisk_version-0x200 ; version string ptrtype_of_loader db 0 ; Filled in by boot loaderloadflags db 1 ; Please load highsetup_move_size dw 0 ; Unusedcode32_start dd 0x100000 ; 32-bit start addressramdisk_image dd 0 ; Loaded ramdisk image addressramdisk_size dd 0 ; Size of loaded ramdiskbootsect_kludge dw 0, 0heap_end_ptr dw 0pad1 dw 0cmd_line_ptr dd 0 ; Command lineramdisk_max dd 0xffffffff ; Highest allowed ramdisk address section .rodatamemdisk_version: db "MEMDISK ", VERSION, " ", DATE, 0;; -----------------------------------------------------------------------;; End kernel image header;; -----------------------------------------------------------------------;; Move ourselves down into memory to reduce the risk of conflicts;; then canonicalize CS to match the other segments.; section .text bits 16start: mov ax,MY_CS mov es,ax movzx cx,byte [setup_sects] inc cx ; Add one for the boot sector shl cx,7 ; Convert to dwords xor si,si xor di,di mov fs,si ; fs <- 0 cld rep movsd mov ds,ax mov ss,ax xor esp,esp ; Stack at top of 64K segment jmp MY_CS:.next.next:;; Copy the command line, if there is one;copy_cmdline: xor di,di ; Bottom of our own segment (= "boot sector") mov eax,[cmd_line_ptr] and eax,eax jz .endcmd ; No command line mov si,ax shr eax,4 ; Convert to segment and si,0x000F ; Starting offset only mov gs,ax mov cx,496 ; Max number of bytes.copycmd: gs lodsb and al,al jz .endcmd stosb loop .copycmd.endcmd: xor al,al stosb;; Now jump to 32-bit code; sti call init32;; When init32 returns, we have been set up, the new boot sector loaded,; and we should go and and run the newly loaded boot sector;; The setup function returns (in AL) the drive number which should be; put into DL; mov dx,ax cli xor esi,esi ; No partition table involved mov ds,si ; Make all the segments consistent mov es,si mov fs,si mov gs,si mov ss,si mov esp,0x7C00 ; Good place for SP to start out jmp 0:0x7C00;; We enter protected mode, set up a flat 32-bit environment, run rep movsd; and then exit. IMPORTANT: This code assumes cs == MY_CS.;; This code is probably excessively anal-retentive in its handling of; segments, but this stuff is painful enough as it is without having to rely; on everything happening "as it ought to."; section .rodata ; desc base, limit, flags%macro desc 3 dd (%2 & 0xffff) | ((%1 & 0xffff) << 16) dd (%1 & 0xff000000) | (%2 & 0xf0000) | ((%3 & 0xf0ff) << 8) | ((%1 & 0x00ff0000) >> 16)%endmacro align 8, db 0call32_gdt: dw call32_gdt_size-1 ; Null descriptor - contains GDT.adj1: dd call32_gdt+CS_BASE ; pointer for LGDT instruction dw 0 ; 0008: Code segment, use16, readable, dpl 0, base CS_BASE, 64K desc CS_BASE, 0xffff, 0x009b ; 0010: Data segment, use16, read/write, dpl 0, base CS_BASE, 64K desc CS_BASE, 0xffff, 0x0093 ; 0018: Data segment, use16, read/write, dpl 0, base 0, 4G desc 0, 0xfffff, 0x809b ; 0020: Code segment, use32, read/write, dpl 0, base 0, 4G desc 0, 0xfffff, 0xc09b ; 0028: Data segment, use32, read/write, dpl 0, base 0, 4G desc 0, 0xfffff, 0xc093 call32_gdt_size: equ $-call32_gdterr_a20: db 'ERROR: A20 gate not responding!',13,10,0 section .bss alignb 4SavedSSSP resd 1 ; Place to save SS:SPReturn resd 1 ; Return valueA20Test resw 1 ; Space to test A20A20Tries resb 1 section .data alignb 4Target dd 0 ; Target addressTarget_Seg dw 20h ; Target CSA20Type dw 0 ; Default = unknown section .text bits 16;; Routines to enable and disable (yuck) A20. These routines are gathered; from tips from a couple of sources, including the Linux kernel and; http://www.x86.org/. The need for the delay to be as large as given here; is indicated by Donnie Barnes of RedHat, the problematic system being an; IBM ThinkPad 760EL.;; We typically toggle A20 twice for every 64K transferred.; %define io_delay call _io_delay%define IO_DELAY_PORT 80h ; Invalid port (we hope!)%define disable_wait 32 ; How long to wait for a disable%define A20_DUNNO 0 ; A20 type unknown%define A20_NONE 1 ; A20 always on?%define A20_BIOS 2 ; A20 BIOS enable%define A20_KBC 3 ; A20 through KBC%define A20_FAST 4 ; A20 through port 92h align 2, db 0A20List dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fastA20DList dw a20d_dunno, a20d_none, a20d_bios, a20d_kbc, a20d_fasta20_adjust_cnt equ ($-A20List)/2slow_out: out dx, al ; Fall through_io_delay: out IO_DELAY_PORT,al out IO_DELAY_PORT,al retenable_a20: pushad mov byte [A20Tries],255 ; Times to try to make this worktry_enable_a20:;; Flush the caches;%if DO_WBINVD call try_wbinvd%endif;; If the A20 type is known, jump straight to type; mov bp,[A20Type] add bp,bp ; Convert to word offset.adj4: jmp word [bp+A20List];; First, see if we are on a system with no A20 gate;a20_dunno:a20_none: mov byte [A20Type], A20_NONE call a20_test jnz a20_done;; Next, try the BIOS (INT 15h AX=2401h);a20_bios: mov byte [A20Type], A20_BIOS mov ax,2401h pushf ; Some BIOSes muck with IF int 15h popf call a20_test jnz a20_done;; Enable the keyboard controller A20 gate;a20_kbc: mov dl, 1 ; Allow early exit call empty_8042 jnz a20_done ; A20 live, no need to use KBC mov byte [A20Type], A20_KBC ; Starting KBC command sequence mov al,0D1h ; Command write out 064h, al call empty_8042_uncond mov al,0DFh ; A20 on out 060h, al call empty_8042_uncond ; Verify that A20 actually is enabled. Do that by ; observing a word in low memory and the same word in ; the HMA until they are no longer coherent. Note that ; we don't do the same check in the disable case, because ; we don't want to *require* A20 masking (SYSLINUX should ; work fine without it, if the BIOS does.).kbc_wait: push cx xor cx,cx.kbc_wait_loop: call a20_test jnz a20_done_pop loop .kbc_wait_loop pop cx;; Running out of options here. Final attempt: enable the "fast A20 gate";a20_fast: mov byte [A20Type], A20_FAST ; Haven't used the KBC yet in al, 092h or al,02h and al,~01h ; Don't accidentally reset the machine! out 092h, al.fast_wait: push cx xor cx,cx.fast_wait_loop: call a20_test jnz a20_done_pop loop .fast_wait_loop pop cx;; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up; and report failure to the user.; dec byte [A20Tries] jnz try_enable_a20 ; Error message time mov si,err_a20print_err: lodsb and al,al jz die mov bx,7 mov ah,0xe int 10h jmp print_errdie: sti.hlt: hlt jmp short .hlt;; A20 unmasked, proceed...;a20_done_pop: pop cxa20_done: popad ret;; This routine tests if A20 is enabled (ZF = 0). This routine; must not destroy any register contents.;a20_test: push es push cx push ax mov cx,0FFFFh ; HMA = segment 0FFFFh mov es,cx mov cx,32 ; Loop count mov ax,[A20Test].a20_wait: inc ax mov [A20Test],ax io_delay ; Serialize, and fix delay cmp ax,[es:A20Test+CS_BASE+10h] loopz .a20_wait.a20_done: pop ax pop cx pop es ret
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -