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>
16 __export
struct firmware
*firmware
= NULL
;
18 extern struct ansi_ops bios_ansi_ops
;
20 #define BIOS_CURXY ((struct curxy *)0x450) /* Array for each page */
21 #define BIOS_ROWS (*(uint8_t *)0x484) /* Minus one; if zero use 24 (= 25 lines) */
22 #define BIOS_COLS (*(uint16_t *)0x44A)
23 #define BIOS_PAGE (*(uint8_t *)0x462)
25 static void bios_text_mode(void)
27 syslinux_force_text_mode();
30 static void bios_get_mode(int *cols
, int *rows
)
32 *rows
= BIOS_ROWS
? BIOS_ROWS
+ 1 : 25;
36 static uint16_t cursor_type
; /* Saved cursor pattern */
38 static void bios_get_cursor(uint8_t *x
, uint8_t *y
)
40 com32sys_t ireg
, oreg
;
42 memset(&ireg
, 0, sizeof(ireg
));
45 ireg
.ebx
.b
[1] = BIOS_PAGE
;
46 __intcall(0x10, &ireg
, &oreg
);
47 cursor_type
= oreg
.ecx
.w
[0];
52 static void bios_erase(int x0
, int y0
, int x1
, int y1
, uint8_t attribute
)
54 static com32sys_t ireg
;
56 ireg
.eax
.w
[0] = 0x0600; /* Clear window */
57 ireg
.ebx
.b
[1] = attribute
;
62 __intcall(0x10, &ireg
, NULL
);
65 static void bios_showcursor(const struct term_state
*st
)
67 static com32sys_t ireg
;
68 uint16_t cursor
= st
->cursor
? cursor_type
: 0x2020;
71 ireg
.ecx
.w
[0] = cursor
;
72 __intcall(0x10, &ireg
, NULL
);
75 static void bios_set_cursor(int x
, int y
, bool visible
)
77 const int page
= BIOS_PAGE
;
78 struct curxy xy
= BIOS_CURXY
[page
];
79 static com32sys_t ireg
;
83 if (xy
.x
!= x
|| xy
.y
!= y
) {
88 __intcall(0x10, &ireg
, NULL
);
92 static void bios_write_char(uint8_t ch
, uint8_t attribute
)
94 static com32sys_t ireg
;
98 ireg
.ebx
.b
[1] = BIOS_PAGE
;
99 ireg
.ebx
.b
[0] = attribute
;
101 __intcall(0x10, &ireg
, NULL
);
104 static void bios_scroll_up(uint8_t cols
, uint8_t rows
, uint8_t attribute
)
106 static com32sys_t ireg
;
108 ireg
.eax
.w
[0] = 0x0601;
109 ireg
.ebx
.b
[1] = attribute
;
111 ireg
.edx
.b
[1] = rows
;
112 ireg
.edx
.b
[0] = cols
;
113 __intcall(0x10, &ireg
, NULL
); /* Scroll */
116 static void bios_beep(void)
118 static com32sys_t ireg
;
120 ireg
.eax
.w
[0] = 0x0e07;
121 ireg
.ebx
.b
[1] = BIOS_PAGE
;
122 __intcall(0x10, &ireg
, NULL
);
125 struct output_ops bios_output_ops
= {
127 .write_char
= bios_write_char
,
128 .showcursor
= bios_showcursor
,
129 .set_cursor
= bios_set_cursor
,
130 .scroll_up
= bios_scroll_up
,
132 .get_mode
= bios_get_mode
,
133 .text_mode
= bios_text_mode
,
134 .get_cursor
= bios_get_cursor
,
137 extern char bios_getchar(char *);
138 extern int bios_pollchar(void);
140 struct input_ops bios_input_ops
= {
141 .getchar
= bios_getchar
,
142 .pollchar
= bios_pollchar
,
145 static void bios_get_serial_console_info(uint16_t *iobase
, uint16_t *divisor
,
148 *iobase
= SerialPort
;
149 *divisor
= BaudDivisor
;
151 *flowctl
= FlowOutput
| FlowInput
| (FlowIgnore
<< 4);
154 *flowctl
|= (0x80 << 8);
157 void *__syslinux_adv_ptr
;
158 size_t __syslinux_adv_size
;
160 void bios_adv_init(void)
162 static com32sys_t reg
;
164 reg
.eax
.w
[0] = 0x0025;
165 __intcall(0x22, ®
, ®
);
167 reg
.eax
.w
[0] = 0x001c;
168 __intcall(0x22, ®
, ®
);
169 __syslinux_adv_ptr
= MK_PTR(reg
.es
, reg
.ebx
.w
[0]);
170 __syslinux_adv_size
= reg
.ecx
.w
[0];
173 int bios_adv_write(void)
175 static com32sys_t reg
;
177 reg
.eax
.w
[0] = 0x001d;
178 __intcall(0x22, ®
, ®
);
179 return (reg
.eflags
.l
& EFLAGS_CF
) ? -1 : 0;
182 struct adv_ops bios_adv_ops
= {
183 .init
= bios_adv_init
,
184 .write
= bios_adv_write
,
188 static int __constfunc
is_power_of_2(unsigned int x
)
190 return x
&& !(x
& (x
- 1));
193 static int vesacon_paged_mode_ok(const struct vesa_mode_info
*mi
)
197 if (!is_power_of_2(mi
->win_size
) ||
198 !is_power_of_2(mi
->win_grain
) || mi
->win_grain
> mi
->win_size
)
199 return 0; /* Impossible... */
201 for (i
= 0; i
< 2; i
++) {
202 if ((mi
->win_attr
[i
] & 0x05) == 0x05 && mi
->win_seg
[i
])
203 return 1; /* Usable window */
206 return 0; /* Nope... */
209 static int bios_vesacon_set_mode(struct vesa_info
*vesa_info
, int *px
, int *py
,
210 enum vesa_pixel_format
*bestpxf
)
213 uint16_t mode
, bestmode
, *mode_ptr
;
214 struct vesa_info
*vi
;
215 struct vesa_general_info
*gi
;
216 struct vesa_mode_info
*mi
;
217 enum vesa_pixel_format pxf
;
218 int x
= *px
, y
= *py
;
221 /* Allocate space in the bounce buffer for these structures */
222 vi
= lzalloc(sizeof *vi
);
224 err
= 10; /* Out of memory */
230 memset(&rm
, 0, sizeof rm
);
232 gi
->signature
= VBE2_MAGIC
; /* Get VBE2 extended data */
233 rm
.eax
.w
[0] = 0x4F00; /* Get SVGA general information */
234 rm
.edi
.w
[0] = OFFS(gi
);
236 __intcall(0x10, &rm
, &rm
);
238 if (rm
.eax
.w
[0] != 0x004F) {
239 err
= 1; /* Function call failed */
242 if (gi
->signature
!= VESA_MAGIC
) {
243 err
= 2; /* No magic */
246 if (gi
->version
< 0x0102) {
247 err
= 3; /* VESA 1.2+ required */
251 /* Copy general info */
252 memcpy(&vesa_info
->gi
, gi
, sizeof *gi
);
254 /* Search for the proper mode with a suitable color and memory model... */
256 mode_ptr
= GET_PTR(gi
->video_mode_ptr
);
260 while ((mode
= *mode_ptr
++) != 0xFFFF) {
261 mode
&= 0x1FF; /* The rest are attributes of sorts */
263 debug("Found mode: 0x%04x\r\n", mode
);
265 memset(mi
, 0, sizeof *mi
);
266 rm
.eax
.w
[0] = 0x4F01; /* Get SVGA mode information */
268 rm
.edi
.w
[0] = OFFS(mi
);
270 __intcall(0x10, &rm
, &rm
);
272 /* Must be a supported mode */
273 if (rm
.eax
.w
[0] != 0x004f)
277 ("mode_attr 0x%04x, h_res = %4d, v_res = %4d, bpp = %2d, layout = %d (%d,%d,%d)\r\n",
278 mi
->mode_attr
, mi
->h_res
, mi
->v_res
, mi
->bpp
, mi
->memory_layout
,
279 mi
->rpos
, mi
->gpos
, mi
->bpos
);
281 /* Must be an LFB color graphics mode supported by the hardware.
286 1 - mode information available (mandatory in VBE 1.2+)
287 0 - mode supported by hardware
289 if ((mi
->mode_attr
& 0x001b) != 0x001b)
292 /* Must be the chosen size */
293 if (mi
->h_res
!= x
|| mi
->v_res
!= y
)
296 /* We don't support multibank (interlaced memory) modes */
298 * Note: The Bochs VESA BIOS (vbe.c 1.58 2006/08/19) violates the
299 * specification which states that banks == 1 for unbanked modes;
300 * fortunately it does report bank_size == 0 for those.
302 if (mi
->banks
> 1 && mi
->bank_size
) {
303 debug("bad: banks = %d, banksize = %d, pages = %d\r\n",
304 mi
->banks
, mi
->bank_size
, mi
->image_pages
);
308 /* Must be either a flat-framebuffer mode, or be an acceptable
310 if (!(mi
->mode_attr
& 0x0080) && !vesacon_paged_mode_ok(mi
)) {
311 debug("bad: invalid paged mode\r\n");
315 /* Must either be a packed-pixel mode or a direct color mode
316 (depending on VESA version ); must be a supported pixel format */
317 pxf
= PXF_NONE
; /* Not usable */
320 (mi
->memory_layout
== 4 ||
321 (mi
->memory_layout
== 6 && mi
->rpos
== 16 && mi
->gpos
== 8 &&
324 else if (mi
->bpp
== 24 &&
325 (mi
->memory_layout
== 4 ||
326 (mi
->memory_layout
== 6 && mi
->rpos
== 16 && mi
->gpos
== 8 &&
329 else if (mi
->bpp
== 16 &&
330 (mi
->memory_layout
== 4 ||
331 (mi
->memory_layout
== 6 && mi
->rpos
== 11 && mi
->gpos
== 5 &&
333 pxf
= PXF_LE_RGB16_565
;
334 else if (mi
->bpp
== 15 &&
335 (mi
->memory_layout
== 4 ||
336 (mi
->memory_layout
== 6 && mi
->rpos
== 10 && mi
->gpos
== 5 &&
338 pxf
= PXF_LE_RGB15_555
;
340 if (pxf
< *bestpxf
) {
341 debug("Best mode so far, pxf = %d\r\n", pxf
);
343 /* Best mode so far... */
348 memcpy(&vesa_info
->mi
, mi
, sizeof *mi
);
352 if (*bestpxf
== PXF_NONE
) {
353 err
= 4; /* No mode found */
360 /* Now set video mode */
361 rm
.eax
.w
[0] = 0x4F02; /* Set SVGA video mode */
362 if (mi
->mode_attr
& 0x0080)
363 mode
|= 0x4000; /* Request linear framebuffer if supported */
365 __intcall(0x10, &rm
, &rm
);
366 if (rm
.eax
.w
[0] != 0x004F) {
367 err
= 9; /* Failed to set mode */
378 static void set_window_pos(struct win_info
*wi
, size_t win_pos
)
380 static com32sys_t ireg
;
382 wi
->win_pos
= win_pos
;
385 return; /* This should never happen... */
387 ireg
.eax
.w
[0] = 0x4F05;
388 ireg
.ebx
.b
[0] = wi
->win_num
;
389 ireg
.edx
.w
[0] = win_pos
>> wi
->win_gshift
;
391 __intcall(0x10, &ireg
, NULL
);
394 static void bios_vesacon_screencpy(size_t dst
, const uint32_t * src
,
395 size_t bytes
, struct win_info
*wi
)
397 size_t win_pos
, win_off
;
398 size_t win_size
= wi
->win_size
;
399 size_t omask
= win_size
- 1;
400 char *win_base
= wi
->win_base
;
401 const char *s
= (const char *)src
;
405 win_off
= dst
& omask
;
406 win_pos
= dst
& ~omask
;
408 if (__unlikely(win_pos
!= wi
->win_pos
))
409 set_window_pos(wi
, win_pos
);
411 l
= min(bytes
, win_size
- win_off
);
412 memcpy(win_base
+ win_off
, s
, l
);
420 static int bios_font_query(uint8_t **font
)
424 /* Get BIOS 8x16 font */
426 memset(&rm
, 0, sizeof rm
);
428 rm
.eax
.w
[0] = 0x1130; /* Get Font Information */
429 rm
.ebx
.w
[0] = 0x0600; /* Get 8x16 ROM font */
430 __intcall(0x10, &rm
, &rm
);
431 *font
= MK_PTR(rm
.es
, rm
.ebp
.w
[0]);
436 struct vesa_ops bios_vesa_ops
= {
437 .set_mode
= bios_vesacon_set_mode
,
438 .screencpy
= bios_vesacon_screencpy
,
439 .font_query
= bios_font_query
,
442 static uint32_t min_lowmem_heap
= 65536;
443 extern char __lowmem_heap
[];
444 uint8_t KbdFlags
; /* Check for keyboard escapes */
445 __export
uint8_t KbdMap
[256]; /* Keyboard map */
447 __export
uint16_t PXERetry
;
449 static inline void check_escapes(void)
451 com32sys_t ireg
, oreg
;
453 ireg
.eax
.b
[1] = 0x02; /* Check keyboard flags */
454 __intcall(0x16, &ireg
, &oreg
);
456 KbdFlags
= oreg
.eax
.b
[0];
458 /* Ctrl->skip 386 check */
459 if (oreg
.eax
.b
[0] & 0x04) {
461 * Now check that there is sufficient low (DOS) memory
463 * NOTE: Linux doesn't use all of real_mode_seg, but we use
464 * the same segment for COMBOOT images, which can use all 64K.
468 __intcall(0x12, &ireg
, &oreg
);
470 mem
= ((uint32_t)__lowmem_heap
) + min_lowmem_heap
+ 1023;
473 if (mem
< oreg
.eax
.w
[0]) {
476 snprintf(buf
, sizeof(buf
),
477 "It appears your computer has only "
478 "%dK of low (\"DOS\") RAM.\n"
479 "This version of Syslinux needs "
481 "If you get this\nmessage in error, "
482 "hold down the Ctrl key while booting, "
483 "and I\nwill take your word for it.\n",
491 extern uint32_t BIOS_timer_next
;
492 extern uint32_t timer_irq
;
493 static inline void bios_timer_init(void)
496 uint32_t *hook
= (uint32_t *)BIOS_timer_hook
;
499 BIOS_timer_next
= next
;
500 *hook
= (uint32_t)&timer_irq
;
503 extern uint16_t *bios_free_mem
;
511 static int bios_scan_memory(scan_memory_callback_t callback
, void *data
)
513 static com32sys_t ireg
;
515 struct e820_entry
*e820buf
;
516 uint64_t start
, len
, maxlen
;
520 const addr_t bios_data
= 0x510; /* Amount to reserve for BIOS data */
522 /* Use INT 12h to get DOS memory */
523 __intcall(0x12, &__com32_zero_regs
, &oreg
);
524 dosmem
= oreg
.eax
.w
[0] << 10;
525 if (dosmem
< 32 * 1024 || dosmem
> 640 * 1024) {
526 /* INT 12h reports nonsense... now what? */
527 uint16_t ebda_seg
= *(uint16_t *) 0x40e;
528 if (ebda_seg
>= 0x8000 && ebda_seg
< 0xa000)
529 dosmem
= ebda_seg
<< 4;
531 dosmem
= 640 * 1024; /* Hope for the best... */
533 rv
= callback(data
, bios_data
, dosmem
- bios_data
, SMT_FREE
);
537 /* First try INT 15h AX=E820h */
538 e820buf
= lzalloc(sizeof *e820buf
);
543 ireg
.edx
.l
= 0x534d4150;
545 ireg
.ecx
.l
= sizeof(*e820buf
);
546 ireg
.es
= SEG(e820buf
);
547 ireg
.edi
.w
[0] = OFFS(e820buf
);
550 __intcall(0x15, &ireg
, &oreg
);
552 if ((oreg
.eflags
.l
& EFLAGS_CF
) ||
553 (oreg
.eax
.l
!= 0x534d4150) || (oreg
.ecx
.l
< 20))
556 start
= e820buf
->start
;
559 if (start
< 0x100000000ULL
) {
560 /* Don't rely on E820 being valid for low memory. Doing so
561 could mean stuff like overwriting the PXE stack even when
562 using "keeppxe", etc. */
563 if (start
< 0x100000ULL
) {
564 if (len
> 0x100000ULL
- start
)
565 len
-= 0x100000ULL
- start
;
571 maxlen
= 0x100000000ULL
- start
;
576 enum syslinux_memmap_types type
;
578 type
= e820buf
->type
== 1 ? SMT_FREE
: SMT_RESERVED
;
579 rv
= callback(data
, (addr_t
) start
, (addr_t
) len
, type
);
586 ireg
.ebx
.l
= oreg
.ebx
.l
;
587 } while (oreg
.ebx
.l
);
594 /* Next try INT 15h AX=E801h */
595 ireg
.eax
.w
[0] = 0xe801;
596 __intcall(0x15, &ireg
, &oreg
);
598 if (!(oreg
.eflags
.l
& EFLAGS_CF
) && oreg
.ecx
.w
[0]) {
599 rv
= callback(data
, (addr_t
) 1 << 20, oreg
.ecx
.w
[0] << 10, SMT_FREE
);
604 rv
= callback(data
, (addr_t
) 16 << 20,
605 oreg
.edx
.w
[0] << 16, SMT_FREE
);
613 /* Finally try INT 15h AH=88h */
614 ireg
.eax
.w
[0] = 0x8800;
615 if (!(oreg
.eflags
.l
& EFLAGS_CF
) && oreg
.eax
.w
[0]) {
616 rv
= callback(data
, (addr_t
) 1 << 20, oreg
.ecx
.w
[0] << 10, SMT_FREE
);
624 static struct syslinux_memscan bios_memscan
= {
625 .func
= bios_scan_memory
,
632 /* Initialize timer */
635 for (i
= 0; i
< 256; i
++)
638 bios_adjust_screen();
640 /* Init the memory subsystem */
641 bios_free_mem
= (uint16_t *)0x413;
642 syslinux_memscan_add(&bios_memscan
);
645 dprintf("%s%s", syslinux_banner
, copyright_str
);
647 /* CPU-dependent initialization and related checks. */
651 * Scan the DMI tables for interesting information.
656 extern void *bios_malloc(size_t, enum heap
, size_t);
657 extern void *bios_realloc(void *, size_t);
658 extern void bios_free(void *);
660 struct mem_ops bios_mem_ops
= {
661 .malloc
= bios_malloc
,
662 .realloc
= bios_realloc
,
666 struct firmware bios_fw
= {
668 .adjust_screen
= bios_adjust_screen
,
669 .cleanup
= bios_cleanup_hardware
,
670 .disk_init
= bios_disk_init
,
671 .o_ops
= &bios_output_ops
,
672 .i_ops
= &bios_input_ops
,
673 .get_serial_console_info
= bios_get_serial_console_info
,
674 .adv_ops
= &bios_adv_ops
,
675 .vesa
= &bios_vesa_ops
,
676 .mem
= &bios_mem_ops
,
679 void syslinux_register_bios(void)