acpi: moving flags_to_string to base code
[syslinux.git] / core / pxelinux.asm
blobe8818a6c87a8aadb894eb072c281bafcdaa86093
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 ; Load configuration file
269 pm_call pm_load_config
270 jz no_config_file
273 ; Now we have the config file open. Parse the config file and
274 ; run the user interface.
276 %include "ui.inc"
279 ; Boot to the local disk by returning the appropriate PXE magic.
280 ; AX contains the appropriate return code.
282 local_boot:
283 push cs
284 pop ds
285 mov [LocalBootType],ax
286 call vgaclearmode
287 mov si,localboot_msg
288 call writestr_early
289 ; Restore the environment we were called with
290 pm_call reset_pxe
291 call cleanup_hardware
292 lss sp,[InitStack]
293 pop gs
294 pop fs
295 pop es
296 pop ds
297 popad
298 mov ax,[cs:LocalBootType]
299 cmp ax,-1 ; localboot -1 == INT 18h
300 je .int18
301 popfd
302 retf ; Return to PXE
303 .int18:
304 popfd
305 int 18h
306 jmp 0F000h:0FFF0h
310 ; kaboom: write a message and bail out. Wait for quite a while,
311 ; or a user keypress, then do a hard reboot.
313 ; Note: use BIOS_timer here; we may not have jiffies set up.
315 global kaboom
316 kaboom:
317 RESET_STACK_AND_SEGS AX
318 .patch: mov si,bailmsg
319 call writestr_early ; Returns with AL = 0
320 .drain: call pollchar
321 jz .drained
322 call getchar
323 jmp short .drain
324 .drained:
325 mov edi,[RebootTime]
326 mov al,[DHCPMagic]
327 and al,09h ; Magic+Timeout
328 cmp al,09h
329 je .time_set
330 mov edi,REBOOT_TIME
331 .time_set:
332 mov cx,18
333 .wait1: push cx
334 mov ecx,edi
335 .wait2: mov dx,[BIOS_timer]
336 .wait3: call pollchar
337 jnz .keypress
338 call do_idle
339 cmp dx,[BIOS_timer]
340 je .wait3
341 loop .wait2,ecx
342 mov al,'.'
343 call writechr
344 pop cx
345 loop .wait1
346 .keypress:
347 call crlf
348 mov word [BIOS_magic],0 ; Cold reboot
349 jmp 0F000h:0FFF0h ; Reset vector address
353 ; pxenv
355 ; This is the main PXENV+/!PXE entry point, using the PXENV+
356 ; calling convention. This is a separate local routine so
357 ; we can hook special things from it if necessary. In particular,
358 ; some PXE stacks seem to not like being invoked from anything but
359 ; the initial stack, so humour it.
361 ; While we're at it, save and restore all registers.
363 global pxenv
364 pxenv:
365 pushfd
366 pushad
368 ; We may be removing ourselves from memory
369 cmp bx,0073h ; PXENV_RESTART_TFTP
370 jz .disable_timer
371 cmp bx,00E5h ; gPXE PXENV_FILE_EXEC
372 jnz .store_stack
374 .disable_timer:
375 call timer_cleanup
377 .store_stack:
378 mov [cs:PXEStack],sp
379 mov [cs:PXEStack+2],ss
380 lss sp,[cs:InitStack]
382 ; Pre-clear the Status field
383 mov word [es:di],cs
385 ; This works either for the PXENV+ or the !PXE calling
386 ; convention, as long as we ignore CF (which is redundant
387 ; with AX anyway.)
388 push es
389 push di
390 push bx
391 .jump: call 0:0
392 add sp,6
393 mov [cs:PXEStatus],ax
395 lss sp,[cs:PXEStack]
397 mov bp,sp
398 and ax,ax
399 setnz [bp+32] ; If AX != 0 set CF on return
401 ; This clobbers the AX return, but we already saved it into
402 ; the PXEStatus variable.
403 popad
405 ; If the call failed, it could return.
406 cmp bx,0073h
407 jz .enable_timer
408 cmp bx,00E5h
409 jnz .pop_flags
411 .enable_timer:
412 call timer_init
414 .pop_flags:
415 popfd ; Restore flags (incl. IF, DF)
418 ; Must be after function def due to NASM bug
419 global PXEEntry
420 PXEEntry equ pxenv.jump+1
422 section .bss16
423 alignb 2
424 PXEStatus resb 2
427 section .text16
429 ; Invoke INT 1Ah on the PXE stack. This is used by the "Plan C" method
430 ; for finding the PXE entry point.
432 global pxe_int1a
433 pxe_int1a:
434 mov [cs:PXEStack],sp
435 mov [cs:PXEStack+2],ss
436 lss sp,[cs:InitStack]
438 int 1Ah ; May trash registers
440 lss sp,[cs:PXEStack]
444 ; Special unload for gPXE: this switches the InitStack from
445 ; gPXE to the ROM PXE stack.
447 %if GPXE
448 global gpxe_unload
449 gpxe_unload:
450 mov bx,PXENV_FILE_EXIT_HOOK
451 mov di,pxe_file_exit_hook
452 call pxenv
453 jc .plain
455 ; Now we actually need to exit back to gPXE, which will
456 ; give control back to us on the *new* "original stack"...
457 pushfd
458 push ds
459 push es
460 mov [PXEStack],sp
461 mov [PXEStack+2],ss
462 lss sp,[InitStack]
463 pop gs
464 pop fs
465 pop es
466 pop ds
467 popad
468 popfd
469 xor ax,ax
470 retf
471 .resume:
474 ; gPXE will have a stack frame looking much like our
475 ; InitStack, except it has a magic cookie at the top,
476 ; and the segment registers are in reverse order.
477 pop eax
478 pop ax
479 pop bx
480 pop cx
481 pop dx
482 push ax
483 push bx
484 push cx
485 push dx
486 mov [cs:InitStack],sp
487 mov [cs:InitStack+2],ss
488 lss sp,[cs:PXEStack]
489 pop es
490 pop ds
491 popfd
493 .plain:
496 section .data16
497 alignz 4
498 pxe_file_exit_hook:
499 .status: dw 0
500 .offset: dw gpxe_unload.resume
501 .seg: dw 0
502 %endif
504 section .text16
506 ; -----------------------------------------------------------------------------
507 ; Common modules
508 ; -----------------------------------------------------------------------------
510 %include "common.inc" ; Universal modules
511 %include "writestr.inc" ; String output
512 writestr_early equ writestr
513 %include "writehex.inc" ; Hexadecimal output
514 %include "rawcon.inc" ; Console I/O w/o using the console functions
516 ; -----------------------------------------------------------------------------
517 ; Begin data section
518 ; -----------------------------------------------------------------------------
520 section .data16
522 copyright_str db ' Copyright (C) 1994-'
523 asciidec YEAR
524 db ' H. Peter Anvin et al', CR, LF, 0
525 err_bootfailed db CR, LF, 'Boot failed: press a key to retry, or wait for reset...', CR, LF, 0
526 bailmsg equ err_bootfailed
527 localboot_msg db 'Booting from local disk...', CR, LF, 0
528 syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
531 ; Config file keyword table
533 %include "keywords.inc"
536 ; Extensions to search for (in *forward* order).
537 ; (.bs and .bss16 are disabled for PXELINUX, since they are not supported)
539 alignz 4
540 exten_table: db '.cbt' ; COMBOOT (specific)
541 db '.0', 0, 0 ; PXE bootstrap program
542 db '.com' ; COMBOOT (same as DOS)
543 db '.c32' ; COM32
544 exten_table_end:
545 dd 0, 0 ; Need 8 null bytes here
548 ; Misc initialized (data) variables
550 section .data16
551 global KeepPXE
552 KeepPXE db 0 ; Should PXE be kept around?
555 ; IP information. Note that the field are in the same order as the
556 ; Linux kernel expects in the ip= option.
558 section .bss16
559 alignb 4
560 global IPInfo
561 IPInfo:
562 .IPv4 resd 1 ; IPv4 information
563 .MyIP resd 1 ; My IP address
564 .ServerIP resd 1
565 .GatewayIP resd 1
566 .Netmask resd 1