7 #include <syslinux/memscan.h>
8 #include <syslinux/firmware.h>
9 #include <syslinux/video.h>
11 #include <sys/vesa/vesa.h>
12 #include <sys/vesa/video.h>
13 #include <sys/vesa/debug.h>
17 __export
struct firmware
*firmware
= NULL
;
19 extern struct ansi_ops bios_ansi_ops
;
21 #define BIOS_CURXY ((struct curxy *)0x450) /* Array for each page */
22 #define BIOS_ROWS (*(uint8_t *)0x484) /* Minus one; if zero use 24 (= 25 lines) */
23 #define BIOS_COLS (*(uint16_t *)0x44A)
24 #define BIOS_PAGE (*(uint8_t *)0x462)
26 static void bios_text_mode(void)
28 syslinux_force_text_mode();
31 static void bios_get_mode(int *cols
, int *rows
)
33 *rows
= BIOS_ROWS
? BIOS_ROWS
+ 1 : 25;
37 static uint16_t cursor_type
; /* Saved cursor pattern */
39 static void bios_get_cursor(uint8_t *x
, uint8_t *y
)
41 com32sys_t ireg
, oreg
;
43 memset(&ireg
, 0, sizeof(ireg
));
46 ireg
.ebx
.b
[1] = BIOS_PAGE
;
47 __intcall(0x10, &ireg
, &oreg
);
48 cursor_type
= oreg
.ecx
.w
[0];
53 static void bios_erase(int x0
, int y0
, int x1
, int y1
, uint8_t attribute
)
55 static com32sys_t ireg
;
56 memset(&ireg
, 0, sizeof(ireg
));
58 ireg
.eax
.w
[0] = 0x0600; /* Clear window */
59 ireg
.ebx
.b
[1] = attribute
;
64 __intcall(0x10, &ireg
, NULL
);
67 static void bios_showcursor(const struct term_state
*st
)
69 static com32sys_t ireg
;
70 uint16_t cursor
= st
->cursor
? cursor_type
: 0x2020;
72 memset(&ireg
, 0, sizeof(ireg
));
75 ireg
.ecx
.w
[0] = cursor
;
76 __intcall(0x10, &ireg
, NULL
);
79 static void bios_set_cursor(int x
, int y
, bool visible
)
81 const int page
= BIOS_PAGE
;
82 struct curxy xy
= BIOS_CURXY
[page
];
83 static com32sys_t ireg
;
85 memset(&ireg
, 0, sizeof(ireg
));
89 if (xy
.x
!= x
|| xy
.y
!= y
) {
94 __intcall(0x10, &ireg
, NULL
);
98 static void bios_write_char(uint8_t ch
, uint8_t attribute
)
100 static com32sys_t ireg
;
102 memset(&ireg
, 0, sizeof(ireg
));
104 ireg
.eax
.b
[1] = 0x09;
106 ireg
.ebx
.b
[1] = BIOS_PAGE
;
107 ireg
.ebx
.b
[0] = attribute
;
109 __intcall(0x10, &ireg
, NULL
);
112 static void bios_scroll_up(uint8_t cols
, uint8_t rows
, uint8_t attribute
)
114 static com32sys_t ireg
;
116 memset(&ireg
, 0, sizeof(ireg
));
118 ireg
.eax
.w
[0] = 0x0601;
119 ireg
.ebx
.b
[1] = attribute
;
121 ireg
.edx
.b
[1] = rows
;
122 ireg
.edx
.b
[0] = cols
;
123 __intcall(0x10, &ireg
, NULL
); /* Scroll */
126 static void bios_beep(void)
128 static com32sys_t ireg
;
130 memset(&ireg
, 0, sizeof(ireg
));
132 ireg
.eax
.w
[0] = 0x0e07;
133 ireg
.ebx
.b
[1] = BIOS_PAGE
;
134 __intcall(0x10, &ireg
, NULL
);
137 struct output_ops bios_output_ops
= {
139 .write_char
= bios_write_char
,
140 .showcursor
= bios_showcursor
,
141 .set_cursor
= bios_set_cursor
,
142 .scroll_up
= bios_scroll_up
,
144 .get_mode
= bios_get_mode
,
145 .text_mode
= bios_text_mode
,
146 .get_cursor
= bios_get_cursor
,
149 extern char bios_getchar(char *);
150 extern int bios_pollchar(void);
151 extern uint8_t bios_shiftflags(void);
153 struct input_ops bios_input_ops
= {
154 .getchar
= bios_getchar
,
155 .pollchar
= bios_pollchar
,
156 .shiftflags
= bios_shiftflags
,
159 static void bios_get_serial_console_info(uint16_t *iobase
, uint16_t *divisor
,
162 *iobase
= SerialPort
;
163 *divisor
= BaudDivisor
;
165 *flowctl
= FlowOutput
| FlowInput
| (FlowIgnore
<< 4);
168 *flowctl
|= (0x80 << 8);
171 void bios_adv_init(void)
173 static com32sys_t reg
;
175 memset(®
, 0, sizeof(reg
));
176 call16(adv_init
, ®
, NULL
);
179 int bios_adv_write(void)
181 static com32sys_t reg
;
183 memset(®
, 0, sizeof(reg
));
184 call16(adv_write
, ®
, ®
);
185 return (reg
.eflags
.l
& EFLAGS_CF
) ? -1 : 0;
188 struct adv_ops bios_adv_ops
= {
189 .init
= bios_adv_init
,
190 .write
= bios_adv_write
,
194 static int __constfunc
is_power_of_2(unsigned int x
)
196 return x
&& !(x
& (x
- 1));
199 static int vesacon_paged_mode_ok(const struct vesa_mode_info
*mi
)
203 if (!is_power_of_2(mi
->win_size
) ||
204 !is_power_of_2(mi
->win_grain
) || mi
->win_grain
> mi
->win_size
)
205 return 0; /* Impossible... */
207 for (i
= 0; i
< 2; i
++) {
208 if ((mi
->win_attr
[i
] & 0x05) == 0x05 && mi
->win_seg
[i
])
209 return 1; /* Usable window */
212 return 0; /* Nope... */
215 static int bios_vesacon_set_mode(struct vesa_info
*vesa_info
, int *px
, int *py
,
216 enum vesa_pixel_format
*bestpxf
)
219 uint16_t mode
, bestmode
, *mode_ptr
;
220 struct vesa_info
*vi
;
221 struct vesa_general_info
*gi
;
222 struct vesa_mode_info
*mi
;
223 enum vesa_pixel_format pxf
;
224 int x
= *px
, y
= *py
;
227 /* Allocate space in the bounce buffer for these structures */
228 vi
= lzalloc(sizeof *vi
);
230 err
= 10; /* Out of memory */
236 memset(&rm
, 0, sizeof rm
);
238 gi
->signature
= VBE2_MAGIC
; /* Get VBE2 extended data */
239 rm
.eax
.w
[0] = 0x4F00; /* Get SVGA general information */
240 rm
.edi
.w
[0] = OFFS(gi
);
242 __intcall(0x10, &rm
, &rm
);
244 if (rm
.eax
.w
[0] != 0x004F) {
245 err
= 1; /* Function call failed */
248 if (gi
->signature
!= VESA_MAGIC
) {
249 err
= 2; /* No magic */
252 if (gi
->version
< 0x0102) {
253 err
= 3; /* VESA 1.2+ required */
257 /* Copy general info */
258 memcpy(&vesa_info
->gi
, gi
, sizeof *gi
);
260 /* Search for the proper mode with a suitable color and memory model... */
262 mode_ptr
= GET_PTR(gi
->video_mode_ptr
);
266 while ((mode
= *mode_ptr
++) != 0xFFFF) {
267 mode
&= 0x1FF; /* The rest are attributes of sorts */
269 debug("Found mode: 0x%04x\r\n", mode
);
271 memset(&rm
, 0, sizeof rm
);
272 memset(mi
, 0, sizeof *mi
);
273 rm
.eax
.w
[0] = 0x4F01; /* Get SVGA mode information */
275 rm
.edi
.w
[0] = OFFS(mi
);
277 __intcall(0x10, &rm
, &rm
);
279 /* Must be a supported mode */
280 if (rm
.eax
.w
[0] != 0x004f)
284 ("mode_attr 0x%04x, h_res = %4d, v_res = %4d, bpp = %2d, layout = %d (%d,%d,%d)\r\n",
285 mi
->mode_attr
, mi
->h_res
, mi
->v_res
, mi
->bpp
, mi
->memory_layout
,
286 mi
->rpos
, mi
->gpos
, mi
->bpos
);
288 /* Must be an LFB color graphics mode supported by the hardware.
293 1 - mode information available (mandatory in VBE 1.2+)
294 0 - mode supported by hardware
296 if ((mi
->mode_attr
& 0x001b) != 0x001b)
299 /* Must be the chosen size */
300 if (mi
->h_res
!= x
|| mi
->v_res
!= y
)
303 /* We don't support multibank (interlaced memory) modes */
305 * Note: The Bochs VESA BIOS (vbe.c 1.58 2006/08/19) violates the
306 * specification which states that banks == 1 for unbanked modes;
307 * fortunately it does report bank_size == 0 for those.
309 if (mi
->banks
> 1 && mi
->bank_size
) {
310 debug("bad: banks = %d, banksize = %d, pages = %d\r\n",
311 mi
->banks
, mi
->bank_size
, mi
->image_pages
);
315 /* Must be either a flat-framebuffer mode, or be an acceptable
317 if (!(mi
->mode_attr
& 0x0080) && !vesacon_paged_mode_ok(mi
)) {
318 debug("bad: invalid paged mode\r\n");
322 /* Must either be a packed-pixel mode or a direct color mode
323 (depending on VESA version ); must be a supported pixel format */
324 pxf
= PXF_NONE
; /* Not usable */
327 (mi
->memory_layout
== 4 ||
328 (mi
->memory_layout
== 6 && mi
->rpos
== 16 && mi
->gpos
== 8 &&
331 else if (mi
->bpp
== 24 &&
332 (mi
->memory_layout
== 4 ||
333 (mi
->memory_layout
== 6 && mi
->rpos
== 16 && mi
->gpos
== 8 &&
336 else if (mi
->bpp
== 16 &&
337 (mi
->memory_layout
== 4 ||
338 (mi
->memory_layout
== 6 && mi
->rpos
== 11 && mi
->gpos
== 5 &&
340 pxf
= PXF_LE_RGB16_565
;
341 else if (mi
->bpp
== 15 &&
342 (mi
->memory_layout
== 4 ||
343 (mi
->memory_layout
== 6 && mi
->rpos
== 10 && mi
->gpos
== 5 &&
345 pxf
= PXF_LE_RGB15_555
;
347 if (pxf
< *bestpxf
) {
348 debug("Best mode so far, pxf = %d\r\n", pxf
);
350 /* Best mode so far... */
355 memcpy(&vesa_info
->mi
, mi
, sizeof *mi
);
359 if (*bestpxf
== PXF_NONE
) {
360 err
= 4; /* No mode found */
367 memset(&rm
, 0, sizeof rm
);
368 /* Now set video mode */
369 rm
.eax
.w
[0] = 0x4F02; /* Set SVGA video mode */
370 if (mi
->mode_attr
& 0x0080)
371 mode
|= 0x4000; /* Request linear framebuffer if supported */
373 __intcall(0x10, &rm
, &rm
);
374 if (rm
.eax
.w
[0] != 0x004F) {
375 err
= 9; /* Failed to set mode */
386 static void set_window_pos(struct win_info
*wi
, size_t win_pos
)
388 static com32sys_t ireg
;
390 wi
->win_pos
= win_pos
;
393 return; /* This should never happen... */
395 memset(&ireg
, 0, sizeof ireg
);
396 ireg
.eax
.w
[0] = 0x4F05;
397 ireg
.ebx
.b
[0] = wi
->win_num
;
398 ireg
.edx
.w
[0] = win_pos
>> wi
->win_gshift
;
400 __intcall(0x10, &ireg
, NULL
);
403 static void bios_vesacon_screencpy(size_t dst
, const uint32_t * src
,
404 size_t bytes
, struct win_info
*wi
)
406 size_t win_pos
, win_off
;
407 size_t win_size
= wi
->win_size
;
408 size_t omask
= win_size
- 1;
409 char *win_base
= wi
->win_base
;
410 const char *s
= (const char *)src
;
414 win_off
= dst
& omask
;
415 win_pos
= dst
& ~omask
;
417 if (__unlikely(win_pos
!= wi
->win_pos
))
418 set_window_pos(wi
, win_pos
);
420 l
= min(bytes
, win_size
- win_off
);
421 memcpy(win_base
+ win_off
, s
, l
);
429 static int bios_font_query(uint8_t **font
)
433 /* Get BIOS 8x16 font */
435 memset(&rm
, 0, sizeof rm
);
437 rm
.eax
.w
[0] = 0x1130; /* Get Font Information */
438 rm
.ebx
.w
[0] = 0x0600; /* Get 8x16 ROM font */
439 __intcall(0x10, &rm
, &rm
);
440 *font
= MK_PTR(rm
.es
, rm
.ebp
.w
[0]);
445 struct vesa_ops bios_vesa_ops
= {
446 .set_mode
= bios_vesacon_set_mode
,
447 .screencpy
= bios_vesacon_screencpy
,
448 .font_query
= bios_font_query
,
451 static uint32_t min_lowmem_heap
= 65536;
452 extern char __lowmem_heap
[];
453 uint8_t KbdFlags
; /* Check for keyboard escapes */
454 __export
uint8_t KbdMap
[256]; /* Keyboard map */
456 __export
uint16_t PXERetry
;
458 static inline void check_escapes(void)
460 com32sys_t ireg
, oreg
;
462 memset(&ireg
, 0, sizeof ireg
);
463 ireg
.eax
.b
[1] = 0x02; /* Check keyboard flags */
464 __intcall(0x16, &ireg
, &oreg
);
466 KbdFlags
= oreg
.eax
.b
[0];
468 /* Ctrl->skip 386 check */
469 if (!(oreg
.eax
.b
[0] & 0x04)) {
471 * Now check that there is sufficient low (DOS) memory
473 * NOTE: Linux doesn't use all of real_mode_seg, but we use
474 * the same segment for COMBOOT images, which can use all 64K.
478 __intcall(0x12, &ireg
, &oreg
);
480 mem
= ((uint32_t)__lowmem_heap
) + min_lowmem_heap
+ 1023;
483 if (oreg
.eax
.w
[0] < mem
) {
486 snprintf(buf
, sizeof(buf
),
487 "It appears your computer has only "
488 "%dK of low (\"DOS\") RAM.\n"
489 "This version of Syslinux needs "
491 "If you get this\nmessage in error, "
492 "hold down the Ctrl key while booting, "
493 "and I\nwill take your word for it.\n",
501 extern uint32_t BIOS_timer_next
;
502 extern uint32_t timer_irq
;
503 static inline void bios_timer_init(void)
506 uint32_t *hook
= (uint32_t *)BIOS_timer_hook
;
509 BIOS_timer_next
= next
;
510 *hook
= (uint32_t)&timer_irq
;
513 extern uint16_t *bios_free_mem
;
521 static int bios_scan_memory(scan_memory_callback_t callback
, void *data
)
523 static com32sys_t ireg
;
525 struct e820_entry
*e820buf
;
526 uint64_t start
, len
, maxlen
;
530 const addr_t bios_data
= 0x510; /* Amount to reserve for BIOS data */
532 /* Use INT 12h to get DOS memory */
533 __intcall(0x12, &__com32_zero_regs
, &oreg
);
534 dosmem
= oreg
.eax
.w
[0] << 10;
535 if (dosmem
< 32 * 1024 || dosmem
> 640 * 1024) {
536 /* INT 12h reports nonsense... now what? */
537 uint16_t ebda_seg
= *(uint16_t *) 0x40e;
538 if (ebda_seg
>= 0x8000 && ebda_seg
< 0xa000)
539 dosmem
= ebda_seg
<< 4;
541 dosmem
= 640 * 1024; /* Hope for the best... */
543 rv
= callback(data
, bios_data
, dosmem
- bios_data
, SMT_FREE
);
547 /* First try INT 15h AX=E820h */
548 e820buf
= lzalloc(sizeof *e820buf
);
552 memset(&ireg
, 0, sizeof ireg
);
554 ireg
.edx
.l
= 0x534d4150;
556 ireg
.ecx
.l
= sizeof(*e820buf
);
557 ireg
.es
= SEG(e820buf
);
558 ireg
.edi
.w
[0] = OFFS(e820buf
);
561 __intcall(0x15, &ireg
, &oreg
);
563 if ((oreg
.eflags
.l
& EFLAGS_CF
) ||
564 (oreg
.eax
.l
!= 0x534d4150) || (oreg
.ecx
.l
< 20))
567 start
= e820buf
->start
;
570 if (start
< 0x100000000ULL
) {
571 /* Don't rely on E820 being valid for low memory. Doing so
572 could mean stuff like overwriting the PXE stack even when
573 using "keeppxe", etc. */
574 if (start
< 0x100000ULL
) {
575 if (len
> 0x100000ULL
- start
)
576 len
-= 0x100000ULL
- start
;
582 maxlen
= 0x100000000ULL
- start
;
587 enum syslinux_memmap_types type
;
589 type
= e820buf
->type
== 1 ? SMT_FREE
: SMT_RESERVED
;
590 rv
= callback(data
, (addr_t
) start
, (addr_t
) len
, type
);
597 ireg
.ebx
.l
= oreg
.ebx
.l
;
598 } while (oreg
.ebx
.l
);
605 /* Next try INT 15h AX=E801h */
606 memset(&ireg
, 0, sizeof ireg
);
607 ireg
.eax
.w
[0] = 0xe801;
608 __intcall(0x15, &ireg
, &oreg
);
610 if (!(oreg
.eflags
.l
& EFLAGS_CF
) && oreg
.ecx
.w
[0]) {
611 rv
= callback(data
, (addr_t
) 1 << 20, oreg
.ecx
.w
[0] << 10, SMT_FREE
);
616 rv
= callback(data
, (addr_t
) 16 << 20,
617 oreg
.edx
.w
[0] << 16, SMT_FREE
);
625 /* Finally try INT 15h AH=88h */
626 memset(&ireg
, 0, sizeof ireg
);
627 ireg
.eax
.w
[0] = 0x8800;
628 __intcall(0x15, &ireg
, &oreg
);
629 if (!(oreg
.eflags
.l
& EFLAGS_CF
) && oreg
.eax
.w
[0]) {
630 rv
= callback(data
, (addr_t
) 1 << 20, oreg
.ecx
.w
[0] << 10, SMT_FREE
);
638 static struct syslinux_memscan bios_memscan
= {
639 .func
= bios_scan_memory
,
646 /* Initialize timer */
649 for (i
= 0; i
< 256; i
++)
652 bios_adjust_screen();
654 /* Init the memory subsystem */
655 bios_free_mem
= (uint16_t *)0x413;
656 syslinux_memscan_add(&bios_memscan
);
659 dprintf("%s%s", syslinux_banner
, copyright_str
);
661 /* CPU-dependent initialization and related checks. */
665 * Scan the DMI tables for interesting information.
670 extern void bios_timer_cleanup(void);
672 extern uint32_t OrigFDCTabPtr
;
674 static void bios_cleanup_hardware(void)
676 /* Restore the original pointer to the floppy descriptor table */
678 *((uint32_t *)(4 * 0x1e)) = OrigFDCTabPtr
;
681 * Linux wants the floppy motor shut off before starting the
682 * kernel, at least bootsect.S seems to imply so. If we don't
683 * load the floppy driver, this is *definitely* so!
685 __intcall(0x13, &zero_regs
, NULL
);
687 call16(bios_timer_cleanup
, &zero_regs
, NULL
);
689 /* If we enabled serial port interrupts, clean them up now */
693 extern void *bios_malloc(size_t, enum heap
, size_t);
694 extern void *bios_realloc(void *, size_t);
695 extern void bios_free(void *);
697 struct mem_ops bios_mem_ops
= {
698 .malloc
= bios_malloc
,
699 .realloc
= bios_realloc
,
703 struct firmware bios_fw
= {
705 .adjust_screen
= bios_adjust_screen
,
706 .cleanup
= bios_cleanup_hardware
,
707 .disk_init
= bios_disk_init
,
708 .o_ops
= &bios_output_ops
,
709 .i_ops
= &bios_input_ops
,
710 .get_serial_console_info
= bios_get_serial_console_info
,
711 .adv_ops
= &bios_adv_ops
,
712 .vesa
= &bios_vesa_ops
,
713 .mem
= &bios_mem_ops
,
716 void syslinux_register_bios(void)