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