diff options
Diffstat (limited to 'contrib/syslinux/syslinux-4.03/memdisk/memdisk16.asm')
-rw-r--r-- | contrib/syslinux/syslinux-4.03/memdisk/memdisk16.asm | 793 |
1 files changed, 0 insertions, 793 deletions
diff --git a/contrib/syslinux/syslinux-4.03/memdisk/memdisk16.asm b/contrib/syslinux/syslinux-4.03/memdisk/memdisk16.asm deleted file mode 100644 index 6bafae7..0000000 --- a/contrib/syslinux/syslinux-4.03/memdisk/memdisk16.asm +++ /dev/null @@ -1,793 +0,0 @@ -;; -*- fundamental -*- -;; ----------------------------------------------------------------------- -;; -;; Copyright 1994-2008 H. Peter Anvin - All Rights Reserved -;; Copyright 2009 Intel Corporation; author: H. Peter Anvin -;; -;; 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. -;; - -%include '../version.gen' - -MY_CS equ 0x0800 ; Segment address to use -CS_BASE equ (MY_CS << 4) ; Corresponding address - -; Low memory bounce buffer -BOUNCE_SEG equ (MY_CS+0x1000) - -%define DO_WBINVD 0 - - section .rodata align=16 - section .data align=16 - section .bss align=16 - section .stack align=16 nobits -stack resb 512 -stack_end equ $ - -;; ----------------------------------------------------------------------- -;; Kernel image header -;; ----------------------------------------------------------------------- - - section .text ; Must be first in image - bits 16 - -cmdline times 497 db 0 ; We put the command line here -setup_sects db 0 -root_flags dw 0 -syssize dw 0 -swap_dev dw 0 -ram_size dw 0 -vid_mode dw 0 -root_dev dw 0 -boot_flag dw 0xAA55 - -_start: jmp short start - - db "HdrS" ; Header signature - dw 0x0203 ; Header version number - -realmode_swtch dw 0, 0 ; default_switch, SETUPSEG -start_sys_seg dw 0x1000 ; obsolete -version_ptr dw memdisk_version-0x200 ; version string ptr -type_of_loader db 0 ; Filled in by boot loader -loadflags db 1 ; Please load high -setup_move_size dw 0 ; Unused -code32_start dd 0x100000 ; 32-bit start address -ramdisk_image dd 0 ; Loaded ramdisk image address -ramdisk_size dd 0 ; Size of loaded ramdisk -bootsect_kludge dw 0, 0 -heap_end_ptr dw 0 -pad1 dw 0 -cmd_line_ptr dd 0 ; Command line -ramdisk_max dd 0xffffffff ; Highest allowed ramdisk address - -; -; These fields aren't real setup fields, they're poked in by the -; 32-bit code. -; -b_esdi dd 0 ; ES:DI for boot sector invocation -b_edx dd 0 ; EDX for boot sector invocation -b_sssp dd 0 ; SS:SP on boot sector invocation -b_csip dd 0 ; CS:IP on boot sector invocation - - section .rodata -memdisk_version: - db "MEMDISK ", VERSION_STR, " ", 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 16 -start: - 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 - mov esp,stack_end - 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 will have poked values into the setup area. -; - movzx edi,word [cs:b_esdi] - mov es,word [cs:b_esdi+2] - mov edx,[cs:b_edx] - - cli - xor esi,esi ; No partition table involved - mov ds,si ; Make all the segments consistent - mov fs,si - mov gs,si - lss sp,[cs:b_sssp] - movzx esp,sp - jmp far [cs:b_csip] - -; -; 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." -; -DummyTSS equ 0x580 ; Hopefully safe place in low mmoery - - section .data - - ; 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 0 -call32_gdt: dw call32_gdt_size-1 ; Null descriptor - contains GDT -.adj1: dd call32_gdt+CS_BASE ; pointer for LGDT instruction - dw 0 - - ; 0008: Dummy TSS to make Intel VT happy - ; Should never be actually accessed... - desc DummyTSS, 103, 0x8089 - - ; 0010: Code segment, use16, readable, dpl 0, base CS_BASE, 64K - desc CS_BASE, 0xffff, 0x009b - - ; 0018: Data segment, use16, read/write, dpl 0, base CS_BASE, 64K - desc CS_BASE, 0xffff, 0x0093 - - ; 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_gdt - -err_a20: db 'ERROR: A20 gate not responding!',13,10,0 - - section .bss - alignb 4 -Return resd 1 ; Return value -SavedSP resw 1 ; Place to save SP -A20Tries resb 1 - - section .data - align 4, db 0 -Target dd 0 ; Target address -Target_Seg dw 20h ; Target CS - -A20Type 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 0 -A20List dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fast -A20DList dw a20d_dunno, a20d_none, a20d_bios, a20d_kbc, a20d_fast -a20_adjust_cnt equ ($-A20List)/2 - -slow_out: out dx, al ; Fall through - -_io_delay: out IO_DELAY_PORT,al - out IO_DELAY_PORT,al - ret - -enable_a20: - pushad - mov byte [A20Tries],255 ; Times to try to make this work - -try_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 ; Write output port - out 064h, al - call empty_8042_uncond - - mov al,0DFh ; A20 on - out 060h, al - call empty_8042_uncond - - ; Apparently the UHCI spec assumes that A20 toggle - ; ends with a null command (assumed to be for sychronization?) - ; Put it here to see if it helps anything... - mov al,0FFh ; Null command - out 064h, 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_a20 -print_err: - lodsb - and al,al - jz die - mov bx,7 - mov ah,0xe - int 10h - jmp print_err - - -die: - sti -.hlt: hlt - jmp short .hlt - -; -; A20 unmasked, proceed... -; -a20_done_pop: pop cx -a20_done: popad - ret - -; -; This routine tests if A20 is enabled (ZF = 0). This routine -; must not destroy any register contents. -; - -; This is the INT 1Fh vector, which is standard PCs is used by the -; BIOS when the screen is in graphics mode. Even if it is, it points to -; data, not code, so it should be safe enough to fiddle with. -A20Test equ (1Fh*4) - -a20_test: - push ds - push es - push cx - push eax - xor ax,ax - mov ds,ax ; DS == 0 - dec ax - mov es,ax ; ES == 0FFFFh - mov cx,32 ; Loop count - mov eax,[A20Test] - cmp eax,[es:A20Test+10h] - jne .a20_done - push eax -.a20_wait: - inc eax - mov [A20Test],eax - io_delay - cmp eax,[es:A20Test+10h] - loopz .a20_wait - pop dword [A20Test] ; Restore original value -.a20_done: - pop eax - pop cx - pop es - pop ds - ret - -disable_a20: - pushad -; -; Flush the caches -; -%if DO_WBINVD - call try_wbinvd -%endif - - mov bp,[A20Type] - add bp,bp ; Convert to word offset -.adj5: jmp word [bp+A20DList] - -a20d_bios: - mov ax,2400h - pushf ; Some BIOSes muck with IF - int 15h - popf - jmp short a20d_snooze - -; -; Disable the "fast A20 gate" -; -a20d_fast: - in al, 092h - and al,~03h - out 092h, al - jmp short a20d_snooze - -; -; Disable the keyboard controller A20 gate -; -a20d_kbc: - call empty_8042_uncond - - mov al,0D1h - out 064h, al ; Write output port - call empty_8042_uncond - - mov al,0DDh ; A20 off - out 060h, al - call empty_8042_uncond - - mov al,0FFh ; Null command/synchronization - out 064h, al - call empty_8042_uncond - - ; Wait a bit for it to take effect -a20d_snooze: - push cx - mov cx, disable_wait -.delayloop: call a20_test - jz .disabled - loop .delayloop -.disabled: pop cx -a20d_dunno: -a20d_none: - popad - ret - -; -; Routine to empty the 8042 KBC controller. If dl != 0 -; then we will test A20 in the loop and exit if A20 is -; suddenly enabled. -; -empty_8042_uncond: - xor dl,dl -empty_8042: - call a20_test - jz .a20_on - and dl,dl - jnz .done -.a20_on: io_delay - in al, 064h ; Status port - test al,1 - jz .no_output - io_delay - in al, 060h ; Read input - jmp short empty_8042 -.no_output: - test al,2 - jnz empty_8042 - io_delay -.done: ret - -; -; Execute a WBINVD instruction if possible on this CPU -; -%if DO_WBINVD -try_wbinvd: - wbinvd - ret -%endif - - section .bss - alignb 4 -PMESP resd 1 ; Protected mode %esp - - section .idt nobits align=4096 - alignb 4096 -pm_idt resb 4096 ; Protected-mode IDT, followed by interrupt stubs - - - - -pm_entry: equ 0x100000 - - section .rodata - align 2, db 0 -call32_rmidt: - dw 0ffffh ; Limit - dd 0 ; Address - - section .data - alignb 2 -call32_pmidt: - dw 8*256 ; Limit - dd 0 ; Address (entered later) - - section .text -; -; This is the main entrypoint in this function -; -init32: - mov bx,call32_call_start ; Where to go in PM - -; -; Enter protected mode. BX contains the entry point relative to the -; real-mode CS. -; -call32_enter_pm: - mov ax,cs - mov ds,ax - movzx ebp,ax - shl ebp,4 ; EBP <- CS_BASE - movzx ebx,bx - add ebx,ebp ; entry point += CS_BASE - cli - mov [SavedSP],sp - cld - call enable_a20 - mov byte [call32_gdt+8+5],89h ; Mark TSS unbusy - o32 lgdt [call32_gdt] ; Set up GDT - o32 lidt [call32_pmidt] ; Set up IDT - mov eax,cr0 - or al,1 - mov cr0,eax ; Enter protected mode - jmp 20h:strict dword .in_pm+CS_BASE -.pm_jmp equ $-6 - - - bits 32 -.in_pm: - xor eax,eax ; Available for future use... - mov fs,eax - mov gs,eax - lldt ax - - mov al,28h ; Set up data segments - mov es,eax - mov ds,eax - mov ss,eax - - mov al,08h - ltr ax - - mov esp,[ebp+PMESP] ; Load protmode %esp if available - jmp ebx ; Go to where we need to go - -; -; This is invoked before first dispatch of the 32-bit code, in 32-bit mode -; -call32_call_start: - ; - ; Set up a temporary stack in the bounce buffer; - ; start32.S will override this to point us to the real - ; high-memory stack. - ; - mov esp, (BOUNCE_SEG << 4) + 0x10000 - - push dword call32_enter_rm.rm_jmp+CS_BASE - push dword call32_enter_pm.pm_jmp+CS_BASE - push dword stack_end ; RM size - push dword call32_gdt+CS_BASE - push dword call32_handle_interrupt+CS_BASE - push dword CS_BASE ; Segment base - push dword (BOUNCE_SEG << 4) ; Bounce buffer address - push dword call32_syscall+CS_BASE ; Syscall entry point - - call pm_entry-CS_BASE ; Run the program... - - ; ... fall through to call32_exit ... - -call32_exit: - mov bx,call32_done ; Return to command loop - -call32_enter_rm: - ; Careful here... the PM code may have relocated the - ; entire RM code, so we need to figure out exactly - ; where we are executing from. If the PM code has - ; relocated us, it *will* have adjusted the GDT to - ; match, though. - call .here -.here: pop ebp - sub ebp,.here - o32 sidt [ebp+call32_pmidt] - cli - cld - mov [ebp+PMESP],esp ; Save exit %esp - xor esp,esp ; Make sure the high bits are zero - jmp 10h:.in_pm16 ; Return to 16-bit mode first - - bits 16 -.in_pm16: - mov ax,18h ; Real-mode-like segment - mov es,ax - mov ds,ax - mov ss,ax - mov fs,ax - mov gs,ax - - lidt [call32_rmidt] ; Real-mode IDT (rm needs no GDT) - mov eax,cr0 - and al,~1 - mov cr0,eax - jmp MY_CS:.in_rm -.rm_jmp equ $-2 - -.in_rm: ; Back in real mode - mov ax,cs - mov ds,ax - mov es,ax - mov fs,ax - mov gs,ax - mov ss,ax - mov sp,[SavedSP] ; Restore stack - jmp bx ; Go to whereever we need to go... - -call32_done: - call disable_a20 - sti - ret - -; -; 16-bit support code -; - bits 16 - -; -; 16-bit interrupt-handling code -; -call32_int_rm: - pushf ; Flags on stack - push cs ; Return segment - push word .cont ; Return address - push dword edx ; Segment:offset of IVT entry - retf ; Invoke IVT routine -.cont: ; ... on resume ... - mov bx,call32_int_resume - jmp call32_enter_pm ; Go back to PM - -; -; 16-bit system call handling code -; -call32_sys_rm: - pop gs - pop fs - pop es - pop ds - popad - popfd - retf ; Invoke routine -.return: - pushfd - pushad - push ds - push es - push fs - push gs - mov bx,call32_sys_resume - jmp call32_enter_pm - -; -; 32-bit support code -; - bits 32 - -; -; This is invoked on getting an interrupt in protected mode. At -; this point, we need to context-switch to real mode and invoke -; the interrupt routine. -; -; When this gets invoked, the registers are saved on the stack and -; AL contains the register number. -; -call32_handle_interrupt: - movzx eax,al - xor ebx,ebx ; Actually makes the code smaller - mov edx,[ebx+eax*4] ; Get the segment:offset of the routine - mov bx,call32_int_rm - jmp call32_enter_rm ; Go to real mode - -call32_int_resume: - popad - iret - -; -; Syscall invocation. We manifest a structure on the real-mode stack, -; containing the call32sys_t structure from <call32.h> as well as -; the following entries (from low to high address): -; - Target offset -; - Target segment -; - Return offset -; - Return segment (== real mode cs) -; - Return flags -; -call32_syscall: - pushfd ; Save IF among other things... - pushad ; We only need to save some, but... - cld - call .here -.here: pop ebp - sub ebp,.here - - movzx edi,word [ebp+SavedSP] - sub edi,54 ; Allocate 54 bytes - mov [ebp+SavedSP],di - add edi,ebp ; Create linear address - - mov esi,[esp+11*4] ; Source regs - xor ecx,ecx - mov cl,11 ; 44 bytes to copy - rep movsd - - movzx eax,byte [esp+10*4] ; Interrupt number - ; ecx == 0 here; adding it to the EA makes the - ; encoding smaller - mov eax,[ecx+eax*4] ; Get IVT entry - stosd ; Save in stack frame - mov ax,call32_sys_rm.return ; Return offset - stosw ; Save in stack frame - mov eax,ebp - shr eax,4 ; Return segment - stosw ; Save in stack frame - mov eax,[edi-12] ; Return flags - and eax,0x200cd7 ; Mask (potentially) unsafe flags - mov [edi-12],eax ; Primary flags entry - stosw ; Return flags - - mov bx,call32_sys_rm - jmp call32_enter_rm ; Go to real mode - - ; On return, the 44-byte return structure is on the - ; real-mode stack. call32_enter_pm will leave ebp - ; pointing to the real-mode base. -call32_sys_resume: - movzx esi,word [ebp+SavedSP] - mov edi,[esp+12*4] ; Dest regs - add esi,ebp ; Create linear address - and edi,edi ; NULL pointer? - jnz .do_copy -.no_copy: mov edi,esi ; Do a dummy copy-to-self -.do_copy: xor ecx,ecx - mov cl,11 ; 44 bytes - rep movsd ; Copy register block - - add word [ebp+SavedSP],44 ; Remove from stack - - popad - popfd - ret ; Return to 32-bit program |