From d39baeaa80ddcaebaaa755e8a62025ad03a09812 Mon Sep 17 00:00:00 2001 From: mintsuki Date: Fri, 18 Nov 2022 23:59:31 +0100 Subject: [PATCH] video: Initial support for multiple framebuffers --- common/drivers/edid.c | 6 +- common/drivers/edid.h | 8 + common/drivers/gop.c | 225 ++++++++++++++-------------- common/drivers/gop.h | 9 +- common/drivers/vbe.c | 6 - common/drivers/vga_textmode.c | 12 +- common/entry.s3.c | 4 +- common/lib/fb.c | 27 ++-- common/lib/fb.h | 25 ++-- common/lib/gterm.c | 268 +++++++++++++++++++--------------- common/lib/gterm.h | 5 +- common/lib/print.s2.c | 4 +- common/lib/readline.c | 32 ++-- common/lib/term.c | 149 ++++++++----------- common/lib/term.h | 32 +++- common/linker_bios.ld.in | 3 +- common/menu.c | 126 ++++++++-------- common/protos/chainload.c | 11 +- common/protos/limine.c | 109 +++++++------- common/protos/linux.c | 51 +++---- common/protos/multiboot1.c | 79 ++++------ common/protos/multiboot2.c | 85 ++++------- 22 files changed, 619 insertions(+), 657 deletions(-) diff --git a/common/drivers/edid.c b/common/drivers/edid.c index 3ee60ea7..25cd9f0b 100644 --- a/common/drivers/edid.c +++ b/common/drivers/edid.c @@ -50,11 +50,7 @@ success: #include -struct edid_info_struct *get_edid_info(void) { - if (!gop_ready) { - goto fail; - } - +struct edid_info_struct *get_edid_info(EFI_HANDLE gop_handle) { struct edid_info_struct *buf = ext_mem_alloc(sizeof(struct edid_info_struct)); EFI_STATUS status; diff --git a/common/drivers/edid.h b/common/drivers/edid.h index 1b89a6d1..ad19ebac 100644 --- a/common/drivers/edid.h +++ b/common/drivers/edid.h @@ -30,6 +30,14 @@ struct edid_info_struct { uint8_t checksum; } __attribute__((packed)); +#if defined (UEFI) +#include + +struct edid_info_struct *get_edid_info(EFI_HANDLE gop_handle); +#endif + +#if defined (BIOS) struct edid_info_struct *get_edid_info(void); +#endif #endif diff --git a/common/drivers/gop.c b/common/drivers/gop.c index 5bf871a9..1ea9deb4 100644 --- a/common/drivers/gop.c +++ b/common/drivers/gop.c @@ -37,7 +37,7 @@ static void linear_mask_to_mask_shift( // Most of this code taken from https://wiki.osdev.org/GOP -static bool mode_to_fb_info(struct fb_info *ret, size_t mode) { +static bool mode_to_fb_info(struct fb_info *ret, EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, size_t mode) { EFI_STATUS status; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info; @@ -98,10 +98,12 @@ static bool mode_to_fb_info(struct fb_info *ret, size_t mode) { bool gop_force_16 = false; -static bool try_mode(struct fb_info *ret, size_t mode, uint64_t width, uint64_t height, int bpp) { +static bool try_mode(struct fb_info *ret, EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, + size_t mode, uint64_t width, uint64_t height, int bpp, + struct fb_info *fbs, size_t fbs_count) { EFI_STATUS status; - if (!mode_to_fb_info(ret, mode)) { + if (!mode_to_fb_info(ret, gop, mode)) { return false; } @@ -121,22 +123,25 @@ static bool try_mode(struct fb_info *ret, size_t mode, uint64_t width, uint64_t } } + for (size_t i = 0; i < fbs_count; i++) { + if (gop->Mode->FrameBufferBase == fbs[i].framebuffer_addr) { + return false; + } + } + printv("gop: Found matching mode %x, attempting to set...\n", mode); - if ((int)mode == current_video_mode) { + if (mode == gop->Mode->Mode) { printv("gop: Mode was already set, perfect!\n"); } else { status = gop->SetMode(gop, mode); if (status) { - current_video_mode = -1; printv("gop: Failed to set video mode %x, moving on...\n", mode); return false; } } - current_video_mode = mode; - ret->framebuffer_addr = gop->Mode->FrameBufferBase; fb_clear(ret); @@ -144,18 +149,14 @@ static bool try_mode(struct fb_info *ret, size_t mode, uint64_t width, uint64_t return true; } -struct fb_info *gop_get_mode_list(size_t *count) { - if (!gop_ready) { - return NULL; - } - +static struct fb_info *get_mode_list(size_t *count, EFI_GRAPHICS_OUTPUT_PROTOCOL *gop) { UINTN modes_count = gop->Mode->MaxMode; struct fb_info *ret = ext_mem_alloc(modes_count * sizeof(struct fb_info)); size_t actual_count = 0; for (size_t i = 0; i < modes_count; i++) { - if (mode_to_fb_info(&ret[actual_count], i)) { + if (mode_to_fb_info(&ret[actual_count], gop, i)) { actual_count++; } } @@ -170,21 +171,8 @@ struct fb_info *gop_get_mode_list(size_t *count) { return ret; } -#define INVALID_PRESET_MODE 0xffffffff - -static no_unwind size_t preset_mode = INVALID_PRESET_MODE; -static no_unwind EFI_GRAPHICS_OUTPUT_MODE_INFORMATION preset_mode_info; - -bool gop_ready = false; -EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; -EFI_HANDLE gop_handle; - -bool init_gop(struct fb_info *ret, +void init_gop(struct fb_info **ret, size_t *_fbs_count, uint64_t target_width, uint64_t target_height, uint16_t target_bpp) { - gop_ready = false; - - ret->default_res = false; - EFI_STATUS status; EFI_HANDLE tmp_handles[1]; @@ -196,7 +184,8 @@ bool init_gop(struct fb_info *ret, status = gBS->LocateHandle(ByProtocol, &gop_guid, NULL, &handles_size, handles); if (status != EFI_SUCCESS && status != EFI_BUFFER_TOO_SMALL) { - return false; + *_fbs_count = 0; + return; } handles = ext_mem_alloc(handles_size); @@ -204,45 +193,15 @@ bool init_gop(struct fb_info *ret, status = gBS->LocateHandle(ByProtocol, &gop_guid, NULL, &handles_size, handles); if (status != EFI_SUCCESS) { pmm_free(handles, handles_size); - return false; + *_fbs_count = 0; + return; } - gop_handle = handles[0]; - pmm_free(handles, handles_size); + size_t handles_count = handles_size / sizeof(EFI_HANDLE); - status = gBS->HandleProtocol(gop_handle, &gop_guid, (void **)&gop); - if (status != EFI_SUCCESS) { - return false; - } + *ret = ext_mem_alloc(handles_count * sizeof(struct fb_info)); - gop_ready = true; - - EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info; - UINTN mode_info_size; - - status = gop->QueryMode(gop, gop->Mode == NULL ? 0 : gop->Mode->Mode, - &mode_info_size, &mode_info); - - if (status == EFI_NOT_STARTED) { - status = gop->SetMode(gop, 0); - if (status) { - panic(false, "gop: Initialisation failed"); - } - status = gop->QueryMode(gop, gop->Mode == NULL ? 0 : gop->Mode->Mode, - &mode_info_size, &mode_info); - } - - if (status) { - panic(false, "gop: Initialisation failed"); - } - - if (preset_mode == INVALID_PRESET_MODE) { - preset_mode = gop->Mode->Mode; - memcpy(&preset_mode_info, mode_info, mode_info_size); - current_video_mode = preset_mode; - } - - struct resolution fallback_resolutions[] = { + const struct resolution fallback_resolutions[] = { { 0, 0, 0 }, // Overridden by EDID { 0, 0, 0 }, // Overridden by preset { 1024, 768, 32 }, @@ -256,67 +215,111 @@ bool init_gop(struct fb_info *ret, { 640, 480, 16 } }; - UINTN modes_count = gop->Mode->MaxMode; + size_t fbs_count = 0; + for (size_t i = 0; i < handles_count; i++) { + struct fb_info *fb = &(*ret)[fbs_count]; - size_t current_fallback = 0; + uint64_t _target_width = target_width; + uint64_t _target_height = target_height; + uint64_t _target_bpp = target_bpp; - if (!target_width || !target_height || !target_bpp) { - goto fallback; - } else { - printv("gop: Requested resolution of %ux%ux%u\n", - target_width, target_height, target_bpp); - } + EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; + + status = gBS->HandleProtocol(handles[i], &gop_guid, (void **)&gop); + if (status != EFI_SUCCESS) { + continue; + } + + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info; + UINTN mode_info_size; + + status = gop->QueryMode(gop, gop->Mode == NULL ? 0 : gop->Mode->Mode, + &mode_info_size, &mode_info); + + if (status == EFI_NOT_STARTED) { + status = gop->SetMode(gop, 0); + if (status) { + continue; + } + status = gop->QueryMode(gop, gop->Mode == NULL ? 0 : gop->Mode->Mode, + &mode_info_size, &mode_info); + } + + if (status) { + continue; + } + + int preset_mode = gop->Mode->Mode; + + fb->edid = get_edid_info(handles[i]); + + UINTN modes_count = gop->Mode->MaxMode; + + size_t current_fallback = 0; + + if (!_target_width || !_target_height || !_target_bpp) { + goto fallback; + } else { + printv("gop: Requested resolution of %ux%ux%u\n", + _target_width, _target_height, _target_bpp); + } retry: - for (size_t i = 0; i < modes_count; i++) { - if (try_mode(ret, i, target_width, target_height, target_bpp)) { - gop_force_16 = false; - return true; - } - } - -fallback: - ret->default_res = true; - - if (current_fallback == 0) { - current_fallback++; - - struct edid_info_struct *edid_info = get_edid_info(); - if (edid_info != NULL) { - uint64_t edid_width = (uint64_t)edid_info->det_timing_desc1[2]; - edid_width += ((uint64_t)edid_info->det_timing_desc1[4] & 0xf0) << 4; - uint64_t edid_height = (uint64_t)edid_info->det_timing_desc1[5]; - edid_height += ((uint64_t)edid_info->det_timing_desc1[7] & 0xf0) << 4; - if (edid_width >= preset_mode_info.HorizontalResolution - && edid_height >= preset_mode_info.VerticalResolution) { - target_width = edid_width; - target_height = edid_height; - target_bpp = 32; - goto retry; + for (size_t j = 0; j < modes_count; j++) { + if (try_mode(fb, gop, j, _target_width, _target_height, _target_bpp, *ret, fbs_count)) { + goto success; } } - } - if (current_fallback == 1) { - current_fallback++; +fallback: + if (current_fallback == 0) { + current_fallback++; - if (try_mode(ret, preset_mode, 0, 0, 0)) { - gop_force_16 = false; - return true; + if (fb->edid != NULL) { + uint64_t edid_width = (uint64_t)fb->edid->det_timing_desc1[2]; + edid_width += ((uint64_t)fb->edid->det_timing_desc1[4] & 0xf0) << 4; + uint64_t edid_height = (uint64_t)fb->edid->det_timing_desc1[5]; + edid_height += ((uint64_t)fb->edid->det_timing_desc1[7] & 0xf0) << 4; + if (edid_width >= mode_info->HorizontalResolution + && edid_height >= mode_info->VerticalResolution) { + _target_width = edid_width; + _target_height = edid_height; + _target_bpp = 32; + goto retry; + } + } } + + if (current_fallback == 1) { + current_fallback++; + + if (try_mode(fb, gop, preset_mode, 0, 0, 0, *ret, fbs_count)) { + goto success; + } + } + + if (current_fallback < SIZEOF_ARRAY(fallback_resolutions)) { + current_fallback++; + + _target_width = fallback_resolutions[current_fallback].width; + _target_height = fallback_resolutions[current_fallback].height; + _target_bpp = fallback_resolutions[current_fallback].bpp; + goto retry; + } + + continue; + +success: + fb->mode_list = get_mode_list(&fb->mode_count, gop); + + fbs_count++; } - if (current_fallback < SIZEOF_ARRAY(fallback_resolutions)) { - current_fallback++; - - target_width = fallback_resolutions[current_fallback].width; - target_height = fallback_resolutions[current_fallback].height; - target_bpp = fallback_resolutions[current_fallback].bpp; - goto retry; - } + pmm_free(handles, handles_size); gop_force_16 = false; - return false; + + *_fbs_count = fbs_count; } #endif diff --git a/common/drivers/gop.h b/common/drivers/gop.h index 32440be4..100c6bcf 100644 --- a/common/drivers/gop.h +++ b/common/drivers/gop.h @@ -6,20 +6,13 @@ #include #include #include -#include #include -bool init_gop(struct fb_info *ret, +void init_gop(struct fb_info **ret, size_t *_fbs_count, uint64_t target_width, uint64_t target_height, uint16_t target_bpp); -struct fb_info *gop_get_mode_list(size_t *count); - extern bool gop_force_16; -extern bool gop_ready; -extern EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; -extern EFI_HANDLE gop_handle; - #endif #endif diff --git a/common/drivers/vbe.c b/common/drivers/vbe.c index 2ecae69d..2b84ab80 100644 --- a/common/drivers/vbe.c +++ b/common/drivers/vbe.c @@ -187,8 +187,6 @@ bool init_vbe(struct fb_info *ret, uint16_t target_width, uint16_t target_height, uint16_t target_bpp) { printv("vbe: Initialising...\n"); - ret->default_res = false; - size_t current_fallback = 0; struct vbe_info_struct vbe_info; @@ -216,8 +214,6 @@ bool init_vbe(struct fb_info *ret, }; if (!target_width || !target_height || !target_bpp) { - ret->default_res = true; - struct edid_info_struct *edid_info = get_edid_info(); if (edid_info != NULL) { int edid_width = (int)edid_info->det_timing_desc1[2]; @@ -293,8 +289,6 @@ retry: } fallback: - ret->default_res = true; - if (current_fallback < SIZEOF_ARRAY(fallback_resolutions)) { target_width = fallback_resolutions[current_fallback].width; target_height = fallback_resolutions[current_fallback].height; diff --git a/common/drivers/vga_textmode.c b/common/drivers/vga_textmode.c index fbc517b9..fb13aa46 100644 --- a/common/drivers/vga_textmode.c +++ b/common/drivers/vga_textmode.c @@ -253,10 +253,7 @@ static void text_deinit(struct term_context *_ctx, void (*_free)(void *, size_t) static struct textmode_context term_local_struct; void vga_textmode_init(bool managed) { - if (term != NULL) { - term->deinit(term, pmm_free); - term = NULL; - } + term_notready(); if (quiet) { return; @@ -270,6 +267,13 @@ void vga_textmode_init(bool managed) { current_video_mode = 0x3; } + terms = ext_mem_alloc(sizeof(void *)); + terms_i = 1; + + terms[0] = ext_mem_alloc(sizeof(struct term_context)); + + struct term_context *term = terms[0]; + struct textmode_context *ctx = &term_local_struct; term = &term_local_struct.term; diff --git a/common/entry.s3.c b/common/entry.s3.c index 28f0ff6a..842c4034 100644 --- a/common/entry.s3.c +++ b/common/entry.s3.c @@ -38,6 +38,8 @@ noreturn void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) gST->ConOut->EnableCursor(gST->ConOut, false); + init_memmap(); + term_fallback(); status = gBS->SetWatchdogTimer(0, 0x10000, 0, NULL); @@ -45,8 +47,6 @@ noreturn void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) print("WARNING: Failed to disable watchdog timer!\n"); } - init_memmap(); - #if defined (__x86_64__) || defined (__i386__) init_gdt(); #endif diff --git a/common/lib/fb.c b/common/lib/fb.c index 95057e1c..5d6f32e1 100644 --- a/common/lib/fb.c +++ b/common/lib/fb.c @@ -6,24 +6,23 @@ #include #include -bool fb_init(struct fb_info *ret, +void fb_init(struct fb_info **ret, size_t *_fbs_count, uint64_t target_width, uint64_t target_height, uint16_t target_bpp) { - bool r; - #if defined (BIOS) - r = init_vbe(ret, target_width, target_height, target_bpp); -#elif defined (UEFI) - r = init_gop(ret, target_width, target_height, target_bpp); -#endif + *ret = ext_mem_alloc(sizeof(struct fb_info)); + if (init_vbe(*ret, target_width, target_height, target_bpp)) { + *_fbs_count = 1; - return r; -} - -struct fb_info *fb_get_mode_list(size_t *count) { -#if defined (BIOS) - return vbe_get_mode_list(count); + (*ret)->edid = get_edid_info(); + size_t mode_count; + (*ret)->mode_list = vbe_get_mode_list(&mode_count); + (*ret)->mode_count = mode_count; + } else { + *_fbs_count = 0; + pmm_free(*ret, sizeof(struct fb_info)); + } #elif defined (UEFI) - return gop_get_mode_list(count); + init_gop(ret, _fbs_count, target_width, target_height, target_bpp); #endif } diff --git a/common/lib/fb.h b/common/lib/fb.h index 83c65170..61f914fa 100644 --- a/common/lib/fb.h +++ b/common/lib/fb.h @@ -3,6 +3,7 @@ #include #include +#include struct resolution { uint64_t width; @@ -15,23 +16,25 @@ struct fb_info { uint64_t framebuffer_width; uint64_t framebuffer_height; uint16_t framebuffer_bpp; - uint8_t memory_model; - uint8_t red_mask_size; - uint8_t red_mask_shift; - uint8_t green_mask_size; - uint8_t green_mask_shift; - uint8_t blue_mask_size; - uint8_t blue_mask_shift; + uint8_t memory_model; + uint8_t red_mask_size; + uint8_t red_mask_shift; + uint8_t green_mask_size; + uint8_t green_mask_shift; + uint8_t blue_mask_size; + uint8_t blue_mask_shift; - bool default_res; uint64_t framebuffer_addr; + + struct edid_info_struct *edid; + + uint64_t mode_count; + struct fb_info *mode_list; }; -bool fb_init(struct fb_info *ret, +void fb_init(struct fb_info **ret, size_t *_fbs_count, uint64_t target_width, uint64_t target_height, uint16_t target_bpp); -struct fb_info *fb_get_mode_list(size_t *count); - void fb_clear(struct fb_info *fb); #endif diff --git a/common/lib/gterm.c b/common/lib/gterm.c index 7a11da59..a2d0a495 100644 --- a/common/lib/gterm.c +++ b/common/lib/gterm.c @@ -360,8 +360,6 @@ static const uint8_t builtin_font[] = { 0x00, 0x00, 0x00, 0x00 }; -struct fb_info fbinfo; - static struct image *background; static size_t margin = 64; @@ -389,10 +387,10 @@ static inline uint32_t colour_blend(uint32_t fg, uint32_t bg) { return ARGB(0, r, g, b); } -static uint32_t blend_gradient_from_box(size_t x, size_t y, uint32_t bg_px, uint32_t hex) { +static uint32_t blend_gradient_from_box(struct fb_info *fb, size_t x, size_t y, uint32_t bg_px, uint32_t hex) { size_t distance, x_distance, y_distance; - size_t gradient_stop_x = fbinfo.framebuffer_width - margin; - size_t gradient_stop_y = fbinfo.framebuffer_height - margin; + size_t gradient_stop_x = fb->framebuffer_width - margin; + size_t gradient_stop_y = fb->framebuffer_height - margin; if (x < margin) x_distance = margin - x; @@ -427,7 +425,7 @@ static size_t fixedp6_to_int(fixedp6 value) { return value / 64; } static fixedp6 int_to_fixedp6(size_t value) { return value * 64; } // Draw rect at coordinates, copying from the image to the fb and canvas, applying fn on every pixel -__attribute__((always_inline)) static inline void genloop(size_t xstart, size_t xend, size_t ystart, size_t yend, uint32_t (*blend)(size_t x, size_t y, uint32_t orig)) { +__attribute__((always_inline)) static inline void genloop(struct fb_info *fb, size_t xstart, size_t xend, size_t ystart, size_t yend, uint32_t (*blend)(struct fb_info *fb, size_t x, size_t y, uint32_t orig)) { uint8_t *img = background->img; const size_t img_width = background->img_width, img_height = background->img_height, img_pitch = background->pitch, colsize = background->bpp / 8; @@ -436,10 +434,10 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t for (size_t y = ystart; y < yend; y++) { size_t image_y = y % img_height, image_x = xstart % img_width; const size_t off = img_pitch * (img_height - 1 - image_y); - size_t canvas_off = fbinfo.framebuffer_width * y; + size_t canvas_off = fb->framebuffer_width * y; for (size_t x = xstart; x < xend; x++) { uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off); - uint32_t i = blend(x, y, img_pixel); + uint32_t i = blend(fb, x, y, img_pixel); bg_canvas[canvas_off + x] = i; if (image_x++ == img_width) image_x = 0; // image_x = x % img_width, but modulo is too expensive } @@ -450,10 +448,10 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t for (size_t y = ystart; y < yend; y++) { size_t image_y = y - background->y_displacement; const size_t off = img_pitch * (img_height - 1 - image_y); - size_t canvas_off = fbinfo.framebuffer_width * y; + size_t canvas_off = fb->framebuffer_width * y; if (image_y >= background->y_size) { /* external part */ for (size_t x = xstart; x < xend; x++) { - uint32_t i = blend(x, y, background->back_colour); + uint32_t i = blend(fb, x, y, background->back_colour); bg_canvas[canvas_off + x] = i; } } @@ -462,7 +460,7 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t size_t image_x = (x - background->x_displacement); bool x_external = image_x >= background->x_size; uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off); - uint32_t i = blend(x, y, x_external ? background->back_colour : img_pixel); + uint32_t i = blend(fb, x, y, x_external ? background->back_colour : img_pixel); bg_canvas[canvas_off + x] = i; } } @@ -473,15 +471,15 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t // so you can set x = xstart * ratio, and increment by ratio at each iteration case IMAGE_STRETCHED: for (size_t y = ystart; y < yend; y++) { - size_t img_y = (y * img_height) / fbinfo.framebuffer_height; // calculate Y with full precision + size_t img_y = (y * img_height) / fb->framebuffer_height; // calculate Y with full precision size_t off = img_pitch * (img_height - 1 - img_y); - size_t canvas_off = fbinfo.framebuffer_width * y; + size_t canvas_off = fb->framebuffer_width * y; - size_t ratio = int_to_fixedp6(img_width) / fbinfo.framebuffer_width; + size_t ratio = int_to_fixedp6(img_width) / fb->framebuffer_width; fixedp6 img_x = ratio * xstart; for (size_t x = xstart; x < xend; x++) { uint32_t img_pixel = *(uint32_t*)(img + fixedp6_to_int(img_x) * colsize + off); - uint32_t i = blend(x, y, img_pixel); + uint32_t i = blend(fb, x, y, img_pixel); bg_canvas[canvas_off + x] = i; img_x += ratio; } @@ -490,17 +488,17 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t } } -static uint32_t blend_external(size_t x, size_t y, uint32_t orig) { (void)x; (void)y; return orig; } -static uint32_t blend_internal(size_t x, size_t y, uint32_t orig) { (void)x; (void)y; return colour_blend(default_bg, orig); } -static uint32_t blend_margin(size_t x, size_t y, uint32_t orig) { return blend_gradient_from_box(x, y, orig, default_bg); } +static uint32_t blend_external(struct fb_info *fb, size_t x, size_t y, uint32_t orig) { (void)fb; (void)x; (void)y; return orig; } +static uint32_t blend_internal(struct fb_info *fb, size_t x, size_t y, uint32_t orig) { (void)fb; (void)x; (void)y; return colour_blend(default_bg, orig); } +static uint32_t blend_margin(struct fb_info *fb, size_t x, size_t y, uint32_t orig) { return blend_gradient_from_box(fb, x, y, orig, default_bg); } -static void loop_external(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_external); } -static void loop_margin(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_margin); } -static void loop_internal(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_internal); } +static void loop_external(struct fb_info *fb, size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(fb, xstart, xend, ystart, yend, blend_external); } +static void loop_margin(struct fb_info *fb, size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(fb, xstart, xend, ystart, yend, blend_margin); } +static void loop_internal(struct fb_info *fb, size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(fb, xstart, xend, ystart, yend, blend_internal); } -static void generate_canvas(void) { +static void generate_canvas(struct fb_info *fb) { if (background) { - bg_canvas_size = fbinfo.framebuffer_width * fbinfo.framebuffer_height * sizeof(uint32_t); + bg_canvas_size = fb->framebuffer_width * fb->framebuffer_height * sizeof(uint32_t); bg_canvas = ext_mem_alloc(bg_canvas_size); int64_t margin_no_gradient = (int64_t)margin - margin_gradient; @@ -509,99 +507,76 @@ static void generate_canvas(void) { margin_no_gradient = 0; } - size_t scan_stop_x = fbinfo.framebuffer_width - margin_no_gradient; - size_t scan_stop_y = fbinfo.framebuffer_height - margin_no_gradient; + size_t scan_stop_x = fb->framebuffer_width - margin_no_gradient; + size_t scan_stop_y = fb->framebuffer_height - margin_no_gradient; - loop_external(0, fbinfo.framebuffer_width, 0, margin_no_gradient); - loop_external(0, fbinfo.framebuffer_width, scan_stop_y, fbinfo.framebuffer_height); - loop_external(0, margin_no_gradient, margin_no_gradient, scan_stop_y); - loop_external(scan_stop_x, fbinfo.framebuffer_width, margin_no_gradient, scan_stop_y); + loop_external(fb, 0, fb->framebuffer_width, 0, margin_no_gradient); + loop_external(fb, 0, fb->framebuffer_width, scan_stop_y, fb->framebuffer_height); + loop_external(fb, 0, margin_no_gradient, margin_no_gradient, scan_stop_y); + loop_external(fb, scan_stop_x, fb->framebuffer_width, margin_no_gradient, scan_stop_y); - size_t gradient_stop_x = fbinfo.framebuffer_width - margin; - size_t gradient_stop_y = fbinfo.framebuffer_height - margin; + size_t gradient_stop_x = fb->framebuffer_width - margin; + size_t gradient_stop_y = fb->framebuffer_height - margin; if (margin_gradient) { - loop_margin(margin_no_gradient, scan_stop_x, margin_no_gradient, margin); - loop_margin(margin_no_gradient, scan_stop_x, gradient_stop_y, scan_stop_y); - loop_margin(margin_no_gradient, margin, margin, gradient_stop_y); - loop_margin(gradient_stop_x, scan_stop_x, margin, gradient_stop_y); + loop_margin(fb, margin_no_gradient, scan_stop_x, margin_no_gradient, margin); + loop_margin(fb, margin_no_gradient, scan_stop_x, gradient_stop_y, scan_stop_y); + loop_margin(fb, margin_no_gradient, margin, margin, gradient_stop_y); + loop_margin(fb, gradient_stop_x, scan_stop_x, margin, gradient_stop_y); } - loop_internal(margin, gradient_stop_x, margin, gradient_stop_y); + loop_internal(fb, margin, gradient_stop_x, margin, gradient_stop_y); } else { bg_canvas = NULL; } } -static bool last_serial = false; -static char *last_config = NULL; +bool gterm_init(struct fb_info **_fbs, size_t *_fbs_count, + char *config, size_t width, size_t height) { + static struct fb_info *fbs; + static size_t fbs_count; + + static bool prev_valid = false; + static char *prev_config; + static size_t prev_width, prev_height; + + if (prev_valid && config == prev_config && width == prev_width && height == prev_height) { + *_fbs = fbs; + *_fbs_count = fbs_count; + reset_term(); + return true; + } + + prev_valid = false; -bool gterm_init(char *config, size_t width, size_t height) { if (quiet) { - if (term != NULL) { - term->deinit(term, pmm_free); - term = NULL; - } + term_notready(); return false; } #if defined (UEFI) if (serial || COM_OUTPUT) { - if (term != NULL) { - term->deinit(term, pmm_free); - term = NULL; - } term_fallback(); return true; } #endif - if (term != NULL - && term_backend == GTERM - && fbinfo.default_res == true - && width == 0 - && height == 0 - && fbinfo.framebuffer_bpp == 32 - && serial == last_serial - && config == last_config) { - term->clear(term, true); - return true; - } - - if (term != NULL - && term_backend == GTERM - && fbinfo.framebuffer_width == width - && fbinfo.framebuffer_height == height - && fbinfo.framebuffer_bpp == 32 - && serial == last_serial - && config == last_config) { - term->clear(term, true); - return true; - } - - if (term != NULL) { - term->deinit(term, pmm_free); - term = NULL; - } + term_notready(); // We force bpp to 32 - if (!fb_init(&fbinfo, width, height, 32)) { - return false; + fb_init(&fbs, &fbs_count, width, height, 32); + + if (_fbs != NULL) { + *_fbs = fbs; + } + if (_fbs_count != NULL) { + *_fbs_count = fbs_count; } - // Ensure this is xRGB8888, we only support that for the menu - if (fbinfo.red_mask_size != 8 - || fbinfo.red_mask_shift != 16 - || fbinfo.green_mask_size != 8 - || fbinfo.green_mask_shift != 8 - || fbinfo.blue_mask_size != 8 - || fbinfo.blue_mask_shift != 0) { + if (fbs_count == 0) { return false; } - last_serial = serial; - last_config = config; - // default scheme margin = 64; margin_gradient = 4; @@ -702,20 +677,6 @@ bool gterm_init(char *config, size_t width, size_t height) { margin_gradient = strtoui(theme_margin_gradient, NULL, 10); } - if (background != NULL) { - char *background_layout = config_get_value(config, 0, "TERM_WALLPAPER_STYLE"); - if (background_layout != NULL && strcmp(background_layout, "centered") == 0) { - char *background_colour = config_get_value(config, 0, "TERM_BACKDROP"); - if (background_colour == NULL) - background_colour = "0"; - uint32_t bg_col = strtoui(background_colour, NULL, 16); - image_make_centered(background, fbinfo.framebuffer_width, fbinfo.framebuffer_height, bg_col); - } else if (background_layout != NULL && strcmp(background_layout, "tiled") == 0) { - } else { - image_make_stretched(background, fbinfo.framebuffer_width, fbinfo.framebuffer_height); - } - } - size_t font_width = 8; size_t font_height = 16; size_t font_size = (font_width * font_height * FBTERM_FONT_GLYPHS) / 8; @@ -775,38 +736,105 @@ no_load_font:; } } - generate_canvas(); + terms_i = 0; + terms = ext_mem_alloc(fbs_count * sizeof(void *)); - term = fbterm_init(ext_mem_alloc, - (void *)(uintptr_t)fbinfo.framebuffer_addr, - fbinfo.framebuffer_width, fbinfo.framebuffer_height, fbinfo.framebuffer_pitch, - bg_canvas, - ansi_colours, ansi_bright_colours, - &default_bg, &default_fg, - font, font_width, font_height, font_spacing, - font_scale_x, font_scale_y, - margin); + for (size_t i = 0; i < fbs_count; i++) { + struct fb_info *fb = &fbs[i]; - pmm_free(font, FONT_MAX); - if (bg_canvas != NULL) { - pmm_free(bg_canvas, bg_canvas_size); + // Ensure this is xRGB8888, we only support that for the menu + if (fb->red_mask_size != 8 + || fb->red_mask_shift != 16 + || fb->green_mask_size != 8 + || fb->green_mask_shift != 8 + || fb->blue_mask_size != 8 + || fb->blue_mask_shift != 0) { + continue; + } + + if (background != NULL) { + char *background_layout = config_get_value(config, 0, "TERM_WALLPAPER_STYLE"); + if (background_layout != NULL && strcmp(background_layout, "centered") == 0) { + char *background_colour = config_get_value(config, 0, "TERM_BACKDROP"); + if (background_colour == NULL) + background_colour = "0"; + uint32_t bg_col = strtoui(background_colour, NULL, 16); + image_make_centered(background, fb->framebuffer_width, fb->framebuffer_height, bg_col); + } else if (background_layout != NULL && strcmp(background_layout, "tiled") == 0) { + } else { + image_make_stretched(background, fb->framebuffer_width, fb->framebuffer_height); + } + } + + generate_canvas(fb); + + terms[terms_i] = fbterm_init(ext_mem_alloc, + (void *)(uintptr_t)fb->framebuffer_addr, + fb->framebuffer_width, fb->framebuffer_height, fb->framebuffer_pitch, + bg_canvas, + ansi_colours, ansi_bright_colours, + &default_bg, &default_fg, + font, font_width, font_height, font_spacing, + font_scale_x, font_scale_y, + margin); + + if (terms[terms_i] != NULL) { + terms_i++; + } + + if (bg_canvas != NULL) { + pmm_free(bg_canvas, bg_canvas_size); + } } - if (term == NULL) { + pmm_free(font, FONT_MAX); + + if (terms_i == 0) { return false; } - if (serial) { - term->cols = term->cols > 80 ? 80 : term->cols; - term->rows = term->rows > 24 ? 24 : term->rows; + for (size_t i = 0; i < terms_i; i++) { + struct term_context *term = terms[i]; + + if (serial) { + term->cols = term->cols > 80 ? 80 : term->cols; + term->rows = term->rows > 24 ? 24 : term->rows; + } } - term->in_bootloader = true; + size_t min_cols = (size_t)-1; + size_t min_rows = (size_t)-1; - term_context_reinit(term); - term->full_refresh(term); + for (size_t i = 0; i < terms_i; i++) { + struct term_context *term = terms[i]; + + if (term->cols < min_cols) { + min_cols = term->cols; + } + + if (term->rows < min_rows) { + min_rows = term->rows; + } + } + + for (size_t i = 0; i < terms_i; i++) { + struct term_context *term = terms[i]; + + term->cols = min_cols; + term->rows = min_rows; + + term->in_bootloader = true; + + term_context_reinit(term); + term->full_refresh(term); + } term_backend = GTERM; + prev_config = config; + prev_height = height; + prev_width = width; + prev_valid = true; + return true; } diff --git a/common/lib/gterm.h b/common/lib/gterm.h index a680e7f2..891aea68 100644 --- a/common/lib/gterm.h +++ b/common/lib/gterm.h @@ -5,8 +5,7 @@ #include #include -extern struct fb_info fbinfo; - -bool gterm_init(char *config, size_t width, size_t height); +bool gterm_init(struct fb_info **ret, size_t *_fbs_count, + char *config, size_t width, size_t height); #endif diff --git a/common/lib/print.s2.c b/common/lib/print.s2.c index 5464958d..9d89e044 100644 --- a/common/lib/print.s2.c +++ b/common/lib/print.s2.c @@ -222,9 +222,7 @@ out: #if defined (BIOS) if (stage3_loaded) { #endif - if (term != NULL) { - term_write(term, print_buf, print_buf_i); - } + FOR_TERM(term_write(TERM, print_buf, print_buf_i)); #if defined (BIOS) } else { s2_print(print_buf, print_buf_i); diff --git a/common/lib/readline.c b/common/lib/readline.c index 5d36a192..2082968f 100644 --- a/common/lib/readline.c +++ b/common/lib/readline.c @@ -352,34 +352,34 @@ again: static void reprint_string(int x, int y, const char *s) { size_t orig_x, orig_y; - term->disable_cursor(term); - term->get_cursor_pos(term, &orig_x, &orig_y); + FOR_TERM(TERM->disable_cursor(TERM)); + terms[0]->get_cursor_pos(terms[0], &orig_x, &orig_y); set_cursor_pos_helper(x, y); print("%s", s); set_cursor_pos_helper(orig_x, orig_y); - term->enable_cursor(term); + FOR_TERM(TERM->enable_cursor(TERM)); } static void cursor_back(void) { size_t x, y; - term->get_cursor_pos(term, &x, &y); + terms[0]->get_cursor_pos(terms[0], &x, &y); if (x) { x--; } else if (y) { y--; - x = term->cols - 1; + x = terms[0]->cols - 1; } set_cursor_pos_helper(x, y); } static void cursor_fwd(void) { size_t x, y; - term->get_cursor_pos(term, &x, &y); - if (x < term->cols - 1) { + terms[0]->get_cursor_pos(terms[0], &x, &y); + if (x < terms[0]->cols - 1) { x++; } else { x = 0; - if (y < term->rows - 1) { + if (y < terms[0]->rows - 1) { y++; } } @@ -387,20 +387,20 @@ static void cursor_fwd(void) { } void readline(const char *orig_str, char *buf, size_t limit) { - bool prev_autoflush = term->autoflush; - term->autoflush = false; + bool prev_autoflush = terms[0]->autoflush; + FOR_TERM(TERM->autoflush = false); size_t orig_str_len = strlen(orig_str); memmove(buf, orig_str, orig_str_len); buf[orig_str_len] = 0; size_t orig_x, orig_y; - term->get_cursor_pos(term, &orig_x, &orig_y); + terms[0]->get_cursor_pos(terms[0], &orig_x, &orig_y); print("%s", orig_str); for (size_t i = orig_str_len; ; ) { - term->double_buffer_flush(term); + FOR_TERM(TERM->double_buffer_flush(TERM)); int c = getchar(); switch (c) { case GETCHAR_CURSOR_LEFT: @@ -460,11 +460,11 @@ void readline(const char *orig_str, char *buf, size_t limit) { buf[i] = c; i++; size_t prev_x, prev_y; - term->get_cursor_pos(term, &prev_x, &prev_y); + terms[0]->get_cursor_pos(terms[0], &prev_x, &prev_y); cursor_fwd(); reprint_string(orig_x, orig_y, buf); // If cursor has wrapped around, move the line start position up one row - if (prev_x == term->cols - 1 && prev_y == term->rows - 1) { + if (prev_x == terms[0]->cols - 1 && prev_y == terms[0]->rows - 1) { orig_y--; print("\e[J"); // Clear the bottom line } @@ -474,6 +474,6 @@ void readline(const char *orig_str, char *buf, size_t limit) { } out: - term->double_buffer_flush(term); - term->autoflush = prev_autoflush; + FOR_TERM(TERM->double_buffer_flush(TERM)); + FOR_TERM(TERM->autoflush = prev_autoflush); } diff --git a/common/lib/term.c b/common/lib/term.c index be72f5ea..d6421585 100644 --- a/common/lib/term.c +++ b/common/lib/term.c @@ -8,95 +8,28 @@ #include #include +#if defined (BIOS) int current_video_mode = -1; +#endif + +struct term_context **terms = NULL; +size_t terms_i = 0; + int term_backend = _NOT_READY; -struct term_context *term; +void term_notready(void) { + for (size_t i = 0; i < terms_i; i++) { + struct term_context *term = terms[i]; -static struct term_context term_local_struct; - -// --- notready --- - -static void notready_raw_putchar(struct term_context *ctx, uint8_t c) { - (void)ctx; - (void)c; -} -static void notready_clear(struct term_context *ctx, bool move) { - (void)ctx; - (void)move; -} -static void notready_void(struct term_context *ctx) { - (void)ctx; -} -static void notready_set_cursor_pos(struct term_context *ctx, size_t x, size_t y) { - (void)ctx; - (void)x; (void)y; -} -static void notready_get_cursor_pos(struct term_context *ctx, size_t *x, size_t *y) { - (void)ctx; - *x = 0; - *y = 0; -} -static void notready_size_t(struct term_context *ctx, size_t n) { - (void)ctx; - (void)n; -} -static bool notready_disable(struct term_context *ctx) { - (void)ctx; - return false; -} -static void notready_move_character(struct term_context *ctx, size_t a, size_t b, size_t c, size_t d) { - (void)ctx; - (void)a; (void)b; (void)c; (void)d; -} -static void notready_uint32_t(struct term_context *ctx, uint32_t n) { - (void)ctx; - (void)n; -} -static void notready_deinit(struct term_context *ctx, void (*_free)(void *, size_t)) { - (void)ctx; - (void)_free; -} - -static void term_notready(void) { - if (term != NULL) { term->deinit(term, pmm_free); - term = NULL; } - term = &term_local_struct; + pmm_free(terms, terms_i * sizeof(void *)); - term->raw_putchar = notready_raw_putchar; - term->clear = notready_clear; - term->enable_cursor = notready_void; - term->disable_cursor = notready_disable; - term->set_cursor_pos = notready_set_cursor_pos; - term->get_cursor_pos = notready_get_cursor_pos; - term->set_text_fg = notready_size_t; - term->set_text_bg = notready_size_t; - term->set_text_fg_bright = notready_size_t; - term->set_text_bg_bright = notready_size_t; - term->set_text_fg_rgb = notready_uint32_t; - term->set_text_bg_rgb = notready_uint32_t; - term->set_text_fg_default = notready_void; - term->set_text_bg_default = notready_void; - term->move_character = notready_move_character; - term->scroll = notready_void; - term->revscroll = notready_void; - term->swap_palette = notready_void; - term->save_state = notready_void; - term->restore_state = notready_void; - term->double_buffer_flush = notready_void; - term->full_refresh = notready_void; - term->deinit = notready_deinit; - - term->cols = 80; - term->rows = 24; + terms_i = 0; + terms = NULL; term_backend = _NOT_READY; - term_context_reinit(term); - - term->in_bootloader = true; } // --- fallback --- @@ -162,7 +95,7 @@ static void fallback_scroll(struct term_context *ctx) { (void)ctx; size_t x, y; fallback_get_cursor_pos(NULL, &x, &y); - fallback_set_cursor_pos(NULL, term->cols - 1, term->rows - 1); + fallback_set_cursor_pos(NULL, ctx->cols - 1, ctx->rows - 1); fallback_raw_putchar(NULL, ' '); fallback_set_cursor_pos(NULL, x, y); } @@ -173,7 +106,7 @@ static size_t cursor_x = 0, cursor_y = 0; static void fallback_scroll(struct term_context *ctx) { (void)ctx; - gST->ConOut->SetCursorPosition(gST->ConOut, term->cols - 1, term->rows - 1); + gST->ConOut->SetCursorPosition(gST->ConOut, ctx->cols - 1, ctx->rows - 1); CHAR16 string[2]; string[0] = ' '; string[1] = 0; @@ -182,7 +115,7 @@ static void fallback_scroll(struct term_context *ctx) { } static void fallback_raw_putchar(struct term_context *ctx, uint8_t c) { - if (!ctx->scroll_enabled && cursor_x == term->cols - 1 && cursor_y == term->rows - 1) { + if (!ctx->scroll_enabled && cursor_x == ctx->cols - 1 && cursor_y == ctx->rows - 1) { return; } gST->ConOut->EnableCursor(gST->ConOut, true); @@ -190,9 +123,9 @@ static void fallback_raw_putchar(struct term_context *ctx, uint8_t c) { string[0] = c; string[1] = 0; gST->ConOut->OutputString(gST->ConOut, string); - if (++cursor_x >= term->cols) { + if (++cursor_x >= ctx->cols) { cursor_x = 0; - if (++cursor_y >= term->rows) { + if (++cursor_y >= ctx->rows) { cursor_y--; } } @@ -210,7 +143,7 @@ static void fallback_clear(struct term_context *ctx, bool move) { static void fallback_set_cursor_pos(struct term_context *ctx, size_t x, size_t y) { (void)ctx; - if (x >= term->cols || y >= term->rows) { + if (x >= ctx->cols || y >= ctx->rows) { return; } gST->ConOut->SetCursorPosition(gST->ConOut, x, y); @@ -225,13 +158,45 @@ static void fallback_get_cursor_pos(struct term_context *ctx, size_t *x, size_t } #endif +static bool dummy_handle(void) { + return true; +} + void term_fallback(void) { term_notready(); #if defined (UEFI) if (!efi_boot_services_exited) { #endif + + terms = ext_mem_alloc(sizeof(void *)); + terms_i = 1; + + terms[0] = ext_mem_alloc(sizeof(struct term_context)); + + struct term_context *term = terms[0]; + fallback_clear(NULL, true); + + term->enable_cursor = (void *)dummy_handle; + term->disable_cursor = (void *)dummy_handle; + term->set_text_fg = (void *)dummy_handle; + term->set_text_bg = (void *)dummy_handle; + term->set_text_fg_bright = (void *)dummy_handle; + term->set_text_bg_bright = (void *)dummy_handle; + term->set_text_fg_rgb = (void *)dummy_handle; + term->set_text_bg_rgb = (void *)dummy_handle; + term->set_text_fg_default = (void *)dummy_handle; + term->set_text_bg_default = (void *)dummy_handle; + term->move_character = (void *)dummy_handle; + term->revscroll = (void *)dummy_handle; + term->swap_palette = (void *)dummy_handle; + term->save_state = (void *)dummy_handle; + term->restore_state = (void *)dummy_handle; + term->double_buffer_flush = (void *)dummy_handle; + term->full_refresh = (void *)dummy_handle; + term->deinit = (void *)dummy_handle; + term->raw_putchar = fallback_raw_putchar; term->clear = fallback_clear; term->set_cursor_pos = fallback_set_cursor_pos; @@ -264,7 +229,7 @@ extern void set_cursor_pos_helper(size_t x, size_t y); static uint8_t xfer_buf[TERM_XFER_CHUNK]; #endif -static uint64_t context_size(void) { +static uint64_t context_size(struct term_context *term) { switch (term_backend) { #if defined (BIOS) case TEXTMODE: @@ -285,7 +250,7 @@ static uint64_t context_size(void) { } } -static void context_save(uint64_t buf) { +static void context_save(struct term_context *term, uint64_t buf) { switch (term_backend) { #if defined (BIOS) case TEXTMODE: { @@ -320,7 +285,7 @@ static void context_save(uint64_t buf) { } } -static void context_restore(uint64_t buf) { +static void context_restore(struct term_context *term, uint64_t buf) { switch (term_backend) { #if defined (BIOS) case TEXTMODE: { @@ -355,19 +320,19 @@ static void context_restore(uint64_t buf) { } } -void _term_write(uint64_t buf, uint64_t count) { +void _term_write(struct term_context *term, uint64_t buf, uint64_t count) { switch (count) { case TERM_CTX_SIZE: { - uint64_t ret = context_size(); + uint64_t ret = context_size(term); memcpy32to64(buf, (uint64_t)(uintptr_t)&ret, sizeof(uint64_t)); return; } case TERM_CTX_SAVE: { - context_save(buf); + context_save(term, buf); return; } case TERM_CTX_RESTORE: { - context_restore(buf); + context_restore(term, buf); return; } case TERM_FULL_REFRESH: { diff --git a/common/lib/term.h b/common/lib/term.h index e3132bc5..abc05856 100644 --- a/common/lib/term.h +++ b/common/lib/term.h @@ -13,28 +13,46 @@ enum { FALLBACK }; +#if defined (BIOS) extern int current_video_mode; -extern int term_backend; +#endif -extern struct term_context *term; +extern struct term_context **terms; +extern size_t terms_i; + +extern int term_backend; #define TERM_CTX_SIZE ((uint64_t)(-1)) #define TERM_CTX_SAVE ((uint64_t)(-2)) #define TERM_CTX_RESTORE ((uint64_t)(-3)) #define TERM_FULL_REFRESH ((uint64_t)(-4)) +#define FOR_TERM(...) do { \ + for (size_t FOR_TERM_i = 0; FOR_TERM_i < terms_i; FOR_TERM_i++) { \ + struct term_context *TERM = terms[FOR_TERM_i]; \ + __VA_ARGS__ \ + ; \ + } \ +} while (0) + inline void reset_term(void) { - term->autoflush = true; - term->enable_cursor(term); - print("\e[2J\e[H"); - term->double_buffer_flush(term); + for (size_t i = 0; i < terms_i; i++) { + struct term_context *term = terms[i]; + + print("\e[2J\e[H"); + term_context_reinit(term); + term->in_bootloader = true; + term->enable_cursor(term); + term->double_buffer_flush(term); + } } inline void set_cursor_pos_helper(size_t x, size_t y) { print("\e[%u;%uH", (int)y + 1, (int)x + 1); } +void term_notready(void); void term_fallback(void); -void _term_write(uint64_t buf, uint64_t count); +void _term_write(struct term_context *term, uint64_t buf, uint64_t count); #endif diff --git a/common/linker_bios.ld.in b/common/linker_bios.ld.in index 3e0132b4..d62871b3 100644 --- a/common/linker_bios.ld.in +++ b/common/linker_bios.ld.in @@ -43,7 +43,8 @@ SECTIONS term_write = .; term_backend = .; term_fallback = .; - term = .; + terms = .; + terms_i = .; stage3_addr = .; #else #ifdef LINKER_NOS2MAP diff --git a/common/menu.c b/common/menu.c index 6fcbad26..a2f764aa 100644 --- a/common/menu.c +++ b/common/menu.c @@ -168,17 +168,17 @@ static void putchar_tokencol(int type, char c) { static bool editor_no_term_reset = false; char *config_entry_editor(const char *title, const char *orig_entry) { - term->autoflush = false; + FOR_TERM(TERM->autoflush = false); - term->enable_cursor(term); + FOR_TERM(TERM->enable_cursor(TERM)); print("\e[2J\e[H"); size_t cursor_offset = 0; size_t entry_size = strlen(orig_entry); - size_t _window_size = term->rows - 8; + size_t _window_size = terms[0]->rows - 8; size_t window_offset = 0; - size_t line_size = term->cols - 2; + size_t line_size = terms[0]->cols - 2; bool display_overflow_error = false; @@ -214,12 +214,12 @@ refresh: invalid_syntax = false; print("\e[2J\e[H"); - term->disable_cursor(term); + FOR_TERM(TERM->disable_cursor(TERM)); { size_t x, y; print("\n"); - term->get_cursor_pos(term, &x, &y); - set_cursor_pos_helper(term->cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), y); + terms[0]->get_cursor_pos(terms[0], &x, &y); + set_cursor_pos_helper(terms[0]->cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), y); print("\e[3%sm%s\e[37m", menu_branding_colour, menu_branding); print("\n\n"); } @@ -227,7 +227,7 @@ refresh: print(" \e[32mESC\e[0m Discard and Exit \e[32mF10\e[0m Boot\n\n"); print(serial ? "/" : "\xda"); - for (size_t i = 0; i < term->cols - 2; i++) { + for (size_t i = 0; i < terms[0]->cols - 2; i++) { switch (i) { case 1: case 2: case 3: if (window_offset > 0) { @@ -237,7 +237,7 @@ refresh: // FALLTHRU default: { size_t title_length = strlen(title); - if (i == (term->cols / 2) - DIV_ROUNDUP(title_length, 2) - 1) { + if (i == (terms[0]->cols / 2) - DIV_ROUNDUP(title_length, 2) - 1) { print("%s", title); i += title_length - 1; } else { @@ -248,7 +248,7 @@ refresh: } size_t tmpx, tmpy; - term->get_cursor_pos(term, &tmpx, &tmpy); + terms[0]->get_cursor_pos(terms[0], &tmpx, &tmpy); print(serial ? "\\" : "\xbf"); set_cursor_pos_helper(0, tmpy + 1); print(serial ? "|" : "\xb3"); @@ -264,20 +264,20 @@ refresh: && current_line < window_offset + window_size && current_line >= window_offset) { size_t x, y; - term->get_cursor_pos(term, &x, &y); + terms[0]->get_cursor_pos(terms[0], &x, &y); if (i == cursor_offset) { cursor_x = x; cursor_y = y; printed_cursor = true; } - set_cursor_pos_helper(term->cols - 1, y); + set_cursor_pos_helper(terms[0]->cols - 1, y); if (current_line == window_offset + window_size - 1) { - term->get_cursor_pos(term, &tmpx, &tmpy); + terms[0]->get_cursor_pos(terms[0], &tmpx, &tmpy); print(serial ? "|" : "\xb3"); set_cursor_pos_helper(0, tmpy + 1); print(serial ? "\\" : "\xc0"); } else { - term->get_cursor_pos(term, &tmpx, &tmpy); + terms[0]->get_cursor_pos(terms[0], &tmpx, &tmpy); print(serial ? "|" : "\xb3"); set_cursor_pos_helper(0, tmpy + 1); print(serial ? "|" : "\xb3"); @@ -295,7 +295,7 @@ refresh: if (current_line < window_offset + window_size && current_line >= window_offset) { if (i == cursor_offset) { - term->get_cursor_pos(term, &cursor_x, &cursor_y); + terms[0]->get_cursor_pos(terms[0], &cursor_x, &cursor_y); printed_cursor = true; } if (syntax_highlighting_enabled) { @@ -305,8 +305,8 @@ refresh: } printed_early = true; size_t x, y; - term->get_cursor_pos(term, &x, &y); - if (y == term->rows - 3) { + terms[0]->get_cursor_pos(terms[0], &x, &y); + if (y == terms[0]->rows - 3) { print(serial ? ">" : "\x1a"); set_cursor_pos_helper(0, y + 1); print(serial ? "\\" : "\xc0"); @@ -323,7 +323,7 @@ refresh: && current_line < window_offset + window_size && current_line >= window_offset && !printed_cursor) { - term->get_cursor_pos(term, &cursor_x, &cursor_y); + terms[0]->get_cursor_pos(terms[0], &cursor_x, &cursor_y); printed_cursor = true; } @@ -370,35 +370,35 @@ refresh: // syntax error alert if (validation_enabled) { size_t x, y; - term->get_cursor_pos(term, &x, &y); - set_cursor_pos_helper(0, term->rows - 1); - term->scroll_enabled = false; + terms[0]->get_cursor_pos(terms[0], &x, &y); + set_cursor_pos_helper(0, terms[0]->rows - 1); + FOR_TERM(TERM->scroll_enabled = false); if (invalid_syntax) { print("\e[31mConfiguration is INVALID.\e[0m"); } else { print("\e[32mConfiguration is valid.\e[0m"); } - term->scroll_enabled = true; + FOR_TERM(TERM->scroll_enabled = true); set_cursor_pos_helper(x, y); } if (current_line - window_offset < window_size) { size_t x, y; for (size_t i = 0; i < (window_size - (current_line - window_offset)) - 1; i++) { - term->get_cursor_pos(term, &x, &y); - set_cursor_pos_helper(term->cols - 1, y); + terms[0]->get_cursor_pos(terms[0], &x, &y); + set_cursor_pos_helper(terms[0]->cols - 1, y); print(serial ? "|" : "\xb3"); set_cursor_pos_helper(0, y + 1); print(serial ? "|" : "\xb3"); } - term->get_cursor_pos(term, &x, &y); - set_cursor_pos_helper(term->cols - 1, y); + terms[0]->get_cursor_pos(terms[0], &x, &y); + set_cursor_pos_helper(terms[0]->cols - 1, y); print(serial ? "|" : "\xb3"); set_cursor_pos_helper(0, y + 1); print(serial ? "\\" : "\xc0"); } - for (size_t i = 0; i < term->cols - 2; i++) { + for (size_t i = 0; i < terms[0]->cols - 2; i++) { switch (i) { case 1: case 2: case 3: if (current_line - window_offset >= window_size) { @@ -410,22 +410,22 @@ refresh: print(serial ? "-" : "\xc4"); } } - term->get_cursor_pos(term, &tmpx, &tmpy); + terms[0]->get_cursor_pos(terms[0], &tmpx, &tmpy); print(serial ? "/" : "\xd9"); set_cursor_pos_helper(0, tmpy + 1); if (display_overflow_error) { - term->scroll_enabled = false; + FOR_TERM(TERM->scroll_enabled = false); print("\e[31mText buffer not big enough, delete something instead."); - term->scroll_enabled = true; + FOR_TERM(TERM->scroll_enabled = true); display_overflow_error = false; } // Hack to redraw the cursor set_cursor_pos_helper(cursor_x, cursor_y); - term->enable_cursor(term); + FOR_TERM(TERM->enable_cursor(TERM)); - term->double_buffer_flush(term); + FOR_TERM(TERM->double_buffer_flush(TERM)); int c = getchar(); size_t buffer_len = strlen(buffer); @@ -584,7 +584,7 @@ static void menu_init_term(void) { if (menu_resolution != NULL) parse_resolution(&req_width, &req_height, &req_bpp, menu_resolution); - if (!quiet && !gterm_init(NULL, req_width, req_height)) { + if (!quiet && !gterm_init(NULL, NULL, NULL, req_width, req_height)) { #if defined (BIOS) vga_textmode_init(true); #elif defined (UEFI) @@ -721,23 +721,23 @@ noreturn void _menu(bool first_run) { size_t tree_offset = 0; refresh: - if (selected_entry >= tree_offset + term->rows - 10) { - tree_offset = selected_entry - (term->rows - 11); + if (selected_entry >= tree_offset + terms[0]->rows - 10) { + tree_offset = selected_entry - (terms[0]->rows - 11); } if (selected_entry < tree_offset) { tree_offset = selected_entry; } - term->autoflush = false; + FOR_TERM(TERM->autoflush = false); - term->disable_cursor(term); + FOR_TERM(TERM->disable_cursor(TERM)); print("\e[2J\e[H"); { size_t x, y; print("\n"); - term->get_cursor_pos(term, &x, &y); - set_cursor_pos_helper(term->cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), y); + terms[0]->get_cursor_pos(terms[0], &x, &y); + set_cursor_pos_helper(terms[0]->cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), y); print("\e[3%sm%s\e[37m", menu_branding_colour, menu_branding); print("\n\n\n\n"); } @@ -746,14 +746,14 @@ refresh: if (quiet) { quiet = false; menu_init_term(); - term->autoflush = false; - term->disable_cursor(term); + FOR_TERM(TERM->autoflush = false); + FOR_TERM(TERM->disable_cursor(TERM)); } print("Config file %s.\n\n", config_ready ? "contains no valid entries" : "not found"); print("For information on the format of Limine config entries, consult CONFIG.md in\n"); print("the root of the Limine source repository.\n\n"); print("Press a key to enter the Limine console..."); - term->double_buffer_flush(term); + FOR_TERM(TERM->double_buffer_flush(TERM)); getchar(); reset_term(); console(); @@ -761,10 +761,10 @@ refresh: { // Draw box around boot menu size_t x, y; - term->get_cursor_pos(term, &x, &y); + terms[0]->get_cursor_pos(terms[0], &x, &y); print(serial ? "/" : "\xda"); - for (size_t i = 0; i < term->cols - 2; i++) { + for (size_t i = 0; i < terms[0]->cols - 2; i++) { switch (i) { case 1: case 2: case 3: if (tree_offset > 0) { @@ -777,16 +777,16 @@ refresh: } print(serial ? "\\" : "\xbf"); - for (size_t i = y + 1; i < term->rows - 2; i++) { + for (size_t i = y + 1; i < terms[0]->rows - 2; i++) { set_cursor_pos_helper(0, i); print(serial ? "|" : "\xb3"); - set_cursor_pos_helper(term->cols - 1, i); + set_cursor_pos_helper(terms[0]->cols - 1, i); print(serial ? "|" : "\xb3"); } - set_cursor_pos_helper(0, term->rows - 2); + set_cursor_pos_helper(0, terms[0]->rows - 2); print(serial ? "\\" : "\xc0"); - for (size_t i = 0; i < term->cols - 2; i++) { + for (size_t i = 0; i < terms[0]->cols - 2; i++) { print(serial ? "-" : "\xc4"); } print(serial ? "/" : "\xd9"); @@ -794,15 +794,15 @@ refresh: set_cursor_pos_helper(x, y + 2); } - size_t max_entries = print_tree(tree_offset, term->rows - 10, serial ? "| " : "\xb3 ", 0, 0, selected_entry, menu_tree, + size_t max_entries = print_tree(tree_offset, terms[0]->rows - 10, serial ? "| " : "\xb3 ", 0, 0, selected_entry, menu_tree, &selected_menu_entry); { size_t x, y; - term->get_cursor_pos(term, &x, &y); + terms[0]->get_cursor_pos(terms[0], &x, &y); - if (tree_offset + (term->rows - 10) < max_entries) { - set_cursor_pos_helper(2, term->rows - 2); + if (tree_offset + (terms[0]->rows - 10) < max_entries) { + set_cursor_pos_helper(2, terms[0]->rows - 2); print(serial ? "vvv" : "\x19\x19\x19"); } @@ -813,7 +813,7 @@ refresh: print(" \e[32mARROWS\e[0m Select \e[32mENTER\e[0m %s", selected_menu_entry->expanded ? "Collapse" : "Expand"); } - set_cursor_pos_helper(term->cols - 13, 3); + set_cursor_pos_helper(terms[0]->cols - 13, 3); print("\e[32mC\e[0m Console"); set_cursor_pos_helper(x, y); } @@ -826,11 +826,11 @@ refresh: if (skip_timeout == false) { print("\n\n"); for (size_t i = timeout; i; i--) { - set_cursor_pos_helper(0, term->rows - 1); - term->scroll_enabled = false; + set_cursor_pos_helper(0, terms[0]->rows - 1); + FOR_TERM(TERM->scroll_enabled = false); print("\e[2K\e[32mBooting automatically in \e[92m%u\e[32m, press any key to stop the countdown...\e[0m", i); - term->scroll_enabled = true; - term->double_buffer_flush(term); + FOR_TERM(TERM->scroll_enabled = true); + FOR_TERM(TERM->double_buffer_flush(TERM)); if ((c = pit_sleep_and_quit_on_keypress(1))) { skip_timeout = true; if (quiet) { @@ -839,21 +839,21 @@ refresh: goto timeout_aborted; } print("\e[2K"); - term->double_buffer_flush(term); + FOR_TERM(TERM->double_buffer_flush(TERM)); goto timeout_aborted; } } goto autoboot; } - set_cursor_pos_helper(0, term->rows - 1); + set_cursor_pos_helper(0, terms[0]->rows - 1); if (selected_menu_entry->comment != NULL) { - term->scroll_enabled = false; + FOR_TERM(TERM->scroll_enabled = false); print("\e[36m%s\e[0m", selected_menu_entry->comment); - term->scroll_enabled = true; + FOR_TERM(TERM->scroll_enabled = true); } - term->double_buffer_flush(term); + FOR_TERM(TERM->double_buffer_flush(TERM)); for (;;) { c = getchar(); @@ -896,7 +896,7 @@ timeout_aborted: } if (!quiet) { if (term_backend == FALLBACK) { - if (!gterm_init(NULL, 0, 0)) { + if (!gterm_init(NULL, NULL, NULL, 0, 0)) { #if defined (BIOS) vga_textmode_init(true); #elif defined (UEFI) diff --git a/common/protos/chainload.c b/common/protos/chainload.c index 24aa695b..3d4ddbdf 100644 --- a/common/protos/chainload.c +++ b/common/protos/chainload.c @@ -216,10 +216,7 @@ noreturn void efi_chainload_file(char *config, struct file_handle *image) { pmm_free(_ptr, image->size); fclose(image); - if (term != NULL) { - term->deinit(term, pmm_free); - term = NULL; - } + term_notready(); size_t req_width = 0, req_height = 0, req_bpp = 0; @@ -227,9 +224,9 @@ noreturn void efi_chainload_file(char *config, struct file_handle *image) { if (resolution != NULL) parse_resolution(&req_width, &req_height, &req_bpp, resolution); - struct fb_info fbinfo; - if (!fb_init(&fbinfo, req_width, req_height, req_bpp)) - panic(true, "chainload: Unable to set video mode"); + struct fb_info *fbinfo; + size_t fb_count; + fb_init(&fbinfo, &fb_count, req_width, req_height, req_bpp); pmm_release_uefi_mem(); diff --git a/common/protos/limine.c b/common/protos/limine.c index 5009564d..36992b2e 100644 --- a/common/protos/limine.c +++ b/common/protos/limine.c @@ -275,9 +275,10 @@ static void callback_shim(struct term_context *ctx, uint64_t a, uint64_t b, uint actual_callback(term_arg, a, b, c, d); } +// TODO pair with specific terminal static void term_write_shim(uint64_t context, uint64_t buf, uint64_t count) { (void)context; - _term_write(buf, count); + _term_write(terms[0], buf, count); } noreturn void limine_load(char *config, char *cmdline) { @@ -670,10 +671,11 @@ FEAT_END parse_resolution(&req_width, &req_height, &req_bpp, resolution); } - struct fb_info fb; - uint64_t *term_fb_ptr = NULL; + struct fb_info *fbs; + size_t fbs_count; + // Terminal feature FEAT_START struct limine_terminal_request *terminal_request = get_request(LIMINE_TERMINAL_REQUEST); @@ -691,11 +693,11 @@ FEAT_START char *term_conf_override_s = config_get_value(config, 0, "TERM_CONFIG_OVERRIDE"); if (term_conf_override_s != NULL && strcmp(term_conf_override_s, "yes") == 0) { - if (!gterm_init(config, req_width, req_height)) { + if (!gterm_init(&fbs, &fbs_count, config, req_width, req_height)) { goto term_fail; } } else { - if (!gterm_init(NULL, req_width, req_height)) { + if (!gterm_init(&fbs, &fbs_count, NULL, req_width, req_height)) { goto term_fail; } } @@ -707,10 +709,8 @@ term_fail: break; // next feature } - fb = fbinfo; - if (terminal_request->callback != 0) { - term->callback = callback_shim; + terms[0]->callback = callback_shim; #if defined (__i386__) actual_callback = (void *)limine_term_callback; @@ -739,8 +739,8 @@ term_fail: term_fb_ptr = &terminal->framebuffer; - terminal->columns = term->cols; - terminal->rows = term->rows; + terminal->columns = terms[0]->cols; + terminal->rows = terms[0]->rows; uint64_t *term_list = ext_mem_alloc(1 * sizeof(uint64_t)); term_list[0] = reported_addr(terminal); @@ -753,27 +753,26 @@ term_fail: goto skip_fb_init; FEAT_END - if (term != NULL) { - term->deinit(term, pmm_free); - term = NULL; - } + term_notready(); - if (!fb_init(&fb, req_width, req_height, req_bpp)) { + fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp); + if (fbs_count == 0) { goto no_fb; } skip_fb_init: - memmap_alloc_range(fb.framebuffer_addr, - (uint64_t)fb.framebuffer_pitch * fb.framebuffer_height, - MEMMAP_FRAMEBUFFER, 0, false, false, true); + for (size_t i = 0; i < fbs_count; i++) { + memmap_alloc_range(fbs[i].framebuffer_addr, + (uint64_t)fbs[i].framebuffer_pitch * fbs[i].framebuffer_height, + MEMMAP_FRAMEBUFFER, 0, false, false, true); + } // Framebuffer feature FEAT_START - // For now we only support 1 framebuffer - struct limine_framebuffer *fbp = ext_mem_alloc(sizeof(struct limine_framebuffer)); + struct limine_framebuffer *fbp = ext_mem_alloc(fbs_count * sizeof(struct limine_framebuffer)); if (term_fb_ptr != NULL) { - *term_fb_ptr = reported_addr(fbp); + *term_fb_ptr = reported_addr(&fbp[0]); } struct limine_framebuffer_request *framebuffer_request = get_request(LIMINE_FRAMEBUFFER_REQUEST); @@ -784,43 +783,41 @@ FEAT_START struct limine_framebuffer_response *framebuffer_response = ext_mem_alloc(sizeof(struct limine_framebuffer_response)); - struct edid_info_struct *edid_info = get_edid_info(); - if (edid_info != NULL) { - fbp->edid_size = sizeof(struct edid_info_struct); - fbp->edid = reported_addr(edid_info); - } - framebuffer_response->revision = 1; - size_t modes_count; - struct fb_info *modes = fb_get_mode_list(&modes_count); - if (modes != NULL) { - uint64_t *modes_list = ext_mem_alloc(modes_count * sizeof(uint64_t)); - for (size_t i = 0; i < modes_count; i++) { - modes[i].memory_model = LIMINE_FRAMEBUFFER_RGB; - modes_list[i] = reported_addr(&modes[i]); + uint64_t *fb_list = ext_mem_alloc(fbs_count * sizeof(uint64_t)); + + for (size_t i = 0; i < fbs_count; i++) { + uint64_t *modes_list = ext_mem_alloc(fbs[i].mode_count * sizeof(uint64_t)); + for (size_t j = 0; j < fbs[i].mode_count; j++) { + fbs[i].mode_list[j].memory_model = LIMINE_FRAMEBUFFER_RGB; + modes_list[j] = reported_addr(&fbs[i].mode_list[j]); } - fbp->modes = reported_addr(modes_list); - fbp->mode_count = modes_count; + fbp[i].modes = reported_addr(modes_list); + fbp[i].mode_count = fbs[i].mode_count; + + if (fbs[i].edid != NULL) { + fbp[i].edid_size = sizeof(struct edid_info_struct); + fbp[i].edid = reported_addr(fbs[i].edid); + } + + fbp[i].memory_model = LIMINE_FRAMEBUFFER_RGB; + fbp[i].address = reported_addr((void *)(uintptr_t)fbs[i].framebuffer_addr); + fbp[i].width = fbs[i].framebuffer_width; + fbp[i].height = fbs[i].framebuffer_height; + fbp[i].bpp = fbs[i].framebuffer_bpp; + fbp[i].pitch = fbs[i].framebuffer_pitch; + fbp[i].red_mask_size = fbs[i].red_mask_size; + fbp[i].red_mask_shift = fbs[i].red_mask_shift; + fbp[i].green_mask_size = fbs[i].green_mask_size; + fbp[i].green_mask_shift = fbs[i].green_mask_shift; + fbp[i].blue_mask_size = fbs[i].blue_mask_size; + fbp[i].blue_mask_shift = fbs[i].blue_mask_shift; + + fb_list[i] = reported_addr(&fbp[i]); } - fbp->memory_model = LIMINE_FRAMEBUFFER_RGB; - fbp->address = reported_addr((void *)(uintptr_t)fb.framebuffer_addr); - fbp->width = fb.framebuffer_width; - fbp->height = fb.framebuffer_height; - fbp->bpp = fb.framebuffer_bpp; - fbp->pitch = fb.framebuffer_pitch; - fbp->red_mask_size = fb.red_mask_size; - fbp->red_mask_shift = fb.red_mask_shift; - fbp->green_mask_size = fb.green_mask_size; - fbp->green_mask_shift = fb.green_mask_shift; - fbp->blue_mask_size = fb.blue_mask_size; - fbp->blue_mask_shift = fb.blue_mask_shift; - - uint64_t *fb_list = ext_mem_alloc(1 * sizeof(uint64_t)); - fb_list[0] = reported_addr(fbp); - - framebuffer_response->framebuffer_count = 1; + framebuffer_response->framebuffer_count = fbs_count; framebuffer_response->framebuffers = reported_addr(fb_list); framebuffer_request->response = reported_addr(framebuffer_response); @@ -1029,10 +1026,8 @@ FEAT_START FEAT_END // Clear terminal for kernels that will use the Limine terminal - if (term != NULL) { - term_write(term, "\e[2J\e[H", 7); - term->in_bootloader = false; - } + FOR_TERM(term_write(TERM, "\e[2J\e[H", 7)); + FOR_TERM(TERM->in_bootloader = false); #if defined (__x86_64__) || defined (__i386__) #if defined (BIOS) diff --git a/common/protos/linux.c b/common/protos/linux.c index 6e46b13f..5ae70b99 100644 --- a/common/protos/linux.c +++ b/common/protos/linux.c @@ -495,10 +495,7 @@ noreturn void linux_load(char *config, char *cmdline) { // Video /////////////////////////////////////// - if (term != NULL) { - term->deinit(term, pmm_free); - term = NULL; - } + term_notready(); struct screen_info *screen_info = &boot_params->screen_info; @@ -518,11 +515,13 @@ noreturn void linux_load(char *config, char *cmdline) { if (resolution != NULL) parse_resolution(&req_width, &req_height, &req_bpp, resolution); - struct fb_info fbinfo; + struct fb_info *fbs; + size_t fbs_count; #if defined (UEFI) gop_force_16 = true; #endif - if (!fb_init(&fbinfo, req_width, req_height, req_bpp)) { + fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp); + if (fbs_count == 0) { #if defined (UEFI) goto no_fb; #elif defined (BIOS) @@ -531,8 +530,8 @@ set_textmode:; screen_info->orig_video_mode = 3; screen_info->orig_video_ega_bx = 3; - screen_info->orig_video_lines = term->rows; - screen_info->orig_video_cols = term->cols; + screen_info->orig_video_lines = 25; + screen_info->orig_video_cols = 80; screen_info->orig_video_points = 16; screen_info->orig_video_isVGA = VIDEO_TYPE_VGAC; @@ -540,19 +539,23 @@ set_textmode:; } else { screen_info->capabilities = VIDEO_CAPABILITY_64BIT_BASE | VIDEO_CAPABILITY_SKIP_QUIRKS; screen_info->flags = VIDEO_FLAGS_NOCURSOR; - screen_info->lfb_base = (uint32_t)fbinfo.framebuffer_addr; - screen_info->ext_lfb_base = (uint32_t)(fbinfo.framebuffer_addr >> 32); - screen_info->lfb_size = fbinfo.framebuffer_pitch * fbinfo.framebuffer_height; - screen_info->lfb_width = fbinfo.framebuffer_width; - screen_info->lfb_height = fbinfo.framebuffer_height; - screen_info->lfb_depth = fbinfo.framebuffer_bpp; - screen_info->lfb_linelength = fbinfo.framebuffer_pitch; - screen_info->red_size = fbinfo.red_mask_size; - screen_info->red_pos = fbinfo.red_mask_shift; - screen_info->green_size = fbinfo.green_mask_size; - screen_info->green_pos = fbinfo.green_mask_shift; - screen_info->blue_size = fbinfo.blue_mask_size; - screen_info->blue_pos = fbinfo.blue_mask_shift; + screen_info->lfb_base = (uint32_t)fbs[0].framebuffer_addr; + screen_info->ext_lfb_base = (uint32_t)(fbs[0].framebuffer_addr >> 32); + screen_info->lfb_size = fbs[0].framebuffer_pitch * fbs[0].framebuffer_height; + screen_info->lfb_width = fbs[0].framebuffer_width; + screen_info->lfb_height = fbs[0].framebuffer_height; + screen_info->lfb_depth = fbs[0].framebuffer_bpp; + screen_info->lfb_linelength = fbs[0].framebuffer_pitch; + screen_info->red_size = fbs[0].red_mask_size; + screen_info->red_pos = fbs[0].red_mask_shift; + screen_info->green_size = fbs[0].green_mask_size; + screen_info->green_pos = fbs[0].green_mask_shift; + screen_info->blue_size = fbs[0].blue_mask_size; + screen_info->blue_pos = fbs[0].blue_mask_shift; + + if (fbs[0].edid != NULL) { + memcpy(&boot_params->edid_info, fbs[0].edid, sizeof(struct edid_info_struct)); + } #if defined (BIOS) screen_info->orig_video_isVGA = VIDEO_TYPE_VLFB; @@ -564,12 +567,6 @@ set_textmode:; #if defined (UEFI) no_fb:; #endif - struct edid_info_struct *edid_info = get_edid_info(); - - if (edid_info != NULL) { - memcpy(&boot_params->edid_info, edid_info, sizeof(struct edid_info_struct)); - } - /////////////////////////////////////// // RSDP /////////////////////////////////////// diff --git a/common/protos/multiboot1.c b/common/protos/multiboot1.c index 1d7c6929..808cd657 100644 --- a/common/protos/multiboot1.c +++ b/common/protos/multiboot1.c @@ -302,77 +302,62 @@ noreturn void multiboot1_load(char *config, char *cmdline) { multiboot1_info->bootloader_name = (uint32_t)(size_t)lowmem_bootname - mb1_info_slide; multiboot1_info->flags |= (1 << 9); - if (term != NULL) { - term->deinit(term, pmm_free); - term = NULL; - } + term_notready(); + + size_t req_width = 0; + size_t req_height = 0; + size_t req_bpp = 0; if (header.flags & (1 << 2)) { - size_t req_width = header.fb_width; - size_t req_height = header.fb_height; - size_t req_bpp = header.fb_bpp; + req_width = header.fb_width; + req_height = header.fb_height; + req_bpp = header.fb_bpp; if (header.fb_mode == 0) { +#if defined (UEFI) +modeset:; +#endif char *resolution = config_get_value(config, 0, "RESOLUTION"); if (resolution != NULL) parse_resolution(&req_width, &req_height, &req_bpp, resolution); - struct fb_info fbinfo; - if (!fb_init(&fbinfo, req_width, req_height, req_bpp)) { + struct fb_info *fbs; + size_t fbs_count; + fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp); + if (fbs_count == 0) { #if defined (UEFI) goto skip_modeset; #elif defined (BIOS) +textmode: vga_textmode_init(false); multiboot1_info->fb_addr = 0xb8000; - multiboot1_info->fb_width = term->cols; - multiboot1_info->fb_height = term->rows; + multiboot1_info->fb_width = 80; + multiboot1_info->fb_height = 25; multiboot1_info->fb_bpp = 16; - multiboot1_info->fb_pitch = 2 * term->cols; + multiboot1_info->fb_pitch = 2 * 80; multiboot1_info->fb_type = 2; #endif } else { - multiboot1_info->fb_addr = (uint64_t)fbinfo.framebuffer_addr; - multiboot1_info->fb_width = fbinfo.framebuffer_width; - multiboot1_info->fb_height = fbinfo.framebuffer_height; - multiboot1_info->fb_bpp = fbinfo.framebuffer_bpp; - multiboot1_info->fb_pitch = fbinfo.framebuffer_pitch; + multiboot1_info->fb_addr = (uint64_t)fbs[0].framebuffer_addr; + multiboot1_info->fb_width = fbs[0].framebuffer_width; + multiboot1_info->fb_height = fbs[0].framebuffer_height; + multiboot1_info->fb_bpp = fbs[0].framebuffer_bpp; + multiboot1_info->fb_pitch = fbs[0].framebuffer_pitch; multiboot1_info->fb_type = 1; - multiboot1_info->fb_red_mask_size = fbinfo.red_mask_size; - multiboot1_info->fb_red_mask_shift = fbinfo.red_mask_shift; - multiboot1_info->fb_green_mask_size = fbinfo.green_mask_size; - multiboot1_info->fb_green_mask_shift = fbinfo.green_mask_shift; - multiboot1_info->fb_blue_mask_size = fbinfo.blue_mask_size; - multiboot1_info->fb_blue_mask_shift = fbinfo.blue_mask_shift; + multiboot1_info->fb_red_mask_size = fbs[0].red_mask_size; + multiboot1_info->fb_red_mask_shift = fbs[0].red_mask_shift; + multiboot1_info->fb_green_mask_size = fbs[0].green_mask_size; + multiboot1_info->fb_green_mask_shift = fbs[0].green_mask_shift; + multiboot1_info->fb_blue_mask_size = fbs[0].blue_mask_size; + multiboot1_info->fb_blue_mask_shift = fbs[0].blue_mask_shift; } } else { #if defined (UEFI) print("multiboot1: Warning: Cannot use text mode with UEFI\n"); - struct fb_info fbinfo; - if (!fb_init(&fbinfo, 0, 0, 0)) { - goto skip_modeset; - } - multiboot1_info->fb_addr = (uint64_t)fbinfo.framebuffer_addr; - multiboot1_info->fb_width = fbinfo.framebuffer_width; - multiboot1_info->fb_height = fbinfo.framebuffer_height; - multiboot1_info->fb_bpp = fbinfo.framebuffer_bpp; - multiboot1_info->fb_pitch = fbinfo.framebuffer_pitch; - multiboot1_info->fb_type = 1; - multiboot1_info->fb_red_mask_size = fbinfo.red_mask_size; - multiboot1_info->fb_red_mask_shift = fbinfo.red_mask_shift; - multiboot1_info->fb_green_mask_size = fbinfo.green_mask_size; - multiboot1_info->fb_green_mask_shift = fbinfo.green_mask_shift; - multiboot1_info->fb_blue_mask_size = fbinfo.blue_mask_size; - multiboot1_info->fb_blue_mask_shift = fbinfo.blue_mask_shift; + goto modeset; #elif defined (BIOS) - vga_textmode_init(false); - - multiboot1_info->fb_addr = 0xb8000; - multiboot1_info->fb_width = term->cols; - multiboot1_info->fb_height = term->rows; - multiboot1_info->fb_bpp = 16; - multiboot1_info->fb_pitch = 2 * term->cols; - multiboot1_info->fb_type = 2; + goto textmode; #endif } diff --git a/common/protos/multiboot2.c b/common/protos/multiboot2.c index 3139ccca..83b02656 100644 --- a/common/protos/multiboot2.c +++ b/common/protos/multiboot2.c @@ -516,29 +516,36 @@ noreturn void multiboot2_load(char *config, char* cmdline) { tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; tag->common.size = sizeof(struct multiboot_tag_framebuffer); - if (term != NULL) { - term->deinit(term, pmm_free); - term = NULL; - } + term_notready(); + + size_t req_width = 0; + size_t req_height = 0; + size_t req_bpp = 0; if (fbtag) { - size_t req_width = fbtag->width; - size_t req_height = fbtag->height; - size_t req_bpp = fbtag->depth; + req_width = fbtag->width; + req_height = fbtag->height; + req_bpp = fbtag->depth; +#if defined (UEFI) +modeset:; +#endif char *resolution = config_get_value(config, 0, "RESOLUTION"); if (resolution != NULL) parse_resolution(&req_width, &req_height, &req_bpp, resolution); - struct fb_info fbinfo; - if (!fb_init(&fbinfo, req_width, req_height, req_bpp)) { + struct fb_info *fbs; + size_t fbs_count; + fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp); + if (fbs_count == 0) { #if defined (BIOS) +textmode: vga_textmode_init(false); tag->common.framebuffer_addr = 0xb8000; - tag->common.framebuffer_pitch = 2 * term->cols; - tag->common.framebuffer_width = term->cols; - tag->common.framebuffer_height = term->rows; + tag->common.framebuffer_pitch = 2 * 80; + tag->common.framebuffer_width = 80; + tag->common.framebuffer_height = 25; tag->common.framebuffer_bpp = 16; tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT; #elif defined (UEFI) @@ -549,54 +556,26 @@ noreturn void multiboot2_load(char *config, char* cmdline) { } #endif } else { - tag->common.framebuffer_addr = fbinfo.framebuffer_addr; - tag->common.framebuffer_pitch = fbinfo.framebuffer_pitch; - tag->common.framebuffer_width = fbinfo.framebuffer_width; - tag->common.framebuffer_height = fbinfo.framebuffer_height; - tag->common.framebuffer_bpp = fbinfo.framebuffer_bpp; + tag->common.framebuffer_addr = fbs[0].framebuffer_addr; + tag->common.framebuffer_pitch = fbs[0].framebuffer_pitch; + tag->common.framebuffer_width = fbs[0].framebuffer_width; + tag->common.framebuffer_height = fbs[0].framebuffer_height; + tag->common.framebuffer_bpp = fbs[0].framebuffer_bpp; tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB; // We only support RGB for VBE - tag->framebuffer_red_field_position = fbinfo.red_mask_shift; - tag->framebuffer_red_mask_size = fbinfo.red_mask_size; - tag->framebuffer_green_field_position = fbinfo.green_mask_shift; - tag->framebuffer_green_mask_size = fbinfo.green_mask_size; - tag->framebuffer_blue_field_position = fbinfo.blue_mask_shift; - tag->framebuffer_blue_mask_size = fbinfo.blue_mask_size; + tag->framebuffer_red_field_position = fbs[0].red_mask_shift; + tag->framebuffer_red_mask_size = fbs[0].red_mask_size; + tag->framebuffer_green_field_position = fbs[0].green_mask_shift; + tag->framebuffer_green_mask_size = fbs[0].green_mask_size; + tag->framebuffer_blue_field_position = fbs[0].blue_mask_shift; + tag->framebuffer_blue_mask_size = fbs[0].blue_mask_size; } } else { #if defined (UEFI) print("multiboot2: Warning: Cannot use text mode with UEFI\n"); - struct fb_info fbinfo; - if (!fb_init(&fbinfo, 0, 0, 0)) { - if (is_framebuffer_required) { - panic(true, "multiboot2: Failed to set video mode"); - } else { - goto skip_modeset; - } - } - - tag->common.framebuffer_addr = fbinfo.framebuffer_addr; - tag->common.framebuffer_pitch = fbinfo.framebuffer_pitch; - tag->common.framebuffer_width = fbinfo.framebuffer_width; - tag->common.framebuffer_height = fbinfo.framebuffer_height; - tag->common.framebuffer_bpp = fbinfo.framebuffer_bpp; - tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB; // We only support RGB for VBE - - tag->framebuffer_red_field_position = fbinfo.red_mask_shift; - tag->framebuffer_red_mask_size = fbinfo.red_mask_size; - tag->framebuffer_green_field_position = fbinfo.green_mask_shift; - tag->framebuffer_green_mask_size = fbinfo.green_mask_size; - tag->framebuffer_blue_field_position = fbinfo.blue_mask_shift; - tag->framebuffer_blue_mask_size = fbinfo.blue_mask_size; + goto modeset; #elif defined (BIOS) - vga_textmode_init(false); - - tag->common.framebuffer_addr = 0xb8000; - tag->common.framebuffer_width = term->cols; - tag->common.framebuffer_height = term->rows; - tag->common.framebuffer_bpp = 16; - tag->common.framebuffer_pitch = 2 * term->cols; - tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT; + goto textmode; #endif }