PXELINUX: call open_config() function before loading 32-bit environment
[syslinux.git] / core / pxelinux.asm
blob38e1319ee68f4459988ce8946e20b587fcb7241b
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
43 ; The following structure is used for "virtual kernels"; i.e. LILO-style
44 ; option labels. The options we permit here are `kernel' and `append
45 ; Since there is no room in the bottom 64K for all of these, we
46 ; stick them in high memory and copy them down before we need them.
48 struc vkernel
49 vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
50 vk_rname: resb FILENAME_MAX ; Real name
51 vk_ipappend: resb 1 ; "IPAPPEND" flag
52 vk_type: resb 1 ; Type of file
53 vk_appendlen: resw 1
54 alignb 4
55 vk_append: resb max_cmd_len+1 ; Command line
56 alignb 4
57 vk_end: equ $ ; Should be <= vk_size
58 endstruc
61 ; ---------------------------------------------------------------------------
62 ; BEGIN CODE
63 ; ---------------------------------------------------------------------------
66 ; Memory below this point is reserved for the BIOS and the MBR
68 section .earlybss
69 global trackbuf
70 trackbufsize equ 8192
71 trackbuf resb trackbufsize ; Track buffer goes here
72 ; ends at 2800h
74 ; These fields save information from before the time
75 ; .bss is zeroed... must be in .earlybss
76 global InitStack
77 InitStack resd 1
79 section .bss16
80 alignb FILENAME_MAX
81 PXEStack resd 1 ; Saved stack during PXE call
83 alignb 4
84 global DHCPMagic, RebootTime, APIVer
85 RebootTime resd 1 ; Reboot timeout, if set by option
86 StrucPtr resw 2 ; Pointer to PXENV+ or !PXE structure
87 APIVer resw 1 ; PXE API version found
88 LocalBootType resw 1 ; Local boot return code
89 DHCPMagic resb 1 ; PXELINUX magic flags
91 section .text16
92 StackBuf equ STACK_TOP-44 ; Base of stack if we use our own
93 StackHome equ StackBuf
95 ; PXE loads the whole file, but assume it can't be more
96 ; than (384-31)K in size.
97 MaxLMA equ 384*1024
100 ; Primary entry point.
102 bootsec equ $
103 _start:
104 jmp 0:_start1 ; Canonicalize the address and skip
105 ; the patch header
108 ; Patch area for adding hardwired DHCP options
110 align 4
112 hcdhcp_magic dd 0x2983c8ac ; Magic number
113 hcdhcp_len dd 7*4 ; Size of this structure
114 hcdhcp_flags dd 0 ; Reserved for the future
115 ; Parameters to be parsed before the ones from PXE
116 bdhcp_offset dd 0 ; Offset (entered by patcher)
117 bdhcp_len dd 0 ; Length (entered by patcher)
118 ; Parameters to be parsed *after* the ones from PXE
119 adhcp_offset dd 0 ; Offset (entered by patcher)
120 adhcp_len dd 0 ; Length (entered by patcher)
122 _start1:
123 pushfd ; Paranoia... in case of return to PXE
124 pushad ; ... save as much state as possible
125 push ds
126 push es
127 push fs
128 push gs
130 cld ; Copy upwards
131 xor ax,ax
132 mov ds,ax
133 mov es,ax
135 %if 0 ; debugging code only... not intended for production use
136 ; Clobber the stack segment, to test for specific pathologies
137 mov di,STACK_BASE
138 mov cx,STACK_LEN >> 1
139 mov ax,0xf4f4
140 rep stosw
142 ; Clobber the tail of the 64K segment, too
143 extern __bss1_end
144 mov di,__bss1_end
145 sub cx,di ; CX = 0 previously
146 shr cx,1
147 rep stosw
148 %endif
150 ; That is all pushed onto the PXE stack. Save the pointer
151 ; to it and switch to an internal stack.
152 mov [InitStack],sp
153 mov [InitStack+2],ss
155 lss esp,[BaseStack]
156 sti ; Stack set up and ready
158 ; Move the hardwired DHCP options (if present) to a safe place...
160 bdhcp_copy:
161 mov cx,[bdhcp_len]
162 mov ax,trackbufsize/2
163 jcxz .none
164 cmp cx,ax
165 jbe .oksize
166 mov cx,ax
167 mov [bdhcp_len],ax
168 .oksize:
169 mov eax,[bdhcp_offset]
170 add eax,_start
171 mov si,ax
172 and si,000Fh
173 shr eax,4
174 push ds
175 mov ds,ax
176 mov di,trackbuf
177 add cx,3
178 shr cx,2
179 rep movsd
180 pop ds
181 .none:
183 adhcp_copy:
184 mov cx,[adhcp_len]
185 mov ax,trackbufsize/2
186 jcxz .none
187 cmp cx,ax
188 jbe .oksize
189 mov cx,ax
190 mov [adhcp_len],ax
191 .oksize:
192 mov eax,[adhcp_offset]
193 add eax,_start
194 mov si,ax
195 and si,000Fh
196 shr eax,4
197 push ds
198 mov ds,ax
199 mov di,trackbuf+trackbufsize/2
200 add cx,3
201 shr cx,2
202 rep movsd
203 pop ds
204 .none:
207 ; Initialize screen (if we're using one)
209 %include "init.inc"
212 ; Tell the user we got this far
214 mov si,syslinux_banner
215 call writestr_early
217 mov si,copyright_str
218 call writestr_early
221 ; do fs initialize
223 mov eax,ROOT_FS_OPS
224 xor ebp,ebp
225 pm_call fs_init
227 section .rodata
228 alignz 4
229 ROOT_FS_OPS:
230 extern pxe_fs_ops
231 dd pxe_fs_ops
232 dd 0
235 section .text16
237 ; Initialize the idle mechanism
239 call reset_idle
242 ; Now we're all set to start with our *real* business. First load the
243 ; configuration file (if any) and parse it.
245 ; In previous versions I avoided using 32-bit registers because of a
246 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
247 ; random. I figure, though, that if there are any of those still left
248 ; they probably won't be trying to install Linux on them...
250 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
251 ; to take'm out. In fact, we may want to put them back if we're going
252 ; to boot ELKS at some point.
256 ; Linux kernel loading code is common. However, we need to define
257 ; a couple of helper macros...
260 ; Unload PXE stack
261 %define HAVE_UNLOAD_PREP
262 %macro UNLOAD_PREP 0
263 pm_call unload_pxe
264 %endmacro
267 ; Open configuration file. ldlinux.c32 needs ConfigName to be set - so we need
268 ; to call open_config() before loading it.
270 ; Note: We don't need to check return value of open_config() function. It will
271 ; call kaboom() on failure.
273 extern open_config
274 pm_call open_config
277 ; Jump to 32-bit ELF space
279 pm_call load_env32
280 jmp kaboom ; load_env32() shouldn't return. If it does, then kaboom!
282 print_hello:
283 enter_command:
284 auto_boot:
285 pm_call hello
287 ; As core/ui.inc used to be included here in core/pxelinux.asm, and it's no
288 ; longer used, its global variables that were previously used by
289 ; core/pxelinux.asm are now declared here.
290 section .bss16
291 alignb 4
292 Kernel_EAX resd 1
293 Kernel_SI resw 1
295 section .bss16
296 global CmdOptPtr, KbdMap
297 alignb 4
298 ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
299 ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
300 KernelExtPtr resw 1 ; During search, final null pointer
301 CmdOptPtrj resw 1 ; Pointer to first option on cmd line
302 KbdFlags resb 1 ; Check for keyboard escapes
303 FuncFlag resb 1 ; Escape sequences received from keyboard
304 KernelType resb 1 ; Kernel type, from vkernel, if known
305 KbdMap resb 256 ; Keyboard map
306 global KernelName
307 KernelName resb FILENAME_MAX ; Mangled name for kernel
308 section .config
309 global PXERetry
310 PXERetry dw 0 ; Extra PXE retries
311 section .data16
312 global SerialNotice
313 SerialNotice db 1 ; Only print this once
314 extern IPOption
315 global IPAppends, numIPAppends
316 alignz 2
317 IPAppends dw IPOption
318 numIPAppends equ ($-IPAppends)/2
320 section .text16
322 ; COMBOOT-loading code
323 %include "comboot.inc"
324 %include "com32.inc"
326 ; Hardware cleanup common code
327 %include "localboot.inc"
329 section .text16
330 align 4
333 ; kaboom: write a message and bail out. Wait for quite a while,
334 ; or a user keypress, then do a hard reboot.
336 ; Note: use BIOS_timer here; we may not have jiffies set up.
338 global kaboom
339 kaboom:
340 RESET_STACK_AND_SEGS AX
341 .patch: mov si,bailmsg
342 call writestr_early ; Returns with AL = 0
343 .drain: call pollchar
344 jz .drained
345 call getchar
346 jmp short .drain
347 .drained:
348 mov edi,[RebootTime]
349 mov al,[DHCPMagic]
350 and al,09h ; Magic+Timeout
351 cmp al,09h
352 je .time_set
353 mov edi,REBOOT_TIME
354 .time_set:
355 mov cx,18
356 .wait1: push cx
357 mov ecx,edi
358 .wait2: mov dx,[BIOS_timer]
359 .wait3: call pollchar
360 jnz .keypress
361 call do_idle
362 cmp dx,[BIOS_timer]
363 je .wait3
364 loop .wait2,ecx
365 mov al,'.'
366 pm_call pm_writechr
367 pop cx
368 loop .wait1
369 .keypress:
370 pm_call crlf
371 mov word [BIOS_magic],0 ; Cold reboot
372 jmp 0F000h:0FFF0h ; Reset vector address
375 ; pxenv
377 ; This is the main PXENV+/!PXE entry point, using the PXENV+
378 ; calling convention. This is a separate local routine so
379 ; we can hook special things from it if necessary. In particular,
380 ; some PXE stacks seem to not like being invoked from anything but
381 ; the initial stack, so humour it.
383 ; While we're at it, save and restore all registers.
385 global pxenv
386 pxenv:
387 pushfd
388 pushad
390 ; We may be removing ourselves from memory
391 cmp bx,0073h ; PXENV_RESTART_TFTP
392 jz .disable_timer
393 cmp bx,00E5h ; gPXE PXENV_FILE_EXEC
394 jnz .store_stack
396 .disable_timer:
397 call timer_cleanup
399 .store_stack:
400 mov [cs:PXEStack],sp
401 mov [cs:PXEStack+2],ss
402 lss sp,[cs:InitStack]
404 ; Pre-clear the Status field
405 mov word [es:di],cs
407 ; This works either for the PXENV+ or the !PXE calling
408 ; convention, as long as we ignore CF (which is redundant
409 ; with AX anyway.)
410 push es
411 push di
412 push bx
413 .jump: call 0:0
414 add sp,6
415 mov [cs:PXEStatus],ax
417 lss sp,[cs:PXEStack]
419 mov bp,sp
420 and ax,ax
421 setnz [bp+32] ; If AX != 0 set CF on return
423 ; This clobbers the AX return, but we already saved it into
424 ; the PXEStatus variable.
425 popad
427 ; If the call failed, it could return.
428 cmp bx,0073h
429 jz .enable_timer
430 cmp bx,00E5h
431 jnz .pop_flags
433 .enable_timer:
434 call timer_init
436 .pop_flags:
437 popfd ; Restore flags (incl. IF, DF)
440 ; Must be after function def due to NASM bug
441 global PXEEntry
442 PXEEntry equ pxenv.jump+1
444 section .bss16
445 alignb 2
446 PXEStatus resb 2
449 section .text16
451 ; Invoke INT 1Ah on the PXE stack. This is used by the "Plan C" method
452 ; for finding the PXE entry point.
454 global pxe_int1a
455 pxe_int1a:
456 mov [cs:PXEStack],sp
457 mov [cs:PXEStack+2],ss
458 lss sp,[cs:InitStack]
460 int 1Ah ; May trash registers
462 lss sp,[cs:PXEStack]
466 ; Special unload for gPXE: this switches the InitStack from
467 ; gPXE to the ROM PXE stack.
469 %if GPXE
470 global gpxe_unload
471 gpxe_unload:
472 mov bx,PXENV_FILE_EXIT_HOOK
473 mov di,pxe_file_exit_hook
474 call pxenv
475 jc .plain
477 ; Now we actually need to exit back to gPXE, which will
478 ; give control back to us on the *new* "original stack"...
479 pushfd
480 push ds
481 push es
482 mov [PXEStack],sp
483 mov [PXEStack+2],ss
484 lss sp,[InitStack]
485 pop gs
486 pop fs
487 pop es
488 pop ds
489 popad
490 popfd
491 xor ax,ax
492 retf
493 .resume:
496 ; gPXE will have a stack frame looking much like our
497 ; InitStack, except it has a magic cookie at the top,
498 ; and the segment registers are in reverse order.
499 pop eax
500 pop ax
501 pop bx
502 pop cx
503 pop dx
504 push ax
505 push bx
506 push cx
507 push dx
508 mov [cs:InitStack],sp
509 mov [cs:InitStack+2],ss
510 lss sp,[cs:PXEStack]
511 pop es
512 pop ds
513 popfd
515 .plain:
518 writestr_early:
519 pm_call pm_writestr
522 pollchar:
523 pm_call pm_pollchar
526 getchar:
527 pm_call pm_getchar
530 section .data16
531 alignz 4
532 pxe_file_exit_hook:
533 .status: dw 0
534 .offset: dw gpxe_unload.resume
535 .seg: dw 0
536 %endif
538 section .text16
540 ; -----------------------------------------------------------------------------
541 ; Common modules
542 ; -----------------------------------------------------------------------------
544 %include "common.inc" ; Universal modules
546 ; -----------------------------------------------------------------------------
547 ; Begin data section
548 ; -----------------------------------------------------------------------------
550 section .data16
552 global copyright_str, syslinux_banner
553 copyright_str db ' Copyright (C) 1994-'
554 asciidec YEAR
555 db ' H. Peter Anvin et al', CR, LF, 0
556 err_bootfailed db CR, LF, 'Boot failed: press a key to retry, or wait for reset...', CR, LF, 0
557 bailmsg equ err_bootfailed
558 localboot_msg db 'Booting from local disk...', CR, LF, 0
559 syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
562 ; Misc initialized (data) variables
564 section .data16
565 global KeepPXE
566 KeepPXE db 0 ; Should PXE be kept around?
569 ; IP information. Note that the field are in the same order as the
570 ; Linux kernel expects in the ip= option.
572 section .bss16
573 alignb 4
574 global IPInfo
575 IPInfo:
576 .IPv4 resd 1 ; IPv4 information
577 .MyIP resd 1 ; My IP address
578 .ServerIP resd 1
579 .GatewayIP resd 1
580 .Netmask resd 1