source: bootcd/isolinux/syslinux-6.03/core/pxelinux.asm

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 12.5 KB
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;   BEGIN CODE
44; ---------------------------------------------------------------------------
45
46;
47; Memory below this point is reserved for the BIOS and the MBR
48;
49                section .earlybss
50                global trackbuf
51trackbufsize    equ 8192
52trackbuf        resb trackbufsize       ; Track buffer goes here
53                ; ends at 2800h
54
55                ; These fields save information from before the time
56                ; .bss is zeroed... must be in .earlybss
57                global InitStack
58InitStack       resd 1
59
60                section .bss16
61                alignb FILENAME_MAX
62PXEStack        resd 1                  ; Saved stack during PXE call
63
64                alignb 4
65                global DHCPMagic, RebootTime, BIOSName
66RebootTime      resd 1                  ; Reboot timeout, if set by option
67LocalBootType   resw 1                  ; Local boot return code
68DHCPMagic       resb 1                  ; PXELINUX magic flags
69BIOSName        resw 1                  ; Dummy variable - always 0
70
71                section .text16
72                global StackBuf
73StackBuf        equ STACK_TOP-44        ; Base of stack if we use our own
74StackHome       equ StackBuf
75
76                ; PXE loads the whole file, but assume it can't be more
77                ; than (384-31)K in size.
78MaxLMA          equ 384*1024
79
80;
81; Primary entry point.
82;
83bootsec         equ $
84_start:
85                jmp 0:_start1           ; Canonicalize the address and skip
86                                        ; the patch header
87
88;
89; Patch area for adding hardwired DHCP options
90;
91                align 4
92
93hcdhcp_magic    dd 0x2983c8ac           ; Magic number
94hcdhcp_len      dd 7*4                  ; Size of this structure
95hcdhcp_flags    dd 0                    ; Reserved for the future
96                global bdhcp_len, adhcp_len
97                ; Parameters to be parsed before the ones from PXE
98bdhcp_offset    dd 0                    ; Offset (entered by patcher)
99bdhcp_len       dd 0                    ; Length (entered by patcher)
100                ; Parameters to be parsed *after* the ones from PXE
101adhcp_offset    dd 0                    ; Offset (entered by patcher)
102adhcp_len       dd 0                    ; Length (entered by patcher)
103
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
111
112                cld                     ; Copy upwards
113                xor ax,ax
114                mov ds,ax
115                mov es,ax
116
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
123
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
131
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
136
137                lss esp,[BaseStack]
138                sti                     ; Stack set up and ready
139
140;
141; Initialize screen (if we're using one)
142;
143%include "init.inc"
144
145;
146; Tell the user we got this far
147;
148                mov si,syslinux_banner
149                call writestr_early
150
151                mov si,copyright_str
152                call writestr_early
153
154;
155; do fs initialize
156;
157                mov eax,ROOT_FS_OPS
158                xor ebp,ebp
159                pm_call pm_fs_init
160
161                section .rodata
162                alignz 4
163ROOT_FS_OPS:
164                extern pxe_fs_ops
165                dd pxe_fs_ops
166                dd 0
167
168
169                section .text16
170;
171; Initialize the idle mechanism
172;
173                extern reset_idle
174                pm_call reset_idle
175
176;
177; Now we're all set to start with our *real* business.
178;
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...
183;
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.
187;
188
189;
190; Linux kernel loading code is common.  However, we need to define
191; a couple of helper macros...
192;
193
194; Unload PXE stack
195%define HAVE_UNLOAD_PREP
196%macro  UNLOAD_PREP 0
197                pm_call unload_pxe
198%endmacro
199
200;
201; Jump to 32-bit ELF space
202;
203                pm_call load_env32
204                jmp kaboom              ; load_env32() shouldn't return. If it does, then kaboom!
205
206print_hello:
207enter_command:
208auto_boot:
209                pm_call hello
210
211;
212; Save hardwired DHCP options.  This is done before the C environment
213; is initialized, so it has to be done in assembly.
214;
215%define MAX_DHCP_OPTS   4096
216                bits 32
217
218                section .savedata
219                global bdhcp_data, adhcp_data
220bdhcp_data:     resb MAX_DHCP_OPTS
221adhcp_data:     resb MAX_DHCP_OPTS
222
223                section .textnr
224pm_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
238
239adhcp_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
252                ret
253
254                bits 16
255
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
261Kernel_EAX      resd 1
262Kernel_SI       resw 1
263
264                section .bss16
265                alignb 4
266ThisKbdTo       resd 1                  ; Temporary holder for KbdTimeout
267ThisTotalTo     resd 1                  ; Temporary holder for TotalTimeout
268KernelExtPtr    resw 1                  ; During search, final null pointer
269FuncFlag        resb 1                  ; Escape sequences received from keyboard
270KernelType      resb 1                  ; Kernel type, from vkernel, if known
271                global KernelName
272KernelName      resb FILENAME_MAX       ; Mangled name for kernel
273
274                section .text16
275;
276; COM32 vestigial data structure
277;
278%include "com32.inc"
279
280                section .text16
281                global local_boot16:function hidden
282local_boot16:
283                mov [LocalBootType],ax
284                lss sp,[InitStack]
285                pop gs
286                pop fs
287                pop es
288                pop ds
289                popad
290                mov ax,[cs:LocalBootType]
291                cmp ax,-1                       ; localboot -1 == INT 18h
292                je .int18
293                popfd
294                retf                            ; Return to PXE
295.int18:
296                popfd
297                int 18h
298                jmp 0F000h:0FFF0h
299                hlt
300
301;
302; kaboom: write a message and bail out.  Wait for quite a while,
303;         or a user keypress, then do a hard reboot.
304;
305;         Note: use BIOS_timer here; we may not have jiffies set up.
306;
307                global kaboom
308kaboom:
309                RESET_STACK_AND_SEGS AX
310.patch:         mov si,bailmsg
311                call writestr_early             ; Returns with AL = 0
312.drain:         call pollchar
313                jz .drained
314                call getchar
315                jmp short .drain
316.drained:
317                mov edi,[RebootTime]
318                mov al,[DHCPMagic]
319                and al,09h              ; Magic+Timeout
320                cmp al,09h
321                je .time_set
322                mov edi,REBOOT_TIME
323.time_set:
324                mov cx,18
325.wait1:         push cx
326                mov ecx,edi
327.wait2:         mov dx,[BIOS_timer]
328.wait3:         call pollchar
329                jnz .keypress
330                pm_call __idle
331                cmp dx,[BIOS_timer]
332                je .wait3
333                loop .wait2,ecx
334                mov al,'.'
335                pm_call pm_writechr
336                pop cx
337                loop .wait1
338.keypress:
339                pm_call crlf
340                mov word [BIOS_magic],0 ; Cold reboot
341                jmp 0F000h:0FFF0h       ; Reset vector address
342
343;
344; pxenv
345;
346; This is the main PXENV+/!PXE entry point, using the PXENV+
347; calling convention.  This is a separate local routine so
348; we can hook special things from it if necessary.  In particular,
349; some PXE stacks seem to not like being invoked from anything but
350; the initial stack, so humour it.
351;
352; While we're at it, save and restore all registers.
353;
354                global pxenv
355pxenv:
356                pushfd
357                pushad
358
359                ; We may be removing ourselves from memory
360                cmp bx,PXENV_RESTART_TFTP
361                jz .disable_timer
362                cmp bx,PXENV_FILE_EXEC
363                jnz .store_stack
364
365.disable_timer:
366                call bios_timer_cleanup
367
368.store_stack:
369                pushf
370                cli
371                inc word [cs:PXEStackLock]
372                jnz .skip1
373                pop bp
374                mov [cs:PXEStack],sp
375                mov [cs:PXEStack+2],ss
376                lss sp,[cs:InitStack]
377                push bp
378.skip1:
379                popf
380
381                ; Pre-clear the Status field
382                mov word [es:di],cs
383
384                ; This works either for the PXENV+ or the !PXE calling
385                ; convention, as long as we ignore CF (which is redundant
386                ; with AX anyway.)
387                push es
388                push di
389                push bx
390.jump:          call 0:0
391                add sp,6
392                mov [cs:PXEStatus],ax
393
394                pushf
395                cli
396                dec word [cs:PXEStackLock]
397                jns .skip2
398                pop bp
399                lss sp,[cs:PXEStack]
400                push bp
401.skip2:
402                popf
403
404                mov bp,sp
405                and ax,ax
406                setnz [bp+32]                   ; If AX != 0 set CF on return
407
408                ; This clobbers the AX return, but we already saved it into
409                ; the PXEStatus variable.
410                popad
411
412                ; If the call failed, it could return.
413                cmp bx,PXENV_RESTART_TFTP
414                jz .enable_timer
415                cmp bx,PXENV_FILE_EXEC
416                jnz .pop_flags
417
418.enable_timer:
419                call timer_init
420
421.pop_flags:
422                popfd                           ; Restore flags (incl. IF, DF)
423                ret
424
425; Must be after function def due to NASM bug
426                global PXEEntry
427PXEEntry        equ pxenv.jump+1
428
429;
430; The PXEStackLock keeps us from switching stacks if we take an interrupt
431; (which ends up calling pxenv) while we are already on the PXE stack.
432; It will be -1 normally, 0 inside a PXE call, and a positive value
433; inside a *nested* PXE call.
434;
435                section .data16
436                alignb 2
437PXEStackLock    dw -1
438
439                section .bss16
440                alignb 2
441PXEStatus       resb 2
442
443                section .text16
444;
445; Invoke INT 1Ah on the PXE stack.  This is used by the "Plan C" method
446; for finding the PXE entry point.
447;
448                global pxe_int1a
449pxe_int1a:
450                mov [cs:PXEStack],sp
451                mov [cs:PXEStack+2],ss
452                lss sp,[cs:InitStack]
453
454                int 1Ah                 ; May trash registers
455
456                lss sp,[cs:PXEStack]
457                ret
458
459;
460; Special unload for gPXE: this switches the InitStack from
461; gPXE to the ROM PXE stack.
462;
463%if GPXE
464                global gpxe_unload
465gpxe_unload:
466                mov bx,PXENV_FILE_EXIT_HOOK
467                mov di,pxe_file_exit_hook
468                call pxenv
469                jc .plain
470
471                ; Now we actually need to exit back to gPXE, which will
472                ; give control back to us on the *new* "original stack"...
473                pushfd
474                push ds
475                push es
476                mov [PXEStack],sp
477                mov [PXEStack+2],ss
478                lss sp,[InitStack]
479                pop gs
480                pop fs
481                pop es
482                pop ds
483                popad
484                popfd
485                xor ax,ax
486                retf
487.resume:
488                cli
489
490                ; gPXE will have a stack frame looking much like our
491                ; InitStack, except it has a magic cookie at the top,
492                ; and the segment registers are in reverse order.
493                pop eax
494                pop ax
495                pop bx
496                pop cx
497                pop dx
498                push ax
499                push bx
500                push cx
501                push dx
502                mov [cs:InitStack],sp
503                mov [cs:InitStack+2],ss
504                lss sp,[cs:PXEStack]
505                pop es
506                pop ds
507                popfd
508
509.plain:
510                ret
511
512writestr_early:
513                pm_call pm_writestr
514                ret
515
516pollchar:
517                pm_call pm_pollchar
518                ret
519
520getchar:
521                pm_call pm_getchar
522                ret
523
524                section .data16
525                alignz 4
526pxe_file_exit_hook:
527.status:        dw 0
528.offset:        dw gpxe_unload.resume
529.seg:           dw 0
530%endif
531
532                section .text16
533
534; -----------------------------------------------------------------------------
535;  PXE modules
536; -----------------------------------------------------------------------------
537
538%if IS_LPXELINUX
539%include "pxeisr.inc"
540%endif
541
542; -----------------------------------------------------------------------------
543;  Common modules
544; -----------------------------------------------------------------------------
545
546%include "common.inc"           ; Universal modules
547
548; -----------------------------------------------------------------------------
549;  Begin data section
550; -----------------------------------------------------------------------------
551
552                section .data16
553
554                global copyright_str, syslinux_banner
555copyright_str   db 'Copyright (C) 1994-'
556                asciidec YEAR
557                db ' H. Peter Anvin et al', CR, LF, 0
558err_bootfailed  db CR, LF, 'Boot failed: press a key to retry, or wait for reset...', CR, LF, 0
559bailmsg         equ err_bootfailed
560localboot_msg   db 'Booting from local disk...', CR, LF, 0
561syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', MY_TYPE, ' '
562                db DATE_STR, ' ', 0
563
564;
565; Misc initialized (data) variables
566;
567                section .data16
568                global KeepPXE
569KeepPXE         db 0                    ; Should PXE be kept around?
570
571                section .bss16
572                global OrigFDCTabPtr
573OrigFDCTabPtr   resd 1                  ; Keep bios_cleanup_hardware() honest
Note: See TracBrowser for help on using the repository browser.