root/core/pxelinux.asm

Revision 5a8a7bf7cb8b312b9d5bf28cc17ecb4c410be2c6, 12.5 KB (checked in by Gene Cumm <gene.cumm@…>, 18 months ago)

PXELINUX: shorten code in pxenv call

Now that both scenarios are clear (do/do not call timer_cleanup/
timer_init), shorten it to eliminate a needless jmp.

  • Property mode set to 100644
Line 
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;
31my_id           equ pxelinux_id
32NULLFILE        equ 0                   ; Zero byte == null file name
33NULLOFFSET      equ 0                   ; Position in which to look
34REBOOT_TIME     equ 5*60                ; If failure, time until full reset
35%assign HIGHMEM_SLOP 128*1024           ; Avoid this much memory near the top
36TFTP_BLOCKSIZE_LG2 equ 9                ; log2(bytes/block)
37TFTP_BLOCKSIZE  equ (1 << TFTP_BLOCKSIZE_LG2)
38
39SECTOR_SHIFT    equ TFTP_BLOCKSIZE_LG2
40SECTOR_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
49vk_vname:       resb FILENAME_MAX       ; Virtual name **MUST BE FIRST!**
50vk_rname:       resb FILENAME_MAX       ; Real name
51vk_ipappend:    resb 1                  ; "IPAPPEND" flag
52vk_type:        resb 1                  ; Type of file
53vk_appendlen:   resw 1
54                alignb 4
55vk_append:      resb max_cmd_len+1      ; Command line
56                alignb 4
57vk_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
70trackbufsize    equ 8192
71trackbuf        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
77InitStack       resd 1
78
79                section .bss16
80                alignb FILENAME_MAX
81PXEStack        resd 1                  ; Saved stack during PXE call
82
83                alignb 4
84                global DHCPMagic, RebootTime, APIVer
85RebootTime      resd 1                  ; Reboot timeout, if set by option
86StrucPtr        resw 2                  ; Pointer to PXENV+ or !PXE structure
87APIVer          resw 1                  ; PXE API version found
88LocalBootType   resw 1                  ; Local boot return code
89DHCPMagic       resb 1                  ; PXELINUX magic flags
90
91                section .text16
92StackBuf        equ STACK_TOP-44        ; Base of stack if we use our own
93StackHome       equ StackBuf
94
95                ; PXE loads the whole file, but assume it can't be more
96                ; than (384-31)K in size.
97MaxLMA          equ 384*1024
98
99;
100; Primary entry point.
101;
102bootsec         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
112hcdhcp_magic    dd 0x2983c8ac           ; Magic number
113hcdhcp_len      dd 7*4                  ; Size of this structure
114hcdhcp_flags    dd 0                    ; Reserved for the future
115                ; Parameters to be parsed before the ones from PXE
116bdhcp_offset    dd 0                    ; Offset (entered by patcher)
117bdhcp_len       dd 0                    ; Length (entered by patcher)
118                ; Parameters to be parsed *after* the ones from PXE
119adhcp_offset    dd 0                    ; Offset (entered by patcher)
120adhcp_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;
160bdhcp_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
183adhcp_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
229ROOT_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;
282local_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
316kaboom:
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
364pxenv:
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
420PXEEntry        equ pxenv.jump+1
421
422                section .bss16
423                alignb 2
424PXEStatus       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
433pxe_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
449gpxe_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
498pxe_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
512writestr_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
522copyright_str   db ' Copyright (C) 1994-'
523                asciidec YEAR
524                db ' H. Peter Anvin et al', CR, LF, 0
525err_bootfailed  db CR, LF, 'Boot failed: press a key to retry, or wait for reset...', CR, LF, 0
526bailmsg         equ err_bootfailed
527localboot_msg   db 'Booting from local disk...', CR, LF, 0
528syslinux_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
540exten_table:    db '.cbt'               ; COMBOOT (specific)
541                db '.0', 0, 0           ; PXE bootstrap program
542                db '.com'               ; COMBOOT (same as DOS)
543                db '.c32'               ; COM32
544exten_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
552KeepPXE         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
561IPInfo:
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
Note: See TracBrowser for help on using the browser.