Add logo by Abi Rasheed
[profile/ivi/syslinux.git] / core / pxelinux.asm
1 ; -*- fundamental -*- (asm-mode sucks)
2 ; ****************************************************************************
3 ;
4 ;  pxelinux.asm
5 ;
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.
9 ;
10 ;   Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
11 ;   Copyright 2009 Intel Corporation; author: H. Peter Anvin
12 ;
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.
18 ;
19 ; ****************************************************************************
20
21 %define IS_PXELINUX 1
22 %include "head.inc"
23 %include "pxe.inc"
24
25 ; gPXE extensions support
26 %define GPXE    1
27
28 ;
29 ; Some semi-configurable constants... change on your own risk.
30 ;
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)
38
39 SECTOR_SHIFT    equ TFTP_BLOCKSIZE_LG2
40 SECTOR_SIZE     equ TFTP_BLOCKSIZE
41
42 ;
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.
47 ;
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
59
60
61 ; ---------------------------------------------------------------------------
62 ;   BEGIN CODE
63 ; ---------------------------------------------------------------------------
64
65 ;
66 ; Memory below this point is reserved for the BIOS and the MBR
67 ;
68                 section .earlybss
69                 global trackbuf
70 trackbufsize    equ 8192
71 trackbuf        resb trackbufsize       ; Track buffer goes here
72                 ; ends at 2800h
73
74                 ; These fields save information from before the time
75                 ; .bss is zeroed... must be in .earlybss
76                 global InitStack
77 InitStack       resd 1
78
79                 section .bss16
80                 alignb FILENAME_MAX
81 PXEStack        resd 1                  ; Saved stack during PXE call
82
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
90
91                 section .text16
92 StackBuf        equ STACK_TOP-44        ; Base of stack if we use our own
93 StackHome       equ StackBuf
94
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
98
99 ;
100 ; Primary entry point.
101 ;
102 bootsec         equ $
103 _start:
104                 jmp 0:_start1           ; Canonicalize the address and skip
105                                         ; the patch header
106
107 ;
108 ; Patch area for adding hardwired DHCP options
109 ;
110                 align 4
111
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)
121
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
129
130                 cld                     ; Copy upwards
131                 xor ax,ax
132                 mov ds,ax
133                 mov es,ax
134
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
141
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
149
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
154
155                 lss esp,[BaseStack]
156                 sti                     ; Stack set up and ready
157 ;
158 ; Move the hardwired DHCP options (if present) to a safe place...
159 ;
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:
182
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:
205
206 ;
207 ; Initialize screen (if we're using one)
208 ;
209 %include "init.inc"
210
211 ;
212 ; Tell the user we got this far
213 ;
214                 mov si,syslinux_banner
215                 call writestr_early
216
217                 mov si,copyright_str
218                 call writestr_early
219
220 ;
221 ; do fs initialize
222 ;
223                 mov eax,ROOT_FS_OPS
224                 xor ebp,ebp
225                 pm_call fs_init
226
227                 section .rodata
228                 alignz 4
229 ROOT_FS_OPS:
230                 extern pxe_fs_ops
231                 dd pxe_fs_ops
232                 dd 0
233
234
235                 section .text16
236 ;
237 ; Initialize the idle mechanism
238 ;
239                 call reset_idle
240
241 ;
242 ; Now we're all set to start with our *real* business.  First load the
243 ; configuration file (if any) and parse it.
244 ;
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...
249 ;
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.
253 ;
254
255 ;
256 ; Linux kernel loading code is common.  However, we need to define
257 ; a couple of helper macros...
258 ;
259
260 ; Unload PXE stack
261 %define HAVE_UNLOAD_PREP
262 %macro  UNLOAD_PREP 0
263                 pm_call unload_pxe
264 %endmacro
265
266 ;
267 ; Load configuration file
268 ;
269                 pm_call pm_load_config
270                 jz no_config_file
271
272 ;
273 ; Now we have the config file open.  Parse the config file and
274 ; run the user interface.
275 ;
276 %include "ui.inc"
277
278 ;
279 ; Boot to the local disk by returning the appropriate PXE magic.
280 ; AX contains the appropriate return code.
281 ;
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
307                 hlt
308
309 ;
310 ; kaboom: write a message and bail out.  Wait for quite a while,
311 ;         or a user keypress, then do a hard reboot.
312 ;
313 ;         Note: use BIOS_timer here; we may not have jiffies set up.
314 ;
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
350
351
352 ;
353 ; pxenv
354 ;
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.
360 ;
361 ; While we're at it, save and restore all registers.
362 ;
363                 global pxenv
364 pxenv:
365                 pushfd
366                 pushad
367
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
373
374 .disable_timer:
375                 call timer_cleanup
376
377 .store_stack:
378                 mov [cs:PXEStack],sp
379                 mov [cs:PXEStack+2],ss
380                 lss sp,[cs:InitStack]
381
382                 ; Pre-clear the Status field
383                 mov word [es:di],cs
384
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
394
395                 lss sp,[cs:PXEStack]
396
397                 mov bp,sp
398                 and ax,ax
399                 setnz [bp+32]                   ; If AX != 0 set CF on return
400
401                 ; This clobbers the AX return, but we already saved it into
402                 ; the PXEStatus variable.
403                 popad
404
405                 ; If the call failed, it could return.
406                 cmp bx,0073h
407                 jz .enable_timer
408                 cmp bx,00E5h
409                 jnz .pop_flags
410
411 .enable_timer:
412                 call timer_init
413
414 .pop_flags:
415                 popfd                           ; Restore flags (incl. IF, DF)
416                 ret
417
418 ; Must be after function def due to NASM bug
419                 global PXEEntry
420 PXEEntry        equ pxenv.jump+1
421
422                 section .bss16
423                 alignb 2
424 PXEStatus       resb 2
425
426
427                 section .text16
428 ;
429 ; Invoke INT 1Ah on the PXE stack.  This is used by the "Plan C" method
430 ; for finding the PXE entry point.
431 ;
432                 global pxe_int1a
433 pxe_int1a:
434                 mov [cs:PXEStack],sp
435                 mov [cs:PXEStack+2],ss
436                 lss sp,[cs:InitStack]
437
438                 int 1Ah                 ; May trash registers
439
440                 lss sp,[cs:PXEStack]
441                 ret
442
443 ;
444 ; Special unload for gPXE: this switches the InitStack from
445 ; gPXE to the ROM PXE stack.
446 ;
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
454
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:
472                 cli
473
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
492
493 .plain:
494                 ret
495
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
503
504                 section .text16
505
506 ; -----------------------------------------------------------------------------
507 ;  Common modules
508 ; -----------------------------------------------------------------------------
509
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
515
516 ; -----------------------------------------------------------------------------
517 ;  Begin data section
518 ; -----------------------------------------------------------------------------
519
520                 section .data16
521
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
529
530 ;
531 ; Config file keyword table
532 ;
533 %include "keywords.inc"
534
535 ;
536 ; Extensions to search for (in *forward* order).
537 ; (.bs and .bss16 are disabled for PXELINUX, since they are not supported)
538 ;
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
546
547 ;
548 ; Misc initialized (data) variables
549 ;
550                 section .data16
551                 global KeepPXE
552 KeepPXE         db 0                    ; Should PXE be kept around?
553
554 ;
555 ; IP information.  Note that the field are in the same order as the
556 ; Linux kernel expects in the ip= option.
557 ;
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