Adding upstream version 6.01~pre5+dfsg.
[syslinux-debian/hramrach.git] / core / pxelinux.asm
blob3e2bc0a1c5c8dfcbc7b2a045d03c23db535503c7
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, StrucPtr, BIOSName
66 RebootTime resd 1 ; Reboot timeout, if set by option
67 StrucPtr resw 2 ; Pointer to PXENV+ or !PXE structure
68 LocalBootType resw 1 ; Local boot return code
69 DHCPMagic resb 1 ; PXELINUX magic flags
70 BIOSName resw 1 ; Dummy variable - always 0
72 section .text16
73 global StackBuf
74 StackBuf equ STACK_TOP-44 ; Base of stack if we use our own
75 StackHome equ StackBuf
77 ; PXE loads the whole file, but assume it can't be more
78 ; than (384-31)K in size.
79 MaxLMA equ 384*1024
82 ; Primary entry point.
84 bootsec equ $
85 _start:
86 jmp 0:_start1 ; Canonicalize the address and skip
87 ; the patch header
90 ; Patch area for adding hardwired DHCP options
92 align 4
94 hcdhcp_magic dd 0x2983c8ac ; Magic number
95 hcdhcp_len dd 7*4 ; Size of this structure
96 hcdhcp_flags dd 0 ; Reserved for the future
97 ; Parameters to be parsed before the ones from PXE
98 bdhcp_offset dd 0 ; Offset (entered by patcher)
99 bdhcp_len dd 0 ; Length (entered by patcher)
100 ; Parameters to be parsed *after* the ones from PXE
101 adhcp_offset dd 0 ; Offset (entered by patcher)
102 adhcp_len dd 0 ; Length (entered by patcher)
104 _start1:
105 pushfd ; Paranoia... in case of return to PXE
106 pushad ; ... save as much state as possible
107 push ds
108 push es
109 push fs
110 push gs
112 cld ; Copy upwards
113 xor ax,ax
114 mov ds,ax
115 mov es,ax
117 %if 0 ; debugging code only... not intended for production use
118 ; Clobber the stack segment, to test for specific pathologies
119 mov di,STACK_BASE
120 mov cx,STACK_LEN >> 1
121 mov ax,0xf4f4
122 rep stosw
124 ; Clobber the tail of the 64K segment, too
125 extern __bss1_end
126 mov di,__bss1_end
127 sub cx,di ; CX = 0 previously
128 shr cx,1
129 rep stosw
130 %endif
132 ; That is all pushed onto the PXE stack. Save the pointer
133 ; to it and switch to an internal stack.
134 mov [InitStack],sp
135 mov [InitStack+2],ss
137 lss esp,[BaseStack]
138 sti ; Stack set up and ready
141 ; Initialize screen (if we're using one)
143 %include "init.inc"
146 ; Tell the user we got this far
148 mov si,syslinux_banner
149 call writestr_early
151 mov si,copyright_str
152 call writestr_early
155 ; do fs initialize
157 mov eax,ROOT_FS_OPS
158 xor ebp,ebp
159 pm_call pm_fs_init
161 section .rodata
162 alignz 4
163 ROOT_FS_OPS:
164 extern pxe_fs_ops
165 dd pxe_fs_ops
166 dd 0
169 section .text16
171 ; Initialize the idle mechanism
173 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 ; COMBOOT-loading code
277 %include "comboot.inc"
278 %include "com32.inc"
281 ; Boot sector loading code
285 ; Abort loading code
289 ; Hardware cleanup common code
292 section .text16
293 global local_boot16:function hidden
294 local_boot16:
295 mov [LocalBootType],ax
296 lss sp,[InitStack]
297 pop gs
298 pop fs
299 pop es
300 pop ds
301 popad
302 mov ax,[cs:LocalBootType]
303 cmp ax,-1 ; localboot -1 == INT 18h
304 je .int18
305 popfd
306 retf ; Return to PXE
307 .int18:
308 popfd
309 int 18h
310 jmp 0F000h:0FFF0h
314 ; kaboom: write a message and bail out. Wait for quite a while,
315 ; or a user keypress, then do a hard reboot.
317 ; Note: use BIOS_timer here; we may not have jiffies set up.
319 global kaboom
320 kaboom:
321 RESET_STACK_AND_SEGS AX
322 .patch: mov si,bailmsg
323 call writestr_early ; Returns with AL = 0
324 .drain: call pollchar
325 jz .drained
326 call getchar
327 jmp short .drain
328 .drained:
329 mov edi,[RebootTime]
330 mov al,[DHCPMagic]
331 and al,09h ; Magic+Timeout
332 cmp al,09h
333 je .time_set
334 mov edi,REBOOT_TIME
335 .time_set:
336 mov cx,18
337 .wait1: push cx
338 mov ecx,edi
339 .wait2: mov dx,[BIOS_timer]
340 .wait3: call pollchar
341 jnz .keypress
342 call do_idle
343 cmp dx,[BIOS_timer]
344 je .wait3
345 loop .wait2,ecx
346 mov al,'.'
347 pm_call pm_writechr
348 pop cx
349 loop .wait1
350 .keypress:
351 pm_call crlf
352 mov word [BIOS_magic],0 ; Cold reboot
353 jmp 0F000h:0FFF0h ; Reset vector address
356 ; pxenv
358 ; This is the main PXENV+/!PXE entry point, using the PXENV+
359 ; calling convention. This is a separate local routine so
360 ; we can hook special things from it if necessary. In particular,
361 ; some PXE stacks seem to not like being invoked from anything but
362 ; the initial stack, so humour it.
364 ; While we're at it, save and restore all registers.
366 global pxenv
367 pxenv:
368 pushfd
369 pushad
371 ; We may be removing ourselves from memory
372 cmp bx,PXENV_RESTART_TFTP
373 jz .disable_timer
374 cmp bx,PXENV_FILE_EXEC
375 jnz .store_stack
377 .disable_timer:
378 call bios_timer_cleanup
380 .store_stack:
381 pushf
383 inc word [cs:PXEStackLock]
384 jnz .skip1
385 mov [cs:PXEStack],sp
386 mov [cs:PXEStack+2],ss
387 lss sp,[cs:InitStack]
388 .skip1:
389 popf
391 ; Pre-clear the Status field
392 mov word [es:di],cs
394 ; This works either for the PXENV+ or the !PXE calling
395 ; convention, as long as we ignore CF (which is redundant
396 ; with AX anyway.)
397 push es
398 push di
399 push bx
400 .jump: call 0:0
401 add sp,6
402 mov [cs:PXEStatus],ax
404 pushf
406 dec word [cs:PXEStackLock]
407 jns .skip2
408 lss sp,[cs:PXEStack]
409 .skip2:
410 popf
412 mov bp,sp
413 and ax,ax
414 setnz [bp+32] ; If AX != 0 set CF on return
416 ; This clobbers the AX return, but we already saved it into
417 ; the PXEStatus variable.
418 popad
420 ; If the call failed, it could return.
421 cmp bx,PXENV_RESTART_TFTP
422 jz .enable_timer
423 cmp bx,PXENV_FILE_EXEC
424 jnz .pop_flags
426 .enable_timer:
427 call timer_init
429 .pop_flags:
430 popfd ; Restore flags (incl. IF, DF)
433 ; Must be after function def due to NASM bug
434 global PXEEntry
435 PXEEntry equ pxenv.jump+1
438 ; The PXEStackLock keeps us from switching stacks if we take an interrupt
439 ; (which ends up calling pxenv) while we are already on the PXE stack.
440 ; It will be -1 normally, 0 inside a PXE call, and a positive value
441 ; inside a *nested* PXE call.
443 section .data16
444 alignb 2
445 PXEStackLock dw -1
447 section .bss16
448 alignb 2
449 PXEStatus resb 2
451 section .text16
453 ; Invoke INT 1Ah on the PXE stack. This is used by the "Plan C" method
454 ; for finding the PXE entry point.
456 global pxe_int1a
457 pxe_int1a:
458 mov [cs:PXEStack],sp
459 mov [cs:PXEStack+2],ss
460 lss sp,[cs:InitStack]
462 int 1Ah ; May trash registers
464 lss sp,[cs:PXEStack]
468 ; Special unload for gPXE: this switches the InitStack from
469 ; gPXE to the ROM PXE stack.
471 %if GPXE
472 global gpxe_unload
473 gpxe_unload:
474 mov bx,PXENV_FILE_EXIT_HOOK
475 mov di,pxe_file_exit_hook
476 call pxenv
477 jc .plain
479 ; Now we actually need to exit back to gPXE, which will
480 ; give control back to us on the *new* "original stack"...
481 pushfd
482 push ds
483 push es
484 mov [PXEStack],sp
485 mov [PXEStack+2],ss
486 lss sp,[InitStack]
487 pop gs
488 pop fs
489 pop es
490 pop ds
491 popad
492 popfd
493 xor ax,ax
494 retf
495 .resume:
498 ; gPXE will have a stack frame looking much like our
499 ; InitStack, except it has a magic cookie at the top,
500 ; and the segment registers are in reverse order.
501 pop eax
502 pop ax
503 pop bx
504 pop cx
505 pop dx
506 push ax
507 push bx
508 push cx
509 push dx
510 mov [cs:InitStack],sp
511 mov [cs:InitStack+2],ss
512 lss sp,[cs:PXEStack]
513 pop es
514 pop ds
515 popfd
517 .plain:
520 writestr_early:
521 pm_call pm_writestr
524 pollchar:
525 pm_call pm_pollchar
528 getchar:
529 pm_call pm_getchar
532 section .data16
533 alignz 4
534 pxe_file_exit_hook:
535 .status: dw 0
536 .offset: dw gpxe_unload.resume
537 .seg: dw 0
538 %endif
540 section .text16
542 ; -----------------------------------------------------------------------------
543 ; PXE modules
544 ; -----------------------------------------------------------------------------
546 %if IS_LPXELINUX
547 %include "pxeisr.inc"
548 %endif
550 ; -----------------------------------------------------------------------------
551 ; Common modules
552 ; -----------------------------------------------------------------------------
554 %include "common.inc" ; Universal modules
556 ; -----------------------------------------------------------------------------
557 ; Begin data section
558 ; -----------------------------------------------------------------------------
560 section .data16
562 global copyright_str, syslinux_banner
563 copyright_str db ' Copyright (C) 1994-'
564 asciidec YEAR
565 db ' H. Peter Anvin et al', CR, LF, 0
566 err_bootfailed db CR, LF, 'Boot failed: press a key to retry, or wait for reset...', CR, LF, 0
567 bailmsg equ err_bootfailed
568 localboot_msg db 'Booting from local disk...', CR, LF, 0
569 syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
572 ; Misc initialized (data) variables
574 section .data16
575 global KeepPXE
576 KeepPXE db 0 ; Should PXE be kept around?