7 #include <syslinux/memscan.h>
8 #include <syslinux/firmware.h>
10 #include <sys/vesa/vesa.h>
11 #include <sys/vesa/video.h>
12 #include <sys/vesa/debug.h>
15 __export
struct firmware
*firmware
= NULL
;
17 extern struct ansi_ops bios_ansi_ops
;
19 #define BIOS_CURXY ((struct curxy *)0x450) /* Array for each page */
20 #define BIOS_ROWS (*(uint8_t *)0x484) /* Minus one; if zero use 24 (= 25 lines) */
21 #define BIOS_COLS (*(uint16_t *)0x44A)
22 #define BIOS_PAGE (*(uint8_t *)0x462)
24 static void bios_set_mode(uint16_t mode
)
26 syslinux_force_text_mode();
29 static void bios_get_mode(int *cols
, int *rows
)
31 *rows
= BIOS_ROWS
? BIOS_ROWS
+ 1 : 25;
35 static uint16_t cursor_type
; /* Saved cursor pattern */
37 static void bios_get_cursor(uint8_t *x
, uint8_t *y
)
39 com32sys_t ireg
, oreg
;
41 memset(&ireg
, 0, sizeof(ireg
));
44 ireg
.ebx
.b
[1] = BIOS_PAGE
;
45 __intcall(0x10, &ireg
, &oreg
);
46 cursor_type
= oreg
.ecx
.w
[0];
51 static void bios_erase(int x0
, int y0
, int x1
, int y1
, uint8_t attribute
)
53 static com32sys_t ireg
;
55 ireg
.eax
.w
[0] = 0x0600; /* Clear window */
56 ireg
.ebx
.b
[1] = attribute
;
61 __intcall(0x10, &ireg
, NULL
);
64 static void bios_showcursor(const struct term_state
*st
)
66 static com32sys_t ireg
;
67 uint16_t cursor
= st
->cursor
? cursor_type
: 0x2020;
70 ireg
.ecx
.w
[0] = cursor
;
71 __intcall(0x10, &ireg
, NULL
);
74 static void bios_set_cursor(int x
, int y
, bool visible
)
76 const int page
= BIOS_PAGE
;
77 struct curxy xy
= BIOS_CURXY
[page
];
78 static com32sys_t ireg
;
82 if (xy
.x
!= x
|| xy
.y
!= y
) {
87 __intcall(0x10, &ireg
, NULL
);
91 static void bios_write_char(uint8_t ch
, uint8_t attribute
)
93 static com32sys_t ireg
;
97 ireg
.ebx
.b
[1] = BIOS_PAGE
;
98 ireg
.ebx
.b
[0] = attribute
;
100 __intcall(0x10, &ireg
, NULL
);
103 static void bios_scroll_up(uint8_t cols
, uint8_t rows
, uint8_t attribute
)
105 static com32sys_t ireg
;
107 ireg
.eax
.w
[0] = 0x0601;
108 ireg
.ebx
.b
[1] = attribute
;
110 ireg
.edx
.b
[1] = rows
;
111 ireg
.edx
.b
[0] = cols
;
112 __intcall(0x10, &ireg
, NULL
); /* Scroll */
115 static void bios_beep(void)
117 static com32sys_t ireg
;
119 ireg
.eax
.w
[0] = 0x0e07;
120 ireg
.ebx
.b
[1] = BIOS_PAGE
;
121 __intcall(0x10, &ireg
, NULL
);
124 struct output_ops bios_output_ops
= {
126 .write_char
= bios_write_char
,
127 .showcursor
= bios_showcursor
,
128 .set_cursor
= bios_set_cursor
,
129 .scroll_up
= bios_scroll_up
,
131 .get_mode
= bios_get_mode
,
132 .set_mode
= bios_set_mode
,
133 .get_cursor
= bios_get_cursor
,
136 extern char bios_getchar(char *);
137 extern int bios_pollchar(void);
139 struct input_ops bios_input_ops
= {
140 .getchar
= bios_getchar
,
141 .pollchar
= bios_pollchar
,
144 static void bios_get_serial_console_info(uint16_t *iobase
, uint16_t *divisor
,
147 *iobase
= SerialPort
;
148 *divisor
= BaudDivisor
;
150 *flowctl
= FlowOutput
| FlowInput
| (FlowIgnore
<< 4);
153 *flowctl
|= (0x80 << 8);
156 void *__syslinux_adv_ptr
;
157 size_t __syslinux_adv_size
;
159 void bios_adv_init(void)
161 static com32sys_t reg
;
163 reg
.eax
.w
[0] = 0x0025;
164 __intcall(0x22, ®
, ®
);
166 reg
.eax
.w
[0] = 0x001c;
167 __intcall(0x22, ®
, ®
);
168 __syslinux_adv_ptr
= MK_PTR(reg
.es
, reg
.ebx
.w
[0]);
169 __syslinux_adv_size
= reg
.ecx
.w
[0];
172 int bios_adv_write(void)
174 static com32sys_t reg
;
176 reg
.eax
.w
[0] = 0x001d;
177 __intcall(0x22, ®
, ®
);
178 return (reg
.eflags
.l
& EFLAGS_CF
) ? -1 : 0;
181 struct adv_ops bios_adv_ops
= {
182 .init
= bios_adv_init
,
183 .write
= bios_adv_write
,
187 static int __constfunc
is_power_of_2(unsigned int x
)
189 return x
&& !(x
& (x
- 1));
192 static int vesacon_paged_mode_ok(const struct vesa_mode_info
*mi
)
196 if (!is_power_of_2(mi
->win_size
) ||
197 !is_power_of_2(mi
->win_grain
) || mi
->win_grain
> mi
->win_size
)
198 return 0; /* Impossible... */
200 for (i
= 0; i
< 2; i
++) {
201 if ((mi
->win_attr
[i
] & 0x05) == 0x05 && mi
->win_seg
[i
])
202 return 1; /* Usable window */
205 return 0; /* Nope... */
208 static int bios_vesacon_set_mode(struct vesa_info
*vesa_info
, int *px
, int *py
,
209 enum vesa_pixel_format
*bestpxf
)
212 uint16_t mode
, bestmode
, *mode_ptr
;
213 struct vesa_info
*vi
;
214 struct vesa_general_info
*gi
;
215 struct vesa_mode_info
*mi
;
216 enum vesa_pixel_format pxf
;
217 int x
= *px
, y
= *py
;
220 /* Allocate space in the bounce buffer for these structures */
221 vi
= lzalloc(sizeof *vi
);
223 err
= 10; /* Out of memory */
229 memset(&rm
, 0, sizeof rm
);
231 gi
->signature
= VBE2_MAGIC
; /* Get VBE2 extended data */
232 rm
.eax
.w
[0] = 0x4F00; /* Get SVGA general information */
233 rm
.edi
.w
[0] = OFFS(gi
);
235 __intcall(0x10, &rm
, &rm
);
237 if (rm
.eax
.w
[0] != 0x004F) {
238 err
= 1; /* Function call failed */
241 if (gi
->signature
!= VESA_MAGIC
) {
242 err
= 2; /* No magic */
245 if (gi
->version
< 0x0102) {
246 err
= 3; /* VESA 1.2+ required */
250 /* Copy general info */
251 memcpy(&vesa_info
->gi
, gi
, sizeof *gi
);
253 /* Search for the proper mode with a suitable color and memory model... */
255 mode_ptr
= GET_PTR(gi
->video_mode_ptr
);
259 while ((mode
= *mode_ptr
++) != 0xFFFF) {
260 mode
&= 0x1FF; /* The rest are attributes of sorts */
262 debug("Found mode: 0x%04x\r\n", mode
);
264 memset(mi
, 0, sizeof *mi
);
265 rm
.eax
.w
[0] = 0x4F01; /* Get SVGA mode information */
267 rm
.edi
.w
[0] = OFFS(mi
);
269 __intcall(0x10, &rm
, &rm
);
271 /* Must be a supported mode */
272 if (rm
.eax
.w
[0] != 0x004f)
276 ("mode_attr 0x%04x, h_res = %4d, v_res = %4d, bpp = %2d, layout = %d (%d,%d,%d)\r\n",
277 mi
->mode_attr
, mi
->h_res
, mi
->v_res
, mi
->bpp
, mi
->memory_layout
,
278 mi
->rpos
, mi
->gpos
, mi
->bpos
);
280 /* Must be an LFB color graphics mode supported by the hardware.
285 1 - mode information available (mandatory in VBE 1.2+)
286 0 - mode supported by hardware
288 if ((mi
->mode_attr
& 0x001b) != 0x001b)
291 /* Must be the chosen size */
292 if (mi
->h_res
!= x
|| mi
->v_res
!= y
)
295 /* We don't support multibank (interlaced memory) modes */
297 * Note: The Bochs VESA BIOS (vbe.c 1.58 2006/08/19) violates the
298 * specification which states that banks == 1 for unbanked modes;
299 * fortunately it does report bank_size == 0 for those.
301 if (mi
->banks
> 1 && mi
->bank_size
) {
302 debug("bad: banks = %d, banksize = %d, pages = %d\r\n",
303 mi
->banks
, mi
->bank_size
, mi
->image_pages
);
307 /* Must be either a flat-framebuffer mode, or be an acceptable
309 if (!(mi
->mode_attr
& 0x0080) && !vesacon_paged_mode_ok(mi
)) {
310 debug("bad: invalid paged mode\r\n");
314 /* Must either be a packed-pixel mode or a direct color mode
315 (depending on VESA version ); must be a supported pixel format */
316 pxf
= PXF_NONE
; /* Not usable */
319 (mi
->memory_layout
== 4 ||
320 (mi
->memory_layout
== 6 && mi
->rpos
== 16 && mi
->gpos
== 8 &&
323 else if (mi
->bpp
== 24 &&
324 (mi
->memory_layout
== 4 ||
325 (mi
->memory_layout
== 6 && mi
->rpos
== 16 && mi
->gpos
== 8 &&
328 else if (mi
->bpp
== 16 &&
329 (mi
->memory_layout
== 4 ||
330 (mi
->memory_layout
== 6 && mi
->rpos
== 11 && mi
->gpos
== 5 &&
332 pxf
= PXF_LE_RGB16_565
;
333 else if (mi
->bpp
== 15 &&
334 (mi
->memory_layout
== 4 ||
335 (mi
->memory_layout
== 6 && mi
->rpos
== 10 && mi
->gpos
== 5 &&
337 pxf
= PXF_LE_RGB15_555
;
339 if (pxf
< *bestpxf
) {
340 debug("Best mode so far, pxf = %d\r\n", pxf
);
342 /* Best mode so far... */
347 memcpy(&vesa_info
->mi
, mi
, sizeof *mi
);
351 if (*bestpxf
== PXF_NONE
) {
352 err
= 4; /* No mode found */
359 /* Now set video mode */
360 rm
.eax
.w
[0] = 0x4F02; /* Set SVGA video mode */
361 if (mi
->mode_attr
& 0x0080)
362 mode
|= 0x4000; /* Request linear framebuffer if supported */
364 __intcall(0x10, &rm
, &rm
);
365 if (rm
.eax
.w
[0] != 0x004F) {
366 err
= 9; /* Failed to set mode */
377 static void set_window_pos(struct win_info
*wi
, size_t win_pos
)
379 static com32sys_t ireg
;
381 wi
->win_pos
= win_pos
;
384 return; /* This should never happen... */
386 ireg
.eax
.w
[0] = 0x4F05;
387 ireg
.ebx
.b
[0] = wi
->win_num
;
388 ireg
.edx
.w
[0] = win_pos
>> wi
->win_gshift
;
390 __intcall(0x10, &ireg
, NULL
);
393 static void bios_vesacon_screencpy(size_t dst
, const uint32_t * src
,
394 size_t bytes
, struct win_info
*wi
)
396 size_t win_pos
, win_off
;
397 size_t win_size
= wi
->win_size
;
398 size_t omask
= win_size
- 1;
399 char *win_base
= wi
->win_base
;
400 const char *s
= (const char *)src
;
404 win_off
= dst
& omask
;
405 win_pos
= dst
& ~omask
;
407 if (__unlikely(win_pos
!= wi
->win_pos
))
408 set_window_pos(wi
, win_pos
);
410 l
= min(bytes
, win_size
- win_off
);
411 memcpy(win_base
+ win_off
, s
, l
);
419 static int bios_font_query(uint8_t **font
)
423 /* Get BIOS 8x16 font */
425 memset(&rm
, 0, sizeof rm
);
427 rm
.eax
.w
[0] = 0x1130; /* Get Font Information */
428 rm
.ebx
.w
[0] = 0x0600; /* Get 8x16 ROM font */
429 __intcall(0x10, &rm
, &rm
);
430 *font
= MK_PTR(rm
.es
, rm
.ebp
.w
[0]);
435 struct vesa_ops bios_vesa_ops
= {
436 .set_mode
= bios_vesacon_set_mode
,
437 .screencpy
= bios_vesacon_screencpy
,
438 .font_query
= bios_font_query
,
441 static uint32_t min_lowmem_heap
= 65536;
442 extern char __lowmem_heap
[];
443 uint8_t KbdFlags
; /* Check for keyboard escapes */
444 __export
uint8_t KbdMap
[256]; /* Keyboard map */
446 __export
uint16_t PXERetry
;
448 static inline void check_escapes(void)
450 com32sys_t ireg
, oreg
;
452 ireg
.eax
.b
[1] = 0x02; /* Check keyboard flags */
453 __intcall(0x16, &ireg
, &oreg
);
455 KbdFlags
= oreg
.eax
.b
[0];
457 /* Ctrl->skip 386 check */
458 if (oreg
.eax
.b
[0] & 0x04) {
460 * Now check that there is sufficient low (DOS) memory
462 * NOTE: Linux doesn't use all of real_mode_seg, but we use
463 * the same segment for COMBOOT images, which can use all 64K.
467 __intcall(0x12, &ireg
, &oreg
);
469 mem
= ((uint32_t)__lowmem_heap
) + min_lowmem_heap
+ 1023;
472 if (mem
< oreg
.eax
.w
[0]) {
475 snprintf(buf
, sizeof(buf
),
476 "It appears your computer has only "
477 "%dK of low (\"DOS\") RAM.\n"
478 "This version of Syslinux needs "
480 "If you get this\nmessage in error, "
481 "hold down the Ctrl key while booting, "
482 "and I\nwill take your word for it.\n",
490 extern uint32_t BIOS_timer_next
;
491 extern uint32_t timer_irq
;
492 static inline void bios_timer_init(void)
495 uint32_t *hook
= (uint32_t *)BIOS_timer_hook
;
498 BIOS_timer_next
= next
;
499 *hook
= (uint32_t)&timer_irq
;
502 extern uint16_t *bios_free_mem
;
508 /* Initialize timer */
511 for (i
= 0; i
< 256; i
++)
514 bios_adjust_screen();
516 /* Init the memory subsystem */
517 bios_free_mem
= (uint16_t *)0x413;
520 /* CPU-dependent initialization and related checks. */
524 * Scan the DMI tables for interesting information.
529 extern void *bios_malloc(size_t, enum heap
, size_t);
530 extern void *bios_realloc(void *, size_t);
531 extern void bios_free(void *);
533 struct mem_ops bios_mem_ops
= {
534 .malloc
= bios_malloc
,
535 .realloc
= bios_realloc
,
537 .scan_memory
= bios_scan_memory
,
540 struct firmware bios_fw
= {
542 .adjust_screen
= bios_adjust_screen
,
543 .cleanup
= bios_cleanup_hardware
,
544 .disk_init
= bios_disk_init
,
545 .o_ops
= &bios_output_ops
,
546 .i_ops
= &bios_input_ops
,
547 .get_serial_console_info
= bios_get_serial_console_info
,
548 .adv_ops
= &bios_adv_ops
,
549 .vesa
= &bios_vesa_ops
,
550 .mem
= &bios_mem_ops
,
553 void syslinux_register_bios(void)