Centralize shift_is_held(), make it work to force the command line
[syslinux/sherbszt.git] / core / pxelinux.asm
blob953a906f082fe969df7ddb0d11884fb53c3a6333
1 ; -*- fundamental -*- (asm-mode sucks)
2 ; ****************************************************************************
4 ; pxelinux.asm
6 ; A program to boot Linux kernels off a TFTP server using the Intel PXE
7 ; network booting API. It is based on the SYSLINUX boot loader for
8 ; MS-DOS floppies.
10 ; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
11 ; Copyright 2009 Intel Corporation; author: H. Peter Anvin
13 ; This program is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
16 ; Boston MA 02111-1307, USA; either version 2 of the License, or
17 ; (at your option) any later version; incorporated herein by reference.
19 ; ****************************************************************************
21 %define IS_PXELINUX 1
22 %include "head.inc"
23 %include "pxe.inc"
25 ; gPXE extensions support
26 %define GPXE 1
29 ; Some semi-configurable constants... change on your own risk.
31 my_id equ pxelinux_id
32 NULLFILE equ 0 ; Zero byte == null file name
33 NULLOFFSET equ 0 ; Position in which to look
34 REBOOT_TIME equ 5*60 ; If failure, time until full reset
35 %assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top
36 TFTP_BLOCKSIZE_LG2 equ 9 ; log2(bytes/block)
37 TFTP_BLOCKSIZE equ (1 << TFTP_BLOCKSIZE_LG2)
39 SECTOR_SHIFT equ TFTP_BLOCKSIZE_LG2
40 SECTOR_SIZE equ TFTP_BLOCKSIZE
42 ; ---------------------------------------------------------------------------
43 ; BEGIN CODE
44 ; ---------------------------------------------------------------------------
47 ; Memory below this point is reserved for the BIOS and the MBR
49 section .earlybss
50 global trackbuf
51 trackbufsize equ 8192
52 trackbuf resb trackbufsize ; Track buffer goes here
53 ; ends at 2800h
55 ; These fields save information from before the time
56 ; .bss is zeroed... must be in .earlybss
57 global InitStack
58 InitStack resd 1
60 section .bss16
61 alignb FILENAME_MAX
62 PXEStack resd 1 ; Saved stack during PXE call
64 alignb 4
65 global DHCPMagic, RebootTime, BIOSName
66 RebootTime resd 1 ; Reboot timeout, if set by option
67 LocalBootType resw 1 ; Local boot return code
68 DHCPMagic resb 1 ; PXELINUX magic flags
69 BIOSName resw 1 ; Dummy variable - always 0
71 section .text16
72 global StackBuf
73 StackBuf equ STACK_TOP-44 ; Base of stack if we use our own
74 StackHome equ StackBuf
76 ; PXE loads the whole file, but assume it can't be more
77 ; than (384-31)K in size.
78 MaxLMA equ 384*1024
81 ; Primary entry point.
83 bootsec equ $
84 _start:
85 jmp 0:_start1 ; Canonicalize the address and skip
86 ; the patch header
89 ; Patch area for adding hardwired DHCP options
91 align 4
93 hcdhcp_magic dd 0x2983c8ac ; Magic number
94 hcdhcp_len dd 7*4 ; Size of this structure
95 hcdhcp_flags dd 0 ; Reserved for the future
96 ; Parameters to be parsed before the ones from PXE
97 bdhcp_offset dd 0 ; Offset (entered by patcher)
98 bdhcp_len dd 0 ; Length (entered by patcher)
99 ; Parameters to be parsed *after* the ones from PXE
100 adhcp_offset dd 0 ; Offset (entered by patcher)
101 adhcp_len dd 0 ; Length (entered by patcher)
103 _start1:
104 pushfd ; Paranoia... in case of return to PXE
105 pushad ; ... save as much state as possible
106 push ds
107 push es
108 push fs
109 push gs
111 cld ; Copy upwards
112 xor ax,ax
113 mov ds,ax
114 mov es,ax
116 %if 0 ; debugging code only... not intended for production use
117 ; Clobber the stack segment, to test for specific pathologies
118 mov di,STACK_BASE
119 mov cx,STACK_LEN >> 1
120 mov ax,0xf4f4
121 rep stosw
123 ; Clobber the tail of the 64K segment, too
124 extern __bss1_end
125 mov di,__bss1_end
126 sub cx,di ; CX = 0 previously
127 shr cx,1
128 rep stosw
129 %endif
131 ; That is all pushed onto the PXE stack. Save the pointer
132 ; to it and switch to an internal stack.
133 mov [InitStack],sp
134 mov [InitStack+2],ss
136 lss esp,[BaseStack]
137 sti ; Stack set up and ready
140 ; Initialize screen (if we're using one)
142 %include "init.inc"
145 ; Tell the user we got this far
147 mov si,syslinux_banner
148 call writestr_early
150 mov si,copyright_str
151 call writestr_early
154 ; do fs initialize
156 mov eax,ROOT_FS_OPS
157 xor ebp,ebp
158 pm_call pm_fs_init
160 section .rodata
161 alignz 4
162 ROOT_FS_OPS:
163 extern pxe_fs_ops
164 dd pxe_fs_ops
165 dd 0
168 section .text16
170 ; Initialize the idle mechanism
172 extern reset_idle
173 pm_call reset_idle
176 ; Now we're all set to start with our *real* business.
178 ; In previous versions I avoided using 32-bit registers because of a
179 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
180 ; random. I figure, though, that if there are any of those still left
181 ; they probably won't be trying to install Linux on them...
183 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
184 ; to take'm out. In fact, we may want to put them back if we're going
185 ; to boot ELKS at some point.
189 ; Linux kernel loading code is common. However, we need to define
190 ; a couple of helper macros...
193 ; Unload PXE stack
194 %define HAVE_UNLOAD_PREP
195 %macro UNLOAD_PREP 0
196 pm_call unload_pxe
197 %endmacro
200 ; Jump to 32-bit ELF space
202 pm_call load_env32
203 jmp kaboom ; load_env32() shouldn't return. If it does, then kaboom!
205 print_hello:
206 enter_command:
207 auto_boot:
208 pm_call hello
211 ; Save hardwired DHCP options. This is done before the C environment
212 ; is initialized, so it has to be done in assembly.
214 %define MAX_DHCP_OPTS 4096
215 bits 32
217 section .savedata
218 global bdhcp_data, adhcp_data
219 bdhcp_data: resb MAX_DHCP_OPTS
220 adhcp_data: resb MAX_DHCP_OPTS
222 section .textnr
223 pm_save_data:
224 mov eax,MAX_DHCP_OPTS
225 movzx ecx,word [bdhcp_len]
226 cmp ecx,eax
227 jna .oksize
228 mov ecx,eax
229 mov [bdhcp_len],ax
230 .oksize:
231 mov esi,[bdhcp_offset]
232 add esi,_start
233 mov edi,bdhcp_data
234 add ecx,3
235 shr ecx,2
236 rep movsd
238 adhcp_copy:
239 movzx ecx,word [adhcp_len]
240 cmp ecx,eax
241 jna .oksize
242 mov ecx,eax
243 mov [adhcp_len],ax
244 .oksize:
245 mov esi,[adhcp_offset]
246 add esi,_start
247 mov edi,adhcp_data
248 add ecx,3
249 shr ecx,2
250 rep movsd
253 bits 16
255 ; As core/ui.inc used to be included here in core/pxelinux.asm, and it's no
256 ; longer used, its global variables that were previously used by
257 ; core/pxelinux.asm are now declared here.
258 section .bss16
259 alignb 4
260 Kernel_EAX resd 1
261 Kernel_SI resw 1
263 section .bss16
264 alignb 4
265 ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
266 ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
267 KernelExtPtr resw 1 ; During search, final null pointer
268 FuncFlag resb 1 ; Escape sequences received from keyboard
269 KernelType resb 1 ; Kernel type, from vkernel, if known
270 global KernelName
271 KernelName resb FILENAME_MAX ; Mangled name for kernel
273 section .text16
275 ; COM32 vestigial data structure
277 %include "com32.inc"
279 section .text16
280 global local_boot16:function hidden
281 local_boot16:
282 mov [LocalBootType],ax
283 lss sp,[InitStack]
284 pop gs
285 pop fs
286 pop es
287 pop ds
288 popad
289 mov ax,[cs:LocalBootType]
290 cmp ax,-1 ; localboot -1 == INT 18h
291 je .int18
292 popfd
293 retf ; Return to PXE
294 .int18:
295 popfd
296 int 18h
297 jmp 0F000h:0FFF0h
301 ; kaboom: write a message and bail out. Wait for quite a while,
302 ; or a user keypress, then do a hard reboot.
304 ; Note: use BIOS_timer here; we may not have jiffies set up.
306 global kaboom
307 kaboom:
308 RESET_STACK_AND_SEGS AX
309 .patch: mov si,bailmsg
310 call writestr_early ; Returns with AL = 0
311 .drain: call pollchar
312 jz .drained
313 call getchar
314 jmp short .drain
315 .drained:
316 mov edi,[RebootTime]
317 mov al,[DHCPMagic]
318 and al,09h ; Magic+Timeout
319 cmp al,09h
320 je .time_set
321 mov edi,REBOOT_TIME
322 .time_set:
323 mov cx,18
324 .wait1: push cx
325 mov ecx,edi
326 .wait2: mov dx,[BIOS_timer]
327 .wait3: call pollchar
328 jnz .keypress
329 pm_call __idle
330 cmp dx,[BIOS_timer]
331 je .wait3
332 loop .wait2,ecx
333 mov al,'.'
334 pm_call pm_writechr
335 pop cx
336 loop .wait1
337 .keypress:
338 pm_call crlf
339 mov word [BIOS_magic],0 ; Cold reboot
340 jmp 0F000h:0FFF0h ; Reset vector address
343 ; pxenv
345 ; This is the main PXENV+/!PXE entry point, using the PXENV+
346 ; calling convention. This is a separate local routine so
347 ; we can hook special things from it if necessary. In particular,
348 ; some PXE stacks seem to not like being invoked from anything but
349 ; the initial stack, so humour it.
351 ; While we're at it, save and restore all registers.
353 global pxenv
354 pxenv:
355 pushfd
356 pushad
358 ; We may be removing ourselves from memory
359 cmp bx,PXENV_RESTART_TFTP
360 jz .disable_timer
361 cmp bx,PXENV_FILE_EXEC
362 jnz .store_stack
364 .disable_timer:
365 call bios_timer_cleanup
367 .store_stack:
368 pushf
370 inc word [cs:PXEStackLock]
371 jnz .skip1
372 mov [cs:PXEStack],sp
373 mov [cs:PXEStack+2],ss
374 lss sp,[cs:InitStack]
375 .skip1:
376 popf
378 ; Pre-clear the Status field
379 mov word [es:di],cs
381 ; This works either for the PXENV+ or the !PXE calling
382 ; convention, as long as we ignore CF (which is redundant
383 ; with AX anyway.)
384 push es
385 push di
386 push bx
387 .jump: call 0:0
388 add sp,6
389 mov [cs:PXEStatus],ax
391 pushf
393 dec word [cs:PXEStackLock]
394 jns .skip2
395 lss sp,[cs:PXEStack]
396 .skip2:
397 popf
399 mov bp,sp
400 and ax,ax
401 setnz [bp+32] ; If AX != 0 set CF on return
403 ; This clobbers the AX return, but we already saved it into
404 ; the PXEStatus variable.
405 popad
407 ; If the call failed, it could return.
408 cmp bx,PXENV_RESTART_TFTP
409 jz .enable_timer
410 cmp bx,PXENV_FILE_EXEC
411 jnz .pop_flags
413 .enable_timer:
414 call timer_init
416 .pop_flags:
417 popfd ; Restore flags (incl. IF, DF)
420 ; Must be after function def due to NASM bug
421 global PXEEntry
422 PXEEntry equ pxenv.jump+1
425 ; The PXEStackLock keeps us from switching stacks if we take an interrupt
426 ; (which ends up calling pxenv) while we are already on the PXE stack.
427 ; It will be -1 normally, 0 inside a PXE call, and a positive value
428 ; inside a *nested* PXE call.
430 section .data16
431 alignb 2
432 PXEStackLock dw -1
434 section .bss16
435 alignb 2
436 PXEStatus resb 2
438 section .text16
440 ; Invoke INT 1Ah on the PXE stack. This is used by the "Plan C" method
441 ; for finding the PXE entry point.
443 global pxe_int1a
444 pxe_int1a:
445 mov [cs:PXEStack],sp
446 mov [cs:PXEStack+2],ss
447 lss sp,[cs:InitStack]
449 int 1Ah ; May trash registers
451 lss sp,[cs:PXEStack]
455 ; Special unload for gPXE: this switches the InitStack from
456 ; gPXE to the ROM PXE stack.
458 %if GPXE
459 global gpxe_unload
460 gpxe_unload:
461 mov bx,PXENV_FILE_EXIT_HOOK
462 mov di,pxe_file_exit_hook
463 call pxenv
464 jc .plain
466 ; Now we actually need to exit back to gPXE, which will
467 ; give control back to us on the *new* "original stack"...
468 pushfd
469 push ds
470 push es
471 mov [PXEStack],sp
472 mov [PXEStack+2],ss
473 lss sp,[InitStack]
474 pop gs
475 pop fs
476 pop es
477 pop ds
478 popad
479 popfd
480 xor ax,ax
481 retf
482 .resume:
485 ; gPXE will have a stack frame looking much like our
486 ; InitStack, except it has a magic cookie at the top,
487 ; and the segment registers are in reverse order.
488 pop eax
489 pop ax
490 pop bx
491 pop cx
492 pop dx
493 push ax
494 push bx
495 push cx
496 push dx
497 mov [cs:InitStack],sp
498 mov [cs:InitStack+2],ss
499 lss sp,[cs:PXEStack]
500 pop es
501 pop ds
502 popfd
504 .plain:
507 writestr_early:
508 pm_call pm_writestr
511 pollchar:
512 pm_call pm_pollchar
515 getchar:
516 pm_call pm_getchar
519 section .data16
520 alignz 4
521 pxe_file_exit_hook:
522 .status: dw 0
523 .offset: dw gpxe_unload.resume
524 .seg: dw 0
525 %endif
527 section .text16
529 ; -----------------------------------------------------------------------------
530 ; PXE modules
531 ; -----------------------------------------------------------------------------
533 %if IS_LPXELINUX
534 %include "pxeisr.inc"
535 %endif
537 ; -----------------------------------------------------------------------------
538 ; Common modules
539 ; -----------------------------------------------------------------------------
541 %include "common.inc" ; Universal modules
543 ; -----------------------------------------------------------------------------
544 ; Begin data section
545 ; -----------------------------------------------------------------------------
547 section .data16
549 global copyright_str, syslinux_banner
550 copyright_str db 'Copyright (C) 1994-'
551 asciidec YEAR
552 db ' H. Peter Anvin et al', CR, LF, 0
553 err_bootfailed db CR, LF, 'Boot failed: press a key to retry, or wait for reset...', CR, LF, 0
554 bailmsg equ err_bootfailed
555 localboot_msg db 'Booting from local disk...', CR, LF, 0
556 syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', MY_TYPE, ' '
557 db DATE_STR, ' ', 0
560 ; Misc initialized (data) variables
562 section .data16
563 global KeepPXE
564 KeepPXE db 0 ; Should PXE be kept around?
566 section .bss16
567 global OrigFDCTabPtr
568 OrigFDCTabPtr resd 1 ; Keep bios_cleanup_hardware() honest