From c9f454d694a938f01f01e1d04bddd9659627cb4c Mon Sep 17 00:00:00 2001 From: tkchia Date: Tue, 20 Sep 2022 20:04:24 +0000 Subject: [PATCH] Bare metal VGA: pass video mode information via `struct mman` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should hopefully help us adapt the VGA console code, to work with video modes other than 80 × 25 × 16 text. --- libc/intrin/mman.greg.c | 6 ++++++ libc/runtime/mman.internal.h | 17 +++++++++++++++++ libc/vga/{vga-init.S => rlinit-vga.S} | 19 ++++++++++++++++++- libc/vga/vga.internal.h | 23 ++++------------------- libc/vga/writev-vga.c | 8 +++++--- 5 files changed, 50 insertions(+), 23 deletions(-) rename libc/vga/{vga-init.S => rlinit-vga.S} (87%) diff --git a/libc/intrin/mman.greg.c b/libc/intrin/mman.greg.c index e85eb9784..ff3d09a73 100644 --- a/libc/intrin/mman.greg.c +++ b/libc/intrin/mman.greg.c @@ -148,6 +148,12 @@ noasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t) { export_offsetof(struct mman, e820); export_offsetof(struct mman, e820_end); export_offsetof(struct mman, bad_idt); + export_offsetof(struct mman, pc_video_type); + export_offsetof(struct mman, pc_video_scan_width); + export_offsetof(struct mman, pc_video_width); + export_offsetof(struct mman, pc_video_height); + export_offsetof(struct mman, pc_video_framebuffer); + export_offsetof(struct mman, pc_video_framebuffer_size); __normalize_e820(mm); __invert_memory(mm, pml4t); } diff --git a/libc/runtime/mman.internal.h b/libc/runtime/mman.internal.h index 5a9e2b642..a5ff1fd22 100644 --- a/libc/runtime/mman.internal.h +++ b/libc/runtime/mman.internal.h @@ -18,8 +18,25 @@ struct mman { unsigned char pc_drive_last_head; /* 0x1d21 */ unsigned char pc_drive; /* 0x1d22 */ char bad_idt[6]; /* 0x1d23 */ + unsigned char pc_video_type; /* 0x1d29 */ + unsigned short pc_video_scan_width; /* 0x1d2a — line width including any + invisible "pixels" */ + unsigned short pc_video_width; /* 0x1d2c — width in chars. (text) + or pixels (graphics) */ + unsigned short pc_video_height; /* 0x1d2e — height in chars. (text) + or pixels (graphics) */ + uint32_t pc_video_framebuffer; /* 0x1d30 */ + uint32_t pc_video_framebuffer_size; /* 0x1d34 */ }; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ + +/* Values for mman::pc_video_type. TODO: implement graphics modes. */ +#define PC_VIDEO_TEXT 0 +#define PC_VIDEO_BGR565 1 +#define PC_VIDEO_BGRX5551 2 +#define PC_VIDEO_BGRX8888 3 +#define PC_VIDEO_RGBX8888 4 + #endif /* COSMOPOLITAN_LIBC_RUNTIME_MMAN_H_ */ diff --git a/libc/vga/vga-init.S b/libc/vga/rlinit-vga.S similarity index 87% rename from libc/vga/vga-init.S rename to libc/vga/rlinit-vga.S index 7e332a5d7..0c24e1de3 100644 --- a/libc/vga/vga-init.S +++ b/libc/vga/rlinit-vga.S @@ -25,6 +25,7 @@ │ OTHER DEALINGS IN THE SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.internal.h" +#include "libc/runtime/mman.internal.h" #include "libc/vga/vga.internal.h" // Code snippet for initializing the VGA video mode for bare metal. @@ -42,6 +43,8 @@ // @see sys_writev_vga (libc/vga/writev-vga.c) .section .sort.text.real.init.2,"ax",@progbits .code16 + call _rlinit_vesafb + jnc 9f mov $0x4f03,%ax # get current video mode via VESA int $0x10 cmp $0x004f,%ax # is VESA a thing here? @@ -58,7 +61,15 @@ mov $0x0500,%ax # just make sure we are on display # page 0 2: int $0x10 # otherwise, change the video mode - mov $0x1003,%ax # enable/disable VGA text blinking + .set mm,0x0500 # note down video mode parameters + movb $PC_VIDEO_TEXT,mm+"struct mman::pc_video_type" + mov $80,%ax + movw %ax,mm+"struct mman::pc_video_scan_width" + movw %ax,mm+"struct mman::pc_video_width" + movw $25,mm+"struct mman::pc_video_height" + movl $0xb8000,mm+"struct mman::pc_video_framebuffer" + movl $8*(80*25*2),mm+"struct mman::pc_video_framebuffer_size" +9: mov $0x1003,%ax # enable/disable VGA text blinking #ifdef VGA_USE_BLINK mov $1,%bx #else @@ -66,6 +77,12 @@ #endif int $0x10 .previous + .real +_rlinit_vesafb_stub: + stc + ret + .alias _rlinit_vesafb_stub,_rlinit_vesafb + .previous .code64 .section .rodata,"a",@progbits vga_console: diff --git a/libc/vga/vga.internal.h b/libc/vga/vga.internal.h index 2d4e06e9f..ca19d1508 100644 --- a/libc/vga/vga.internal.h +++ b/libc/vga/vga.internal.h @@ -2,21 +2,11 @@ #define COSMOPOLITAN_LIBC_VGA_VGA_INTERNAL_H_ /* - * VGA_TTY_HEIGHT, VGA_TTY_WIDTH, VGA_USE_WCS, & VGA_PERSNICKETY_STATUS are - * configuration knobs which can potentially be used to tweak the features - * to be compiled into our VGA teletypewriter support. + * VGA_USE_WCS, VGA_USE_BLINK, & VGA_PERSNICKETY_STATUS are configuration + * knobs which can potentially be used to tweak the features to be compiled + * into our VGA teletypewriter support. */ -/** - * Height of the video screen, in character units. Undefine if the height - * may vary at runtime. - */ -#define VGA_TTY_HEIGHT 25 -/** - * Width of the video screen, in character units. Undefine if the width may - * vary at runtime. - */ -#define VGA_TTY_WIDTH 80 /** * If VGA_USE_WCS is defined, the tty code can maintain an array of the * Unicode characters "underlying" the 8-bit (or 9-bit) characters that are @@ -114,12 +104,7 @@ struct VgaTextCharCell { struct Tty { unsigned short y, x; -#ifndef VGA_TTY_HEIGHT - unsigned short yn; -#endif -#ifndef VGA_TTY_WIDTH - unsigned short xn; -#endif + unsigned short yn, xn; uint32_t u8; uint32_t n8; uint32_t pr; diff --git a/libc/vga/writev-vga.c b/libc/vga/writev-vga.c index d71cd445b..ea9749165 100644 --- a/libc/vga/writev-vga.c +++ b/libc/vga/writev-vga.c @@ -60,7 +60,9 @@ ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) { __attribute__((__constructor__)) static textstartup void _vga_init(void) { if (IsMetal()) { - void * const vid_buf = (void *)(BANE + 0xb8000ull); + struct mman *mm = (struct mman *)(BANE + 0x0500); + unsigned short height = mm->pc_video_height, width = mm->pc_video_width; + void *vid_buf = (void *)(BANE + mm->pc_video_framebuffer); /* * 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 @@ -78,7 +80,7 @@ __attribute__((__constructor__)) static textstartup void _vga_init(void) { * Initialize our tty structure from the current screen contents, * current cursor position, & character height. */ - _StartTty(&_vga_tty, VGA_TTY_HEIGHT, VGA_TTY_WIDTH, pos.row, pos.col, - chr_ht, vid_buf, vga_wcs); + _StartTty(&_vga_tty, height, width, pos.row, pos.col, chr_ht, + vid_buf, vga_wcs); } }