This repository has been archived on 2023-08-20. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
RescueBootCD/extra/syslinux-3.09/pxelinux.lst

9128 lines
562 KiB
Plaintext

1 ; -*- fundamental -*- (asm-mode sucks)
2 ; $Id: pxelinux.asm,v 1.168 2005/01/20 18:43:22 hpa Exp $
3 ; ****************************************************************************
4 ;
5 ; pxelinux.asm
6 ;
7 ; A program to boot Linux kernels off a TFTP server using the Intel PXE
8 ; network booting API. It is based on the SYSLINUX boot loader for
9 ; MS-DOS floppies.
10 ;
11 ; Copyright (C) 1994-2005 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 "macros.inc"
23 <1> ;; $Id: macros.inc,v 1.9 2004/12/14 22:46:25 hpa Exp $
24 <1> ;; -----------------------------------------------------------------------
25 <1> ;;
26 <1> ;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved
27 <1> ;;
28 <1> ;; This program is free software; you can redistribute it and/or modify
29 <1> ;; it under the terms of the GNU General Public License as published by
30 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
31 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
32 <1> ;; (at your option) any later version; incorporated herein by reference.
33 <1> ;;
34 <1> ;; -----------------------------------------------------------------------
35 <1>
36 <1> ;;
37 <1> ;; macros.inc
38 <1> ;;
39 <1> ;; Convenient macros
40 <1> ;;
41 <1>
42 <1> %ifndef _MACROS_INC
43 <1> %define _MACROS_INC
44 <1>
45 <1> ;
46 <1> ; Identify the module we're compiling; the "correct" should be defined
47 <1> ; in the module itself to 1
48 <1> ;
49 <1> %ifndef IS_SYSLINUX
50 <1> %define IS_SYSLINUX 0
51 <1> %endif
52 <1> %ifndef IS_MDSLINUX
53 <1> %define IS_MDSLINUX 0
54 <1> %endif
55 <1> %ifndef IS_PXELINUX
56 <1> %define IS_PXELINUX 0
57 <1> %endif
58 <1> %ifndef IS_ISOLINUX
59 <1> %define IS_ISOLINUX 0
60 <1> %endif
61 <1> %ifndef IS_EXTLINUX
62 <1> %define IS_EXTLINUX 0
63 <1> %endif
64 <1>
65 <1> ;
66 <1> ; Macros similar to res[bwd], but which works in the code segment (after
67 <1> ; section .text) or the data segment (section .data)
68 <1> ;
69 <1> %macro zb 1.nolist
70 <1> times %1 db 0
71 <1> %endmacro
72 <1>
73 <1> %macro zw 1.nolist
74 <1> times %1 dw 0
75 <1> %endmacro
76 <1>
77 <1> %macro zd 1.nolist
78 <1> times %1 dd 0
79 <1> %endmacro
80 <1>
81 <1> ;
82 <1> ; Macro to emit an unsigned decimal number as a string
83 <1> ;
84 <1> %macro asciidec 1.nolist
85 <1> %ifndef DEPEND ; Not safe for "depend"
86 <1> %if %1 >= 1000000000
87 <1> db ((%1/1000000000) % 10) + '0'
88 <1> %endif
89 <1> %if %1 >= 100000000
90 <1> db ((%1/100000000) % 10) + '0'
91 <1> %endif
92 <1> %if %1 >= 10000000
93 <1> db ((%1/10000000) % 10) + '0'
94 <1> %endif
95 <1> %if %1 >= 1000000
96 <1> db ((%1/1000000) % 10) + '0'
97 <1> %endif
98 <1> %if %1 >= 100000
99 <1> db ((%1/100000) % 10) + '0'
100 <1> %endif
101 <1> %if %1 >= 10000
102 <1> db ((%1/10000) % 10) + '0'
103 <1> %endif
104 <1> %if %1 >= 1000
105 <1> db ((%1/1000) % 10) + '0'
106 <1> %endif
107 <1> %if %1 >= 100
108 <1> db ((%1/100) % 10) + '0'
109 <1> %endif
110 <1> %if %1 >= 10
111 <1> db ((%1/10) % 10) + '0'
112 <1> %endif
113 <1> db (%1 % 10) + '0'
114 <1> %endif
115 <1> %endmacro
116 <1>
117 <1> ;
118 <1> ; Macros for network byte order of constants
119 <1> ;
120 <1> %define htons(x) ( ( ((x) & 0FFh) << 8 ) + ( ((x) & 0FF00h) >> 8 ) )
121 <1> %define ntohs(x) htons(x)
122 <1> %define htonl(x) ( ( ((x) & 0FFh) << 24) + ( ((x) & 0FF00h) << 8 ) + ( ((x) & 0FF0000h) >> 8 ) + ( ((x) & 0FF000000h) >> 24) )
123 <1> %define ntohl(x) htonl(x)
124 <1>
125 <1> ;
126 <1> ; ASCII
127 <1> ;
128 <1> CR equ 13 ; Carriage Return
129 <1> LF equ 10 ; Line Feed
130 <1> FF equ 12 ; Form Feed
131 <1> BS equ 8 ; Backspace
132 <1>
133 <1> %endif ; _MACROS_INC
134 %include "config.inc"
135 <1> ;; $Id: config.inc,v 1.9 2005/06/16 05:52:44 hpa Exp $
136 <1> ;; -----------------------------------------------------------------------
137 <1> ;;
138 <1> ;; Copyright 2002-2005 H. Peter Anvin - All Rights Reserved
139 <1> ;;
140 <1> ;; This program is free software; you can redistribute it and/or modify
141 <1> ;; it under the terms of the GNU General Public License as published by
142 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
143 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
144 <1> ;; (at your option) any later version; incorporated herein by reference.
145 <1> ;;
146 <1> ;; -----------------------------------------------------------------------
147 <1>
148 <1> ;;
149 <1> ;; config.inc
150 <1> ;;
151 <1> ;; Common configuration options. Some of these are imposed by the kernel.
152 <1> ;;
153 <1>
154 <1> %ifndef _CONFIG_INC
155 <1> %define _CONFIG_INC
156 <1>
157 <1> max_cmd_len equ 511 ; Must be &3; 255 is the kernel limit
158 <1> HIGHMEM_MAX equ 037FFFFFFh ; DEFAULT highest address for an initrd
159 <1> DEFAULT_BAUD equ 9600 ; Default baud rate for serial port
160 <1> BAUD_DIVISOR equ 115200 ; Serial port parameter
161 <1>
162 <1> %assign DO_WBINVD 0 ; Should we use WBINVD or not?
163 <1>
164 <1> ;
165 <1> ; Version number definitinons
166 <1> ;
167 <1> %ifndef DEPEND ; Generated file
168 <1> %include "version.gen"
169 <2> %define VERSION "3.09"
170 <2> %define VER_MAJOR 3
171 <2> %define VER_MINOR 9
172 <1> %endif
173 <1>
174 <1> ;
175 <1> ; Should be updated with every release to avoid bootsector/SYS file mismatch
176 <1> ;
177 <1> %define version_str VERSION ; Must be 4 characters long!
178 <1> %define date DATE_STR ; Defined from the Makefile
179 <1> %define year '2005'
180 <1>
181 <1> %endif ; _CONFIG_INC
182 %include "kernel.inc"
183 <1> ;; $Id: kernel.inc,v 1.5 2005/01/10 02:41:31 hpa Exp $
184 <1> ;; -----------------------------------------------------------------------
185 <1> ;;
186 <1> ;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
187 <1> ;;
188 <1> ;; This program is free software; you can redistribute it and/or modify
189 <1> ;; it under the terms of the GNU General Public License as published by
190 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
191 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
192 <1> ;; (at your option) any later version; incorporated herein by reference.
193 <1> ;;
194 <1> ;; -----------------------------------------------------------------------
195 <1>
196 <1> ;;
197 <1> ;; kernel.inc
198 <1> ;;
199 <1> ;; Header file for the kernel interface definitions
200 <1> ;;
201 <1>
202 <1> %ifndef _KERNEL_INC
203 <1> %define _KERNEL_INC
204 <1>
205 <1> ;;
206 <1> ;; Structure of the real_mode_seg
207 <1> ;;
208 <1>
209 <1> struc real_mode_seg_t
210 00000000 <res 00000020> <1> resb 20h-($-$$) ; org 20h
211 00000020 <res 00000002> <1> kern_cmd_magic resw 1 ; 0020 Magic # for command line
212 00000022 <res 00000002> <1> kern_cmd_offset resw 1 ; 0022 Offset for kernel command line
213 00000024 <res 000001CD> <1> resb 497-($-$$) ; org 497d
214 000001F1 <res 00000001> <1> bs_setupsecs resb 1 ; 01F1 Sectors for setup code (0 -> 4)
215 000001F2 <res 00000002> <1> bs_rootflags resw 1 ; 01F2 Root readonly flag
216 000001F4 <res 00000002> <1> bs_syssize resw 1 ; 01F4
217 000001F6 <res 00000002> <1> bs_swapdev resw 1 ; 01F6 Swap device (obsolete)
218 000001F8 <res 00000002> <1> bs_ramsize resw 1 ; 01F8 Ramdisk flags, formerly ramdisk size
219 000001FA <res 00000002> <1> bs_vidmode resw 1 ; 01FA Video mode
220 000001FC <res 00000002> <1> bs_rootdev resw 1 ; 01FC Root device
221 000001FE <res 00000002> <1> bs_bootsign resw 1 ; 01FE Boot sector signature (0AA55h)
222 00000200 <res 00000001> <1> su_jump resb 1 ; 0200 0EBh
223 00000201 <res 00000001> <1> su_jump2 resb 1 ; 0201 Size of following header
224 00000202 <res 00000004> <1> su_header resd 1 ; 0202 New setup code: header
225 00000206 <res 00000002> <1> su_version resw 1 ; 0206 See linux/arch/i386/boot/setup.S
226 00000208 <res 00000002> <1> su_switch resw 1 ; 0208
227 0000020A <res 00000002> <1> su_setupseg resw 1 ; 020A
228 0000020C <res 00000002> <1> su_startsys resw 1 ; 020C
229 0000020E <res 00000002> <1> su_kver resw 1 ; 020E Kernel version pointer
230 00000210 <res 00000001> <1> su_loader resb 1 ; 0210 Loader ID
231 00000211 <res 00000001> <1> su_loadflags resb 1 ; 0211 Load high flag
232 00000212 <res 00000002> <1> su_movesize resw 1 ; 0212
233 00000214 <res 00000004> <1> su_code32start resd 1 ; 0214 Start of code loaded high
234 00000218 <res 00000004> <1> su_ramdiskat resd 1 ; 0218 Start of initial ramdisk
235 0000021C <res 00000004> <1> su_ramdisklen resd 1 ; 021C Length of initial ramdisk
236 00000220 <res 00000002> <1> su_bsklugeoffs resw 1 ; 0220
237 00000222 <res 00000002> <1> su_bsklugeseg resw 1 ; 0222
238 00000224 <res 00000002> <1> su_heapend resw 1 ; 0224
239 00000226 <res 00000002> <1> su_pad1 resw 1 ; 0226
240 00000228 <res 00000004> <1> su_cmd_line_ptr resd 1 ; 0228
241 0000022C <res 00000004> <1> su_ramdisk_max resd 1 ; 022C
242 00000230 <res 00008DC4> <1> resb (9000h-12)-($-$$) ; Were bootsect.S puts it...
243 <1> linux_stack equ $ ; 8FF4
244 <1> linux_fdctab equ $
245 00008FF4 <res 0000000C> <1> resb 9000h-($-$$)
246 <1> cmd_line_here equ $ ; 9000 Should be out of the way
247 <1> endstruc
248 <1>
249 <1> ;
250 <1> ; Kernel command line signature
251 <1> ;
252 <1> CMD_MAGIC equ 0A33Fh ; Command line magic
253 <1>
254 <1> ;
255 <1> ; Magic number of su_header field
256 <1> ;
257 <1> HEADER_ID equ 'HdrS' ; HdrS (in littleendian hex)
258 <1>
259 <1> ;
260 <1> ; Flags for the su_loadflags field
261 <1> ;
262 <1> LOAD_HIGH equ 01h ; Large kernel, load high
263 <1> CAN_USE_HEAP equ 80h ; Boot loader reports heap size
264 <1>
265 <1> ;
266 <1> ; ID codes for various modules
267 <1> ;
268 <1> syslinux_id equ 031h ; 3 = SYSLINUX family; 1 = SYSLINUX
269 <1> pxelinux_id equ 032h ; 3 = SYSLINUX family; 2 = PXELINUX
270 <1> isolinux_id equ 033h ; 3 = SYSLINUX family; 3 = ISOLINUX
271 <1> extlinux_id equ 034h ; 3 = SYSLINUX family; 4 = EXTLINUX
272 <1>
273 <1> %endif ; _KERNEL_INC
274 %include "bios.inc"
275 <1> ;; $Id: bios.inc,v 1.3 2004/12/14 22:46:24 hpa Exp $
276 <1> ;; -----------------------------------------------------------------------
277 <1> ;;
278 <1> ;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved
279 <1> ;;
280 <1> ;; This program is free software; you can redistribute it and/or modify
281 <1> ;; it under the terms of the GNU General Public License as published by
282 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
283 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
284 <1> ;; (at your option) any later version; incorporated herein by reference.
285 <1> ;;
286 <1> ;; -----------------------------------------------------------------------
287 <1>
288 <1> ;;
289 <1> ;; bios.inc
290 <1> ;;
291 <1> ;; Header file for the BIOS data structures etc.
292 <1> ;;
293 <1>
294 <1> %ifndef _BIOS_INC
295 <1> %define _BIOS_INC
296 <1>
297 <1> absolute 4*1Eh ; In the interrupt table
298 <1> fdctab equ $
299 00000078 <res 00000002> <1> fdctab1 resw 1
300 0000007A <res 00000002> <1> fdctab2 resw 1
301 <1> absolute 0400h
302 00000400 <res 00000008> <1> serial_base resw 4 ; Base addresses for 4 serial ports
303 <1> absolute 0413h
304 00000413 <res 00000002> <1> BIOS_fbm resw 1 ; Free Base Memory (kilobytes)
305 <1> absolute 0462h
306 00000462 <res 00000001> <1> BIOS_page resb 1 ; Current video page
307 <1> absolute 046Ch
308 0000046C <res 00000002> <1> BIOS_timer resw 1 ; Timer ticks
309 <1> absolute 0472h
310 00000472 <res 00000002> <1> BIOS_magic resw 1 ; BIOS reset magic
311 <1> absolute 0484h
312 00000484 <res 00000001> <1> BIOS_vidrows resb 1 ; Number of screen rows
313 <1>
314 <1> %endif ; _BIOS_INC
315 %include "tracers.inc"
316 <1> ;; $Id: tracers.inc,v 1.6 2005/01/12 00:35:13 hpa Exp $
317 <1> ;; -----------------------------------------------------------------------
318 <1> ;;
319 <1> ;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
320 <1> ;;
321 <1> ;; This program is free software; you can redistribute it and/or modify
322 <1> ;; it under the terms of the GNU General Public License as published by
323 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
324 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
325 <1> ;; (at your option) any later version; incorporated herein by reference.
326 <1> ;;
327 <1> ;; -----------------------------------------------------------------------
328 <1>
329 <1> ;;
330 <1> ;; tracers.inc
331 <1> ;;
332 <1> ;; Debugging tracers
333 <1> ;;
334 <1>
335 <1> %ifndef _TRACERS_INC
336 <1> %define _TRACERS_INC
337 <1>
338 <1> ; Note: The Makefile builds one version with DEBUG_MESSAGES automatically.
339 <1> ; %define DEBUG_TRACERS 1 ; Uncomment to get debugging tracers
340 <1> ; %define DEBUG_MESSAGES ; Uncomment to get debugging messages
341 <1>
342 <1> %ifdef DEBUG_TRACERS
343 <1>
344 <1> %macro TRACER 1
345 <1> call debug_tracer
346 <1> db %1
347 <1> %endmacro
348 <1>
349 <1> %else ; DEBUG_TRACERS
350 <1>
351 <1> %macro TRACER 1
352 <1> %endmacro
353 <1>
354 <1> %endif ; DEBUG_TRACERS
355 <1>
356 <1> %endif ; _TRACERS_INC
357 %include "pxe.inc"
358 <1> ;; -----------------------------------------------------------------------
359 <1> ;;
360 <1> ;; Copyright 1999-2004 H. Peter Anvin - All Rights Reserved
361 <1> ;;
362 <1> ;; This program is free software; you can redistribute it and/or modify
363 <1> ;; it under the terms of the GNU General Public License as published by
364 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
365 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
366 <1> ;; (at your option) any later version; incorporated herein by reference.
367 <1> ;;
368 <1> ;; -----------------------------------------------------------------------
369 <1> ;; $Id: pxe.inc,v 1.5 2004/12/14 23:03:28 hpa Exp $
370 <1>
371 <1> ;;
372 <1> ;; pxe.inc
373 <1> ;;
374 <1> ;; PXE opcodes
375 <1> ;;
376 <1>
377 <1> %ifndef _PXE_INC
378 <1> %define _PXE_INC 1
379 <1>
380 <1> %define PXENV_TFTP_OPEN 0020h
381 <1> %define PXENV_TFTP_CLOSE 0021h
382 <1> %define PXENV_TFTP_READ 0022h
383 <1> %define PXENV_TFTP_READ_FILE 0023h
384 <1> %define PXENV_TFTP_READ_FILE_PMODE 0024h
385 <1> %define PXENV_TFTP_GET_FSIZE 0025h
386 <1>
387 <1> %define PXENV_UDP_OPEN 0030h
388 <1> %define PXENV_UDP_CLOSE 0031h
389 <1> %define PXENV_UDP_READ 0032h
390 <1> %define PXENV_UDP_WRITE 0033h
391 <1>
392 <1> %define PXENV_START_UNDI 0000h
393 <1> %define PXENV_UNDI_STARTUP 0001h
394 <1> %define PXENV_UNDI_CLEANUP 0002h
395 <1> %define PXENV_UNDI_INITIALIZE 0003h
396 <1> %define PXENV_UNDI_RESET_NIC 0004h
397 <1> %define PXENV_UNDI_SHUTDOWN 0005h
398 <1> %define PXENV_UNDI_OPEN 0006h
399 <1> %define PXENV_UNDI_CLOSE 0007h
400 <1> %define PXENV_UNDI_TRANSMIT 0008h
401 <1> %define PXENV_UNDI_SET_MCAST_ADDR 0009h
402 <1> %define PXENV_UNDI_SET_STATION_ADDR 000Ah
403 <1> %define PXENV_UNDI_SET_PACKET_FILTER 000Bh
404 <1> %define PXENV_UNDI_GET_INFORMATION 000Ch
405 <1> %define PXENV_UNDI_GET_STATISTICS 000Dh
406 <1> %define PXENV_UNDI_CLEAR_STATISTICS 000Eh
407 <1> %define PXENV_UNDI_INITIATE_DIAGS 000Fh
408 <1> %define PXENV_UNDI_FORCE_INTERRUPT 0010h
409 <1> %define PXENV_UNDI_GET_MCAST_ADDR 0011h
410 <1> %define PXENV_UNDI_GET_NIC_TYPE 0012h
411 <1> %define PXENV_UNDI_GET_IFACE_INFO 0013h
412 <1> %define PXENV_UNDI_ISR 0014h
413 <1> %define PXENV_STOP_UNDI 0015h ; Overlap...?
414 <1> %define PXENV_UNDI_GET_STATE 0015h ; Overlap...?
415 <1>
416 <1> %define PXENV_UNLOAD_STACK 0070h
417 <1> %define PXENV_GET_CACHED_INFO 0071h
418 <1> %define PXENV_RESTART_DHCP 0072h
419 <1> %define PXENV_RESTART_TFTP 0073h
420 <1> %define PXENV_MODE_SWITCH 0074h
421 <1> %define PXENV_START_BASE 0075h
422 <1> %define PXENV_STOP_BASE 0076h
423 <1>
424 <1> %define PXENV_EXIT_SUCCESS 0x0000
425 <1> %define PXENV_EXIT_FAILURE 0x0001
426 <1>
427 <1> %define PXENV_STATUS_SUCCESS 0x00
428 <1> %define PXENV_STATUS_FAILURE 0x01
429 <1> %define PXENV_STATUS_BAD_FUNC 0x02
430 <1> %define PXENV_STATUS_UNSUPPORTED 0x03
431 <1> %define PXENV_STATUS_KEEP_UNDI 0x04
432 <1> %define PXENV_STATUS_KEEP_ALL 0x05
433 <1> %define PXENV_STATUS_OUT_OF_RESOURCES 0x06
434 <1> %define PXENV_STATUS_ARP_TIMEOUT 0x11
435 <1> %define PXENV_STATUS_UDP_CLOSED 0x18
436 <1> %define PXENV_STATUS_UDP_OPEN 0x19
437 <1> %define PXENV_STATUS_TFTP_CLOSED 0x1A
438 <1> %define PXENV_STATUS_TFTP_OPEN 0x1B
439 <1> %define PXENV_STATUS_MCOPY_PROBLEM 0x20
440 <1> %define PXENV_STATUS_BIS_INTEGRITY_FAILURE 0x21
441 <1> %define PXENV_STATUS_BIS_VALIDATE_FAILURE 0x22
442 <1> %define PXENV_STATUS_BIS_INIT_FAILURE 0x23
443 <1> %define PXENV_STATUS_BIS_SHUTDOWN_FAILURE 0x24
444 <1> %define PXENV_STATUS_BIS_GBOA_FAILURE 0x25
445 <1> %define PXENV_STATUS_BIS_FREE_FAILURE 0x26
446 <1> %define PXENV_STATUS_BIS_GSI_FAILURE 0x27
447 <1> %define PXENV_STATUS_BIS_BAD_CKSUM 0x28
448 <1> %define PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS 0x30
449 <1> %define PXENV_STATUS_TFTP_OPEN_TIMEOUT 0x32
450 <1>
451 <1> %define PXENV_STATUS_TFTP_UNKNOWN_OPCODE 0x33
452 <1> %define PXENV_STATUS_TFTP_READ_TIMEOUT 0x35
453 <1> %define PXENV_STATUS_TFTP_ERROR_OPCODE 0x36
454 <1> %define PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION 0x38
455 <1> %define PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION 0x39
456 <1> %define PXENV_STATUS_TFTP_TOO_MANY_PACKAGES 0x3A
457 <1> %define PXENV_STATUS_TFTP_FILE_NOT_FOUND 0x3B
458 <1> %define PXENV_STATUS_TFTP_ACCESS_VIOLATION 0x3C
459 <1> %define PXENV_STATUS_TFTP_NO_MCAST_ADDRESS 0x3D
460 <1> %define PXENV_STATUS_TFTP_NO_FILESIZE 0x3E
461 <1> %define PXENV_STATUS_TFTP_INVALID_PACKET_SIZE 0x3F
462 <1> %define PXENV_STATUS_DHCP_TIMEOUT 0x51
463 <1> %define PXENV_STATUS_DHCP_NO_IP_ADDRESS 0x52
464 <1> %define PXENV_STATUS_DHCP_NO_BOOTFILE_NAME 0x53
465 <1> %define PXENV_STATUS_DHCP_BAD_IP_ADDRESS 0x54
466 <1> %define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x60
467 <1> %define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x61
468 <1> %define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x62
469 <1> %define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC 0x63
470 <1> %define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY 0x64
471 <1> %define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA 0x65
472 <1> %define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA 0x66
473 <1> %define PXENV_STATUS_UNDI_BAD_MAC_ADDRESS 0x67
474 <1> %define PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM 0x68
475 <1> %define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x69
476 <1> %define PXENV_STATUS_UNDI_INVALID_STATE 0x6A
477 <1> %define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x6B
478 <1> %define PXENV_STATUS_UNDI_INVALID_PARAMETER 0x6C
479 <1> %define PXENV_STATUS_BSTRAP_PROMPT_MENU 0x74
480 <1> %define PXENV_STATUS_BSTRAP_MCAST_ADDR 0x76
481 <1> %define PXENV_STATUS_BSTRAP_MISSING_LIST 0x77
482 <1> %define PXENV_STATUS_BSTRAP_NO_RESPONSE 0x78
483 <1> %define PXENV_STATUS_BSTRAP_FILE_TOO_BIG 0x79
484 <1> %define PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE 0xA0
485 <1> %define PXENV_STATUS_BINL_NO_PXE_SERVER 0xA1
486 <1> %define PXENV_STATUS_NOT_AVAILABLE_IN_PMODE 0xA2
487 <1> %define PXENV_STATUS_NOT_AVAILABLE_IN_RMODE 0xA3
488 <1> %define PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED 0xB0
489 <1> %define PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY 0xC0
490 <1> %define PXENV_STATUS_LOADER_NO_BC_ROMID 0xC1
491 <1> %define PXENV_STATUS_LOADER_BAD_BC_ROMID 0xC2
492 <1> %define PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE 0xC3
493 <1> %define PXENV_STATUS_LOADER_NO_UNDI_ROMID 0xC4
494 <1> %define PXENV_STATUS_LOADER_BAD_UNDI_ROMID 0xC5
495 <1> %define PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE 0xC6
496 <1> %define PXENV_STATUS_LOADER_NO_PXE_STRUCT 0xC8
497 <1> %define PXENV_STATUS_LOADER_NO_PXENV_STRUCT 0xC9
498 <1> %define PXENV_STATUS_LOADER_UNDI_START 0xCA
499 <1> %define PXENV_STATUS_LOADER_BC_START 0xCB
500 <1>
501 <1> %endif ; _PXE_INC
502 <1>
503 %include "layout.inc"
504 <1> ; $Id: layout.inc,v 1.1 2004/12/28 06:05:14 hpa Exp $
505 <1> ; -----------------------------------------------------------------------
506 <1> ;
507 <1> ; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved
508 <1> ;
509 <1> ; This program is free software; you can redistribute it and/or modify
510 <1> ; it under the terms of the GNU General Public License as published by
511 <1> ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
512 <1> ; Bostom MA 02111-1307, USA; either version 2 of the License, or
513 <1> ; (at your option) any later version; incorporated herein by reference.
514 <1> ;
515 <1> ; -----------------------------------------------------------------------
516 <1>
517 <1> ;
518 <1> ; layout.inc
519 <1> ;
520 <1> ; Memory layout of segments
521 <1> ;
522 <1>
523 <1>
524 <1> ; Memory below 0800h is reserved for the BIOS and the MBR
525 <1> BSS_START equ 0800h
526 <1>
527 <1> ; PXELINUX needs lots of BSS, so it relocates itself on startup
528 <1> %if IS_PXELINUX
529 <1> TEXT_START equ 9000h
530 <1> %else
531 <1> TEXT_START equ 7C00h
532 <1> %endif
533 <1>
534 <1> %ifdef MAP
535 <1> [map all MAP]
536 <1> %endif
537 <1>
538 <1> ;
539 <1> ; The various sections and their relationship
540 <1> ;
541 <1> org TEXT_START
542 <1>
543 <1> ; NASM BUG: refers to hacks to handle NASM 0.98.38 bugs; might need
544 <1> ; conditional compilation
545 <1>
546 <1> section .earlybss nobits start=BSS_START
547 <1> section .bcopy32 align=4 valign=16 follows=.data vfollows=.earlybss
548 <1> ; NASM BUG: follows= here should be vfollows=
549 <1> section .bss nobits align=256 follows=.bcopy32
550 <1>
551 <1> section .text start=TEXT_START
552 <1> ; NASM BUG: follows=.text not accepted here
553 <1> section .data align=16 ; follows=.text
554 <1>
555 <1> ; NASM BUG: We would like to do follows=.bcopy32
556 <1> section .latebss nobits align=16 start=0E000h
557 <1>
558 <1>
559
560 ;
561 ; Some semi-configurable constants... change on your own risk.
562 ;
563 my_id equ pxelinux_id
564 FILENAME_MAX_LG2 equ 7 ; log2(Max filename size Including final null)
565 FILENAME_MAX equ (1 << FILENAME_MAX_LG2)
566 NULLFILE equ 0 ; Zero byte == null file name
567 NULLOFFSET equ 4 ; Position in which to look
568 REBOOT_TIME equ 5*60 ; If failure, time until full reset
569 %assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top
570 MAX_OPEN_LG2 equ 5 ; log2(Max number of open sockets)
571 MAX_OPEN equ (1 << MAX_OPEN_LG2)
572 PKTBUF_SIZE equ (65536/MAX_OPEN) ; Per-socket packet buffer size
573 TFTP_PORT equ htons(69) ; Default TFTP port
574 PKT_RETRY equ 6 ; Packet transmit retry count
575 PKT_TIMEOUT equ 12 ; Initial timeout, timer ticks @ 55 ms
576 ; Desired TFTP block size
577 ; For Ethernet MTU is normally 1500. Unfortunately there seems to
578 ; be a fair number of networks with "substandard" MTUs which break.
579 ; The code assumes TFTP_LARGEBLK <= 2K.
580 TFTP_MTU equ 1472
581 TFTP_LARGEBLK equ (TFTP_MTU-20-8-4) ; MTU - IP hdr - UDP hdr - TFTP hdr
582 ; Standard TFTP block size
583 TFTP_BLOCKSIZE_LG2 equ 9 ; log2(bytes/block)
584 TFTP_BLOCKSIZE equ (1 << TFTP_BLOCKSIZE_LG2)
585 %assign USE_PXE_PROVIDED_STACK 1 ; Use stack provided by PXE?
586
587 SECTOR_SHIFT equ TFTP_BLOCKSIZE_LG2
588 SECTOR_SIZE equ TFTP_BLOCKSIZE
589
590 ;
591 ; This is what we need to do when idle
592 ;
593 %macro RESET_IDLE 0
594 call reset_idle
595 %endmacro
596 %macro DO_IDLE 0
597 call check_for_arp
598 %endmacro
599
600 ;
601 ; TFTP operation codes
602 ;
603 TFTP_RRQ equ htons(1) ; Read request
604 TFTP_WRQ equ htons(2) ; Write request
605 TFTP_DATA equ htons(3) ; Data packet
606 TFTP_ACK equ htons(4) ; ACK packet
607 TFTP_ERROR equ htons(5) ; ERROR packet
608 TFTP_OACK equ htons(6) ; OACK packet
609
610 ;
611 ; TFTP error codes
612 ;
613 TFTP_EUNDEF equ htons(0) ; Unspecified error
614 TFTP_ENOTFOUND equ htons(1) ; File not found
615 TFTP_EACCESS equ htons(2) ; Access violation
616 TFTP_ENOSPACE equ htons(3) ; Disk full
617 TFTP_EBADOP equ htons(4) ; Invalid TFTP operation
618 TFTP_EBADID equ htons(5) ; Unknown transfer
619 TFTP_EEXISTS equ htons(6) ; File exists
620 TFTP_ENOUSER equ htons(7) ; No such user
621 TFTP_EOPTNEG equ htons(8) ; Option negotiation failure
622
623 ;
624 ; The following structure is used for "virtual kernels"; i.e. LILO-style
625 ; option labels. The options we permit here are `kernel' and `append
626 ; Since there is no room in the bottom 64K for all of these, we
627 ; stick them at vk_seg:0000 and copy them down before we need them.
628 ;
629 struc vkernel
630 00000000 <res 00000080> vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
631 00000080 <res 00000080> vk_rname: resb FILENAME_MAX ; Real name
632 00000100 <res 00000001> vk_ipappend: resb 1 ; "IPAPPEND" flag
633 00000101 <res 00000001> resb 1 ; Pad
634 00000102 <res 00000002> vk_appendlen: resw 1
635 alignb 4
636 00000104 <res 00000200> vk_append: resb max_cmd_len+1 ; Command line
637 alignb 4
638 vk_end: equ $ ; Should be <= vk_size
639 endstruc
640
641 ;
642 ; Segment assignments in the bottom 640K
643 ; 0000h - main code/data segment (and BIOS segment)
644 ;
645 real_mode_seg equ 4000h
646 vk_seg equ 3000h ; Virtual kernels
647 xfer_buf_seg equ 2000h ; Bounce buffer for I/O to high mem
648 pktbuf_seg equ 1000h ; Packet buffers segments
649 comboot_seg equ real_mode_seg ; COMBOOT image loading zone
650
651 ;
652 ; BOOTP/DHCP packet pattern
653 ;
654 struc bootp_t
655 bootp:
656 00000000 <res 00000001> .opcode resb 1 ; BOOTP/DHCP "opcode"
657 00000001 <res 00000001> .hardware resb 1 ; ARP hardware type
658 00000002 <res 00000001> .hardlen resb 1 ; Hardware address length
659 00000003 <res 00000001> .gatehops resb 1 ; Used by forwarders
660 00000004 <res 00000004> .ident resd 1 ; Transaction ID
661 00000008 <res 00000002> .seconds resw 1 ; Seconds elapsed
662 0000000A <res 00000002> .flags resw 1 ; Broadcast flags
663 0000000C <res 00000004> .cip resd 1 ; Client IP
664 00000010 <res 00000004> .yip resd 1 ; "Your" IP
665 00000014 <res 00000004> .sip resd 1 ; Next server IP
666 00000018 <res 00000004> .gip resd 1 ; Relay agent IP
667 0000001C <res 00000010> .macaddr resb 16 ; Client MAC address
668 0000002C <res 00000040> .sname resb 64 ; Server name (optional)
669 0000006C <res 00000080> .bootfile resb 128 ; Boot file name
670 000000EC <res 00000004> .option_magic resd 1 ; Vendor option magic cookie
671 000000F0 <res 000004EC> .options resb 1260 ; Vendor options
672 endstruc
673
674 BOOTP_OPTION_MAGIC equ htonl(0x63825363) ; See RFC 2132
675
676 ;
677 ; TFTP connection data structure. Each one of these corresponds to a local
678 ; UDP port. The size of this structure must be a power of 2.
679 ; HBO = host byte order; NBO = network byte order
680 ; (*) = written by options negotiation code, must be dword sized
681 ;
682 struc open_file_t
683 00000000 <res 00000002> tftp_localport resw 1 ; Local port number (0 = not in use)
684 00000002 <res 00000002> tftp_remoteport resw 1 ; Remote port number
685 00000004 <res 00000004> tftp_remoteip resd 1 ; Remote IP address
686 00000008 <res 00000004> tftp_filepos resd 1 ; Bytes downloaded (including buffer)
687 0000000C <res 00000004> tftp_filesize resd 1 ; Total file size(*)
688 00000010 <res 00000004> tftp_blksize resd 1 ; Block size for this connection(*)
689 00000014 <res 00000002> tftp_bytesleft resw 1 ; Unclaimed data bytes
690 00000016 <res 00000002> tftp_lastpkt resw 1 ; Sequence number of last packet (NBO)
691 00000018 <res 00000002> tftp_dataptr resw 1 ; Pointer to available data
692 0000001A <res 00000004> resw 2 ; Currently unusued
693 ; At end since it should not be zeroed on socked close
694 0000001E <res 00000002> tftp_pktbuf resw 1 ; Packet buffer offset
695 endstruc
696 %ifndef DEPEND
697 %if (open_file_t_size & (open_file_t_size-1))
698 %error "open_file_t is not a power of 2"
699 %endif
700 %endif
701
702 ; ---------------------------------------------------------------------------
703 ; BEGIN CODE
704 ; ---------------------------------------------------------------------------
705
706 ;
707 ; Memory below this point is reserved for the BIOS and the MBR
708 ;
709 section .earlybss
710 trackbufsize equ 8192
711 00000000 <res 00002000> trackbuf resb trackbufsize ; Track buffer goes here
712 00002000 <res 00002000> getcbuf resb trackbufsize
713 ; ends at 4800h
714
715 ; Put some large buffers here, before RBFG_brainfuck,
716 ; where we can still carefully control the address
717 ; assignments...
718
719 alignb open_file_t_size
720 00004000 <res 00000400> Files resb MAX_OPEN*open_file_t_size
721
722 alignb FILENAME_MAX
723 00004400 <res 00000100> BootFile resb 256 ; Boot file from DHCP packet
724 00004500 <res 00000004> ConfigServer resd 1 ; Null prefix for mangled config name
725 00004504 <res 000000FC> ConfigName resb 256-4 ; Configuration file from DHCP option
726 00004600 <res 00000100> PathPrefix resb 256 ; Path prefix derived from boot file
727 00004700 <res 00000010> DotQuadBuf resb 16 ; Buffer for dotted-quad IP address
728 00004710 <res 00000050> IPOption resb 80 ; ip= option buffer
729 00004760 <res 00000004> InitStack resd 1 ; Pointer to reset stack
730
731 ; Warning here: RBFG build 22 randomly overwrites memory location
732 ; [0x5680,0x576c), possibly more. It seems that it gets confused and
733 ; screws up the pointer to its own internal packet buffer and starts
734 ; writing a received ARP packet into low memory.
735 00004764 <res 00000E00> RBFG_brainfuck resb 0E00h
736
737 section .bss
738 alignb 4
739 00000000 <res 00000004> RebootTime resd 1 ; Reboot timeout, if set by option
740 00000004 <res 00000004> StrucPtr resd 1 ; Pointer to PXENV+ or !PXE structure
741 00000008 <res 00000002> APIVer resw 1 ; PXE API version found
742 0000000A <res 00000002> IPOptionLen resw 1 ; Length of IPOption
743 0000000C <res 00000002> IdleTimer resw 1 ; Time to check for ARP?
744 0000000E <res 00000002> LocalBootType resw 1 ; Local boot return code
745 00000010 <res 00000002> PktTimeout resw 1 ; Timeout for current packet
746 00000012 <res 00000002> RealBaseMem resw 1 ; Amount of DOS memory after freeing
747 00000014 <res 00000001> OverLoad resb 1 ; Set if DHCP packet uses "overloading"
748
749 ; The relative position of these fields matter!
750 00000015 <res 00000001> MACLen resb 1 ; MAC address len
751 00000016 <res 00000001> MACType resb 1 ; MAC address type
752 00000017 <res 00000010> MAC resb 16 ; Actual MAC address
753 00000027 <res 00000007> BOOTIFStr resb 7 ; Space for "BOOTIF="
754 0000002E <res 00000033> MACStr resb 3*17 ; MAC address as a string
755
756 ;
757 ; PXE packets which don't need static initialization
758 ;
759 00000061 <res 00000001>- alignb 4
760 00000061 <rept>
761 pxe_unload_stack_pkt:
762 00000064 <res 00000002> .status: resw 1 ; Status
763 00000066 <res 00000014> .reserved: resw 10 ; Reserved
764 pxe_unload_stack_pkt_len equ $-pxe_unload_stack_pkt
765
766 0000007A <res 00000001>- alignb 16
767 0000007A <rept>
768 ; BOOTP/DHCP packet buffer
769
770 alignb 16
771 00000080 <res 00000800> packet_buf resb 2048 ; Transfer packet
772 packet_buf_size equ $-packet_buf
773
774 ;
775 ; Constants for the xfer_buf_seg
776 ;
777 ; The xfer_buf_seg is also used to store message file buffers. We
778 ; need two trackbuffers (text and graphics), plus a work buffer
779 ; for the graphics decompressor.
780 ;
781 xbs_textbuf equ 0 ; Also hard-coded, do not change
782 xbs_vgabuf equ trackbufsize
783 xbs_vgatmpbuf equ 2*trackbufsize
784
785 section .text
786 ;
787 ; PXELINUX needs more BSS than the other derivatives;
788 ; therefore we relocate it from 7C00h on startup.
789 ;
790 StackBuf equ $ ; Base of stack if we use our own
791
792 ;
793 ; Primary entry point.
794 ;
795 bootsec equ $
796 _start:
797 00000000 669C pushfd ; Paranoia... in case of return to PXE
798 00000002 6660 pushad ; ... save as much state as possible
799 00000004 1E push ds
800 00000005 06 push es
801 00000006 0FA0 push fs
802 00000008 0FA8 push gs
803
804 0000000A 31C0 xor ax,ax
805 0000000C 8ED8 mov ds,ax
806 0000000E 8EC0 mov es,ax
807
808 ; This is uglier than it should be, but works around
809 ; some NASM 0.98.38 bugs.
810 00000010 BF[0000] mov di,section..bcopy32.start
811 00000013 81C70802 add di,__bcopy_size-4
812 00000017 8DB500EC lea si,[di-(TEXT_START-7C00h)]
813 0000001B 8D8D0470 lea cx,[di-(TEXT_START-4)]
814 0000001F C1E902 shr cx,2
815 00000022 FD std ; Overlapping areas, copy backwards
816 00000023 F366A5 rep movsd
817
818 00000026 EA[2B00]0000 jmp 0:_start1 ; Canonicalize address
819 _start1:
820 0000002B 89E5 mov bp,sp
821 0000002D C45E30 les bx,[bp+48] ; ES:BX -> !PXE or PXENV+ structure
822
823 ; That is all pushed onto the PXE stack. Save the pointer
824 ; to it and switch to an internal stack.
825 00000030 8926[6047] mov [InitStack],sp
826 00000034 8C16[6247] mov [InitStack+2],ss
827
828 %if USE_PXE_PROVIDED_STACK
829 ; Apparently some platforms go bonkers if we
830 ; set up our own stack...
831 00000038 8926[A008] mov [BaseStack],sp
832 0000003C 8C16[A408] mov [BaseStack+4],ss
833 %endif
834
835 00000040 FA cli ; Paranoia
836 00000041 660FB226[A008] lss esp,[BaseStack]
837
838 00000047 FB sti ; Stack set up and ready
839 00000048 FC cld ; Copy upwards
840
841 ;
842 ; Initialize screen (if we're using one)
843 ;
844 ; Now set up screen parameters
845 00000049 E85A22 call adjust_screen
846
847 ; Wipe the F-key area
848 0000004C B000 mov al,NULLFILE
849 0000004E BF[DC16] mov di,FKeyName
850 00000051 B90005 mov cx,10*(1 << FILENAME_MAX_LG2)
851 00000054 06 push es ; Save ES -> PXE structure
852 00000055 1E push ds ; ES <- DS
853 00000056 07 pop es
854 00000057 F3AA rep stosb
855 00000059 07 pop es ; Restore ES
856
857 ;
858 ; Tell the user we got this far
859 ;
860 0000005A BE[EE06] mov si,syslinux_banner
861 0000005D E8F41D call writestr
862
863 00000060 BE[4B01] mov si,copyright_str
864 00000063 E8EE1D call writestr
865
866 ;
867 ; Assume API version 2.1, in case we find the !PXE structure without
868 ; finding the PXENV+ structure. This should really look at the Base
869 ; Code ROM ID structure in have_pxe, but this is adequate for now --
870 ; if we have !PXE, we have to be 2.1 or higher, and we don't care
871 ; about higher versions than that.
872 ;
873 00000066 C706[0800]0102 mov word [APIVer],0201h
874
875 ;
876 ; Now we need to find the !PXE structure. It's *supposed* to be pointed
877 ; to by SS:[SP+4], but support INT 1Ah, AX=5650h method as well.
878 ; FIX: ES:BX should point to the PXENV+ structure on entry as well.
879 ; We should make that the second test, and not trash ES:BX...
880 ;
881 0000006C 2666813F21505845 cmp dword [es:bx], '!PXE'
882 00000074 0F840F01 je have_pxe
883
884 ; Uh-oh, not there... try plan B
885 00000078 B85056 mov ax, 5650h
886 0000007B CD1A int 1Ah ; May trash regs
887 0000007D 7223 jc no_pxe
888 0000007F 3D4E56 cmp ax,564Eh
889 00000082 751E jne no_pxe
890
891 ; Okay, that gave us the PXENV+ structure, find !PXE
892 ; structure from that (if available)
893 00000084 2666813F5058454E cmp dword [es:bx], 'PXEN'
894 0000008C 7514 jne no_pxe
895 0000008E 26817F04562B cmp word [es:bx+4], 'V+'
896 00000094 7415 je have_pxenv
897
898 ; Nothing there either. Last-ditch: scan memory
899 00000096 E87C11 call memory_scan_for_pxe_struct ; !PXE scan
900 00000099 0F83EA00 jnc have_pxe
901 0000009D E8DE11 call memory_scan_for_pxenv_struct ; PXENV+ scan
902 000000A0 7309 jnc have_pxenv
903
904 000000A2 BE[3004] no_pxe: mov si,err_nopxe
905 000000A5 E8AC1D call writestr
906 000000A8 E90A11 jmp kaboom
907
908 have_pxenv:
909 000000AB 891E[0400] mov [StrucPtr],bx
910 000000AF 8C06[0600] mov [StrucPtr+2],es
911
912 000000B3 BE[CA04] mov si,found_pxenv
913 000000B6 E89B1D call writestr
914
915 000000B9 BE[1205] mov si,apiver_str
916 000000BC E8951D call writestr
917 000000BF 268B4706 mov ax,[es:bx+6]
918 000000C3 A3[0800] mov [APIVer],ax
919 000000C6 E8AB1D call writehex4
920 000000C9 E87B1D call crlf
921
922 000000CC 3D0102 cmp ax,0201h ; API version 2.1 or higher
923 000000CF 721F jb old_api
924 000000D1 89DE mov si,bx
925 000000D3 8CC0 mov ax,es
926 000000D5 26C45F28 les bx,[es:bx+28h] ; !PXE structure pointer
927 000000D9 2666813F21505845 cmp dword [es:bx],'!PXE'
928 000000E1 0F84A200 je have_pxe
929
930 ; Nope, !PXE structure missing despite API 2.1+, or at least
931 ; the pointer is missing. Do a last-ditch attempt to find it.
932 000000E5 E82D11 call memory_scan_for_pxe_struct
933 000000E8 0F839B00 jnc have_pxe
934
935 ; Otherwise, no dice, use PXENV+ structure
936 000000EC 89F3 mov bx,si
937 000000EE 8EC0 mov es,ax
938
939 old_api: ; Need to use a PXENV+ structure
940 000000F0 BE[E304] mov si,using_pxenv_msg
941 000000F3 E85E1D call writestr
942
943 000000F6 26668B470A mov eax,[es:bx+0Ah] ; PXE RM API
944 000000FB 66A3[A815] mov [PXENVEntry],eax
945
946 000000FF BE[C005] mov si,undi_data_msg
947 00000102 E84F1D call writestr
948 00000105 268B4720 mov ax,[es:bx+20h]
949 00000109 E8681D call writehex4
950 0000010C E8381D call crlf
951 0000010F BE[D905] mov si,undi_data_len_msg
952 00000112 E83F1D call writestr
953 00000115 268B4722 mov ax,[es:bx+22h]
954 00000119 E8581D call writehex4
955 0000011C E8281D call crlf
956 0000011F BE[F205] mov si,undi_code_msg
957 00000122 E82F1D call writestr
958 00000125 268B4724 mov ax,[es:bx+24h]
959 00000129 E8481D call writehex4
960 0000012C E8181D call crlf
961 0000012F BE[0B06] mov si,undi_code_len_msg
962 00000132 E81F1D call writestr
963 00000135 268B4726 mov ax,[es:bx+26h]
964 00000139 E8381D call writehex4
965 0000013C E8081D call crlf
966
967 ; Compute base memory size from PXENV+ structure
968 0000013F 6631F6 xor esi,esi
969 00000142 26660FB74720 movzx eax,word [es:bx+20h] ; UNDI data seg
970 00000148 263B4724 cmp ax,[es:bx+24h] ; UNDI code seg
971 0000014C 770A ja .use_data
972 0000014E 268B4724 mov ax,[es:bx+24h]
973 00000152 268B7726 mov si,[es:bx+26h]
974 00000156 EB04 jmp short .combine
975 .use_data:
976 00000158 268B7722 mov si,[es:bx+22h]
977 .combine:
978 0000015C 66C1E004 shl eax,4
979 00000160 6601F0 add eax,esi
980 00000163 66C1E80A shr eax,10 ; Convert to kilobytes
981 00000167 A3[1200] mov [RealBaseMem],ax
982
983 0000016A BE[4A05] mov si,pxenventry_msg
984 0000016D E8E41C call writestr
985 00000170 A1[AA15] mov ax,[PXENVEntry+2]
986 00000173 E8FE1C call writehex4
987 00000176 B03A mov al,':'
988 00000178 E80A24 call writechr
989 0000017B A1[A815] mov ax,[PXENVEntry]
990 0000017E E8F31C call writehex4
991 00000181 E8C31C call crlf
992 00000184 E99400 jmp have_entrypoint
993
994 have_pxe:
995 00000187 891E[0400] mov [StrucPtr],bx
996 0000018B 8C06[0600] mov [StrucPtr+2],es
997
998 0000018F 26668B4710 mov eax,[es:bx+10h]
999 00000194 66A3[B215] mov [PXEEntry],eax
1000
1001 00000198 BE[C005] mov si,undi_data_msg
1002 0000019B E8B61C call writestr
1003 0000019E 26668B472A mov eax,[es:bx+2Ah]
1004 000001A3 E8DB1C call writehex8
1005 000001A6 E89E1C call crlf
1006 000001A9 BE[D905] mov si,undi_data_len_msg
1007 000001AC E8A51C call writestr
1008 000001AF 268B472E mov ax,[es:bx+2Eh]
1009 000001B3 E8BE1C call writehex4
1010 000001B6 E88E1C call crlf
1011 000001B9 BE[F205] mov si,undi_code_msg
1012 000001BC E8951C call writestr
1013 000001BF 268B4732 mov ax,[es:bx+32h]
1014 000001C3 E8BB1C call writehex8
1015 000001C6 E87E1C call crlf
1016 000001C9 BE[0B06] mov si,undi_code_len_msg
1017 000001CC E8851C call writestr
1018 000001CF 268B4736 mov ax,[es:bx+36h]
1019 000001D3 E89E1C call writehex4
1020 000001D6 E86E1C call crlf
1021
1022 ; Compute base memory size from !PXE structure
1023 000001D9 6631F6 xor esi,esi
1024 000001DC 26668B472A mov eax,[es:bx+2Ah]
1025 000001E1 26663B4732 cmp eax,[es:bx+32h]
1026 000001E6 770B ja .use_data
1027 000001E8 26668B4732 mov eax,[es:bx+32h]
1028 000001ED 268B7736 mov si,[es:bx+36h]
1029 000001F1 EB04 jmp short .combine
1030 .use_data:
1031 000001F3 268B772E mov si,[es:bx+2Eh]
1032 .combine:
1033 000001F7 6601F0 add eax,esi
1034 000001FA 66C1E80A shr eax,10
1035 000001FE A3[1200] mov [RealBaseMem],ax
1036
1037 00000201 BE[2605] mov si,pxeentry_msg
1038 00000204 E84D1C call writestr
1039 00000207 A1[B415] mov ax,[PXEEntry+2]
1040 0000020A E8671C call writehex4
1041 0000020D B03A mov al,':'
1042 0000020F E87323 call writechr
1043 00000212 A1[B215] mov ax,[PXEEntry]
1044 00000215 E85C1C call writehex4
1045 00000218 E82C1C call crlf
1046
1047 have_entrypoint:
1048 0000021B 0E push cs
1049 0000021C 07 pop es ; Restore CS == DS == ES
1050
1051 ;
1052 ; Network-specific initialization
1053 ;
1054 0000021D 31C0 xor ax,ax
1055 0000021F A2[9C23] mov [LocalDomain],al ; No LocalDomain received
1056
1057 ;
1058 ; Now attempt to get the BOOTP/DHCP packet that brought us life (and an IP
1059 ; address). This lives in the DHCPACK packet (query info 2).
1060 ;
1061 query_bootp:
1062 00000222 BF[4A08] mov di,pxe_bootp_query_pkt_2
1063 00000225 BB7100 mov bx,PXENV_GET_CACHED_INFO
1064
1065 00000228 E87C13 call pxenv
1066 0000022B FF36[4A08] push word [pxe_bootp_query_pkt_2.status]
1067 0000022F 7205 jc .pxe_err1
1068 00000231 83F800 cmp ax,byte 0
1069 00000234 742C je .pxe_ok
1070 .pxe_err1:
1071 00000236 BF[6208] mov di,pxe_bootp_size_query_pkt
1072 00000239 BB7100 mov bx,PXENV_GET_CACHED_INFO
1073
1074 0000023C E86813 call pxenv
1075 0000023F 7209 jc .pxe_err
1076 .pxe_size:
1077 00000241 A1[6608] mov ax,[pxe_bootp_size_query_pkt.buffersize]
1078 00000244 E82D1C call writehex4
1079 00000247 E8FD1B call crlf
1080
1081 .pxe_err:
1082 0000024A BE[5D04] mov si,err_pxefailed
1083 0000024D E8041C call writestr
1084 00000250 E8211C call writehex4
1085 00000253 B020 mov al, ' '
1086 00000255 E82D23 call writechr
1087 00000258 58 pop ax ; Status
1088 00000259 E8181C call writehex4
1089 0000025C E8E81B call crlf
1090 0000025F E9530F jmp kaboom ; We're dead
1091
1092 .pxe_ok:
1093 00000262 59 pop cx ; Forget status
1094 00000263 8B0E[4E08] mov cx,[pxe_bootp_query_pkt_2.buffersize]
1095 00000267 E8C215 call parse_dhcp ; Parse DHCP packet
1096 ;
1097 ; Save away MAC address (assume this is in query info 2. If this
1098 ; turns out to be problematic it might be better getting it from
1099 ; the query info 1 packet.)
1100 ;
1101 .save_mac:
1102 0000026A 0FB60E[0200] movzx cx,byte [trackbuf+bootp.hardlen]
1103 0000026F 880E[1500] mov [MACLen],cl
1104 00000273 A0[0100] mov al,[trackbuf+bootp.hardware]
1105 00000276 A2[1600] mov [MACType],al
1106 00000279 BE[1C00] mov si,trackbuf+bootp.macaddr
1107 0000027C BF[1700] mov di,MAC
1108 0000027F 51 push cx
1109 00000280 F3A4 rep movsb
1110 00000282 B9[2700] mov cx,MAC+16
1111 00000285 29F9 sub cx,di
1112 00000287 31C0 xor ax,ax
1113 00000289 F3AA rep stosb
1114
1115 0000028B BE[1E07] mov si,bootif_str
1116 0000028E BF[2700] mov di,BOOTIFStr
1117 00000291 B90700 mov cx,bootif_str_len
1118 00000294 F3A4 rep movsb
1119
1120 00000296 59 pop cx
1121 00000297 BE[1600] mov si,MACType
1122 0000029A 41 inc cx
1123 0000029B BB[3B01] mov bx,hextbl_lower
1124 .hexify_mac:
1125 0000029E AC lodsb
1126 0000029F 88C4 mov ah,al
1127 000002A1 C0E804 shr al,4
1128 000002A4 D7 xlatb
1129 000002A5 AA stosb
1130 000002A6 88E0 mov al,ah
1131 000002A8 240F and al,0Fh
1132 000002AA D7 xlatb
1133 000002AB AA stosb
1134 000002AC B02D mov al,'-'
1135 000002AE AA stosb
1136 000002AF E2ED loop .hexify_mac
1137 000002B1 C645FF00 mov [di-1],byte 0 ; Null-terminate and strip final colon
1138
1139 ;
1140 ; Now, get the boot file and other info. This lives in the CACHED_REPLY
1141 ; packet (query info 3).
1142 ;
1143 000002B5 C606[6408]03 mov [pxe_bootp_size_query_pkt.packettype], byte 3
1144
1145 000002BA BF[5608] mov di,pxe_bootp_query_pkt_3
1146 000002BD BB7100 mov bx,PXENV_GET_CACHED_INFO
1147
1148 000002C0 E8E412 call pxenv
1149 000002C3 FF36[5608] push word [pxe_bootp_query_pkt_3.status]
1150 000002C7 0F826BFF jc .pxe_err1
1151 000002CB 83F800 cmp ax,byte 0
1152 000002CE 0F8564FF jne .pxe_err1
1153
1154 ; Packet loaded OK...
1155 000002D2 59 pop cx ; Forget status
1156 000002D3 8B0E[5A08] mov cx,[pxe_bootp_query_pkt_3.buffersize]
1157 000002D7 E85215 call parse_dhcp ; Parse DHCP packet
1158 ;
1159 ; Generate ip= option
1160 ;
1161 000002DA E8CC16 call genipopt
1162
1163 ;
1164 ; Print IP address
1165 ;
1166 000002DD 66A1[EC08] mov eax,[MyIP]
1167 000002E1 BF[0047] mov di,DotQuadBuf
1168 000002E4 57 push di
1169 000002E5 E80B15 call gendotquad ; This takes network byte order input
1170
1171 000002E8 86E0 xchg ah,al ; Convert to host byte order
1172 000002EA 66C1C810 ror eax,16 ; (BSWAP doesn't work on 386)
1173 000002EE 86E0 xchg ah,al
1174
1175 000002F0 BE[5306] mov si,myipaddr_msg
1176 000002F3 E85E1B call writestr
1177 000002F6 E8881B call writehex8
1178 000002F9 B020 mov al,' '
1179 000002FB E88722 call writechr
1180 000002FE 5E pop si ; DotQuadBuf
1181 000002FF E8521B call writestr
1182 00000302 E8421B call crlf
1183
1184 00000305 BE[1047] mov si,IPOption
1185 00000308 E8491B call writestr
1186 0000030B E8391B call crlf
1187
1188 ;
1189 ; Check to see if we got any PXELINUX-specific DHCP options; in particular,
1190 ; if we didn't get the magic enable, do not recognize any other options.
1191 ;
1192 check_dhcp_magic:
1193 0000030E F606[0909]01 test byte [DHCPMagic], 1 ; If we didn't get the magic enable...
1194 00000313 7505 jnz .got_magic
1195 00000315 C606[0909]00 mov byte [DHCPMagic], 0 ; If not, kill all other options
1196 .got_magic:
1197
1198
1199 ;
1200 ; Initialize UDP stack
1201 ;
1202 udp_init:
1203 0000031A 66A1[EC08] mov eax,[MyIP]
1204 0000031E 66A3[7008] mov [pxe_udp_open_pkt.sip],eax
1205 00000322 BF[6E08] mov di,pxe_udp_open_pkt
1206 00000325 BB3000 mov bx,PXENV_UDP_OPEN
1207 00000328 E87C12 call pxenv
1208 0000032B 7207 jc .failed
1209 0000032D 833E[6E08]00 cmp word [pxe_udp_open_pkt.status], byte 0
1210 00000332 7409 je .success
1211 00000334 BE[7904] .failed: mov si,err_udpinit
1212 00000337 E81A1B call writestr
1213 0000033A E9780E jmp kaboom
1214 .success:
1215
1216 ;
1217 ; Common initialization code
1218 ;
1219 %include "init.inc"
1220 <1> ; -*- fundamental -*-
1221 <1> ; -----------------------------------------------------------------------
1222 <1> ;
1223 <1> ; Copyright 2004 H. Peter Anvin - All Rights Reserved
1224 <1> ;
1225 <1> ; This program is free software; you can redistribute it and/or modify
1226 <1> ; it under the terms of the GNU General Public License as published by
1227 <1> ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
1228 <1> ; Boston MA 02111-1307, USA; either version 2 of the License, or
1229 <1> ; (at your option) any later version; incorporated herein by reference.
1230 <1> ;
1231 <1> ; -----------------------------------------------------------------------
1232 <1> ; $Id: init.inc,v 1.1 2004/12/19 07:08:48 hpa Exp $
1233 <1>
1234 <1> ;
1235 <1> ; init.inc
1236 <1> ;
1237 <1> ; Common initialization code (inline)
1238 <1> ;
1239 <1>
1240 <1> section .text
1241 <1> common_init:
1242 <1> ; Now set up screen parameters
1243 0000033D E8661F <1> call adjust_screen
1244 <1>
1245 <1> ; Wipe the F-key area
1246 00000340 B000 <1> mov al,NULLFILE
1247 00000342 BF[DC16] <1> mov di,FKeyName
1248 00000345 B90005 <1> mov cx,10*(1 << FILENAME_MAX_LG2)
1249 00000348 F3AA <1> rep stosb
1250 <1>
1251 0000034A BE[0000] <1> mov si,linuxauto_cmd ; Default command: "linux auto"
1252 0000034D BF[D80A] <1> mov di,default_cmd
1253 00000350 B90B00 <1> mov cx,linuxauto_len
1254 00000353 F3A4 <1> rep movsb
1255 <1>
1256 00000355 BF[DC15] <1> mov di,KbdMap ; Default keymap 1:1
1257 00000358 30C0 <1> xor al,al
1258 0000035A FEC5 <1> inc ch ; CX <- 256
1259 0000035C AA <1> mkkeymap: stosb
1260 0000035D FEC0 <1> inc al
1261 0000035F E2FB <1> loop mkkeymap
1262 <1>
1263 <1> ;
1264 <1> ; Clear Files structures
1265 <1> ;
1266 00000361 BF[0040] <1> mov di,Files
1267 00000364 B90001 <1> mov cx,(MAX_OPEN*open_file_t_size)/4
1268 00000367 6631C0 <1> xor eax,eax
1269 0000036A F366AB <1> rep stosd
1270 <1>
1271 <1> %if IS_PXELINUX
1272 0000036D BF[1E40] <1> mov di,Files+tftp_pktbuf
1273 00000370 B92000 <1> mov cx,MAX_OPEN
1274 <1> .setbufptr:
1275 00000373 8905 <1> mov [di],ax
1276 00000375 83C720 <1> add di,open_file_t_size
1277 00000378 050008 <1> add ax,PKTBUF_SIZE
1278 0000037B E2F6 <1> loop .setbufptr
1279 <1> %endif
1280 <1>
1281 <1> section .data
1282 00000000 6C696E757820617574- <1> linuxauto_cmd db 'linux auto',0
1283 00000009 6F00 <1>
1284 <1> linuxauto_len equ $-linuxauto_cmd
1285 <1>
1286 <1> section .text ; This is an inline file...
1287 <1>
1288 %include "cpuinit.inc"
1289 <1> ;; $Id: cpuinit.inc,v 1.5 2004/12/27 07:04:08 hpa Exp $
1290 <1> ;; -----------------------------------------------------------------------
1291 <1> ;;
1292 <1> ;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
1293 <1> ;;
1294 <1> ;; This program is free software; you can redistribute it and/or modify
1295 <1> ;; it under the terms of the GNU General Public License as published by
1296 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
1297 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
1298 <1> ;; (at your option) any later version; incorporated herein by reference.
1299 <1> ;;
1300 <1> ;; -----------------------------------------------------------------------
1301 <1>
1302 <1> ;;
1303 <1> ;; cpuinit.inc
1304 <1> ;;
1305 <1> ;; CPU-dependent initialization and related checks.
1306 <1> ;;
1307 <1>
1308 <1> check_escapes:
1309 0000037D B402 <1> mov ah,02h ; Check keyboard flags
1310 0000037F CD16 <1> int 16h
1311 00000381 A2[8408] <1> mov [KbdFlags],al ; Save for boot prompt check
1312 00000384 A804 <1> test al,04h ; Ctrl->skip 386 check
1313 00000386 7510 <1> jnz skip_checks
1314 <1>
1315 <1> ;
1316 <1> ; Now check that there is sufficient low (DOS) memory
1317 <1> ;
1318 <1> ; NOTE: Linux doesn't use all of real_mode_seg, but we use the same
1319 <1> ; segment for COMBOOT images, which can use all 64K
1320 <1> ;
1321 <1> dosram_k equ (real_mode_seg+0x1000) >> 6 ; Minimum DOS memory (K)
1322 00000388 CD12 <1> int 12h
1323 0000038A 3D4001 <1> cmp ax,dosram_k
1324 0000038D 7309 <1> jae enough_ram
1325 0000038F BE[C301] <1> mov si,err_noram
1326 00000392 E8BF1A <1> call writestr
1327 00000395 E91D0E <1> jmp kaboom
1328 <1> enough_ram:
1329 <1> skip_checks:
1330 <1>
1331 <1> ;
1332 <1> ; Initialize the bcopy32 code in low memory
1333 <1> ;
1334 00000398 BE[0000] <1> mov si,section..bcopy32.start
1335 0000039B BF[0000] <1> mov di,__bcopy_start
1336 0000039E B98300 <1> mov cx,__bcopy_size >> 2
1337 000003A1 F366A5 <1> rep movsd
1338 <1>
1339 <1> ;
1340 <1> ; Check if we're 386 (as opposed to 486+); if so we need to blank out
1341 <1> ; the WBINVD instruction
1342 <1> ;
1343 <1> ; We check for 486 by setting EFLAGS.AC
1344 <1> ;
1345 <1> %if DO_WBINVD
1346 <1> pushfd ; Save the good flags
1347 <1> pushfd
1348 <1> pop eax
1349 <1> mov ebx,eax
1350 <1> xor eax,(1 << 18) ; AC bit
1351 <1> push eax
1352 <1> popfd
1353 <1> pushfd
1354 <1> pop eax
1355 <1> popfd ; Restore the original flags
1356 <1> xor eax,ebx
1357 <1> jnz is_486
1358 <1> ;
1359 <1> ; 386 - Looks like we better blot out the WBINVD instruction
1360 <1> ;
1361 <1> mov byte [try_wbinvd],0c3h ; Near RET
1362 <1> is_486:
1363 <1> %endif ; DO_WBINVD
1364 <1>
1365
1366 ;
1367 ; Now we're all set to start with our *real* business. First load the
1368 ; configuration file (if any) and parse it.
1369 ;
1370 ; In previous versions I avoided using 32-bit registers because of a
1371 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
1372 ; random. I figure, though, that if there are any of those still left
1373 ; they probably won't be trying to install Linux on them...
1374 ;
1375 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
1376 ; to take'm out. In fact, we may want to put them back if we're going
1377 ; to boot ELKS at some point.
1378 ;
1379
1380 ;
1381 ; Store standard filename prefix
1382 ;
1383 000003A4 F606[0909]04 prefix: test byte [DHCPMagic], 04h ; Did we get a path prefix option
1384 000003A9 7537 jnz .got_prefix
1385 000003AB BE[0044] mov si,BootFile
1386 000003AE BF[0046] mov di,PathPrefix
1387 000003B1 FC cld
1388 000003B2 E8C721 call strcpy
1389 000003B5 89F9 mov cx,di
1390 000003B7 81E9[0146] sub cx,PathPrefix+1
1391 000003BB FD std
1392 000003BC 8D75FE lea si,[di-2] ; Skip final null!
1393 000003BF AC .find_alnum: lodsb
1394 000003C0 0C20 or al,20h
1395 000003C2 3C2E cmp al,'.' ; Count . or - as alphanum
1396 000003C4 7414 je .alnum
1397 000003C6 3C2D cmp al,'-'
1398 000003C8 7410 je .alnum
1399 000003CA 3C30 cmp al,'0'
1400 000003CC 720F jb .notalnum
1401 000003CE 3C39 cmp al,'9'
1402 000003D0 7608 jbe .alnum
1403 000003D2 3C61 cmp al,'a'
1404 000003D4 7207 jb .notalnum
1405 000003D6 3C7A cmp al,'z'
1406 000003D8 7703 ja .notalnum
1407 000003DA E2E3 .alnum: loop .find_alnum
1408 000003DC 4E dec si
1409 000003DD C6440200 .notalnum: mov byte [si+2],0 ; Zero-terminate after delimiter
1410 000003E1 FC cld
1411 .got_prefix:
1412 000003E2 BE[6E06] mov si,tftpprefix_msg
1413 000003E5 E86C1A call writestr
1414 000003E8 BE[0046] mov si,PathPrefix
1415 000003EB E8661A call writestr
1416 000003EE E8561A call crlf
1417
1418 ;
1419 ; Load configuration file
1420 ;
1421 find_config:
1422
1423 ;
1424 ; Begin looking for configuration file
1425 ;
1426 config_scan:
1427 000003F1 BF[0045] mov di,ConfigServer
1428 000003F4 6631C0 xor eax,eax
1429 000003F7 66AB stosd ; The config file is always from the server
1430
1431 000003F9 F606[0909]02 test byte [DHCPMagic], 02h
1432 000003FE 7418 jz .no_option
1433
1434 ; We got a DHCP option, try it first
1435 00000400 BE[B306] mov si,trying_msg
1436 00000403 E84E1A call writestr
1437 ; mov di,ConfigName ; - already the case
1438 00000406 89FE mov si,di
1439 00000408 E8491A call writestr
1440 0000040B E8391A call crlf
1441 0000040E BF[0045] mov di,ConfigServer
1442 00000411 E82C16 call open
1443 00000414 0F858900 jnz .success
1444
1445 .no_option:
1446 00000418 BF[0445] mov di,ConfigName
1447 0000041B BE[0A07] mov si,cfgprefix
1448 0000041E B90D00 mov cx,cfgprefix_len
1449 00000421 F3A4 rep movsb
1450
1451 ; Try loading by MAC address
1452 ; Have to guess config file name
1453 00000423 57 push di
1454 00000424 BE[2E00] mov si,MACStr
1455 00000427 B91A00 mov cx,(3*17+1)/2
1456 0000042A F3A5 rep movsw
1457 0000042C BE[B306] mov si,trying_msg
1458 0000042F E8221A call writestr
1459 00000432 BF[0445] mov di,ConfigName
1460 00000435 89FE mov si,di
1461 00000437 E81A1A call writestr
1462 0000043A E80A1A call crlf
1463 0000043D BF[0045] mov di,ConfigServer
1464 00000440 E8FD15 call open
1465 00000443 5F pop di
1466 00000444 755B jnz .success
1467
1468 .scan_ip:
1469 00000446 B90800 mov cx,8
1470 00000449 66A1[EC08] mov eax,[MyIP]
1471 0000044D 86E0 xchg ah,al ; Convert to host byte order
1472 0000044F 66C1C810 ror eax,16
1473 00000453 86E0 xchg ah,al
1474 00000455 66C1C004 .hexify_loop: rol eax,4
1475 00000459 6650 push eax
1476 0000045B 240F and al,0Fh
1477 0000045D 3C0A cmp al,10
1478 0000045F 7304 jae .high
1479 00000461 0430 .low: add al,'0'
1480 00000463 EB02 jmp short .char
1481 00000465 0437 .high: add al,'A'-10
1482 00000467 AA .char: stosb
1483 00000468 6658 pop eax
1484 0000046A E2E9 loop .hexify_loop
1485
1486 0000046C B90900 mov cx,9 ; Up to 9 attempts
1487
1488 0000046F C60500 .tryagain: mov byte [di],0
1489 00000472 83F901 cmp cx,byte 1
1490 00000475 750A jne .not_default
1491 00000477 60 pusha
1492 00000478 BE[E606] mov si,default_str
1493 0000047B B90800 mov cx,default_len
1494 0000047E F3A4 rep movsb ; Copy "default" string
1495 00000480 61 popa
1496 00000481 60 .not_default: pusha
1497 00000482 BE[B306] mov si,trying_msg
1498 00000485 E8CC19 call writestr
1499 00000488 BF[0445] mov di,ConfigName
1500 0000048B 89FE mov si,di
1501 0000048D E8C419 call writestr
1502 00000490 E8B419 call crlf
1503 00000493 BF[0045] mov di,ConfigServer
1504 00000496 E8A715 call open
1505 00000499 61 popa
1506 0000049A 7505 jnz .success
1507 0000049C 4F dec di
1508 0000049D E2D0 loop .tryagain
1509
1510 0000049F EB03 jmp no_config_file
1511
1512 .success:
1513
1514 ;
1515 ; Now we have the config file open. Parse the config file and
1516 ; run the user interface.
1517 ;
1518 %include "ui.inc"
1519 <1> ;; $Id: ui.inc,v 1.20 2005/04/08 16:33:32 hpa Exp $
1520 <1> ;; -----------------------------------------------------------------------
1521 <1> ;;
1522 <1> ;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
1523 <1> ;;
1524 <1> ;; This program is free software; you can redistribute it and/or modify
1525 <1> ;; it under the terms of the GNU General Public License as published by
1526 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
1527 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
1528 <1> ;; (at your option) any later version; incorporated herein by reference.
1529 <1> ;;
1530 <1> ;; -----------------------------------------------------------------------
1531 <1>
1532 <1> ;
1533 <1> ; This file should be entered with the config file open (for getc)
1534 <1> ;
1535 000004A1 E8E31B <1> call parse_config ; Parse configuration file
1536 <1> no_config_file:
1537 <1> ;
1538 <1> ; Check whether or not we are supposed to display the boot prompt.
1539 <1> ;
1540 <1> check_for_key:
1541 000004A4 833E[F000]00 <1> cmp word [ForcePrompt],byte 0 ; Force prompt?
1542 000004A9 7509 <1> jnz enter_command
1543 000004AB F606[8408]5B <1> test byte [KbdFlags],5Bh ; Caps, Scroll, Shift, Alt
1544 000004B0 0F842001 <1> jz auto_boot ; If neither, default boot
1545 <1>
1546 <1> enter_command:
1547 000004B4 BE[7501] <1> mov si,boot_prompt
1548 000004B7 E89A19 <1> call cwritestr
1549 <1>
1550 000004BA C606[8508]00 <1> mov byte [FuncFlag],0 ; <Ctrl-F> not pressed
1551 000004BF BF[D408] <1> mov di,command_line
1552 <1> ;
1553 <1> ; get the very first character -- we can either time
1554 <1> ; out, or receive a character press at this time. Some dorky BIOSes stuff
1555 <1> ; a return in the buffer on bootup, so wipe the keyboard buffer first.
1556 <1> ;
1557 000004C2 B411 <1> clear_buffer: mov ah,11h ; Check for pending char
1558 000004C4 CD16 <1> int 16h
1559 000004C6 7406 <1> jz get_char_time
1560 000004C8 B410 <1> mov ah,10h ; Get char
1561 000004CA CD16 <1> int 16h
1562 000004CC EBF4 <1> jmp short clear_buffer
1563 <1> get_char_time:
1564 000004CE E89C1F <1> call vgashowcursor
1565 <1> RESET_IDLE
1566 000004D1 E81315 <2> call reset_idle
1567 000004D4 8B0E[EC00] <1> mov cx,[KbdTimeOut]
1568 000004D8 21C9 <1> and cx,cx
1569 000004DA 7428 <1> jz get_char ; Timeout == 0 -> no timeout
1570 000004DC 41 <1> inc cx ; The first loop will happen
1571 <1> ; immediately as we don't
1572 <1> ; know the appropriate DX value
1573 000004DD 51 <1> time_loop: push cx
1574 000004DE 52 <1> tick_loop: push dx
1575 000004DF E8FA18 <1> call pollchar
1576 000004E2 751E <1> jnz get_char_pop
1577 000004E4 8B166C04 <1> mov dx,[BIOS_timer] ; Get time "of day"
1578 000004E8 58 <1> pop ax
1579 000004E9 39C2 <1> cmp dx,ax ; Has the timer advanced?
1580 000004EB 74F1 <1> je tick_loop
1581 000004ED 59 <1> pop cx
1582 <1> DO_IDLE
1583 000004EE E80115 <2> call check_for_arp
1584 000004F1 E2EA <1> loop time_loop ; If so, decrement counter
1585 <1>
1586 <1> ; Timeout!!!!
1587 000004F3 E87D1F <1> call vgahidecursor
1588 000004F6 BE[DC11] <1> mov si,Ontimeout ; Copy ontimeout command
1589 000004F9 8B0E[E800] <1> mov cx,[OntimeoutLen] ; if we have one...
1590 000004FD F3A4 <1> rep movsb
1591 <1> .stddefault:
1592 000004FF E9E000 <1> jmp command_done
1593 <1>
1594 00000502 6658 <1> get_char_pop: pop eax ; Clear stack
1595 <1> get_char:
1596 00000504 E8661F <1> call vgashowcursor
1597 00000507 E8FC18 <1> call getchar
1598 0000050A E8661F <1> call vgahidecursor
1599 0000050D 20C0 <1> and al,al
1600 0000050F 747B <1> jz func_key
1601 <1>
1602 00000511 3C7F <1> got_ascii: cmp al,7Fh ; <DEL> == <BS>
1603 00000513 744D <1> je backspace
1604 00000515 3C20 <1> cmp al,' ' ; ASCII?
1605 00000517 722A <1> jb not_ascii
1606 00000519 7706 <1> ja enter_char
1607 0000051B 81FF[D408] <1> cmp di,command_line ; Space must not be first
1608 0000051F 74E3 <1> je short get_char
1609 00000521 F606[8508]01 <1> enter_char: test byte [FuncFlag],1
1610 00000526 740F <1> jz .not_ctrl_f
1611 00000528 C606[8508]00 <1> mov byte [FuncFlag],0
1612 0000052D 3C30 <1> cmp al,'0'
1613 0000052F 7206 <1> jb .not_ctrl_f
1614 00000531 7451 <1> je ctrl_f_0
1615 00000533 3C39 <1> cmp al,'9'
1616 00000535 764F <1> jbe ctrl_f
1617 00000537 81FF[D30A] <1> .not_ctrl_f: cmp di,max_cmd_len+command_line ; Check there's space
1618 0000053B 73C7 <1> jnb short get_char
1619 0000053D AA <1> stosb ; Save it
1620 0000053E E84420 <1> call writechr ; Echo to screen
1621 00000541 EBC1 <1> jmp short get_char
1622 00000543 C606[8508]00 <1> not_ascii: mov byte [FuncFlag],0
1623 00000548 3C0D <1> cmp al,0Dh ; Enter
1624 0000054A 0F849400 <1> je command_done
1625 0000054E 3C06 <1> cmp al,'F' & 1Fh ; <Ctrl-F>
1626 00000550 742B <1> je set_func_flag
1627 00000552 3C15 <1> cmp al,'U' & 1Fh ; <Ctrl-U>
1628 00000554 741B <1> je kill_command ; Kill input line
1629 00000556 3C16 <1> cmp al,'V' & 1Fh ; <Ctrl-V>
1630 00000558 7459 <1> je print_version
1631 0000055A 3C18 <1> cmp al,'X' & 1Fh ; <Ctrl-X>
1632 0000055C 7419 <1> je force_text_mode
1633 0000055E 3C08 <1> cmp al,08h ; Backspace
1634 00000560 75A2 <1> jne get_char
1635 00000562 81FF[D408] <1> backspace: cmp di,command_line ; Make sure there is anything
1636 00000566 749C <1> je get_char ; to erase
1637 00000568 4F <1> dec di ; Unstore one character
1638 00000569 BE[7C01] <1> mov si,wipe_char ; and erase it from the screen
1639 0000056C E8E518 <1> call cwritestr
1640 0000056F EB11 <1> jmp short get_char_2
1641 <1>
1642 <1> kill_command:
1643 00000571 E8D318 <1> call crlf
1644 00000574 E93DFF <1> jmp enter_command
1645 <1>
1646 <1> force_text_mode:
1647 00000577 E8CB1E <1> call vgaclearmode
1648 0000057A E937FF <1> jmp enter_command
1649 <1>
1650 <1> set_func_flag:
1651 0000057D C606[8508]01 <1> mov byte [FuncFlag],1
1652 <1> get_char_2:
1653 00000582 EB80 <1> jmp short get_char
1654 <1>
1655 00000584 040A <1> ctrl_f_0: add al,10 ; <Ctrl-F>0 == F10
1656 00000586 2C31 <1> ctrl_f: sub al,'1'
1657 00000588 30E4 <1> xor ah,ah
1658 0000058A EB0A <1> jmp short show_help
1659 <1>
1660 <1> func_key:
1661 <1> ; AL = 0 if we get here
1662 0000058C 86C4 <1> xchg al,ah
1663 0000058E 3C44 <1> cmp al,68 ; F10
1664 00000590 77F0 <1> ja short get_char_2
1665 00000592 2C3B <1> sub al,59 ; F1
1666 00000594 72EC <1> jb short get_char_2
1667 <1> show_help: ; AX = func key # (0 = F1, 9 = F10)
1668 00000596 57 <1> push di ; Save end-of-cmdline pointer
1669 00000597 C1E007 <1> shl ax,FILENAME_MAX_LG2 ; Convert to pointer
1670 0000059A 05[DC16] <1> add ax,FKeyName
1671 0000059D 97 <1> xchg di,ax
1672 0000059E 807D0400 <1> cmp byte [di+NULLOFFSET],NULLFILE
1673 000005A2 742D <1> je short fk_nofile ; Undefined F-key
1674 000005A4 E8360D <1> call searchdir
1675 000005A7 7428 <1> jz short fk_nofile ; File not found
1676 000005A9 56 <1> push si
1677 000005AA E89A18 <1> call crlf
1678 000005AD 5E <1> pop si
1679 000005AE E83D16 <1> call get_msg_file
1680 000005B1 EB0D <1> jmp short fk_wrcmd
1681 <1>
1682 <1> print_version:
1683 000005B3 57 <1> push di ; Command line write pointer
1684 000005B4 BE[EE06] <1> mov si,syslinux_banner
1685 000005B7 E89A18 <1> call cwritestr
1686 000005BA BE[4B01] <1> mov si,copyright_str
1687 000005BD E89418 <1> call cwritestr
1688 <1>
1689 <1> ; ... fall through ...
1690 <1>
1691 <1> ; Write the boot prompt and command line again and
1692 <1> ; wait for input. Note that this expects the cursor
1693 <1> ; to already have been CRLF'd, and that the old value
1694 <1> ; of DI (the command line write pointer) is on the stack.
1695 <1> fk_wrcmd:
1696 000005C0 BE[7501] <1> mov si,boot_prompt
1697 000005C3 E88E18 <1> call cwritestr
1698 000005C6 5F <1> pop di ; Command line write pointer
1699 000005C7 57 <1> push di
1700 000005C8 C60500 <1> mov byte [di],0 ; Null-terminate command line
1701 000005CB BE[D408] <1> mov si,command_line
1702 000005CE E88318 <1> call cwritestr ; Write command line so far
1703 000005D1 5F <1> fk_nofile: pop di
1704 000005D2 EBAE <1> jmp short get_char_2
1705 <1> auto_boot:
1706 000005D4 BE[D80A] <1> mov si,default_cmd
1707 000005D7 BF[D408] <1> mov di,command_line
1708 000005DA B98000 <1> mov cx,(max_cmd_len+4) >> 2
1709 000005DD F366A5 <1> rep movsd
1710 000005E0 EB0C <1> jmp short load_kernel
1711 <1> command_done:
1712 000005E2 E86218 <1> call crlf
1713 000005E5 81FF[D408] <1> cmp di,command_line ; Did we just hit return?
1714 000005E9 74E9 <1> je auto_boot
1715 000005EB 30C0 <1> xor al,al ; Store a final null
1716 000005ED AA <1> stosb
1717 <1>
1718 <1> load_kernel: ; Load the kernel now
1719 <1> ;
1720 <1> ; First we need to mangle the kernel name the way DOS would...
1721 <1> ;
1722 000005EE BE[D408] <1> mov si,command_line
1723 000005F1 BF[E01B] <1> mov di,KernelName
1724 000005F4 56 <1> push si
1725 000005F5 57 <1> push di
1726 000005F6 E8420F <1> call mangle_name
1727 000005F9 5F <1> pop di
1728 000005FA 5E <1> pop si
1729 <1> ;
1730 <1> ; Fast-forward to first option (we start over from the beginning, since
1731 <1> ; mangle_name doesn't necessarily return a consistent ending state.)
1732 <1> ;
1733 000005FB AC <1> clin_non_wsp: lodsb
1734 000005FC 3C20 <1> cmp al,' '
1735 000005FE 77FB <1> ja clin_non_wsp
1736 00000600 20C0 <1> clin_is_wsp: and al,al
1737 00000602 7405 <1> jz clin_opt_ptr
1738 00000604 AC <1> lodsb
1739 00000605 3C20 <1> cmp al,' '
1740 00000607 76F7 <1> jbe clin_is_wsp
1741 00000609 4E <1> clin_opt_ptr: dec si ; Point to first nonblank
1742 0000060A 8936[8208] <1> mov [CmdOptPtr],si ; Save ptr to first option
1743 <1> ;
1744 <1> ; If "allowoptions 0", put a null character here in order to ignore any
1745 <1> ; user-specified options.
1746 <1> ;
1747 0000060E A1[F400] <1> mov ax,[AllowOptions]
1748 00000611 21C0 <1> and ax,ax
1749 00000613 7502 <1> jnz clin_opt_ok
1750 00000615 8804 <1> mov [si],al
1751 <1> clin_opt_ok:
1752 <1>
1753 <1> ;
1754 <1> ; Now check if it is a "virtual kernel"
1755 <1> ;
1756 <1> vk_check:
1757 00000617 31F6 <1> xor si,si ; Beginning of vk_seg
1758 <1> .scan:
1759 00000619 3B36[F800] <1> cmp si,[VKernelBytes]
1760 0000061D 7355 <1> jae .not_vk
1761 <1>
1762 0000061F 1E <1> push ds
1763 00000620 680030 <1> push word vk_seg
1764 00000623 1F <1> pop ds
1765 <1>
1766 00000624 BF[D80C] <1> mov di,VKernelBuf
1767 00000627 E80B1B <1> call rllunpack
1768 0000062A 1F <1> pop ds
1769 <1> ; SI updated on return
1770 <1>
1771 0000062B 29CF <1> sub di,cx ; Return to beginning of buf
1772 0000062D 56 <1> push si
1773 0000062E BE[E01B] <1> mov si,KernelName
1774 00000631 B98000 <1> mov cx,FILENAME_MAX
1775 00000634 26F3A6 <1> es repe cmpsb
1776 00000637 5E <1> pop si
1777 00000638 7402 <1> je .found
1778 0000063A EBDD <1> jmp .scan
1779 <1>
1780 <1> ;
1781 <1> ; We *are* using a "virtual kernel"
1782 <1> ;
1783 <1> .found:
1784 0000063C 06 <1> push es
1785 0000063D 680040 <1> push word real_mode_seg
1786 00000640 07 <1> pop es
1787 00000641 BF0090 <1> mov di,cmd_line_here
1788 00000644 BE[DC0D] <1> mov si,VKernelBuf+vk_append
1789 00000647 8B0E[DA0D] <1> mov cx,[VKernelBuf+vk_appendlen]
1790 0000064B F3A4 <1> rep movsb
1791 0000064D 893E[EE00] <1> mov [CmdLinePtr],di ; Where to add rest of cmd
1792 00000651 07 <1> pop es
1793 00000652 BF[E01B] <1> mov di,KernelName
1794 00000655 57 <1> push di
1795 00000656 BE[580D] <1> mov si,VKernelBuf+vk_rname
1796 00000659 B98000 <1> mov cx,FILENAME_MAX ; We need ECX == CX later
1797 0000065C F3A4 <1> rep movsb
1798 0000065E 5F <1> pop di
1799 <1> %if IS_PXELINUX
1800 0000065F A0[D80D] <1> mov al,[VKernelBuf+vk_ipappend]
1801 00000662 A2[0809] <1> mov [IPAppend],al
1802 <1> %endif
1803 00000665 31DB <1> xor bx,bx ; Try only one version
1804 <1>
1805 <1> %if IS_PXELINUX || IS_ISOLINUX
1806 <1> ; Is this a "localboot" pseudo-kernel?
1807 <1> %if IS_PXELINUX
1808 00000667 803E[5C0D]00 <1> cmp byte [VKernelBuf+vk_rname+4], 0
1809 <1> %else
1810 <1> cmp byte [VKernelBuf+vk_rname], 0
1811 <1> %endif
1812 0000066C 7528 <1> jne get_kernel ; No, it's real, go get it
1813 <1>
1814 0000066E A1[590D] <1> mov ax, [VKernelBuf+vk_rname+1]
1815 00000671 E9EE0A <1> jmp local_boot
1816 <1> %else
1817 <1> jmp get_kernel
1818 <1> %endif
1819 <1>
1820 <1> .not_vk:
1821 <1>
1822 <1> ;
1823 <1> ; Not a "virtual kernel" - check that's OK and construct the command line
1824 <1> ;
1825 00000674 833E[F200]00 <1> cmp word [AllowImplicit],byte 0
1826 00000679 7455 <1> je bad_implicit
1827 0000067B 06 <1> push es
1828 0000067C 56 <1> push si
1829 0000067D 57 <1> push di
1830 0000067E BF0040 <1> mov di,real_mode_seg
1831 00000681 8EC7 <1> mov es,di
1832 00000683 BE[DC0F] <1> mov si,AppendBuf
1833 00000686 BF0090 <1> mov di,cmd_line_here
1834 00000689 8B0E[E600] <1> mov cx,[AppendLen]
1835 0000068D F3A4 <1> rep movsb
1836 0000068F 893E[EE00] <1> mov [CmdLinePtr],di
1837 00000693 5F <1> pop di
1838 00000694 5E <1> pop si
1839 00000695 07 <1> pop es
1840 <1> ;
1841 <1> ; Find the kernel on disk
1842 <1> ;
1843 00000696 C606[601C]00 <1> get_kernel: mov byte [KernelName+FILENAME_MAX],0 ; Zero-terminate filename/extension
1844 <1> %if IS_SYSLINUX || IS_MDSLINUX ; SYSLINUX has to deal with DOS mangled names...
1845 <1> mov eax,[KernelName+8] ; Save initial extension
1846 <1> mov [exten_table_end],eax ; Last case == initial ext.
1847 <1> %else
1848 0000069B BF[E41B] <1> mov di,KernelName+4*IS_PXELINUX
1849 0000069E 30C0 <1> xor al,al
1850 000006A0 B97B00 <1> mov cx,FILENAME_MAX-5 ; Need 4 chars + null
1851 000006A3 F2AE <1> repne scasb ; Scan for final null
1852 000006A5 7501 <1> jne .no_skip
1853 000006A7 4F <1> dec di ; Point to final null
1854 000006A8 893E[8008] <1> .no_skip: mov [KernelExtPtr],di
1855 <1> %endif
1856 000006AC BB[2808] <1> mov bx,exten_table
1857 000006AF 53 <1> .search_loop: push bx
1858 000006B0 BF[E01B] <1> mov di,KernelName ; Search on disk
1859 000006B3 E8270C <1> call searchdir
1860 000006B6 5B <1> pop bx
1861 000006B7 756B <1> jnz kernel_good
1862 000006B9 668B07 <1> mov eax,[bx] ; Try a different extension
1863 <1> %if IS_SYSLINUX || IS_MDSLINUX
1864 <1> mov [KernelName+8],eax
1865 <1> %else
1866 000006BC 8B36[8008] <1> mov si,[KernelExtPtr]
1867 000006C0 668904 <1> mov [si],eax
1868 000006C3 C6440400 <1> mov byte [si+4],0
1869 <1> %endif
1870 000006C7 83C304 <1> add bx,byte 4
1871 000006CA 81FB[3808] <1> cmp bx,exten_table_end
1872 000006CE 76DF <1> jna .search_loop ; allow == case (final case)
1873 <1> ; Fall into bad_kernel
1874 <1> ;
1875 <1> ; bad_kernel: Kernel image not found
1876 <1> ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0"
1877 <1> ;
1878 <1> bad_implicit:
1879 <1> bad_kernel:
1880 000006D0 8B0E[EA00] <1> mov cx,[OnerrorLen]
1881 000006D4 21C9 <1> and cx,cx
1882 000006D6 751A <1> jnz on_error
1883 <1> .really:
1884 000006D8 BE[E01B] <1> mov si,KernelName
1885 000006DB BF[601C] <1> mov di,KernelCName
1886 000006DE 57 <1> push di
1887 000006DF E8AE0E <1> call unmangle_name ; Get human form
1888 000006E2 BE[8001] <1> mov si,err_notfound ; Complain about missing kernel
1889 000006E5 E86C17 <1> call cwritestr
1890 000006E8 5E <1> pop si ; KernelCName
1891 000006E9 E86817 <1> call cwritestr
1892 000006EC BE[E006] <1> mov si,crlf_msg
1893 000006EF E9AE0A <1> jmp abort_load ; Ask user for clue
1894 <1>
1895 <1> ;
1896 <1> ; on_error: bad kernel, but we have onerror set
1897 <1> ;
1898 <1> on_error:
1899 000006F2 BE[DC13] <1> mov si,Onerror
1900 000006F5 BF[D408] <1> mov di,command_line
1901 000006F8 56 <1> push si ; <A>
1902 000006F9 57 <1> push di ; <B>
1903 000006FA 51 <1> push cx ; <C>
1904 000006FB 51 <1> push cx ; <D>
1905 000006FC 57 <1> push di ; <E>
1906 000006FD F3A6 <1> repe cmpsb
1907 000006FF 5F <1> pop di ; <E> di == command_line
1908 00000700 5B <1> pop bx ; <D> bx == [OnerrorLen]
1909 00000701 74D5 <1> je bad_kernel.really ; Onerror matches command_line already
1910 00000703 F7DB <1> neg bx ; bx == -[OnerrorLen]
1911 00000705 8D8FFF01 <1> lea cx,[max_cmd_len+bx]
1912 <1> ; CX == max_cmd_len-[OnerrorLen]
1913 00000709 BF[D20A] <1> mov di,command_line+max_cmd_len-1
1914 0000070C C6450100 <1> mov byte [di+1],0 ; Enforce null-termination
1915 00000710 8D31 <1> lea si,[di+bx]
1916 00000712 FD <1> std
1917 00000713 F3A4 <1> rep movsb ; Make space in command_line
1918 00000715 FC <1> cld
1919 00000716 59 <1> pop cx ; <C> cx == [OnerrorLen]
1920 00000717 5F <1> pop di ; <B> di == command_line
1921 00000718 5E <1> pop si ; <A> si == Onerror
1922 00000719 F3A4 <1> rep movsb
1923 0000071B E9D0FE <1> jmp load_kernel
1924 <1>
1925 <1> ;
1926 <1> ; kernel_corrupt: Called if the kernel file does not seem healthy
1927 <1> ;
1928 0000071E BE[9E01] <1> kernel_corrupt: mov si,err_notkernel
1929 00000721 E97C0A <1> jmp abort_load
1930 <1> ;
1931 <1> ; This is it! We have a name (and location on the disk)... let's load
1932 <1> ; that sucker!! First we have to decide what kind of file this is; base
1933 <1> ; that decision on the file extension. The following extensions are
1934 <1> ; recognized; case insensitive:
1935 <1> ;
1936 <1> ; .com - COMBOOT image
1937 <1> ; .cbt - COMBOOT image
1938 <1> ; .c32 - COM32 image
1939 <1> ; .bs - Boot sector
1940 <1> ; .0 - PXE bootstrap program (PXELINUX only)
1941 <1> ; .bin - Boot sector
1942 <1> ; .bss - Boot sector, but transfer over DOS superblock (SYSLINUX only)
1943 <1> ; .img - Floppy image (ISOLINUX only)
1944 <1> ;
1945 <1> ; Anything else is assumed to be a Linux kernel.
1946 <1> ;
1947 <1> kernel_good:
1948 00000724 60 <1> pusha
1949 00000725 BE[E01B] <1> mov si,KernelName
1950 00000728 BF[601C] <1> mov di,KernelCName
1951 0000072B E8620E <1> call unmangle_name
1952 0000072E 81EF[601C] <1> sub di,KernelCName
1953 00000732 893E[DC1B] <1> mov [KernelCNameLen],di
1954 00000736 61 <1> popa
1955 <1>
1956 <1> %if IS_SYSLINUX || IS_MDSLINUX
1957 <1> mov ecx,[KernelName+7]
1958 <1> mov cl,'.'
1959 <1> %else
1960 00000737 57 <1> push di
1961 00000738 50 <1> push ax
1962 00000739 BF[E41B] <1> mov di,KernelName+4*IS_PXELINUX
1963 0000073C 30C0 <1> xor al,al
1964 0000073E B98000 <1> mov cx,FILENAME_MAX
1965 00000741 F2AE <1> repne scasb
1966 00000743 7501 <1> jne .one_step
1967 00000745 4F <1> dec di
1968 00000746 668B4DFC <1> .one_step: mov ecx,[di-4] ; 4 bytes before end
1969 0000074A 58 <1> pop ax
1970 0000074B 5F <1> pop di
1971 <1> %endif
1972 <1>
1973 <1> ;
1974 <1> ; At this point, DX:AX contains the size of the kernel, and SI contains
1975 <1> ; the file handle/cluster pointer.
1976 <1> ;
1977 0000074C 6681C900202020 <1> or ecx,20202000h ; Force lower case
1978 <1>
1979 00000753 6681F92E636F6D <1> cmp ecx,'.com'
1980 0000075A 0F848104 <1> je is_comboot_image
1981 0000075E 6681F92E636274 <1> cmp ecx,'.cbt'
1982 00000765 0F847604 <1> je is_comboot_image
1983 00000769 6681F92E633332 <1> cmp ecx,'.c32'
1984 00000770 0F845507 <1> je is_com32_image
1985 <1> %if IS_ISOLINUX
1986 <1> cmp ecx,'.img'
1987 <1> je is_disk_image
1988 <1> %endif
1989 00000774 6681F92E627373 <1> cmp ecx,'.bss'
1990 0000077B 0F84DA09 <1> je is_bss_sector
1991 0000077F 6681F92E62696E <1> cmp ecx,'.bin'
1992 00000786 0F844909 <1> je is_bootsector
1993 <1> %if IS_SYSLINUX || IS_MDSLINUX
1994 <1> cmp ecx,'.bs '
1995 <1> je is_bootsector
1996 <1> cmp ecx,'.0 '
1997 <1> je is_bootsector
1998 <1> %else
1999 0000078A 66C1E908 <1> shr ecx,8
2000 0000078E 6681F92E627300 <1> cmp ecx,'.bs'
2001 00000795 0F843A09 <1> je is_bootsector
2002 00000799 66C1E908 <1> shr ecx,8
2003 0000079D 81F92E30 <1> cmp cx,'.0'
2004 000007A1 0F842E09 <1> je is_bootsector
2005 <1> %endif
2006 <1> ; Otherwise Linux kernel
2007 <1>
2008 <1> section .bss
2009 <1> alignb 2
2010 00000880 <res 00000002> <1> KernelExtPtr resw 1 ; During search, final null pointer
2011 00000882 <res 00000002> <1> CmdOptPtr resw 1 ; Pointer to first option on cmd line
2012 00000884 <res 00000001> <1> KbdFlags resb 1 ; Check for keyboard escapes
2013 00000885 <res 00000001> <1> FuncFlag resb 1 ; Escape sequences received from keyboard
2014 <1>
2015 <1> section .text
2016
2017 ;
2018 ; Linux kernel loading code is common. However, we need to define
2019 ; a couple of helper macros...
2020 ;
2021
2022 ; Handle "ipappend" option
2023 %define HAVE_SPECIAL_APPEND
2024 %macro SPECIAL_APPEND 0
2025 test byte [IPAppend],01h ; ip=
2026 jz .noipappend1
2027 mov si,IPOption
2028 mov cx,[IPOptionLen]
2029 rep movsb
2030 mov al,' '
2031 stosb
2032 .noipappend1:
2033 test byte [IPAppend],02h
2034 jz .noipappend2
2035 mov si,BOOTIFStr
2036 call strcpy
2037 mov byte [es:di-1],' ' ; Replace null with space
2038 .noipappend2:
2039 %endmacro
2040
2041 ; Unload PXE stack
2042 %define HAVE_UNLOAD_PREP
2043 %macro UNLOAD_PREP 0
2044 call unload_pxe
2045 %endmacro
2046
2047 %include "runkernel.inc"
2048 <1> ;; $Id: runkernel.inc,v 1.21 2005/06/16 05:52:44 hpa Exp $
2049 <1> ;; -----------------------------------------------------------------------
2050 <1> ;;
2051 <1> ;; Copyright 1994-2005 H. Peter Anvin - All Rights Reserved
2052 <1> ;;
2053 <1> ;; This program is free software; you can redistribute it and/or modify
2054 <1> ;; it under the terms of the GNU General Public License as published by
2055 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
2056 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
2057 <1> ;; (at your option) any later version; incorporated herein by reference.
2058 <1> ;;
2059 <1> ;; -----------------------------------------------------------------------
2060 <1>
2061 <1> ;;
2062 <1> ;; runkernel.inc
2063 <1> ;;
2064 <1> ;; Common code for running a Linux kernel
2065 <1> ;;
2066 <1>
2067 <1> ;
2068 <1> ; Hook macros, that may or may not be defined
2069 <1> ;
2070 <1> %ifndef HAVE_SPECIAL_APPEND
2071 <1> %macro SPECIAL_APPEND 0
2072 <1> %endmacro
2073 <1> %endif
2074 <1>
2075 <1> %ifndef HAVE_UNLOAD_PREP
2076 <1> %macro UNLOAD_PREP 0
2077 <1> %endmacro
2078 <1> %endif
2079 <1>
2080 <1> ;
2081 <1> ; A Linux kernel consists of three parts: boot sector, setup code, and
2082 <1> ; kernel code. The boot sector is never executed when using an external
2083 <1> ; booting utility, but it contains some status bytes that are necessary.
2084 <1> ;
2085 <1> ; First check that our kernel is at least 1K and less than 8M (if it is
2086 <1> ; more than 8M, we need to change the logic for loading it anyway...)
2087 <1> ;
2088 <1> ; We used to require the kernel to be 64K or larger, but it has gotten
2089 <1> ; popular to use the Linux kernel format for other things, which may
2090 <1> ; not be so large.
2091 <1> ;
2092 <1> is_linux_kernel:
2093 000007A5 81FA8000 <1> cmp dx,80h ; 8 megs
2094 000007A9 0F8771FF <1> ja kernel_corrupt
2095 000007AD 21D2 <1> and dx,dx
2096 000007AF 7507 <1> jnz kernel_sane
2097 000007B1 3D0004 <1> cmp ax,1024 ; Bootsect + 1 setup sect
2098 000007B4 0F8266FF <1> jb kernel_corrupt
2099 000007B8 50 <1> kernel_sane: push ax
2100 000007B9 52 <1> push dx
2101 000007BA 56 <1> push si
2102 000007BB BE[C606] <1> mov si,loading_msg
2103 000007BE E89316 <1> call cwritestr
2104 <1> ;
2105 <1> ; Now start transferring the kernel
2106 <1> ;
2107 000007C1 680040 <1> push word real_mode_seg
2108 000007C4 07 <1> pop es
2109 <1>
2110 000007C5 660FB7C0 <1> movzx eax,ax ; Fix this by using a 32-bit
2111 000007C9 66C1E210 <1> shl edx,16 ; register for the kernel size
2112 000007CD 6609D0 <1> or eax,edx
2113 000007D0 66A3[8C08] <1> mov [KernelSize],eax
2114 000007D4 6605FF010000 <1> add eax,SECTOR_SIZE-1
2115 000007DA 66C1E809 <1> shr eax,SECTOR_SHIFT
2116 000007DE 66A3[9008] <1> mov [KernelSects],eax ; Total sectors in kernel
2117 <1>
2118 <1> ;
2119 <1> ; Now, if we transfer these straight, we'll hit 64K boundaries. Hence we
2120 <1> ; have to see if we're loading more than 64K, and if so, load it step by
2121 <1> ; step.
2122 <1> ;
2123 <1>
2124 <1> ;
2125 <1> ; Start by loading the bootsector/setup code, to see if we need to
2126 <1> ; do something funky. It should fit in the first 32K (loading 64K won't
2127 <1> ; work since we might have funny stuff up near the end of memory).
2128 <1> ; If we have larger than 32K clusters, yes, we're hosed.
2129 <1> ;
2130 000007E2 E8A709 <1> call abort_check ; Check for abort key
2131 000007E5 66B940000000 <1> mov ecx,8000h >> SECTOR_SHIFT ; Half a moby (32K)
2132 000007EB 663B0E[9008] <1> cmp ecx,[KernelSects]
2133 000007F0 7605 <1> jna .normalkernel
2134 000007F2 668B0E[9008] <1> mov ecx,[KernelSects]
2135 <1> .normalkernel:
2136 000007F7 66290E[9008] <1> sub [KernelSects],ecx
2137 000007FC 31DB <1> xor bx,bx
2138 000007FE 5E <1> pop si ; Cluster pointer on stack
2139 000007FF E8BC0D <1> call getfssec
2140 00000802 26813EFE0155AA <1> cmp word [es:bs_bootsign],0AA55h
2141 00000809 0F8511FF <1> jne kernel_corrupt ; Boot sec signature missing
2142 <1>
2143 <1> ;
2144 <1> ; Save the cluster pointer for later...
2145 <1> ;
2146 0000080D 56 <1> push si
2147 <1> ;
2148 <1> ; Get the BIOS' idea of what the size of high memory is.
2149 <1> ;
2150 0000080E E87A1C <1> call highmemsize
2151 <1> ;
2152 <1> ; Construct the command line (append options have already been copied)
2153 <1> ;
2154 <1> construct_cmdline:
2155 00000811 8B3E[EE00] <1> mov di,[CmdLinePtr]
2156 00000815 BE[0B00] <1> mov si,boot_image ; BOOT_IMAGE=
2157 00000818 B90B00 <1> mov cx,boot_image_len
2158 0000081B F3A4 <1> rep movsb
2159 0000081D BE[601C] <1> mov si,KernelCName ; Unmangled kernel name
2160 00000820 8B0E[DC1B] <1> mov cx,[KernelCNameLen]
2161 00000824 F3A4 <1> rep movsb
2162 00000826 B020 <1> mov al,' ' ; Space
2163 00000828 AA <1> stosb
2164 <1>
2165 <1> SPECIAL_APPEND ; Module-specific hook
2166 00000829 F606[0809]01 <2> test byte [IPAppend],01h
2167 0000082E 740C <2> jz .noipappend1
2168 00000830 BE[1047] <2> mov si,IPOption
2169 00000833 8B0E[0A00] <2> mov cx,[IPOptionLen]
2170 00000837 F3A4 <2> rep movsb
2171 00000839 B020 <2> mov al,' '
2172 0000083B AA <2> stosb
2173 <2> .noipappend1:
2174 0000083C F606[0809]02 <2> test byte [IPAppend],02h
2175 00000841 740B <2> jz .noipappend2
2176 00000843 BE[2700] <2> mov si,BOOTIFStr
2177 00000846 E8331D <2> call strcpy
2178 00000849 26C645FF20 <2> mov byte [es:di-1],' '
2179 <2> .noipappend2:
2180 <1>
2181 0000084E 8B36[8208] <1> mov si,[CmdOptPtr] ; Options from user input
2182 00000852 E8271D <1> call strcpy
2183 <1>
2184 <1> ;
2185 <1> ; Scan through the command line for anything that looks like we might be
2186 <1> ; interested in. The original version of this code automatically assumed
2187 <1> ; the first option was BOOT_IMAGE=, but that is no longer certain.
2188 <1> ;
2189 00000855 BE0090 <1> mov si,cmd_line_here
2190 00000858 31C0 <1> xor ax,ax
2191 0000085A A3[9C08] <1> mov [InitRDPtr],ax ; No initrd= option (yet)
2192 0000085D 06 <1> push es ; Set DS <- real_mode_seg
2193 0000085E 1F <1> pop ds
2194 0000085F AC <1> get_next_opt: lodsb
2195 00000860 20C0 <1> and al,al
2196 00000862 0F84A300 <1> jz cmdline_end
2197 00000866 3C20 <1> cmp al,' '
2198 00000868 76F5 <1> jbe get_next_opt
2199 0000086A 4E <1> dec si
2200 0000086B 668B04 <1> mov eax,[si]
2201 0000086E 663D7667613D <1> cmp eax,'vga='
2202 00000874 744D <1> je is_vga_cmd
2203 00000876 663D6D656D3D <1> cmp eax,'mem='
2204 0000087C 7474 <1> je is_mem_cmd
2205 <1> %if IS_PXELINUX
2206 0000087E 663D6B656570 <1> cmp eax,'keep' ; Is it "keeppxe"?
2207 00000884 7516 <1> jne .notkeep
2208 00000886 66817C0370707865 <1> cmp dword [si+3],'ppxe'
2209 0000088E 750C <1> jne .notkeep
2210 00000890 807C0720 <1> cmp byte [si+7],' ' ; Must be whitespace or EOS
2211 00000894 7706 <1> ja .notkeep
2212 00000896 2E800E[A608]01 <1> or byte [cs:KeepPXE],1
2213 <1> .notkeep:
2214 <1> %endif
2215 0000089C 06 <1> push es ; Save ES -> real_mode_seg
2216 0000089D 0E <1> push cs
2217 0000089E 07 <1> pop es ; Set ES <- normal DS
2218 0000089F BF[1707] <1> mov di,initrd_cmd
2219 000008A2 B90700 <1> mov cx,initrd_cmd_len
2220 000008A5 F3A6 <1> repe cmpsb
2221 000008A7 7511 <1> jne .not_initrd
2222 <1>
2223 000008A9 3C20 <1> cmp al,' '
2224 000008AB 7607 <1> jbe .noramdisk
2225 000008AD 2E8936[9C08] <1> mov [cs:InitRDPtr],si
2226 000008B2 EB06 <1> jmp .not_initrd
2227 <1> .noramdisk:
2228 000008B4 31C0 <1> xor ax,ax
2229 000008B6 2EA3[9C08] <1> mov [cs:InitRDPtr],ax
2230 000008BA 07 <1> .not_initrd: pop es ; Restore ES -> real_mode_seg
2231 000008BB AC <1> skip_this_opt: lodsb ; Load from command line
2232 000008BC 3C20 <1> cmp al,' '
2233 000008BE 77FB <1> ja skip_this_opt
2234 000008C0 4E <1> dec si
2235 000008C1 EB9C <1> jmp short get_next_opt
2236 <1> is_vga_cmd:
2237 000008C3 83C604 <1> add si,4
2238 000008C6 668B44FF <1> mov eax,[si-1]
2239 000008CA BBFFFF <1> mov bx,-1
2240 000008CD 663D3D6E6F72 <1> cmp eax,'=nor' ; vga=normal
2241 000008D3 7417 <1> je vc0
2242 000008D5 4B <1> dec bx ; bx <- -2
2243 000008D6 663D3D657874 <1> cmp eax,'=ext' ; vga=ext
2244 000008DC 740E <1> je vc0
2245 000008DE 4B <1> dec bx ; bx <- -3
2246 000008DF 663D3D61736B <1> cmp eax,'=ask' ; vga=ask
2247 000008E5 7405 <1> je vc0
2248 000008E7 E81212 <1> call parseint ; vga=<number>
2249 000008EA 72CF <1> jc skip_this_opt ; Not an integer
2250 000008EC 891EFA01 <1> vc0: mov [bs_vidmode],bx ; Set video mode
2251 000008F0 EBC9 <1> jmp short skip_this_opt
2252 <1> is_mem_cmd:
2253 000008F2 83C604 <1> add si,4
2254 000008F5 E80412 <1> call parseint
2255 000008F8 72C1 <1> jc skip_this_opt ; Not an integer
2256 <1> %if HIGHMEM_SLOP != 0
2257 000008FA 6681EB00000200 <1> sub ebx,HIGHMEM_SLOP
2258 <1> %endif
2259 00000901 2E66891E[981F] <1> mov [cs:HighMemSize],ebx
2260 00000907 EBB2 <1> jmp short skip_this_opt
2261 <1> cmdline_end:
2262 00000909 0E <1> push cs ; Restore standard DS
2263 0000090A 1F <1> pop ds
2264 0000090B 81EE0090 <1> sub si,cmd_line_here
2265 0000090F 8936[9808] <1> mov [CmdLineLen],si ; Length including final null
2266 <1> ;
2267 <1> ; Now check if we have a large kernel, which needs to be loaded high
2268 <1> ;
2269 00000913 66C706[8808]FFFFFF- <1> mov dword [RamdiskMax], HIGHMEM_MAX ; Default initrd limit
2270 0000091B 37 <1>
2271 0000091C 2666813E0202486472- <1> cmp dword [es:su_header],HEADER_ID ; New setup code ID
2272 00000925 53 <1>
2273 00000926 0F859701 <1> jne old_kernel ; Old kernel, load low
2274 0000092A 26813E06020002 <1> cmp word [es:su_version],0200h ; Setup code version 2.0
2275 00000931 0F828C01 <1> jb old_kernel ; Old kernel, load low
2276 00000935 26813E06020102 <1> cmp word [es:su_version],0201h ; Version 2.01+?
2277 0000093C 721F <1> jb new_kernel ; If 2.00, skip this step
2278 0000093E 26C7062402F48F <1> mov word [es:su_heapend],linux_stack ; Set up the heap
2279 00000945 26800E110280 <1> or byte [es:su_loadflags],80h ; Let the kernel know we care
2280 0000094B 26813E06020302 <1> cmp word [es:su_version],0203h ; Version 2.03+?
2281 00000952 7209 <1> jb new_kernel ; Not 2.03+
2282 00000954 2666A12C02 <1> mov eax,[es:su_ramdisk_max]
2283 00000959 66A3[8808] <1> mov [RamdiskMax],eax ; Set the ramdisk limit
2284 <1>
2285 <1> ;
2286 <1> ; We definitely have a new-style kernel. Let the kernel know who we are,
2287 <1> ; and that we are clueful
2288 <1> ;
2289 <1> new_kernel:
2290 0000095D 26C606100232 <1> mov byte [es:su_loader],my_id ; Show some ID
2291 00000963 260FB606F101 <1> movzx ax,byte [es:bs_setupsecs] ; Variable # of setup sectors
2292 00000969 A3[9A08] <1> mov [SetupSecs],ax
2293 0000096C 6631C0 <1> xor eax,eax
2294 0000096F 2666A31C02 <1> mov [es:su_ramdisklen],eax ; No initrd loaded yet
2295 <1>
2296 <1> ;
2297 <1> ; About to load the kernel. This is a modern kernel, so use the boot flags
2298 <1> ; we were provided.
2299 <1> ;
2300 00000974 26A01102 <1> mov al,[es:su_loadflags]
2301 00000978 A2[9E08] <1> mov [LoadFlags],al
2302 <1> ;
2303 <1> ; Load the kernel. We always load it at 100000h even if we're supposed to
2304 <1> ; load it "low"; for a "low" load we copy it down to low memory right before
2305 <1> ; jumping to it.
2306 <1> ;
2307 <1> read_kernel:
2308 0000097B BE[601C] <1> mov si,KernelCName ; Print kernel name part of
2309 0000097E E8D314 <1> call cwritestr ; "Loading" message
2310 00000981 BE[CF06] <1> mov si,dotdot_msg ; Print dots
2311 00000984 E8CD14 <1> call cwritestr
2312 <1>
2313 00000987 66A1[981F] <1> mov eax,[HighMemSize]
2314 0000098B 662D00001000 <1> sub eax,100000h ; Load address
2315 00000991 663B06[8C08] <1> cmp eax,[KernelSize]
2316 00000996 0F823502 <1> jb no_high_mem ; Not enough high memory
2317 <1> ;
2318 <1> ; Move the stuff beyond the setup code to high memory at 100000h
2319 <1> ;
2320 0000099A 660FB736[9A08] <1> movzx esi,word [SetupSecs] ; Setup sectors
2321 000009A0 46 <1> inc si ; plus 1 boot sector
2322 000009A1 C1E609 <1> shl si,9 ; Convert to bytes
2323 000009A4 66B900800000 <1> mov ecx,8000h ; 32K
2324 000009AA 6629F1 <1> sub ecx,esi ; Number of bytes to copy
2325 000009AD 6651 <1> push ecx
2326 000009AF 6681C600000400 <1> add esi,(real_mode_seg << 4) ; Pointer to source
2327 000009B6 66BF00001000 <1> mov edi,100000h ; Copy to address 100000h
2328 <1>
2329 000009BC E8(3000) <1> call bcopy ; Transfer to high memory
2330 <1>
2331 <1> ; On exit EDI -> where to load the rest
2332 <1>
2333 000009BF BE[D006] <1> mov si,dot_msg ; Progress report
2334 000009C2 E88F14 <1> call cwritestr
2335 000009C5 E8C407 <1> call abort_check
2336 <1>
2337 000009C8 6659 <1> pop ecx ; Number of bytes in the initial portion
2338 000009CA 5E <1> pop si ; Restore file handle/cluster pointer
2339 000009CB 66A1[8C08] <1> mov eax,[KernelSize]
2340 000009CF 662D00800000 <1> sub eax,8000h ; Amount of kernel not yet loaded
2341 000009D5 7605 <1> jbe high_load_done ; Zero left (tiny kernel)
2342 <1>
2343 000009D7 31D2 <1> xor dx,dx ; No padding needed
2344 000009D9 E8DF17 <1> call load_high ; Copy the file
2345 <1>
2346 <1> high_load_done:
2347 000009DC 66893E[9408] <1> mov [KernelEnd],edi
2348 000009E1 B80040 <1> mov ax,real_mode_seg ; Set to real mode seg
2349 000009E4 8EC0 <1> mov es,ax
2350 <1>
2351 000009E6 BE[D006] <1> mov si,dot_msg
2352 000009E9 E86814 <1> call cwritestr
2353 <1>
2354 <1> ;
2355 <1> ; Now see if we have an initial RAMdisk; if so, do requisite computation
2356 <1> ; We know we have a new kernel; the old_kernel code already will have objected
2357 <1> ; if we tried to load initrd using an old kernel
2358 <1> ;
2359 <1> load_initrd:
2360 000009EC 833E[9C08]00 <1> cmp word [InitRDPtr],0
2361 000009F1 7403 <1> jz nk_noinitrd
2362 000009F3 E8E600 <1> call parse_load_initrd
2363 <1> nk_noinitrd:
2364 <1> ;
2365 <1> ; Abandon hope, ye that enter here! We do no longer permit aborts.
2366 <1> ;
2367 000009F6 E89307 <1> call abort_check ; Last chance!!
2368 <1>
2369 000009F9 BE[AA06] <1> mov si,ready_msg
2370 000009FC E85514 <1> call cwritestr
2371 <1>
2372 000009FF E8431A <1> call vgaclearmode ; We can't trust ourselves after this
2373 <1>
2374 <1> UNLOAD_PREP ; Module-specific hook
2375 00000A02 E8440D <2> call unload_pxe
2376 <1>
2377 <1> ;
2378 <1> ; Now, if we were supposed to load "low", copy the kernel down to 10000h
2379 <1> ; and the real mode stuff to 90000h. We assume that all bzImage kernels are
2380 <1> ; capable of starting their setup from a different address.
2381 <1> ;
2382 00000A05 B80040 <1> mov ax,real_mode_seg
2383 00000A08 8EE0 <1> mov fs,ax
2384 <1>
2385 <1> ;
2386 <1> ; Copy command line. Unfortunately, the kernel boot protocol requires
2387 <1> ; the command line to exist in the 9xxxxh range even if the rest of the
2388 <1> ; setup doesn't.
2389 <1> ;
2390 00000A0A FA <1> cli ; In case of hooked interrupts
2391 00000A0B F606[9E08]01 <1> test byte [LoadFlags],LOAD_HIGH
2392 00000A10 7415 <1> jz need_high_cmdline
2393 00000A12 64813E06020202 <1> cmp word [fs:su_version],0202h ; Support new cmdline protocol?
2394 00000A19 720C <1> jb need_high_cmdline
2395 <1> ; New cmdline protocol
2396 <1> ; Store 32-bit (flat) pointer to command line
2397 00000A1B 6466C7062802009004- <1> mov dword [fs:su_cmd_line_ptr],(real_mode_seg << 4) + cmd_line_here
2398 00000A24 00 <1>
2399 00000A25 EB70 <1> jmp short in_proper_place
2400 <1>
2401 <1> need_high_cmdline:
2402 <1> ;
2403 <1> ; Copy command line up to 90000h
2404 <1> ;
2405 00000A27 B80090 <1> mov ax,9000h ; Note AL <- 0
2406 00000A2A 8EC0 <1> mov es,ax
2407 00000A2C BE0090 <1> mov si,cmd_line_here
2408 00000A2F 89F7 <1> mov di,si
2409 00000A31 64C70620003FA3 <1> mov [fs:kern_cmd_magic],word CMD_MAGIC ; Store magic
2410 00000A38 64893E2200 <1> mov [fs:kern_cmd_offset],di ; Store pointer
2411 <1>
2412 00000A3D 8B0E[9808] <1> mov cx,[CmdLineLen]
2413 00000A41 81F9FF00 <1> cmp cx,255
2414 00000A45 7603 <1> jna .len_ok
2415 00000A47 B9FF00 <1> mov cx,255 ; Protocol < 0x202 has 255 as hard limit
2416 <1> .len_ok:
2417 00000A4A 64F3A4 <1> fs rep movsb
2418 00000A4D AA <1> stosb ; Final null, note AL == 0 already
2419 <1>
2420 00000A4E 0FA0 <1> push fs
2421 00000A50 07 <1> pop es
2422 <1>
2423 00000A51 F606[9E08]01 <1> test byte [LoadFlags],LOAD_HIGH
2424 00000A56 753F <1> jnz in_proper_place ; If high load, we're done
2425 <1>
2426 <1> ;
2427 <1> ; Loading low; we can't assume it's safe to run in place.
2428 <1> ;
2429 <1> ; Copy real_mode stuff up to 90000h
2430 <1> ;
2431 00000A58 B80090 <1> mov ax,9000h
2432 00000A5B 8EC0 <1> mov es,ax
2433 00000A5D 8B0E[9A08] <1> mov cx,[SetupSecs]
2434 00000A61 41 <1> inc cx ; Setup + boot sector
2435 00000A62 C1E107 <1> shl cx,7 ; Sectors -> dwords
2436 00000A65 31F6 <1> xor si,si
2437 00000A67 31FF <1> xor di,di
2438 00000A69 64F366A5 <1> fs rep movsd ; Copy setup + boot sector
2439 <1> ;
2440 <1> ; Some kernels in the 1.2 ballpark but pre-bzImage have more than 4
2441 <1> ; setup sectors, but the boot protocol had not yet been defined. They
2442 <1> ; rely on a signature to figure out if they need to copy stuff from
2443 <1> ; the "protected mode" kernel area. Unfortunately, we used that area
2444 <1> ; as a transfer buffer, so it's going to find the signature there.
2445 <1> ; Hence, zero the low 32K beyond the setup area.
2446 <1> ;
2447 00000A6D 8B3E[9A08] <1> mov di,[SetupSecs]
2448 00000A71 47 <1> inc di ; Setup + boot sector
2449 00000A72 B94000 <1> mov cx,32768/512 ; Sectors/32K
2450 00000A75 29F9 <1> sub cx,di ; Remaining sectors
2451 00000A77 C1E709 <1> shl di,9 ; Sectors -> bytes
2452 00000A7A C1E107 <1> shl cx,7 ; Sectors -> dwords
2453 00000A7D 6631C0 <1> xor eax,eax
2454 00000A80 F366AB <1> rep stosd ; Clear region
2455 <1> ;
2456 <1> ; Copy the kernel down to the "low" location
2457 <1> ;
2458 00000A83 668B0E[8C08] <1> mov ecx,[KernelSize]
2459 00000A88 66BE00001000 <1> mov esi,100000h
2460 00000A8E 66BF00000100 <1> mov edi,10000h
2461 00000A94 E8(3000) <1> call bcopy
2462 <1>
2463 <1> ;
2464 <1> ; Now everything is where it needs to be...
2465 <1> ;
2466 <1> ; When we get here, es points to the final segment, either
2467 <1> ; 9000h or real_mode_seg
2468 <1> ;
2469 <1> in_proper_place:
2470 <1>
2471 <1> ;
2472 <1> ; If the default root device is set to FLOPPY (0000h), change to
2473 <1> ; /dev/fd0 (0200h)
2474 <1> ;
2475 00000A97 26833EFC0100 <1> cmp word [es:bs_rootdev],byte 0
2476 00000A9D 7507 <1> jne root_not_floppy
2477 00000A9F 26C706FC010002 <1> mov word [es:bs_rootdev],0200h
2478 <1> root_not_floppy:
2479 <1>
2480 <1> ;
2481 <1> ; Copy the disk table to high memory, then re-initialize the floppy
2482 <1> ; controller
2483 <1> ;
2484 <1> %if IS_SYSLINUX || IS_MDSLINUX
2485 <1> lgs si,[cs:fdctab]
2486 <1> mov di,linux_fdctab
2487 <1> mov cx,6 ; 12 bytes
2488 <1> gs rep movsw
2489 <1> mov [cs:fdctab],word linux_fdctab ; Save new floppy tab pos
2490 <1> mov [cs:fdctab+2],es
2491 <1> %endif
2492 <1> ;
2493 <1> ; Linux wants the floppy motor shut off before starting the kernel,
2494 <1> ; at least bootsect.S seems to imply so.
2495 <1> ;
2496 <1> kill_motor:
2497 00000AA6 31C0 <1> xor ax,ax
2498 00000AA8 31D2 <1> xor dx,dx
2499 00000AAA CD13 <1> int 13h
2500 <1>
2501 <1> ;
2502 <1> ; If we're debugging, wait for a keypress so we can read any debug messages
2503 <1> ;
2504 <1> %ifdef debug
2505 <1> xor ax,ax
2506 <1> int 16h
2507 <1> %endif
2508 <1> ;
2509 <1> ; Set up segment registers and the Linux real-mode stack
2510 <1> ; Note: es == the real mode segment
2511 <1> ;
2512 00000AAC FA <1> cli
2513 00000AAD 8CC3 <1> mov bx,es
2514 00000AAF 8EDB <1> mov ds,bx
2515 00000AB1 8EE3 <1> mov fs,bx
2516 00000AB3 8EEB <1> mov gs,bx
2517 00000AB5 8ED3 <1> mov ss,bx
2518 00000AB7 BCF48F <1> mov sp,linux_stack
2519 <1> ;
2520 <1> ; We're done... now RUN THAT KERNEL!!!!
2521 <1> ; Setup segment == real mode segment + 020h; we need to jump to offset
2522 <1> ; zero in the real mode segment.
2523 <1> ;
2524 00000ABA 83C320 <1> add bx,020h
2525 00000ABD 53 <1> push bx
2526 00000ABE 6A00 <1> push word 0h
2527 00000AC0 CB <1> retf
2528 <1>
2529 <1> ;
2530 <1> ; Load an older kernel. Older kernels always have 4 setup sectors, can't have
2531 <1> ; initrd, and are always loaded low.
2532 <1> ;
2533 <1> old_kernel:
2534 00000AC1 833E[9C08]00 <1> cmp word [InitRDPtr],0 ; Old kernel can't have initrd
2535 00000AC6 7406 <1> je load_old_kernel
2536 00000AC8 BE[5003] <1> mov si,err_oldkernel
2537 00000ACB E9D206 <1> jmp abort_load
2538 <1> load_old_kernel:
2539 00000ACE C706[9A08]0400 <1> mov word [SetupSecs],4 ; Always 4 setup sectors
2540 00000AD4 C606[9E08]00 <1> mov byte [LoadFlags],0 ; Always low
2541 00000AD9 E99FFE <1> jmp read_kernel
2542 <1>
2543 <1> ;
2544 <1> ; parse_load_initrd
2545 <1> ;
2546 <1> ; Parse an initrd= option and load the initrds. Note that we load
2547 <1> ; from the high end of memory first, so we parse this option from
2548 <1> ; left to right.
2549 <1> ;
2550 <1> parse_load_initrd:
2551 00000ADC 06 <1> push es
2552 00000ADD 1E <1> push ds
2553 00000ADE B80040 <1> mov ax,real_mode_seg
2554 00000AE1 8ED8 <1> mov ds,ax
2555 00000AE3 0E <1> push cs
2556 00000AE4 07 <1> pop es ; DS == real_mode_seg, ES == CS
2557 <1>
2558 00000AE5 2E8B36[9C08] <1> mov si,[cs:InitRDPtr]
2559 <1> .find_end:
2560 00000AEA AC <1> lodsb
2561 00000AEB 3C20 <1> cmp al,' '
2562 00000AED 77FB <1> ja .find_end
2563 <1> ; Now SI points to one character beyond the
2564 <1> ; byte that ended this option.
2565 <1>
2566 <1> .get_chunk:
2567 00000AEF 4E <1> dec si
2568 <1>
2569 <1> ; DS:SI points to a termination byte
2570 <1>
2571 00000AF0 31C0 <1> xor ax,ax
2572 00000AF2 8604 <1> xchg al,[si] ; Zero-terminate
2573 00000AF4 56 <1> push si ; Save ending byte address
2574 00000AF5 50 <1> push ax ; Save ending byte
2575 <1>
2576 <1> .find_start:
2577 00000AF6 4E <1> dec si
2578 00000AF7 2E3B36[9C08] <1> cmp si,[cs:InitRDPtr]
2579 00000AFC 7406 <1> je .got_start
2580 00000AFE 803C2C <1> cmp byte [si],','
2581 00000B01 75F3 <1> jne .find_start
2582 <1>
2583 <1> ; It's a comma byte
2584 00000B03 46 <1> inc si
2585 <1>
2586 <1> .got_start:
2587 00000B04 56 <1> push si
2588 00000B05 BF[E01D] <1> mov di,InitRD ; Target buffer for mangled name
2589 00000B08 E8300A <1> call mangle_name
2590 00000B0B E80F00 <1> call loadinitrd
2591 00000B0E 5E <1> pop si
2592 <1>
2593 00000B0F 58 <1> pop ax
2594 00000B10 5F <1> pop di
2595 00000B11 8805 <1> mov [di],al ; Restore ending byte
2596 <1>
2597 00000B13 2E3B36[9C08] <1> cmp si,[cs:InitRDPtr]
2598 00000B18 77D5 <1> ja .get_chunk
2599 <1>
2600 00000B1A 1F <1> pop ds
2601 00000B1B 07 <1> pop es
2602 00000B1C C3 <1> ret
2603 <1>
2604 <1> ;
2605 <1> ; Load RAM disk into high memory
2606 <1> ;
2607 <1> ; Input: InitRD - set to the mangled name of the initrd
2608 <1> ;
2609 <1> loadinitrd:
2610 00000B1D 1E <1> push ds
2611 00000B1E 06 <1> push es
2612 00000B1F 8CC8 <1> mov ax,cs ; CS == DS == ES
2613 00000B21 8ED8 <1> mov ds,ax
2614 00000B23 8EC0 <1> mov es,ax
2615 00000B25 BE[E01D] <1> mov si,InitRD
2616 00000B28 BF[E01C] <1> mov di,InitRDCName
2617 00000B2B E8620A <1> call unmangle_name ; Create human-readable name
2618 00000B2E 81EF[E01C] <1> sub di,InitRDCName
2619 00000B32 893E[DE1B] <1> mov [InitRDCNameLen],di
2620 00000B36 BF[E01D] <1> mov di,InitRD
2621 00000B39 E8A107 <1> call searchdir ; Look for it in directory
2622 00000B3C 747F <1> jz .notthere
2623 <1>
2624 00000B3E 89D1 <1> mov cx,dx
2625 00000B40 66C1E110 <1> shl ecx,16
2626 00000B44 89C1 <1> mov cx,ax ; ECX <- ram disk length
2627 <1>
2628 00000B46 B80040 <1> mov ax,real_mode_seg
2629 00000B49 8EC0 <1> mov es,ax
2630 <1>
2631 00000B4B 6651 <1> push ecx ; Bytes to load
2632 00000B4D 2666833E1C0200 <1> cmp dword [es:su_ramdisklen],0
2633 00000B54 740B <1> je .nopadding ; Don't pad the last initrd
2634 00000B56 6681C1FF0F0000 <1> add ecx,4095
2635 00000B5D 81E100F0 <1> and cx,0F000h
2636 <1> .nopadding:
2637 00000B61 2666010E1C02 <1> add [es:su_ramdisklen],ecx
2638 00000B67 668B16[981F] <1> mov edx,[HighMemSize] ; End of memory
2639 00000B6C 664A <1> dec edx
2640 00000B6E 66A1[8808] <1> mov eax,[RamdiskMax] ; Highest address allowed by kernel
2641 00000B72 6639C2 <1> cmp edx,eax
2642 00000B75 7603 <1> jna .memsize_ok
2643 00000B77 6689C2 <1> mov edx,eax ; Adjust to fit inside limit
2644 <1> .memsize_ok:
2645 00000B7A 6642 <1> inc edx
2646 00000B7C 81E200F0 <1> and dx,0F000h ; Round down to 4K boundary
2647 00000B80 6629CA <1> sub edx,ecx ; Subtract size of ramdisk
2648 00000B83 81E200F0 <1> and dx,0F000h ; Round down to 4K boundary
2649 00000B87 663B16[9408] <1> cmp edx,[KernelEnd] ; Are we hitting the kernel image?
2650 00000B8C 7241 <1> jb no_high_mem
2651 <1>
2652 00000B8E 266689161802 <1> mov [es:su_ramdiskat],edx ; Load address
2653 00000B94 668916[8808] <1> mov [RamdiskMax],edx ; Next initrd loaded here
2654 <1>
2655 00000B99 6689D7 <1> mov edi,edx ; initrd load address
2656 00000B9C 56 <1> push si
2657 00000B9D BE[C406] <1> mov si,crlfloading_msg ; Write "Loading "
2658 00000BA0 E8B112 <1> call cwritestr
2659 00000BA3 BE[E01C] <1> mov si,InitRDCName ; Write ramdisk name
2660 00000BA6 E8AB12 <1> call cwritestr
2661 00000BA9 BE[CF06] <1> mov si,dotdot_msg ; Write dots
2662 00000BAC E8A512 <1> call cwritestr
2663 00000BAF 5E <1> pop si
2664 <1>
2665 00000BB0 6658 <1> pop eax ; Bytes to load
2666 00000BB2 BAFF0F <1> mov dx,0FFFh ; Pad to page
2667 00000BB5 E80316 <1> call load_high ; Load the file
2668 <1>
2669 00000BB8 07 <1> pop es
2670 00000BB9 1F <1> pop ds
2671 00000BBA E98A12 <1> jmp crlf ; Print carriage return and return
2672 <1>
2673 <1> .notthere:
2674 00000BBD BE[E402] <1> mov si,err_noinitrd
2675 00000BC0 E89112 <1> call cwritestr
2676 00000BC3 BE[E01C] <1> mov si,InitRDCName
2677 00000BC6 E88B12 <1> call cwritestr
2678 00000BC9 BE[E006] <1> mov si,crlf_msg
2679 00000BCC E9D105 <1> jmp abort_load
2680 <1>
2681 <1> no_high_mem: ; Error routine
2682 00000BCF BE[0503] <1> mov si,err_nohighmem
2683 00000BD2 E9CB05 <1> jmp abort_load
2684 <1>
2685 00000BD5 C3 <1> ret
2686 <1>
2687 <1> section .data
2688 0000000B 424F4F545F494D4147- <1> boot_image db 'BOOT_IMAGE='
2689 00000014 453D <1>
2690 <1> boot_image_len equ $-boot_image
2691 <1>
2692 <1> section .bss
2693 00000886 <res 00000001>- <1> alignb 4
2694 00000886 <rept> <1>
2695 00000888 <res 00000004> <1> RamdiskMax resd 1 ; Highest address for ramdisk
2696 0000088C <res 00000004> <1> KernelSize resd 1 ; Size of kernel in bytes
2697 00000890 <res 00000004> <1> KernelSects resd 1 ; Size of kernel in sectors
2698 00000894 <res 00000004> <1> KernelEnd resd 1 ; Ending address of the kernel image
2699 00000898 <res 00000002> <1> CmdLineLen resw 1 ; Length of command line including null
2700 0000089A <res 00000002> <1> SetupSecs resw 1 ; Number of setup sectors
2701 0000089C <res 00000002> <1> InitRDPtr resw 1 ; Pointer to initrd= option in command line
2702 0000089E <res 00000001> <1> LoadFlags resb 1 ; Loadflags from kernel
2703
2704 ;
2705 ; COMBOOT-loading code
2706 ;
2707 %include "comboot.inc"
2708 <1> ;; $Id: comboot.inc,v 1.39 2005/01/20 18:43:22 hpa Exp $
2709 <1> ;; -----------------------------------------------------------------------
2710 <1> ;;
2711 <1> ;; Copyright 1994-2005 H. Peter Anvin - All Rights Reserved
2712 <1> ;;
2713 <1> ;; This program is free software; you can redistribute it and/or modify
2714 <1> ;; it under the terms of the GNU General Public License as published by
2715 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
2716 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
2717 <1> ;; (at your option) any later version; incorporated herein by reference.
2718 <1> ;;
2719 <1> ;; -----------------------------------------------------------------------
2720 <1>
2721 <1> ;;
2722 <1> ;; comboot.inc
2723 <1> ;;
2724 <1> ;; Common code for running a COMBOOT image
2725 <1> ;;
2726 <1>
2727 <1> section .text
2728 <1>
2729 <1> ; Parameter registers definition; this is the definition
2730 <1> ; of the stack frame used by INT 21h and INT 22h.
2731 <1> %define P_FLAGS word [bp+44]
2732 <1> %define P_FLAGSL byte [bp+44]
2733 <1> %define P_FLAGSH byte [bp+45]
2734 <1> %define P_CS word [bp+42]
2735 <1> %define P_IP word [bp+40]
2736 <1> %define P_DS word [bp+38]
2737 <1> %define P_ES word [bp+36]
2738 <1> %define P_FS word [bp+34]
2739 <1> %define P_GS word [bp+32]
2740 <1> %define P_EAX dword [bp+28]
2741 <1> %define P_AX word [bp+28]
2742 <1> %define P_HAX word [bp+30]
2743 <1> %define P_AL byte [bp+28]
2744 <1> %define P_AH byte [bp+29]
2745 <1> %define P_ECX dword [bp+24]
2746 <1> %define P_CX word [bp+24]
2747 <1> %define P_HCX word [bp+26]
2748 <1> %define P_CL byte [bp+24]
2749 <1> %define P_CH byte [bp+25]
2750 <1> %define P_EDX dword [bp+20]
2751 <1> %define P_DX word [bp+20]
2752 <1> %define P_HDX word [bp+22]
2753 <1> %define P_DL byte [bp+20]
2754 <1> %define P_DH byte [bp+21]
2755 <1> %define P_EBX dword [bp+16]
2756 <1> %define P_BX word [bp+16]
2757 <1> %define P_HBX word [bp+18]
2758 <1> %define P_BL byte [bp+16]
2759 <1> %define P_BH byte [bp+17]
2760 <1> %define P_EBP dword [bp+8]
2761 <1> %define P_BP word [bp+8]
2762 <1> %define P_HBP word [bp+10]
2763 <1> %define P_ESI dword [bp+4]
2764 <1> %define P_SI word [bp+4]
2765 <1> %define P_HSI word [bp+6]
2766 <1> %define P_EDI dword [bp]
2767 <1> %define P_DI word [bp]
2768 <1> %define P_HDI word [bp+2]
2769 <1>
2770 <1> ; Looks like a COMBOOT image but too large
2771 <1> comboot_too_large:
2772 00000BD6 BE[A003] <1> mov si,err_comlarge
2773 00000BD9 E87812 <1> call cwritestr
2774 00000BDC E9D5F8 <1> jmp enter_command
2775 <1>
2776 <1> ;
2777 <1> ; Load a COMBOOT image. A COMBOOT image is basically a DOS .COM file,
2778 <1> ; except that it may, of course, not contain any DOS system calls. We
2779 <1> ; do, however, allow the execution of INT 20h to return to SYSLINUX.
2780 <1> ;
2781 <1> is_comboot_image:
2782 00000BDF 21D2 <1> and dx,dx
2783 00000BE1 75F3 <1> jnz comboot_too_large
2784 00000BE3 3D00FF <1> cmp ax,0ff00h ; Max size in bytes
2785 00000BE6 73EE <1> jae comboot_too_large
2786 <1>
2787 00000BE8 56 <1> push si ; Save file handle
2788 <1>
2789 00000BE9 E8CC04 <1> call make_plain_cmdline
2790 <1>
2791 00000BEC E86600 <1> call comboot_setup_api
2792 <1>
2793 00000BEF B90040 <1> mov cx,comboot_seg
2794 00000BF2 8EC1 <1> mov es,cx
2795 <1>
2796 00000BF4 31FF <1> xor di,di
2797 00000BF6 B94000 <1> mov cx,64 ; 256 bytes (size of PSP)
2798 00000BF9 6631C0 <1> xor eax,eax ; Clear PSP
2799 00000BFC F366AB <1> rep stosd
2800 <1>
2801 00000BFF 26C7060000CD20 <1> mov word [es:0], 020CDh ; INT 20h instruction
2802 <1> ; First non-free paragraph
2803 <1> ; This is valid because comboot_seg == real_mode_seg
2804 <1> ; == the highest segment used by all derivatives
2805 00000C06 CD12 <1> int 12h ; Get DOS memory size
2806 00000C08 C1E006 <1> shl ax,6 ; Kilobytes -> paragraphs
2807 00000C0B 26A30200 <1> mov word [es:02h],ax
2808 <1>
2809 <1> %ifndef DEPEND
2810 <1> %if real_mode_seg != comboot_seg
2811 <1> %error "This code assumes real_mode_seg == comboot_seg"
2812 <1> %endif
2813 <1> %endif
2814 <1> ; Copy the command line from high memory
2815 00000C0F BE0090 <1> mov si,cmd_line_here
2816 00000C12 B97D00 <1> mov cx,125 ; Max cmdline len (minus space and CR)
2817 00000C15 BF8100 <1> mov di,081h ; Offset in PSP for command line
2818 00000C18 B020 <1> mov al,' ' ; DOS command lines begin with a space
2819 00000C1A AA <1> stosb
2820 <1>
2821 00000C1B 26AC <1> .loop: es lodsb
2822 00000C1D 20C0 <1> and al,al
2823 00000C1F 7403 <1> jz .done
2824 00000C21 AA <1> stosb
2825 00000C22 E2F7 <1> loop .loop
2826 <1> .done:
2827 <1>
2828 00000C24 B00D <1> mov al,0Dh ; CR after last character
2829 00000C26 AA <1> stosb
2830 00000C27 89F8 <1> mov ax,di
2831 00000C29 2C82 <1> sub al,82h ; Include space but not CR
2832 00000C2B 26A28000 <1> mov [es:80h],al ; Store command line length
2833 <1>
2834 <1> ; Now actually load the file...
2835 00000C2F 5E <1> pop si ; File handle
2836 00000C30 BB0001 <1> mov bx,100h ; Load at <seg>:0100h
2837 00000C33 B97F00 <1> mov cx,0FF00h >> SECTOR_SHIFT
2838 <1> ; Absolute maximum # of sectors
2839 00000C36 E88509 <1> call getfssec
2840 <1>
2841 <1> ; And invoke the program...
2842 00000C39 8926[6855] <1> mov [SavedSSSP],sp
2843 00000C3D 8C16[6A55] <1> mov [SavedSSSP+2],ss ; Save away SS:SP
2844 <1>
2845 00000C41 8CC0 <1> mov ax,es
2846 00000C43 8ED8 <1> mov ds,ax
2847 00000C45 8ED0 <1> mov ss,ax
2848 00000C47 31E4 <1> xor sp,sp
2849 00000C49 6A00 <1> push word 0 ; Return to address 0 -> exit
2850 <1>
2851 00000C4B EA00010040 <1> jmp comboot_seg:100h ; Run it
2852 <1>
2853 <1> ; Proper return vector
2854 00000C50 FA <1> comboot_return: cli ; Don't trust anyone
2855 00000C51 31C0 <1> xor ax,ax
2856 00000C53 EB55 <1> jmp comboot_exit
2857 <1>
2858 <1> ;
2859 <1> ; Set up the COMBOOT API interrupt vectors. This is also used
2860 <1> ; by the COM32 code.
2861 <1> ;
2862 <1> comboot_setup_api:
2863 00000C55 BF8000 <1> mov di,4*0x20 ; DOS interrupt vectors
2864 00000C58 66B8[500C0000] <1> mov eax,comboot_return ; INT 20h = exit
2865 00000C5E 66AB <1> stosd
2866 00000C60 B8[740C] <1> mov ax,comboot_int21 ; INT 21h = DOS-compatible syscalls
2867 00000C63 66AB <1> stosd
2868 00000C65 B8[5B0D] <1> mov ax,comboot_int22 ; INT 22h = proprietary syscalls
2869 00000C68 66AB <1> stosd
2870 00000C6A B8[A60C] <1> mov ax,comboot_bogus
2871 00000C6D B91D00 <1> mov cx,29 ; All remaining DOS vectors
2872 00000C70 F366AB <1> rep stosd
2873 00000C73 C3 <1> ret
2874 <1>
2875 <1> ; INT 21h: generic DOS system call
2876 00000C74 FA <1> comboot_int21: cli
2877 00000C75 1E <1> push ds
2878 00000C76 06 <1> push es
2879 00000C77 0FA0 <1> push fs
2880 00000C79 0FA8 <1> push gs
2881 00000C7B 6660 <1> pushad
2882 00000C7D FC <1> cld
2883 00000C7E 8CCD <1> mov bp,cs
2884 00000C80 8EDD <1> mov ds,bp
2885 00000C82 8EC5 <1> mov es,bp
2886 00000C84 89E5 <1> mov bp,sp ; Set up stack frame
2887 <1>
2888 00000C86 E81D16 <1> call adjust_screen ; The COMBOOT program might have changed the screen
2889 <1>
2890 00000C89 B90A00 <1> mov cx,int21_count
2891 00000C8C BE[6A00] <1> mov si,int21_table
2892 00000C8F AC <1> .again: lodsb
2893 00000C90 3A461D <1> cmp al,P_AH
2894 00000C93 AD <1> lodsw
2895 00000C94 E0F9 <1> loopne .again
2896 <1> ; The last function in the list is the
2897 <1> ; "no such function" function
2898 00000C96 F8 <1> clc
2899 00000C97 FFD0 <1> call ax ; Call the invoked function
2900 <1> comboot_resume:
2901 00000C99 0F92462C <1> setc P_FLAGSL ; Propagate CF->error
2902 00000C9D 6661 <1> popad
2903 00000C9F 0FA9 <1> pop gs
2904 00000CA1 0FA1 <1> pop fs
2905 00000CA3 07 <1> pop es
2906 00000CA4 1F <1> pop ds
2907 00000CA5 CF <1> iret
2908 <1>
2909 <1> ; Attempted to execute non-21h DOS system call
2910 00000CA6 FA <1> comboot_bogus: cli ; Don't trust anyone
2911 00000CA7 B8[8203] <1> mov ax,err_notdos
2912 <1> ;
2913 <1> ; Generic COMBOOT return to command line code
2914 <1> ; AX -> message (if any)
2915 <1> ; BX -> where to go next
2916 <1> ;
2917 <1> comboot_exit:
2918 00000CAA BB[B404] <1> mov bx,enter_command ; Normal return to command prompt
2919 <1> comboot_exit_special:
2920 00000CAD 31D2 <1> xor dx,dx
2921 00000CAF 8EDA <1> mov ds,dx
2922 00000CB1 8EC2 <1> mov es,dx
2923 00000CB3 0FB226[6855] <1> lss sp,[SavedSSSP]
2924 00000CB8 FB <1> sti
2925 00000CB9 FC <1> cld
2926 00000CBA E8E915 <1> call adjust_screen ; The COMBOOT program might have changed the screen
2927 00000CBD 21C0 <1> and ax,ax
2928 00000CBF 740A <1> je .nomsg
2929 00000CC1 BE[601C] <1> mov si,KernelCName
2930 00000CC4 E88D11 <1> call cwritestr
2931 00000CC7 96 <1> xchg si,ax
2932 00000CC8 E88911 <1> call cwritestr
2933 00000CCB FFE3 <1> .nomsg: jmp bx
2934 <1>
2935 <1> ;
2936 <1> ; INT 21h system calls
2937 <1> ;
2938 <1> comboot_getkey: ; 01 = get key with echo
2939 00000CCD E89D17 <1> call vgashowcursor
2940 00000CD0 E86500 <1> call comboot_getchar
2941 00000CD3 E89D17 <1> call vgahidecursor
2942 00000CD6 E8AC18 <1> call writechr
2943 00000CD9 F8 <1> clc
2944 00000CDA C3 <1> ret
2945 <1>
2946 <1> comboot_writechr: ; 02 = writechr
2947 00000CDB 8A4614 <1> mov al,P_DL
2948 00000CDE E8A418 <1> call writechr
2949 00000CE1 F8 <1> clc
2950 00000CE2 C3 <1> ret
2951 <1>
2952 <1> comboot_writeserial: ; 04 = write serial port
2953 00000CE3 8A4614 <1> mov al,P_DL
2954 00000CE6 E8B510 <1> call write_serial
2955 00000CE9 F8 <1> clc
2956 00000CEA C3 <1> ret
2957 <1>
2958 <1> comboot_getkeynoecho: ; 08 = get key w/o echo
2959 00000CEB E84A00 <1> call comboot_getchar
2960 00000CEE F8 <1> clc
2961 00000CEF C3 <1> ret
2962 <1>
2963 <1> comboot_writestr: ; 09 = write DOS string
2964 00000CF0 8E4626 <1> mov es,P_DS
2965 00000CF3 8B7614 <1> mov si,P_DX
2966 00000CF6 26AC <1> .loop: es lodsb
2967 00000CF8 3C24 <1> cmp al,'$' ; End string with $ - bizarre
2968 00000CFA 7405 <1> je .done
2969 00000CFC E88618 <1> call writechr
2970 00000CFF EBF5 <1> jmp short .loop
2971 00000D01 F8 <1> .done: clc
2972 00000D02 C3 <1> ret
2973 <1>
2974 <1> comboot_checkkey: ; 0B = check keyboard status
2975 00000D03 803E[B100]00 <1> cmp byte [APIKeyFlag],00h
2976 00000D08 7503 <1> jnz .waiting
2977 00000D0A E8CF10 <1> call pollchar
2978 00000D0D 0F94C0 <1> .waiting: setz al
2979 00000D10 FEC8 <1> dec al ; AL = 0FFh if present, 0 if not
2980 00000D12 88461C <1> mov P_AL,al
2981 00000D15 F8 <1> clc
2982 00000D16 C3 <1> ret
2983 <1>
2984 <1> comboot_checkver: ; 30 = check DOS version
2985 <1> ; We return 0 in all DOS-compatible version registers,
2986 <1> ; but the high part of eax-ebx-ecx-edx spell "SYSLINUX"
2987 00000D17 66C7461C00005359 <1> mov P_EAX,'SY' << 16
2988 00000D1F 66C746100000534C <1> mov P_EBX,'SL' << 16
2989 00000D27 66C746180000494E <1> mov P_ECX,'IN' << 16
2990 00000D2F 66C7461400005558 <1> mov P_EDX,'UX' << 16
2991 00000D37 C3 <1> ret
2992 <1>
2993 <1> comboot_getchar:
2994 00000D38 803E[B100]00 <1> cmp byte [APIKeyFlag],00h
2995 00000D3D 7513 <1> jne .queued
2996 00000D3F E8C410 <1> call getchar ; If not queued get input
2997 00000D42 20C0 <1> and al,al ; Function key? (CF <- 0)
2998 00000D44 7508 <1> jnz .done
2999 00000D46 8826[B000] <1> mov [APIKeyWait],ah ; High part of key
3000 00000D4A FE06[B100] <1> inc byte [APIKeyFlag] ; Set flag
3001 00000D4E 88461C <1> .done: mov P_AL,al
3002 00000D51 C3 <1> ret
3003 00000D52 A0[B000] <1> .queued: mov al,[APIKeyWait]
3004 00000D55 FE0E[B100] <1> dec byte [APIKeyFlag]
3005 00000D59 EBF3 <1> jmp .done
3006 <1>
3007 <1> ;
3008 <1> ; INT 22h - SYSLINUX-specific system calls
3009 <1> ; System call number in ax
3010 <1> ;
3011 <1> comboot_int22:
3012 00000D5B FA <1> cli
3013 00000D5C 1E <1> push ds
3014 00000D5D 06 <1> push es
3015 00000D5E 0FA0 <1> push fs
3016 00000D60 0FA8 <1> push gs
3017 00000D62 6660 <1> pushad
3018 00000D64 FC <1> cld
3019 00000D65 8CCD <1> mov bp,cs
3020 00000D67 8EDD <1> mov ds,bp
3021 00000D69 8EC5 <1> mov es,bp
3022 00000D6B 89E5 <1> mov bp,sp ; Set up stack frame
3023 <1>
3024 00000D6D E83615 <1> call adjust_screen ; The COMBOOT program might have changed the screen
3025 <1>
3026 00000D70 83F814 <1> cmp ax,int22_count
3027 00000D73 7202 <1> jb .ok
3028 00000D75 31C0 <1> xor ax,ax ; Function 0 -> unimplemented
3029 <1> .ok:
3030 00000D77 93 <1> xchg ax,bx
3031 00000D78 01DB <1> add bx,bx ; CF <- 0
3032 00000D7A FF97[8800] <1> call [bx+int22_table]
3033 00000D7E E918FF <1> jmp comboot_resume ; On return
3034 <1>
3035 <1> ;
3036 <1> ; INT 22h AX=0000h Unimplemented call
3037 <1> ;
3038 <1> comapi_err:
3039 00000D81 F9 <1> stc
3040 00000D82 C3 <1> ret
3041 <1>
3042 <1> ;
3043 <1> ; INT 22h AX=0001h Get SYSLINUX version
3044 <1> ;
3045 <1> comapi_get_version:
3046 <1> ; Number of API functions supported
3047 00000D83 C7461C1400 <1> mov P_AX,int22_count
3048 <1> ; SYSLINUX version
3049 00000D88 C746180903 <1> mov P_CX,(VER_MAJOR << 8)+VER_MINOR
3050 <1> ; SYSLINUX derivative ID byte
3051 00000D8D C746143200 <1> mov P_DX,my_id
3052 <1> ; For future use
3053 00000D92 8C4E10 <1> mov P_BX,cs ; cs == 0
3054 <1>
3055 00000D95 8C5E24 <1> mov P_ES,ds
3056 <1> ; ES:SI -> version banner
3057 00000D98 C74604[EE06] <1> mov P_SI,syslinux_banner
3058 <1> ; ES:DI -> copyright string
3059 00000D9D C74600[4B01] <1> mov P_DI,copyright_str
3060 <1>
3061 <1> comapi_nop:
3062 00000DA2 F8 <1> clc
3063 00000DA3 C3 <1> ret
3064 <1>
3065 <1> ;
3066 <1> ; INT 22h AX=0002h Write string
3067 <1> ;
3068 <1> ; Write null-terminated string in ES:BX
3069 <1> ;
3070 <1> comapi_writestr:
3071 00000DA4 8E5E24 <1> mov ds,P_ES
3072 00000DA7 8B7610 <1> mov si,P_BX
3073 00000DAA E8A710 <1> call writestr
3074 00000DAD F8 <1> clc
3075 00000DAE C3 <1> ret
3076 <1>
3077 <1> ;
3078 <1> ; INT 22h AX=0003h Run command
3079 <1> ;
3080 <1> ; Terminates the COMBOOT program and executes the command line in
3081 <1> ; ES:BX as if it had been entered by the user.
3082 <1> ;
3083 <1> comapi_run:
3084 00000DAF 8E5E24 <1> mov ds,P_ES
3085 00000DB2 8B7610 <1> mov si,P_BX
3086 00000DB5 BF[D408] <1> mov di,command_line
3087 00000DB8 E8C117 <1> call strcpy
3088 00000DBB 31C0 <1> xor ax,ax
3089 00000DBD BB[EE05] <1> mov bx,load_kernel ; Run a new kernel
3090 00000DC0 E9EAFE <1> jmp comboot_exit_special ; Terminate task, clean up
3091 <1>
3092 <1> ;
3093 <1> ; INT 22h AX=0004h Run default command
3094 <1> ;
3095 <1> ; Terminates the COMBOOT program and executes the default command line
3096 <1> ; as if a timeout had happened or the user pressed <Enter>.
3097 <1> ;
3098 <1> comapi_run_default:
3099 00000DC3 BB[D405] <1> mov bx,auto_boot
3100 00000DC6 E9E4FE <1> jmp comboot_exit_special
3101 <1>
3102 <1> ;
3103 <1> ; INT 22h AX=0005h Force text mode
3104 <1> ;
3105 <1> ; Puts the video in standard text mode
3106 <1> ;
3107 <1> comapi_textmode:
3108 00000DC9 E87916 <1> call vgaclearmode
3109 00000DCC F8 <1> clc
3110 00000DCD C3 <1> ret
3111 <1>
3112 <1> ;
3113 <1> ; INT 22h AX=0006h Open file
3114 <1> ;
3115 <1> comapi_open:
3116 00000DCE 1E <1> push ds
3117 00000DCF 8E5E24 <1> mov ds,P_ES
3118 00000DD2 8B7604 <1> mov si,P_SI
3119 00000DD5 BF[E01D] <1> mov di,InitRD
3120 00000DD8 57 <1> push di
3121 00000DD9 E85F07 <1> call mangle_name
3122 00000DDC 5F <1> pop di
3123 00000DDD 1F <1> pop ds
3124 00000DDE E8FC04 <1> call searchdir
3125 00000DE1 7410 <1> jz .err
3126 00000DE3 89461C <1> mov P_AX,ax
3127 00000DE6 89561E <1> mov P_HAX,dx
3128 00000DE9 C746180002 <1> mov P_CX,SECTOR_SIZE
3129 00000DEE 897604 <1> mov P_SI,si
3130 00000DF1 F8 <1> clc
3131 00000DF2 C3 <1> ret
3132 <1> .err:
3133 00000DF3 F9 <1> stc
3134 00000DF4 C3 <1> ret
3135 <1>
3136 <1>
3137 <1> ;
3138 <1> ; INT 22h AX=0007h Read file
3139 <1> ;
3140 <1> comapi_read:
3141 00000DF5 8E4624 <1> mov es,P_ES
3142 00000DF8 8B5E10 <1> mov bx,P_BX
3143 00000DFB 8B7604 <1> mov si,P_SI
3144 00000DFE 8B4E18 <1> mov cx,P_CX
3145 00000E01 E8BA07 <1> call getfssec
3146 00000E04 7302 <1> jnc .noteof
3147 00000E06 31F6 <1> xor si,si ; SI <- 0 on EOF, CF <- 0
3148 00000E08 897604 <1> .noteof: mov P_SI,si
3149 00000E0B C3 <1> ret
3150 <1>
3151 <1> ;
3152 <1> ; INT 22h AX=0008h Close file
3153 <1> ;
3154 <1> comapi_close:
3155 <1> ; Do nothing for now. Eventually implement
3156 <1> ; an internal API for this.
3157 00000E0C F8 <1> clc
3158 00000E0D C3 <1> ret
3159 <1>
3160 <1> ;
3161 <1> ; INT 22h AX=0009h Call PXE stack
3162 <1> ;
3163 <1> %if IS_PXELINUX
3164 <1> comapi_pxecall:
3165 00000E0E 8B5E10 <1> mov bx,P_BX
3166 00000E11 8E4624 <1> mov es,P_ES
3167 00000E14 8B7E00 <1> mov di,P_DI
3168 00000E17 E88D07 <1> call pxenv
3169 00000E1A 89461C <1> mov P_AX,ax
3170 00000E1D F8 <1> clc
3171 00000E1E C3 <1> ret
3172 <1> %else
3173 <1> comapi_pxecall equ comapi_err ; Not available
3174 <1> %endif
3175 <1>
3176 <1> ;
3177 <1> ; INT 22h AX=000Ah Get Derivative-Specific Info
3178 <1> ;
3179 <1> comapi_derinfo:
3180 00000E1F C6461C32 <1> mov P_AL,my_id
3181 <1> %if IS_SYSLINUX || IS_MDSLINUX || IS_EXTLINUX
3182 <1> mov al,[DriveNumber]
3183 <1> mov P_DL,al
3184 <1> mov P_ES,cs
3185 <1> mov P_BX,PartInfo
3186 <1> %elif IS_PXELINUX
3187 00000E23 A1[0800] <1> mov ax,[APIVer]
3188 00000E26 894614 <1> mov P_DX,ax
3189 00000E29 A1[0400] <1> mov ax,[StrucPtr]
3190 00000E2C 894610 <1> mov P_BX,ax
3191 00000E2F A1[0600] <1> mov ax,[StrucPtr+2]
3192 00000E32 894624 <1> mov P_ES,ax
3193 00000E35 A1[6047] <1> mov ax,[InitStack]
3194 00000E38 894604 <1> mov P_SI,ax
3195 00000E3B A1[6247] <1> mov ax,[InitStack+2]
3196 00000E3E 894622 <1> mov P_FS,ax
3197 <1> %elif IS_ISOLINUX
3198 <1> mov al,[DriveNo]
3199 <1> mov P_DL,al
3200 <1> mov P_ES,cs
3201 <1> mov P_BX,spec_packet
3202 <1> %endif
3203 00000E41 F8 <1> clc
3204 00000E42 C3 <1> ret
3205 <1>
3206 <1> ;
3207 <1> ; INT 22h AX=000Bh Get Serial Console Configuration
3208 <1> ;
3209 <1> comapi_serialcfg:
3210 00000E43 A1[F600] <1> mov ax,[SerialPort]
3211 00000E46 894614 <1> mov P_DX,ax
3212 00000E49 A1[CA08] <1> mov ax,[BaudDivisor]
3213 00000E4C 894618 <1> mov P_CX,ax
3214 00000E4F A1[CC08] <1> mov ax,[FlowControl]
3215 00000E52 08E0 <1> or al,ah
3216 00000E54 8A26[CE08] <1> mov ah,[FlowIgnore]
3217 00000E58 C0EC04 <1> shr ah,4
3218 00000E5B F606[BE00]01 <1> test byte [DisplayCon],01h
3219 00000E60 7503 <1> jnz .normalconsole
3220 00000E62 80CC80 <1> or ah,80h
3221 <1> .normalconsole:
3222 00000E65 894610 <1> mov P_BX,ax
3223 00000E68 F8 <1> clc
3224 00000E69 C3 <1> ret
3225 <1>
3226 <1> ;
3227 <1> ; INT 22h AX=000Ch Perform final cleanup
3228 <1> ;
3229 <1> comapi_cleanup:
3230 <1> %if IS_PXELINUX
3231 <1> ; Unload PXE if requested
3232 00000E6A F6C203 <1> test dl,3
3233 00000E6D 0F9506[A608] <1> setnz [KeepPXE]
3234 00000E72 29E5 <1> sub bp,sp ; unload_pxe may move the stack around
3235 00000E74 E8D208 <1> call unload_pxe
3236 00000E77 01E5 <1> add bp,sp ; restore frame pointer...
3237 <1> %elif IS_SYSLINUX || IS_MDSLINUX || IS_EXTLINUX
3238 <1> ; Restore original FDC table
3239 <1> mov eax,[OrigFDCTabPtr]
3240 <1> mov [fdctab],eax
3241 <1> %endif
3242 <1> ; Reset the floppy disk subsystem
3243 00000E79 31C0 <1> xor ax,ax
3244 00000E7B 31D2 <1> xor dx,dx
3245 00000E7D CD13 <1> int 13h
3246 00000E7F F8 <1> clc
3247 00000E80 C3 <1> ret
3248 <1>
3249 <1> ;
3250 <1> ; INT 22h AX=000Dh Clean up then replace bootstrap
3251 <1> ;
3252 <1> comapi_chainboot:
3253 00000E81 E8E6FF <1> call comapi_cleanup
3254 00000E84 668B4600 <1> mov eax,P_EDI
3255 00000E88 66A3[0400] <1> mov [trackbuf+4],eax ; Copy from
3256 00000E8C 668B4618 <1> mov eax,P_ECX
3257 00000E90 66A3[0800] <1> mov [trackbuf+8],eax ; Total bytes
3258 00000E94 66B8007C0000 <1> mov eax,7C00h
3259 00000E9A 66A3[0000] <1> mov [trackbuf],eax ; Copy to
3260 00000E9E 66A3[6455] <1> mov [EntryPoint],eax ; CS:IP entry point
3261 00000EA2 668B7604 <1> mov esi,P_ESI
3262 00000EA6 668B5610 <1> mov edx,P_EBX
3263 00000EAA 8B5E26 <1> mov bx,P_DS
3264 00000EAD E96802 <1> jmp replace_bootstrap_one
3265 <1>
3266 <1>
3267 <1> ;
3268 <1> ; INT 22h AX=000Eh Get configuration file name
3269 <1> ;
3270 <1> comapi_configfile:
3271 00000EB0 8C4E24 <1> mov P_ES,cs
3272 00000EB3 C74610[0445] <1> mov P_BX,ConfigName
3273 00000EB8 F8 <1> clc
3274 00000EB9 C3 <1> ret
3275 <1>
3276 <1> ;
3277 <1> ; INT 22h AX=000Fh Get IPAPPEND strings
3278 <1> ;
3279 <1> %if IS_PXELINUX
3280 <1> comapi_ipappend:
3281 00000EBA 8C4E24 <1> mov P_ES,cs
3282 00000EBD C746180200 <1> mov P_CX,numIPAppends
3283 00000EC2 C74610[1600] <1> mov P_BX,IPAppends
3284 00000EC7 F8 <1> clc
3285 00000EC8 C3 <1> ret
3286 <1>
3287 <1> section .data
3288 <1> alignb 2, db 0
3289 00000016 [1047] <1> IPAppends dw IPOption
3290 00000018 [2700] <1> dw BOOTIFStr
3291 <1> numIPAppends equ ($-IPAppends)/2
3292 <1>
3293 <1> %else
3294 <1> comapi_ipappend equ comapi_err
3295 <1> %endif
3296 <1>
3297 <1> ;
3298 <1> ; INT 22h AX=0010h Resolve hostname
3299 <1> ;
3300 <1> %if IS_PXELINUX
3301 <1> comapi_dnsresolv:
3302 0000001A 8E5E24 <1> mov ds,P_ES
3303 0000001D 8B7610 <1> mov si,P_BX
3304 00000020 E8(4F26) <1> call dns_resolv
3305 00000023 6689461C <1> mov P_EAX,eax
3306 00000027 C3 <1> ret
3307 <1> %else
3308 <1> comapi_dnsresolv equ comapi_err
3309 <1> %endif
3310 <1>
3311 <1> section .data
3312 <1> %macro int21 2
3313 <1> db %1
3314 <1> dw %2
3315 <1> %endmacro
3316 <1>
3317 <1>
3318 <1> ;
3319 <1> ; INT 22h AX=0011h Maximum number of shuffle descriptors
3320 <1> ;
3321 <1> comapi_maxshuffle:
3322 00000028 C746185505 <1> mov P_CX,(2*trackbufsize)/12
3323 0000002D C3 <1> ret
3324 <1>
3325 <1> ;
3326 <1> ; INT 22h AX=0012h Cleanup, shuffle and boot
3327 <1> ;
3328 <1> comapi_shuffle:
3329 0000002E E8(6A0E) <1> call comapi_cleanup
3330 00000031 8B4E18 <1> mov cx,P_CX
3331 00000034 81F95505 <1> cmp cx,(2*trackbufsize)/12
3332 00000038 7729 <1> ja .error
3333 <1>
3334 0000003A 51 <1> push cx ; On stack: descriptor count
3335 <1>
3336 0000003B 678D0C49 <1> lea cx,[ecx+ecx*2] ; CX *= 3
3337 <1>
3338 0000003F 8E6624 <1> mov fs,P_ES
3339 00000042 8B7600 <1> mov si,P_DI
3340 00000045 BF[0000] <1> mov di,trackbuf
3341 00000048 57 <1> push di ; On stack: descriptor list address
3342 00000049 64F366A5 <1> fs rep movsd ; Copy the list
3343 <1>
3344 0000004D 668B4608 <1> mov eax,P_EBP
3345 00000051 66A3[6455] <1> mov [EntryPoint],eax ; CS:IP entry point
3346 00000055 668B7604 <1> mov esi,P_ESI
3347 00000059 668B5610 <1> mov edx,P_EBX
3348 0000005D 8B5E26 <1> mov bx,P_DS
3349 00000060 E9(1D11) <1> jmp replace_bootstrap
3350 <1> .error:
3351 00000063 F9 <1> stc
3352 00000064 C3 <1> ret
3353 <1>
3354 <1> ;
3355 <1> ; INT 22h AX=0013h Idle call
3356 <1> ;
3357 <1> comapi_idle:
3358 <1> DO_IDLE
3359 00000065 E8(F219) <2> call check_for_arp
3360 00000068 F8 <1> clc
3361 00000069 C3 <1> ret
3362 <1>
3363 <1> int21_table:
3364 <1> int21 00h, comboot_return
3365 0000006A 00 <2> db %1
3366 0000006B [500C] <2> dw %2
3367 <1> int21 01h, comboot_getkey
3368 0000006D 01 <2> db %1
3369 0000006E [CD0C] <2> dw %2
3370 <1> int21 02h, comboot_writechr
3371 00000070 02 <2> db %1
3372 00000071 [DB0C] <2> dw %2
3373 <1> int21 04h, comboot_writeserial
3374 00000073 04 <2> db %1
3375 00000074 [E30C] <2> dw %2
3376 <1> int21 08h, comboot_getkeynoecho
3377 00000076 08 <2> db %1
3378 00000077 [EB0C] <2> dw %2
3379 <1> int21 09h, comboot_writestr
3380 00000079 09 <2> db %1
3381 0000007A [F00C] <2> dw %2
3382 <1> int21 0Bh, comboot_checkkey
3383 0000007C 0B <2> db %1
3384 0000007D [030D] <2> dw %2
3385 <1> int21 30h, comboot_checkver
3386 0000007F 30 <2> db %1
3387 00000080 [170D] <2> dw %2
3388 <1> int21 4Ch, comboot_return
3389 00000082 4C <2> db %1
3390 00000083 [500C] <2> dw %2
3391 <1> int21 -1, comboot_bogus
3392 00000085 FF <2> db %1
3393 00000086 [A60C] <2> dw %2
3394 <1> int21_count equ ($-int21_table)/3
3395 <1>
3396 <1> align 2, db 0
3397 <1> int22_table:
3398 00000088 [810D] <1> dw comapi_err ; 0000 unimplemented syscall
3399 0000008A [830D] <1> dw comapi_get_version ; 0001 get SYSLINUX version
3400 0000008C [A40D] <1> dw comapi_writestr ; 0002 write string
3401 0000008E [AF0D] <1> dw comapi_run ; 0003 run specified command
3402 00000090 [C30D] <1> dw comapi_run_default ; 0004 run default command
3403 00000092 [C90D] <1> dw comapi_textmode ; 0005 force text mode
3404 00000094 [CE0D] <1> dw comapi_open ; 0006 open file
3405 00000096 [F50D] <1> dw comapi_read ; 0007 read file
3406 00000098 [0C0E] <1> dw comapi_close ; 0008 close file
3407 0000009A [0E0E] <1> dw comapi_pxecall ; 0009 call PXE stack
3408 0000009C [1F0E] <1> dw comapi_derinfo ; 000A derivative-specific info
3409 0000009E [430E] <1> dw comapi_serialcfg ; 000B get serial port config
3410 000000A0 [6A0E] <1> dw comapi_cleanup ; 000C perform final cleanup
3411 000000A2 [810E] <1> dw comapi_chainboot ; 000D clean up then bootstrap
3412 000000A4 [B00E] <1> dw comapi_configfile ; 000E get name of config file
3413 000000A6 [BA0E] <1> dw comapi_ipappend ; 000F get ipappend strings
3414 000000A8 [1A00] <1> dw comapi_dnsresolv ; 0010 resolve hostname
3415 000000AA [2800] <1> dw comapi_maxshuffle ; 0011 maximum shuffle descriptors
3416 000000AC [2E00] <1> dw comapi_shuffle ; 0012 cleanup, shuffle and boot
3417 000000AE [6500] <1> dw comapi_idle ; 0013 idle call
3418 <1> int22_count equ ($-int22_table)/2
3419 <1>
3420 000000B0 00 <1> APIKeyWait db 0
3421 000000B1 00 <1> APIKeyFlag db 0
3422 %include "com32.inc"
3423 <1> ;; $Id: com32.inc,v 1.9 2005/01/06 22:34:06 hpa Exp $
3424 <1> ;; -----------------------------------------------------------------------
3425 <1> ;;
3426 <1> ;; Copyright 1994-2003 H. Peter Anvin - All Rights Reserved
3427 <1> ;;
3428 <1> ;; This program is free software; you can redistribute it and/or modify
3429 <1> ;; it under the terms of the GNU General Public License as published by
3430 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
3431 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
3432 <1> ;; (at your option) any later version; incorporated herein by reference.
3433 <1> ;;
3434 <1> ;; -----------------------------------------------------------------------
3435 <1>
3436 <1> ;;
3437 <1> ;; com32.inc
3438 <1> ;;
3439 <1> ;; Common code for running a COM32 image
3440 <1> ;;
3441 <1>
3442 <1> ;
3443 <1> ; Load a COM32 image. A COM32 image is the 32-bit analogue to a DOS
3444 <1> ; .com file. A COM32 image is loaded at address 0x101000, with %esp
3445 <1> ; set to the high end of usable memory.
3446 <1> ;
3447 <1> ; A COM32 image should begin with the magic bytes:
3448 <1> ; B8 FF 4C CD 21, which is "mov eax,0x21cd4cff" in 32-bit mode and
3449 <1> ; "mov ax,0x4cff; int 0x21" in 16-bit mode. This will abort the
3450 <1> ; program with an error if run in 16-bit mode.
3451 <1> ;
3452 <1> pm_idt: equ 0x100000
3453 <1> pm_entry: equ 0x101000
3454 <1>
3455 <1> bits 16
3456 <1> section .data
3457 <1> align 2, db 0
3458 <1> com32_pmidt:
3459 000000B2 0008 <1> dw 8*256 ; Limit
3460 000000B4 00001000 <1> dd pm_idt ; Address
3461 <1>
3462 <1> com32_rmidt:
3463 000000B8 FFFF <1> dw 0ffffh ; Limit
3464 000000BA 00000000 <1> dd 0 ; Address
3465 <1>
3466 <1> section .text
3467 <1> is_com32_image:
3468 00000EC9 56 <1> push si ; Save file handle
3469 00000ECA 52 <1> push dx ; File length held in DX:AX
3470 00000ECB 50 <1> push ax
3471 <1>
3472 00000ECC E8E901 <1> call make_plain_cmdline
3473 <1> ; Copy the command line into the low cmdline buffer
3474 00000ECF B80040 <1> mov ax,real_mode_seg
3475 00000ED2 8EE0 <1> mov fs,ax
3476 00000ED4 BE0090 <1> mov si,cmd_line_here
3477 00000ED7 BF[D408] <1> mov di,command_line
3478 00000EDA 8B0E[EE00] <1> mov cx,[CmdLinePtr]
3479 00000EDE 41 <1> inc cx ; Include final null
3480 00000EDF 29F1 <1> sub cx,si
3481 00000EE1 64F3A4 <1> fs rep movsb
3482 <1>
3483 00000EE4 E8A415 <1> call highmemsize ; We need the high memory size...
3484 00000EE7 E86BFD <1> call comboot_setup_api ; Set up the COMBOOT-style API
3485 <1>
3486 00000EEA 66BF00101000 <1> mov edi,pm_entry ; Load address
3487 00000EF0 6658 <1> pop eax ; File length
3488 00000EF2 5E <1> pop si ; File handle
3489 00000EF3 31D2 <1> xor dx,dx ; No padding
3490 00000EF5 E8C312 <1> call load_high
3491 00000EF8 E84C0F <1> call crlf
3492 <1>
3493 <1> com32_start:
3494 00000EFB 66BB[440F0000] <1> mov ebx,com32_call_start ; Where to go in PM
3495 <1>
3496 <1> com32_enter_pm:
3497 00000F01 FA <1> cli
3498 00000F02 8CC8 <1> mov ax,cs
3499 00000F04 8ED8 <1> mov ds,ax
3500 00000F06 8926[6855] <1> mov [SavedSSSP],sp
3501 00000F0A 8C16[6A55] <1> mov [SavedSSSP+2],ss
3502 00000F0E FC <1> cld
3503 00000F0F E8(4B01) <1> call a20_test
3504 00000F12 7503 <1> jnz .a20ok
3505 00000F14 E8(CC00) <1> call enable_a20
3506 <1>
3507 <1> .a20ok:
3508 00000F17 0F0116[0000] <1> lgdt [bcopy_gdt] ; We can use the same GDT just fine
3509 00000F1C 0F011E[B200] <1> lidt [com32_pmidt] ; Set up the IDT
3510 00000F21 0F20C0 <1> mov eax,cr0
3511 00000F24 0C01 <1> or al,1
3512 00000F26 0F22C0 <1> mov cr0,eax ; Enter protected mode
3513 00000F29 EA[2E0F]2000 <1> jmp 20h:.in_pm
3514 <1>
3515 <1> bits 32
3516 <1> .in_pm:
3517 00000F2E 31C0 <1> xor eax,eax ; Available for future use...
3518 00000F30 8EE0 <1> mov fs,eax
3519 00000F32 8EE8 <1> mov gs,eax
3520 <1>
3521 00000F34 B028 <1> mov al,28h ; Set up data segments
3522 00000F36 8EC0 <1> mov es,eax
3523 00000F38 8ED8 <1> mov ds,eax
3524 00000F3A 8ED0 <1> mov ss,eax
3525 <1>
3526 00000F3C 8B25[A0080000] <1> mov esp,[PMESP] ; Load protmode %esp if available
3527 00000F42 FFE3 <1> jmp ebx ; Go to where we need to go
3528 <1>
3529 <1> ;
3530 <1> ; This is invoked right before the actually starting the COM32
3531 <1> ; progam, in 32-bit mode...
3532 <1> ;
3533 <1> com32_call_start:
3534 <1> ;
3535 <1> ; Point the stack to the end of high memory
3536 <1> ;
3537 00000F44 678B26[981F] <1> mov esp,[word HighMemSize]
3538 <1>
3539 <1> ;
3540 <1> ; Set up the protmode IDT and the interrupt jump buffers
3541 <1> ; We set these up in the system area at 0x100000,
3542 <1> ; but we could also put them beyond the stack.
3543 <1> ;
3544 00000F49 BF00001000 <1> mov edi,pm_idt
3545 <1>
3546 <1> ; Form an interrupt gate descriptor
3547 00000F4E B800082000 <1> mov eax,0x00200000+((pm_idt+8*256)&0x0000ffff)
3548 00000F53 BB00EE1000 <1> mov ebx,0x0000ee00+((pm_idt+8*256)&0xffff0000)
3549 00000F58 31C9 <1> xor ecx,ecx
3550 00000F5A FEC5 <1> inc ch ; ecx <- 256
3551 <1>
3552 00000F5C 51 <1> push ecx
3553 <1> .make_idt:
3554 00000F5D AB <1> stosd
3555 00000F5E 83C008 <1> add eax,8
3556 00000F61 93 <1> xchg eax,ebx
3557 00000F62 AB <1> stosd
3558 00000F63 93 <1> xchg eax,ebx
3559 00000F64 E2F7 <1> loop .make_idt
3560 <1>
3561 00000F66 59 <1> pop ecx
3562 <1>
3563 <1> ; Each entry in the interrupt jump buffer contains
3564 <1> ; the following instructions:
3565 <1> ;
3566 <1> ; 00000000 60 pushad
3567 <1> ; 00000001 B0xx mov al,<interrupt#>
3568 <1> ; 00000003 E9xxxxxxxx jmp com32_handle_interrupt
3569 <1>
3570 00000F67 B860B000E9 <1> mov eax,0e900b060h
3571 00000F6C BB[1B08F0FF] <1> mov ebx,com32_handle_interrupt-(pm_idt+8*256+8)
3572 <1>
3573 <1> .make_ijb:
3574 00000F71 AB <1> stosd
3575 00000F72 284FFE <1> sub [edi-2],cl ; Interrupt #
3576 00000F75 93 <1> xchg eax,ebx
3577 00000F76 AB <1> stosd
3578 00000F77 83E808 <1> sub eax,8
3579 00000F7A 93 <1> xchg eax,ebx
3580 00000F7B E2F4 <1> loop .make_ijb
3581 <1>
3582 <1> ; Now everything is set up for interrupts...
3583 <1>
3584 00000F7D 68[36100000] <1> push dword com32_farcall ; Farcall entry point
3585 00000F82 6800000100 <1> push dword (1 << 16) ; 64K bounce buffer
3586 00000F87 6800000400 <1> push dword (comboot_seg << 4) ; Bounce buffer address
3587 00000F8C 68[3E100000] <1> push dword com32_intcall ; Intcall entry point
3588 00000F91 68[D4080000] <1> push dword command_line ; Command line pointer
3589 00000F96 6A05 <1> push dword 5 ; Argument count
3590 00000F98 FB <1> sti ; Interrupts OK now
3591 00000F99 E8(00101000) <1> call pm_entry ; Run the program...
3592 <1> ; ... on return, fall through to com32_exit ...
3593 <1>
3594 <1> com32_exit:
3595 00000F9E 66BB[E30F] <1> mov bx,com32_done ; Return to command loop
3596 <1>
3597 <1> com32_enter_rm:
3598 00000FA2 FA <1> cli
3599 00000FA3 FC <1> cld
3600 00000FA4 8925[A0080000] <1> mov [PMESP],esp ; Save exit %esp
3601 00000FAA 31E4 <1> xor esp,esp ; Make sure the high bits are zero
3602 00000FAC EA[B30F0000]0800 <1> jmp 08h:.in_pm16 ; Return to 16-bit mode first
3603 <1>
3604 <1> bits 16
3605 <1> .in_pm16:
3606 00000FB3 B81800 <1> mov ax,18h ; Real-mode-like segment
3607 00000FB6 8EC0 <1> mov es,ax
3608 00000FB8 8ED8 <1> mov ds,ax
3609 00000FBA 8ED0 <1> mov ss,ax
3610 00000FBC 8EE0 <1> mov fs,ax
3611 00000FBE 8EE8 <1> mov gs,ax
3612 <1>
3613 00000FC0 0F011E[B800] <1> lidt [com32_rmidt] ; Real-mode IDT (rm needs no GDT)
3614 00000FC5 0F20C0 <1> mov eax,cr0
3615 00000FC8 24FE <1> and al,~1
3616 00000FCA 0F22C0 <1> mov cr0,eax
3617 00000FCD EA[D20F]0000 <1> jmp 0:.in_rm
3618 <1>
3619 <1> .in_rm: ; Back in real mode
3620 00000FD2 8CC8 <1> mov ax,cs ; Set up sane segments
3621 00000FD4 8ED8 <1> mov ds,ax
3622 00000FD6 8EC0 <1> mov es,ax
3623 00000FD8 8EE0 <1> mov fs,ax
3624 00000FDA 8EE8 <1> mov gs,ax
3625 00000FDC 0FB226[6855] <1> lss sp,[SavedSSSP] ; Restore stack
3626 00000FE1 FFE3 <1> jmp bx ; Go to whereever we need to go...
3627 <1>
3628 <1> com32_done:
3629 00000FE3 E8(6D01) <1> call disable_a20
3630 00000FE6 FB <1> sti
3631 00000FE7 E9CAF4 <1> jmp enter_command
3632 <1>
3633 <1> ;
3634 <1> ; 16-bit support code
3635 <1> ;
3636 <1> bits 16
3637 <1>
3638 <1> ;
3639 <1> ; 16-bit interrupt-handling code
3640 <1> ;
3641 <1> com32_int_rm:
3642 00000FEA 9C <1> pushf ; Flags on stack
3643 00000FEB 0E <1> push cs ; Return segment
3644 00000FEC 68[F20F] <1> push word .cont ; Return address
3645 00000FEF 6652 <1> push dword edx ; Segment:offset of IVT entry
3646 00000FF1 CB <1> retf ; Invoke IVT routine
3647 <1> .cont: ; ... on resume ...
3648 00000FF2 66BB[34100000] <1> mov ebx,com32_int_resume
3649 00000FF8 E906FF <1> jmp com32_enter_pm ; Go back to PM
3650 <1>
3651 <1> ;
3652 <1> ; 16-bit system call handling code
3653 <1> ;
3654 <1> com32_sys_rm:
3655 00000FFB 0FA9 <1> pop gs
3656 00000FFD 0FA1 <1> pop fs
3657 00000FFF 07 <1> pop es
3658 00001000 1F <1> pop ds
3659 00001001 6661 <1> popad
3660 00001003 669D <1> popfd
3661 00001005 2E8926[A408] <1> mov [cs:Com32SysSP],sp
3662 0000100A CB <1> retf ; Invoke routine
3663 <1> .return:
3664 <1> ; We clean up SP here because we don't know if the
3665 <1> ; routine returned with RET, RETF or IRET
3666 0000100B 2E8B26[A408] <1> mov sp,[cs:Com32SysSP]
3667 00001010 669C <1> pushfd
3668 00001012 6660 <1> pushad
3669 00001014 1E <1> push ds
3670 00001015 06 <1> push es
3671 00001016 0FA0 <1> push fs
3672 00001018 0FA8 <1> push gs
3673 0000101A 66BB[8E100000] <1> mov ebx,com32_sys_resume
3674 00001020 E9DEFE <1> jmp com32_enter_pm
3675 <1>
3676 <1> ;
3677 <1> ; 32-bit support code
3678 <1> ;
3679 <1> bits 32
3680 <1>
3681 <1> ;
3682 <1> ; This is invoked on getting an interrupt in protected mode. At
3683 <1> ; this point, we need to context-switch to real mode and invoke
3684 <1> ; the interrupt routine.
3685 <1> ;
3686 <1> ; When this gets invoked, the registers are saved on the stack and
3687 <1> ; AL contains the register number.
3688 <1> ;
3689 <1> com32_handle_interrupt:
3690 00001023 0FB6C0 <1> movzx eax,al
3691 00001026 31DB <1> xor ebx,ebx ; Actually makes the code smaller
3692 00001028 8B1483 <1> mov edx,[ebx+eax*4] ; Get the segment:offset of the routine
3693 0000102B 66BB[EA0F] <1> mov bx,com32_int_rm
3694 0000102F E96EFFFFFF <1> jmp com32_enter_rm ; Go to real mode
3695 <1>
3696 <1> com32_int_resume:
3697 00001034 61 <1> popad
3698 00001035 CF <1> iret
3699 <1>
3700 <1> ;
3701 <1> ; Intcall/farcall invocation. We manifest a structure on the real-mode stack,
3702 <1> ; containing the com32sys_t structure from <com32.h> as well as
3703 <1> ; the following entries (from low to high address):
3704 <1> ; - Target offset
3705 <1> ; - Target segment
3706 <1> ; - Return offset
3707 <1> ; - Return segment (== real mode cs == 0)
3708 <1> ; - Return flags
3709 <1> ;
3710 <1> com32_farcall:
3711 00001036 9C <1> pushfd ; Save IF among other things...
3712 00001037 60 <1> pushad ; We only need to save some, but...
3713 <1>
3714 00001038 8B442428 <1> mov eax,[esp+10*4] ; CS:IP
3715 0000103C EB0E <1> jmp com32_syscall
3716 <1>
3717 <1>
3718 <1> com32_intcall:
3719 0000103E 9C <1> pushfd ; Save IF among other things...
3720 0000103F 60 <1> pushad ; We only need to save some, but...
3721 <1>
3722 00001040 0FB6442428 <1> movzx eax,byte [esp+10*4] ; INT number
3723 00001045 8B048500000000 <1> mov eax,[eax*4] ; Get CS:IP from low memory
3724 <1>
3725 <1> com32_syscall:
3726 0000104C FC <1> cld
3727 <1>
3728 0000104D 670FB73E[6855] <1> movzx edi,word [word SavedSSSP]
3729 00001053 670FB71E[6A55] <1> movzx ebx,word [word SavedSSSP+2]
3730 00001059 83EF36 <1> sub edi,54 ; Allocate 54 bytes
3731 0000105C 6667893E[6855] <1> mov [word SavedSSSP],di
3732 00001062 C1E304 <1> shl ebx,4
3733 00001065 01DF <1> add edi,ebx ; Create linear address
3734 <1>
3735 00001067 8B74242C <1> mov esi,[esp+11*4] ; Source regs
3736 0000106B 31C9 <1> xor ecx,ecx
3737 0000106D B10B <1> mov cl,11 ; 44 bytes to copy
3738 0000106F F3A5 <1> rep movsd
3739 <1>
3740 <1> ; EAX is already set up to be CS:IP
3741 00001071 AB <1> stosd ; Save in stack frame
3742 00001072 B8[0B100000] <1> mov eax,com32_sys_rm.return ; Return seg:offs
3743 00001077 AB <1> stosd ; Save in stack frame
3744 00001078 8B47F4 <1> mov eax,[edi-12] ; Return flags
3745 0000107B 25D70C2000 <1> and eax,0x200cd7 ; Mask (potentially) unsafe flags
3746 00001080 8947F4 <1> mov [edi-12],eax ; Primary flags entry
3747 00001083 66AB <1> stosw ; Return flags
3748 <1>
3749 00001085 66BB[FB0F] <1> mov bx,com32_sys_rm
3750 00001089 E914FFFFFF <1> jmp com32_enter_rm ; Go to real mode
3751 <1>
3752 <1> ; On return, the 44-byte return structure is on the
3753 <1> ; real-mode stack, plus the 10 additional bytes used
3754 <1> ; by the target address (see above.)
3755 <1> com32_sys_resume:
3756 0000108E 670FB736[6855] <1> movzx esi,word [word SavedSSSP]
3757 00001094 670FB706[6A55] <1> movzx eax,word [word SavedSSSP+2]
3758 0000109A 8B7C2430 <1> mov edi,[esp+12*4] ; Dest regs
3759 0000109E C1E004 <1> shl eax,4
3760 000010A1 01C6 <1> add esi,eax ; Create linear address
3761 000010A3 21FF <1> and edi,edi ; NULL pointer?
3762 000010A5 7502 <1> jnz .do_copy
3763 000010A7 89F7 <1> .no_copy: mov edi,esi ; Do a dummy copy-to-self
3764 000010A9 31C9 <1> .do_copy: xor ecx,ecx
3765 000010AB B10B <1> mov cl,11 ; 44 bytes
3766 000010AD F3A5 <1> rep movsd ; Copy register block
3767 <1>
3768 000010AF 678306[6855]36 <1> add dword [word SavedSSSP],54 ; Remove from stack
3769 <1>
3770 000010B5 61 <1> popad
3771 000010B6 9D <1> popfd
3772 000010B7 C3 <1> ret ; Return to 32-bit program
3773 <1>
3774 <1> bits 16
3775 <1>
3776 <1> section .bss
3777 0000089F <res 00000001> <1> alignb 4
3778 000008A0 <res 00000004> <1> PMESP resd 1 ; Protected-mode ESP
3779 000008A4 <res 00000002> <1> Com32SysSP resw 1 ; SP saved during COM32 syscall
3780 <1>
3781 <1> section .text
3782 %include "cmdline.inc"
3783 <1> ;; $Id: cmdline.inc,v 1.2 2004/12/14 22:46:24 hpa Exp $
3784 <1> ;; -----------------------------------------------------------------------
3785 <1> ;;
3786 <1> ;; Copyright 2003 H. Peter Anvin - All Rights Reserved
3787 <1> ;;
3788 <1> ;; This program is free software; you can redistribute it and/or modify
3789 <1> ;; it under the terms of the GNU General Public License as published by
3790 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
3791 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
3792 <1> ;; (at your option) any later version; incorporated herein by reference.
3793 <1> ;;
3794 <1> ;; -----------------------------------------------------------------------
3795 <1>
3796 <1> ;;
3797 <1> ;; cmdline.inc
3798 <1> ;;
3799 <1> ;; Common routine to assemble [null-terminated] command line into
3800 <1> ;; real_mode_seg:cmd_line_here.
3801 <1> ;; Not used by plain kernel due to BOOT_IMAGE= etc.
3802 <1> ;;
3803 <1>
3804 <1> ;
3805 <1> ; Assumes DS == CS
3806 <1> make_plain_cmdline:
3807 000010B8 06 <1> push es
3808 <1> ; ui.inc has already copied the actual command line
3809 000010B9 B80040 <1> mov ax,real_mode_seg
3810 000010BC 8EC0 <1> mov es,ax
3811 <1>
3812 000010BE 8B36[8208] <1> mov si,[CmdOptPtr]
3813 000010C2 8B3E[EE00] <1> mov di,[CmdLinePtr]
3814 <1>
3815 000010C6 AC <1> .loop: lodsb
3816 000010C7 AA <1> stosb
3817 000010C8 20C0 <1> and al,al
3818 000010CA 75FA <1> jnz .loop
3819 <1>
3820 000010CC 4F <1> dec di
3821 000010CD 893E[EE00] <1> mov [CmdLinePtr],di
3822 <1>
3823 000010D1 07 <1> pop es
3824 000010D2 C3 <1> ret
3825 <1>
3826 <1>
3827
3828 ;
3829 ; Boot sector loading code
3830 ;
3831 %include "bootsect.inc"
3832 <1> ;; $Id: bootsect.inc,v 1.15 2005/01/12 00:34:54 hpa Exp $
3833 <1> ;; -----------------------------------------------------------------------
3834 <1> ;;
3835 <1> ;; Copyright 1994-2005 H. Peter Anvin - All Rights Reserved
3836 <1> ;;
3837 <1> ;; This program is free software; you can redistribute it and/or modify
3838 <1> ;; it under the terms of the GNU General Public License as published by
3839 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
3840 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
3841 <1> ;; (at your option) any later version; incorporated herein by reference.
3842 <1> ;;
3843 <1> ;; -----------------------------------------------------------------------
3844 <1>
3845 <1> ;;
3846 <1> ;; bootsect.inc
3847 <1> ;;
3848 <1> ;; Load a boot sector (or other bootstrap program.)
3849 <1> ;;
3850 <1> ;; Unlike previous versions of this software, this doesn't require that
3851 <1> ;; the length is 512 bytes. This allows PXE bootstraps and WinNT
3852 <1> ;; "CD boot sectors" to be invoked.
3853 <1> ;;
3854 <1>
3855 <1> ;
3856 <1> ; Load a boot sector
3857 <1> ;
3858 <1> is_bootsector:
3859 <1> %if IS_SYSLINUX || IS_MDSLINUX
3860 <1> ; Transfer zero bytes
3861 <1> mov byte [CopySuper],0
3862 <1> jmp short load_bootsec
3863 <1>
3864 <1> is_bss_sector:
3865 <1> ; Transfer the superblock
3866 <1> mov byte [CopySuper],superblock_len
3867 <1> %endif
3868 <1> load_bootsec:
3869 000010D3 92 <1> xchg dx,ax
3870 000010D4 66C1E010 <1> shl eax,16
3871 000010D8 92 <1> xchg dx,ax ; Now EAX = file length
3872 000010D9 66BF00001000 <1> mov edi, 100000h
3873 000010DF 66893E[0400] <1> mov [trackbuf+4],edi ; Copy from this address
3874 000010E4 6657 <1> push edi ; Save load address
3875 000010E6 31D2 <1> xor dx,dx ; No padding
3876 000010E8 E8D010 <1> call load_high
3877 000010EB E8590D <1> call crlf
3878 <1>
3879 000010EE 6681EF00001000 <1> sub edi,100000h
3880 000010F5 66893E[0800] <1> mov [trackbuf+8],edi ; Save length
3881 <1>
3882 000010FA 66B8007C0000 <1> mov eax,7C00h ; Entry point
3883 00001100 66A3[0000] <1> mov [trackbuf],eax ; Copy to this address
3884 00001104 66A3[6455] <1> mov [EntryPoint],eax ; Jump to this address when done
3885 <1>
3886 <1> %if IS_SYSLINUX || IS_MDSLINUX
3887 <1> movzx ecx,byte [CopySuper]
3888 <1> jcxz .not_bss
3889 <1>
3890 <1> ; For a BSS boot sector we have to patch.
3891 <1> mov esi,superblock
3892 <1> mov edi,100000h+(superblock-bootsec)
3893 <1> call bcopy
3894 <1>
3895 <1> .not_bss:
3896 <1> %endif
3897 <1>
3898 00001108 6631D2 <1> xor edx,edx
3899 0000110B 6631F6 <1> xor esi,esi
3900 <1> %if IS_SYSLINUX || IS_MDSLINUX || IS_EXTLINUX
3901 <1> ; Restore original FDC table
3902 <1> mov eax,[OrigFDCTabPtr]
3903 <1> mov [fdctab],eax
3904 <1>
3905 <1> mov dl,[DriveNumber]
3906 <1> mov si,PartInfo ; Partition info buffer
3907 <1> mov di,800h-18 ; Put partition info here
3908 <1> push di
3909 <1> mov cx,8 ; 16 bytes
3910 <1> xor ax,ax
3911 <1> rep movsw
3912 <1> pop si ; DS:SI points to partition info
3913 <1> %elif IS_ISOLINUX
3914 <1> mov dl,[DriveNo]
3915 <1> %elif IS_PXELINUX
3916 0000110E C606[A608]01 <1> mov byte [KeepPXE],1 ; Chainloading another NBP
3917 00001113 E8CF06 <1> call reset_pxe
3918 <1> %endif
3919 00001116 31DB <1> xor bx,bx
3920 <1>
3921 <1> ;
3922 <1> ; replace_bootstrap for the special case where we have exactly one
3923 <1> ; descriptor, and it's the first entry in the trackbuf
3924 <1> ;
3925 <1>
3926 <1> replace_bootstrap_one:
3927 00001118 68[0000] <1> push word trackbuf ; Address of descriptor list
3928 0000111B 6A01 <1> push word 1 ; Length of descriptor list
3929 <1> ; Fall through
3930 <1>
3931 <1> ;
3932 <1> ; Entrypoint for "shut down and replace bootstrap" -- also invoked by
3933 <1> ; the COMBOOT API. This routine expects two words on the stack:
3934 <1> ; address of the copy list (versus DS) and count. Additionally,
3935 <1> ; the values of ESI and EDX are passed on to the new bootstrap;
3936 <1> ; the value of BX becomes the new DS.
3937 <1> ;
3938 <1> replace_bootstrap:
3939 <1> ;
3940 <1> ; Prepare for shutting down
3941 <1> ;
3942 0000111D E82513 <1> call vgaclearmode
3943 <1>
3944 <1> ;
3945 <1> ; Set up initial stack frame (not used by PXE if keeppxe is
3946 <1> ; set - we use the PXE stack then.)
3947 <1> ; AFTER THIS POINT ONLY .earlybss IS AVAILABLE, NOT .bss
3948 <1> ;
3949 00001120 31C0 <1> xor ax,ax
3950 00001122 8ED8 <1> mov ds,ax
3951 00001124 8EC0 <1> mov es,ax
3952 <1>
3953 <1> %if IS_PXELINUX
3954 00001126 F606[A608]01 <1> test byte [KeepPXE],01h
3955 0000112B 7406 <1> jz .stdstack
3956 0000112D C43E[6047] <1> les di,[InitStack] ; Reset stack to PXE original
3957 00001131 EB0A <1> jmp .stackok
3958 <1> %endif
3959 <1> .stdstack:
3960 00001133 BFD47B <1> mov di,7C00h-44
3961 00001136 57 <1> push di
3962 00001137 B91600 <1> mov cx,22 ; 44 bytes
3963 0000113A F3AB <1> rep stosw
3964 0000113C 5F <1> pop di
3965 <1> .stackok:
3966 <1>
3967 0000113D 266689551C <1> mov [es:di+28],edx
3968 00001142 266689750C <1> mov [es:di+12],esi
3969 00001147 26895D06 <1> mov [es:di+6],bx
3970 <1>
3971 0000114B 58 <1> pop ax ; Copy list count
3972 0000114C 5B <1> pop bx ; Copy from...
3973 <1>
3974 0000114D FA <1> cli
3975 0000114E 8CC1 <1> mov cx,es
3976 00001150 8ED1 <1> mov ss,cx
3977 00001152 660FB7E7 <1> movzx esp,di
3978 <1>
3979 00001156 E9(CD01) <1> jmp shuffle_and_boot
3980 <1>
3981 <1> %if IS_SYSLINUX || IS_MDSLINUX
3982 <1> ; Nothing
3983 <1> %else
3984 <1> is_bss_sector:
3985 00001159 BE[BB03] <1> mov si,err_bssimage
3986 0000115C E8F50C <1> call cwritestr
3987 0000115F E952F3 <1> jmp enter_command
3988 <1> %endif
3989
3990 ;
3991 ; Boot to the local disk by returning the appropriate PXE magic.
3992 ; AX contains the appropriate return code.
3993 ;
3994 local_boot:
3995 00001162 8CCE mov si,cs
3996 00001164 8EDE mov ds,si ; Restore DI
3997 00001166 660FB226[A008] lss esp,[BaseStack]
3998 0000116C A3[0E00] mov [LocalBootType],ax
3999 0000116F E8D312 call vgaclearmode
4000 00001172 BE[7C06] mov si,localboot_msg
4001 00001175 E8DC0C call writestr
4002 ; Restore the environment we were called with
4003 00001178 0FB226[6047] lss sp,[InitStack]
4004 0000117D 0FA9 pop gs
4005 0000117F 0FA1 pop fs
4006 00001181 07 pop es
4007 00001182 1F pop ds
4008 00001183 6661 popad
4009 00001185 2EA1[0E00] mov ax,[cs:LocalBootType]
4010 00001189 669D popfd
4011 0000118B CB retf ; Return to PXE
4012
4013 ;
4014 ; abort_check: let the user abort with <ESC> or <Ctrl-C>
4015 ;
4016 abort_check:
4017 0000118C E84D0C call pollchar
4018 0000118F 7423 jz ac_ret1
4019 00001191 60 pusha
4020 00001192 E8710C call getchar
4021 00001195 3C1B cmp al,27 ; <ESC>
4022 00001197 7404 je ac_kill
4023 00001199 3C03 cmp al,3 ; <Ctrl-C>
4024 0000119B 7516 jne ac_ret2
4025 0000119D BE[D706] ac_kill: mov si,aborted_msg
4026
4027 ;
4028 ; abort_load: Called by various routines which wants to print a fatal
4029 ; error message and return to the command prompt. Since this
4030 ; may happen at just about any stage of the boot process, assume
4031 ; our state is messed up, and just reset the segment registers
4032 ; and the stack forcibly.
4033 ;
4034 ; SI = offset (in _text) of error message to print
4035 ;
4036 abort_load:
4037 000011A0 8CC8 mov ax,cs ; Restore CS = DS = ES
4038 000011A2 8ED8 mov ds,ax
4039 000011A4 8EC0 mov es,ax
4040 000011A6 660FB226[A008] lss esp,[BaseStack]
4041 000011AC FB sti
4042 000011AD E8A40C call cwritestr ; Expects SI -> error msg
4043 000011B0 E901F3 al_ok: jmp enter_command ; Return to command prompt
4044 ;
4045 ; End of abort_check
4046 ;
4047 000011B3 61 ac_ret2: popa
4048 000011B4 C3 ac_ret1: ret
4049
4050
4051 ;
4052 ; kaboom: write a message and bail out. Wait for quite a while,
4053 ; or a user keypress, then do a hard reboot.
4054 ;
4055 kaboom:
4056 000011B5 8CC8 mov ax,cs
4057 000011B7 8EC0 mov es,ax
4058 000011B9 8ED8 mov ds,ax
4059 000011BB 660FB226[A008] lss esp,[BaseStack]
4060 000011C1 FB sti
4061 000011C2 BE[F403] .patch: mov si,bailmsg
4062 000011C5 E88C0C call writestr ; Returns with AL = 0
4063 000011C8 E8110C .drain: call pollchar
4064 000011CB 7405 jz .drained
4065 000011CD E8360C call getchar
4066 000011D0 EBF6 jmp short .drain
4067 .drained:
4068 000011D2 668B3E[0000] mov edi,[RebootTime]
4069 000011D7 A0[0909] mov al,[DHCPMagic]
4070 000011DA 2409 and al,09h ; Magic+Timeout
4071 000011DC 3C09 cmp al,09h
4072 000011DE 7406 je .time_set
4073 000011E0 66BF2C010000 mov edi,REBOOT_TIME
4074 .time_set:
4075 000011E6 B91200 mov cx,18
4076 000011E9 51 .wait1: push cx
4077 000011EA 6689F9 mov ecx,edi
4078 000011ED 8B166C04 .wait2: mov dx,[BIOS_timer]
4079 000011F1 E8E80B .wait3: call pollchar
4080 000011F4 7511 jnz .keypress
4081 000011F6 3B166C04 cmp dx,[BIOS_timer]
4082 000011FA 74F5 je .wait3
4083 000011FC 67E2EE loop .wait2,ecx
4084 000011FF B02E mov al,'.'
4085 00001201 E88113 call writechr
4086 00001204 59 pop cx
4087 00001205 E2E2 loop .wait1
4088 .keypress:
4089 00001207 E83D0C call crlf
4090 0000120A C70672040000 mov word [BIOS_magic],0 ; Cold reboot
4091 00001210 EAF0FF00F0 jmp 0F000h:0FFF0h ; Reset vector address
4092
4093 ;
4094 ; memory_scan_for_pxe_struct:
4095 ;
4096 ; If none of the standard methods find the !PXE structure, look for it
4097 ; by scanning memory.
4098 ;
4099 ; On exit, if found:
4100 ; CF = 0, ES:BX -> !PXE structure
4101 ; Otherwise CF = 1, all registers saved
4102 ;
4103 memory_scan_for_pxe_struct:
4104 00001215 1E push ds
4105 00001216 60 pusha
4106 00001217 8CC8 mov ax,cs
4107 00001219 8ED8 mov ds,ax
4108 0000121B BE[7005] mov si,trymempxe_msg
4109 0000121E E8330C call writestr
4110 00001221 A11304 mov ax,[BIOS_fbm] ; Starting segment
4111 00001224 C1E006 shl ax,(10-4) ; Kilobytes -> paragraphs
4112 ; mov ax,01000h ; Start to look here
4113 00001227 48 dec ax ; To skip inc ax
4114 .mismatch:
4115 00001228 40 inc ax
4116 00001229 3D00A0 cmp ax,0A000h ; End of memory
4117 0000122C 7346 jae .not_found
4118 0000122E E8430C call writehex4
4119 00001231 BE[D206] mov si,fourbs_msg
4120 00001234 E81D0C call writestr
4121 00001237 8EC0 mov es,ax
4122 00001239 26668B160000 mov edx,[es:0]
4123 0000123F 6681FA21505845 cmp edx,'!PXE'
4124 00001246 75E0 jne .mismatch
4125 00001248 260FB60E0400 movzx cx,byte [es:4] ; Length of structure
4126 0000124E 80F908 cmp cl,08h ; Minimum length
4127 00001251 72D5 jb .mismatch
4128 00001253 50 push ax
4129 00001254 31C0 xor ax,ax
4130 00001256 31F6 xor si,si
4131 00001258 26AC .checksum: es lodsb
4132 0000125A 00C4 add ah,al
4133 0000125C E2FA loop .checksum
4134 0000125E 58 pop ax
4135 0000125F 75C7 jnz .mismatch ; Checksum must == 0
4136 00001261 89E5 .found: mov bp,sp
4137 00001263 31DB xor bx,bx
4138 00001265 895E08 mov [bp+8],bx ; Save BX into stack frame (will be == 0)
4139 00001268 8CC0 mov ax,es
4140 0000126A E8070C call writehex4
4141 0000126D E8D70B call crlf
4142 00001270 61 popa
4143 00001271 1F pop ds
4144 00001272 F8 clc
4145 00001273 C3 ret
4146 00001274 BE[4706] .not_found: mov si,notfound_msg
4147 00001277 E8DA0B call writestr
4148 0000127A 61 popa
4149 0000127B 1F pop ds
4150 0000127C F9 stc
4151 0000127D C3 ret
4152
4153 ;
4154 ; memory_scan_for_pxenv_struct:
4155 ;
4156 ; If none of the standard methods find the PXENV+ structure, look for it
4157 ; by scanning memory.
4158 ;
4159 ; On exit, if found:
4160 ; CF = 0, ES:BX -> PXENV+ structure
4161 ; Otherwise CF = 1, all registers saved
4162 ;
4163 memory_scan_for_pxenv_struct:
4164 0000127E 60 pusha
4165 0000127F BE[9705] mov si,trymempxenv_msg
4166 00001282 E8CF0B call writestr
4167 ; mov ax,[BIOS_fbm] ; Starting segment
4168 ; shl ax,(10-4) ; Kilobytes -> paragraphs
4169 00001285 B80010 mov ax,01000h ; Start to look here
4170 00001288 48 dec ax ; To skip inc ax
4171 .mismatch:
4172 00001289 40 inc ax
4173 0000128A 3D00A0 cmp ax,0A000h ; End of memory
4174 0000128D 7344 jae .not_found
4175 0000128F 8EC0 mov es,ax
4176 00001291 26668B160000 mov edx,[es:0]
4177 00001297 6681FA5058454E cmp edx,'PXEN'
4178 0000129E 75E9 jne .mismatch
4179 000012A0 268B160400 mov dx,[es:4]
4180 000012A5 81FA562B cmp dx,'V+'
4181 000012A9 75DE jne .mismatch
4182 000012AB 260FB60E0800 movzx cx,byte [es:8] ; Length of structure
4183 000012B1 80F926 cmp cl,26h ; Minimum length
4184 000012B4 72D3 jb .mismatch
4185 000012B6 31C0 xor ax,ax
4186 000012B8 31F6 xor si,si
4187 000012BA 26AC .checksum: es lodsb
4188 000012BC 00C4 add ah,al
4189 000012BE E2FA loop .checksum
4190 000012C0 20E4 and ah,ah
4191 000012C2 75C5 jnz .mismatch ; Checksum must == 0
4192 000012C4 89E5 .found: mov bp,sp
4193 000012C6 895E08 mov [bp+8],bx ; Save BX into stack frame
4194 000012C9 89D8 mov ax,bx
4195 000012CB E8A60B call writehex4
4196 000012CE E8760B call crlf
4197 000012D1 F8 clc
4198 000012D2 C3 ret
4199 000012D3 BE[4706] .not_found: mov si,notfound_msg
4200 000012D6 E87B0B call writestr
4201 000012D9 6661 popad
4202 000012DB F9 stc
4203 000012DC C3 ret
4204
4205 ;
4206 ; searchdir:
4207 ;
4208 ; Open a TFTP connection to the server
4209 ;
4210 ; On entry:
4211 ; DS:DI = mangled filename
4212 ; If successful:
4213 ; ZF clear
4214 ; SI = socket pointer
4215 ; DX:AX = file length in bytes
4216 ; If unsuccessful
4217 ; ZF set
4218 ;
4219
4220 searchdir:
4221 000012DD 06 push es
4222 000012DE 8CD8 mov ax,ds
4223 000012E0 8EC0 mov es,ax
4224 000012E2 89FE mov si,di
4225 000012E4 55 push bp
4226 000012E5 89E5 mov bp,sp
4227
4228 000012E7 E8DB01 call allocate_socket
4229 000012EA 0F84CF01 jz .error
4230
4231 000012EE B80600 mov ax,PKT_RETRY ; Retry counter
4232 000012F1 C706[1000]0C00 mov word [PktTimeout],PKT_TIMEOUT ; Initial timeout
4233
4234 000012F7 50 .sendreq: push ax ; [bp-2] - Retry counter
4235 000012F8 56 push si ; [bp-4] - File name
4236
4237 000012F9 BF[8000] mov di,packet_buf
4238 000012FC 893E[8608] mov [pxe_udp_write_pkt.buffer],di
4239
4240 00001300 B80001 mov ax,TFTP_RRQ ; TFTP opcode
4241 00001303 AB stosw
4242
4243 00001304 66AD lodsd ; EAX <- server override (if any)
4244 00001306 6621C0 and eax,eax
4245 00001309 750D jnz .noprefix ; No prefix, and we have the server
4246
4247 0000130B 56 push si ; Add common prefix
4248 0000130C BE[0046] mov si,PathPrefix
4249 0000130F E86A12 call strcpy
4250 00001312 4F dec di
4251 00001313 5E pop si
4252
4253 00001314 66A1[F008] mov eax,[ServerIP] ; Get default server
4254
4255 .noprefix:
4256 00001318 E86112 call strcpy ; Filename
4257
4258 0000131B 66894704 mov [bx+tftp_remoteip],eax
4259
4260 0000131F 53 push bx ; [bp-6] - TFTP block
4261 00001320 8B1F mov bx,[bx]
4262 00001322 53 push bx ; [bp-8] - TID (local port no)
4263
4264 00001323 C606[7608]00 mov [pxe_udp_write_pkt.status],byte 0
4265 00001328 66A3[7808] mov [pxe_udp_write_pkt.sip],eax
4266 ; Now figure out the gateway
4267 0000132C 663306[EC08] xor eax,[MyIP]
4268 00001331 662306[F408] and eax,[Netmask]
4269 00001336 7404 jz .nogwneeded
4270 00001338 66A1[F808] mov eax,[Gateway]
4271 .nogwneeded:
4272 0000133C 66A3[7C08] mov [pxe_udp_write_pkt.gip],eax
4273 00001340 891E[8008] mov [pxe_udp_write_pkt.lport],bx
4274 00001344 A1[FC08] mov ax,[ServerPort]
4275 00001347 A3[8208] mov [pxe_udp_write_pkt.rport],ax
4276 0000134A BE[A708] mov si,tftp_tail
4277 0000134D B91B00 mov cx,tftp_tail_len
4278 00001350 F3A4 rep movsb
4279 00001352 81EF[8000] sub di,packet_buf ; Get packet size
4280 00001356 893E[8408] mov [pxe_udp_write_pkt.buffersize],di
4281
4282 0000135A BF[7608] mov di,pxe_udp_write_pkt
4283 0000135D BB3300 mov bx,PXENV_UDP_WRITE
4284 00001360 E84402 call pxenv
4285 00001363 0F824D01 jc .failure
4286 00001367 833E[7608]00 cmp word [pxe_udp_write_pkt.status],byte 0
4287 0000136C 0F854401 jne .failure
4288
4289 ;
4290 ; Danger, Will Robinson! We need to support timeout
4291 ; and retry lest we just lost a packet...
4292 ;
4293
4294 ; Packet transmitted OK, now we need to receive
4295 00001370 FF36[1000] .getpacket: push word [PktTimeout] ; [bp-10]
4296 00001374 FF366C04 push word [BIOS_timer] ; [bp-12]
4297
4298 00001378 8B5EF8 .pkt_loop: mov bx,[bp-8] ; TID
4299 0000137B BF[8000] mov di,packet_buf
4300 0000137E C706[8A08]0000 mov word [pxe_udp_read_pkt.status],0
4301 00001384 893E[9A08] mov [pxe_udp_read_pkt.buffer],di
4302 00001388 8C1E[9C08] mov [pxe_udp_read_pkt.buffer+2],ds
4303 0000138C C706[9808]0008 mov word [pxe_udp_read_pkt.buffersize],packet_buf_size
4304 00001392 66A1[EC08] mov eax,[MyIP]
4305 00001396 66A3[9008] mov [pxe_udp_read_pkt.dip],eax
4306 0000139A 891E[9608] mov [pxe_udp_read_pkt.lport],bx
4307 0000139E BF[8A08] mov di,pxe_udp_read_pkt
4308 000013A1 BB3200 mov bx,PXENV_UDP_READ
4309 000013A4 E80002 call pxenv
4310 000013A7 21C0 and ax,ax
4311 000013A9 741A jz .got_packet ; Wait for packet
4312 .no_packet:
4313 000013AB 8B166C04 mov dx,[BIOS_timer]
4314 000013AF 3B56F4 cmp dx,[bp-12]
4315 000013B2 74C4 je .pkt_loop
4316 000013B4 8956F4 mov [bp-12],dx
4317 000013B7 FF4EF6 dec word [bp-10] ; Timeout
4318 000013BA 75BC jnz .pkt_loop
4319 000013BC 58 pop ax ; Adjust stack
4320 000013BD 58 pop ax
4321 000013BE D126[1000] shl word [PktTimeout],1 ; Exponential backoff
4322 000013C2 E9EF00 jmp .failure
4323
4324 .got_packet:
4325 000013C5 8B76FA mov si,[bp-6] ; TFTP pointer
4326 000013C8 8B5EF8 mov bx,[bp-8] ; TID
4327
4328 000013CB 668B4404 mov eax,[si+tftp_remoteip]
4329 000013CF 663906[8C08] cmp [pxe_udp_read_pkt.sip],eax ; This is technically not to the TFTP spec?
4330 000013D4 75D5 jne .no_packet
4331
4332 ; Got packet - reset timeout
4333 000013D6 C706[1000]0C00 mov word [PktTimeout],PKT_TIMEOUT
4334
4335 000013DC 58 pop ax ; Adjust stack
4336 000013DD 58 pop ax
4337
4338 000013DE A1[9408] mov ax,[pxe_udp_read_pkt.rport]
4339 000013E1 894402 mov [si+tftp_remoteport],ax
4340
4341 ; filesize <- -1 == unknown
4342 000013E4 66C7440CFFFFFFFF mov dword [si+tftp_filesize], -1
4343 ; Default blksize unless blksize option negotiated
4344 000013EC C744100002 mov word [si+tftp_blksize], TFTP_BLOCKSIZE
4345
4346 000013F1 8B0E[9808] mov cx,[pxe_udp_read_pkt.buffersize]
4347 000013F5 83E902 sub cx,2 ; CX <- bytes after opcode
4348 000013F8 0F82B800 jb .failure ; Garbled reply
4349
4350 000013FC BE[8000] mov si,packet_buf
4351 000013FF AD lodsw
4352
4353 00001400 3D0005 cmp ax, TFTP_ERROR
4354 00001403 0F84A800 je .bailnow ; ERROR reply: don't try again
4355
4356 00001407 3D0006 cmp ax, TFTP_OACK
4357 0000140A 757C jne .no_tsize
4358
4359 ; Now we need to parse the OACK packet to get the transfer
4360 ; size. SI -> first byte of options; CX -> byte count
4361 .parse_oack:
4362 0000140C E37A jcxz .no_tsize ; No options acked
4363 .get_opt_name:
4364 0000140E 89F7 mov di,si
4365 00001410 89F3 mov bx,si
4366 00001412 AC .opt_name_loop: lodsb
4367 00001413 20C0 and al,al
4368 00001415 7407 jz .got_opt_name
4369 00001417 0C20 or al,20h ; Convert to lowercase
4370 00001419 AA stosb
4371 0000141A E2F6 loop .opt_name_loop
4372 ; We ran out, and no final null
4373 0000141C EB6A jmp .err_reply
4374 .got_opt_name: ; si -> option value
4375 0000141E 49 dec cx ; bytes left in pkt
4376 0000141F 7467 jz .err_reply ; Option w/o value
4377
4378 ; Parse option pointed to by bx; guaranteed to be
4379 ; null-terminated.
4380 00001421 51 push cx
4381 00001422 56 push si
4382 00001423 89DE mov si,bx ; -> option name
4383 00001425 BB[C208] mov bx,tftp_opt_table
4384 00001428 B90200 mov cx,tftp_opts
4385 .opt_loop:
4386 0000142B 51 push cx
4387 0000142C 56 push si
4388 0000142D 8B3F mov di,[bx] ; Option pointer
4389 0000142F 8B4F02 mov cx,[bx+2] ; Option len
4390 00001432 F3A6 repe cmpsb
4391 00001434 5E pop si
4392 00001435 59 pop cx
4393 00001436 7409 je .get_value ; OK, known option
4394 00001438 83C306 add bx,6
4395 0000143B E2EE loop .opt_loop
4396
4397 0000143D 5E pop si
4398 0000143E 59 pop cx
4399 0000143F EB47 jmp .err_reply ; Non-negotiated option returned
4400
4401 00001441 5E .get_value: pop si ; si -> option value
4402 00001442 59 pop cx ; cx -> bytes left in pkt
4403 00001443 8B5F04 mov bx,[bx+4] ; Pointer to data target
4404 00001446 035EFA add bx,[bp-6] ; TFTP socket pointer
4405 00001449 6631C0 xor eax,eax
4406 0000144C 6631D2 xor edx,edx
4407 0000144F AC .value_loop: lodsb
4408 00001450 20C0 and al,al
4409 00001452 7414 jz .got_value
4410 00001454 2C30 sub al,'0'
4411 00001456 3C09 cmp al, 9
4412 00001458 772E ja .err_reply ; Not a decimal digit
4413 0000145A 666BD20A imul edx,10
4414 0000145E 6601C2 add edx,eax
4415 00001461 668917 mov [bx],edx
4416 00001464 E2E9 loop .value_loop
4417 ; Ran out before final null, accept anyway
4418 00001466 EB03 jmp short .done_pkt
4419
4420 .got_value:
4421 00001468 49 dec cx
4422 00001469 75A3 jnz .get_opt_name ; Not end of packet
4423
4424 ; ZF == 1
4425
4426 ; Success, done!
4427 .done_pkt:
4428 0000146B 5E pop si ; Junk
4429 0000146C 5E pop si ; We want the packet ptr in SI
4430
4431 0000146D 668B440C mov eax,[si+tftp_filesize]
4432 00001471 6683F8FF cmp eax,-1
4433 00001475 7411 jz .no_tsize
4434 00001477 6689C2 mov edx,eax
4435 0000147A 66C1EA10 shr edx,16 ; DX:AX == EAX
4436
4437 0000147E 6621C0 and eax,eax ; Set ZF depending on file size
4438 00001481 5D pop bp ; Junk
4439 00001482 5D pop bp ; Junk (retry counter)
4440 00001483 743A jz .error_si ; ZF = 1 need to free the socket
4441 00001485 5D pop bp
4442 00001486 07 pop es
4443 00001487 C3 ret
4444
4445 .no_tsize:
4446 .err_reply: ; Option negotiation error. Send ERROR reply.
4447 ; ServerIP and gateway are already programmed in
4448 00001488 8B76FA mov si,[bp-6]
4449 0000148B 8B4402 mov ax,[si+tftp_remoteport]
4450 0000148E A3[8208] mov word [pxe_udp_write_pkt.rport],ax
4451 00001491 C706[8608][CE08] mov word [pxe_udp_write_pkt.buffer],tftp_opt_err
4452 00001497 C706[8408]1A00 mov word [pxe_udp_write_pkt.buffersize],tftp_opt_err_len
4453 0000149D BF[7608] mov di,pxe_udp_write_pkt
4454 000014A0 BB3300 mov bx,PXENV_UDP_WRITE
4455 000014A3 E80101 call pxenv
4456
4457 ; Write an error message and explode
4458 000014A6 BE[9A04] mov si,err_oldtftp
4459 000014A9 E8A809 call writestr
4460 000014AC E906FD jmp kaboom
4461
4462 000014AF C746FE0100 .bailnow: mov word [bp-2],1 ; Immediate error - no retry
4463
4464 000014B4 5B .failure: pop bx ; Junk
4465 000014B5 5B pop bx
4466 000014B6 5E pop si
4467 000014B7 58 pop ax
4468 000014B8 48 dec ax ; Retry counter
4469 000014B9 0F853AFE jnz .sendreq ; Try again
4470
4471 000014BD 89DE .error: mov si,bx ; Socket pointer
4472 .error_si: ; Socket pointer already in SI
4473 000014BF E83000 call free_socket ; ZF <- 1, SI <- 0
4474 000014C2 5D pop bp
4475 000014C3 07 pop es
4476 000014C4 C3 ret
4477
4478 ;
4479 ; allocate_socket: Allocate a local UDP port structure
4480 ;
4481 ; If successful:
4482 ; ZF set
4483 ; BX = socket pointer
4484 ; If unsuccessful:
4485 ; ZF clear
4486 ;
4487 allocate_socket:
4488 000014C5 51 push cx
4489 000014C6 BB[0040] mov bx,Files
4490 000014C9 B92000 mov cx,MAX_OPEN
4491 000014CC 833F00 .check: cmp word [bx], byte 0
4492 000014CF 7409 je .found
4493 000014D1 83C320 add bx,open_file_t_size
4494 000014D4 E2F6 loop .check
4495 000014D6 31C9 xor cx,cx ; ZF = 1
4496 000014D8 59 pop cx
4497 000014D9 C3 ret
4498 ; Allocate a socket number. Socket numbers are made
4499 ; guaranteed unique by including the socket slot number
4500 ; (inverted, because we use the loop counter cx); add a
4501 ; counter value to keep the numbers from being likely to
4502 ; get immediately reused.
4503 ;
4504 ; The NextSocket variable also contains the top two bits
4505 ; set. This generates a value in the range 49152 to
4506 ; 57343.
4507 .found:
4508 000014DA 49 dec cx
4509 000014DB 50 push ax
4510 000014DC A1[A408] mov ax,[NextSocket]
4511 000014DF 40 inc ax
4512 000014E0 25FFC0 and ax,((1 << (13-MAX_OPEN_LG2))-1) | 0xC000
4513 000014E3 A3[A408] mov [NextSocket],ax
4514 000014E6 C1E108 shl cx,13-MAX_OPEN_LG2
4515 000014E9 01C1 add cx,ax ; ZF = 0
4516 000014EB 86E9 xchg ch,cl ; Convert to network byte order
4517 000014ED 890F mov [bx],cx ; Socket in use
4518 000014EF 58 pop ax
4519 000014F0 59 pop cx
4520 000014F1 C3 ret
4521
4522 ;
4523 ; Free socket: socket in SI; return SI = 0, ZF = 1 for convenience
4524 ;
4525 free_socket:
4526 000014F2 06 push es
4527 000014F3 60 pusha
4528 000014F4 31C0 xor ax,ax
4529 000014F6 8EC0 mov es,ax
4530 000014F8 89F7 mov di,si
4531 000014FA B90F00 mov cx,tftp_pktbuf >> 1 ; tftp_pktbuf is not cleared
4532 000014FD F3AB rep stosw
4533 000014FF 61 popa
4534 00001500 07 pop es
4535 00001501 31F6 xor si,si
4536 00001503 C3 ret
4537
4538 ;
4539 ; parse_dotquad:
4540 ; Read a dot-quad pathname in DS:SI and output an IP
4541 ; address in EAX, with SI pointing to the first
4542 ; nonmatching character.
4543 ;
4544 ; Return CF=1 on error.
4545 ;
4546 parse_dotquad:
4547 00001504 51 push cx
4548 00001505 B90400 mov cx,4
4549 00001508 6631C0 xor eax,eax
4550 .parseloop:
4551 0000150B 88E5 mov ch,ah
4552 0000150D 88C4 mov ah,al
4553 0000150F AC lodsb
4554 00001510 2C30 sub al,'0'
4555 00001512 720A jb .notnumeric
4556 00001514 3C09 cmp al,9
4557 00001516 7706 ja .notnumeric
4558 00001518 D50A aad ; AL += 10 * AH; AH = 0;
4559 0000151A 86E5 xchg ah,ch
4560 0000151C EBED jmp .parseloop
4561 .notnumeric:
4562 0000151E 3CFE cmp al,'.'-'0'
4563 00001520 9C pushf
4564 00001521 88E0 mov al,ah
4565 00001523 88EC mov ah,ch
4566 00001525 30ED xor ch,ch
4567 00001527 66C1C808 ror eax,8
4568 0000152B 9D popf
4569 0000152C 7504 jne .error
4570 0000152E E2DB loop .parseloop
4571 00001530 EB06 jmp .done
4572 .error:
4573 00001532 E203 loop .realerror ; If CX := 1 then we're done
4574 00001534 F8 clc
4575 00001535 EB01 jmp .done
4576 .realerror:
4577 00001537 F9 stc
4578 .done:
4579 00001538 4E dec si ; CF unchanged!
4580 00001539 59 pop cx
4581 0000153A C3 ret
4582 ;
4583 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
4584 ; to by ES:DI; ends on encountering any whitespace.
4585 ;
4586 ; This verifies that a filename is < FILENAME_MAX characters
4587 ; and doesn't contain whitespace, and zero-pads the output buffer,
4588 ; so "repe cmpsb" can do a compare.
4589 ;
4590 ; The first four bytes of the manged name is the IP address of
4591 ; the download host.
4592 ;
4593 mangle_name:
4594 0000153B 56 push si
4595 0000153C 66A1[F008] mov eax,[ServerIP]
4596 00001540 803C00 cmp byte [si],0
4597 00001543 742F je .noip ; Null filename?!?!
4598 00001545 813C3A3A cmp word [si],'::' ; Leading ::?
4599 00001549 742F je .gotprefix
4600
4601 .more:
4602 0000154B 46 inc si
4603 0000154C 803C00 cmp byte [si],0
4604 0000154F 7423 je .noip
4605 00001551 813C3A3A cmp word [si],'::'
4606 00001555 75F4 jne .more
4607
4608 ; We have a :: prefix of some sort, it could be either
4609 ; a DNS name or a dot-quad IP address. Try the dot-quad
4610 ; first...
4611 .here:
4612 00001557 5E pop si
4613 00001558 56 push si
4614 00001559 E8A8FF call parse_dotquad
4615 0000155C 7206 jc .notdq
4616 0000155E 813C3A3A cmp word [si],'::'
4617 00001562 7416 je .gotprefix
4618 .notdq:
4619 00001564 5E pop si
4620 00001565 56 push si
4621 00001566 E8E610 call dns_resolv
4622 00001569 813C3A3A cmp word [si],'::'
4623 0000156D 7505 jne .noip
4624 0000156F 6621C0 and eax,eax
4625 00001572 7506 jnz .gotprefix
4626
4627 .noip:
4628 00001574 5E pop si
4629 00001575 6631C0 xor eax,eax
4630 00001578 EB03 jmp .prefix_done
4631
4632 .gotprefix:
4633 0000157A 59 pop cx ; Adjust stack
4634 0000157B 46 inc si ; Skip double colon
4635 0000157C 46 inc si
4636
4637 .prefix_done:
4638 0000157D 66AB stosd ; Save IP address prefix
4639 0000157F B97B00 mov cx,FILENAME_MAX-5
4640
4641 .mn_loop:
4642 00001582 AC lodsb
4643 00001583 3C20 cmp al,' ' ; If control or space, end
4644 00001585 7603 jna .mn_end
4645 00001587 AA stosb
4646 00001588 E2F8 loop .mn_loop
4647 .mn_end:
4648 0000158A 41 inc cx ; At least one null byte
4649 0000158B 31C0 xor ax,ax ; Zero-fill name
4650 0000158D F3AA rep stosb ; Doesn't do anything if CX=0
4651 0000158F C3 ret ; Done
4652
4653 ;
4654 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
4655 ; filename to the conventional representation. This is needed
4656 ; for the BOOT_IMAGE= parameter for the kernel.
4657 ; NOTE: A 13-byte buffer is mandatory, even if the string is
4658 ; known to be shorter.
4659 ;
4660 ; DS:SI -> input mangled file name
4661 ; ES:DI -> output buffer
4662 ;
4663 ; On return, DI points to the first byte after the output name,
4664 ; which is set to a null byte.
4665 ;
4666 unmangle_name:
4667 00001590 6650 push eax
4668 00001592 66AD lodsd
4669 00001594 6621C0 and eax,eax
4670 00001597 7407 jz .noip
4671 00001599 E85702 call gendotquad
4672 0000159C B83A3A mov ax,'::'
4673 0000159F AB stosw
4674 .noip:
4675 000015A0 E8D90F call strcpy
4676 000015A3 4F dec di ; Point to final null byte
4677 000015A4 6658 pop eax
4678 000015A6 C3 ret
4679
4680 ;
4681 ; pxenv
4682 ;
4683 ; This is the main PXENV+/!PXE entry point, using the PXENV+
4684 ; calling convention. This is a separate local routine so
4685 ; we can hook special things from it if necessary.
4686 ;
4687
4688 pxenv:
4689 000015A7 9A[AE15]0000 .jump: call 0:pxe_thunk ; Default to calling the thunk
4690 000015AC FC cld ; Make sure DF <- 0
4691 000015AD C3 ret
4692
4693 ; Must be after function def due to NASM bug
4694 PXENVEntry equ pxenv.jump+1
4695
4696 ;
4697 ; pxe_thunk
4698 ;
4699 ; Convert from the PXENV+ calling convention (BX, ES, DI) to the !PXE
4700 ; calling convention (using the stack.)
4701 ;
4702 ; This is called as a far routine so that we can just stick it into
4703 ; the PXENVEntry variable.
4704 ;
4705 000015AE 06 pxe_thunk: push es
4706 000015AF 57 push di
4707 000015B0 53 push bx
4708 000015B1 9A00000000 .jump: call 0:0
4709 000015B6 83C406 add sp,byte 6
4710 000015B9 83F801 cmp ax,byte 1
4711 000015BC F5 cmc ; Set CF unless ax == 0
4712 000015BD CB retf
4713
4714 ; Must be after function def due to NASM bug
4715 PXEEntry equ pxe_thunk.jump+1
4716
4717 ;
4718 ; getfssec: Get multiple clusters from a file, given the starting cluster.
4719 ;
4720 ; In this case, get multiple blocks from a specific TCP connection.
4721 ;
4722 ; On entry:
4723 ; ES:BX -> Buffer
4724 ; SI -> TFTP socket pointer
4725 ; CX -> 512-byte block count; 0FFFFh = until end of file
4726 ; On exit:
4727 ; SI -> TFTP socket pointer (or 0 on EOF)
4728 ; CF = 1 -> Hit EOF
4729 ;
4730 000015BE 56 getfssec: push si
4731 000015BF 0FA0 push fs
4732 000015C1 89DF mov di,bx
4733 000015C3 89F3 mov bx,si
4734 000015C5 B80010 mov ax,pktbuf_seg
4735 000015C8 8EE0 mov fs,ax
4736
4737 000015CA 660FB7C9 movzx ecx,cx
4738 000015CE 66C1E109 shl ecx,TFTP_BLOCKSIZE_LG2 ; Convert to bytes
4739 000015D2 7426 jz .hit_eof ; Nothing to do?
4740
4741 .need_more:
4742 000015D4 6651 push ecx
4743
4744 000015D6 660FB74714 movzx eax,word [bx+tftp_bytesleft]
4745 000015DB 6639C1 cmp ecx,eax
4746 000015DE 7605 jna .ok_size
4747 000015E0 6689C1 mov ecx,eax
4748 000015E3 E32C jcxz .need_packet ; No bytes available?
4749 .ok_size:
4750
4751 000015E5 89C8 mov ax,cx ; EAX<31:16> == ECX<31:16> == 0
4752 000015E7 8B7718 mov si,[bx+tftp_dataptr]
4753 000015EA 294F14 sub [bx+tftp_bytesleft],cx
4754 000015ED 64F3A4 fs rep movsb ; Copy from packet buffer
4755 000015F0 897718 mov [bx+tftp_dataptr],si
4756
4757 000015F3 6659 pop ecx
4758 000015F5 6629C1 sub ecx,eax
4759 000015F8 75DA jnz .need_more
4760
4761
4762 .hit_eof:
4763 000015FA 0FA1 pop fs
4764 000015FC 5E pop si
4765
4766 ; Is there anything left of this?
4767 000015FD 668B440C mov eax,[si+tftp_filesize]
4768 00001601 662B4408 sub eax,[si+tftp_filepos]
4769 00001605 7509 jnz .bytes_left ; CF <- 0
4770
4771 00001607 394414 cmp [si+tftp_bytesleft],ax
4772 0000160A 7504 jnz .bytes_left ; CF <- 0
4773
4774 ; The socket is closed and the buffer drained
4775 ; Close socket structure and re-init for next user
4776 0000160C E8E3FE call free_socket
4777 0000160F F9 stc
4778 .bytes_left:
4779 00001610 C3 ret
4780
4781 ;
4782 ; No data in buffer, check to see if we can get a packet...
4783 ;
4784 .need_packet:
4785 00001611 6659 pop ecx
4786 00001613 668B470C mov eax,[bx+tftp_filesize]
4787 00001617 663B4708 cmp eax,[bx+tftp_filepos]
4788 0000161B 74DD je .hit_eof ; Already EOF'd; socket already closed
4789
4790 0000161D 6660 pushad
4791 0000161F 06 push es
4792 00001620 89DE mov si,bx
4793 00001622 E80500 call get_packet
4794 00001625 07 pop es
4795 00001626 6661 popad
4796
4797 00001628 EBAA jmp .need_more
4798
4799 ;
4800 ; Get a fresh packet; expects fs -> pktbuf_seg and ds:si -> socket structure
4801 ;
4802 get_packet:
4803 0000162A 8CD8 mov ax,ds
4804 0000162C 8EC0 mov es,ax
4805
4806 .packet_loop:
4807 ; Start by ACKing the previous packet; this should cause the
4808 ; next packet to be sent.
4809 0000162E B90600 mov cx,PKT_RETRY
4810 00001631 C706[1000]0C00 mov word [PktTimeout],PKT_TIMEOUT
4811
4812 00001637 51 .send_ack: push cx ; <D> Retry count
4813
4814 00001638 8B4416 mov ax,[si+tftp_lastpkt]
4815 0000163B E8C400 call ack_packet ; Send ACK
4816
4817 ; We used to test the error code here, but sometimes
4818 ; PXE would return negative status even though we really
4819 ; did send the ACK. Now, just treat a failed send as
4820 ; a normally lost packet, and let it time out in due
4821 ; course of events.
4822
4823 .send_ok: ; Now wait for packet.
4824 0000163E 8B166C04 mov dx,[BIOS_timer] ; Get current time
4825
4826 00001642 8B0E[1000] mov cx,[PktTimeout]
4827 00001646 51 .wait_data: push cx ; <E> Timeout
4828 00001647 52 push dx ; <F> Old time
4829
4830 00001648 8B5C1E mov bx,[si+tftp_pktbuf]
4831 0000164B 891E[9A08] mov [pxe_udp_read_pkt.buffer],bx
4832 0000164F 8C26[9C08] mov [pxe_udp_read_pkt.buffer+2],fs
4833 00001653 C706[9808]0008 mov [pxe_udp_read_pkt.buffersize],word PKTBUF_SIZE
4834 00001659 668B4404 mov eax,[si+tftp_remoteip]
4835 0000165D 66A3[8C08] mov [pxe_udp_read_pkt.sip],eax
4836 00001661 66A1[EC08] mov eax,[MyIP]
4837 00001665 66A3[9008] mov [pxe_udp_read_pkt.dip],eax
4838 00001669 8B4402 mov ax,[si+tftp_remoteport]
4839 0000166C A3[9408] mov [pxe_udp_read_pkt.rport],ax
4840 0000166F 8B04 mov ax,[si+tftp_localport]
4841 00001671 A3[9608] mov [pxe_udp_read_pkt.lport],ax
4842 00001674 BF[8A08] mov di,pxe_udp_read_pkt
4843 00001677 BB3200 mov bx,PXENV_UDP_READ
4844 0000167A 56 push si ; <G>
4845 0000167B E829FF call pxenv
4846 0000167E 5E pop si ; <G>
4847 0000167F 21C0 and ax,ax
4848 00001681 7416 jz .recv_ok
4849
4850 ; No packet, or receive failure
4851 00001683 8B166C04 mov dx,[BIOS_timer]
4852 00001687 58 pop ax ; <F> Old time
4853 00001688 59 pop cx ; <E> Timeout
4854 00001689 39D0 cmp ax,dx ; Same time -> don't advance timeout
4855 0000168B 74B9 je .wait_data ; Same clock tick
4856 0000168D E2B7 loop .wait_data ; Decrease timeout
4857
4858 0000168F 59 pop cx ; <D> Didn't get any, send another ACK
4859 00001690 D126[1000] shl word [PktTimeout],1 ; Exponential backoff
4860 00001694 E2A1 loop .send_ack
4861 00001696 E91CFB jmp kaboom ; Forget it...
4862
4863 00001699 5A .recv_ok: pop dx ; <F>
4864 0000169A 59 pop cx ; <E>
4865
4866 0000169B 833E[9808]04 cmp word [pxe_udp_read_pkt.buffersize],byte 4
4867 000016A0 72A4 jb .wait_data ; Bad size for a DATA packet
4868
4869 000016A2 8B5C1E mov bx,[si+tftp_pktbuf]
4870 000016A5 64813F0003 cmp word [fs:bx],TFTP_DATA ; Not a data packet?
4871 000016AA 759A jne .wait_data ; Then wait for something else
4872
4873 000016AC 8B4416 mov ax,[si+tftp_lastpkt]
4874 000016AF 86E0 xchg ah,al ; Host byte order
4875 000016B1 40 inc ax ; Which packet are we waiting for?
4876 000016B2 86E0 xchg ah,al ; Network byte order
4877 000016B4 64394702 cmp [fs:bx+2],ax
4878 000016B8 740A je .right_packet
4879
4880 ; Wrong packet, ACK the packet and then try again
4881 ; This is presumably because the ACK got lost,
4882 ; so the server just resent the previous packet
4883 000016BA 648B4702 mov ax,[fs:bx+2]
4884 000016BE E84100 call ack_packet
4885 000016C1 E97AFF jmp .send_ok ; Reset timeout
4886
4887 .right_packet: ; It's the packet we want. We're also EOF if the size < blocksize
4888
4889 000016C4 59 pop cx ; <D> Don't need the retry count anymore
4890
4891 000016C5 894416 mov [si+tftp_lastpkt],ax ; Update last packet number
4892
4893 000016C8 660FB70E[9808] movzx ecx,word [pxe_udp_read_pkt.buffersize]
4894 000016CE 83E904 sub cx,byte 4 ; Skip TFTP header
4895
4896 ; If this is a zero-length block, don't mess with the pointers,
4897 ; since we may have just set up the previous block that way
4898 000016D1 741F jz .last_block
4899
4900 ; Set pointer to data block
4901 000016D3 8D4704 lea ax,[bx+4] ; Data past TFTP header
4902 000016D6 894418 mov [si+tftp_dataptr],ax
4903
4904 000016D9 66014C08 add [si+tftp_filepos],ecx
4905 000016DD 894C14 mov [si+tftp_bytesleft],cx
4906
4907 000016E0 3B4C10 cmp cx,[si+tftp_blksize] ; Is it a full block?
4908 000016E3 720D jb .last_block ; If so, it's not EOF
4909
4910 ; If we had the exact right number of bytes, always get
4911 ; one more packet to get the (zero-byte) EOF packet and
4912 ; close the socket.
4913 000016E5 668B4408 mov eax,[si+tftp_filepos]
4914 000016E9 6639440C cmp [si+tftp_filesize],eax
4915 000016ED 0F843DFF je .packet_loop
4916
4917 000016F1 C3 ret
4918
4919
4920 .last_block: ; Last block - ACK packet immediately
4921 000016F2 648B4702 mov ax,[fs:bx+2]
4922 000016F6 E80900 call ack_packet
4923
4924 ; Make sure we know we are at end of file
4925 000016F9 668B4408 mov eax,[si+tftp_filepos]
4926 000016FD 6689440C mov [si+tftp_filesize],eax
4927
4928 00001701 C3 ret
4929
4930 ;
4931 ; ack_packet:
4932 ;
4933 ; Send ACK packet. This is a common operation and so is worth canning.
4934 ;
4935 ; Entry:
4936 ; SI = TFTP block
4937 ; AX = Packet # to ack (network byte order)
4938 ; Exit:
4939 ; ZF = 0 -> Error
4940 ; All registers preserved
4941 ;
4942 ; This function uses the pxe_udp_write_pkt but not the packet_buf.
4943 ;
4944 ack_packet:
4945 00001702 6660 pushad
4946 00001704 A3[EA08] mov [ack_packet_buf+2],ax ; Packet number to ack
4947 00001707 8B04 mov ax,[si]
4948 00001709 A3[8008] mov [pxe_udp_write_pkt.lport],ax
4949 0000170C 8B4402 mov ax,[si+tftp_remoteport]
4950 0000170F A3[8208] mov [pxe_udp_write_pkt.rport],ax
4951 00001712 668B4404 mov eax,[si+tftp_remoteip]
4952 00001716 66A3[7808] mov [pxe_udp_write_pkt.sip],eax
4953 0000171A 663306[EC08] xor eax,[MyIP]
4954 0000171F 662306[F408] and eax,[Netmask]
4955 00001724 7404 jz .nogw
4956 00001726 66A1[F808] mov eax,[Gateway]
4957 .nogw:
4958 0000172A 66A3[7C08] mov [pxe_udp_write_pkt.gip],eax
4959 0000172E C706[8608][E808] mov [pxe_udp_write_pkt.buffer],word ack_packet_buf
4960 00001734 C706[8408]0400 mov [pxe_udp_write_pkt.buffersize], word 4
4961 0000173A BF[7608] mov di,pxe_udp_write_pkt
4962 0000173D BB3300 mov bx,PXENV_UDP_WRITE
4963 00001740 E864FE call pxenv
4964 00001743 83F800 cmp ax,byte 0 ; ZF = 1 if write OK
4965 00001746 6661 popad
4966 00001748 C3 ret
4967
4968 ;
4969 ; unload_pxe:
4970 ;
4971 ; This function unloads the PXE and UNDI stacks and unclaims
4972 ; the memory.
4973 ;
4974 unload_pxe:
4975 00001749 F606[A608]01 test byte [KeepPXE],01h ; Should we keep PXE around?
4976 0000174E 0F859300 jnz reset_pxe
4977
4978 00001752 1E push ds
4979 00001753 06 push es
4980
4981 00001754 8CC8 mov ax,cs
4982 00001756 8ED8 mov ds,ax
4983 00001758 8EC0 mov es,ax
4984
4985 0000175A BE[4008] mov si,new_api_unload
4986 0000175D 803E[0900]02 cmp byte [APIVer+1],2 ; Major API version >= 2?
4987 00001762 7303 jae .new_api
4988 00001764 BE[4508] mov si,old_api_unload
4989 .new_api:
4990
4991 00001767 31C0 .call_loop: xor ax,ax
4992 00001769 AC lodsb
4993 0000176A 21C0 and ax,ax
4994 0000176C 741C jz .call_done
4995 0000176E 93 xchg bx,ax
4996 0000176F BF[6400] mov di,pxe_unload_stack_pkt
4997 00001772 57 push di
4998 00001773 31C0 xor ax,ax
4999 00001775 B90B00 mov cx,pxe_unload_stack_pkt_len >> 1
5000 00001778 F3AB rep stosw
5001 0000177A 5F pop di
5002 0000177B E829FE call pxenv
5003 0000177E 7240 jc .cant_free
5004 00001780 A1[6400] mov ax,word [pxe_unload_stack_pkt.status]
5005 00001783 83F800 cmp ax,PXENV_STATUS_SUCCESS
5006 00001786 7538 jne .cant_free
5007 00001788 EBDD jmp .call_loop
5008
5009 .call_done:
5010 ;
5011 ; This isn't necessary anymore; we can use the memory area previously
5012 ; used by the PXE stack indefinitely, and the chainload code sets up
5013 ; a new stack independently. Leave the source code in here for now,
5014 ; but expect to rip it out soonish.
5015 ;
5016 %if 0 ; USE_PXE_PROVIDED_STACK
5017 ; We need to switch to our local stack here...
5018 pusha
5019 pushf
5020 push gs
5021
5022 mov si,sp
5023 mov ax,ss
5024 mov gs,ax
5025 sub ax,[BaseStack+4] ; Are we using the base stack
5026 je .is_base_stack ; (as opposed to the COMBOOT stack)?
5027
5028 lgs si,[SavedSSSP] ; COMBOOT stack
5029 .is_base_stack:
5030
5031 mov cx,[InitStack]
5032 mov di,StackBuf
5033 mov [BaseStack],di
5034 mov [BaseStack+4],es
5035 sub cx,si
5036 sub di,cx
5037 mov [SavedSSSP],di ; New SP
5038 mov [SavedSSSP+2],es
5039 gs rep movsb
5040
5041 and ax,ax ; Remember which stack
5042 jne .combootstack
5043
5044 ; Update the base stack pointer since it's in use
5045 lss sp,[SavedSSSP]
5046
5047 .combootstack:
5048 pop gs
5049 popf
5050 popa
5051 %endif
5052 0000178A BB00FF mov bx,0FF00h
5053
5054 0000178D 8B16[1200] mov dx,[RealBaseMem]
5055 00001791 3B161304 cmp dx,[BIOS_fbm] ; Sanity check
5056 00001795 7629 jna .cant_free
5057 00001797 43 inc bx
5058
5059 ; Check that PXE actually unhooked the INT 1Ah chain
5060 00001798 660FB7066800 movzx eax,word [4*0x1a]
5061 0000179E 660FB70E6A00 movzx ecx,word [4*0x1a+2]
5062 000017A4 66C1E104 shl ecx,4
5063 000017A8 6601C8 add eax,ecx
5064 000017AB 66C1E80A shr eax,10
5065 000017AF 39D0 cmp ax,dx ; Not in range
5066 000017B1 7306 jae .ok
5067 000017B3 3B061304 cmp ax,[BIOS_fbm]
5068 000017B7 7307 jae .cant_free
5069 ; inc bx
5070
5071 .ok:
5072 000017B9 89161304 mov [BIOS_fbm],dx
5073 .pop_ret:
5074 000017BD 07 pop es
5075 000017BE 1F pop ds
5076 000017BF C3 ret
5077
5078 .cant_free:
5079 000017C0 BE[2406] mov si,cant_free_msg
5080 000017C3 E88E06 call writestr
5081 000017C6 50 push ax
5082 000017C7 93 xchg bx,ax
5083 000017C8 E8A906 call writehex4
5084 000017CB B02D mov al,'-'
5085 000017CD E8B50D call writechr
5086 000017D0 58 pop ax
5087 000017D1 E8A006 call writehex4
5088 000017D4 B02D mov al,'-'
5089 000017D6 E8AC0D call writechr
5090 000017D9 66A16800 mov eax,[4*0x1a]
5091 000017DD E8A106 call writehex8
5092 000017E0 E86406 call crlf
5093 000017E3 EBD8 jmp .pop_ret
5094
5095 ; We want to keep PXE around, but still we should reset
5096 ; it to the standard bootup configuration
5097 reset_pxe:
5098 000017E5 06 push es
5099 000017E6 0E push cs
5100 000017E7 07 pop es
5101 000017E8 BB3100 mov bx,PXENV_UDP_CLOSE
5102 000017EB BF[7408] mov di,pxe_udp_close_pkt
5103 000017EE E8B6FD call pxenv
5104 000017F1 07 pop es
5105 000017F2 C3 ret
5106
5107 ;
5108 ; gendotquad
5109 ;
5110 ; Take an IP address (in network byte order) in EAX and
5111 ; output a dotted quad string to ES:DI.
5112 ; DI points to terminal null at end of string on exit.
5113 ;
5114 gendotquad:
5115 000017F3 6650 push eax
5116 000017F5 51 push cx
5117 000017F6 B90400 mov cx,4
5118 .genchar:
5119 000017F9 6650 push eax
5120 000017FB 3C0A cmp al,10 ; < 10?
5121 000017FD 7216 jb .lt10 ; If so, skip first 2 digits
5122
5123 000017FF 3C64 cmp al,100 ; < 100
5124 00001801 7209 jb .lt100 ; If so, skip first digit
5125
5126 00001803 D464 aam 100
5127 ; Now AH = 100-digit; AL = remainder
5128 00001805 80C430 add ah,'0'
5129 00001808 268825 mov [es:di],ah
5130 0000180B 47 inc di
5131
5132 .lt100:
5133 0000180C D40A aam 10
5134 ; Now AH = 10-digit; AL = remainder
5135 0000180E 80C430 add ah,'0'
5136 00001811 268825 mov [es:di],ah
5137 00001814 47 inc di
5138
5139 .lt10:
5140 00001815 0430 add al,'0'
5141 00001817 AA stosb
5142 00001818 B02E mov al,'.'
5143 0000181A AA stosb
5144 0000181B 6658 pop eax
5145 0000181D 66C1C808 ror eax,8 ; Move next char into LSB
5146 00001821 E2D6 loop .genchar
5147 00001823 4F dec di
5148 00001824 26C60500 mov [es:di], byte 0
5149 00001828 59 pop cx
5150 00001829 6658 pop eax
5151 0000182B C3 ret
5152
5153 ;
5154 ; parse_dhcp
5155 ;
5156 ; Parse a DHCP packet. This includes dealing with "overloaded"
5157 ; option fields (see RFC 2132, section 9.3)
5158 ;
5159 ; This should fill in the following global variables, if the
5160 ; information is present:
5161 ;
5162 ; MyIP - client IP address
5163 ; ServerIP - boot server IP address
5164 ; Netmask - network mask
5165 ; Gateway - default gateway router IP
5166 ; BootFile - boot file name
5167 ; DNSServers - DNS server IPs
5168 ; LocalDomain - Local domain name
5169 ;
5170 ; This assumes the DHCP packet is in "trackbuf" and the length
5171 ; of the packet in in CX on entry.
5172 ;
5173
5174 parse_dhcp:
5175 0000182C C606[1400]00 mov byte [OverLoad],0 ; Assume no overload
5176 00001831 66A1[1000] mov eax, [trackbuf+bootp.yip]
5177 00001835 6621C0 and eax, eax
5178 00001838 7408 jz .noyip
5179 0000183A 3CE0 cmp al,224 ; Class D or higher -> bad
5180 0000183C 7304 jae .noyip
5181 0000183E 66A3[EC08] mov [MyIP], eax
5182 .noyip:
5183 00001842 66A1[1400] mov eax, [trackbuf+bootp.sip]
5184 00001846 6621C0 and eax, eax
5185 00001849 7408 jz .nosip
5186 0000184B 3CE0 cmp al,224 ; Class D or higher -> bad
5187 0000184D 7304 jae .nosip
5188 0000184F 66A3[F008] mov [ServerIP], eax
5189 .nosip:
5190 00001853 81E9F000 sub cx, bootp.options
5191 00001857 7610 jbe .nooptions
5192 00001859 BE[EC00] mov si, trackbuf+bootp.option_magic
5193 0000185C 66AD lodsd
5194 0000185E 663D63825363 cmp eax, BOOTP_OPTION_MAGIC
5195 00001864 7503 jne .nooptions
5196 00001866 E83400 call parse_dhcp_options
5197 .nooptions:
5198 00001869 BE[6C00] mov si, trackbuf+bootp.bootfile
5199 0000186C F606[1400]01 test byte [OverLoad],1
5200 00001871 7408 jz .nofileoverload
5201 00001873 B98000 mov cx,128
5202 00001876 E82400 call parse_dhcp_options
5203 00001879 EB11 jmp short .parsed_file
5204 .nofileoverload:
5205 0000187B 803C00 cmp byte [si], 0
5206 0000187E 740C jz .parsed_file ; No bootfile name
5207 00001880 BF[0044] mov di,BootFile
5208 00001883 B92000 mov cx,32
5209 00001886 F366A5 rep movsd
5210 00001889 30C0 xor al,al
5211 0000188B AA stosb ; Null-terminate
5212 .parsed_file:
5213 0000188C BE[2C00] mov si, trackbuf+bootp.sname
5214 0000188F F606[1400]02 test byte [OverLoad],2
5215 00001894 7406 jz .nosnameoverload
5216 00001896 B94000 mov cx,64
5217 00001899 E80100 call parse_dhcp_options
5218 .nosnameoverload:
5219 0000189C C3 ret
5220
5221 ;
5222 ; Parse a sequence of DHCP options, pointed to by DS:SI; the field
5223 ; size is CX -- some DHCP servers leave option fields unterminated
5224 ; in violation of the spec.
5225 ;
5226 ; For parse_some_dhcp_options, DH contains the minimum value for
5227 ; the option to recognize -- this is used to restrict parsing to
5228 ; PXELINUX-specific options only.
5229 ;
5230 parse_dhcp_options:
5231 0000189D 31D2 xor dx,dx
5232
5233 parse_some_dhcp_options:
5234 .loop:
5235 0000189F 21C9 and cx,cx
5236 000018A1 0F84A200 jz .done
5237
5238 000018A5 AC lodsb
5239 000018A6 49 dec cx
5240 000018A7 0F849C00 jz .done ; Last byte; must be PAD, END or malformed
5241 000018AB 3C00 cmp al, 0 ; PAD option
5242 000018AD 74F0 je .loop
5243 000018AF 3CFF cmp al,255 ; END option
5244 000018B1 0F849200 je .done
5245
5246 ; Anything else will have a length field
5247 000018B5 88C2 mov dl,al ; DL <- option number
5248 000018B7 31C0 xor ax,ax
5249 000018B9 AC lodsb ; AX <- option length
5250 000018BA 49 dec cx
5251 000018BB 29C1 sub cx,ax ; Decrement bytes left counter
5252 000018BD 0F828600 jb .done ; Malformed option: length > field size
5253
5254 000018C1 38F2 cmp dl,dh ; Is the option value valid?
5255 000018C3 0F82D600 jb .opt_done
5256
5257 000018C7 80FA01 cmp dl,1 ; SUBNET MASK option
5258 000018CA 750B jne .not_subnet
5259 000018CC 668B1C mov ebx,[si]
5260 000018CF 66891E[F408] mov [Netmask],ebx
5261 000018D4 E9C600 jmp .opt_done
5262 .not_subnet:
5263
5264 000018D7 80FA03 cmp dl,3 ; ROUTER option
5265 000018DA 750B jne .not_router
5266 000018DC 668B1C mov ebx,[si]
5267 000018DF 66891E[F808] mov [Gateway],ebx
5268 000018E4 E9B600 jmp .opt_done
5269 .not_router:
5270
5271 000018E7 80FA06 cmp dl,6 ; DNS SERVERS option
5272 000018EA 751B jne .not_dns
5273 000018EC 60 pusha
5274 000018ED 89C1 mov cx,ax
5275 000018EF C1E902 shr cx,2
5276 000018F2 80F904 cmp cl,DNS_MAX_SERVERS
5277 000018F5 7602 jna .oklen
5278 000018F7 B104 mov cl,DNS_MAX_SERVERS
5279 .oklen:
5280 000018F9 BF[9C24] mov di,DNSServers
5281 000018FC F366A5 rep movsd
5282 000018FF 893E[3901] mov [LastDNSServer],di
5283 00001903 61 popa
5284 00001904 E99600 jmp .opt_done
5285 .not_dns:
5286
5287 00001907 80FA0F cmp dl,15 ; DNS LOCAL DOMAIN option
5288 0000190A 7514 jne .not_localdomain
5289 0000190C 60 pusha
5290 0000190D 89F3 mov bx,si
5291 0000190F 01C3 add bx,ax
5292 00001911 31C0 xor ax,ax
5293 00001913 8607 xchg [bx],al ; Zero-terminate option
5294 00001915 BF[9C23] mov di,LocalDomain
5295 00001918 E8F10C call dns_mangle ; Convert to DNS label set
5296 0000191B 8807 mov [bx],al ; Restore ending byte
5297 0000191D 61 popa
5298 0000191E EB7D jmp .opt_done
5299 .not_localdomain:
5300
5301 00001920 80FA2B cmp dl,43 ; VENDOR ENCAPSULATED option
5302 00001923 750B jne .not_vendor
5303 00001925 60 pusha
5304 00001926 B6D0 mov dh,208 ; Only recognize PXELINUX options
5305 00001928 89C1 mov cx,ax ; Length of option = max bytes to parse
5306 0000192A E872FF call parse_some_dhcp_options ; Parse recursive structure
5307 0000192D 61 popa
5308 0000192E EB6D jmp .opt_done
5309 .not_vendor:
5310
5311 00001930 80FA34 cmp dl,52 ; OPTION OVERLOAD option
5312 00001933 7508 jne .not_overload
5313 00001935 8A1C mov bl,[si]
5314 00001937 881E[1400] mov [OverLoad],bl
5315 0000193B EB60 jmp .opt_done
5316 .not_overload:
5317
5318 0000193D 80FA43 cmp dl,67 ; BOOTFILE NAME option
5319 00001940 7506 jne .not_bootfile
5320 00001942 BF[0044] mov di,BootFile
5321 00001945 EB5B jmp short .copyoption
5322 .done:
5323 00001947 C3 ret ; This is here to make short jumps easier
5324 .not_bootfile:
5325
5326 00001948 80FAD0 cmp dl,208 ; PXELINUX MAGIC option
5327 0000194B 7514 jne .not_pl_magic
5328 0000194D 3C04 cmp al,4 ; Must have length == 4
5329 0000194F 754C jne .opt_done
5330 00001951 66813CF100747E cmp dword [si], htonl(0xF100747E) ; Magic number
5331 00001958 7543 jne .opt_done
5332 0000195A 800E[0909]01 or byte [DHCPMagic], byte 1 ; Found magic #
5333 0000195F EB3C jmp short .opt_done
5334 .not_pl_magic:
5335
5336 00001961 80FAD1 cmp dl,209 ; PXELINUX CONFIGFILE option
5337 00001964 750A jne .not_pl_config
5338 00001966 BF[0445] mov di,ConfigName
5339 00001969 800E[0909]02 or byte [DHCPMagic], byte 2 ; Got config file
5340 0000196E EB32 jmp short .copyoption
5341 .not_pl_config:
5342
5343 00001970 80FAD2 cmp dl,210 ; PXELINUX PATHPREFIX option
5344 00001973 750A jne .not_pl_prefix
5345 00001975 BF[0046] mov di,PathPrefix
5346 00001978 800E[0909]04 or byte [DHCPMagic], byte 4 ; Got path prefix
5347 0000197D EB23 jmp short .copyoption
5348 .not_pl_prefix:
5349
5350 0000197F 80FAD3 cmp dl,211 ; PXELINUX REBOOTTIME option
5351 00001982 7519 jne .not_pl_timeout
5352 00001984 3C04 cmp al,4
5353 00001986 7515 jne .opt_done
5354 00001988 668B1C mov ebx,[si]
5355 0000198B 86DF xchg bl,bh ; Convert to host byte order
5356 0000198D 66C1C310 rol ebx,16
5357 00001991 86DF xchg bl,bh
5358 00001993 66891E[0000] mov [RebootTime],ebx
5359 00001998 800E[0909]08 or byte [DHCPMagic], byte 8 ; Got RebootTime
5360 ; jmp short .opt_done
5361 .not_pl_timeout:
5362
5363 ; Unknown option. Skip to the next one.
5364 .opt_done:
5365 0000199D 01C6 add si,ax
5366 .opt_done_noskip:
5367 0000199F E9FDFE jmp .loop
5368
5369 ; Common code for copying an option verbatim
5370 .copyoption:
5371 000019A2 91 xchg cx,ax
5372 000019A3 F3A4 rep movsb
5373 000019A5 91 xchg cx,ax ; Now ax == 0
5374 000019A6 AA stosb ; Null-terminate
5375 000019A7 EBF6 jmp short .opt_done_noskip
5376
5377 ;
5378 ; genipopt
5379 ;
5380 ; Generate an ip=<client-ip>:<boot-server-ip>:<gw-ip>:<netmask>
5381 ; option into IPOption based on a DHCP packet in trackbuf.
5382 ; Assumes CS == DS == ES.
5383 ;
5384 genipopt:
5385 000019A9 6660 pushad
5386 000019AB BF[1047] mov di,IPOption
5387 000019AE 66B869703D00 mov eax,'ip='
5388 000019B4 66AB stosd
5389 000019B6 4F dec di
5390 000019B7 66A1[EC08] mov eax,[MyIP]
5391 000019BB E835FE call gendotquad
5392 000019BE B03A mov al,':'
5393 000019C0 AA stosb
5394 000019C1 66A1[F008] mov eax,[ServerIP]
5395 000019C5 E82BFE call gendotquad
5396 000019C8 B03A mov al,':'
5397 000019CA AA stosb
5398 000019CB 66A1[F808] mov eax,[Gateway]
5399 000019CF E821FE call gendotquad
5400 000019D2 B03A mov al,':'
5401 000019D4 AA stosb
5402 000019D5 66A1[F408] mov eax,[Netmask]
5403 000019D9 E817FE call gendotquad ; Zero-terminates its output
5404 000019DC 81EF[1047] sub di,IPOption
5405 000019E0 893E[0A00] mov [IPOptionLen],di
5406 000019E4 6661 popad
5407 000019E6 C3 ret
5408
5409 ;
5410 ; Call the receive loop while idle. This is done mostly so we can respond to
5411 ; ARP messages, but perhaps in the future this can be used to do network
5412 ; console.
5413 ;
5414 ; hpa sez: people using automatic control on the serial port get very
5415 ; unhappy if we poll for ARP too often (the PXE stack is pretty slow,
5416 ; typically.) Therefore, only poll if at least 4 BIOS timer ticks have
5417 ; passed since the last poll, and reset this when a character is
5418 ; received (RESET_IDLE).
5419 ;
5420 reset_idle:
5421 000019E7 50 push ax
5422 000019E8 2EA16C04 mov ax,[cs:BIOS_timer]
5423 000019EC 2EA3[0C00] mov [cs:IdleTimer],ax
5424 000019F0 58 pop ax
5425 000019F1 C3 ret
5426
5427 check_for_arp:
5428 000019F2 50 push ax
5429 000019F3 2EA16C04 mov ax,[cs:BIOS_timer]
5430 000019F7 2E2B06[0C00] sub ax,[cs:IdleTimer]
5431 000019FC 83F804 cmp ax,4
5432 000019FF 58 pop ax
5433 00001A00 7301 jae .need_poll
5434 00001A02 C3 ret
5435 00001A03 6660 .need_poll: pushad
5436 00001A05 1E push ds
5437 00001A06 06 push es
5438 00001A07 8CC8 mov ax,cs
5439 00001A09 8ED8 mov ds,ax
5440 00001A0B 8EC0 mov es,ax
5441 00001A0D BF[8000] mov di,packet_buf
5442 00001A10 A2[8A08] mov [pxe_udp_read_pkt.status],al ; 0
5443 00001A13 893E[9A08] mov [pxe_udp_read_pkt.buffer],di
5444 00001A17 8C1E[9C08] mov [pxe_udp_read_pkt.buffer+2],ds
5445 00001A1B C706[9808]0008 mov word [pxe_udp_read_pkt.buffersize],packet_buf_size
5446 00001A21 66A1[EC08] mov eax,[MyIP]
5447 00001A25 66A3[9008] mov [pxe_udp_read_pkt.dip],eax
5448 00001A29 C706[9608]0009 mov word [pxe_udp_read_pkt.lport],htons(9) ; discard port
5449 00001A2F BF[8A08] mov di,pxe_udp_read_pkt
5450 00001A32 BB3200 mov bx,PXENV_UDP_READ
5451 00001A35 E86FFB call pxenv
5452 ; Ignore result...
5453 00001A38 07 pop es
5454 00001A39 1F pop ds
5455 00001A3A 6661 popad
5456 RESET_IDLE
5457 00001A3C E8A8FF <1> call reset_idle
5458 00001A3F C3 ret
5459
5460 ; -----------------------------------------------------------------------------
5461 ; Common modules
5462 ; -----------------------------------------------------------------------------
5463
5464 %include "getc.inc" ; getc et al
5465 <1> ;; $Id: getc.inc,v 1.6 2004/12/17 06:42:01 hpa Exp $
5466 <1> ;; -----------------------------------------------------------------------
5467 <1> ;;
5468 <1> ;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
5469 <1> ;;
5470 <1> ;; This program is free software; you can redistribute it and/or modify
5471 <1> ;; it under the terms of the GNU General Public License as published by
5472 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
5473 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
5474 <1> ;; (at your option) any later version; incorporated herein by reference.
5475 <1> ;;
5476 <1> ;; -----------------------------------------------------------------------
5477 <1>
5478 <1> ;;
5479 <1> ;; getc.inc
5480 <1> ;;
5481 <1> ;; Simple file handling library (open, getc, ungetc)
5482 <1> ;;
5483 <1>
5484 <1> ;
5485 <1> ; open,getc: Load a file a character at a time for parsing in a manner
5486 <1> ; similar to the C library getc routine. Only one simultaneous
5487 <1> ; use is supported. Note: "open" trashes the trackbuf.
5488 <1> ;
5489 <1> ; open: Input: mangled filename in DS:DI
5490 <1> ; Output: ZF set on file not found or zero length
5491 <1> ;
5492 <1> ; openfd: Input: file handle in SI
5493 <1> ; Output: none
5494 <1> ;
5495 <1> ; getc: Output: CF set on end of file
5496 <1> ; Character loaded in AL
5497 <1> ;
5498 <1> open:
5499 00001A40 E89AF8 <1> call searchdir
5500 00001A43 7425 <1> jz openfd.ret
5501 <1> openfd:
5502 00001A45 9C <1> pushf
5503 00001A46 A3[B808] <1> mov [FBytes],ax
5504 00001A49 8916[BA08] <1> mov [FBytes+2],dx
5505 00001A4D 66A1[B808] <1> mov eax,[FBytes]
5506 00001A51 6605FF010000 <1> add eax,SECTOR_SIZE-1
5507 00001A57 66C1E809 <1> shr eax,SECTOR_SHIFT
5508 00001A5B 66A3[BC08] <1> mov [FSectors],eax ; Number of sectors
5509 00001A5F 8936[C008] <1> mov [FNextClust],si ; Cluster pointer
5510 00001A63 A1[0609] <1> mov ax,[EndOfGetCBuf] ; Pointer at end of buffer ->
5511 00001A66 A3[C208] <1> mov [FPtr],ax ; nothing loaded yet
5512 00001A69 9D <1> popf ; Restore no ZF
5513 00001A6A C3 <1> .ret: ret
5514 <1>
5515 <1> getc:
5516 00001A6B F9 <1> stc ; If we exit here -> EOF
5517 00001A6C 668B0E[B808] <1> mov ecx,[FBytes]
5518 00001A71 67E33F <1> jecxz .ret
5519 00001A74 8B36[C208] <1> mov si,[FPtr]
5520 00001A78 3B36[0609] <1> cmp si,[EndOfGetCBuf]
5521 00001A7C 722A <1> jb .loaded
5522 <1> ; Buffer empty -- load another set
5523 00001A7E 668B0E[BC08] <1> mov ecx,[FSectors]
5524 00001A83 6683F910 <1> cmp ecx,trackbufsize >> SECTOR_SHIFT
5525 00001A87 7606 <1> jna .oksize
5526 00001A89 66B910000000 <1> mov ecx,trackbufsize >> SECTOR_SHIFT
5527 00001A8F 66290E[BC08] <1> .oksize: sub [FSectors],ecx ; Reduce remaining clusters
5528 00001A94 8B36[C008] <1> mov si,[FNextClust]
5529 00001A98 06 <1> push es ; ES may be != DS, save old ES
5530 00001A99 1E <1> push ds
5531 00001A9A 07 <1> pop es
5532 00001A9B BB[0020] <1> mov bx,getcbuf
5533 00001A9E 53 <1> push bx
5534 00001A9F E81CFB <1> call getfssec ; Load a trackbuf full of data
5535 00001AA2 8936[C008] <1> mov [FNextClust],si ; Store new next pointer
5536 00001AA6 5E <1> pop si ; SI -> newly loaded data
5537 00001AA7 07 <1> pop es ; Restore ES
5538 00001AA8 AC <1> .loaded: lodsb ; Load a byte, increment SI
5539 00001AA9 8936[C208] <1> mov [FPtr],si ; Update next byte pointer
5540 00001AAD 66FF0E[B808] <1> dec dword [FBytes] ; Update bytes left counter
5541 00001AB2 F8 <1> clc ; Not EOF
5542 00001AB3 C3 <1> .ret: ret
5543 <1>
5544 <1> ;
5545 <1> ; ungetc: Push a character (in AL) back into the getc buffer
5546 <1> ; Note: if more than one byte is pushed back, this may cause
5547 <1> ; bytes to be written below the getc buffer boundary. If there
5548 <1> ; is a risk for this to occur, the getcbuf base address should
5549 <1> ; be moved up.
5550 <1> ;
5551 <1> ungetc:
5552 00001AB4 8B36[C208] <1> mov si,[FPtr]
5553 00001AB8 4E <1> dec si
5554 00001AB9 8804 <1> mov [si],al
5555 00001ABB 8936[C208] <1> mov [FPtr],si
5556 00001ABF 66FF06[B808] <1> inc dword [FBytes]
5557 00001AC4 C3 <1> ret
5558 <1>
5559 <1> ;
5560 <1> ; skipspace: Skip leading whitespace using "getc". If we hit end-of-line
5561 <1> ; or end-of-file, return with carry set; ZF = true of EOF
5562 <1> ; ZF = false for EOLN; otherwise CF = ZF = 0.
5563 <1> ;
5564 <1> ; Otherwise AL = first character after whitespace
5565 <1> ;
5566 <1> skipspace:
5567 00001AC5 E8A3FF <1> .loop: call getc
5568 00001AC8 720D <1> jc .eof
5569 00001ACA 3C1A <1> cmp al,1Ah ; DOS EOF
5570 00001ACC 7409 <1> je .eof
5571 00001ACE 3C0A <1> cmp al,0Ah
5572 00001AD0 7409 <1> je .eoln
5573 00001AD2 3C20 <1> cmp al,' '
5574 00001AD4 76EF <1> jbe .loop
5575 00001AD6 C3 <1> ret ; CF = ZF = 0
5576 00001AD7 38C0 <1> .eof: cmp al,al ; Set ZF
5577 00001AD9 F9 <1> stc ; Set CF
5578 00001ADA C3 <1> ret
5579 00001ADB 04FF <1> .eoln: add al,0FFh ; Set CF, clear ZF
5580 00001ADD C3 <1> ret
5581 <1>
5582 <1> ;
5583 <1> ; getint: Load an integer from the getc file.
5584 <1> ; Return CF if error; otherwise return integer in EBX
5585 <1> ;
5586 <1> getint:
5587 00001ADE BF[A808] <1> mov di,NumBuf
5588 00001AE1 81FF[B708] <1> .getnum: cmp di,NumBufEnd ; Last byte in NumBuf
5589 00001AE5 730F <1> jae .loaded
5590 00001AE7 57 <1> push di
5591 00001AE8 E880FF <1> call getc
5592 00001AEB 5F <1> pop di
5593 00001AEC 7208 <1> jc .loaded
5594 00001AEE AA <1> stosb
5595 00001AEF 3C2D <1> cmp al,'-'
5596 00001AF1 73EE <1> jnb .getnum
5597 00001AF3 E8BEFF <1> call ungetc ; Unget non-numeric
5598 00001AF6 C60500 <1> .loaded: mov byte [di],0
5599 00001AF9 BE[A808] <1> mov si,NumBuf
5600 <1> ; Fall through to parseint
5601 <1>
5602 <1> ;
5603 <1> ; parseint: Convert an integer to a number in EBX
5604 <1> ; Get characters from string in DS:SI
5605 <1> ; Return CF on error
5606 <1> ; DS:SI points to first character after number
5607 <1> ;
5608 <1> ; Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+K, val+M
5609 <1> ;
5610 <1> parseint:
5611 00001AFC 6650 <1> push eax
5612 00001AFE 6651 <1> push ecx
5613 00001B00 55 <1> push bp
5614 00001B01 6631C0 <1> xor eax,eax ; Current digit (keep eax == al)
5615 00001B04 6689C3 <1> mov ebx,eax ; Accumulator
5616 00001B07 6689D9 <1> mov ecx,ebx ; Base
5617 00001B0A 31ED <1> xor bp,bp ; Used for negative flag
5618 00001B0C AC <1> .begin: lodsb
5619 00001B0D 3C2D <1> cmp al,'-'
5620 00001B0F 7505 <1> jne .not_minus
5621 00001B11 83F501 <1> xor bp,1 ; Set unary minus flag
5622 00001B14 EBF6 <1> jmp short .begin
5623 <1> .not_minus:
5624 00001B16 3C30 <1> cmp al,'0'
5625 00001B18 724F <1> jb .err
5626 00001B1A 7408 <1> je .octhex
5627 00001B1C 3C39 <1> cmp al,'9'
5628 00001B1E 7749 <1> ja .err
5629 00001B20 B10A <1> mov cl,10 ; Base = decimal
5630 00001B22 EB17 <1> jmp short .foundbase
5631 <1> .octhex:
5632 00001B24 AC <1> lodsb
5633 00001B25 3C30 <1> cmp al,'0'
5634 00001B27 7225 <1> jb .km ; Value is zero
5635 00001B29 0C20 <1> or al,20h ; Downcase
5636 00001B2B 3C78 <1> cmp al,'x'
5637 00001B2D 7408 <1> je .ishex
5638 00001B2F 3C37 <1> cmp al,'7'
5639 00001B31 7736 <1> ja .err
5640 00001B33 B108 <1> mov cl,8 ; Base = octal
5641 00001B35 EB04 <1> jmp short .foundbase
5642 <1> .ishex:
5643 00001B37 B030 <1> mov al,'0' ; No numeric value accrued yet
5644 00001B39 B110 <1> mov cl,16 ; Base = hex
5645 <1> .foundbase:
5646 00001B3B E83A00 <1> call unhexchar
5647 00001B3E 720E <1> jc .km ; Not a (hex) digit
5648 00001B40 38C8 <1> cmp al,cl
5649 00001B42 730A <1> jae .km ; Invalid for base
5650 00001B44 660FAFD9 <1> imul ebx,ecx ; Multiply accumulated by base
5651 00001B48 6601C3 <1> add ebx,eax ; Add current digit
5652 00001B4B AC <1> lodsb
5653 00001B4C EBED <1> jmp short .foundbase
5654 <1> .km:
5655 00001B4E 4E <1> dec si ; Back up to last non-numeric
5656 00001B4F AC <1> lodsb
5657 00001B50 0C20 <1> or al,20h
5658 00001B52 3C6B <1> cmp al,'k'
5659 00001B54 7416 <1> je .isk
5660 00001B56 3C6D <1> cmp al,'m'
5661 00001B58 7418 <1> je .ism
5662 00001B5A 4E <1> dec si ; Back up
5663 00001B5B 21ED <1> .fini: and bp,bp
5664 00001B5D 7404 <1> jz .ret ; CF=0!
5665 00001B5F 66F7DB <1> neg ebx ; Value was negative
5666 00001B62 F8 <1> .done: clc
5667 00001B63 5D <1> .ret: pop bp
5668 00001B64 6659 <1> pop ecx
5669 00001B66 6658 <1> pop eax
5670 00001B68 C3 <1> ret
5671 00001B69 F9 <1> .err: stc
5672 00001B6A EBF7 <1> jmp short .ret
5673 00001B6C 66C1E30A <1> .isk: shl ebx,10 ; x 2^10
5674 00001B70 EBF0 <1> jmp short .done
5675 00001B72 66C1E314 <1> .ism: shl ebx,20 ; x 2^20
5676 00001B76 EBEA <1> jmp short .done
5677 <1>
5678 <1>
5679 <1> section .bss
5680 000008A6 <res 00000001>- <1> alignb 4
5681 000008A6 <rept> <1>
5682 000008A8 <res 0000000F> <1> NumBuf resb 15 ; Buffer to load number
5683 000008B7 <res 00000001> <1> NumBufEnd resb 1 ; Last byte in NumBuf
5684 000008B8 <res 00000004> <1> FBytes resd 1 ; Number of bytes left in getc file
5685 000008BC <res 00000004> <1> FSectors resd 1 ; Number of sectors in getc file
5686 000008C0 <res 00000002> <1> FNextClust resw 1 ; Pointer to next cluster in d:o
5687 000008C2 <res 00000002> <1> FPtr resw 1 ; Pointer to next char in buffer
5688 <1>
5689 <1> ;
5690 <1> ; unhexchar: Convert a hexadecimal digit in AL to the equivalent number;
5691 <1> ; return CF=1 if not a hex digit
5692 <1> ;
5693 <1> section .text
5694 <1> unhexchar:
5695 00001B78 3C30 <1> cmp al,'0'
5696 00001B7A 7215 <1> jb .ret ; If failure, CF == 1 already
5697 00001B7C 3C39 <1> cmp al,'9'
5698 00001B7E 7703 <1> ja .notdigit
5699 00001B80 2C30 <1> sub al,'0' ; CF <- 0
5700 00001B82 C3 <1> ret
5701 00001B83 0C20 <1> .notdigit: or al,20h ; upper case -> lower case
5702 00001B85 3C61 <1> cmp al,'a'
5703 00001B87 7208 <1> jb .ret ; If failure, CF == 1 already
5704 00001B89 3C66 <1> cmp al,'f'
5705 00001B8B 7703 <1> ja .err
5706 00001B8D 2C57 <1> sub al,'a'-10 ; CF <- 0
5707 00001B8F C3 <1> ret
5708 00001B90 F9 <1> .err: stc
5709 00001B91 C3 <1> .ret: ret
5710 <1>
5711 <1> ;
5712 <1> ;
5713 <1> ; getline: Get a command line, converting control characters to spaces
5714 <1> ; and collapsing streches to one; a space is appended to the
5715 <1> ; end of the string, unless the line is empty.
5716 <1> ; The line is terminated by ^J, ^Z or EOF and is written
5717 <1> ; to ES:DI. On return, DI points to first char after string.
5718 <1> ; CF is set if we hit EOF.
5719 <1> ;
5720 <1> getline:
5721 00001B92 E830FF <1> call skipspace
5722 00001B95 B201 <1> mov dl,1 ; Empty line -> empty string.
5723 00001B97 742B <1> jz .eof ; eof
5724 00001B99 7226 <1> jc .eoln ; eoln
5725 00001B9B E816FF <1> call ungetc
5726 00001B9E 52 <1> .fillloop: push dx
5727 00001B9F 57 <1> push di
5728 00001BA0 E8C8FE <1> call getc
5729 00001BA3 5F <1> pop di
5730 00001BA4 5A <1> pop dx
5731 00001BA5 721E <1> jc .ret ; CF set!
5732 00001BA7 3C20 <1> cmp al,' '
5733 00001BA9 7605 <1> jna .ctrl
5734 00001BAB 31D2 <1> xor dx,dx
5735 00001BAD AA <1> .store: stosb
5736 00001BAE EBEE <1> jmp short .fillloop
5737 00001BB0 3C0A <1> .ctrl: cmp al,10
5738 00001BB2 7411 <1> je .ret ; CF clear!
5739 00001BB4 3C1A <1> cmp al,26
5740 00001BB6 740C <1> je .eof
5741 00001BB8 20D2 <1> and dl,dl
5742 00001BBA 75E2 <1> jnz .fillloop ; Ignore multiple spaces
5743 00001BBC B020 <1> mov al,' ' ; Ctrl -> space
5744 00001BBE 42 <1> inc dx
5745 00001BBF EBEC <1> jmp short .store
5746 00001BC1 F8 <1> .eoln: clc ; End of line is not end of file
5747 00001BC2 EB01 <1> jmp short .ret
5748 00001BC4 F9 <1> .eof: stc
5749 00001BC5 9C <1> .ret: pushf ; We want the last char to be space!
5750 00001BC6 20D2 <1> and dl,dl
5751 00001BC8 7503 <1> jnz .xret
5752 00001BCA B020 <1> mov al,' '
5753 00001BCC AA <1> stosb
5754 00001BCD 9D <1> .xret: popf
5755 00001BCE C3 <1> ret
5756 %include "conio.inc" ; Console I/O
5757 <1> ;; $Id: conio.inc,v 1.13 2005/06/16 04:39:19 hpa Exp $
5758 <1> ;; -----------------------------------------------------------------------
5759 <1> ;;
5760 <1> ;; Copyright 1994-2005 H. Peter Anvin - All Rights Reserved
5761 <1> ;;
5762 <1> ;; This program is free software; you can redistribute it and/or modify
5763 <1> ;; it under the terms of the GNU General Public License as published by
5764 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
5765 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
5766 <1> ;; (at your option) any later version; incorporated herein by reference.
5767 <1> ;;
5768 <1> ;; -----------------------------------------------------------------------
5769 <1>
5770 <1> ;;
5771 <1> ;; conio.inc
5772 <1> ;;
5773 <1> ;; Console I/O code, except:
5774 <1> ;; writechr, writestr - module-dependent
5775 <1> ;; cwritestr, crlf - writestr.inc
5776 <1> ;; writehex* - writehex.inc
5777 <1> ;;
5778 <1>
5779 <1> ;
5780 <1> ; loadkeys: Load a LILO-style keymap; SI and DX:AX set by searchdir
5781 <1> ;
5782 <1> section .text
5783 <1>
5784 <1> loadkeys:
5785 00001BCF 21D2 <1> and dx,dx ; Should be 256 bytes exactly
5786 00001BD1 751A <1> jne loadkeys_ret
5787 00001BD3 3D0001 <1> cmp ax,256
5788 00001BD6 7515 <1> jne loadkeys_ret
5789 <1>
5790 00001BD8 BB[0000] <1> mov bx,trackbuf
5791 00001BDB B90100 <1> mov cx,1 ; 1 cluster should be >= 256 bytes
5792 00001BDE E8DDF9 <1> call getfssec
5793 <1>
5794 00001BE1 BE[0000] <1> mov si,trackbuf
5795 00001BE4 BF[DC15] <1> mov di,KbdMap
5796 00001BE7 B94000 <1> mov cx,256 >> 2
5797 00001BEA F366A5 <1> rep movsd
5798 <1>
5799 00001BED C3 <1> loadkeys_ret: ret
5800 <1>
5801 <1> ;
5802 <1> ; get_msg_file: Load a text file and write its contents to the screen,
5803 <1> ; interpreting color codes. Is called with SI and DX:AX
5804 <1> ; set by routine searchdir
5805 <1> ;
5806 <1> get_msg_file:
5807 00001BEE 06 <1> push es
5808 00001BEF 66C1E210 <1> shl edx,16 ; EDX <- DX:AX (length of file)
5809 00001BF3 89C2 <1> mov dx,ax
5810 00001BF5 B80020 <1> mov ax,xfer_buf_seg ; Use for temporary storage
5811 00001BF8 8EC0 <1> mov es,ax
5812 <1>
5813 00001BFA C606[CF08]07 <1> mov byte [TextAttribute],07h ; Default grey on white
5814 00001BFF C606[D008]07 <1> mov byte [DisplayMask],07h ; Display text in all modes
5815 00001C04 E87901 <1> call msg_initvars
5816 <1>
5817 00001C07 6652 <1> get_msg_chunk: push edx ; EDX = length of file
5818 00001C09 31DB <1> xor bx,bx ; == xbs_textbuf
5819 00001C0B 8B0E[0009] <1> mov cx,[BufSafe]
5820 00001C0F E8ACF9 <1> call getfssec
5821 00001C12 665A <1> pop edx
5822 00001C14 56 <1> push si ; Save current cluster
5823 00001C15 31F6 <1> xor si,si ; == xbs_textbuf
5824 00001C17 8B0E[0409] <1> mov cx,[BufSafeBytes] ; Number of bytes left in chunk
5825 <1> print_msg_file:
5826 00001C1B 51 <1> push cx
5827 00001C1C 6652 <1> push edx
5828 00001C1E 26AC <1> es lodsb
5829 00001C20 3C1A <1> cmp al,1Ah ; DOS EOF?
5830 00001C22 7418 <1> je msg_done_pop
5831 00001C24 56 <1> push si
5832 00001C25 8A0E[1001] <1> mov cl,[UsingVGA]
5833 00001C29 FEC1 <1> inc cl ; 01h = text mode, 02h = graphics
5834 00001C2B FF16[C408] <1> call [NextCharJump] ; Do what shall be done
5835 00001C2F 5E <1> pop si
5836 00001C30 665A <1> pop edx
5837 00001C32 59 <1> pop cx
5838 00001C33 664A <1> dec edx
5839 00001C35 7408 <1> jz msg_done
5840 00001C37 E2E2 <1> loop print_msg_file
5841 00001C39 5E <1> pop si
5842 00001C3A EBCB <1> jmp short get_msg_chunk
5843 <1> msg_done_pop:
5844 00001C3C 83C406 <1> add sp,byte 6 ; Drop pushed EDX, CX
5845 <1> msg_done:
5846 00001C3F 5E <1> pop si
5847 00001C40 07 <1> pop es
5848 00001C41 C3 <1> ret
5849 <1> msg_putchar: ; Normal character
5850 00001C42 3C0F <1> cmp al,0Fh ; ^O = color code follows
5851 00001C44 7467 <1> je msg_ctrl_o
5852 00001C46 3C0D <1> cmp al,0Dh ; Ignore <CR>
5853 00001C48 745A <1> je msg_ignore
5854 00001C4A 3C0A <1> cmp al,0Ah ; <LF> = newline
5855 00001C4C 7466 <1> je msg_newline
5856 00001C4E 3C0C <1> cmp al,0Ch ; <FF> = clear screen
5857 00001C50 0F849500 <1> je msg_formfeed
5858 00001C54 3C07 <1> cmp al,07h ; <BEL> = beep
5859 00001C56 744D <1> je msg_beep
5860 00001C58 3C19 <1> cmp al,19h ; <EM> = return to text mode
5861 00001C5A 0F840601 <1> je msg_novga
5862 00001C5E 3C18 <1> cmp al,18h ; <CAN> = VGA filename follows
5863 00001C60 0F84CF00 <1> je msg_vga
5864 00001C64 7306 <1> jnb .not_modectl
5865 00001C66 3C10 <1> cmp al,10h ; 10h to 17h are mode controls
5866 00001C68 0F832401 <1> jae msg_modectl
5867 <1> .not_modectl:
5868 <1>
5869 00001C6C E82801 <1> msg_normal: call write_serial_displaymask ; Write to serial port
5870 00001C6F 840E[D008] <1> test [DisplayMask],cl
5871 00001C73 742F <1> jz msg_ignore ; Not screen
5872 00001C75 F606[BE00]01 <1> test byte [DisplayCon],01h
5873 00001C7A 7428 <1> jz msg_ignore
5874 00001C7C 8A1E[CF08] <1> mov bl,[TextAttribute]
5875 00001C80 8A3E6204 <1> mov bh,[BIOS_page]
5876 00001C84 B409 <1> mov ah,09h ; Write character/attribute
5877 00001C86 B90100 <1> mov cx,1 ; One character only
5878 00001C89 CD10 <1> int 10h ; Write to screen
5879 00001C8B A0[C608] <1> mov al,[CursorCol]
5880 00001C8E 40 <1> inc ax
5881 00001C8F 3A06[C808] <1> cmp al,[VidCols]
5882 00001C93 7725 <1> ja msg_line_wrap ; Screen wraparound
5883 00001C95 A2[C608] <1> mov [CursorCol],al
5884 <1>
5885 00001C98 8A3E6204 <1> msg_gotoxy: mov bh,[BIOS_page]
5886 00001C9C 8B16[C608] <1> mov dx,[CursorDX]
5887 00001CA0 B402 <1> mov ah,02h ; Set cursor position
5888 00001CA2 CD10 <1> int 10h
5889 00001CA4 C3 <1> msg_ignore: ret
5890 <1>
5891 00001CA5 B8070E <1> msg_beep: mov ax,0E07h ; Beep
5892 00001CA8 31DB <1> xor bx,bx
5893 00001CAA CD10 <1> int 10h
5894 00001CAC C3 <1> ret
5895 <1>
5896 <1> msg_ctrl_o: ; ^O = color code follows
5897 00001CAD C706[C408][0A1D] <1> mov word [NextCharJump],msg_setbg
5898 00001CB3 C3 <1> ret
5899 <1> msg_newline: ; Newline char or end of line
5900 00001CB4 BE[E006] <1> mov si,crlf_msg
5901 00001CB7 E81001 <1> call write_serial_str_displaymask
5902 <1> msg_line_wrap: ; Screen wraparound
5903 00001CBA 840E[D008] <1> test [DisplayMask],cl
5904 00001CBE 74E4 <1> jz msg_ignore
5905 00001CC0 C606[C608]00 <1> mov byte [CursorCol],0
5906 00001CC5 A0[C708] <1> mov al,[CursorRow]
5907 00001CC8 40 <1> inc ax
5908 00001CC9 3A06[C908] <1> cmp al,[VidRows]
5909 00001CCD 7705 <1> ja msg_scroll
5910 00001CCF A2[C708] <1> mov [CursorRow],al
5911 00001CD2 EBC4 <1> jmp short msg_gotoxy
5912 00001CD4 31C9 <1> msg_scroll: xor cx,cx ; Upper left hand corner
5913 00001CD6 8B16[C808] <1> mov dx,[ScreenSize]
5914 00001CDA 8836[C708] <1> mov [CursorRow],dh ; New cursor at the bottom
5915 00001CDE 8A3E[C000] <1> mov bh,[ScrollAttribute]
5916 00001CE2 B80106 <1> mov ax,0601h ; Scroll up one line
5917 00001CE5 CD10 <1> int 10h
5918 00001CE7 EBAF <1> jmp short msg_gotoxy
5919 <1> msg_formfeed: ; Form feed character
5920 00001CE9 BE[E306] <1> mov si,crff_msg
5921 00001CEC E8DB00 <1> call write_serial_str_displaymask
5922 00001CEF 840E[D008] <1> test [DisplayMask],cl
5923 00001CF3 74AF <1> jz msg_ignore
5924 00001CF5 31C9 <1> xor cx,cx
5925 00001CF7 890E[C608] <1> mov [CursorDX],cx ; Upper lefthand corner
5926 00001CFB 8B16[C808] <1> mov dx,[ScreenSize]
5927 00001CFF 8A3E[CF08] <1> mov bh,[TextAttribute]
5928 00001D03 B80006 <1> mov ax,0600h ; Clear screen region
5929 00001D06 CD10 <1> int 10h
5930 00001D08 EB8E <1> jmp msg_gotoxy
5931 <1> msg_setbg: ; Color background character
5932 00001D0A E86BFE <1> call unhexchar
5933 00001D0D 722F <1> jc msg_color_bad
5934 00001D0F C0E004 <1> shl al,4
5935 00001D12 840E[D008] <1> test [DisplayMask],cl
5936 00001D16 7403 <1> jz .dontset
5937 00001D18 A2[CF08] <1> mov [TextAttribute],al
5938 <1> .dontset:
5939 00001D1B C706[C408][221D] <1> mov word [NextCharJump],msg_setfg
5940 00001D21 C3 <1> ret
5941 <1> msg_setfg: ; Color foreground character
5942 00001D22 E853FE <1> call unhexchar
5943 00001D25 7217 <1> jc msg_color_bad
5944 00001D27 840E[D008] <1> test [DisplayMask],cl
5945 00001D2B 7404 <1> jz .dontset
5946 00001D2D 0806[CF08] <1> or [TextAttribute],al ; setbg set foreground to 0
5947 <1> .dontset:
5948 00001D31 EB10 <1> jmp short msg_putcharnext
5949 <1> msg_vga:
5950 00001D33 C706[C408][4A1D] <1> mov word [NextCharJump],msg_filename
5951 00001D39 BF[791E] <1> mov di, VGAFileBuf
5952 00001D3C EB21 <1> jmp short msg_setvgafileptr
5953 <1>
5954 <1> msg_color_bad:
5955 00001D3E C606[CF08]07 <1> mov byte [TextAttribute],07h ; Default attribute
5956 <1> msg_putcharnext:
5957 00001D43 C706[C408][421C] <1> mov word [NextCharJump],msg_putchar
5958 00001D49 C3 <1> ret
5959 <1>
5960 <1> msg_filename: ; Getting VGA filename
5961 00001D4A 3C0A <1> cmp al,0Ah ; <LF> = end of filename
5962 00001D4C 741B <1> je msg_viewimage
5963 00001D4E 3C20 <1> cmp al,' '
5964 00001D50 7611 <1> jbe msg_ret ; Ignore space/control char
5965 00001D52 8B3E[661E] <1> mov di,[VGAFilePtr]
5966 00001D56 81FF[F91E] <1> cmp di,VGAFileBufEnd
5967 00001D5A 7307 <1> jnb msg_ret
5968 00001D5C 8805 <1> mov [di],al ; Can't use stosb (DS:)
5969 00001D5E 47 <1> inc di
5970 <1> msg_setvgafileptr:
5971 00001D5F 893E[661E] <1> mov [VGAFilePtr],di
5972 00001D63 C3 <1> msg_ret: ret
5973 <1>
5974 <1> msg_novga:
5975 00001D64 E8DE06 <1> call vgaclearmode
5976 00001D67 EB17 <1> jmp short msg_initvars
5977 <1>
5978 <1> msg_viewimage:
5979 00001D69 06 <1> push es
5980 00001D6A 1E <1> push ds
5981 00001D6B 07 <1> pop es ; ES <- DS
5982 00001D6C BE[791E] <1> mov si,VGAFileBuf
5983 00001D6F BF[F91E] <1> mov di,VGAFileMBuf
5984 00001D72 57 <1> push di
5985 00001D73 E8C5F7 <1> call mangle_name
5986 00001D76 5F <1> pop di
5987 00001D77 E863F5 <1> call searchdir
5988 00001D7A 07 <1> pop es
5989 00001D7B 74C6 <1> jz msg_putcharnext ; Not there
5990 00001D7D E83F05 <1> call vgadisplayfile
5991 <1> ; Fall through
5992 <1>
5993 <1> ; Subroutine to initialize variables, also needed
5994 <1> ; after loading a graphics file
5995 <1> msg_initvars:
5996 00001D80 60 <1> pusha
5997 00001D81 8A3E6204 <1> mov bh,[BIOS_page]
5998 00001D85 B403 <1> mov ah,03h ; Read cursor position
5999 00001D87 CD10 <1> int 10h
6000 00001D89 8916[C608] <1> mov [CursorDX],dx
6001 00001D8D 61 <1> popa
6002 00001D8E EBB3 <1> jmp short msg_putcharnext ; Initialize state machine
6003 <1>
6004 <1> msg_modectl:
6005 00001D90 2407 <1> and al,07h
6006 00001D92 A2[D008] <1> mov [DisplayMask],al
6007 00001D95 EBAC <1> jmp short msg_putcharnext
6008 <1>
6009 <1> ;
6010 <1> ; write_serial: If serial output is enabled, write character on serial port
6011 <1> ; write_serial_displaymask: d:o, but ignore if DisplayMask & 04h == 0
6012 <1> ;
6013 <1> write_serial_displaymask:
6014 00001D97 F606[D008]04 <1> test byte [DisplayMask], 04h
6015 00001D9C 742B <1> jz write_serial.end
6016 <1> write_serial:
6017 00001D9E 669C <1> pushfd
6018 00001DA0 6660 <1> pushad
6019 00001DA2 8B1E[F600] <1> mov bx,[SerialPort]
6020 00001DA6 21DB <1> and bx,bx
6021 00001DA8 741B <1> je .noserial
6022 00001DAA 50 <1> push ax
6023 00001DAB 8A26[CD08] <1> mov ah,[FlowInput]
6024 <1> .waitspace:
6025 <1> ; Wait for space in transmit register
6026 00001DAF 8D5705 <1> lea dx,[bx+5] ; DX -> LSR
6027 00001DB2 EC <1> in al,dx
6028 00001DB3 A820 <1> test al,20h
6029 00001DB5 74F8 <1> jz .waitspace
6030 <1>
6031 <1> ; Wait for input flow control
6032 00001DB7 42 <1> inc dx ; DX -> MSR
6033 00001DB8 EC <1> in al,dx
6034 00001DB9 20E0 <1> and al,ah
6035 00001DBB 38E0 <1> cmp al,ah
6036 00001DBD 75F0 <1> jne .waitspace
6037 <1> .no_flow:
6038 <1>
6039 00001DBF 87D3 <1> xchg dx,bx ; DX -> THR
6040 00001DC1 58 <1> pop ax
6041 00001DC2 E8(C600) <1> call slow_out ; Send data
6042 00001DC5 6661 <1> .noserial: popad
6043 00001DC7 669D <1> popfd
6044 00001DC9 C3 <1> .end: ret
6045 <1>
6046 <1> ;
6047 <1> ; write_serial_str: write_serial for strings
6048 <1> ; write_serial_str_displaymask: d:o, but ignore if DisplayMask & 04h == 0
6049 <1> ;
6050 <1> write_serial_str_displaymask:
6051 00001DCA F606[D008]04 <1> test byte [DisplayMask], 04h
6052 00001DCF 740A <1> jz write_serial_str.end
6053 <1>
6054 <1> write_serial_str:
6055 00001DD1 AC <1> .loop lodsb
6056 00001DD2 20C0 <1> and al,al
6057 00001DD4 7405 <1> jz .end
6058 00001DD6 E8C5FF <1> call write_serial
6059 00001DD9 EBF6 <1> jmp short .loop
6060 00001DDB C3 <1> .end: ret
6061 <1>
6062 <1> ;
6063 <1> ; pollchar: check if we have an input character pending (ZF = 0)
6064 <1> ;
6065 <1> pollchar:
6066 00001DDC 6660 <1> pushad
6067 00001DDE B411 <1> mov ah,11h ; Poll keyboard
6068 00001DE0 CD16 <1> int 16h
6069 00001DE2 751F <1> jnz .done ; Keyboard response
6070 00001DE4 8B16[F600] <1> mov dx,[SerialPort]
6071 00001DE8 21D2 <1> and dx,dx
6072 00001DEA 7417 <1> jz .done ; No serial port -> no input
6073 00001DEC 83C205 <1> add dx,byte 5 ; DX -> LSR
6074 00001DEF EC <1> in al,dx
6075 00001DF0 A801 <1> test al,1 ; ZF = 0 if data pending
6076 00001DF2 740F <1> jz .done
6077 00001DF4 42 <1> inc dx ; DX -> MSR
6078 00001DF5 8A26[CE08] <1> mov ah,[FlowIgnore] ; Required status bits
6079 00001DF9 EC <1> in al,dx
6080 00001DFA 20E0 <1> and al,ah
6081 00001DFC 38E0 <1> cmp al,ah
6082 00001DFE 0F95C0 <1> setne al
6083 00001E01 FEC8 <1> dec al ; Set ZF = 0 if equal
6084 00001E03 6661 <1> .done: popad
6085 00001E05 C3 <1> ret
6086 <1>
6087 <1> ;
6088 <1> ; getchar: Read a character from keyboard or serial port
6089 <1> ;
6090 <1> getchar:
6091 <1> RESET_IDLE
6092 00001E06 E8DEFB <2> call reset_idle
6093 <1> .again:
6094 <1> DO_IDLE
6095 00001E09 E8E6FB <2> call check_for_arp
6096 00001E0C B411 <1> mov ah,11h ; Poll keyboard
6097 00001E0E CD16 <1> int 16h
6098 00001E10 7522 <1> jnz .kbd ; Keyboard input?
6099 00001E12 8B1E[F600] <1> mov bx,[SerialPort]
6100 00001E16 21DB <1> and bx,bx
6101 00001E18 74EF <1> jz .again
6102 00001E1A 8D5705 <1> lea dx,[bx+5] ; DX -> LSR
6103 00001E1D EC <1> in al,dx
6104 00001E1E A801 <1> test al,1
6105 00001E20 74E7 <1> jz .again
6106 00001E22 42 <1> inc dx ; DX -> MSR
6107 00001E23 8A26[CE08] <1> mov ah,[FlowIgnore]
6108 00001E27 EC <1> in al,dx
6109 00001E28 20E0 <1> and al,ah
6110 00001E2A 38E0 <1> cmp al,ah
6111 00001E2C 75DB <1> jne .again
6112 00001E2E 30E4 <1> .serial: xor ah,ah ; Avoid confusion
6113 00001E30 87D3 <1> xchg dx,bx ; Data port
6114 00001E32 EC <1> in al,dx
6115 00001E33 C3 <1> ret
6116 00001E34 B410 <1> .kbd: mov ah,10h ; Get keyboard input
6117 00001E36 CD16 <1> int 16h
6118 00001E38 3CE0 <1> cmp al,0E0h
6119 00001E3A 7502 <1> jnz .not_ext
6120 00001E3C 30C0 <1> xor al,al
6121 <1> .not_ext:
6122 00001E3E 20C0 <1> and al,al
6123 00001E40 7404 <1> jz .func_key
6124 00001E42 BB[DC15] <1> mov bx,KbdMap ; Convert character sets
6125 00001E45 D7 <1> xlatb
6126 00001E46 C3 <1> .func_key: ret
6127 <1>
6128 <1> %ifdef DEBUG_TRACERS
6129 <1> ;
6130 <1> ; debug hack to print a character with minimal code impact
6131 <1> ;
6132 <1> debug_tracer: pushad
6133 <1> pushfd
6134 <1> mov bp,sp
6135 <1> mov bx,[bp+9*4] ; Get return address
6136 <1> mov al,[cs:bx] ; Get data byte
6137 <1> inc word [bp+9*4] ; Return to after data byte
6138 <1> call writechr
6139 <1> popfd
6140 <1> popad
6141 <1> ret
6142 <1> %endif ; DEBUG_TRACERS
6143 <1>
6144 <1> section .data
6145 <1> ; This is a word to pc_setint16 can set it
6146 000000BE 0100 <1> DisplayCon dw 01h ; Console display enabled
6147 <1>
6148 000000C0 07 <1> ScrollAttribute db 07h ; Grey on white (normal text color)
6149 <1>
6150 <1> section .bss
6151 <1> alignb 2
6152 000008C4 <res 00000002> <1> NextCharJump resw 1 ; Routine to interpret next print char
6153 <1> CursorDX equ $
6154 000008C6 <res 00000001> <1> CursorCol resb 1 ; Cursor column for message file
6155 000008C7 <res 00000001> <1> CursorRow resb 1 ; Cursor row for message file
6156 <1> ScreenSize equ $
6157 000008C8 <res 00000001> <1> VidCols resb 1 ; Columns on screen-1
6158 000008C9 <res 00000001> <1> VidRows resb 1 ; Rows on screen-1
6159 <1>
6160 <1> ; Serial console stuff...
6161 000008CA <res 00000002> <1> BaudDivisor resw 1 ; Baud rate divisor
6162 <1> FlowControl equ $
6163 000008CC <res 00000001> <1> FlowOutput resb 1 ; Outputs to assert for serial flow
6164 000008CD <res 00000001> <1> FlowInput resb 1 ; Input bits for serial flow
6165 000008CE <res 00000001> <1> FlowIgnore resb 1 ; Ignore input unless these bits set
6166 <1>
6167 000008CF <res 00000001> <1> TextAttribute resb 1 ; Text attribute for message file
6168 000008D0 <res 00000001> <1> DisplayMask resb 1 ; Display modes mask
6169 %include "writestr.inc" ; String output
6170 <1> ;; $Id: writestr.inc,v 1.5 2005/01/18 13:13:50 hpa Exp $
6171 <1> ;; -----------------------------------------------------------------------
6172 <1> ;;
6173 <1> ;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
6174 <1> ;;
6175 <1> ;; This program is free software; you can redistribute it and/or modify
6176 <1> ;; it under the terms of the GNU General Public License as published by
6177 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
6178 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
6179 <1> ;; (at your option) any later version; incorporated herein by reference.
6180 <1> ;;
6181 <1> ;; -----------------------------------------------------------------------
6182 <1>
6183 <1> ;;
6184 <1> ;; writestr.inc
6185 <1> ;;
6186 <1> ;; Code to write a simple string.
6187 <1> ;;
6188 <1>
6189 <1> section .text
6190 <1> ;
6191 <1> ; crlf: Print a newline
6192 <1> ;
6193 00001E47 50 <1> crlf: push ax
6194 00001E48 B00D <1> mov al,CR
6195 00001E4A E83807 <1> call writechr
6196 00001E4D B00A <1> mov al,LF
6197 00001E4F E83307 <1> call writechr
6198 00001E52 58 <1> pop ax
6199 00001E53 C3 <1> ret
6200 <1>
6201 <1> ;
6202 <1> ; cwritestr: write a null-terminated string to the console, saving
6203 <1> ; registers on entry.
6204 <1> ;
6205 <1> ; Note: writestr and cwritestr are distinct in SYSLINUX (only)
6206 <1> ;
6207 <1> cwritestr:
6208 00001E54 669C <1> pushfd
6209 00001E56 6660 <1> pushad
6210 00001E58 AC <1> .top: lodsb
6211 00001E59 20C0 <1> and al,al
6212 00001E5B 7405 <1> jz .end
6213 00001E5D E82507 <1> call writechr
6214 00001E60 EBF6 <1> jmp short .top
6215 00001E62 6661 <1> .end: popad
6216 00001E64 669D <1> popfd
6217 00001E66 C3 <1> ret
6218 writestr equ cwritestr
6219 %include "writehex.inc" ; Hexadecimal output
6220 <1> ;; $Id: writehex.inc,v 1.3 2005/01/18 13:13:50 hpa Exp $
6221 <1> ;; -----------------------------------------------------------------------
6222 <1> ;;
6223 <1> ;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
6224 <1> ;;
6225 <1> ;; This program is free software; you can redistribute it and/or modify
6226 <1> ;; it under the terms of the GNU General Public License as published by
6227 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
6228 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
6229 <1> ;; (at your option) any later version; incorporated herein by reference.
6230 <1> ;;
6231 <1> ;; -----------------------------------------------------------------------
6232 <1>
6233 <1> ;;
6234 <1> ;; writehex.inc
6235 <1> ;;
6236 <1> ;; Write hexadecimal numbers to the console
6237 <1> ;;
6238 <1>
6239 <1> section .text
6240 <1> ;
6241 <1> ; writehex[248]: Write a hex number in (AL, AX, EAX) to the console
6242 <1> ;
6243 <1> writehex2:
6244 00001E67 669C <1> pushfd
6245 00001E69 6660 <1> pushad
6246 00001E6B 66C1C018 <1> rol eax,24
6247 00001E6F B90200 <1> mov cx,2
6248 00001E72 EB14 <1> jmp short writehex_common
6249 <1> writehex4:
6250 00001E74 669C <1> pushfd
6251 00001E76 6660 <1> pushad
6252 00001E78 66C1C010 <1> rol eax,16
6253 00001E7C B90400 <1> mov cx,4
6254 00001E7F EB07 <1> jmp short writehex_common
6255 <1> writehex8:
6256 00001E81 669C <1> pushfd
6257 00001E83 6660 <1> pushad
6258 00001E85 B90800 <1> mov cx,8
6259 <1> writehex_common:
6260 00001E88 66C1C004 <1> .loop: rol eax,4
6261 00001E8C 6650 <1> push eax
6262 00001E8E 240F <1> and al,0Fh
6263 00001E90 3C0A <1> cmp al,10
6264 00001E92 7304 <1> jae .high
6265 00001E94 0430 <1> .low: add al,'0'
6266 00001E96 EB02 <1> jmp short .ischar
6267 00001E98 0437 <1> .high: add al,'A'-10
6268 00001E9A E8E806 <1> .ischar: call writechr
6269 00001E9D 6658 <1> pop eax
6270 00001E9F E2E7 <1> loop .loop
6271 00001EA1 6661 <1> popad
6272 00001EA3 669D <1> popfd
6273 00001EA5 C3 <1> ret
6274 <1>
6275 %include "parseconfig.inc" ; High-level config file handling
6276 <1> ;; $Id: parseconfig.inc,v 1.22 2005/04/06 09:53:39 hpa Exp $
6277 <1> ;; -----------------------------------------------------------------------
6278 <1> ;;
6279 <1> ;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved
6280 <1> ;;
6281 <1> ;; This program is free software; you can redistribute it and/or modify
6282 <1> ;; it under the terms of the GNU General Public License as published by
6283 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
6284 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
6285 <1> ;; (at your option) any later version; incorporated herein by reference.
6286 <1> ;;
6287 <1> ;; -----------------------------------------------------------------------
6288 <1>
6289 <1> ;;
6290 <1> ;; parseconfig.inc
6291 <1> ;;
6292 <1> ;; Configuration file operations
6293 <1> ;;
6294 <1>
6295 <1> section .text
6296 <1> ;
6297 <1> ; "default" command
6298 <1> ;
6299 00001EA6 BF[D80A] <1> pc_default: mov di,default_cmd
6300 00001EA9 E8E6FC <1> call getline
6301 00001EAC C645FF00 <1> mov byte [di-1],0 ; null-terminate
6302 00001EB0 C3 <1> ret
6303 <1>
6304 <1> ;
6305 <1> ; "ontimeout" command
6306 <1> ;
6307 00001EB1 BF[DC11] <1> pc_ontimeout: mov di,Ontimeout
6308 00001EB4 E8DBFC <1> call getline
6309 00001EB7 81EF[DD11] <1> sub di,Ontimeout+1 ; Don't need final space
6310 00001EBB 893E[E800] <1> mov [OntimeoutLen],di
6311 00001EBF C3 <1> ret
6312 <1>
6313 <1> ;
6314 <1> ; "onerror" command
6315 <1> ;
6316 00001EC0 BF[DC13] <1> pc_onerror: mov di,Onerror
6317 00001EC3 E8CCFC <1> call getline
6318 00001EC6 81EF[DC13] <1> sub di,Onerror
6319 00001ECA 893E[EA00] <1> mov [OnerrorLen],di
6320 00001ECE C3 <1> ret
6321 <1>
6322 <1> ;
6323 <1> ; "append" command
6324 <1> ;
6325 00001ECF 803E[FA00]00 <1> pc_append: cmp byte [VKernel],0
6326 00001ED4 770F <1> ja .vk
6327 00001ED6 BF[DC0F] <1> mov di,AppendBuf
6328 00001ED9 E8B6FC <1> call getline
6329 00001EDC 81EF[DC0F] <1> sub di,AppendBuf
6330 00001EE0 893E[E600] <1> .app1: mov [AppendLen],di
6331 00001EE4 C3 <1> ret
6332 00001EE5 BF[DC0D] <1> .vk: mov di,VKernelBuf+vk_append ; "append" command (vkernel)
6333 00001EE8 E8A7FC <1> call getline
6334 00001EEB 81EF[DC0D] <1> sub di,VKernelBuf+vk_append
6335 00001EEF 83FF02 <1> cmp di,byte 2
6336 00001EF2 7509 <1> jne .app2
6337 00001EF4 803E[DC0D]2D <1> cmp byte [VKernelBuf+vk_append],'-'
6338 00001EF9 7502 <1> jne .app2
6339 00001EFB 31FF <1> xor di,di ; If "append -" -> null string
6340 00001EFD 893E[DA0D] <1> .app2: mov [VKernelBuf+vk_appendlen],di
6341 00001F01 C3 <1> ret
6342 <1>
6343 <1> ;
6344 <1> ; "ipappend" command (PXELINUX only)
6345 <1> ;
6346 <1> %if IS_PXELINUX
6347 00001F02 E8D9FB <1> pc_ipappend: call getint
6348 00001F05 720B <1> jc .err
6349 00001F07 803E[FA00]00 <1> cmp byte [VKernel],0
6350 00001F0C 7505 <1> jne .vk
6351 00001F0E 881E[0809] <1> mov [IPAppend],bl
6352 00001F12 C3 <1> .err: ret
6353 00001F13 881E[D80D] <1> .vk: mov [VKernelBuf+vk_ipappend],bl
6354 00001F17 C3 <1> ret
6355 <1> %endif
6356 <1>
6357 <1> ;
6358 <1> ; "localboot" command (PXELINUX, ISOLINUX)
6359 <1> ;
6360 <1> %if IS_PXELINUX || IS_ISOLINUX
6361 00001F18 E8C3FB <1> pc_localboot: call getint
6362 00001F1B 803E[FA00]00 <1> cmp byte [VKernel],0 ; ("label" section only)
6363 00001F20 740E <1> je .err
6364 00001F22 BF[580D] <1> mov di,VKernelBuf+vk_rname
6365 00001F25 31C0 <1> xor ax,ax
6366 00001F27 B98000 <1> mov cx,FILENAME_MAX
6367 00001F2A F3AA <1> rep stosb ; Null kernel name
6368 <1> %if IS_PXELINUX
6369 <1> ; PXELINUX uses the first 4 bytes of vk_rname for the
6370 <1> ; mangled IP address
6371 00001F2C 891E[5D0D] <1> mov [VKernelBuf+vk_rname+5], bx ; Return type
6372 <1> %else
6373 <1> mov [VKernelBuf+vk_rname+1], bx ; Return type
6374 <1> %endif
6375 00001F30 C3 <1> .err: ret
6376 <1> %endif
6377 <1>
6378 <1> ;
6379 <1> ; "kernel" command
6380 00001F31 803E[FA00]00 <1> pc_kernel: cmp byte [VKernel],0
6381 00001F36 7409 <1> je .err ; ("label" section only)
6382 00001F38 E84001 <1> call pc_getline
6383 00001F3B BF[580D] <1> mov di,VKernelBuf+vk_rname
6384 00001F3E E8FAF5 <1> call mangle_name
6385 00001F41 C3 <1> .err: ret
6386 <1>
6387 <1> ;
6388 <1> ; "timeout" command
6389 <1> ;
6390 00001F42 E899FB <1> pc_timeout: call getint
6391 00001F45 720B <1> jc .err
6392 00001F47 B815D2 <1> mov ax,0D215h ; There are approx 1.D215h
6393 00001F4A F7E3 <1> mul bx ; clock ticks per 1/10 s
6394 00001F4C 01D3 <1> add bx,dx
6395 00001F4E 891E[EC00] <1> mov [KbdTimeOut],bx
6396 00001F52 C3 <1> .err: ret
6397 <1>
6398 <1> ;
6399 <1> ; Generic integer variable setting commands:
6400 <1> ; "prompt", "implicit"
6401 <1> ;
6402 <1> pc_setint16:
6403 00001F53 50 <1> push ax
6404 00001F54 E887FB <1> call getint
6405 00001F57 5E <1> pop si
6406 00001F58 7202 <1> jc .err
6407 00001F5A 891C <1> mov [si],bx
6408 00001F5C C3 <1> .err: ret
6409 <1>
6410 <1> ;
6411 <1> ; Generic file-processing commands:
6412 <1> ; "display", "font", "kbdmap"
6413 <1> ;
6414 00001F5D 50 <1> pc_filecmd: push ax ; Function to tailcall
6415 00001F5E E81A01 <1> call pc_getline
6416 00001F61 BF[601D] <1> mov di,MNameBuf
6417 00001F64 57 <1> push di
6418 00001F65 E8D3F5 <1> call mangle_name
6419 00001F68 5F <1> pop di
6420 00001F69 E871F3 <1> call searchdir ; tailcall
6421 00001F6C 7501 <1> jnz .ok
6422 00001F6E 58 <1> pop ax ; Drop the successor function
6423 00001F6F C3 <1> .ok: ret ; Tailcall if OK, error return
6424 <1>
6425 <1> ;
6426 <1> ; "serial" command
6427 <1> ;
6428 00001F70 E86BFB <1> pc_serial: call getint
6429 00001F73 7207 <1> jc .err
6430 00001F75 53 <1> push bx ; Serial port #
6431 00001F76 E84CFB <1> call skipspace
6432 00001F79 7302 <1> jnc .ok
6433 00001F7B 5B <1> pop bx
6434 00001F7C C3 <1> .err: ret
6435 <1> .ok:
6436 00001F7D E834FB <1> call ungetc
6437 00001F80 E85BFB <1> call getint
6438 00001F83 C706[CC08]0000 <1> mov [FlowControl], word 0 ; Default to no flow control
6439 00001F89 7229 <1> jc .nobaud
6440 <1> .valid_baud:
6441 00001F8B 6653 <1> push ebx
6442 00001F8D E835FB <1> call skipspace
6443 00001F90 7208 <1> jc .no_flow
6444 00001F92 E81FFB <1> call ungetc
6445 00001F95 E846FB <1> call getint ; Hardware flow control?
6446 00001F98 7302 <1> jnc .valid_flow
6447 <1> .no_flow:
6448 00001F9A 31DB <1> xor bx,bx ; Default -> no flow control
6449 <1> .valid_flow:
6450 00001F9C 80E70F <1> and bh,0Fh ; FlowIgnore
6451 00001F9F C0E704 <1> shl bh,4
6452 00001FA2 883E[CE08] <1> mov [FlowIgnore],bh
6453 00001FA6 88DF <1> mov bh,bl
6454 00001FA8 81E303F0 <1> and bx,0F003h ; Valid bits
6455 00001FAC 891E[CC08] <1> mov [FlowControl],bx
6456 00001FB0 665B <1> pop ebx ; Baud rate
6457 00001FB2 EB06 <1> jmp short .parse_baud
6458 <1> .nobaud:
6459 00001FB4 66BB80250000 <1> mov ebx,DEFAULT_BAUD ; No baud rate given
6460 <1> .parse_baud:
6461 00001FBA 5F <1> pop di ; Serial port #
6462 00001FBB 6683FB4B <1> cmp ebx,byte 75
6463 00001FBF 72BB <1> jb .err ; < 75 baud == bogus
6464 00001FC1 66B800C20100 <1> mov eax,BAUD_DIVISOR
6465 00001FC7 6699 <1> cdq
6466 00001FC9 66F7F3 <1> div ebx
6467 00001FCC A3[CA08] <1> mov [BaudDivisor],ax
6468 00001FCF 50 <1> push ax ; Baud rate divisor
6469 00001FD0 83FF03 <1> cmp di,3
6470 00001FD3 7706 <1> ja .port_is_io ; If port > 3 then port is I/O addr
6471 00001FD5 D1E7 <1> shl di,1
6472 00001FD7 8BBD0004 <1> mov di,[di+serial_base] ; Get the I/O port from the BIOS
6473 <1> .port_is_io:
6474 00001FDB 893E[F600] <1> mov [SerialPort],di
6475 00001FDF 8D5503 <1> lea dx,[di+3] ; DX -> LCR
6476 00001FE2 B083 <1> mov al,83h ; Enable DLAB
6477 00001FE4 E8(C600) <1> call slow_out
6478 00001FE7 58 <1> pop ax ; Divisor
6479 00001FE8 89FA <1> mov dx,di ; DX -> LS
6480 00001FEA E8(C600) <1> call slow_out
6481 00001FED 42 <1> inc dx ; DX -> MS
6482 00001FEE 88E0 <1> mov al,ah
6483 00001FF0 E8(C600) <1> call slow_out
6484 00001FF3 B003 <1> mov al,03h ; Disable DLAB
6485 00001FF5 83C202 <1> add dx,byte 2 ; DX -> LCR
6486 00001FF8 E8(C600) <1> call slow_out
6487 00001FFB EC <1> in al,dx ; Read back LCR (detect missing hw)
6488 00001FFC 3C03 <1> cmp al,03h ; If nothing here we'll read 00 or FF
6489 00001FFE 7520 <1> jne .serial_port_bad ; Assume serial port busted
6490 00002000 83EA02 <1> sub dx,byte 2 ; DX -> IER
6491 00002003 30C0 <1> xor al,al ; IRQ disable
6492 00002005 E8(C600) <1> call slow_out
6493 <1>
6494 00002008 83C203 <1> add dx,byte 3 ; DX -> MCR
6495 0000200B EC <1> in al,dx
6496 0000200C 0A06[CC08] <1> or al,[FlowOutput] ; Assert bits
6497 00002010 E8(C600) <1> call slow_out
6498 <1>
6499 <1> ; Show some life
6500 00002013 BE[EE06] <1> mov si,syslinux_banner
6501 00002016 E8B8FD <1> call write_serial_str
6502 00002019 BE[4B01] <1> mov si,copyright_str
6503 0000201C E8B2FD <1> call write_serial_str
6504 0000201F C3 <1> ret
6505 <1>
6506 <1> .serial_port_bad:
6507 00002020 C706[F600]0000 <1> mov [SerialPort], word 0
6508 00002026 C3 <1> ret
6509 <1>
6510 <1> ;
6511 <1> ; "F"-key command
6512 <1> ;
6513 00002027 50 <1> pc_fkey: push ax
6514 00002028 E85000 <1> call pc_getline
6515 0000202B 5F <1> pop di
6516 0000202C E80CF5 <1> call mangle_name ; Mangle file name
6517 0000202F C3 <1> ret
6518 <1>
6519 <1> ;
6520 <1> ; "label" command
6521 <1> ;
6522 00002030 E86300 <1> pc_label: call commit_vk ; Commit any current vkernel
6523 00002033 BF[D80C] <1> mov di,VKernelBuf ; Erase the vkernelbuf for better compression
6524 00002036 B98201 <1> mov cx,(vk_size >> 1)
6525 00002039 31C0 <1> xor ax,ax
6526 0000203B F3AB <1> rep stosw
6527 0000203D E83B00 <1> call pc_getline
6528 00002040 BF[D80C] <1> mov di,VKernelBuf+vk_vname
6529 00002043 E8F5F4 <1> call mangle_name ; Mangle virtual name
6530 00002046 C606[FA00]01 <1> mov byte [VKernel],1 ; We've seen a "label" statement
6531 0000204B BE[D80C] <1> mov si,VKernelBuf+vk_vname ; By default, rname == vname
6532 0000204E BF[580D] <1> mov di,VKernelBuf+vk_rname
6533 00002051 B98000 <1> mov cx,FILENAME_MAX
6534 00002054 F3A4 <1> rep movsb
6535 00002056 BE[DC0F] <1> mov si,AppendBuf ; Default append==global append
6536 00002059 BF[DC0D] <1> mov di,VKernelBuf+vk_append
6537 0000205C 8B0E[E600] <1> mov cx,[AppendLen]
6538 00002060 890E[DA0D] <1> mov [VKernelBuf+vk_appendlen],cx
6539 00002064 F3A4 <1> rep movsb
6540 <1> %if IS_PXELINUX ; PXELINUX only
6541 00002066 A0[0809] <1> mov al,[IPAppend] ; Default ipappend==global ipappend
6542 00002069 A2[D80D] <1> mov [VKernelBuf+vk_ipappend],al
6543 <1> %endif
6544 0000206C C3 <1> ret
6545 <1>
6546 <1> ;
6547 <1> ; "say" command
6548 <1> ;
6549 0000206D E80B00 <1> pc_say: call pc_getline ; "say" command
6550 00002070 E8E1FD <1> call writestr
6551 00002073 E9D1FD <1> jmp crlf ; tailcall
6552 <1>
6553 <1> ;
6554 <1> ; "noescape" command
6555 <1> ;
6556 <1> pc_noescape:
6557 00002076 C606[8408]00 <1> mov byte [KbdFlags],0
6558 <1> ; Fall into pc_getline
6559 <1>
6560 <1> ;
6561 <1> ; Comment line
6562 <1> ;
6563 <1> pc_comment: ; Fall into pc_getline
6564 <1>
6565 <1> ;
6566 <1> ; Common subroutine: load line into trackbuf; returns with SI -> trackbuf
6567 <1> ;
6568 0000207B BF[0000] <1> pc_getline: mov di,trackbuf
6569 0000207E 57 <1> push di
6570 0000207F E810FB <1> call getline
6571 00002082 30C0 <1> xor al,al
6572 00002084 AA <1> stosb ; Null-terminate
6573 00002085 5E <1> pop si
6574 00002086 C3 <1> ret
6575 <1>
6576 <1> ;
6577 <1> ; Main loop for configuration file parsing
6578 <1> ;
6579 <1> parse_config:
6580 00002087 BF[D80C] <1> mov di,VKernelBuf ; Clear VKernelBuf at start
6581 0000208A 31C0 <1> xor ax,ax
6582 0000208C B90403 <1> mov cx,vk_size
6583 0000208F F3AA <1> rep stosb
6584 <1> .again:
6585 00002091 E8C400 <1> call getcommand
6586 00002094 73FB <1> jnc .again ; If not EOF do it again
6587 <1> ;
6588 <1> ; The fall through to commit_vk to commit any final
6589 <1> ; VKernel being read
6590 <1> ;
6591 <1> ;
6592 <1> ; commit_vk: Store the current VKernelBuf into buffer segment
6593 <1> ;
6594 <1> commit_vk:
6595 <1> ; For better compression, clean up the append field
6596 00002096 A1[DA0D] <1> mov ax,[VKernelBuf+vk_appendlen]
6597 00002099 BF[DC0D] <1> mov di,VKernelBuf+vk_append
6598 0000209C 01C7 <1> add di,ax
6599 0000209E B90002 <1> mov cx,max_cmd_len+1
6600 000020A1 29C1 <1> sub cx,ax
6601 000020A3 31C0 <1> xor ax,ax
6602 000020A5 F3AA <1> rep stosb
6603 <1>
6604 <1> ; Pack temporarily into trackbuf
6605 000020A7 BE[D80C] <1> mov si,VKernelBuf
6606 000020AA BF[0000] <1> mov di,trackbuf
6607 000020AD B90403 <1> mov cx,vk_size
6608 000020B0 E82100 <1> call rllpack
6609 <1> ; Now DX = number of bytes
6610 000020B3 8B3E[F800] <1> mov di,[VKernelBytes]
6611 000020B7 89D1 <1> mov cx,dx
6612 000020B9 01FA <1> add dx,di
6613 000020BB 7210 <1> jc .overflow ; If > 1 segment
6614 000020BD 8916[F800] <1> mov [VKernelBytes],dx
6615 000020C1 BE[0000] <1> mov si,trackbuf
6616 000020C4 06 <1> push es
6617 000020C5 680030 <1> push word vk_seg
6618 000020C8 07 <1> pop es
6619 000020C9 F3A4 <1> rep movsb
6620 000020CB 07 <1> pop es
6621 000020CC C3 <1> ret
6622 <1> .overflow:
6623 000020CD BE[C100] <1> mov si,vk_overflow_msg
6624 000020D0 E881FD <1> call writestr
6625 000020D3 C3 <1> ret
6626 <1>
6627 <1> section .data
6628 000000C1 4F7574206F66206D65- <1> vk_overflow_msg db 'Out of memory parsing config file', CR, LF, 0
6629 000000CA 6D6F72792070617273- <1>
6630 000000D3 696E6720636F6E6669- <1>
6631 000000DC 672066696C650D0A00 <1>
6632 <1>
6633 000000E5 00 <1> align 2, db 0
6634 000000E6 0000 <1> AppendLen dw 0 ; Bytes in append= command
6635 000000E8 0000 <1> OntimeoutLen dw 0 ; Bytes in ontimeout command
6636 000000EA 0000 <1> OnerrorLen dw 0 ; Bytes in onerror command
6637 000000EC 0000 <1> KbdTimeOut dw 0 ; Keyboard timeout (if any)
6638 000000EE 0090 <1> CmdLinePtr dw cmd_line_here ; Command line advancing pointer
6639 000000F0 0000 <1> ForcePrompt dw 0 ; Force prompt
6640 000000F2 0100 <1> AllowImplicit dw 1 ; Allow implicit kernels
6641 000000F4 0100 <1> AllowOptions dw 1 ; User-specified options allowed
6642 000000F6 0000 <1> SerialPort dw 0 ; Serial port base (or 0 for no serial port)
6643 000000F8 0000 <1> VKernelBytes dw 0 ; Number of bytes used by vkernels
6644 000000FA 00 <1> VKernel db 0 ; Have we seen any "label" statements?
6645 <1>
6646 <1> section .bss
6647 000008D1 <res 00000001>- <1> alignb 4 ; For the good of REP MOVSD
6648 000008D1 <rept> <1>
6649 000008D4 <res 00000201> <1> command_line resb max_cmd_len+2 ; Command line buffer
6650 00000AD5 <res 00000001>- <1> alignb 4
6651 00000AD5 <rept> <1>
6652 00000AD8 <res 00000200> <1> default_cmd resb max_cmd_len+1 ; "default" command line
6653 <1>
6654 <1> %include "rllpack.inc"
6655 <2> ; -*- fundamental -*-
6656 <2> ; -----------------------------------------------------------------------
6657 <2> ;
6658 <2> ; Copyright 2004 H. Peter Anvin - All Rights Reserved
6659 <2> ;
6660 <2> ; This program is free software; you can redistribute it and/or modify
6661 <2> ; it under the terms of the GNU General Public License as published by
6662 <2> ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
6663 <2> ; Boston MA 02111-1307, USA; either version 2 of the License, or
6664 <2> ; (at your option) any later version; incorporated herein by reference.
6665 <2> ;
6666 <2> ; -----------------------------------------------------------------------
6667 <2> ; $Id: rllpack.inc,v 1.2 2004/12/17 07:52:54 hpa Exp $
6668 <2>
6669 <2> ;
6670 <2> ; rllpack.inc
6671 <2> ;
6672 <2> ; Very simple RLL compressor/decompressor, used to pack binary structures
6673 <2> ; together.
6674 <2> ;
6675 <2> ; Format of leading byte
6676 <2> ; 1-128 = x verbatim bytes follow
6677 <2> ; 129-255 = (x-126) times subsequent byte
6678 <2> ; 0 = end of data
6679 <2> ;
6680 <2>
6681 <2> section .text
6682 <2>
6683 <2> ;
6684 <2> ; rllpack:
6685 <2> ; Pack CX bytes from DS:SI into ES:DI
6686 <2> ; Returns updated SI, DI and CX = number of bytes output
6687 <2> ;
6688 <2> rllpack:
6689 000020D4 50 <2> push ax
6690 000020D5 53 <2> push bx
6691 000020D6 51 <2> push cx
6692 000020D7 55 <2> push bp
6693 000020D8 57 <2> push di
6694 <2> .startseq:
6695 000020D9 31C0 <2> xor ax,ax ; Zero byte
6696 000020DB 31DB <2> xor bx,bx ; Run length zero
6697 000020DD 89FD <2> mov bp,di ; Pointer to header byte
6698 000020DF AA <2> stosb ; Store header byte (might be zero)
6699 000020E0 E349 <2> jcxz .done_null
6700 <2> .stdbyte:
6701 000020E2 AC <2> lodsb
6702 000020E3 AA <2> stosb
6703 000020E4 49 <2> dec cx
6704 000020E5 38C4 <2> cmp ah,al
6705 000020E7 740F <2> je .same
6706 <2> .diff:
6707 000020E9 88C4 <2> mov ah,al
6708 000020EB 31DB <2> xor bx,bx
6709 <2> .plainbyte:
6710 000020ED 43 <2> inc bx
6711 000020EE 26FE4600 <2> inc byte [es:bp]
6712 000020F2 E334 <2> jcxz .done
6713 000020F4 79EC <2> jns .stdbyte
6714 000020F6 EBE1 <2> jmp .startseq
6715 <2> .same:
6716 000020F8 80FB02 <2> cmp bl,2
6717 000020FB 72F0 <2> jb .plainbyte
6718 <2> ; 3 bytes or more in a row, time to convert sequence
6719 000020FD 26285E00 <2> sub byte [es:bp],bl
6720 00002101 7501 <2> jnz .normal
6721 00002103 4F <2> dec di ; We killed a whole stretch, remove start byte
6722 <2> .normal:
6723 00002104 43 <2> inc bx
6724 00002105 29DF <2> sub di,bx
6725 00002107 89FD <2> mov bp,di
6726 00002109 88D8 <2> mov al,bl
6727 0000210B 047E <2> add al,126
6728 0000210D AA <2> stosb
6729 0000210E 88E0 <2> mov al,ah
6730 00002110 AA <2> stosb
6731 <2> .getrun:
6732 00002111 E315 <2> jcxz .done
6733 00002113 80FB81 <2> cmp bl,255-126
6734 00002116 73C1 <2> jae .startseq
6735 00002118 AC <2> lodsb
6736 00002119 38E0 <2> cmp al,ah
6737 0000211B 7508 <2> jne .nomatch
6738 0000211D 43 <2> inc bx
6739 0000211E 26FE4600 <2> inc byte [es:bp]
6740 00002122 49 <2> dec cx
6741 00002123 EBEC <2> jmp .getrun
6742 <2> .nomatch:
6743 00002125 4E <2> dec si
6744 00002126 EBB1 <2> jmp .startseq
6745 <2> .done:
6746 00002128 30C0 <2> xor al,al
6747 0000212A AA <2> stosb
6748 <2> .done_null:
6749 0000212B 5A <2> pop dx
6750 0000212C 29FA <2> sub dx,di
6751 0000212E F7DA <2> neg dx
6752 00002130 5D <2> pop bp
6753 00002131 59 <2> pop cx
6754 00002132 5B <2> pop bx
6755 00002133 58 <2> pop ax
6756 00002134 C3 <2> ret
6757 <2> ;
6758 <2> ; rllunpack:
6759 <2> ; Unpack bytes from DS:SI into ES:DI
6760 <2> ; On return SI, DI are updated and CX contains number of bytes output
6761 <2> ;
6762 <2> rllunpack:
6763 00002135 50 <2> push ax
6764 00002136 57 <2> push di
6765 00002137 31C9 <2> xor cx,cx
6766 <2> .header:
6767 00002139 AC <2> lodsb
6768 0000213A 20C0 <2> and al,al
6769 0000213C 7413 <2> jz .done
6770 0000213E 3C81 <2> cmp al,129
6771 00002140 7306 <2> jae .isrun
6772 <2> ; Not a run
6773 00002142 88C1 <2> mov cl,al
6774 00002144 F3A4 <2> rep movsb
6775 00002146 EBF1 <2> jmp .header
6776 <2> .isrun:
6777 00002148 2C7E <2> sub al,126
6778 0000214A 88C1 <2> mov cl,al
6779 0000214C AC <2> lodsb
6780 0000214D F3AA <2> rep stosb
6781 0000214F EBE8 <2> jmp .header
6782 <2> .done:
6783 00002151 59 <2> pop cx
6784 00002152 29F9 <2> sub cx,di
6785 00002154 F7D9 <2> neg cx
6786 00002156 58 <2> pop ax
6787 00002157 C3 <2> ret
6788 %include "parsecmd.inc" ; Low-level config file handling
6789 <1> ;; $Id: parsecmd.inc,v 1.10 2004/12/21 06:30:55 hpa Exp $
6790 <1> ;; -----------------------------------------------------------------------
6791 <1> ;;
6792 <1> ;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
6793 <1> ;;
6794 <1> ;; This program is free software; you can redistribute it and/or modify
6795 <1> ;; it under the terms of the GNU General Public License as published by
6796 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
6797 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
6798 <1> ;; (at your option) any later version; incorporated herein by reference.
6799 <1> ;;
6800 <1> ;; -----------------------------------------------------------------------
6801 <1>
6802 <1> ;;
6803 <1> ;; parsecmd.inc
6804 <1> ;;
6805 <1> ;; Command line parser code
6806 <1> ;;
6807 <1>
6808 <1> section .text
6809 <1>
6810 <1> ; -------------------------------------------------------------------------
6811 <1> ; getcommand: Get a keyword from the current "getc" file and match it
6812 <1> ; against a list of keywords (keywd_table). Each entry in
6813 <1> ; that table should have the following form:
6814 <1> ; <32 bit hash value> <16 bit handler offset>
6815 <1> ;
6816 <1> ; The handler is called, and upon return this function
6817 <1> ; returns with CF = 0. On EOF, this function returns
6818 <1> ; with CF = 1.
6819 <1> ; -------------------------------------------------------------------------
6820 <1>
6821 <1> getcommand:
6822 <1> .find:
6823 00002158 E86AF9 <1> call skipspace ; Skip leading whitespace
6824 0000215B 7451 <1> jz .eof ; End of file
6825 0000215D 72F9 <1> jc .find ; End of line: try again
6826 <1>
6827 0000215F 0C20 <1> or al,20h ; Convert to lower case
6828 00002161 660FB6D8 <1> movzx ebx,al ; Hash for a one-char keyword
6829 <1> .read_loop:
6830 00002165 6653 <1> push ebx
6831 00002167 E801F9 <1> call getc
6832 0000216A 665B <1> pop ebx
6833 0000216C 7240 <1> jc .eof
6834 0000216E 3C20 <1> cmp al,' ' ; Whitespace
6835 00002170 760A <1> jbe .done
6836 00002172 0C20 <1> or al,20h
6837 00002174 66C1C305 <1> rol ebx,5
6838 00002178 30C3 <1> xor bl,al
6839 0000217A EBE9 <1> jmp short .read_loop
6840 0000217C E835F9 <1> .done: call ungetc
6841 0000217F E843F9 <1> call skipspace
6842 00002182 742A <1> jz .eof
6843 00002184 7219 <1> jc .noparm
6844 00002186 E82BF9 <1> call ungetc ; Return nonwhitespace char to buf
6845 00002189 BE[2807] <1> mov si,keywd_table
6846 0000218C B92000 <1> mov cx,keywd_count
6847 <1> .table_search:
6848 0000218F 66AD <1> lodsd
6849 00002191 6639C3 <1> cmp ebx,eax
6850 00002194 7413 <1> je .found_keywd
6851 00002196 66AD <1> lodsd ; Skip entrypoint/argument
6852 00002198 E2F5 <1> loop .table_search
6853 <1>
6854 <1> ; Otherwise unrecognized keyword
6855 0000219A BE[9E02] <1> mov si,err_badcfg
6856 0000219D EB05 <1> jmp short .error
6857 <1>
6858 <1> ; No parameter
6859 <1> .noparm:
6860 0000219F BE[C002] <1> mov si,err_noparm
6861 000021A2 B00A <1> mov al,10 ; Already at EOL
6862 <1> .error:
6863 000021A4 E8ADFC <1> call cwritestr
6864 000021A7 EB07 <1> jmp short .skipline
6865 <1>
6866 000021A9 AD <1> .found_keywd: lodsw ; Load argument into ax
6867 000021AA FF14 <1> call [si]
6868 000021AC F8 <1> clc
6869 000021AD C3 <1> ret
6870 <1>
6871 000021AE F9 <1> .eof: stc
6872 000021AF C3 <1> ret
6873 <1>
6874 000021B0 3C0A <1> .skipline: cmp al,10 ; Search for LF
6875 000021B2 74A4 <1> je .find
6876 000021B4 E8B4F8 <1> call getc
6877 000021B7 72F5 <1> jc .eof
6878 000021B9 EBF5 <1> jmp short .skipline
6879 <1>
6880 <1> section .bss
6881 <1> alignb 4
6882 <1> vk_size equ (vk_end + 3) & ~3
6883 00000CD8 <res 00000304> <1> VKernelBuf: resb vk_size ; "Current" vkernel
6884 00000FDC <res 00000200> <1> AppendBuf resb max_cmd_len+1 ; append=
6885 000011DC <res 00000200> <1> Ontimeout resb max_cmd_len+1 ; ontimeout
6886 000013DC <res 00000200> <1> Onerror resb max_cmd_len+1 ; onerror
6887 000015DC <res 00000100> <1> KbdMap resb 256 ; Keyboard map
6888 000016DC <res 00000500> <1> FKeyName resb 10*FILENAME_MAX ; File names for F-key help
6889 00001BDC <res 00000002> <1> KernelCNameLen resw 1 ; Length of unmangled kernel name
6890 00001BDE <res 00000002> <1> InitRDCNameLen resw 1 ; Length of unmangled initrd name
6891 <1> %if IS_SYSLINUX
6892 <1> KernelName resb FILENAME_MAX+1 ; Mangled name for kernel
6893 <1> KernelCName resb FILENAME_MAX+2 ; Unmangled kernel name
6894 <1> InitRDCName resb FILENAME_MAX+2 ; Unmangled initrd name
6895 <1> %else
6896 00001BE0 <res 00000080> <1> KernelName resb FILENAME_MAX ; Mangled name for kernel
6897 00001C60 <res 00000080> <1> KernelCName resb FILENAME_MAX ; Unmangled kernel name
6898 00001CE0 <res 00000080> <1> InitRDCName resb FILENAME_MAX ; Unmangled initrd name
6899 <1> %endif
6900 00001D60 <res 00000080> <1> MNameBuf resb FILENAME_MAX
6901 00001DE0 <res 00000080> <1> InitRD resb FILENAME_MAX
6902 %include "bcopy32.inc" ; 32-bit bcopy
6903 <1> ;; $Id: bcopy32.inc,v 1.16 2005/01/06 22:34:06 hpa Exp $
6904 <1> ;; -----------------------------------------------------------------------
6905 <1> ;;
6906 <1> ;; Copyright 1994-2005 H. Peter Anvin - All Rights Reserved
6907 <1> ;;
6908 <1> ;; This program is free software; you can redistribute it and/or modify
6909 <1> ;; it under the terms of the GNU General Public License as published by
6910 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
6911 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
6912 <1> ;; (at your option) any later version; incorporated herein by reference.
6913 <1> ;;
6914 <1> ;; -----------------------------------------------------------------------
6915 <1>
6916 <1> ;;
6917 <1> ;; bcopy32.inc
6918 <1> ;;
6919 <1> ;; 32-bit bcopy routine for real mode
6920 <1> ;;
6921 <1>
6922 <1> ;
6923 <1> ; 32-bit bcopy routine for real mode
6924 <1> ;
6925 <1> ; We enter protected mode, set up a flat 32-bit environment, run rep movsd
6926 <1> ; and then exit. IMPORTANT: This code assumes cs == 0.
6927 <1> ;
6928 <1> ; This code is probably excessively anal-retentive in its handling of
6929 <1> ; segments, but this stuff is painful enough as it is without having to rely
6930 <1> ; on everything happening "as it ought to."
6931 <1> ;
6932 <1> ; NOTE: this code is relocated into low memory, just after the .earlybss
6933 <1> ; segment, in order to support to "bcopy over self" operation.
6934 <1> ;
6935 <1>
6936 <1> section .bcopy32
6937 <1> align 8
6938 <1> __bcopy_start:
6939 <1>
6940 <1> ; This is in the .text segment since it needs to be
6941 <1> ; contiguous with the rest of the bcopy stuff
6942 <1>
6943 00000000 2F00 <1> bcopy_gdt: dw bcopy_gdt_size-1 ; Null descriptor - contains GDT
6944 00000002 [00000000] <1> dd bcopy_gdt ; pointer for LGDT instruction
6945 00000006 0000 <1> dw 0
6946 00000008 FFFF0000 <1> dd 0000ffffh ; Code segment, use16, readable,
6947 0000000C 009B0000 <1> dd 00009b00h ; present, dpl 0, cover 64K
6948 00000010 FFFF0000 <1> dd 0000ffffh ; Data segment, use16, read/write,
6949 00000014 00938F00 <1> dd 008f9300h ; present, dpl 0, cover all 4G
6950 00000018 FFFF0000 <1> dd 0000ffffh ; Data segment, use16, read/write,
6951 0000001C 00930000 <1> dd 00009300h ; present, dpl 0, cover 64K
6952 <1> ; The rest are used for COM32 only
6953 00000020 FFFF0000 <1> dd 0000ffffh ; Code segment, use32, readable,
6954 00000024 009BCF00 <1> dd 00cf9b00h ; present, dpl 0, cover all 4G
6955 00000028 FFFF0000 <1> dd 0000ffffh ; Data segment, use32, read/write,
6956 0000002C 0093CF00 <1> dd 00cf9300h ; present, dpl 0, cover all 4G
6957 <1> bcopy_gdt_size: equ $-bcopy_gdt
6958 <1>
6959 <1> ;
6960 <1> ; bcopy:
6961 <1> ; 32-bit copy, overlap safe
6962 <1> ;
6963 <1> ; Inputs:
6964 <1> ; ESI - source pointer
6965 <1> ; EDI - target pointer
6966 <1> ; ECX - byte count
6967 <1> ; DF - zero
6968 <1> ;
6969 <1> ; Outputs:
6970 <1> ; ESI - first byte after source
6971 <1> ; EDI - first byte after target
6972 <1> ; ECX - zero
6973 <1> ;
6974 00000030 6650 <1> bcopy: push eax
6975 00000032 6656 <1> push esi
6976 00000034 6657 <1> push edi
6977 00000036 6651 <1> push ecx
6978 00000038 9C <1> pushf ; Saves, among others, the IF flag
6979 00000039 1E <1> push ds
6980 0000003A 06 <1> push es
6981 <1>
6982 0000003B FA <1> cli
6983 0000003C E88D00 <1> call enable_a20
6984 <1>
6985 0000003F 662E0F0116[0000] <1> o32 lgdt [cs:bcopy_gdt]
6986 00000046 0F20C0 <1> mov eax,cr0
6987 00000049 0C01 <1> or al,1
6988 0000004B 0F22C0 <1> mov cr0,eax ; Enter protected mode
6989 0000004E EA[5300]0800 <1> jmp 08h:.in_pm
6990 <1>
6991 00000053 B81000 <1> .in_pm: mov ax,10h ; Data segment selector
6992 00000056 8EC0 <1> mov es,ax
6993 00000058 8ED8 <1> mov ds,ax
6994 <1>
6995 <1> ; Don't mess with ss, fs, and gs. They are never changed
6996 <1> ; and should be able to make it back out of protected mode.
6997 <1> ; This works because (and only because) we don't take
6998 <1> ; interrupt in protected mode.
6999 <1>
7000 0000005A 6639FE <1> cmp esi,edi ; If source > destination, we might
7001 0000005D 7713 <1> ja .reverse ; have to copy backwards
7002 <1>
7003 <1> .forward:
7004 0000005F 88C8 <1> mov al,cl ; Save low bits
7005 00000061 2403 <1> and al,3
7006 00000063 66C1E902 <1> shr ecx,2 ; Convert to dwords
7007 00000067 67F366A5 <1> a32 rep movsd ; Do our business
7008 <1> ; At this point ecx == 0
7009 <1>
7010 0000006B 88C1 <1> mov cl,al ; Copy any fractional dword
7011 0000006D 67F3A4 <1> a32 rep movsb
7012 00000070 EB2B <1> jmp .exit
7013 <1>
7014 <1> .reverse:
7015 00000072 FD <1> std ; Reverse copy
7016 00000073 66678D740EFF <1> lea esi,[esi+ecx-1] ; Point to final byte
7017 00000079 66678D7C0FFF <1> lea edi,[edi+ecx-1]
7018 0000007F 6689C8 <1> mov eax,ecx
7019 00000082 6683E103 <1> and ecx,3
7020 00000086 66C1E802 <1> shr eax,2
7021 0000008A 67F3A4 <1> a32 rep movsb
7022 <1>
7023 <1> ; Change ESI/EDI to point to the last dword, instead
7024 <1> ; of the last byte.
7025 0000008D 6683EE03 <1> sub esi,3
7026 00000091 6683EF03 <1> sub edi,3
7027 00000095 6689C1 <1> mov ecx,eax
7028 00000098 67F366A5 <1> a32 rep movsd
7029 <1>
7030 0000009C FC <1> cld
7031 <1>
7032 <1> .exit:
7033 0000009D B81800 <1> mov ax,18h ; "Real-mode-like" data segment
7034 000000A0 8EC0 <1> mov es,ax
7035 000000A2 8ED8 <1> mov ds,ax
7036 <1>
7037 000000A4 0F20C0 <1> mov eax,cr0
7038 000000A7 24FE <1> and al,~1
7039 000000A9 0F22C0 <1> mov cr0,eax ; Disable protected mode
7040 000000AC EA[B100]0000 <1> jmp 0:.in_rm
7041 <1>
7042 <1> .in_rm: ; Back in real mode
7043 000000B1 07 <1> pop es
7044 000000B2 1F <1> pop ds
7045 000000B3 E8B700 <1> call disable_a20
7046 <1>
7047 000000B6 9D <1> popf ; Re-enables interrupts
7048 000000B7 6658 <1> pop eax
7049 000000B9 665F <1> pop edi
7050 000000BB 665E <1> pop esi
7051 000000BD 6601C7 <1> add edi,eax
7052 000000C0 6601C6 <1> add esi,eax
7053 000000C3 6658 <1> pop eax
7054 000000C5 C3 <1> ret
7055 <1>
7056 <1> ;
7057 <1> ; Routines to enable and disable (yuck) A20. These routines are gathered
7058 <1> ; from tips from a couple of sources, including the Linux kernel and
7059 <1> ; http://www.x86.org/. The need for the delay to be as large as given here
7060 <1> ; is indicated by Donnie Barnes of RedHat, the problematic system being an
7061 <1> ; IBM ThinkPad 760EL.
7062 <1> ;
7063 <1> ; We typically toggle A20 twice for every 64K transferred.
7064 <1> ;
7065 <1> %define io_delay call _io_delay
7066 <1> %define IO_DELAY_PORT 80h ; Invalid port (we hope!)
7067 <1> %define disable_wait 32 ; How long to wait for a disable
7068 <1>
7069 <1> ; Note the skip of 2 here
7070 <1> %define A20_DUNNO 0 ; A20 type unknown
7071 <1> %define A20_NONE 2 ; A20 always on?
7072 <1> %define A20_BIOS 4 ; A20 BIOS enable
7073 <1> %define A20_KBC 6 ; A20 through KBC
7074 <1> %define A20_FAST 8 ; A20 through port 92h
7075 <1>
7076 000000C6 EE <1> slow_out: out dx, al ; Fall through
7077 <1>
7078 000000C7 E680 <1> _io_delay: out IO_DELAY_PORT,al
7079 000000C9 E680 <1> out IO_DELAY_PORT,al
7080 000000CB C3 <1> ret
7081 <1>
7082 <1> enable_a20:
7083 000000CC 6660 <1> pushad
7084 000000CE 2EC606[6E55]FF <1> mov byte [cs:A20Tries],255 ; Times to try to make this work
7085 <1>
7086 <1> try_enable_a20:
7087 <1> ;
7088 <1> ; Flush the caches
7089 <1> ;
7090 <1> %if DO_WBINVD
7091 <1> call try_wbinvd
7092 <1> %endif
7093 <1>
7094 <1> ;
7095 <1> ; If the A20 type is known, jump straight to type
7096 <1> ;
7097 000000D4 2E8B2E[0802] <1> mov bp,[cs:A20Type]
7098 000000D9 2EFFA6[F401] <1> jmp word [cs:bp+A20List]
7099 <1>
7100 <1> ;
7101 <1> ; First, see if we are on a system with no A20 gate
7102 <1> ;
7103 <1> a20_dunno:
7104 <1> a20_none:
7105 000000DE 2EC606[0802]02 <1> mov byte [cs:A20Type], A20_NONE
7106 000000E4 E86400 <1> call a20_test
7107 000000E7 755F <1> jnz a20_done
7108 <1>
7109 <1> ;
7110 <1> ; Next, try the BIOS (INT 15h AX=2401h)
7111 <1> ;
7112 <1> a20_bios:
7113 000000E9 2EC606[0802]04 <1> mov byte [cs:A20Type], A20_BIOS
7114 000000EF B80124 <1> mov ax,2401h
7115 000000F2 9C <1> pushf ; Some BIOSes muck with IF
7116 000000F3 CD15 <1> int 15h
7117 000000F5 9D <1> popf
7118 <1>
7119 000000F6 E85200 <1> call a20_test
7120 000000F9 754D <1> jnz a20_done
7121 <1>
7122 <1> ;
7123 <1> ; Enable the keyboard controller A20 gate
7124 <1> ;
7125 <1> a20_kbc:
7126 000000FB B201 <1> mov dl, 1 ; Allow early exit
7127 000000FD E8AC00 <1> call empty_8042
7128 00000100 7546 <1> jnz a20_done ; A20 live, no need to use KBC
7129 <1>
7130 00000102 2EC606[0802]06 <1> mov byte [cs:A20Type], A20_KBC ; Starting KBC command sequence
7131 <1>
7132 00000108 B0D1 <1> mov al,0D1h ; Command write
7133 0000010A E664 <1> out 064h, al
7134 0000010C E89B00 <1> call empty_8042_uncond
7135 <1>
7136 0000010F B0DF <1> mov al,0DFh ; A20 on
7137 00000111 E660 <1> out 060h, al
7138 00000113 E89400 <1> call empty_8042_uncond
7139 <1>
7140 <1> ; Verify that A20 actually is enabled. Do that by
7141 <1> ; observing a word in low memory and the same word in
7142 <1> ; the HMA until they are no longer coherent. Note that
7143 <1> ; we don't do the same check in the disable case, because
7144 <1> ; we don't want to *require* A20 masking (SYSLINUX should
7145 <1> ; work fine without it, if the BIOS does.)
7146 00000116 51 <1> .kbc_wait: push cx
7147 00000117 31C9 <1> xor cx,cx
7148 <1> .kbc_wait_loop:
7149 00000119 E82F00 <1> call a20_test
7150 0000011C 7529 <1> jnz a20_done_pop
7151 0000011E E2F9 <1> loop .kbc_wait_loop
7152 <1>
7153 00000120 59 <1> pop cx
7154 <1> ;
7155 <1> ; Running out of options here. Final attempt: enable the "fast A20 gate"
7156 <1> ;
7157 <1> a20_fast:
7158 00000121 2EC606[0802]08 <1> mov byte [cs:A20Type], A20_FAST ; Haven't used the KBC yet
7159 00000127 E492 <1> in al, 092h
7160 00000129 0C02 <1> or al,02h
7161 0000012B 24FE <1> and al,~01h ; Don't accidentally reset the machine!
7162 0000012D E692 <1> out 092h, al
7163 <1>
7164 0000012F 51 <1> .fast_wait: push cx
7165 00000130 31C9 <1> xor cx,cx
7166 <1> .fast_wait_loop:
7167 00000132 E81600 <1> call a20_test
7168 00000135 7510 <1> jnz a20_done_pop
7169 00000137 E2F9 <1> loop .fast_wait_loop
7170 <1>
7171 00000139 59 <1> pop cx
7172 <1>
7173 <1> ;
7174 <1> ; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up
7175 <1> ; and report failure to the user.
7176 <1> ;
7177 <1>
7178 <1>
7179 0000013A 2EFE0E[6E55] <1> dec byte [cs:A20Tries]
7180 0000013F 7593 <1> jnz try_enable_a20
7181 <1>
7182 00000141 BE[D703] <1> mov si, err_a20
7183 00000144 E9(A011) <1> jmp abort_load
7184 <1> ;
7185 <1> ; A20 unmasked, proceed...
7186 <1> ;
7187 00000147 59 <1> a20_done_pop: pop cx
7188 00000148 6661 <1> a20_done: popad
7189 0000014A C3 <1> ret
7190 <1>
7191 <1> ;
7192 <1> ; This routine tests if A20 is enabled (ZF = 0). This routine
7193 <1> ; must not destroy any register contents.
7194 <1> ;
7195 <1> a20_test:
7196 0000014B 06 <1> push es
7197 0000014C 51 <1> push cx
7198 0000014D 50 <1> push ax
7199 0000014E B9FFFF <1> mov cx,0FFFFh ; HMA = segment 0FFFFh
7200 00000151 8EC1 <1> mov es,cx
7201 00000153 B92000 <1> mov cx,32 ; Loop count
7202 00000156 2EA1[6C55] <1> mov ax,[cs:A20Test]
7203 0000015A 40 <1> .a20_wait: inc ax
7204 0000015B 2EA3[6C55] <1> mov [cs:A20Test],ax
7205 0000015F E865FF <1> io_delay ; Serialize, and fix delay
7206 00000162 263B06[7C55] <1> cmp ax,[es:A20Test+10h]
7207 00000167 E1F1 <1> loopz .a20_wait
7208 00000169 58 <1> .a20_done: pop ax
7209 0000016A 59 <1> pop cx
7210 0000016B 07 <1> pop es
7211 0000016C C3 <1> ret
7212 <1>
7213 <1> disable_a20:
7214 0000016D 6660 <1> pushad
7215 <1> ;
7216 <1> ; Flush the caches
7217 <1> ;
7218 <1> %if DO_WBINVD
7219 <1> call try_wbinvd
7220 <1> %endif
7221 <1>
7222 0000016F 2E8B2E[0802] <1> mov bp,[cs:A20Type]
7223 00000174 2EFFA6[FE01] <1> jmp word [cs:bp+A20DList]
7224 <1>
7225 <1> a20d_bios:
7226 00000179 B80024 <1> mov ax,2400h
7227 0000017C 9C <1> pushf ; Some BIOSes muck with IF
7228 0000017D CD15 <1> int 15h
7229 0000017F 9D <1> popf
7230 00000180 EB19 <1> jmp short a20d_snooze
7231 <1>
7232 <1> ;
7233 <1> ; Disable the "fast A20 gate"
7234 <1> ;
7235 <1> a20d_fast:
7236 00000182 E492 <1> in al, 092h
7237 00000184 24FC <1> and al,~03h
7238 00000186 E692 <1> out 092h, al
7239 00000188 EB11 <1> jmp short a20d_snooze
7240 <1>
7241 <1> ;
7242 <1> ; Disable the keyboard controller A20 gate
7243 <1> ;
7244 <1> a20d_kbc:
7245 0000018A E81D00 <1> call empty_8042_uncond
7246 0000018D B0D1 <1> mov al,0D1h
7247 0000018F E664 <1> out 064h, al ; Command write
7248 00000191 E81600 <1> call empty_8042_uncond
7249 00000194 B0DD <1> mov al,0DDh ; A20 off
7250 00000196 E660 <1> out 060h, al
7251 00000198 E80F00 <1> call empty_8042_uncond
7252 <1> ; Wait a bit for it to take effect
7253 <1> a20d_snooze:
7254 0000019B 51 <1> push cx
7255 0000019C B92000 <1> mov cx, disable_wait
7256 0000019F E8A9FF <1> .delayloop: call a20_test
7257 000001A2 7402 <1> jz .disabled
7258 000001A4 E2F9 <1> loop .delayloop
7259 000001A6 59 <1> .disabled: pop cx
7260 <1> a20d_dunno:
7261 <1> a20d_none:
7262 000001A7 6661 <1> popad
7263 000001A9 C3 <1> ret
7264 <1>
7265 <1> ;
7266 <1> ; Routine to empty the 8042 KBC controller. If dl != 0
7267 <1> ; then we will test A20 in the loop and exit if A20 is
7268 <1> ; suddenly enabled.
7269 <1> ;
7270 <1> empty_8042_uncond:
7271 000001AA 30D2 <1> xor dl,dl
7272 <1> empty_8042:
7273 000001AC E89CFF <1> call a20_test
7274 000001AF 7404 <1> jz .a20_on
7275 000001B1 20D2 <1> and dl,dl
7276 000001B3 7517 <1> jnz .done
7277 000001B5 E80FFF <1> .a20_on: io_delay
7278 000001B8 E464 <1> in al, 064h ; Status port
7279 000001BA A801 <1> test al,1
7280 000001BC 7407 <1> jz .no_output
7281 000001BE E806FF <1> io_delay
7282 000001C1 E460 <1> in al, 060h ; Read input
7283 000001C3 EBE7 <1> jmp short empty_8042
7284 <1> .no_output:
7285 000001C5 A802 <1> test al,2
7286 000001C7 75E3 <1> jnz empty_8042
7287 000001C9 E8FBFE <1> io_delay
7288 000001CC C3 <1> .done: ret
7289 <1>
7290 <1> ;
7291 <1> ; Execute a WBINVD instruction if possible on this CPU
7292 <1> ;
7293 <1> %if DO_WBINVD
7294 <1> try_wbinvd:
7295 <1> wbinvd
7296 <1> ret
7297 <1> %endif
7298 <1>
7299 <1> ;
7300 <1> ; bcopy_over_self:
7301 <1> ;
7302 <1> ; This routine is used to shuffle memory around, followed by
7303 <1> ; invoking an entry point somewhere in low memory. This routine
7304 <1> ; can clobber any memory above 7C00h, we therefore have to move
7305 <1> ; necessary code into the trackbuf area before doing the copy,
7306 <1> ; and do adjustments to anything except BSS area references.
7307 <1> ;
7308 <1> ; NOTE: Since PXELINUX relocates itself, put all these
7309 <1> ; references in the ".earlybss" segment.
7310 <1> ;
7311 <1> ; After performing the copy, this routine resets the stack and
7312 <1> ; jumps to the specified entrypoint.
7313 <1> ;
7314 <1> ; IMPORTANT: This routine does not canonicalize the stack or the
7315 <1> ; SS register. That is the responsibility of the caller.
7316 <1> ;
7317 <1> ; Inputs:
7318 <1> ; DS:BX -> Pointer to list of (dst, src, len) pairs
7319 <1> ; AX -> Number of list entries
7320 <1> ; [CS:EntryPoint] -> CS:IP to jump to
7321 <1> ; On stack - initial state (fd, ad, ds, es, fs, gs)
7322 <1> ;
7323 <1> shuffle_and_boot:
7324 000001CD 21C0 <1> and ax,ax
7325 000001CF 7414 <1> jz .done
7326 <1> .loop:
7327 000001D1 668B3F <1> mov edi,[bx]
7328 000001D4 668B7704 <1> mov esi,[bx+4]
7329 000001D8 668B4F08 <1> mov ecx,[bx+8]
7330 000001DC E851FE <1> call bcopy
7331 000001DF 83C30C <1> add bx,12
7332 000001E2 48 <1> dec ax
7333 000001E3 75EC <1> jnz .loop
7334 <1>
7335 <1> .done:
7336 000001E5 0FA9 <1> pop gs
7337 000001E7 0FA1 <1> pop fs
7338 000001E9 07 <1> pop es
7339 000001EA 1F <1> pop ds
7340 000001EB 6661 <1> popad
7341 000001ED 669D <1> popfd
7342 000001EF 2EFF2E[6455] <1> jmp far [cs:EntryPoint]
7343 <1>
7344 <1> align 2
7345 000001F4 [DE00][DE00][E900]- <1> A20List dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fast
7346 000001FA [FB00][2101] <1>
7347 000001FE [A701][A701][7901]- <1> A20DList dw a20d_dunno, a20d_none, a20d_bios, a20d_kbc, a20d_fast
7348 00000204 [8A01][8201] <1>
7349 <1> a20_adjust_cnt equ ($-A20List)/2
7350 <1>
7351 00000208 0200 <1> A20Type dw A20_NONE ; A20 type
7352 <1>
7353 <1> ; Total size of .bcopy32 section
7354 0000020A 00<rept> <1> alignb 4, db 0 ; Even number of dwords
7355 <1> __bcopy_size equ $-__bcopy_start
7356 <1>
7357 <1> section .earlybss
7358 <1> alignb 2
7359 00005564 <res 00000004> <1> EntryPoint resd 1 ; CS:IP for shuffle_and_boot
7360 00005568 <res 00000004> <1> SavedSSSP resd 1 ; Saved real mode SS:SP
7361 0000556C <res 00000002> <1> A20Test resw 1 ; Counter for testing status of A20
7362 0000556E <res 00000001> <1> A20Tries resb 1 ; Times until giving up on A20
7363 %include "loadhigh.inc" ; Load a file into high memory
7364 <1> ;; $Id: loadhigh.inc,v 1.7 2005/01/06 22:34:06 hpa Exp $
7365 <1> ;; -----------------------------------------------------------------------
7366 <1> ;;
7367 <1> ;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
7368 <1> ;;
7369 <1> ;; This program is free software; you can redistribute it and/or modify
7370 <1> ;; it under the terms of the GNU General Public License as published by
7371 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
7372 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
7373 <1> ;; (at your option) any later version; incorporated herein by reference.
7374 <1> ;;
7375 <1> ;; -----------------------------------------------------------------------
7376 <1>
7377 <1> ;;
7378 <1> ;; loadhigh.inc
7379 <1> ;;
7380 <1> ;; Load a file into high memory
7381 <1> ;;
7382 <1>
7383 <1> section .text
7384 <1>
7385 <1> ;
7386 <1> ; load_high: loads (the remainder of) a file into high memory.
7387 <1> ; This routine prints dots for each 64K transferred, and
7388 <1> ; calls abort_check periodically.
7389 <1> ;
7390 <1> ; The xfer_buf_seg is used as a bounce buffer.
7391 <1> ;
7392 <1> ; The input address (EDI) should be dword aligned, and the final
7393 <1> ; stretch is padded with zeroes if necessary.
7394 <1> ;
7395 <1> ; Inputs: SI = file handle/cluster pointer
7396 <1> ; EDI = target address in high memory
7397 <1> ; EAX = size of remaining file in bytes
7398 <1> ; DX = zero-padding mask (e.g. 0003h for pad to dword)
7399 <1> ;
7400 <1> ; Outputs: SI = file handle/cluster pointer
7401 <1> ; EDI = first untouched address (not including padding)
7402 <1> ;
7403 <1> load_high:
7404 000021BB 06 <1> push es
7405 <1>
7406 000021BC BB0020 <1> mov bx,xfer_buf_seg
7407 000021BF 8EC3 <1> mov es,bx
7408 <1>
7409 <1> .read_loop:
7410 000021C1 21F6 <1> and si,si ; If SI == 0 then we have end of file
7411 000021C3 7460 <1> jz .eof
7412 000021C5 56 <1> push si
7413 000021C6 BE[D006] <1> mov si,dot_msg
7414 000021C9 E888FC <1> call cwritestr
7415 000021CC 5E <1> pop si
7416 000021CD E8BCEF <1> call abort_check
7417 <1>
7418 000021D0 6650 <1> push eax ; <A> Total bytes to transfer
7419 000021D2 663D00000100 <1> cmp eax,(1 << 16) ; Max 64K in one transfer
7420 000021D8 7606 <1> jna .size_ok
7421 000021DA 66B800000100 <1> mov eax,(1 << 16)
7422 <1> .size_ok:
7423 000021E0 6650 <1> push eax ; <B> Bytes transferred this chunk
7424 000021E2 6605FF010000 <1> add eax,SECTOR_SIZE-1
7425 000021E8 66C1E809 <1> shr eax,SECTOR_SHIFT ; Convert to sectors
7426 <1>
7427 <1> ; Now (e)ax contains the number of sectors to get
7428 000021EC 6657 <1> push edi ; <C> Target buffer
7429 000021EE 89C1 <1> mov cx,ax
7430 000021F0 31DB <1> xor bx,bx ; ES:0
7431 000021F2 E8C9F3 <1> call getfssec ; Load the data into xfer_buf_seg
7432 000021F5 665F <1> pop edi ; <C> Target buffer
7433 000021F7 6659 <1> pop ecx ; <B> Byte count this round
7434 000021F9 6651 <1> push ecx ; <B> Byte count this round
7435 000021FB 6657 <1> push edi ; <C> Target buffer
7436 <1> .fix_slop:
7437 000021FD 85D1 <1> test cx,dx
7438 000021FF 7409 <1> jz .noslop
7439 <1> ; The last dword fractional - pad with zeroes
7440 <1> ; Zero-padding is critical for multi-file initramfs.
7441 00002201 2667C60100 <1> mov byte [es:ecx],0
7442 00002206 6641 <1> inc ecx
7443 00002208 EBF3 <1> jmp short .fix_slop
7444 <1> .noslop:
7445 0000220A 6656 <1> push esi ; <D> File handle/cluster pointer
7446 0000220C 66BE00000200 <1> mov esi,(xfer_buf_seg << 4) ; Source address
7447 00002212 E8(3000) <1> call bcopy ; Copy to high memory
7448 00002215 665E <1> pop esi ; <D> File handle/cluster pointer
7449 00002217 665F <1> pop edi ; <C> Target buffer
7450 00002219 6659 <1> pop ecx ; <B> Byte count this round
7451 0000221B 6658 <1> pop eax ; <A> Total bytes to transfer
7452 0000221D 6601CF <1> add edi,ecx
7453 00002220 6629C8 <1> sub eax,ecx
7454 00002223 759C <1> jnz .read_loop ; More to read...
7455 <1>
7456 <1> .eof:
7457 00002225 07 <1> pop es
7458 00002226 C3 <1> ret
7459 <1>
7460 %include "font.inc" ; VGA font stuff
7461 <1> ;; $Id: font.inc,v 1.7 2004/12/27 07:04:08 hpa Exp $
7462 <1> ;; -----------------------------------------------------------------------
7463 <1> ;;
7464 <1> ;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved
7465 <1> ;;
7466 <1> ;; This program is free software; you can redistribute it and/or modify
7467 <1> ;; it under the terms of the GNU General Public License as published by
7468 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
7469 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
7470 <1> ;; (at your option) any later version; incorporated herein by reference.
7471 <1> ;;
7472 <1> ;; -----------------------------------------------------------------------
7473 <1>
7474 <1> ;;
7475 <1> ;; font.inc
7476 <1> ;;
7477 <1> ;; VGA font handling code
7478 <1> ;;
7479 <1>
7480 <1> section .text
7481 <1>
7482 <1> ;
7483 <1> ; loadfont: Load a .psf font file and install it onto the VGA console
7484 <1> ; (if we're not on a VGA screen then ignore.) It is called with
7485 <1> ; SI and DX:AX set by routine searchdir
7486 <1> ;
7487 <1> loadfont:
7488 00002227 BB[0000] <1> mov bx,trackbuf ; The trackbuf is >= 16K; the part
7489 0000222A 8B0E[0009] <1> mov cx,[BufSafe] ; of a PSF file we care about is no
7490 0000222E E88DF3 <1> call getfssec ; more than 8K+4 bytes
7491 <1>
7492 00002231 A1[0000] <1> mov ax,[trackbuf] ; Magic number
7493 00002234 3D3604 <1> cmp ax,0436h
7494 00002237 755B <1> jne lf_ret
7495 <1>
7496 00002239 A0[0200] <1> mov al,[trackbuf+2] ; File mode
7497 0000223C 3C05 <1> cmp al,5 ; Font modes 0-5 supported
7498 0000223E 7754 <1> ja lf_ret
7499 <1>
7500 00002240 8A3E[0300] <1> mov bh,byte [trackbuf+3] ; Height of font
7501 00002244 80FF02 <1> cmp bh,2 ; VGA minimum
7502 00002247 724B <1> jb lf_ret
7503 00002249 80FF20 <1> cmp bh,32 ; VGA maximum
7504 0000224C 7746 <1> ja lf_ret
7505 <1>
7506 <1> ; Copy to font buffer
7507 0000224E BE[0400] <1> mov si,trackbuf+4 ; Start of font data
7508 00002251 883E[FC00] <1> mov [VGAFontSize],bh
7509 00002255 BF[0000] <1> mov di,vgafontbuf
7510 00002258 B90008 <1> mov cx,(32*256) >> 2 ; Maximum size
7511 0000225B F366A5 <1> rep movsd
7512 <1>
7513 0000225E C606[FE00]01 <1> mov [UserFont], byte 1 ; Set font flag
7514 <1>
7515 <1> ; Fall through to use_font
7516 <1>
7517 <1> ;
7518 <1> ; use_font:
7519 <1> ; This routine activates whatever font happens to be in the
7520 <1> ; vgafontbuf, and updates the adjust_screen data.
7521 <1> ; Must be called with CS = DS = ES
7522 <1> ;
7523 <1> use_font:
7524 00002263 F606[FE00]01 <1> test [UserFont], byte 1 ; Are we using a user-specified font?
7525 00002268 743C <1> jz adjust_screen ; If not, just do the normal stuff
7526 <1>
7527 0000226A BD[0000] <1> mov bp,vgafontbuf
7528 0000226D 8A3E[FC00] <1> mov bh,[VGAFontSize]
7529 <1>
7530 00002271 30DB <1> xor bl,bl ; Needed by both INT 10h calls
7531 00002273 803E[1001]01 <1> cmp [UsingVGA], byte 1 ; Are we in graphics mode?
7532 00002278 751B <1> jne .text
7533 <1>
7534 <1> .graphics:
7535 0000227A 31C9 <1> xor cx,cx
7536 0000227C 88F9 <1> mov cl,bh ; CX = bytes/character
7537 0000227E B8E001 <1> mov ax,480
7538 00002281 F6F1 <1> div cl ; Compute char rows per screen
7539 00002283 88C2 <1> mov dl,al
7540 00002285 FEC8 <1> dec al
7541 00002287 A2[C908] <1> mov [VidRows],al
7542 0000228A B82111 <1> mov ax,1121h ; Set user character table
7543 0000228D CD10 <1> int 10h
7544 0000228F C606[C808]4F <1> mov [VidCols], byte 79 ; Always 80 bytes/line
7545 00002294 C3 <1> .lf_ret: ret ; No need to call adjust_screen
7546 <1>
7547 <1> .text:
7548 00002295 B90001 <1> mov cx,256
7549 00002298 31D2 <1> xor dx,dx
7550 0000229A B81011 <1> mov ax,1110h
7551 0000229D CD10 <1> int 10h ; Load into VGA RAM
7552 <1>
7553 0000229F 30DB <1> xor bl,bl
7554 000022A1 B80311 <1> mov ax,1103h ; Select page 0
7555 000022A4 CD10 <1> int 10h
7556 <1>
7557 <1> ; Fall through to adjust_screen
7558 <1>
7559 <1> lf_ret equ use_font.lf_ret
7560 <1>
7561 <1> ;
7562 <1> ; adjust_screen: Set the internal variables associated with the screen size.
7563 <1> ; This is a subroutine in case we're loading a custom font.
7564 <1> ;
7565 <1> adjust_screen:
7566 000022A6 60 <1> pusha
7567 000022A7 A08404 <1> mov al,[BIOS_vidrows]
7568 000022AA 20C0 <1> and al,al
7569 000022AC 7502 <1> jnz vidrows_ok
7570 000022AE B018 <1> mov al,24 ; No vidrows in BIOS, assume 25
7571 <1> ; (Remember: vidrows == rows-1)
7572 000022B0 A2[C908] <1> vidrows_ok: mov [VidRows],al
7573 000022B3 B40F <1> mov ah,0fh
7574 000022B5 CD10 <1> int 10h ; Read video state
7575 000022B7 FECC <1> dec ah ; Store count-1 (same as rows)
7576 000022B9 8826[C808] <1> mov [VidCols],ah
7577 000022BD 61 <1> popa
7578 000022BE C3 <1> ret
7579 <1>
7580 <1>
7581 <1> ; VGA font buffer at the end of memory (so loading a font works even
7582 <1> ; in graphics mode, but don't put too much pressure on the .bss)
7583 <1> section .latebss
7584 00000000 <res 00002000> <1> vgafontbuf resb 8192
7585 <1>
7586 <1> section .data
7587 000000FB 00 <1> align 2, db 0
7588 000000FC 1000 <1> VGAFontSize dw 16 ; Defaults to 16 byte font
7589 000000FE 00 <1> UserFont db 0 ; Using a user-specified font
7590 <1>
7591 <1>
7592 %include "graphics.inc" ; VGA graphics
7593 <1> ;; $Id: graphics.inc,v 1.4 2004/12/17 06:42:01 hpa Exp $
7594 <1> ;; -----------------------------------------------------------------------
7595 <1> ;;
7596 <1> ;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
7597 <1> ;;
7598 <1> ;; This program is free software; you can redistribute it and/or modify
7599 <1> ;; it under the terms of the GNU General Public License as published by
7600 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
7601 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
7602 <1> ;; (at your option) any later version; incorporated herein by reference.
7603 <1> ;;
7604 <1> ;; -----------------------------------------------------------------------
7605 <1>
7606 <1> ; ----------------------------------------------------------------------------
7607 <1> ; VGA splash screen code
7608 <1> ; ----------------------------------------------------------------------------
7609 <1>
7610 <1> ;
7611 <1> ; vgadisplayfile:
7612 <1> ; Display a graphical splash screen.
7613 <1> ;
7614 <1> ; Input:
7615 <1> ;
7616 <1> ; SI = cluster/socket pointer
7617 <1> ;
7618 <1> section .text
7619 <1>
7620 <1> vgadisplayfile:
7621 000022BF 8936[641E] <1> mov [VGACluster],si
7622 000022C3 06 <1> push es
7623 <1>
7624 <1> ; This is a cheap and easy way to make sure the screen is
7625 <1> ; cleared in case we were in graphics mode already
7626 000022C4 E87E01 <1> call vgaclearmode
7627 000022C7 E84D01 <1> call vgasetmode
7628 000022CA 7514 <1> jnz .error_nz
7629 <1>
7630 <1> .graphalready:
7631 000022CC B80020 <1> mov ax,xfer_buf_seg ; Use as temporary storage
7632 000022CF 8EC0 <1> mov es,ax
7633 000022D1 8EE0 <1> mov fs,ax
7634 <1>
7635 000022D3 E8F300 <1> call vgagetchunk ; Get the first chunk
7636 <1>
7637 <1> ; The header WILL be in the first chunk.
7638 000022D6 2666813E00203DF313- <1> cmp dword [es:xbs_vgabuf],0x1413f33d ; Magic number
7639 000022DF 14 <1>
7640 000022E0 757D <1> .error_nz: jne .error
7641 000022E2 26A10420 <1> mov ax,[es:xbs_vgabuf+4]
7642 000022E6 A3[601E] <1> mov [GraphXSize],ax
7643 <1>
7644 000022E9 BA0820 <1> mov dx,xbs_vgabuf+8 ; Color map offset
7645 000022EC B81210 <1> mov ax,1012h ; Set RGB registers
7646 000022EF 31DB <1> xor bx,bx ; First register number
7647 000022F1 B91000 <1> mov cx,16 ; 16 registers
7648 000022F4 CD10 <1> int 10h
7649 <1>
7650 <1> .movecursor:
7651 000022F6 26A10620 <1> mov ax,[es:xbs_vgabuf+6] ; Number of pixel rows
7652 000022FA 8B16[FC00] <1> mov dx,[VGAFontSize]
7653 000022FE 01D0 <1> add ax,dx
7654 00002300 48 <1> dec ax
7655 00002301 F6F2 <1> div dl
7656 00002303 31D2 <1> xor dx,dx ; Set column to 0
7657 00002305 3A06[C908] <1> cmp al,[VidRows]
7658 00002309 7205 <1> jb .rowsok
7659 0000230B A0[C908] <1> mov al,[VidRows]
7660 0000230E FEC8 <1> dec al
7661 <1> .rowsok:
7662 00002310 88C6 <1> mov dh,al
7663 00002312 B402 <1> mov ah,2
7664 00002314 31DB <1> xor bx,bx
7665 00002316 CD10 <1> int 10h ; Set cursor below image
7666 <1>
7667 00002318 268B0E0620 <1> mov cx,[es:xbs_vgabuf+6] ; Number of graphics rows
7668 <1>
7669 0000231D BE3820 <1> mov si,xbs_vgabuf+8+3*16 ; Beginning of pixel data
7670 00002320 C706[621E]0000 <1> mov word [VGAPos],0
7671 <1>
7672 <1> .drawpixelrow:
7673 00002326 51 <1> push cx
7674 00002327 8B0E[601E] <1> mov cx,[GraphXSize]
7675 0000232B BF0040 <1> mov di,xbs_vgatmpbuf ; Row buffer
7676 0000232E E83000 <1> call rledecode ; Decode one row
7677 00002331 56 <1> push si
7678 00002332 BE0040 <1> mov si,xbs_vgatmpbuf
7679 00002335 89F7 <1> mov di,si
7680 00002337 033E[601E] <1> add di,[GraphXSize]
7681 0000233B B9A000 <1> mov cx,640/4
7682 0000233E 6631C0 <1> xor eax,eax
7683 00002341 F366AB <1> rep stosd ; Clear rest of row
7684 00002344 BF00A0 <1> mov di,0A000h ; VGA segment
7685 00002347 8EC7 <1> mov es,di
7686 00002349 8B3E[621E] <1> mov di,[VGAPos]
7687 0000234D BD8002 <1> mov bp,640
7688 00002350 E89500 <1> call packedpixel2vga
7689 00002353 8306[621E]50 <1> add word [VGAPos],byte 80 ; Advance to next pixel row
7690 00002358 0FA0 <1> push fs
7691 0000235A 07 <1> pop es
7692 0000235B 5E <1> pop si
7693 0000235C 59 <1> pop cx
7694 0000235D E2C7 <1> loop .drawpixelrow
7695 <1>
7696 <1> .error:
7697 0000235F 07 <1> pop es
7698 00002360 C3 <1> ret
7699 <1>
7700 <1> ;
7701 <1> ; rledecode:
7702 <1> ; Decode a pixel row in RLE16 format.
7703 <1> ;
7704 <1> ; FS:SI -> input
7705 <1> ; CX -> pixel count
7706 <1> ; ES:DI -> output (packed pixel)
7707 <1> ;
7708 <1> rledecode:
7709 00002361 66D1E6 <1> shl esi,1 ; Nybble pointer
7710 00002364 30D2 <1> xor dl,dl ; Last pixel
7711 <1> .loop:
7712 00002366 E83E00 <1> call .getnybble
7713 00002369 38D0 <1> cmp al,dl
7714 0000236B 740D <1> je .run ; Start of run sequence
7715 0000236D AA <1> stosb
7716 0000236E 88C2 <1> mov dl,al
7717 00002370 49 <1> dec cx
7718 00002371 75F3 <1> jnz .loop
7719 <1> .done:
7720 00002373 66D1EE <1> shr esi,1
7721 00002376 83D600 <1> adc si,byte 0
7722 00002379 C3 <1> ret
7723 <1> .run:
7724 0000237A 31DB <1> xor bx,bx
7725 0000237C E82800 <1> call .getnybble
7726 0000237F 20C0 <1> and al,al
7727 00002381 7410 <1> jz .longrun
7728 00002383 88C3 <1> mov bl,al
7729 <1> .dorun:
7730 00002385 51 <1> push cx
7731 00002386 89D9 <1> mov cx,bx
7732 00002388 88D0 <1> mov al,dl
7733 0000238A F3AA <1> rep stosb
7734 0000238C 59 <1> pop cx
7735 0000238D 29D9 <1> sub cx,bx
7736 0000238F 77D5 <1> ja .loop
7737 00002391 EBE0 <1> jmp short .done
7738 <1> .longrun:
7739 00002393 E81100 <1> call .getnybble
7740 00002396 88C4 <1> mov ah,al
7741 00002398 E80C00 <1> call .getnybble
7742 0000239B C0E004 <1> shl al,4
7743 0000239E 08E0 <1> or al,ah
7744 000023A0 88C3 <1> mov bl,al
7745 000023A2 83C310 <1> add bx,16
7746 000023A5 EBDE <1> jmp short .dorun
7747 <1> .getnybble:
7748 000023A7 66D1EE <1> shr esi,1
7749 000023AA 64AC <1> fs lodsb
7750 000023AC 7208 <1> jc .high
7751 000023AE 4E <1> dec si
7752 000023AF 240F <1> and al,0Fh
7753 000023B1 F9 <1> stc
7754 000023B2 66D1D6 <1> rcl esi,1
7755 000023B5 C3 <1> ret
7756 <1> .high:
7757 000023B6 C0E804 <1> shr al,4
7758 000023B9 81FE0040 <1> cmp si,xbs_vgabuf+trackbufsize ; Chunk overrun
7759 000023BD 7206 <1> jb .nonewchunk
7760 000023BF E80700 <1> call vgagetchunk
7761 000023C2 BE0020 <1> mov si,xbs_vgabuf ; Start at beginning of buffer
7762 <1> .nonewchunk:
7763 000023C5 66D1E6 <1> shl esi,1
7764 000023C8 C3 <1> ret
7765 <1>
7766 <1> ;
7767 <1> ; vgagetchunk:
7768 <1> ; Get a new trackbufsize chunk of VGA image data
7769 <1> ;
7770 <1> ; On input, ES is assumed to point to the buffer segment.
7771 <1> ;
7772 <1> vgagetchunk:
7773 000023C9 6660 <1> pushad
7774 000023CB 8B36[641E] <1> mov si,[VGACluster]
7775 000023CF 21F6 <1> and si,si
7776 000023D1 7412 <1> jz .eof ; EOF overrun, not much to do...
7777 <1>
7778 000023D3 8B0E[0009] <1> mov cx,[BufSafe] ; One trackbuf worth of data
7779 000023D7 BB0020 <1> mov bx,xbs_vgabuf
7780 000023DA E8E1F1 <1> call getfssec
7781 <1>
7782 000023DD 7302 <1> jnc .noteof
7783 000023DF 31F6 <1> xor si,si
7784 000023E1 8936[641E] <1> .noteof: mov [VGACluster],si
7785 <1>
7786 000023E5 6661 <1> .eof: popad
7787 000023E7 C3 <1> ret
7788 <1>
7789 <1> ;
7790 <1> ; packedpixel2vga:
7791 <1> ; Convert packed-pixel to VGA bitplanes
7792 <1> ;
7793 <1> ; FS:SI -> packed pixel string
7794 <1> ; BP -> pixel count (multiple of 8)
7795 <1> ; ES:DI -> output
7796 <1> ;
7797 <1> packedpixel2vga:
7798 000023E8 BAC403 <1> mov dx,3C4h ; VGA Sequencer Register select port
7799 000023EB B002 <1> mov al,2 ; Sequencer mask
7800 000023ED EE <1> out dx,al ; Select the sequencer mask
7801 000023EE 42 <1> inc dx ; VGA Sequencer Register data port
7802 000023EF B001 <1> mov al,1
7803 000023F1 88C3 <1> mov bl,al
7804 <1> .planeloop:
7805 000023F3 60 <1> pusha
7806 000023F4 EE <1> out dx,al
7807 <1> .loop1:
7808 000023F5 B90800 <1> mov cx,8
7809 <1> .loop2:
7810 000023F8 87CB <1> xchg cx,bx
7811 000023FA 64AC <1> fs lodsb
7812 000023FC D2E8 <1> shr al,cl
7813 000023FE D0D5 <1> rcl ch,1 ; VGA is bigendian. Sigh.
7814 00002400 87CB <1> xchg cx,bx
7815 00002402 E2F4 <1> loop .loop2
7816 00002404 88F8 <1> mov al,bh
7817 00002406 AA <1> stosb
7818 00002407 83ED08 <1> sub bp,byte 8
7819 0000240A 77E9 <1> ja .loop1
7820 0000240C 61 <1> popa
7821 0000240D FEC3 <1> inc bl
7822 0000240F D0E0 <1> shl al,1
7823 00002411 80FB04 <1> cmp bl,4
7824 00002414 76DD <1> jbe .planeloop
7825 00002416 C3 <1> ret
7826 <1>
7827 <1> ;
7828 <1> ; vgasetmode:
7829 <1> ; Enable VGA graphics, if possible; return ZF=1 on success
7830 <1> ; DS must be set to the base segment; ES is set to DS.
7831 <1> ;
7832 <1> vgasetmode:
7833 00002417 1E <1> push ds
7834 00002418 07 <1> pop es
7835 00002419 B8001A <1> mov ax,1A00h ; Get video card and monitor
7836 0000241C 31DB <1> xor bx,bx
7837 0000241E CD10 <1> int 10h
7838 00002420 80EB07 <1> sub bl, 7 ; BL=07h and BL=08h OK
7839 00002423 80FB01 <1> cmp bl, 1
7840 00002426 771C <1> ja .error ; ZF=0
7841 <1> ; mov bx,TextColorReg
7842 <1> ; mov dx,1009h ; Read color registers
7843 <1> ; int 10h
7844 00002428 B81200 <1> mov ax,0012h ; Set mode = 640x480 VGA 16 colors
7845 0000242B CD10 <1> int 10h
7846 0000242D BA[FF00] <1> mov dx,linear_color
7847 00002430 B80210 <1> mov ax,1002h ; Write color registers
7848 00002433 CD10 <1> int 10h
7849 00002435 C606[1001]01 <1> mov [UsingVGA], byte 1
7850 <1>
7851 0000243A E826FE <1> call use_font ; Set graphics font/data
7852 0000243D C606[C000]00 <1> mov byte [ScrollAttribute], 00h
7853 <1>
7854 00002442 31C0 <1> xor ax,ax ; Set ZF
7855 <1> .error:
7856 00002444 C3 <1> ret
7857 <1>
7858 <1> ;
7859 <1> ; vgaclearmode:
7860 <1> ; Disable VGA graphics. It is not safe to assume any value
7861 <1> ; for DS or ES.
7862 <1> ;
7863 <1> vgaclearmode:
7864 00002445 1E <1> push ds
7865 00002446 06 <1> push es
7866 00002447 6660 <1> pushad
7867 00002449 8CC8 <1> mov ax,cs
7868 0000244B 8ED8 <1> mov ds,ax
7869 0000244D 8EC0 <1> mov es,ax
7870 0000244F 803E[1001]01 <1> cmp [UsingVGA], byte 1
7871 00002454 7512 <1> jne .done
7872 00002456 B80300 <1> mov ax,0003h ; Return to normal video mode
7873 00002459 CD10 <1> int 10h
7874 <1> ; mov dx,TextColorReg ; Restore color registers
7875 <1> ; mov ax,1002h
7876 <1> ; int 10h
7877 0000245B C606[1001]00 <1> mov [UsingVGA], byte 0
7878 <1>
7879 00002460 E800FE <1> call use_font ; Restore text font/data
7880 00002463 C606[C000]07 <1> mov byte [ScrollAttribute], 07h
7881 <1> .done:
7882 00002468 6661 <1> popad
7883 0000246A 07 <1> pop es
7884 0000246B 1F <1> pop ds
7885 0000246C C3 <1> ret
7886 <1>
7887 <1> ;
7888 <1> ; vgashowcursor/vgahidecursor:
7889 <1> ; If VGA graphics is enabled, draw a cursor/clear a cursor
7890 <1> ;
7891 <1> vgashowcursor:
7892 0000246D 6660 <1> pushad
7893 0000246F B05F <1> mov al,'_'
7894 00002471 EB04 <1> jmp short vgacursorcommon
7895 <1> vgahidecursor:
7896 00002473 6660 <1> pushad
7897 00002475 B020 <1> mov al,' '
7898 <1> vgacursorcommon:
7899 00002477 803E[1001]01 <1> cmp [UsingVGA], byte 1
7900 0000247C 750A <1> jne .done
7901 0000247E B409 <1> mov ah,09h
7902 00002480 BB0700 <1> mov bx,0007h
7903 00002483 B90100 <1> mov cx,1
7904 00002486 CD10 <1> int 10h
7905 <1> .done:
7906 00002488 6661 <1> popad
7907 0000248A C3 <1> ret
7908 <1>
7909 <1>
7910 <1> section .data
7911 <1> ; Map colors to consecutive DAC registers
7912 000000FF 000102030405060708- <1> linear_color db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0
7913 00000108 090A0B0C0D0E0F00 <1>
7914 00000110 00 <1> UsingVGA db 0
7915 <1>
7916 <1> section .bss
7917 <1> alignb 2
7918 00001E60 <res 00000002> <1> GraphXSize resw 1 ; Width of splash screen file
7919 00001E62 <res 00000002> <1> VGAPos resw 1 ; Pointer into VGA memory
7920 00001E64 <res 00000002> <1> VGACluster resw 1 ; Cluster pointer for VGA image file
7921 00001E66 <res 00000002> <1> VGAFilePtr resw 1 ; Pointer into VGAFileBuf
7922 00001E68 <res 00000011> <1> TextColorReg resb 17 ; VGA color registers for text mode
7923 <1> %if IS_SYSLINUX
7924 <1> VGAFileBuf resb FILENAME_MAX+2 ; Unmangled VGA image name
7925 <1> %else
7926 00001E79 <res 00000080> <1> VGAFileBuf resb FILENAME_MAX ; Unmangled VGA image name
7927 <1> %endif
7928 <1> VGAFileBufEnd equ $
7929 00001EF9 <res 00000080> <1> VGAFileMBuf resb FILENAME_MAX ; Mangled VGA image name
7930 <1>
7931 %include "highmem.inc" ; High memory sizing
7932 <1> ;; $Id: highmem.inc,v 1.4 2004/12/17 06:42:01 hpa Exp $
7933 <1> ;; -----------------------------------------------------------------------
7934 <1> ;;
7935 <1> ;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved
7936 <1> ;;
7937 <1> ;; This program is free software; you can redistribute it and/or modify
7938 <1> ;; it under the terms of the GNU General Public License as published by
7939 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
7940 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
7941 <1> ;; (at your option) any later version; incorporated herein by reference.
7942 <1> ;;
7943 <1> ;; -----------------------------------------------------------------------
7944 <1>
7945 <1> ;;
7946 <1> ;; highmem.inc
7947 <1> ;;
7948 <1> ;; Probe for the size of high memory. This can be overridden by a
7949 <1> ;; mem= command on the command line while booting a new kernel.
7950 <1> ;;
7951 <1>
7952 <1> section .text
7953 <1>
7954 <1> ;
7955 <1> ; This is set up as a subroutine; it will set up the global variable
7956 <1> ; HighMemSize. All registers are preserved. Assumes DS == CS.
7957 <1> ;
7958 <1> highmemsize:
7959 0000248B 06 <1> push es
7960 0000248C 6660 <1> pushad
7961 <1>
7962 <1> ;
7963 <1> ; First, try INT 15:E820 (get BIOS memory map)
7964 <1> ;
7965 <1> get_e820:
7966 0000248E 6631DB <1> xor ebx,ebx ; Start with first record
7967 00002491 66C706[941F]0000F0- <1> mov dword [E820Max],-(1 << 20) ; Max amount of high memory
7968 00002499 FF <1>
7969 0000249A 66891E[901F] <1> mov dword [E820Mem],ebx ; Detected amount of high memory
7970 0000249F 8EC3 <1> mov es,bx ; Need ES = DS = 0 for now
7971 000024A1 EB05 <1> jmp short .do_e820 ; Skip "at end" check first time!
7972 000024A3 6621DB <1> .int_loop: and ebx,ebx ; If we're back at beginning...
7973 000024A6 7478 <1> jz .e820_done ; ... we're done
7974 000024A8 66B820E80000 <1> .do_e820: mov eax,0000E820h
7975 000024AE 66BA50414D53 <1> mov edx,534D4150h ; "SMAP" backwards
7976 000024B4 6631C9 <1> xor ecx,ecx
7977 000024B7 B114 <1> mov cl,20 ; ECX <- 20
7978 000024B9 BF[7C1F] <1> mov di,E820Buf
7979 000024BC CD15 <1> int 15h
7980 000024BE 7307 <1> jnc .no_carry
7981 <1> ; If carry, ebx == 0 means error, ebx != 0 means we're done
7982 000024C0 6621DB <1> and ebx,ebx
7983 000024C3 755B <1> jnz .e820_done
7984 000024C5 EB6F <1> jmp no_e820
7985 <1> .no_carry:
7986 000024C7 663D50414D53 <1> cmp eax,534D4150h
7987 000024CD 7567 <1> jne no_e820
7988 <1> ;
7989 <1> ; Look for a memory block starting at <= 1 MB and continuing upward
7990 <1> ;
7991 000024CF 66833E[801F]00 <1> cmp dword [E820Buf+4], byte 0
7992 000024D5 77CC <1> ja .int_loop ; Start >= 4 GB?
7993 000024D7 66BA00001000 <1> mov edx, (1 << 20)
7994 000024DD 662B16[7C1F] <1> sub edx, [E820Buf]
7995 000024E2 7319 <1> jnb .ram_range ; Start >= 1 MB?
7996 <1> ; If we get here, it starts > 1 MB but < 4 GB; if this is a
7997 <1> ; *non*-memory range, remember this as unusable; some BIOSes
7998 <1> ; get the length of primary RAM wrong!
7999 000024E4 66833E[8C1F]01 <1> cmp dword [E820Buf+16], byte 1
8000 000024EA 74B7 <1> je .int_loop ; If it's memory, don't worry about it
8001 000024EC 66F7DA <1> neg edx ; This means what for memory limit?
8002 000024EF 663B16[941F] <1> cmp edx,[E820Max] ; Better or worse
8003 000024F4 73AD <1> jnb .int_loop
8004 000024F6 668916[941F] <1> mov [E820Max],edx
8005 000024FB EBA6 <1> jmp .int_loop
8006 <1>
8007 <1> .ram_range:
8008 000024FD F9 <1> stc
8009 000024FE 6619C0 <1> sbb eax,eax ; eax <- 0xFFFFFFFF
8010 00002501 66833E[881F]00 <1> cmp dword [E820Buf+12], byte 0
8011 00002507 7704 <1> ja .huge ; Size >= 4 GB
8012 00002509 66A1[841F] <1> mov eax, [E820Buf+8]
8013 0000250D 6629D0 <1> .huge: sub eax, edx ; Adjust size to start at 1 MB
8014 00002510 7691 <1> jbe .int_loop ; Completely below 1 MB?
8015 <1>
8016 <1> ; Now EAX contains the size of memory 1 MB...up
8017 00002512 66833E[8C1F]01 <1> cmp dword [E820Buf+16], byte 1
8018 00002518 7589 <1> jne .int_loop ; High memory isn't usable memory!!!!
8019 <1>
8020 <1> ; We're good!
8021 0000251A 66A3[901F] <1> mov [E820Mem],eax
8022 0000251E EB83 <1> jmp .int_loop ; Still need to add low 1 MB
8023 <1>
8024 <1> .e820_done:
8025 00002520 66A1[901F] <1> mov eax,[E820Mem]
8026 00002524 6621C0 <1> and eax,eax
8027 00002527 740D <1> jz no_e820 ; Nothing found by E820?
8028 00002529 663B06[941F] <1> cmp eax,[E820Max] ; Make sure we're not limited
8029 0000252E 7638 <1> jna got_highmem_add1mb
8030 00002530 66A1[941F] <1> mov eax,[E820Max]
8031 00002534 EB32 <1> jmp got_highmem_add1mb
8032 <1>
8033 <1> ;
8034 <1> ; INT 15:E820 failed. Try INT 15:E801.
8035 <1> ;
8036 <1> no_e820:
8037 00002536 B801E8 <1> mov ax,0e801h ; Query high memory (semi-recent)
8038 00002539 CD15 <1> int 15h
8039 0000253B 7215 <1> jc no_e801
8040 0000253D 3D003C <1> cmp ax,3c00h
8041 00002540 7710 <1> ja no_e801 ; > 3C00h something's wrong with this call
8042 00002542 721A <1> jb e801_hole ; If memory hole we can only use low part
8043 <1>
8044 00002544 89D8 <1> mov ax,bx
8045 00002546 66C1E010 <1> shl eax,16 ; 64K chunks
8046 0000254A 660500000001 <1> add eax,(16 << 20) ; Add first 16M
8047 00002550 EB1C <1> jmp short got_highmem
8048 <1>
8049 <1> ;
8050 <1> ; INT 15:E801 failed. Try INT 15:88.
8051 <1> ;
8052 <1> no_e801:
8053 00002552 B488 <1> mov ah,88h ; Query high memory (oldest)
8054 00002554 CD15 <1> int 15h
8055 00002556 3D0038 <1> cmp ax,14*1024 ; Don't trust memory >15M
8056 00002559 7603 <1> jna e801_hole
8057 0000255B B80038 <1> mov ax,14*1024
8058 <1> e801_hole:
8059 0000255E 6625FFFF0000 <1> and eax,0ffffh
8060 00002564 66C1E00A <1> shl eax,10 ; Convert from kilobytes
8061 <1> got_highmem_add1mb:
8062 00002568 660500001000 <1> add eax,(1 << 20) ; First megabyte
8063 <1> got_highmem:
8064 <1> %if HIGHMEM_SLOP != 0
8065 0000256E 662D00000200 <1> sub eax,HIGHMEM_SLOP
8066 <1> %endif
8067 00002574 66A3[981F] <1> mov [HighMemSize],eax
8068 00002578 6661 <1> popad
8069 0000257A 07 <1> pop es
8070 0000257B C3 <1> ret ; Done!
8071 <1>
8072 <1> section .bss
8073 00001F79 <res 00000001>- <1> alignb 4
8074 00001F79 <rept> <1>
8075 00001F7C <res 00000014> <1> E820Buf resd 5 ; INT 15:E820 data buffer
8076 00001F90 <res 00000004> <1> E820Mem resd 1 ; Memory detected by E820
8077 00001F94 <res 00000004> <1> E820Max resd 1 ; Is E820 memory capped?
8078 00001F98 <res 00000004> <1> HighMemSize resd 1 ; End of memory pointer (bytes)
8079 %include "strcpy.inc" ; strcpy()
8080 <1> ;
8081 <1> ; strcpy: Copy DS:SI -> ES:DI up to and including a null byte;
8082 <1> ; on exit SI and DI point to the byte *after* the null byte
8083 <1> ;
8084 <1> section .text
8085 <1>
8086 0000257C 50 <1> strcpy: push ax
8087 0000257D AC <1> .loop: lodsb
8088 0000257E AA <1> stosb
8089 0000257F 20C0 <1> and al,al
8090 00002581 75FA <1> jnz .loop
8091 00002583 58 <1> pop ax
8092 00002584 C3 <1> ret
8093 <1>
8094 %include "rawcon.inc" ; Console I/O w/o using the console functions
8095 <1> ;
8096 <1> ; writechr: Write a single character in AL to the console without
8097 <1> ; mangling any registers. This does raw console writes,
8098 <1> ; since some PXE BIOSes seem to interfere regular console I/O.
8099 <1> ;
8100 <1> %if IS_ISOLINUX
8101 <1> writechr_full:
8102 <1> %else
8103 <1> writechr:
8104 <1> %endif
8105 00002585 1E <1> push ds
8106 00002586 0E <1> push cs
8107 00002587 1F <1> pop ds
8108 00002588 E813F8 <1> call write_serial ; write to serial port if needed
8109 0000258B 669C <1> pushfd
8110 0000258D F606[BE00]01 <1> test byte [DisplayCon],01h ; Write to screen?
8111 00002592 7443 <1> jz .nothing
8112 <1>
8113 00002594 6660 <1> pushad
8114 00002596 8A3E6204 <1> mov bh,[BIOS_page]
8115 0000259A 50 <1> push ax
8116 0000259B B403 <1> mov ah,03h ; Read cursor position
8117 0000259D CD10 <1> int 10h
8118 0000259F 58 <1> pop ax
8119 000025A0 3C08 <1> cmp al,8
8120 000025A2 7456 <1> je .bs
8121 000025A4 3C0D <1> cmp al,13
8122 000025A6 744E <1> je .cr
8123 000025A8 3C0A <1> cmp al,10
8124 000025AA 7419 <1> je .lf
8125 000025AC 52 <1> push dx
8126 000025AD 8A3E6204 <1> mov bh,[BIOS_page]
8127 000025B1 B307 <1> mov bl,07h ; White on black
8128 000025B3 B90100 <1> mov cx,1 ; One only
8129 000025B6 B409 <1> mov ah,09h ; Write char and attribute
8130 000025B8 CD10 <1> int 10h
8131 000025BA 5A <1> pop dx
8132 000025BB FEC2 <1> inc dl
8133 000025BD 3A16[C808] <1> cmp dl,[VidCols]
8134 000025C1 760A <1> jna .curxyok
8135 000025C3 30D2 <1> xor dl,dl
8136 000025C5 FEC6 <1> .lf: inc dh
8137 000025C7 3A36[C908] <1> cmp dh,[VidRows]
8138 000025CB 770E <1> ja .scroll
8139 000025CD 8A3E6204 <1> .curxyok: mov bh,[BIOS_page]
8140 000025D1 B402 <1> mov ah,02h ; Set cursor position
8141 000025D3 CD10 <1> int 10h
8142 000025D5 6661 <1> .ret: popad
8143 <1> .nothing:
8144 000025D7 669D <1> popfd
8145 000025D9 1F <1> pop ds
8146 000025DA C3 <1> ret
8147 000025DB FECE <1> .scroll: dec dh
8148 000025DD 8A3E6204 <1> mov bh,[BIOS_page]
8149 000025E1 B402 <1> mov ah,02h
8150 000025E3 CD10 <1> int 10h
8151 000025E5 B80106 <1> mov ax,0601h ; Scroll up one line
8152 000025E8 8A3E[C000] <1> mov bh,[ScrollAttribute]
8153 000025EC 31C9 <1> xor cx,cx
8154 000025EE 8B16[C808] <1> mov dx,[ScreenSize] ; The whole screen
8155 000025F2 CD10 <1> int 10h
8156 000025F4 EBDF <1> jmp short .ret
8157 000025F6 30D2 <1> .cr: xor dl,dl
8158 000025F8 EBD3 <1> jmp short .curxyok
8159 000025FA 80EA01 <1> .bs: sub dl,1
8160 000025FD 73CE <1> jnc .curxyok
8161 000025FF 8A16[C808] <1> mov dl,[VidCols]
8162 00002603 80EE01 <1> sub dh,1
8163 00002606 73C5 <1> jnc .curxyok
8164 00002608 30F6 <1> xor dh,dh
8165 0000260A EBC1 <1> jmp short .curxyok
8166 <1>
8167 %include "dnsresolv.inc" ; DNS resolver
8168 <1> ; -*- fundamental -*-
8169 <1> ; -----------------------------------------------------------------------
8170 <1> ;
8171 <1> ; Copyright 2004 H. Peter Anvin - All Rights Reserved
8172 <1> ;
8173 <1> ; This program is free software; you can redistribute it and/or modify
8174 <1> ; it under the terms of the GNU General Public License as published by
8175 <1> ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8176 <1> ; Bostom MA 02111-1307, USA; either version 2 of the License, or
8177 <1> ; (at your option) any later version; incorporated herein by reference.
8178 <1> ;
8179 <1> ; -----------------------------------------------------------------------
8180 <1>
8181 <1> ;
8182 <1> ; dnsresolv.inc
8183 <1> ;
8184 <1> ; Very simple DNS resolver (assumes recursion-enabled DNS server;
8185 <1> ; this should be the normal thing for client-serving DNS servers.)
8186 <1> ;
8187 <1>
8188 <1> DNS_PORT equ htons(53) ; Default DNS port
8189 <1> DNS_MAX_PACKET equ 512 ; Defined by protocol
8190 <1> ; TFTP uses the range 49152-57343
8191 <1> DNS_LOCAL_PORT equ htons(60053) ; All local DNS queries come from this port #
8192 <1> DNS_MAX_SERVERS equ 4 ; Max no of DNS servers
8193 <1>
8194 <1> section .text
8195 <1>
8196 <1> ;
8197 <1> ; Turn a string in DS:SI into a DNS "label set" in ES:DI.
8198 <1> ; On return, DI points to the first byte after the label set,
8199 <1> ; and SI to the terminating byte.
8200 <1> ;
8201 <1> ; On return, DX contains the number of dots encountered.
8202 <1> ;
8203 <1> dns_mangle:
8204 0000260C 50 <1> push ax
8205 0000260D 53 <1> push bx
8206 0000260E 31D2 <1> xor dx,dx
8207 <1> .isdot:
8208 00002610 42 <1> inc dx
8209 00002611 30C0 <1> xor al,al
8210 00002613 89FB <1> mov bx,di
8211 00002615 AA <1> stosb
8212 <1> .getbyte:
8213 00002616 AC <1> lodsb
8214 00002617 20C0 <1> and al,al
8215 00002619 740E <1> jz .endstring
8216 0000261B 3C3A <1> cmp al,':'
8217 0000261D 740A <1> jz .endstring
8218 0000261F 3C2E <1> cmp al,'.'
8219 00002621 74ED <1> je .isdot
8220 00002623 26FE07 <1> inc byte [es:bx]
8221 00002626 AA <1> stosb
8222 00002627 EBED <1> jmp .getbyte
8223 <1> .endstring:
8224 00002629 4E <1> dec si
8225 0000262A 4A <1> dec dx ; We always counted one high
8226 0000262B 26803F00 <1> cmp byte [es:bx],0
8227 0000262F 7403 <1> jz .done
8228 00002631 30C0 <1> xor al,al
8229 00002633 AA <1> stosb
8230 <1> .done:
8231 00002634 5B <1> pop bx
8232 00002635 58 <1> pop ax
8233 00002636 C3 <1> ret
8234 <1>
8235 <1> ;
8236 <1> ; Compare two sets of DNS labels, in DS:SI and ES:DI; the one in SI
8237 <1> ; is allowed pointers relative to a packet in DNSRecvBuf.
8238 <1> ;
8239 <1> ; Assumes DS == ES. ZF = 1 if same; no registers changed.
8240 <1> ; (Note: change reference to [di] to [es:di] to remove DS == ES assumption)
8241 <1> ;
8242 <1> dns_compare:
8243 00002637 60 <1> pusha
8244 <1> %if 0
8245 <1>
8246 <1> .label:
8247 <1> lodsb
8248 <1> cmp al,0C0h
8249 <1> jb .noptr
8250 <1> and al,03Fh ; Get pointer value
8251 <1> mov ah,al ; ... in network byte order!
8252 <1> lodsb
8253 <1> mov si,DNSRecvBuf
8254 <1> add si,ax
8255 <1> jmp .label
8256 <1> .noptr:
8257 <1> cmp al,[di]
8258 <1> jne .done ; Mismatch
8259 <1> inc di
8260 <1> movzx cx,al ; End label?
8261 <1> and cx,cx ; ZF = 1 if match
8262 <1> jz .done
8263 <1>
8264 <1> ; We have a string of bytes that need to match now
8265 <1> repe cmpsb
8266 <1> je .label
8267 <1>
8268 <1> .done:
8269 <1> %else
8270 00002638 31C0 <1> xor ax,ax
8271 <1> %endif
8272 0000263A 61 <1> popa
8273 0000263B C3 <1> ret
8274 <1>
8275 <1> ;
8276 <1> ; Skip past a DNS label set in DS:SI.
8277 <1> ;
8278 <1> dns_skiplabel:
8279 0000263C 50 <1> push ax
8280 0000263D 31C0 <1> xor ax,ax ; AH == 0
8281 <1> .loop:
8282 0000263F AC <1> lodsb
8283 00002640 3CC0 <1> cmp al,0C0h ; Pointer?
8284 00002642 7308 <1> jae .ptr
8285 00002644 20C0 <1> and al,al
8286 00002646 7405 <1> jz .done
8287 00002648 01C6 <1> add si,ax
8288 0000264A EBF3 <1> jmp .loop
8289 <1> .ptr:
8290 0000264C 46 <1> inc si ; Pointer is two bytes
8291 <1> .done:
8292 0000264D 58 <1> pop ax
8293 0000264E C3 <1> ret
8294 <1>
8295 <1> ; DNS header format
8296 <1> struc dnshdr
8297 00000000 <res 00000002> <1> .id: resw 1
8298 00000002 <res 00000002> <1> .flags: resw 1
8299 00000004 <res 00000002> <1> .qdcount: resw 1
8300 00000006 <res 00000002> <1> .ancount: resw 1
8301 00000008 <res 00000002> <1> .nscount: resw 1
8302 0000000A <res 00000002> <1> .arcount: resw 1
8303 <1> endstruc
8304 <1>
8305 <1> ; DNS query
8306 <1> struc dnsquery
8307 00000000 <res 00000002> <1> .qtype: resw 1
8308 00000002 <res 00000002> <1> .qclass: resw 1
8309 <1> endstruc
8310 <1>
8311 <1> ; DNS RR
8312 <1> struc dnsrr
8313 00000000 <res 00000002> <1> .type: resw 1
8314 00000002 <res 00000002> <1> .class: resw 1
8315 00000004 <res 00000004> <1> .ttl: resd 1
8316 00000008 <res 00000002> <1> .rdlength: resw 1
8317 <1> .rdata: equ $
8318 <1> endstruc
8319 <1>
8320 <1> section .bss
8321 <1> alignb 2, db 0
8322 00001F9C <res 00000200> <1> DNSSendBuf resb DNS_MAX_PACKET
8323 0000219C <res 00000200> <1> DNSRecvBuf resb DNS_MAX_PACKET
8324 0000239C <res 00000100> <1> LocalDomain resb 256 ; Max possible length
8325 0000249C <res 00000010> <1> DNSServers resd DNS_MAX_SERVERS
8326 <1>
8327 <1> section .data
8328 <1> pxe_udp_write_pkt_dns:
8329 00000111 0000 <1> .status: dw 0 ; Status
8330 00000113 00000000 <1> .sip: dd 0 ; Server IP
8331 00000117 00000000 <1> .gip: dd 0 ; Gateway IP
8332 0000011B EA95 <1> .lport: dw DNS_LOCAL_PORT ; Local port
8333 0000011D 0035 <1> .rport: dw DNS_PORT ; Remote port
8334 0000011F 0000 <1> .buffersize: dw 0 ; Size of packet
8335 00000121 [9C1F]0000 <1> .buffer: dw DNSSendBuf, 0 ; off, seg of buffer
8336 <1>
8337 <1> pxe_udp_read_pkt_dns:
8338 00000125 0000 <1> .status: dw 0 ; Status
8339 00000127 00000000 <1> .sip: dd 0 ; Source IP
8340 0000012B 00000000 <1> .dip: dd 0 ; Destination (our) IP
8341 0000012F 0035 <1> .rport: dw DNS_PORT ; Remote port
8342 00000131 EA95 <1> .lport: dw DNS_LOCAL_PORT ; Local port
8343 00000133 0002 <1> .buffersize: dw DNS_MAX_PACKET ; Max packet size
8344 00000135 [9C21]0000 <1> .buffer: dw DNSRecvBuf, 0 ; off, seg of buffer
8345 <1>
8346 00000139 [9C24] <1> LastDNSServer dw DNSServers
8347 <1>
8348 <1> ; Actual resolver function
8349 <1> ; Points to a null-terminated or :-terminated string in DS:SI
8350 <1> ; and returns the name in EAX if it exists and can be found.
8351 <1> ; If EAX = 0 on exit, the lookup failed.
8352 <1>
8353 <1> section .text
8354 <1> dns_resolv:
8355 0000264F 1E <1> push ds
8356 00002650 06 <1> push es
8357 00002651 57 <1> push di
8358 00002652 51 <1> push cx
8359 00002653 52 <1> push dx
8360 <1>
8361 00002654 0E <1> push cs
8362 00002655 07 <1> pop es ; ES <- CS
8363 <1>
8364 <1> ; First, build query packet
8365 00002656 BF[9E1F] <1> mov di,DNSSendBuf+dnshdr.flags
8366 00002659 26FF45FE <1> inc word [es:di-2] ; New query ID
8367 0000265D B80100 <1> mov ax,htons(0100h) ; Recursion requested
8368 00002660 AB <1> stosw
8369 00002661 B80001 <1> mov ax,htons(1) ; One question
8370 00002664 AB <1> stosw
8371 00002665 31C0 <1> xor ax,ax ; No answers, NS or ARs
8372 00002667 AB <1> stosw
8373 00002668 AB <1> stosw
8374 00002669 AB <1> stosw
8375 <1>
8376 0000266A E89FFF <1> call dns_mangle ; Convert name to DNS labels
8377 <1>
8378 0000266D 0E <1> push cs ; DS <- CS
8379 0000266E 1F <1> pop ds
8380 <1>
8381 0000266F 56 <1> push si ; Save pointer to after DNS string
8382 <1>
8383 <1> ; Initialize...
8384 00002670 66A1[EC08] <1> mov eax,[MyIP]
8385 00002674 66A3[2B01] <1> mov [pxe_udp_read_pkt_dns.dip],eax
8386 <1>
8387 00002678 21D2 <1> and dx,dx
8388 0000267A 7507 <1> jnz .fqdn ; If we have dots, assume it's FQDN
8389 0000267C 4F <1> dec di ; Remove final null
8390 0000267D BE[9C23] <1> mov si,LocalDomain
8391 00002680 E8F9FE <1> call strcpy ; Uncompressed DNS label set so it ends in null
8392 <1> .fqdn:
8393 <1>
8394 00002683 B80001 <1> mov ax,htons(1)
8395 00002686 AB <1> stosw ; QTYPE = 1 = A
8396 00002687 AB <1> stosw ; QCLASS = 1 = IN
8397 <1>
8398 00002688 81EF[9C1F] <1> sub di,DNSSendBuf
8399 0000268C 893E[1F01] <1> mov [pxe_udp_write_pkt_dns.buffersize],di
8400 <1>
8401 <1> ; Now, send it to the nameserver(s)
8402 <1> ; Outer loop: exponential backoff
8403 <1> ; Inner loop: scan the various DNS servers
8404 <1>
8405 00002690 BA0C00 <1> mov dx,PKT_TIMEOUT
8406 00002693 B90600 <1> mov cx,PKT_RETRY
8407 <1> .backoff:
8408 00002696 BE[9C24] <1> mov si,DNSServers
8409 <1> .servers:
8410 00002699 3B36[3901] <1> cmp si,[LastDNSServer]
8411 0000269D 720E <1> jb .moreservers
8412 <1>
8413 <1> .nomoreservers:
8414 0000269F 01D2 <1> add dx,dx ; Exponential backoff
8415 000026A1 E2F3 <1> loop .backoff
8416 <1>
8417 000026A3 6631C0 <1> xor eax,eax ; Nothing...
8418 <1> .done:
8419 000026A6 5E <1> pop si
8420 000026A7 5A <1> pop dx
8421 000026A8 59 <1> pop cx
8422 000026A9 5F <1> pop di
8423 000026AA 07 <1> pop es
8424 000026AB 1F <1> pop ds
8425 000026AC C3 <1> ret
8426 <1>
8427 <1> .moreservers:
8428 000026AD 66AD <1> lodsd ; EAX <- next server
8429 000026AF 56 <1> push si
8430 000026B0 51 <1> push cx
8431 000026B1 52 <1> push dx
8432 <1>
8433 000026B2 C706[1101]0000 <1> mov word [pxe_udp_write_pkt_dns.status],0
8434 <1>
8435 000026B8 66A3[1301] <1> mov [pxe_udp_write_pkt_dns.sip],eax
8436 000026BC 66A3[2701] <1> mov [pxe_udp_read_pkt_dns.sip],eax
8437 000026C0 663306[EC08] <1> xor eax,[MyIP]
8438 000026C5 662306[F408] <1> and eax,[Netmask]
8439 000026CA 7404 <1> jz .nogw
8440 000026CC 66A1[F808] <1> mov eax,[Gateway]
8441 <1> .nogw:
8442 000026D0 66A3[1701] <1> mov [pxe_udp_write_pkt_dns.gip],eax
8443 <1>
8444 000026D4 BF[1101] <1> mov di,pxe_udp_write_pkt_dns
8445 000026D7 BB3300 <1> mov bx,PXENV_UDP_WRITE
8446 000026DA E8CAEE <1> call pxenv
8447 000026DD 0F829F00 <1> jc .timeout ; Treat failed transmit as timeout
8448 000026E1 833E[1101]00 <1> cmp word [pxe_udp_write_pkt_dns.status],0
8449 000026E6 0F859600 <1> jne .timeout
8450 <1>
8451 000026EA 8B0E6C04 <1> mov cx,[BIOS_timer]
8452 <1> .waitrecv:
8453 000026EE A16C04 <1> mov ax,[BIOS_timer]
8454 000026F1 29C8 <1> sub ax,cx
8455 000026F3 39D0 <1> cmp ax,dx
8456 000026F5 0F838700 <1> jae .timeout
8457 <1>
8458 000026F9 C706[2501]0000 <1> mov word [pxe_udp_read_pkt_dns.status],0
8459 000026FF C706[3301]0002 <1> mov word [pxe_udp_read_pkt_dns.buffersize],DNS_MAX_PACKET
8460 00002705 BF[2501] <1> mov di,pxe_udp_read_pkt_dns
8461 00002708 BB3200 <1> mov bx,PXENV_UDP_READ
8462 0000270B E899EE <1> call pxenv
8463 0000270E 21C0 <1> and ax,ax
8464 00002710 75DC <1> jnz .waitrecv
8465 00002712 3906[2501] <1> cmp [pxe_udp_read_pkt_dns.status],ax
8466 00002716 75D6 <1> jnz .waitrecv
8467 <1>
8468 <1> ; Got a packet, deal with it...
8469 00002718 BE[9C21] <1> mov si,DNSRecvBuf
8470 0000271B AD <1> lodsw
8471 0000271C 3B06[9C1F] <1> cmp ax,[DNSSendBuf] ; ID
8472 00002720 75CC <1> jne .waitrecv ; Not ours
8473 <1>
8474 00002722 AD <1> lodsw ; flags
8475 00002723 3480 <1> xor al,80h ; Query#/Answer bit
8476 00002725 A9F80F <1> test ax,htons(0F80Fh)
8477 00002728 7549 <1> jnz .badness
8478 <1>
8479 0000272A AD <1> lodsw
8480 0000272B 86E0 <1> xchg ah,al ; ntohs
8481 0000272D 89C1 <1> mov cx,ax ; Questions echoed
8482 0000272F AD <1> lodsw
8483 00002730 86E0 <1> xchg ah,al ; ntohs
8484 00002732 50 <1> push ax ; Replies
8485 00002733 AD <1> lodsw ; NS records
8486 00002734 AD <1> lodsw ; Authority records
8487 <1>
8488 00002735 E308 <1> jcxz .qskipped
8489 <1> .skipq:
8490 00002737 E802FF <1> call dns_skiplabel ; Skip name
8491 0000273A 83C604 <1> add si,4 ; Skip question trailer
8492 0000273D E2F8 <1> loop .skipq
8493 <1>
8494 <1> .qskipped:
8495 0000273F 59 <1> pop cx ; Number of replies
8496 00002740 E331 <1> jcxz .badness
8497 <1>
8498 <1> .parseanswer:
8499 00002742 BF[A81F] <1> mov di,DNSSendBuf+dnshdr_size
8500 00002745 E8EFFE <1> call dns_compare
8501 00002748 9C <1> pushf
8502 00002749 E8F0FE <1> call dns_skiplabel
8503 0000274C 8B4408 <1> mov ax,[si+8] ; RDLENGTH
8504 0000274F 86E0 <1> xchg ah,al ; ntohs
8505 00002751 9D <1> popf
8506 00002752 7518 <1> jnz .notsame
8507 00002754 66813C00010001 <1> cmp dword [si],htons(1)*0x10001 ; TYPE = A, CLASS = IN?
8508 0000275B 750F <1> jne .notsame
8509 0000275D 83F804 <1> cmp ax,4 ; RDLENGTH = 4?
8510 00002760 750A <1> jne .notsame
8511 <1> ;
8512 <1> ; We hit paydirt here...
8513 <1> ;
8514 00002762 668B440A <1> mov eax,[si+10]
8515 <1> .gotresult:
8516 00002766 83C406 <1> add sp,6 ; Drop timeout information
8517 00002769 E93AFF <1> jmp .done
8518 <1>
8519 <1> .notsame:
8520 0000276C 83C60A <1> add si,10
8521 0000276F 01C6 <1> add si,ax
8522 00002771 E2CF <1> loop .parseanswer
8523 <1>
8524 <1> .badness:
8525 <1> ; We got back no data from this server. Unfortunately, for a recursive,
8526 <1> ; non-authoritative query there is no such thing as an NXDOMAIN reply,
8527 <1> ; which technically means we can't draw any conclusions. However,
8528 <1> ; in practice that means the domain doesn't exist. If this turns out
8529 <1> ; to be a problem, we may want to add code to go through all the servers
8530 <1> ; before giving up.
8531 <1>
8532 <1> ; If the DNS server wasn't capable of recursion, and isn't capable
8533 <1> ; of giving us an authoritative reply (i.e. neither AA or RA set),
8534 <1> ; then at least try a different setver...
8535 00002773 F706[9E21]0480 <1> test word [DNSRecvBuf+dnshdr.flags],htons(0480h)
8536 00002779 7405 <1> jz .timeout
8537 <1>
8538 0000277B 6631C0 <1> xor eax,eax
8539 0000277E EBE6 <1> jmp .gotresult
8540 <1>
8541 <1> .timeout:
8542 00002780 5A <1> pop dx
8543 00002781 59 <1> pop cx
8544 00002782 5E <1> pop si
8545 00002783 E913FF <1> jmp .servers
8546
8547 ; -----------------------------------------------------------------------------
8548 ; Begin data section
8549 ; -----------------------------------------------------------------------------
8550
8551 section .data
8552
8553 0000013B 303132333435363738- hextbl_lower db '0123456789abcdef'
8554 00000144 39616263646566
8555 0000014B 20436F707972696768- copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
8556 00000154 742028432920313939-
8557 0000015D 342D3230303520482E-
8558 00000166 20506574657220416E-
8559 0000016F 76696E
8560 00000172 0D0A00 db CR, LF, 0
8561 00000175 626F6F743A2000 boot_prompt db 'boot: ', 0
8562 0000017C 08200800 wipe_char db BS, ' ', BS, 0
8563 00000180 436F756C64206E6F74- err_notfound db 'Could not find kernel image: ',0
8564 00000189 2066696E64206B6572-
8565 00000192 6E656C20696D616765-
8566 0000019B 3A2000
8567 0000019E 0D0A496E76616C6964- err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
8568 000001A7 206F7220636F727275-
8569 000001B0 7074206B65726E656C-
8570 000001B9 20696D6167652E0D0A-
8571 000001C2 00
8572 000001C3 497420617070656172- err_noram db 'It appears your computer has less than '
8573 000001CC 7320796F757220636F-
8574 000001D5 6D7075746572206861-
8575 000001DE 73206C657373207468-
8576 000001E7 616E20
8577 000001EA 333230 asciidec dosram_k
8578 000001ED 4B206F66206C6F7720- db 'K of low ("DOS")'
8579 000001F6 2822444F532229
8580 000001FD 0D0A db CR, LF
8581 000001FF 52414D2E20204C696E- db 'RAM. Linux needs at least this amount to boot. If you get'
8582 00000208 7578206E6565647320-
8583 00000211 6174206C6561737420-
8584 0000021A 7468697320616D6F75-
8585 00000223 6E7420746F20626F6F-
8586 0000022C 742E2020496620796F-
8587 00000235 7520676574
8588 0000023A 0D0A db CR, LF
8589 0000023C 74686973206D657373- db 'this message in error, hold down the Ctrl key while'
8590 00000245 61676520696E206572-
8591 0000024E 726F722C20686F6C64-
8592 00000257 20646F776E20746865-
8593 00000260 204374726C206B6579-
8594 00000269 207768696C65
8595 0000026F 0D0A db CR, LF
8596 00000271 626F6F74696E672C20- db 'booting, and I will take your word for it.', CR, LF, 0
8597 0000027A 616E6420492077696C-
8598 00000283 6C2074616B6520796F-
8599 0000028C 757220776F72642066-
8600 00000295 6F722069742E0D0A00
8601 0000029E 556E6B6E6F776E206B- err_badcfg db 'Unknown keyword in config file.', CR, LF, 0
8602 000002A7 6579776F726420696E-
8603 000002B0 20636F6E6669672066-
8604 000002B9 696C652E0D0A00
8605 000002C0 4D697373696E672070- err_noparm db 'Missing parameter in config file.', CR, LF, 0
8606 000002C9 6172616D6574657220-
8607 000002D2 696E20636F6E666967-
8608 000002DB 2066696C652E0D0A00
8609 000002E4 0D0A436F756C64206E- err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0
8610 000002ED 6F742066696E642072-
8611 000002F6 616D6469736B20696D-
8612 000002FF 6167653A2000
8613 00000305 4E6F7420656E6F7567- err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0
8614 0000030E 68206D656D6F727920-
8615 00000317 746F206C6F61642073-
8616 00000320 706563696669656420-
8617 00000329 6B65726E656C2E0D0A-
8618 00000332 00
8619 00000333 0D0A4B65726E656C20- err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0
8620 0000033C 7472616E7366657220-
8621 00000345 6661696C7572652E0D-
8622 0000034E 0A00
8623 00000350 43616E6E6F74206C6F- err_oldkernel db 'Cannot load a ramdisk with an old kernel image.'
8624 00000359 616420612072616D64-
8625 00000362 69736B207769746820-
8626 0000036B 616E206F6C64206B65-
8627 00000374 726E656C20696D6167-
8628 0000037D 652E
8629 0000037F 0D0A00 db CR, LF, 0
8630 00000382 3A20617474656D7074- err_notdos db ': attempted DOS system call', CR, LF, 0
8631 0000038B 656420444F53207379-
8632 00000394 7374656D2063616C6C-
8633 0000039D 0D0A00
8634 000003A0 434F4D424F4F542069- err_comlarge db 'COMBOOT image too large.', CR, LF, 0
8635 000003A9 6D61676520746F6F20-
8636 000003B2 6C617267652E0D0A00
8637 000003BB 42535320696D616765- err_bssimage db 'BSS images not supported.', CR, LF, 0
8638 000003C4 73206E6F7420737570-
8639 000003CD 706F727465642E0D0A-
8640 000003D6 00
8641 000003D7 0D0A41323020676174- err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0
8642 000003E0 65206E6F7420726573-
8643 000003E9 706F6E64696E67210D-
8644 000003F2 0A00
8645 000003F4 0D0A426F6F74206661- err_bootfailed db CR, LF, 'Boot failed: press a key to retry, or wait for reset...', CR, LF, 0
8646 000003FD 696C65643A20707265-
8647 00000406 73732061206B657920-
8648 0000040F 746F2072657472792C-
8649 00000418 206F72207761697420-
8650 00000421 666F72207265736574-
8651 0000042A 2E2E2E0D0A00
8652 bailmsg equ err_bootfailed
8653 00000430 4E6F2021505845206F- err_nopxe db "No !PXE or PXENV+ API found; we're dead...", CR, LF, 0
8654 00000439 72205058454E562B20-
8655 00000442 41504920666F756E64-
8656 0000044B 3B2077652772652064-
8657 00000454 6561642E2E2E0D0A00
8658 0000045D 505845204150492063- err_pxefailed db 'PXE API call failed, error ', 0
8659 00000466 616C6C206661696C65-
8660 0000046F 642C206572726F7220-
8661 00000478 00
8662 00000479 4661696C656420746F- err_udpinit db 'Failed to initialize UDP stack', CR, LF, 0
8663 00000482 20696E697469616C69-
8664 0000048B 7A6520554450207374-
8665 00000494 61636B0D0A00
8666 0000049A 544654502073657276- err_oldtftp db 'TFTP server does not support the tsize option', CR, LF, 0
8667 000004A3 657220646F6573206E-
8668 000004AC 6F7420737570706F72-
8669 000004B5 742074686520747369-
8670 000004BE 7A65206F7074696F6E-
8671 000004C7 0D0A00
8672 000004CA 466F756E6420505845- found_pxenv db 'Found PXENV+ structure', CR, LF, 0
8673 000004D3 4E562B207374727563-
8674 000004DC 747572650D0A00
8675 000004E3 4F6C64205058452041- using_pxenv_msg db 'Old PXE API detected, using PXENV+ structure', CR, LF, 0
8676 000004EC 504920646574656374-
8677 000004F5 65642C207573696E67-
8678 000004FE 205058454E562B2073-
8679 00000507 74727563747572650D-
8680 00000510 0A00
8681 00000512 505845204150492076- apiver_str db 'PXE API version is ',0
8682 0000051B 657273696F6E206973-
8683 00000524 2000
8684 00000526 50584520656E747279- pxeentry_msg db 'PXE entry point found (we hope) at ', 0
8685 0000052F 20706F696E7420666F-
8686 00000538 756E64202877652068-
8687 00000541 6F7065292061742000
8688 0000054A 5058454E5620656E74- pxenventry_msg db 'PXENV entry point found (we hope) at ', 0
8689 00000553 727920706F696E7420-
8690 0000055C 666F756E6420287765-
8691 00000565 20686F706529206174-
8692 0000056E 2000
8693 00000570 5363616E6E696E6720- trymempxe_msg db 'Scanning memory for !PXE structure... ', 0
8694 00000579 6D656D6F727920666F-
8695 00000582 722021505845207374-
8696 0000058B 727563747572652E2E-
8697 00000594 2E2000
8698 00000597 5363616E6E696E6720- trymempxenv_msg db 'Scanning memory for PXENV+ structure... ', 0
8699 000005A0 6D656D6F727920666F-
8700 000005A9 72205058454E562B20-
8701 000005B2 737472756374757265-
8702 000005BB 2E2E2E2000
8703 000005C0 554E44492064617461- undi_data_msg db 'UNDI data segment at: ',0
8704 000005C9 207365676D656E7420-
8705 000005D2 61743A20202000
8706 000005D9 554E44492064617461- undi_data_len_msg db 'UNDI data segment size: ',0
8707 000005E2 207365676D656E7420-
8708 000005EB 73697A653A2000
8709 000005F2 554E444920636F6465- undi_code_msg db 'UNDI code segment at: ',0
8710 000005FB 207365676D656E7420-
8711 00000604 61743A20202000
8712 0000060B 554E444920636F6465- undi_code_len_msg db 'UNDI code segment size: ',0
8713 00000614 207365676D656E7420-
8714 0000061D 73697A653A2000
8715 00000624 4661696C656420746F- cant_free_msg db 'Failed to free base memory, error ', 0
8716 0000062D 206672656520626173-
8717 00000636 65206D656D6F72792C-
8718 0000063F 206572726F722000
8719 00000647 6E6F7420666F756E64- notfound_msg db 'not found', CR, LF, 0
8720 00000650 0D0A00
8721 00000653 4D7920495020616464- myipaddr_msg db 'My IP address seems to be ',0
8722 0000065C 72657373207365656D-
8723 00000665 7320746F2062652000
8724 0000066E 544654502070726566- tftpprefix_msg db 'TFTP prefix: ', 0
8725 00000677 69783A2000
8726 0000067C 426F6F74696E672066- localboot_msg db 'Booting from local disk...', CR, LF, 0
8727 00000685 726F6D206C6F63616C-
8728 0000068E 206469736B2E2E2E0D-
8729 00000697 0A00
8730 00000699 436F6D6D616E64206C- cmdline_msg db 'Command line: ', CR, LF, 0
8731 000006A2 696E653A200D0A00
8732 000006AA 52656164792E0D0A00 ready_msg db 'Ready.', CR, LF, 0
8733 000006B3 547279696E6720746F- trying_msg db 'Trying to load: ', 0
8734 000006BC 206C6F61643A2000
8735 000006C4 0D0A crlfloading_msg db CR, LF ; Fall through
8736 000006C6 4C6F6164696E672000 loading_msg db 'Loading ', 0
8737 000006CF 2E dotdot_msg db '.'
8738 000006D0 2E00 dot_msg db '.', 0
8739 000006D2 0808080800 fourbs_msg db BS, BS, BS, BS, 0
8740 000006D7 2061626F727465642E aborted_msg db ' aborted.' ; Fall through to crlf_msg!
8741 000006E0 0D0A crlf_msg db CR, LF
8742 000006E2 00 null_msg db 0
8743 000006E3 0D0C00 crff_msg db CR, FF, 0
8744 000006E6 64656661756C7400 default_str db 'default', 0
8745 default_len equ ($-default_str)
8746 000006EE 0D0A5058454C494E55- syslinux_banner db CR, LF, 'PXELINUX ', version_str, ' ', date, ' ', 0
8747 000006F7 5820332E3039203078-
8748 00000700 343165666662636120-
8749 00000709 00
8750 0000070A 7078656C696E75782E- cfgprefix db 'pxelinux.cfg/' ; No final null!
8751 00000713 6366672F
8752 cfgprefix_len equ ($-cfgprefix)
8753
8754 ;
8755 ; Command line options we'd like to take a look at
8756 ;
8757 ; mem= and vga= are handled as normal 32-bit integer values
8758 00000717 696E697472643D initrd_cmd db 'initrd='
8759 initrd_cmd_len equ $-initrd_cmd
8760
8761 ; This one we make ourselves
8762 0000071E 424F4F5449463D bootif_str db 'BOOTIF='
8763 bootif_str_len equ $-bootif_str
8764 ;
8765 ; Config file keyword table
8766 ;
8767 %include "keywords.inc"
8768 <1> ;; $Id: keywords.inc,v 1.12 2005/01/04 22:17:17 hpa Exp $
8769 <1> ;; -----------------------------------------------------------------------
8770 <1> ;;
8771 <1> ;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
8772 <1> ;;
8773 <1> ;; This program is free software; you can redistribute it and/or modify
8774 <1> ;; it under the terms of the GNU General Public License as published by
8775 <1> ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8776 <1> ;; Boston MA 02111-1307, USA; either version 2 of the License, or
8777 <1> ;; (at your option) any later version; incorporated herein by reference.
8778 <1> ;;
8779 <1> ;; -----------------------------------------------------------------------
8780 <1>
8781 <1> ;;
8782 <1> ;; keywords.inc
8783 <1> ;;
8784 <1> ;; Common header file for the handling of keyword hash and macros
8785 <1> ;;
8786 <1>
8787 <1> %ifndef DEPEND ; Generated file
8788 <1> %include "kwdhash.gen"
8789 <2> hash_hash equ 0x00000023
8790 <2> hash_menu equ 0x003719b5
8791 <2> hash_append equ 0xc53999a4
8792 <2> hash_default equ 0xcc5159ed
8793 <2> hash_display equ 0xd509bc40
8794 <2> hash_font equ 0x0032b1b4
8795 <2> hash_implicit equ 0xa6f50207
8796 <2> hash_ipappend equ 0xc5399af0
8797 <2> hash_kbdmap equ 0xd013b850
8798 <2> hash_kernel equ 0xd068b4cc
8799 <2> hash_label equ 0x06f104cc
8800 <2> hash_localboot equ 0x04f0def4
8801 <2> hash_prompt equ 0xe7163a74
8802 <2> hash_say equ 0x0001c059
8803 <2> hash_serial equ 0xe068a84c
8804 <2> hash_console equ 0x18d831fd
8805 <2> hash_timeout equ 0xd4e332c9
8806 <2> hash_allowoptions equ 0x1648dd10
8807 <2> hash_ontimeout equ 0xd4e35eb9
8808 <2> hash_onerror equ 0x1a68c589
8809 <2> hash_noescape equ 0x0d00090e
8810 <2> hash_f0 equ 0x00000cf0
8811 <2> hash_f1 equ 0x00000cf1
8812 <2> hash_f2 equ 0x00000cf2
8813 <2> hash_f3 equ 0x00000cf3
8814 <2> hash_f4 equ 0x00000cf4
8815 <2> hash_f5 equ 0x00000cf5
8816 <2> hash_f6 equ 0x00000cf6
8817 <2> hash_f7 equ 0x00000cf7
8818 <2> hash_f8 equ 0x00000cf8
8819 <2> hash_f9 equ 0x00000cf9
8820 <2> hash_f10 equ 0x00019e10
8821 <2> hash_f11 equ 0x00019e11
8822 <2> hash_f12 equ 0x00019e12
8823 <1> %endif
8824 <1>
8825 <1> %macro keyword 2
8826 <1> dd hash_%1 ; Hash value
8827 <1> dw 0 ; No argument
8828 <1> dw %2 ; Entrypoint
8829 <1> %endmacro
8830 <1>
8831 <1> %macro keyword 3
8832 <1> dd hash_%1 ; Hash value
8833 <1> dw %3 ; 16-bit argument
8834 <1> dw %2 ; Entrypoint
8835 <1> %endmacro
8836 <1>
8837 <1> %macro keyword 4
8838 <1> dd hash_%1 ; Hash value
8839 <1> db %3, %4 ; 2 8-bit arguments
8840 <1> dw %2 ; Entrypoint
8841 <1> %endmacro
8842 <1>
8843 <1> keywd_size equ 8 ; Bytes per keyword
8844 <1>
8845 00000725 00<rept> <1> align 4, db 0
8846 <1>
8847 <1> keywd_table:
8848 <1> keyword hash, pc_comment
8849 00000728 23000000 <2> dd hash_%1
8850 0000072C 0000 <2> dw 0
8851 0000072E [7B20] <2> dw %2
8852 <1> keyword menu, pc_comment
8853 00000730 B5193700 <2> dd hash_%1
8854 00000734 0000 <2> dw 0
8855 00000736 [7B20] <2> dw %2
8856 <1> keyword append, pc_append
8857 00000738 A49939C5 <2> dd hash_%1
8858 0000073C 0000 <2> dw 0
8859 0000073E [CF1E] <2> dw %2
8860 <1> keyword default, pc_default
8861 00000740 ED5951CC <2> dd hash_%1
8862 00000744 0000 <2> dw 0
8863 00000746 [A61E] <2> dw %2
8864 <1> keyword display, pc_filecmd, get_msg_file
8865 00000748 40BC09D5 <2> dd hash_%1
8866 0000074C [EE1B] <2> dw %3
8867 0000074E [5D1F] <2> dw %2
8868 <1> keyword font, pc_filecmd, loadfont
8869 00000750 B4B13200 <2> dd hash_%1
8870 00000754 [2722] <2> dw %3
8871 00000756 [5D1F] <2> dw %2
8872 <1> keyword implicit, pc_setint16, AllowImplicit
8873 00000758 0702F5A6 <2> dd hash_%1
8874 0000075C [F200] <2> dw %3
8875 0000075E [531F] <2> dw %2
8876 <1> keyword kbdmap, pc_filecmd, loadkeys
8877 00000760 50B813D0 <2> dd hash_%1
8878 00000764 [CF1B] <2> dw %3
8879 00000766 [5D1F] <2> dw %2
8880 <1> keyword kernel, pc_kernel
8881 00000768 CCB468D0 <2> dd hash_%1
8882 0000076C 0000 <2> dw 0
8883 0000076E [311F] <2> dw %2
8884 <1> keyword label, pc_label
8885 00000770 CC04F106 <2> dd hash_%1
8886 00000774 0000 <2> dw 0
8887 00000776 [3020] <2> dw %2
8888 <1> keyword prompt, pc_setint16, ForcePrompt
8889 00000778 743A16E7 <2> dd hash_%1
8890 0000077C [F000] <2> dw %3
8891 0000077E [531F] <2> dw %2
8892 <1> keyword say, pc_say
8893 00000780 59C00100 <2> dd hash_%1
8894 00000784 0000 <2> dw 0
8895 00000786 [6D20] <2> dw %2
8896 <1> keyword serial, pc_serial
8897 00000788 4CA868E0 <2> dd hash_%1
8898 0000078C 0000 <2> dw 0
8899 0000078E [701F] <2> dw %2
8900 <1> keyword console, pc_setint16, DisplayCon
8901 00000790 FD31D818 <2> dd hash_%1
8902 00000794 [BE00] <2> dw %3
8903 00000796 [531F] <2> dw %2
8904 <1> keyword timeout, pc_timeout
8905 00000798 C932E3D4 <2> dd hash_%1
8906 0000079C 0000 <2> dw 0
8907 0000079E [421F] <2> dw %2
8908 <1> keyword ontimeout, pc_ontimeout
8909 000007A0 B95EE3D4 <2> dd hash_%1
8910 000007A4 0000 <2> dw 0
8911 000007A6 [B11E] <2> dw %2
8912 <1> keyword onerror, pc_onerror
8913 000007A8 89C5681A <2> dd hash_%1
8914 000007AC 0000 <2> dw 0
8915 000007AE [C01E] <2> dw %2
8916 <1> keyword allowoptions, pc_setint16, AllowOptions
8917 000007B0 10DD4816 <2> dd hash_%1
8918 000007B4 [F400] <2> dw %3
8919 000007B6 [531F] <2> dw %2
8920 <1> keyword noescape, pc_noescape
8921 000007B8 0E09000D <2> dd hash_%1
8922 000007BC 0000 <2> dw 0
8923 000007BE [7620] <2> dw %2
8924 <1> keyword f1, pc_fkey, FKeyName+(0<<FILENAME_MAX_LG2)
8925 000007C0 F10C0000 <2> dd hash_%1
8926 000007C4 [DC16] <2> dw %3
8927 000007C6 [2720] <2> dw %2
8928 <1> keyword f2, pc_fkey, FKeyName+(1<<FILENAME_MAX_LG2)
8929 000007C8 F20C0000 <2> dd hash_%1
8930 000007CC [5C17] <2> dw %3
8931 000007CE [2720] <2> dw %2
8932 <1> keyword f3, pc_fkey, FKeyName+(2<<FILENAME_MAX_LG2)
8933 000007D0 F30C0000 <2> dd hash_%1
8934 000007D4 [DC17] <2> dw %3
8935 000007D6 [2720] <2> dw %2
8936 <1> keyword f4, pc_fkey, FKeyName+(3<<FILENAME_MAX_LG2)
8937 000007D8 F40C0000 <2> dd hash_%1
8938 000007DC [5C18] <2> dw %3
8939 000007DE [2720] <2> dw %2
8940 <1> keyword f5, pc_fkey, FKeyName+(4<<FILENAME_MAX_LG2)
8941 000007E0 F50C0000 <2> dd hash_%1
8942 000007E4 [DC18] <2> dw %3
8943 000007E6 [2720] <2> dw %2
8944 <1> keyword f6, pc_fkey, FKeyName+(5<<FILENAME_MAX_LG2)
8945 000007E8 F60C0000 <2> dd hash_%1
8946 000007EC [5C19] <2> dw %3
8947 000007EE [2720] <2> dw %2
8948 <1> keyword f7, pc_fkey, FKeyName+(6<<FILENAME_MAX_LG2)
8949 000007F0 F70C0000 <2> dd hash_%1
8950 000007F4 [DC19] <2> dw %3
8951 000007F6 [2720] <2> dw %2
8952 <1> keyword f8, pc_fkey, FKeyName+(7<<FILENAME_MAX_LG2)
8953 000007F8 F80C0000 <2> dd hash_%1
8954 000007FC [5C1A] <2> dw %3
8955 000007FE [2720] <2> dw %2
8956 <1> keyword f9, pc_fkey, FKeyName+(8<<FILENAME_MAX_LG2)
8957 00000800 F90C0000 <2> dd hash_%1
8958 00000804 [DC1A] <2> dw %3
8959 00000806 [2720] <2> dw %2
8960 <1> keyword f10, pc_fkey, FKeyName+(9<<FILENAME_MAX_LG2)
8961 00000808 109E0100 <2> dd hash_%1
8962 0000080C [5C1B] <2> dw %3
8963 0000080E [2720] <2> dw %2
8964 <1> keyword f0, pc_fkey, FKeyName+(9<<FILENAME_MAX_LG2)
8965 00000810 F00C0000 <2> dd hash_%1
8966 00000814 [5C1B] <2> dw %3
8967 00000816 [2720] <2> dw %2
8968 <1> %if IS_PXELINUX
8969 <1> keyword ipappend, pc_ipappend
8970 00000818 F09A39C5 <2> dd hash_%1
8971 0000081C 0000 <2> dw 0
8972 0000081E [021F] <2> dw %2
8973 <1> %endif
8974 <1> %if IS_PXELINUX || IS_ISOLINUX
8975 <1> keyword localboot, pc_localboot
8976 00000820 F4DEF004 <2> dd hash_%1
8977 00000824 0000 <2> dw 0
8978 00000826 [181F] <2> dw %2
8979 <1> %endif
8980 <1>
8981 <1> keywd_count equ ($-keywd_table)/keywd_size
8982 <1>
8983
8984 ;
8985 ; Extensions to search for (in *forward* order).
8986 ; (.bs and .bss are disabled for PXELINUX, since they are not supported)
8987 ;
8988 align 4, db 0
8989 00000828 2E636274 exten_table: db '.cbt' ; COMBOOT (specific)
8990 0000082C 2E300000 db '.0', 0, 0 ; PXE bootstrap program
8991 00000830 2E636F6D db '.com' ; COMBOOT (same as DOS)
8992 00000834 2E633332 db '.c32' ; COM32
8993 exten_table_end:
8994 00000838 0000000000000000 dd 0, 0 ; Need 8 null bytes here
8995
8996 ;
8997 ; PXE unload sequences
8998 ;
8999 new_api_unload:
9000 00000840 31 db PXENV_UDP_CLOSE
9001 00000841 05 db PXENV_UNDI_SHUTDOWN
9002 00000842 70 db PXENV_UNLOAD_STACK
9003 00000843 15 db PXENV_STOP_UNDI
9004 00000844 00 db 0
9005 old_api_unload:
9006 00000845 31 db PXENV_UDP_CLOSE
9007 00000846 05 db PXENV_UNDI_SHUTDOWN
9008 00000847 70 db PXENV_UNLOAD_STACK
9009 00000848 02 db PXENV_UNDI_CLEANUP
9010 00000849 00 db 0
9011
9012 ;
9013 ; PXE query packets partially filled in
9014 ;
9015 pxe_bootp_query_pkt_2:
9016 0000084A 0000 .status: dw 0 ; Status
9017 0000084C 0200 .packettype: dw 2 ; DHCPACK packet
9018 0000084E 0020 .buffersize: dw trackbufsize ; Packet size
9019 00000850 [0000]0000 .buffer: dw trackbuf, 0 ; seg:off of buffer
9020 00000854 0020 .bufferlimit: dw trackbufsize ; Unused
9021
9022 pxe_bootp_query_pkt_3:
9023 00000856 0000 .status: dw 0 ; Status
9024 00000858 0300 .packettype: dw 3 ; Boot server packet
9025 0000085A 0020 .buffersize: dw trackbufsize ; Packet size
9026 0000085C [0000]0000 .buffer: dw trackbuf, 0 ; seg:off of buffer
9027 00000860 0020 .bufferlimit: dw trackbufsize ; Unused
9028
9029 pxe_bootp_size_query_pkt:
9030 00000862 0000 .status: dw 0 ; Status
9031 00000864 0200 .packettype: dw 2 ; DHCPACK packet
9032 00000866 0000 .buffersize: dw 0 ; Packet size
9033 00000868 00000000 .buffer: dw 0, 0 ; seg:off of buffer
9034 0000086C 0000 .bufferlimit: dw 0 ; Unused
9035
9036 pxe_udp_open_pkt:
9037 0000086E 0000 .status: dw 0 ; Status
9038 00000870 00000000 .sip: dd 0 ; Source (our) IP
9039
9040 pxe_udp_close_pkt:
9041 00000874 0000 .status: dw 0 ; Status
9042
9043 pxe_udp_write_pkt:
9044 00000876 0000 .status: dw 0 ; Status
9045 00000878 00000000 .sip: dd 0 ; Server IP
9046 0000087C 00000000 .gip: dd 0 ; Gateway IP
9047 00000880 0000 .lport: dw 0 ; Local port
9048 00000882 0000 .rport: dw 0 ; Remote port
9049 00000884 0000 .buffersize: dw 0 ; Size of packet
9050 00000886 00000000 .buffer: dw 0, 0 ; seg:off of buffer
9051
9052 pxe_udp_read_pkt:
9053 0000088A 0000 .status: dw 0 ; Status
9054 0000088C 00000000 .sip: dd 0 ; Source IP
9055 00000890 00000000 .dip: dd 0 ; Destination (our) IP
9056 00000894 0000 .rport: dw 0 ; Remote port
9057 00000896 0000 .lport: dw 0 ; Local port
9058 00000898 0000 .buffersize: dw 0 ; Max packet size
9059 0000089A 00000000 .buffer: dw 0, 0 ; seg:off of buffer
9060
9061 ;
9062 ; Misc initialized (data) variables
9063 ;
9064 0000089E 00<rept> alignb 4, db 0
9065 000008A0 [00000000] BaseStack dd StackBuf ; SS:ESP of base stack
9066 000008A4 00C0 NextSocket dw 49152 ; Counter for allocating socket numbers
9067 000008A6 00 KeepPXE db 0 ; Should PXE be kept around?
9068
9069 ;
9070 ; TFTP commands
9071 ;
9072 000008A7 6F6374657400 tftp_tail db 'octet', 0 ; Octet mode
9073 000008AD 7473697A6500 tsize_str db 'tsize' ,0 ; Request size
9074 tsize_len equ ($-tsize_str)
9075 000008B3 3000 db '0', 0
9076 000008B5 626C6B73697A6500 blksize_str db 'blksize', 0 ; Request large blocks
9077 blksize_len equ ($-blksize_str)
9078 000008BD 31343430 asciidec TFTP_LARGEBLK
9079 000008C1 00 db 0
9080 tftp_tail_len equ ($-tftp_tail)
9081
9082 alignb 2, db 0
9083 ;
9084 ; Options negotiation parsing table (string pointer, string len, offset
9085 ; into socket structure)
9086 ;
9087 tftp_opt_table:
9088 000008C2 [AD08]06000C00 dw tsize_str, tsize_len, tftp_filesize
9089 000008C8 [B508]08001000 dw blksize_str, blksize_len, tftp_blksize
9090 tftp_opts equ ($-tftp_opt_table)/6
9091
9092 ;
9093 ; Error packet to return on options negotiation error
9094 ;
9095 000008CE 0005 tftp_opt_err dw TFTP_ERROR ; ERROR packet
9096 000008D0 0008 dw TFTP_EOPTNEG ; ERROR 8: bad options
9097 000008D2 7473697A65206F7074- db 'tsize option required', 0 ; Error message
9098 000008DB 696F6E207265717569-
9099 000008E4 72656400
9100 tftp_opt_err_len equ ($-tftp_opt_err)
9101
9102 alignb 4, db 0
9103 000008E8 00040000 ack_packet_buf: dw TFTP_ACK, 0 ; TFTP ACK packet
9104
9105 ;
9106 ; IP information (initialized to "unknown" values)
9107 000008EC 00000000 MyIP dd 0 ; My IP address
9108 000008F0 00000000 ServerIP dd 0 ; IP address of boot server
9109 000008F4 00000000 Netmask dd 0 ; Netmask of this subnet
9110 000008F8 00000000 Gateway dd 0 ; Default router
9111 000008FC 0045 ServerPort dw TFTP_PORT ; TFTP server port
9112
9113 ;
9114 ; Variables that are uninitialized in SYSLINUX but initialized here
9115 ;
9116 000008FE 00<rept> alignb 4, db 0
9117 00000900 1000 BufSafe dw trackbufsize/TFTP_BLOCKSIZE ; Clusters we can load into trackbuf
9118 00000902 1000 BufSafeSec dw trackbufsize/512 ; = how many sectors?
9119 00000904 0020 BufSafeBytes dw trackbufsize ; = how many bytes?
9120 00000906 [0040] EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes
9121 %ifndef DEPEND
9122 %if ( trackbufsize % TFTP_BLOCKSIZE ) != 0
9123 %error trackbufsize must be a multiple of TFTP_BLOCKSIZE
9124 %endif
9125 %endif
9126 00000908 00 IPAppend db 0 ; Default IPAPPEND option
9127 00000909 00 DHCPMagic db 0 ; DHCP site-specific option info