[metal] Read VGA info from BDA before long mode entry, not after

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`.
This commit is contained in:
tkchia 2022-10-04 22:13:42 +00:00
parent 9926ed74f1
commit 7059a7109d
4 changed files with 23 additions and 15 deletions

View file

@ -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_height);
export_offsetof(struct mman, pc_video_framebuffer); export_offsetof(struct mman, pc_video_framebuffer);
export_offsetof(struct mman, pc_video_framebuffer_size); 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); __normalize_e820(mm);
__invert_memory(mm, pml4t); __invert_memory(mm, pml4t);
} }

View file

@ -29,6 +29,12 @@ struct mman {
uint64_t pc_video_framebuffer; /* 0x1d30 — physical address of uint64_t pc_video_framebuffer; /* 0x1d30 — physical address of
video frame buffer */ video frame buffer */
uint64_t pc_video_framebuffer_size; /* 0x1d38 */ 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_ COSMOPOLITAN_C_END_

View file

@ -78,7 +78,13 @@
xor %bx,%bx xor %bx,%bx
#endif #endif
int $0x10 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 .previous
.code64 .code64
.section .rodata,"a",@progbits .section .rodata,"a",@progbits

View file

@ -40,21 +40,15 @@ __attribute__((__constructor__)) static textstartup void _vga_init(void) {
uint64_t vid_buf_phy = mm->pc_video_framebuffer; uint64_t vid_buf_phy = mm->pc_video_framebuffer;
void *vid_buf = (void *)(BANE + vid_buf_phy); void *vid_buf = (void *)(BANE + vid_buf_phy);
size_t vid_buf_sz = mm->pc_video_framebuffer_size; size_t vid_buf_sz = mm->pc_video_framebuffer_size;
/* unsigned short starty = mm->pc_video_curs_info.y,
* Get the initial cursor position from the BIOS data area. Also get startx = mm->pc_video_curs_info.x;
* the height (in scan lines) of each character; this is used to set the uint8_t chr_ht, chr_wid;
* 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;
if (vid_type == PC_VIDEO_TEXT) { if (vid_type == PC_VIDEO_TEXT) {
chr_ht = *(uint8_t *)(BANE + 0x0485ull), unsigned short chr_ht_val = mm->pc_video_char_height;
chr_ht_hi = *(uint8_t *)(BANE + 0x0486ull); if (chr_ht_val > 32 || chr_ht_val < 2)
if (chr_ht_hi != 0 || chr_ht > 32 || chr_ht < 2)
chr_ht = VGA_ASSUME_CHAR_HEIGHT_PX; chr_ht = VGA_ASSUME_CHAR_HEIGHT_PX;
else
chr_ht = chr_ht_val;
} else } else
chr_ht = VGA_ASSUME_CHAR_HEIGHT_PX; chr_ht = VGA_ASSUME_CHAR_HEIGHT_PX;
chr_wid = VGA_ASSUME_CHAR_WIDTH_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, * Initialize our tty structure from the current screen geometry,
* screen contents, cursor position, & character dimensions. * 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); chr_ht, chr_wid, vid_buf, false);
} }
} }