|
|
1.1 root 1: /* At entry, the processor is in 16 bit real mode and the code is being
2: * executed from an address it was not linked to. Code must be pic and
3: * 32 bit sensitive until things are fixed up.
4: *
5: * Also be very careful as the stack is at the rear end of the interrupt
6: * table so using a noticeable amount of stack space is a no-no.
7: */
8:
9: FILE_LICENCE ( GPL2_OR_LATER )
10:
11: #include <config/general.h>
12:
13: #define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
14: #define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
15: #define PCI_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( ' ' << 24 ) )
16: #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
17: #define PMM_ALLOCATE 0x0000
18: #define PMM_FIND 0x0001
19: #define PMM_HANDLE_BASE ( ( ( 'F' - 'A' + 1 ) << 26 ) + \
20: ( ( 'E' - 'A' + 1 ) << 21 ) + \
21: ( ( 'N' - 'A' + 1 ) << 16 ) )
22: #define PMM_HANDLE_BASE_IMAGE_SOURCE \
23: ( PMM_HANDLE_BASE | 0x00001000 )
24: #define PMM_HANDLE_BASE_DECOMPRESS_TO \
25: ( PMM_HANDLE_BASE | 0x00002000 )
26:
27: /* ROM banner timeout. Based on the configurable BANNER_TIMEOUT in
28: * config.h, but converted to a number of (18Hz) timer ticks, and
29: * doubled to allow for BIOSes that switch video modes immediately
30: * beforehand, so rendering the message almost invisible to the user.
31: */
32: #define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 )
33:
34: /* Allow payload to be excluded from ROM size
35: */
36: #if ROMPREFIX_EXCLUDE_PAYLOAD
37: #define ZINFO_TYPE_ADxB "ADHB"
38: #define ZINFO_TYPE_ADxW "ADHW"
39: #else
40: #define ZINFO_TYPE_ADxB "ADDB"
41: #define ZINFO_TYPE_ADxW "ADDW"
42: #endif
43:
44: .text
45: .code16
46: .arch i386
47: .section ".prefix", "ax", @progbits
48: .globl _rom_start
49: _rom_start:
50:
51: .org 0x00
52: romheader:
53: .word 0xAA55 /* BIOS extension signature */
54: romheader_size: .byte 0 /* Size in 512-byte blocks */
55: jmp init /* Initialisation vector */
56: checksum:
57: .byte 0
58: .org 0x16
59: .word undiheader
60: .org 0x18
61: .word pciheader
62: .org 0x1a
63: .word pnpheader
64: .size romheader, . - romheader
65:
66: .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
67: .ascii ZINFO_TYPE_ADxB
68: .long romheader_size
69: .long 512
70: .long 0
71: .previous
72:
73: build_id:
74: .long _build_id /* Randomly-generated build ID */
75:
76: pciheader:
77: .ascii "PCIR" /* Signature */
78: .word pci_vendor_id /* Vendor identification */
79: .word pci_device_id /* Device identification */
80: .word 0x0000 /* Device list pointer */
81: .word pciheader_len /* PCI data structure length */
82: .byte 0x03 /* PCI data structure revision */
83: .byte 0x02, 0x00, 0x00 /* Class code */
84: pciheader_image_length:
85: .word 0 /* Image length */
86: .word 0x0001 /* Revision level */
87: .byte 0x00 /* Code type */
88: .byte 0x80 /* Last image indicator */
89: pciheader_runtime_length:
90: .word 0 /* Maximum run-time image length */
91: .word 0x0000 /* Configuration utility code header */
92: .word 0x0000 /* DMTF CLP entry point */
93: .equ pciheader_len, . - pciheader
94: .size pciheader, . - pciheader
95:
96: .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
97: .ascii ZINFO_TYPE_ADxW
98: .long pciheader_image_length
99: .long 512
100: .long 0
101: .ascii ZINFO_TYPE_ADxW
102: .long pciheader_runtime_length
103: .long 512
104: .long 0
105: .previous
106:
107: pnpheader:
108: .ascii "$PnP" /* Signature */
109: .byte 0x01 /* Structure revision */
110: .byte ( pnpheader_len / 16 ) /* Length (in 16 byte increments) */
111: .word 0x0000 /* Offset of next header */
112: .byte 0x00 /* Reserved */
113: .byte 0x00 /* Checksum */
114: .long 0x00000000 /* Device identifier */
115: .word mfgstr /* Manufacturer string */
116: .word prodstr /* Product name */
117: .byte 0x02 /* Device base type code */
118: .byte 0x00 /* Device sub-type code */
119: .byte 0x00 /* Device interface type code */
120: .byte 0xf4 /* Device indicator */
121: .word 0x0000 /* Boot connection vector */
122: .word 0x0000 /* Disconnect vector */
123: .word bev_entry /* Boot execution vector */
124: .word 0x0000 /* Reserved */
125: .word 0x0000 /* Static resource information vector*/
126: .equ pnpheader_len, . - pnpheader
127: .size pnpheader, . - pnpheader
128:
129: /* Manufacturer string */
130: mfgstr:
131: .asciz "http://ipxe.org"
132: .size mfgstr, . - mfgstr
133:
134: /* Product string
135: *
136: * Defaults to PRODUCT_SHORT_NAME. If the ROM image is writable at
137: * initialisation time, it will be filled in to include the PCI
138: * bus:dev.fn number of the card as well.
139: */
140: prodstr:
141: .ascii PRODUCT_SHORT_NAME
142: prodstr_separator:
143: .byte 0
144: .ascii "(PCI "
145: prodstr_pci_id:
146: .asciz "xx:xx.x)" /* Filled in by init code */
147: .size prodstr, . - prodstr
148:
149: .globl undiheader
150: .weak undiloader
151: undiheader:
152: .ascii "UNDI" /* Signature */
153: .byte undiheader_len /* Length of structure */
154: .byte 0 /* Checksum */
155: .byte 0 /* Structure revision */
156: .byte 0,1,2 /* PXE version: 2.1.0 */
157: .word undiloader /* Offset to loader routine */
158: .word _data16_memsz /* Stack segment size */
159: .word _data16_memsz /* Data segment size */
160: .word _text16_memsz /* Code segment size */
161: .ascii "PCIR" /* Bus type */
162: .equ undiheader_len, . - undiheader
163: .size undiheader, . - undiheader
164:
165: /* Initialisation (called once during POST)
166: *
167: * Determine whether or not this is a PnP system via a signature
168: * check. If it is PnP, return to the PnP BIOS indicating that we are
169: * a boot-capable device; the BIOS will call our boot execution vector
170: * if it wants to boot us. If it is not PnP, hook INT 19.
171: */
172: init:
173: /* Preserve registers, clear direction flag, set %ds=%cs */
174: pushaw
175: pushw %ds
176: pushw %es
177: pushw %fs
178: pushw %gs
179: cld
180: pushw %cs
181: popw %ds
182:
183: /* Shuffle some registers around. We need %di available for
184: * the print_xxx functions, and in a register that's
185: * addressable from %es, so shuffle as follows:
186: *
187: * %di (pointer to PnP structure) => %bx
188: * %bx (runtime segment address, for PCI 3.0) => %gs
189: */
190: movw %bx, %gs
191: movw %di, %bx
192:
193: /* Store PCI bus:dev.fn address */
194: movw %ax, init_pci_busdevfn
195:
196: /* Print message as early as possible */
197: movw $init_message, %si
198: xorw %di, %di
199: call print_message
200: call print_pci_busdevfn
201:
202: /* Fill in product name string, if possible */
203: movw $prodstr_pci_id, %di
204: call print_pci_busdevfn
205: movb $( ' ' ), prodstr_separator
206:
207: /* Print segment address */
208: movb $( ' ' ), %al
209: xorw %di, %di
210: call print_character
211: movw %cs, %ax
212: call print_hex_word
213:
214: /* Check for PCI BIOS version */
215: pushl %ebx
216: pushl %edx
217: pushl %edi
218: stc
219: movw $0xb101, %ax
220: int $0x1a
221: jc no_pci3
222: cmpl $PCI_SIGNATURE, %edx
223: jne no_pci3
224: testb %ah, %ah
225: jnz no_pci3
226: movw $init_message_pci, %si
227: xorw %di, %di
228: call print_message
229: movb %bh, %al
230: call print_hex_nibble
231: movb $( '.' ), %al
232: call print_character
233: movb %bl, %al
234: call print_hex_byte
235: cmpb $3, %bh
236: jb no_pci3
237: /* PCI >=3.0: leave %gs as-is if sane */
238: movw %gs, %ax
239: cmpw $0xa000, %ax /* Insane if %gs < 0xa000 */
240: jb pci3_insane
241: movw %cs, %bx /* Sane if %cs == %gs */
242: cmpw %bx, %ax
243: je 1f
244: movzbw romheader_size, %cx /* Sane if %cs+len <= %gs */
245: shlw $5, %cx
246: addw %cx, %bx
247: cmpw %bx, %ax
248: jae 1f
249: movw %cs, %bx /* Sane if %gs+len <= %cs */
250: addw %cx, %ax
251: cmpw %bx, %ax
252: jbe 1f
253: pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */
254: movb $( '!' ), %al
255: call print_character
256: movw %gs, %ax
257: call print_hex_word
258: no_pci3:
259: /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
260: pushw %cs
261: popw %gs
262: 1: popl %edi
263: popl %edx
264: popl %ebx
265:
266: /* Check for PnP BIOS. Although %es:di should point to the
267: * PnP BIOS signature on entry, some BIOSes fail to do this.
268: */
269: movw $( 0xf000 - 1 ), %bx
270: pnp_scan:
271: incw %bx
272: jz no_pnp
273: movw %bx, %es
274: cmpl $PNP_SIGNATURE, %es:0
275: jne pnp_scan
276: xorw %dx, %dx
277: xorw %si, %si
278: movzbw %es:5, %cx
279: 1: es lodsb
280: addb %al, %dl
281: loop 1b
282: jnz pnp_scan
283: /* Is PnP: print PnP message */
284: movw $init_message_pnp, %si
285: xorw %di, %di
286: call print_message
287: jmp pnp_done
288: no_pnp: /* Not PnP-compliant - hook INT 19 */
289: movw $init_message_int19, %si
290: xorw %di, %di
291: call print_message
292: xorw %ax, %ax
293: movw %ax, %es
294: pushl %es:( 0x19 * 4 )
295: popl orig_int19
296: pushw %gs /* %gs contains runtime %cs */
297: pushw $int19_entry
298: popl %es:( 0x19 * 4 )
299: pnp_done:
300:
301: /* Check for PMM */
302: movw $( 0xe000 - 1 ), %bx
303: pmm_scan:
304: incw %bx
305: jz no_pmm
306: movw %bx, %es
307: cmpl $PMM_SIGNATURE, %es:0
308: jne pmm_scan
309: xorw %dx, %dx
310: xorw %si, %si
311: movzbw %es:5, %cx
312: 1: es lodsb
313: addb %al, %dl
314: loop 1b
315: jnz pmm_scan
316: /* PMM found: print PMM message */
317: movw $init_message_pmm, %si
318: xorw %di, %di
319: call print_message
320: /* We have PMM and so a 1kB stack: preserve whole registers */
321: pushal
322: /* Allocate image source PMM block */
323: movzwl image_source_size, %ecx
324: shll $5, %ecx
325: movl $PMM_HANDLE_BASE_IMAGE_SOURCE, %ebx
326: movw $get_pmm_image_source, %bp
327: call get_pmm
328: movl %esi, image_source
329: jc 1f
330: /* Copy ROM to image source PMM block */
331: pushw %es
332: xorw %ax, %ax
333: movw %ax, %es
334: movl %esi, %edi
335: xorl %esi, %esi
336: movzbl romheader_size, %ecx
337: shll $9, %ecx
338: addr32 rep movsb /* PMM presence implies flat real mode */
339: popw %es
340: /* Shrink ROM */
341: movb shrunk_rom_size, %al
342: movb %al, romheader_size
343: 1: /* Allocate decompression PMM block. Round up the size to the
344: * nearest 128kB and use the size within the PMM handle; this
345: * allows the same decompression area to be shared between
346: * multiple iPXE ROMs even with differing build IDs
347: */
348: movl $_textdata_memsz_pgh, %ecx
349: addl $0x00001fff, %ecx
350: andl $0xffffe000, %ecx
351: movl %ecx, %ebx
352: shrw $12, %bx
353: orl $PMM_HANDLE_BASE_DECOMPRESS_TO, %ebx
354: movw $get_pmm_decompress_to, %bp
355: call get_pmm
356: movl %esi, decompress_to
357: /* Restore registers */
358: popal
359: no_pmm:
360:
361: /* Update checksum */
362: xorw %bx, %bx
363: xorw %si, %si
364: movzbw romheader_size, %cx
365: shlw $9, %cx
366: 1: lodsb
367: addb %al, %bl
368: loop 1b
369: subb %bl, checksum
370:
371: /* Copy self to option ROM space. Required for PCI3.0, which
372: * loads us to a temporary location in low memory. Will be a
373: * no-op for lower PCI versions.
374: */
375: movb $( ' ' ), %al
376: xorw %di, %di
377: call print_character
378: movw %gs, %ax
379: call print_hex_word
380: movzbw romheader_size, %cx
381: shlw $9, %cx
382: movw %ax, %es
383: xorw %si, %si
384: xorw %di, %di
385: cs rep movsb
386:
387: /* Prompt for POST-time shell */
388: movw $init_message_prompt, %si
389: xorw %di, %di
390: call print_message
391: movw $prodstr, %si
392: call print_message
393: movw $init_message_dots, %si
394: call print_message
395: /* Wait for Ctrl-B */
396: movw $0xff02, %bx
397: call wait_for_key
398: /* Clear prompt */
399: pushf
400: xorw %di, %di
401: call print_kill_line
402: movw $init_message_done, %si
403: call print_message
404: popf
405: jnz 2f
406: /* Ctrl-B was pressed: invoke iPXE. The keypress will be
407: * picked up by the initial shell prompt, and we will drop
408: * into a shell.
409: */
410: stc /* Inhibit relocation */
411: pushw %cs
412: call exec
413: 2:
414: /* Restore registers */
415: popw %gs
416: popw %fs
417: popw %es
418: popw %ds
419: popaw
420:
421: /* Indicate boot capability to PnP BIOS, if present */
422: movw $0x20, %ax
423: lret
424: .size init, . - init
425:
426: /* Attempt to find or allocate PMM block
427: *
428: * Parameters:
429: * %ecx : size of block to allocate, in paragraphs
430: * %ebx : PMM handle base
431: * %bp : routine to check acceptability of found blocks
432: * %es:0000 : PMM structure
433: * Returns:
434: * %ebx : PMM handle
435: * %esi : allocated block address, or zero (with CF set) if allocation failed
436: */
437: get_pmm:
438: /* Preserve registers */
439: pushl %eax
440: pushw %di
441: movw $' ', %di
442: get_pmm_find:
443: /* Try to find existing block */
444: pushl %ebx /* PMM handle */
445: pushw $PMM_FIND
446: lcall *%es:7
447: addw $6, %sp
448: pushw %dx
449: pushw %ax
450: popl %esi
451: testl %esi, %esi
452: jz get_pmm_allocate
453: /* Block found - check acceptability */
454: call *%bp
455: jnc get_pmm_done
456: /* Block not acceptable - increment handle and retry */
457: incl %ebx
458: jmp get_pmm_find
459: get_pmm_allocate:
460: /* Block not found - try to allocate new block */
461: pushw $0x0002 /* Extended memory */
462: pushl %ebx /* PMM handle */
463: pushl %ecx /* Length */
464: pushw $PMM_ALLOCATE
465: lcall *%es:7
466: addw $12, %sp
467: pushw %dx
468: pushw %ax
469: popl %esi
470: movw $'+', %di /* Indicate allocation attempt */
471: testl %esi, %esi
472: jnz get_pmm_done
473: stc
474: get_pmm_done:
475: /* Print block address */
476: pushfw
477: movw %di, %ax
478: xorw %di, %di
479: call print_character
480: movl %esi, %eax
481: call print_hex_dword
482: popfw
483: /* Restore registers and return */
484: popw %di
485: popl %eax
486: ret
487: .size get_pmm, . - get_pmm
488:
489: /* Check acceptability of image source block */
490: get_pmm_image_source:
491: pushw %es
492: xorw %ax, %ax
493: movw %ax, %es
494: movl build_id, %eax
495: addr32 cmpl %es:build_id(%esi), %eax
496: je 1f
497: stc
498: 1: popw %es
499: ret
500: .size get_pmm_image_source, . - get_pmm_image_source
501:
502: /* Check acceptability of decompression block */
503: get_pmm_decompress_to:
504: clc
505: ret
506: .size get_pmm_decompress_to, . - get_pmm_decompress_to
507:
508: /*
509: * Note to hardware vendors:
510: *
511: * If you wish to brand this boot ROM, please do so by defining the
512: * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/general.h.
513: *
514: * While nothing in the GPL prevents you from removing all references
515: * to iPXE or http://ipxe.org, we prefer you not to do so.
516: *
517: * If you have an OEM-mandated branding requirement that cannot be
518: * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
519: * please contact us.
520: *
521: * [ Including an ASCII NUL in PRODUCT_NAME is considered to be
522: * bypassing the spirit of this request! ]
523: */
524: init_message:
525: .ascii "\n"
526: .ascii PRODUCT_NAME
527: .ascii "\n"
528: .asciz "iPXE (http://ipxe.org) "
529: .size init_message, . - init_message
530: init_message_pci:
531: .asciz " PCI"
532: .size init_message_pci, . - init_message_pci
533: init_message_pnp:
534: .asciz " PnP"
535: .size init_message_pnp, . - init_message_pnp
536: init_message_pmm:
537: .asciz " PMM"
538: .size init_message_pmm, . - init_message_pmm
539: init_message_int19:
540: .asciz " INT19"
541: .size init_message_int19, . - init_message_int19
542: init_message_prompt:
543: .asciz "\nPress Ctrl-B to configure "
544: .size init_message_prompt, . - init_message_prompt
545: init_message_dots:
546: .asciz "..."
547: .size init_message_dots, . - init_message_dots
548: init_message_done:
549: .asciz "\n\n"
550: .size init_message_done, . - init_message_done
551:
552: /* PCI bus:dev.fn
553: *
554: */
555: init_pci_busdevfn:
556: .word 0xffff
557: .size init_pci_busdevfn, . - init_pci_busdevfn
558:
559: /* Image source area
560: *
561: * May be either zero (indicating to use option ROM space as source),
562: * or within a PMM-allocated block.
563: */
564: .globl image_source
565: image_source:
566: .long 0
567: .size image_source, . - image_source
568:
569: /* Image source size (in 512-byte sectors)
570: *
571: */
572: image_source_size:
573: .word 0
574: .size image_source_size, . - image_source_size
575: .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
576: .ascii "ADDW"
577: .long image_source_size
578: .long 512
579: .long 0
580: .previous
581:
582: /* Shrunk ROM size (in 512-byte sectors)
583: *
584: */
585: shrunk_rom_size:
586: .byte 0
587: .size shrunk_rom_size, . - shrunk_rom_size
588: .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
589: .ascii "ADHB"
590: .long shrunk_rom_size
591: .long 512
592: .long 0
593: .previous
594:
595: /* Temporary decompression area
596: *
597: * May be either zero (indicating to use default decompression area in
598: * high memory), or within a PMM-allocated block.
599: */
600: .globl decompress_to
601: decompress_to:
602: .long 0
603: .size decompress_to, . - decompress_to
604:
605: /* Boot Execution Vector entry point
606: *
607: * Called by the PnP BIOS when it wants to boot us.
608: */
609: bev_entry:
610: clc /* Allow relocation */
611: pushw %cs
612: call exec
613: lret
614: .size bev_entry, . - bev_entry
615:
616: /* INT19 entry point
617: *
618: * Called via the hooked INT 19 if we detected a non-PnP BIOS. We
619: * attempt to return via the original INT 19 vector (if we were able
620: * to store it).
621: */
622: int19_entry:
623: pushw %cs
624: popw %ds
625: /* Prompt user to press B to boot */
626: movw $int19_message_prompt, %si
627: xorw %di, %di
628: call print_message
629: movw $prodstr, %si
630: call print_message
631: movw $int19_message_dots, %si
632: call print_message
633: movw $0xdf4e, %bx
634: call wait_for_key
635: pushf
636: xorw %di, %di
637: call print_kill_line
638: movw $int19_message_done, %si
639: call print_message
640: popf
641: jz 1f
642: /* Leave keypress in buffer and start iPXE. The keypress will
643: * cause the usual initial Ctrl-B prompt to be skipped.
644: */
645: clc /* Allow relocation */
646: pushw %cs
647: call exec
648: 1: /* Try to call original INT 19 vector */
649: movl %cs:orig_int19, %eax
650: testl %eax, %eax
651: je 2f
652: ljmp *%cs:orig_int19
653: 2: /* No chained vector: issue INT 18 as a last resort */
654: int $0x18
655: .size int19_entry, . - int19_entry
656: orig_int19:
657: .long 0
658: .size orig_int19, . - orig_int19
659:
660: int19_message_prompt:
661: .asciz "Press N to skip booting from "
662: .size int19_message_prompt, . - int19_message_prompt
663: int19_message_dots:
664: .asciz "..."
665: .size int19_message_dots, . - int19_message_dots
666: int19_message_done:
667: .asciz "\n\n"
668: .size int19_message_done, . - int19_message_done
669:
670: /* Execute as a boot device
671: *
672: */
673: exec: /* Set %ds = %cs */
674: pushw %cs
675: popw %ds
676:
677: /* Preserve state of CF */
678: lahf
679:
680: /* Print message as soon as possible */
681: movw $prodstr, %si
682: xorw %di, %di
683: call print_message
684: movw $exec_message_pre_install, %si
685: call print_message
686:
687: /* Store magic word on BIOS stack and remember BIOS %ss:sp */
688: pushl $STACK_MAGIC
689: movw %ss, %dx
690: movw %sp, %bp
691:
692: /* Obtain a reasonably-sized temporary stack */
693: xorw %bx, %bx
694: movw %bx, %ss
695: movw $0x7c00, %sp
696:
697: /* Install iPXE */
698: sahf
699: pushfw
700: call alloc_basemem
701: popfw
702: movl image_source, %esi
703: movl decompress_to, %edi
704: call install_prealloc
705:
706: /* Print message indicating successful installation */
707: movw $exec_message_post_install, %si
708: xorw %di, %di
709: call print_message
710:
711: /* Set up real-mode stack */
712: movw %bx, %ss
713: movw $_estack16, %sp
714:
715: /* Jump to .text16 segment */
716: pushw %ax
717: pushw $1f
718: lret
719: .section ".text16", "awx", @progbits
720: 1: /* Call main() */
721: pushl $main
722: pushw %cs
723: call prot_call
724: popl %ecx /* discard */
725:
726: /* Uninstall iPXE */
727: call uninstall
728:
729: /* Restore BIOS stack */
730: movw %dx, %ss
731: movw %bp, %sp
732:
733: /* Check magic word on BIOS stack */
734: popl %eax
735: cmpl $STACK_MAGIC, %eax
736: jne 1f
737: /* BIOS stack OK: return to caller */
738: lret
739: 1: /* BIOS stack corrupt: use INT 18 */
740: int $0x18
741: .previous
742:
743: exec_message_pre_install:
744: .asciz " starting execution..."
745: .size exec_message_pre_install, . - exec_message_pre_install
746: exec_message_post_install:
747: .asciz "ok\n"
748: .size exec_message_post_install, . - exec_message_post_install
749:
750: /* Wait for key press specified by %bl (masked by %bh)
751: *
752: * Used by init and INT19 code when prompting user. If the specified
753: * key is pressed, it is left in the keyboard buffer.
754: *
755: * Returns with ZF set iff specified key is pressed.
756: */
757: wait_for_key:
758: /* Preserve registers */
759: pushw %cx
760: pushw %ax
761: 1: /* Empty the keyboard buffer before waiting for input */
762: movb $0x01, %ah
763: int $0x16
764: jz 2f
765: xorw %ax, %ax
766: int $0x16
767: jmp 1b
768: 2: /* Wait for a key press */
769: movw $ROM_BANNER_TIMEOUT, %cx
770: 3: decw %cx
771: js 99f /* Exit with ZF clear */
772: /* Wait for timer tick to be updated */
773: call wait_for_tick
774: /* Check to see if a key was pressed */
775: movb $0x01, %ah
776: int $0x16
777: jz 3b
778: /* Check to see if key was the specified key */
779: andb %bh, %al
780: cmpb %al, %bl
781: je 99f /* Exit with ZF set */
782: /* Not the specified key: remove from buffer and stop waiting */
783: pushfw
784: xorw %ax, %ax
785: int $0x16
786: popfw /* Exit with ZF clear */
787: 99: /* Restore registers and return */
788: popw %ax
789: popw %cx
790: ret
791: .size wait_for_key, . - wait_for_key
792:
793: /* Wait for timer tick
794: *
795: * Used by wait_for_key
796: */
797: wait_for_tick:
798: pushl %eax
799: pushw %fs
800: movw $0x40, %ax
801: movw %ax, %fs
802: movl %fs:(0x6c), %eax
803: 1: pushf
804: sti
805: hlt
806: popf
807: cmpl %fs:(0x6c), %eax
808: je 1b
809: popw %fs
810: popl %eax
811: ret
812: .size wait_for_tick, . - wait_for_tick
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.