diff options
author | hpa <hpa> | 2002-06-11 05:48:29 +0000 |
---|---|---|
committer | hpa <hpa> | 2002-06-11 05:48:29 +0000 |
commit | abac6f53695c0b99e0235ca3da81ab3cd822f475 (patch) | |
tree | 42c9c90abcb685ec654b25e680f6a0e272d1fe52 /com32.inc | |
parent | 73d0682dcdd250939e560d333b591d7a5a8299ca (diff) | |
download | syslinux-abac6f53695c0b99e0235ca3da81ab3cd822f475.tar.gz |
Add an API for COMBOOT images, and add support for "COM32" -- 32-bit
linear .com files.
Diffstat (limited to 'com32.inc')
-rw-r--r-- | com32.inc | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/com32.inc b/com32.inc new file mode 100644 index 00000000..ac0440f8 --- /dev/null +++ b/com32.inc @@ -0,0 +1,319 @@ +;; $Id$ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2002 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, +;; Bostom MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; com32.inc +;; +;; Common code for running a COM32 image +;; + +; +; Load a COM32 image. A COM32 image is the 32-bit analogue to a DOS +; .com file. A COM32 image is loaded at address 0x101000, with %esp +; set to the high end of usable memory. +; +; A COM32 image should begin with the magic bytes: +; B8 FF 4C CD 21, which is "mov eax,0x21cd4cff" in 32-bit mode and +; "mov ax,0x4cff; int 0x21" in 16-bit mode. This will abort the +; program with an error if run in 16-bit mode. +; +pm_idt: equ 0x100000 +pm_entry: equ 0x101000 + + bits 16 + align 2 +com32_pmidt: + dw 8*256 ; Limit + dd pm_idt ; Address + +com32_rmidt: + dw 0ffffh ; Limit + dd 0 ; Address + +is_com32_image: + call highmemsize ; We need the high memory size... + call comboot_setup_api ; Set up the COMBOOT-style API + + mov edi,pm_entry ; Load address + xchg eax,edx ; Gotta fix this insanity... + shl eax,16 + mov ax,dx + call load_high + call crlf + +com32_start: + mov ebx,com32_call_start ; Where to go in PM + +com32_enter_pm: + mov [SavedSSSP],sp + mov [SavedSSSP+2],ss + + cli + cld + call a20_test + jnz .a20ok + call enable_a20 + +.a20ok: + lgdt [bcopy_gdt] ; We can use the same GDT just fine + lidt [com32_pmidt] ; Set up the IDT + mov eax,cr0 + or al,1 + mov cr0,eax ; Enter protected mode + jmp 20h:.in_pm + + bits 32 +.in_pm: + xor eax,eax ; Available for future use... + mov fs,eax + mov gs,eax + + mov al,28h ; Set up data segments + mov es,eax + mov ds,eax + mov ss,eax + + mov esp,[PMESP] ; Load protmode %esp if available + jmp ebx ; Go to where we need to go + +; +; This is invoked right before the actually starting the COM32 +; progam, in 32-bit mode... +; +com32_call_start: + ; + ; Point the stack to the end of high memory + ; + mov esp,[word HighMemSize] + + ; + ; Set up the protmode IDT and the interrupt jump buffers + ; We set these up in the system area at 0x100000, + ; but we could also put them beyond the stack. + ; + mov edi,pm_idt + + ; Form an interrupt gate descriptor + mov eax,0x00200000+((pm_idt+8*256)&0x0000ffff) + mov ebx,0x0000ee00+((pm_idt+8*256)&0xffff0000) + xor ecx,ecx + inc ch ; ecx <- 256 + + push ecx +.make_idt: + stosd + add eax,8 + xchg eax,ebx + stosd + xchg eax,ebx + loop .make_idt + + pop ecx + + ; Each entry in the interrupt jump buffer contains + ; the following instructions: + ; + ; 00000000 60 pushad + ; 00000001 B0xx mov al,<interrupt#> + ; 00000003 E9xxxxxxxx jmp com32_handle_interrupt + + mov eax,0e900b060h + mov ebx,com32_handle_interrupt-(pm_idt+8*256+8) + +.make_ijb: + stosd + sub [edi-2],cl ; Interrupt # + xchg eax,ebx + stosd + sub eax,8 + xchg eax,ebx + loop .make_ijb + + ; Now everything is set up for interrupts... + + push dword (1 << 16) ; 64K bounce buffer + push dword (comboot_seg << 4) ; Bounce buffer address + push dword com32_syscall ; Syscall entry point + movzx esi,word [word CmdOptPtr] + push esi ; Command line pointer + push dword 4 ; Argument count + sti ; Interrupts OK now + call pm_entry ; Run the program... + ; ... on return, fall through to com32_exit ... + +com32_exit: + mov bx,com32_done ; Return to command loop + +com32_enter_rm: + cli + cld + mov [PMESP],esp ; Save exit %esp + xor esp,esp ; Make sure the high bits are zero + jmp 08h:.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 [com32_rmidt] ; Real-mode IDT (rm needs no GDT) + mov eax,cr0 + and al,~1 + mov cr0,eax + jmp 0:.in_rm + +.in_rm: ; Back in real mode + mov ax,cs ; Set up sane segments + mov ds,ax + mov es,ax + mov fs,ax + mov gs,ax + lss sp,[SavedSSSP] ; Restore stack + jmp bx ; Go to whereever we need to go... + +com32_done: + call disable_a20 + sti + jmp enter_command + +; +; 16-bit support code +; + bits 16 + +; +; 16-bit interrupt-handling code +; +com32_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 ebx,com32_int_resume + jmp com32_enter_pm ; Go back to PM + +; +; 16-bit system call handling code +; +com32_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 ebx,com32_sys_resume + jmp com32_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. +; +com32_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,com32_int_rm + jmp com32_enter_rm ; Go to real mode + +com32_int_resume: + popad + iret + +; +; Syscall invocation. We manifest a structure on the real-mode stack, +; containing the com32sys_t structure from <com32.h> as well as +; the following entries (from low to high address): +; - Target offset +; - Target segment +; - Return offset +; - Return segment (== real mode cs == 0) +; - Return flags +; +com32_syscall: + pushfd ; Save IF among other things... + pushad ; We only need to save some, but... + cld + + movzx edi,word [word SavedSSSP] + movzx eax,word [word SavedSSSP+2] + sub edi,54 ; Allocate 54 bytes + mov [word SavedSSSP],di + shl eax,4 + add edi,eax ; 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 eax,com32_sys_rm.return ; Return seg:offs + stosd ; 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,com32_sys_rm + jmp com32_enter_rm ; Go to real mode + + ; On return, the 44-byte return structure is on the + ; real-mode stack. +com32_sys_resume: + movzx esi,word [word SavedSSSP] + movzx eax,word [word SavedSSSP+2] + mov edi,[esp+12*4] ; Dest regs + shl eax,4 + add esi,eax ; 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 dword [word SavedSSSP],44 ; Remove from stack + + popad + popfd + ret ; Return to 32-bit program + + bits 16 |