From 7059a7109d3a7647ecafc3f7b178b1dd12ec83d8 Mon Sep 17 00:00:00 2001 From: tkchia Date: Tue, 4 Oct 2022 22:13:42 +0000 Subject: [PATCH] [metal] Read VGA info from BDA before long mode entry, not after MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If using a pre-existing VGA text console, the VGA initialization code now retrieves the cursor position & character height from the BIOS data area while still in real mode — rather than reading from the BIOS data area only after entering long mode. (This should help make the code more correct, if Cosmopolitan were to support UEFI graphics output in the future. If the program were booted via UEFI, then the long mode IsMetal() code would still be activated, but the BIOS data area might not have been initialized in that case.) This change also means that there are now a few more fields in the `struct mman`. --- libc/intrin/mman.greg.c | 2 ++ libc/runtime/mman.internal.h | 6 ++++++ libc/vga/rlinit-vga.S | 8 +++++++- libc/vga/vga-init.c | 22 ++++++++-------------- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/libc/intrin/mman.greg.c b/libc/intrin/mman.greg.c index b8f87c165..2dad09c1f 100644 --- a/libc/intrin/mman.greg.c +++ b/libc/intrin/mman.greg.c @@ -169,6 +169,8 @@ noasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t) { export_offsetof(struct mman, pc_video_height); export_offsetof(struct mman, pc_video_framebuffer); export_offsetof(struct mman, pc_video_framebuffer_size); + export_offsetof(struct mman, pc_video_curs_info); + export_offsetof(struct mman, pc_video_char_height); __normalize_e820(mm); __invert_memory(mm, pml4t); } diff --git a/libc/runtime/mman.internal.h b/libc/runtime/mman.internal.h index 9f96ed695..2488a4ac2 100644 --- a/libc/runtime/mman.internal.h +++ b/libc/runtime/mman.internal.h @@ -29,6 +29,12 @@ struct mman { uint64_t pc_video_framebuffer; /* 0x1d30 — physical address of video frame buffer */ uint64_t pc_video_framebuffer_size; /* 0x1d38 */ + struct { /* 0x1d40 — starting cursor pos. */ + unsigned short y, x; + } pc_video_curs_info; + unsigned short pc_video_char_height; /* 0x1d44 — character height (useful + for setting cursor shape + in text mode) */ }; COSMOPOLITAN_C_END_ diff --git a/libc/vga/rlinit-vga.S b/libc/vga/rlinit-vga.S index ed74f4fe3..6d4962bec 100644 --- a/libc/vga/rlinit-vga.S +++ b/libc/vga/rlinit-vga.S @@ -78,7 +78,13 @@ xor %bx,%bx #endif int $0x10 -9: +9: mov 0x0450,%dx # note down cursor position + movzbw %dh,%ax + mov %ax,mm+"struct mman::pc_video_curs_info" + mov %dl,%al + mov %ax,mm+"struct mman::pc_video_curs_info"+2 + mov 0x0486,%ax # ...& character height + mov %ax,mm+"struct mman::pc_video_char_height" .previous .code64 .section .rodata,"a",@progbits diff --git a/libc/vga/vga-init.c b/libc/vga/vga-init.c index 347c6e826..2434c7a33 100644 --- a/libc/vga/vga-init.c +++ b/libc/vga/vga-init.c @@ -40,21 +40,15 @@ __attribute__((__constructor__)) static textstartup void _vga_init(void) { uint64_t vid_buf_phy = mm->pc_video_framebuffer; void *vid_buf = (void *)(BANE + vid_buf_phy); size_t vid_buf_sz = mm->pc_video_framebuffer_size; - /* - * Get the initial cursor position from the BIOS data area. Also get - * the height (in scan lines) of each character; this is used to set the - * cursor shape. - */ - typedef struct { - unsigned char col, row; - } bios_curs_pos_t; - bios_curs_pos_t pos = *(bios_curs_pos_t *)(BANE + 0x0450ull); - uint8_t chr_ht, chr_ht_hi, chr_wid; + unsigned short starty = mm->pc_video_curs_info.y, + startx = mm->pc_video_curs_info.x; + uint8_t chr_ht, chr_wid; if (vid_type == PC_VIDEO_TEXT) { - chr_ht = *(uint8_t *)(BANE + 0x0485ull), - chr_ht_hi = *(uint8_t *)(BANE + 0x0486ull); - if (chr_ht_hi != 0 || chr_ht > 32 || chr_ht < 2) + unsigned short chr_ht_val = mm->pc_video_char_height; + if (chr_ht_val > 32 || chr_ht_val < 2) chr_ht = VGA_ASSUME_CHAR_HEIGHT_PX; + else + chr_ht = chr_ht_val; } else chr_ht = VGA_ASSUME_CHAR_HEIGHT_PX; chr_wid = VGA_ASSUME_CHAR_WIDTH_PX; @@ -64,7 +58,7 @@ __attribute__((__constructor__)) static textstartup void _vga_init(void) { * Initialize our tty structure from the current screen geometry, * screen contents, cursor position, & character dimensions. */ - _StartTty(&_vga_tty, vid_type, height, width, stride, pos.row, pos.col, + _StartTty(&_vga_tty, vid_type, height, width, stride, starty, startx, chr_ht, chr_wid, vid_buf, false); } }