syslinux-3.08-2 sources from FC4
[bootcd.git] / syslinux / com32.inc
1 ;; $Id: com32.inc,v 1.9 2005/01/06 22:34:06 hpa Exp $
2 ;; -----------------------------------------------------------------------
3 ;;   
4 ;;   Copyright 1994-2003 H. Peter Anvin - All Rights Reserved
5 ;;
6 ;;   This program is free software; you can redistribute it and/or modify
7 ;;   it under the terms of the GNU General Public License as published by
8 ;;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
9 ;;   Boston MA 02111-1307, USA; either version 2 of the License, or
10 ;;   (at your option) any later version; incorporated herein by reference.
11 ;;
12 ;; -----------------------------------------------------------------------
13
14 ;;
15 ;; com32.inc
16 ;;
17 ;; Common code for running a COM32 image
18 ;;
19
20 ;
21 ; Load a COM32 image.  A COM32 image is the 32-bit analogue to a DOS
22 ; .com file.  A COM32 image is loaded at address 0x101000, with %esp
23 ; set to the high end of usable memory.
24 ;
25 ; A COM32 image should begin with the magic bytes:
26 ; B8 FF 4C CD 21, which is "mov eax,0x21cd4cff" in 32-bit mode and
27 ; "mov ax,0x4cff; int 0x21" in 16-bit mode.  This will abort the
28 ; program with an error if run in 16-bit mode.
29 ;
30 pm_idt:         equ 0x100000
31 pm_entry:       equ 0x101000
32
33                 bits 16
34                 section .data
35                 align 2, db 0
36 com32_pmidt:
37                 dw 8*256                ; Limit
38                 dd pm_idt               ; Address
39
40 com32_rmidt:
41                 dw 0ffffh               ; Limit
42                 dd 0                    ; Address
43
44                 section .text
45 is_com32_image:
46                 push si                 ; Save file handle
47                 push dx                 ; File length held in DX:AX
48                 push ax
49
50                 call make_plain_cmdline
51                 ; Copy the command line into the low cmdline buffer
52                 mov ax,real_mode_seg
53                 mov fs,ax
54                 mov si,cmd_line_here
55                 mov di,command_line
56                 mov cx,[CmdLinePtr]
57                 inc cx                  ; Include final null
58                 sub cx,si
59                 fs rep movsb
60
61                 call highmemsize        ; We need the high memory size...
62                 call comboot_setup_api  ; Set up the COMBOOT-style API
63
64                 mov edi,pm_entry        ; Load address
65                 pop eax                 ; File length
66                 pop si                  ; File handle
67                 xor dx,dx               ; No padding
68                 call load_high
69                 call crlf
70
71 com32_start:
72                 mov ebx,com32_call_start        ; Where to go in PM
73
74 com32_enter_pm:
75                 cli
76                 mov ax,cs
77                 mov ds,ax
78                 mov [SavedSSSP],sp
79                 mov [SavedSSSP+2],ss
80                 cld
81                 call a20_test
82                 jnz .a20ok
83                 call enable_a20
84
85 .a20ok:
86                 lgdt [bcopy_gdt]        ; We can use the same GDT just fine
87                 lidt [com32_pmidt]      ; Set up the IDT
88                 mov eax,cr0
89                 or al,1
90                 mov cr0,eax             ; Enter protected mode
91                 jmp 20h:.in_pm
92                 
93                 bits 32
94 .in_pm:
95                 xor eax,eax             ; Available for future use...
96                 mov fs,eax
97                 mov gs,eax
98
99                 mov al,28h              ; Set up data segments
100                 mov es,eax
101                 mov ds,eax
102                 mov ss,eax
103
104                 mov esp,[PMESP]         ; Load protmode %esp if available
105                 jmp ebx                 ; Go to where we need to go
106
107 ;
108 ; This is invoked right before the actually starting the COM32
109 ; progam, in 32-bit mode...
110 ;
111 com32_call_start:
112                 ;
113                 ; Point the stack to the end of high memory
114                 ;
115                 mov esp,[word HighMemSize]
116
117                 ;
118                 ; Set up the protmode IDT and the interrupt jump buffers
119                 ; We set these up in the system area at 0x100000,
120                 ; but we could also put them beyond the stack.
121                 ;
122                 mov edi,pm_idt
123
124                 ; Form an interrupt gate descriptor
125                 mov eax,0x00200000+((pm_idt+8*256)&0x0000ffff)
126                 mov ebx,0x0000ee00+((pm_idt+8*256)&0xffff0000)
127                 xor ecx,ecx
128                 inc ch                          ; ecx <- 256
129
130                 push ecx
131 .make_idt:
132                 stosd
133                 add eax,8
134                 xchg eax,ebx
135                 stosd
136                 xchg eax,ebx
137                 loop .make_idt
138
139                 pop ecx
140
141                 ; Each entry in the interrupt jump buffer contains
142                 ; the following instructions:
143                 ;
144                 ; 00000000 60                pushad
145                 ; 00000001 B0xx              mov al,<interrupt#>
146                 ; 00000003 E9xxxxxxxx        jmp com32_handle_interrupt
147
148                 mov eax,0e900b060h
149                 mov ebx,com32_handle_interrupt-(pm_idt+8*256+8)
150
151 .make_ijb:
152                 stosd
153                 sub [edi-2],cl                  ; Interrupt #
154                 xchg eax,ebx
155                 stosd
156                 sub eax,8
157                 xchg eax,ebx
158                 loop .make_ijb
159
160                 ; Now everything is set up for interrupts...
161
162                 push dword com32_farcall        ; Farcall entry point
163                 push dword (1 << 16)            ; 64K bounce buffer
164                 push dword (comboot_seg << 4)   ; Bounce buffer address
165                 push dword com32_intcall        ; Intcall entry point
166                 push dword command_line         ; Command line pointer
167                 push dword 5                    ; Argument count
168                 sti                             ; Interrupts OK now
169                 call pm_entry                   ; Run the program...
170                 ; ... on return, fall through to com32_exit ...
171
172 com32_exit:
173                 mov bx,com32_done       ; Return to command loop
174
175 com32_enter_rm:
176                 cli
177                 cld
178                 mov [PMESP],esp         ; Save exit %esp
179                 xor esp,esp             ; Make sure the high bits are zero
180                 jmp 08h:.in_pm16        ; Return to 16-bit mode first
181
182                 bits 16
183 .in_pm16:
184                 mov ax,18h              ; Real-mode-like segment
185                 mov es,ax
186                 mov ds,ax
187                 mov ss,ax
188                 mov fs,ax
189                 mov gs,ax
190
191                 lidt [com32_rmidt]      ; Real-mode IDT (rm needs no GDT)
192                 mov eax,cr0
193                 and al,~1
194                 mov cr0,eax
195                 jmp 0:.in_rm
196
197 .in_rm:                                 ; Back in real mode
198                 mov ax,cs               ; Set up sane segments
199                 mov ds,ax
200                 mov es,ax
201                 mov fs,ax
202                 mov gs,ax
203                 lss sp,[SavedSSSP]      ; Restore stack
204                 jmp bx                  ; Go to whereever we need to go...
205
206 com32_done:
207                 call disable_a20
208                 sti
209                 jmp enter_command
210
211 ;
212 ; 16-bit support code
213 ;
214                 bits 16
215
216 ;
217 ; 16-bit interrupt-handling code
218 ;
219 com32_int_rm:
220                 pushf                           ; Flags on stack
221                 push cs                         ; Return segment
222                 push word .cont                 ; Return address
223                 push dword edx                  ; Segment:offset of IVT entry
224                 retf                            ; Invoke IVT routine
225 .cont:          ; ... on resume ...
226                 mov ebx,com32_int_resume
227                 jmp com32_enter_pm              ; Go back to PM
228
229 ;
230 ; 16-bit system call handling code
231 ;
232 com32_sys_rm:
233                 pop gs
234                 pop fs
235                 pop es
236                 pop ds
237                 popad
238                 popfd
239                 mov [cs:Com32SysSP],sp
240                 retf                            ; Invoke routine
241 .return:
242                 ; We clean up SP here because we don't know if the
243                 ; routine returned with RET, RETF or IRET
244                 mov sp,[cs:Com32SysSP]
245                 pushfd
246                 pushad
247                 push ds
248                 push es
249                 push fs
250                 push gs
251                 mov ebx,com32_sys_resume
252                 jmp com32_enter_pm
253
254 ;
255 ; 32-bit support code
256 ;
257                 bits 32
258
259 ;
260 ; This is invoked on getting an interrupt in protected mode.  At
261 ; this point, we need to context-switch to real mode and invoke
262 ; the interrupt routine.
263 ;
264 ; When this gets invoked, the registers are saved on the stack and
265 ; AL contains the register number.
266 ;
267 com32_handle_interrupt:
268                 movzx eax,al
269                 xor ebx,ebx             ; Actually makes the code smaller
270                 mov edx,[ebx+eax*4]     ; Get the segment:offset of the routine
271                 mov bx,com32_int_rm
272                 jmp com32_enter_rm      ; Go to real mode
273
274 com32_int_resume:
275                 popad
276                 iret
277
278 ;
279 ; Intcall/farcall invocation.  We manifest a structure on the real-mode stack,
280 ; containing the com32sys_t structure from <com32.h> as well as
281 ; the following entries (from low to high address):
282 ; - Target offset
283 ; - Target segment
284 ; - Return offset
285 ; - Return segment (== real mode cs == 0)
286 ; - Return flags
287 ;
288 com32_farcall:
289                 pushfd                          ; Save IF among other things...
290                 pushad                          ; We only need to save some, but...
291
292                 mov eax,[esp+10*4]              ; CS:IP
293                 jmp com32_syscall
294
295
296 com32_intcall:
297                 pushfd                          ; Save IF among other things...
298                 pushad                          ; We only need to save some, but...
299
300                 movzx eax,byte [esp+10*4]       ; INT number
301                 mov eax,[eax*4]                 ; Get CS:IP from low memory
302
303 com32_syscall:
304                 cld
305
306                 movzx edi,word [word SavedSSSP]
307                 movzx ebx,word [word SavedSSSP+2]
308                 sub edi,54              ; Allocate 54 bytes
309                 mov [word SavedSSSP],di
310                 shl ebx,4
311                 add edi,ebx             ; Create linear address
312
313                 mov esi,[esp+11*4]      ; Source regs
314                 xor ecx,ecx
315                 mov cl,11               ; 44 bytes to copy
316                 rep movsd
317
318                 ; EAX is already set up to be CS:IP
319                 stosd                   ; Save in stack frame
320                 mov eax,com32_sys_rm.return     ; Return seg:offs
321                 stosd                   ; Save in stack frame
322                 mov eax,[edi-12]        ; Return flags
323                 and eax,0x200cd7        ; Mask (potentially) unsafe flags
324                 mov [edi-12],eax        ; Primary flags entry
325                 stosw                   ; Return flags
326
327                 mov bx,com32_sys_rm
328                 jmp com32_enter_rm      ; Go to real mode
329
330                 ; On return, the 44-byte return structure is on the
331                 ; real-mode stack, plus the 10 additional bytes used
332                 ; by the target address (see above.)
333 com32_sys_resume:
334                 movzx esi,word [word SavedSSSP]
335                 movzx eax,word [word SavedSSSP+2]
336                 mov edi,[esp+12*4]      ; Dest regs
337                 shl eax,4
338                 add esi,eax             ; Create linear address
339                 and edi,edi             ; NULL pointer?
340                 jnz .do_copy
341 .no_copy:       mov edi,esi             ; Do a dummy copy-to-self
342 .do_copy:       xor ecx,ecx
343                 mov cl,11               ; 44 bytes
344                 rep movsd               ; Copy register block
345
346                 add dword [word SavedSSSP],54   ; Remove from stack
347
348                 popad
349                 popfd
350                 ret                     ; Return to 32-bit program
351
352                 bits 16
353
354                 section .bss
355                 alignb 4
356 PMESP           resd 1                  ; Protected-mode ESP
357 Com32SysSP      resw 1                  ; SP saved during COM32 syscall
358
359                 section .text