core: remove unused header file vkernel.inc
[syslinux.git] / core / pxelinux.asm
blobd3215e72d99748cbcfaa888f1e9fba9de65ccd50
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, APIVer, BIOSName
66 RebootTime resd 1 ; Reboot timeout, if set by option
67 StrucPtr resw 2 ; Pointer to PXENV+ or !PXE structure
68 APIVer resw 1 ; PXE API version found
69 LocalBootType resw 1 ; Local boot return code
70 DHCPMagic resb 1 ; PXELINUX magic flags
71 BIOSName resw 1 ; Dummy variable - always 0
73 section .text16
74 global StackBuf
75 StackBuf equ STACK_TOP-44 ; Base of stack if we use our own
76 StackHome equ StackBuf
78 ; PXE loads the whole file, but assume it can't be more
79 ; than (384-31)K in size.
80 MaxLMA equ 384*1024
83 ; Primary entry point.
85 bootsec equ $
86 _start:
87 jmp 0:_start1 ; Canonicalize the address and skip
88 ; the patch header
91 ; Patch area for adding hardwired DHCP options
93 align 4
95 hcdhcp_magic dd 0x2983c8ac ; Magic number
96 hcdhcp_len dd 7*4 ; Size of this structure
97 hcdhcp_flags dd 0 ; Reserved for the future
98 ; Parameters to be parsed before the ones from PXE
99 bdhcp_offset dd 0 ; Offset (entered by patcher)
100 bdhcp_len dd 0 ; Length (entered by patcher)
101 ; Parameters to be parsed *after* the ones from PXE
102 adhcp_offset dd 0 ; Offset (entered by patcher)
103 adhcp_len dd 0 ; Length (entered by patcher)
105 _start1:
106 pushfd ; Paranoia... in case of return to PXE
107 pushad ; ... save as much state as possible
108 push ds
109 push es
110 push fs
111 push gs
113 cld ; Copy upwards
114 xor ax,ax
115 mov ds,ax
116 mov es,ax
118 %if 0 ; debugging code only... not intended for production use
119 ; Clobber the stack segment, to test for specific pathologies
120 mov di,STACK_BASE
121 mov cx,STACK_LEN >> 1
122 mov ax,0xf4f4
123 rep stosw
125 ; Clobber the tail of the 64K segment, too
126 extern __bss1_end
127 mov di,__bss1_end
128 sub cx,di ; CX = 0 previously
129 shr cx,1
130 rep stosw
131 %endif
133 ; That is all pushed onto the PXE stack. Save the pointer
134 ; to it and switch to an internal stack.
135 mov [InitStack],sp
136 mov [InitStack+2],ss
138 lss esp,[BaseStack]
139 sti ; Stack set up and ready
142 ; Initialize screen (if we're using one)
144 %include "init.inc"
147 ; Tell the user we got this far
149 mov si,syslinux_banner
150 call writestr_early
152 mov si,copyright_str
153 call writestr_early
156 ; do fs initialize
158 mov eax,ROOT_FS_OPS
159 xor ebp,ebp
160 pm_call fs_init
162 section .rodata
163 alignz 4
164 ROOT_FS_OPS:
165 extern pxe_fs_ops
166 dd pxe_fs_ops
167 dd 0
170 section .text16
172 ; Initialize the idle mechanism
174 call reset_idle
177 ; Now we're all set to start with our *real* business.
179 ; In previous versions I avoided using 32-bit registers because of a
180 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
181 ; random. I figure, though, that if there are any of those still left
182 ; they probably won't be trying to install Linux on them...
184 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
185 ; to take'm out. In fact, we may want to put them back if we're going
186 ; to boot ELKS at some point.
190 ; Linux kernel loading code is common. However, we need to define
191 ; a couple of helper macros...
194 ; Unload PXE stack
195 %define HAVE_UNLOAD_PREP
196 %macro UNLOAD_PREP 0
197 pm_call unload_pxe
198 %endmacro
201 ; Jump to 32-bit ELF space
203 pm_call load_env32
204 jmp kaboom ; load_env32() shouldn't return. If it does, then kaboom!
206 print_hello:
207 enter_command:
208 auto_boot:
209 pm_call hello
212 ; Save hardwired DHCP options. This is done before the C environment
213 ; is initialized, so it has to be done in assembly.
215 %define MAX_DHCP_OPTS 4096
216 bits 32
218 section .savedata
219 global bdhcp_data, adhcp_data
220 bdhcp_data: resb MAX_DHCP_OPTS
221 adhcp_data: resb MAX_DHCP_OPTS
223 section .textnr
224 pm_save_data:
225 mov eax,MAX_DHCP_OPTS
226 movzx ecx,word [bdhcp_len]
227 cmp ecx,eax
228 jna .oksize
229 mov ecx,eax
230 mov [bdhcp_len],ax
231 .oksize:
232 mov esi,[bdhcp_offset]
233 add esi,_start
234 mov edi,bdhcp_data
235 add ecx,3
236 shr ecx,2
237 rep movsd
239 adhcp_copy:
240 movzx ecx,word [adhcp_len]
241 cmp ecx,eax
242 jna .oksize
243 mov ecx,eax
244 mov [adhcp_len],ax
245 .oksize:
246 mov esi,[adhcp_offset]
247 add esi,_start
248 mov edi,adhcp_data
249 add ecx,3
250 shr ecx,2
251 rep movsd
254 bits 16
256 ; As core/ui.inc used to be included here in core/pxelinux.asm, and it's no
257 ; longer used, its global variables that were previously used by
258 ; core/pxelinux.asm are now declared here.
259 section .bss16
260 alignb 4
261 Kernel_EAX resd 1
262 Kernel_SI resw 1
264 section .bss16
265 alignb 4
266 ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
267 ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
268 KernelExtPtr resw 1 ; During search, final null pointer
269 FuncFlag resb 1 ; Escape sequences received from keyboard
270 KernelType resb 1 ; Kernel type, from vkernel, if known
271 global KernelName
272 KernelName resb FILENAME_MAX ; Mangled name for kernel
274 section .text16
276 ; COMBOOT-loading code
278 %include "comboot.inc"
279 %include "com32.inc"
282 ; Boot sector loading code
286 ; Abort loading code
290 ; Hardware cleanup common code
293 %include "localboot.inc"
296 ; kaboom: write a message and bail out. Wait for quite a while,
297 ; or a user keypress, then do a hard reboot.
299 ; Note: use BIOS_timer here; we may not have jiffies set up.
301 global kaboom
302 kaboom:
303 RESET_STACK_AND_SEGS AX
304 .patch: mov si,bailmsg
305 call writestr_early ; Returns with AL = 0
306 .drain: call pollchar
307 jz .drained
308 call getchar
309 jmp short .drain
310 .drained:
311 mov edi,[RebootTime]
312 mov al,[DHCPMagic]
313 and al,09h ; Magic+Timeout
314 cmp al,09h
315 je .time_set
316 mov edi,REBOOT_TIME
317 .time_set:
318 mov cx,18
319 .wait1: push cx
320 mov ecx,edi
321 .wait2: mov dx,[BIOS_timer]
322 .wait3: call pollchar
323 jnz .keypress
324 call do_idle
325 cmp dx,[BIOS_timer]
326 je .wait3
327 loop .wait2,ecx
328 mov al,'.'
329 pm_call pm_writechr
330 pop cx
331 loop .wait1
332 .keypress:
333 pm_call crlf
334 mov word [BIOS_magic],0 ; Cold reboot
335 jmp 0F000h:0FFF0h ; Reset vector address
338 ; pxenv
340 ; This is the main PXENV+/!PXE entry point, using the PXENV+
341 ; calling convention. This is a separate local routine so
342 ; we can hook special things from it if necessary. In particular,
343 ; some PXE stacks seem to not like being invoked from anything but
344 ; the initial stack, so humour it.
346 ; While we're at it, save and restore all registers.
348 global pxenv
349 pxenv:
350 pushfd
351 pushad
353 ; We may be removing ourselves from memory
354 cmp bx,PXENV_RESTART_TFTP
355 jz .disable_timer
356 cmp bx,PXENV_FILE_EXEC
357 jnz .store_stack
359 .disable_timer:
360 call timer_cleanup
362 .store_stack:
363 pushf
365 inc word [cs:PXEStackLock]
366 jnz .skip1
367 mov [cs:PXEStack],sp
368 mov [cs:PXEStack+2],ss
369 lss sp,[cs:InitStack]
370 .skip1:
371 popf
373 ; Pre-clear the Status field
374 mov word [es:di],cs
376 ; This works either for the PXENV+ or the !PXE calling
377 ; convention, as long as we ignore CF (which is redundant
378 ; with AX anyway.)
379 push es
380 push di
381 push bx
382 .jump: call 0:0
383 add sp,6
384 mov [cs:PXEStatus],ax
386 pushf
388 dec word [cs:PXEStackLock]
389 jns .skip2
390 lss sp,[cs:PXEStack]
391 .skip2:
392 popf
394 mov bp,sp
395 and ax,ax
396 setnz [bp+32] ; If AX != 0 set CF on return
398 ; This clobbers the AX return, but we already saved it into
399 ; the PXEStatus variable.
400 popad
402 ; If the call failed, it could return.
403 cmp bx,PXENV_RESTART_TFTP
404 jz .enable_timer
405 cmp bx,PXENV_FILE_EXEC
406 jnz .pop_flags
408 .enable_timer:
409 call timer_init
411 .pop_flags:
412 popfd ; Restore flags (incl. IF, DF)
415 ; Must be after function def due to NASM bug
416 global PXEEntry
417 PXEEntry equ pxenv.jump+1
420 ; The PXEStackLock keeps us from switching stacks if we take an interrupt
421 ; (which ends up calling pxenv) while we are already on the PXE stack.
422 ; It will be -1 normally, 0 inside a PXE call, and a positive value
423 ; inside a *nested* PXE call.
425 section .data16
426 alignb 2
427 PXEStackLock dw -1
429 section .bss16
430 alignb 2
431 PXEStatus resb 2
433 section .text16
435 ; Invoke INT 1Ah on the PXE stack. This is used by the "Plan C" method
436 ; for finding the PXE entry point.
438 global pxe_int1a
439 pxe_int1a:
440 mov [cs:PXEStack],sp
441 mov [cs:PXEStack+2],ss
442 lss sp,[cs:InitStack]
444 int 1Ah ; May trash registers
446 lss sp,[cs:PXEStack]
450 ; Special unload for gPXE: this switches the InitStack from
451 ; gPXE to the ROM PXE stack.
453 %if GPXE
454 global gpxe_unload
455 gpxe_unload:
456 mov bx,PXENV_FILE_EXIT_HOOK
457 mov di,pxe_file_exit_hook
458 call pxenv
459 jc .plain
461 ; Now we actually need to exit back to gPXE, which will
462 ; give control back to us on the *new* "original stack"...
463 pushfd
464 push ds
465 push es
466 mov [PXEStack],sp
467 mov [PXEStack+2],ss
468 lss sp,[InitStack]
469 pop gs
470 pop fs
471 pop es
472 pop ds
473 popad
474 popfd
475 xor ax,ax
476 retf
477 .resume:
480 ; gPXE will have a stack frame looking much like our
481 ; InitStack, except it has a magic cookie at the top,
482 ; and the segment registers are in reverse order.
483 pop eax
484 pop ax
485 pop bx
486 pop cx
487 pop dx
488 push ax
489 push bx
490 push cx
491 push dx
492 mov [cs:InitStack],sp
493 mov [cs:InitStack+2],ss
494 lss sp,[cs:PXEStack]
495 pop es
496 pop ds
497 popfd
499 .plain:
502 writestr_early:
503 pm_call pm_writestr
506 pollchar:
507 pm_call pm_pollchar
510 getchar:
511 pm_call pm_getchar
514 section .data16
515 alignz 4
516 pxe_file_exit_hook:
517 .status: dw 0
518 .offset: dw gpxe_unload.resume
519 .seg: dw 0
520 %endif
522 section .text16
524 ; -----------------------------------------------------------------------------
525 ; PXE modules
526 ; -----------------------------------------------------------------------------
528 %if IS_LPXELINUX
529 %include "pxeisr.inc"
530 %endif
532 ; -----------------------------------------------------------------------------
533 ; Common modules
534 ; -----------------------------------------------------------------------------
536 %include "common.inc" ; Universal modules
538 ; -----------------------------------------------------------------------------
539 ; Begin data section
540 ; -----------------------------------------------------------------------------
542 section .data16
544 global copyright_str, syslinux_banner
545 copyright_str db ' Copyright (C) 1994-'
546 asciidec YEAR
547 db ' H. Peter Anvin et al', CR, LF, 0
548 err_bootfailed db CR, LF, 'Boot failed: press a key to retry, or wait for reset...', CR, LF, 0
549 bailmsg equ err_bootfailed
550 localboot_msg db 'Booting from local disk...', CR, LF, 0
551 syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
554 ; Misc initialized (data) variables
556 section .data16
557 global KeepPXE
558 KeepPXE db 0 ; Should PXE be kept around?
561 ; IP information. Note that the field are in the same order as the
562 ; Linux kernel expects in the ip= option.
564 section .bss16
565 alignb 4
566 global IPInfo
567 IPInfo:
568 .IPv4 resd 1 ; IPv4 information
569 .MyIP resd 1 ; My IP address
570 .ServerIP resd 1
571 .GatewayIP resd 1
572 .Netmask resd 1