com32: mark the invalid SEG() as __unlikely()
[syslinux/sherbszt.git] / core / pxelinux.asm
blobef9c723802f4cec8af3604ae09ee1473b053fe84
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 global StackBuf
93 StackBuf equ STACK_TOP-44 ; Base of stack if we use our own
94 StackHome equ StackBuf
96 ; PXE loads the whole file, but assume it can't be more
97 ; than (384-31)K in size.
98 MaxLMA equ 384*1024
101 ; Primary entry point.
103 bootsec equ $
104 _start:
105 jmp 0:_start1 ; Canonicalize the address and skip
106 ; the patch header
109 ; Patch area for adding hardwired DHCP options
111 align 4
113 hcdhcp_magic dd 0x2983c8ac ; Magic number
114 hcdhcp_len dd 7*4 ; Size of this structure
115 hcdhcp_flags dd 0 ; Reserved for the future
116 ; Parameters to be parsed before the ones from PXE
117 bdhcp_offset dd 0 ; Offset (entered by patcher)
118 bdhcp_len dd 0 ; Length (entered by patcher)
119 ; Parameters to be parsed *after* the ones from PXE
120 adhcp_offset dd 0 ; Offset (entered by patcher)
121 adhcp_len dd 0 ; Length (entered by patcher)
123 _start1:
124 pushfd ; Paranoia... in case of return to PXE
125 pushad ; ... save as much state as possible
126 push ds
127 push es
128 push fs
129 push gs
131 cld ; Copy upwards
132 xor ax,ax
133 mov ds,ax
134 mov es,ax
136 %if 0 ; debugging code only... not intended for production use
137 ; Clobber the stack segment, to test for specific pathologies
138 mov di,STACK_BASE
139 mov cx,STACK_LEN >> 1
140 mov ax,0xf4f4
141 rep stosw
143 ; Clobber the tail of the 64K segment, too
144 extern __bss1_end
145 mov di,__bss1_end
146 sub cx,di ; CX = 0 previously
147 shr cx,1
148 rep stosw
149 %endif
151 ; That is all pushed onto the PXE stack. Save the pointer
152 ; to it and switch to an internal stack.
153 mov [InitStack],sp
154 mov [InitStack+2],ss
156 lss esp,[BaseStack]
157 sti ; Stack set up and ready
160 ; Initialize screen (if we're using one)
162 %include "init.inc"
165 ; Tell the user we got this far
167 mov si,syslinux_banner
168 call writestr_early
170 mov si,copyright_str
171 call writestr_early
174 ; do fs initialize
176 mov eax,ROOT_FS_OPS
177 xor ebp,ebp
178 pm_call fs_init
180 section .rodata
181 alignz 4
182 ROOT_FS_OPS:
183 extern pxe_fs_ops
184 dd pxe_fs_ops
185 dd 0
188 section .text16
190 ; Initialize the idle mechanism
192 call reset_idle
195 ; Now we're all set to start with our *real* business. First load the
196 ; configuration file (if any) and parse it.
198 ; In previous versions I avoided using 32-bit registers because of a
199 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
200 ; random. I figure, though, that if there are any of those still left
201 ; they probably won't be trying to install Linux on them...
203 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
204 ; to take'm out. In fact, we may want to put them back if we're going
205 ; to boot ELKS at some point.
209 ; Linux kernel loading code is common. However, we need to define
210 ; a couple of helper macros...
213 ; Unload PXE stack
214 %define HAVE_UNLOAD_PREP
215 %macro UNLOAD_PREP 0
216 pm_call unload_pxe
217 %endmacro
220 ; Open configuration file. ldlinux.c32 needs ConfigName to be set - so we need
221 ; to call open_config() before loading it.
223 ; Note: We don't need to check return value of open_config() function. It will
224 ; call kaboom() on failure.
226 extern open_config
227 pm_call open_config
230 ; Jump to 32-bit ELF space
232 pm_call load_env32
233 jmp kaboom ; load_env32() shouldn't return. If it does, then kaboom!
235 print_hello:
236 enter_command:
237 auto_boot:
238 pm_call hello
241 ; Save hardwired DHCP options. This is done before the C environment
242 ; is initialized, so it has to be done in assembly.
244 %define MAX_DHCP_OPTS 4096
245 bits 32
247 section .savedata
248 global bdhcp_data, adhcp_data
249 bdhcp_data: resb MAX_DHCP_OPTS
250 adhcp_data: resb MAX_DHCP_OPTS
252 section .textnr
253 pm_save_data:
254 mov eax,MAX_DHCP_OPTS
255 movzx ecx,word [bdhcp_len]
256 cmp ecx,eax
257 jna .oksize
258 mov ecx,eax
259 mov [bdhcp_len],ax
260 .oksize:
261 mov esi,[bdhcp_offset]
262 add esi,_start
263 mov edi,bdhcp_data
264 add ecx,3
265 shr ecx,2
266 rep movsd
268 adhcp_copy:
269 movzx ecx,word [adhcp_len]
270 cmp ecx,eax
271 jna .oksize
272 mov ecx,eax
273 mov [adhcp_len],ax
274 .oksize:
275 mov esi,[adhcp_offset]
276 add esi,_start
277 mov edi,adhcp_data
278 add ecx,3
279 shr ecx,2
280 rep movsd
283 bits 16
285 ; As core/ui.inc used to be included here in core/pxelinux.asm, and it's no
286 ; longer used, its global variables that were previously used by
287 ; core/pxelinux.asm are now declared here.
288 section .bss16
289 alignb 4
290 Kernel_EAX resd 1
291 Kernel_SI resw 1
293 section .bss16
294 global CmdOptPtr, KbdMap
295 alignb 4
296 ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
297 ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
298 KernelExtPtr resw 1 ; During search, final null pointer
299 CmdOptPtrj resw 1 ; Pointer to first option on cmd line
300 KbdFlags resb 1 ; Check for keyboard escapes
301 FuncFlag resb 1 ; Escape sequences received from keyboard
302 KernelType resb 1 ; Kernel type, from vkernel, if known
303 KbdMap resb 256 ; Keyboard map
304 global KernelName
305 KernelName resb FILENAME_MAX ; Mangled name for kernel
306 section .config
307 global PXERetry
308 PXERetry dw 0 ; Extra PXE retries
309 section .data16
310 global SerialNotice
311 SerialNotice db 1 ; Only print this once
312 extern IPOption
313 global IPAppends, numIPAppends
314 alignz 2
315 IPAppends dw IPOption
316 numIPAppends equ ($-IPAppends)/2
318 section .text16
320 ; COMBOOT-loading code
322 %include "comboot.inc"
323 %include "com32.inc"
326 ; Boot sector loading code
330 ; Abort loading code
334 ; Hardware cleanup common code
337 %include "localboot.inc"
340 ; kaboom: write a message and bail out. Wait for quite a while,
341 ; or a user keypress, then do a hard reboot.
343 ; Note: use BIOS_timer here; we may not have jiffies set up.
345 global kaboom
346 kaboom:
347 RESET_STACK_AND_SEGS AX
348 .patch: mov si,bailmsg
349 call writestr_early ; Returns with AL = 0
350 .drain: call pollchar
351 jz .drained
352 call getchar
353 jmp short .drain
354 .drained:
355 mov edi,[RebootTime]
356 mov al,[DHCPMagic]
357 and al,09h ; Magic+Timeout
358 cmp al,09h
359 je .time_set
360 mov edi,REBOOT_TIME
361 .time_set:
362 mov cx,18
363 .wait1: push cx
364 mov ecx,edi
365 .wait2: mov dx,[BIOS_timer]
366 .wait3: call pollchar
367 jnz .keypress
368 call do_idle
369 cmp dx,[BIOS_timer]
370 je .wait3
371 loop .wait2,ecx
372 mov al,'.'
373 pm_call pm_writechr
374 pop cx
375 loop .wait1
376 .keypress:
377 pm_call crlf
378 mov word [BIOS_magic],0 ; Cold reboot
379 jmp 0F000h:0FFF0h ; Reset vector address
382 ; pxenv
384 ; This is the main PXENV+/!PXE entry point, using the PXENV+
385 ; calling convention. This is a separate local routine so
386 ; we can hook special things from it if necessary. In particular,
387 ; some PXE stacks seem to not like being invoked from anything but
388 ; the initial stack, so humour it.
390 ; While we're at it, save and restore all registers.
392 global pxenv
393 pxenv:
394 pushfd
395 pushad
397 ; We may be removing ourselves from memory
398 cmp bx,PXENV_RESTART_TFTP
399 jz .disable_timer
400 cmp bx,PXENV_FILE_EXEC
401 jnz .store_stack
403 .disable_timer:
404 call timer_cleanup
406 .store_stack:
407 mov [cs:PXEStack],sp
408 mov [cs:PXEStack+2],ss
409 lss sp,[cs:InitStack]
411 ; Pre-clear the Status field
412 mov word [es:di],cs
414 ; This works either for the PXENV+ or the !PXE calling
415 ; convention, as long as we ignore CF (which is redundant
416 ; with AX anyway.)
417 push es
418 push di
419 push bx
420 .jump: call 0:0
421 add sp,6
422 mov [cs:PXEStatus],ax
424 lss sp,[cs:PXEStack]
426 mov bp,sp
427 and ax,ax
428 setnz [bp+32] ; If AX != 0 set CF on return
430 ; This clobbers the AX return, but we already saved it into
431 ; the PXEStatus variable.
432 popad
434 ; If the call failed, it could return.
435 cmp bx,PXENV_RESTART_TFTP
436 jz .enable_timer
437 cmp bx,PXENV_FILE_EXEC
438 jnz .pop_flags
440 .enable_timer:
441 call timer_init
443 .pop_flags:
444 popfd ; Restore flags (incl. IF, DF)
447 ; Must be after function def due to NASM bug
448 global PXEEntry
449 PXEEntry equ pxenv.jump+1
451 section .bss16
452 alignb 2
453 PXEStatus resb 2
456 section .text16
458 ; Invoke INT 1Ah on the PXE stack. This is used by the "Plan C" method
459 ; for finding the PXE entry point.
461 global pxe_int1a
462 pxe_int1a:
463 mov [cs:PXEStack],sp
464 mov [cs:PXEStack+2],ss
465 lss sp,[cs:InitStack]
467 int 1Ah ; May trash registers
469 lss sp,[cs:PXEStack]
473 ; Special unload for gPXE: this switches the InitStack from
474 ; gPXE to the ROM PXE stack.
476 %if GPXE
477 global gpxe_unload
478 gpxe_unload:
479 mov bx,PXENV_FILE_EXIT_HOOK
480 mov di,pxe_file_exit_hook
481 call pxenv
482 jc .plain
484 ; Now we actually need to exit back to gPXE, which will
485 ; give control back to us on the *new* "original stack"...
486 pushfd
487 push ds
488 push es
489 mov [PXEStack],sp
490 mov [PXEStack+2],ss
491 lss sp,[InitStack]
492 pop gs
493 pop fs
494 pop es
495 pop ds
496 popad
497 popfd
498 xor ax,ax
499 retf
500 .resume:
503 ; gPXE will have a stack frame looking much like our
504 ; InitStack, except it has a magic cookie at the top,
505 ; and the segment registers are in reverse order.
506 pop eax
507 pop ax
508 pop bx
509 pop cx
510 pop dx
511 push ax
512 push bx
513 push cx
514 push dx
515 mov [cs:InitStack],sp
516 mov [cs:InitStack+2],ss
517 lss sp,[cs:PXEStack]
518 pop es
519 pop ds
520 popfd
522 .plain:
525 writestr_early:
526 pm_call pm_writestr
529 pollchar:
530 pm_call pm_pollchar
533 getchar:
534 pm_call pm_getchar
537 section .data16
538 alignz 4
539 pxe_file_exit_hook:
540 .status: dw 0
541 .offset: dw gpxe_unload.resume
542 .seg: dw 0
543 %endif
545 section .text16
547 ; -----------------------------------------------------------------------------
548 ; Common modules
549 ; -----------------------------------------------------------------------------
551 %include "common.inc" ; Universal modules
553 ; -----------------------------------------------------------------------------
554 ; Begin data section
555 ; -----------------------------------------------------------------------------
557 section .data16
559 global copyright_str, syslinux_banner
560 copyright_str db ' Copyright (C) 1994-'
561 asciidec YEAR
562 db ' H. Peter Anvin et al', CR, LF, 0
563 err_bootfailed db CR, LF, 'Boot failed: press a key to retry, or wait for reset...', CR, LF, 0
564 bailmsg equ err_bootfailed
565 localboot_msg db 'Booting from local disk...', CR, LF, 0
566 syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
569 ; Misc initialized (data) variables
571 section .data16
572 global KeepPXE
573 KeepPXE db 0 ; Should PXE be kept around?
576 ; IP information. Note that the field are in the same order as the
577 ; Linux kernel expects in the ip= option.
579 section .bss16
580 alignb 4
581 global IPInfo
582 IPInfo:
583 .IPv4 resd 1 ; IPv4 information
584 .MyIP resd 1 ; My IP address
585 .ServerIP resd 1
586 .GatewayIP resd 1
587 .Netmask resd 1