1 ; -*- fundamental -*- (asm-mode sucks)
2 ; ****************************************************************************
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
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 ; ****************************************************************************
25 ; gPXE extensions support
29 ; Some semi-configurable constants... change on your own risk.
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.
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
55 vk_append: resb max_cmd_len
+1 ; Command line
57 vk_end: equ $
; Should be <= vk_size
61 ; ---------------------------------------------------------------------------
63 ; ---------------------------------------------------------------------------
66 ; Memory below this point is reserved for the BIOS and the MBR
71 trackbuf resb trackbufsize
; Track buffer goes here
74 ; These fields save information from before the time
75 ; .bss is zeroed... must be in .earlybss
81 PXEStack resd
1 ; Saved stack during PXE call
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
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.
100 ; Primary entry point.
104 jmp 0:_start1
; Canonicalize the address and skip
108 ; Patch area for adding hardwired DHCP options
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)
123 pushfd ; Paranoia... in case of return to PXE
124 pushad ; ... save as much state as possible
135 %if
0 ; debugging code only... not intended for production use
136 ; Clobber the stack segment, to test for specific pathologies
138 mov cx,STACK_LEN
>> 1
142 ; Clobber the tail of the 64K segment, too
145 sub cx,di ; CX = 0 previously
150 ; That is all pushed onto the PXE stack. Save the pointer
151 ; to it and switch to an internal stack.
156 sti ; Stack set up and ready
158 ; Move the hardwired DHCP options (if present) to a safe place...
162 mov ax,trackbufsize
/2
169 mov eax,[bdhcp_offset
]
185 mov ax,trackbufsize
/2
192 mov eax,[adhcp_offset
]
199 mov di,trackbuf
+trackbufsize
/2
207 ; Initialize screen (if we're using one)
212 ; Tell the user we got this far
214 mov si,syslinux_banner
237 ; Initialize the idle mechanism
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...
261 %define HAVE_UNLOAD_PREP
267 ; Load configuration file
269 pm_call pm_load_config
273 ; Now we have the config file open. Parse the config file and
274 ; run the user interface.
279 ; Boot to the local disk by returning the appropriate PXE magic.
280 ; AX contains the appropriate return code.
285 mov [LocalBootType
],ax
289 ; Restore the environment we were called with
291 call cleanup_hardware
298 mov ax,[cs:LocalBootType
]
299 cmp ax,-1 ; localboot -1 == INT 18h
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.
317 RESET_STACK_AND_SEGS
AX
318 .
patch: mov si,bailmsg
319 call writestr_early
; Returns with AL = 0
320 .
drain: call pollchar
327 and al,09h ; Magic+Timeout
335 .
wait2: mov dx,[BIOS_timer
]
336 .
wait3: call pollchar
348 mov word [BIOS_magic
],0 ; Cold reboot
349 jmp 0F000h:0FFF0h
; Reset vector address
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.
368 ; We may be removing ourselves from memory
369 cmp bx,0073h ; PXENV_RESTART_TFTP
371 cmp bx,00E5h
; gPXE PXENV_FILE_EXEC
379 mov [cs:PXEStack
+2],ss
380 lss sp,[cs:InitStack
]
382 ; Pre-clear the Status field
385 ; This works either for the PXENV+ or the !PXE calling
386 ; convention, as long as we ignore CF (which is redundant
393 mov [cs:PXEStatus
],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.
405 ; If the call failed, it could return.
415 popfd ; Restore flags (incl. IF, DF)
418 ; Must be after function def due to NASM bug
420 PXEEntry
equ pxenv.jump
+1
429 ; Invoke INT 1Ah on the PXE stack. This is used by the "Plan C" method
430 ; for finding the PXE entry point.
435 mov [cs:PXEStack
+2],ss
436 lss sp,[cs:InitStack
]
438 int 1Ah ; May trash registers
444 ; Special unload for gPXE: this switches the InitStack from
445 ; gPXE to the ROM PXE stack.
450 mov bx,PXENV_FILE_EXIT_HOOK
451 mov di,pxe_file_exit_hook
455 ; Now we actually need to exit back to gPXE, which will
456 ; give control back to us on the *new* "original stack"...
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.
486 mov [cs:InitStack
],sp
487 mov [cs:InitStack
+2],ss
500 .
offset: dw gpxe_unload.resume
506 ; -----------------------------------------------------------------------------
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 ; -----------------------------------------------------------------------------
518 ; -----------------------------------------------------------------------------
522 copyright_str
db ' Copyright (C) 1994-'
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)
540 exten_table: db '.cbt' ; COMBOOT (specific)
541 db '.0', 0, 0 ; PXE bootstrap program
542 db '.com' ; COMBOOT (same as DOS)
545 dd 0, 0 ; Need 8 null bytes here
548 ; Misc initialized (data) variables
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.
562 .IPv4 resd
1 ; IPv4 information
563 .MyIP resd
1 ; My IP address