misc: Backport multiple framebuffer support from trunk
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 <efi.h>
-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 <efi.h>
+
+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..c970efa1 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;
- }
-
- gop_handle = handles[0];
- pmm_free(handles, handles_size);
-
- status = gBS->HandleProtocol(gop_handle, &gop_guid, (void **)&gop);
- if (status != EFI_SUCCESS) {
- return false;
+ *_fbs_count = 0;
+ return;
}
- gop_ready = true;
+ size_t handles_count = handles_size / sizeof(EFI_HANDLE);
- 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;
- }
+ *ret = ext_mem_alloc(handles_count * sizeof(struct fb_info));
- 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,113 @@ 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;
+ 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;
+ }
}
- }
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;
+ if (current_fallback == 0) {
+ current_fallback++;
+
+ 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 (current_fallback == 1) {
+ current_fallback++;
- if (try_mode(ret, preset_mode, 0, 0, 0)) {
- gop_force_16 = false;
- return true;
+ 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;
}
- }
- if (current_fallback < SIZEOF_ARRAY(fallback_resolutions)) {
- current_fallback++;
+ continue;
- target_width = fallback_resolutions[current_fallback].width;
- target_height = fallback_resolutions[current_fallback].height;
- target_bpp = fallback_resolutions[current_fallback].bpp;
- goto retry;
+success:;
+ size_t mode_count;
+ fb->mode_list = get_mode_list(&mode_count, gop);
+ fb->mode_count = mode_count;
+
+ fbs_count++;
}
+ 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 <stdint.h>
#include <stddef.h>
#include <stdbool.h>
-#include <efi.h>
#include <lib/fb.h>
-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 eeab80ee..d49007e2 100644
--- a/common/drivers/vga_textmode.c
+++ b/common/drivers/vga_textmode.c
@@ -244,15 +244,12 @@ static void text_deinit(struct term_context *_ctx, void (*_free)(void *, size_t)
_free(ctx->front_buffer, VD_ROWS * VD_COLS);
ctx->front_buffer = NULL;
}
-}
-static struct textmode_context term_local_struct;
+ pmm_free(ctx, sizeof(struct textmode_context));
+}
void vga_textmode_init(bool managed) {
- if (term != NULL) {
- term->deinit(term, pmm_free);
- term = NULL;
- }
+ term_notready();
if (quiet) {
return;
@@ -266,8 +263,13 @@ void vga_textmode_init(bool managed) {
current_video_mode = 0x3;
}
- struct textmode_context *ctx = &term_local_struct;
- term = &term_local_struct.term;
+ terms = ext_mem_alloc(sizeof(void *));
+ terms_i = 1;
+
+ terms[0] = ext_mem_alloc(sizeof(struct textmode_context));
+
+ struct term_context *term = terms[0];
+ struct textmode_context *ctx = (void *)term;
if (ctx->back_buffer == NULL) {
ctx->back_buffer = ext_mem_alloc(VD_ROWS * VD_COLS);
diff --git a/common/entry.s3.c b/common/entry.s3.c
index 28f0ff6a..a4a0bb27 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
@@ -130,5 +130,7 @@ noreturn void stage3_common(void) {
init_io_apics();
#endif
+ term_notready();
+
menu(true);
}
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 <drivers/gop.h>
#include <mm/pmm.h>
-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 <stdint.h>
#include <stddef.h>
+#include <drivers/edid.h>
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;
-
- bool default_res;
+ 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;
+
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 4d288702..ec3b7e7f 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;
@@ -390,10 +388,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;
@@ -428,7 +426,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;
@@ -437,10 +435,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
}
@@ -451,10 +449,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;
}
}
@@ -463,7 +461,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;
}
}
@@ -474,15 +472,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;
}
@@ -491,17 +489,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;
@@ -510,99 +508,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;
- }
+ term_notready();
- 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;
- }
+ // We force bpp to 32
+ fb_init(&fbs, &fbs_count, width, height, 32);
- if (term != NULL) {
- term->deinit(term, pmm_free);
- term = NULL;
+ if (_fbs != NULL) {
+ *_fbs = fbs;
}
-
- // We force bpp to 32
- if (!fb_init(&fbinfo, width, height, 32)) {
- return false;
+ 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;
@@ -716,20 +691,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;
@@ -789,38 +750,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,
- &default_bg_bright, &default_fg_bright,
- 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,
+ &default_bg_bright, &default_fg_bright,
+ 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;
+ }
+ }
+
+ size_t min_cols = (size_t)-1;
+ size_t min_rows = (size_t)-1;
+
+ 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;
+ }
}
- term->in_bootloader = true;
+ for (size_t i = 0; i < terms_i; i++) {
+ struct term_context *term = terms[i];
+
+ term->cols = min_cols;
+ term->rows = min_rows;
- term_context_reinit(term);
+ term->in_bootloader = true;
+
+ term_context_reinit(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 <stdbool.h>
#include <lib/fb.h>
-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/panic.s2.c b/common/lib/panic.s2.c
index 901e968b..23634504 100644
--- a/common/lib/panic.s2.c
+++ b/common/lib/panic.s2.c
@@ -54,6 +54,9 @@ noreturn void panic(bool allow_menu, const char *fmt, ...) {
getchar();
+ // This fixes a crash
+ term_notready();
+
menu(false);
/*
fb_clear(&fbinfo);
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 6f9f91e6..1a03d9dc 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->cursor_enabled = false;
- term->get_cursor_pos(term, &orig_x, &orig_y);
+ FOR_TERM(TERM->cursor_enabled = false);
+ 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->cursor_enabled = true;
+ FOR_TERM(TERM->cursor_enabled = true);
}
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("\n\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 e0d802e5..66a23f3f 100644
--- a/common/lib/term.c
+++ b/common/lib/term.c
@@ -8,89 +8,28 @@
#include <drivers/vga_textmode.h>
#include <term/backends/framebuffer.h>
+#if defined (BIOS)
int current_video_mode = -1;
-int term_backend = _NOT_READY;
+#endif
-struct term_context *term;
+struct term_context **terms = NULL;
+size_t terms_i = 0;
-static struct term_context term_local_struct;
+int term_backend = _NOT_READY;
-// --- notready ---
+void term_notready(void) {
+ for (size_t i = 0; i < terms_i; i++) {
+ struct term_context *term = terms[i];
-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 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;
-
- term->raw_putchar = notready_raw_putchar;
- term->clear = notready_clear;
- 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;
+ pmm_free(terms, terms_i * sizeof(void *));
- term_backend = _NOT_READY;
- term_context_reinit(term);
+ terms_i = 0;
+ terms = NULL;
- term->in_bootloader = true;
+ term_backend = _NOT_READY;
}
// --- fallback ---
@@ -156,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);
}
@@ -167,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;
@@ -176,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);
@@ -184,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--;
}
}
@@ -204,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);
@@ -219,13 +158,43 @@ 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->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;
@@ -258,7 +227,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:
@@ -279,7 +248,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: {
@@ -314,7 +283,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: {
@@ -349,7 +318,7 @@ 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_OOB_OUTPUT_GET: {
memcpy32to64(buf, (uint64_t)(uintptr_t)&term->oob_output, sizeof(uint64_t));
@@ -360,16 +329,16 @@ void _term_write(uint64_t buf, uint64_t count) {
return;
}
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 d9bc2553..d0cbd5b4 100644
--- a/common/lib/term.h
+++ b/common/lib/term.h
@@ -13,10 +13,14 @@ 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))
@@ -25,18 +29,32 @@ extern struct term_context *term;
#define TERM_OOB_OUTPUT_GET ((uint64_t)(-10))
#define TERM_OOB_OUTPUT_SET ((uint64_t)(-11))
+#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->cursor_enabled = true;;
- 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->cursor_enabled = true;
+ 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..882be123 100644
--- a/common/linker_bios.ld.in
+++ b/common/linker_bios.ld.in
@@ -43,7 +43,9 @@ SECTIONS
term_write = .;
term_backend = .;
term_fallback = .;
- term = .;
+ term_notready = .;
+ terms = .;
+ terms_i = .;
stage3_addr = .;
#else
#ifdef LINKER_NOS2MAP
diff --git a/common/menu.c b/common/menu.c
index 60a40d1e..f4040d45 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->cursor_enabled = true;
+ FOR_TERM(TERM->cursor_enabled = true);
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->cursor_enabled = false;
+ FOR_TERM(TERM->cursor_enabled = false);
{
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->cursor_enabled = true;
+ FOR_TERM(TERM->cursor_enabled = true);
- 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)
@@ -625,10 +625,6 @@ noreturn void _menu(bool first_run) {
#endif
}
- if (!first_run) {
- term_fallback();
- }
-
if (bad_config == false) {
#if defined (UEFI)
if (init_config_disk(boot_volume)) {
@@ -721,23 +717,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->cursor_enabled = false;
+ FOR_TERM(TERM->cursor_enabled = false);
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 +742,14 @@ refresh:
if (quiet) {
quiet = false;
menu_init_term();
- term->autoflush = false;
- term->cursor_enabled = false;
+ FOR_TERM(TERM->autoflush = false);
+ FOR_TERM(TERM->cursor_enabled = false);
}
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 +757,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 +773,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 +790,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 +809,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 +822,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 +835,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 +892,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 c1066dfa..5e0040dd 100644
--- a/common/protos/chainload.c
+++ b/common/protos/chainload.c
@@ -218,10 +218,7 @@ noreturn void efi_chainload_file(char *config, char *cmdline, struct file_handle
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;
@@ -229,9 +226,9 @@ noreturn void efi_chainload_file(char *config, char *cmdline, struct file_handle
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);
size_t cmdline_len = strlen(cmdline);
CHAR16 *new_cmdline;
diff --git a/common/protos/limine.c b/common/protos/limine.c
index 6aee412d..1163cfa7 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -278,9 +278,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) {
@@ -673,10 +674,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);
@@ -696,11 +698,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;
}
}
@@ -712,10 +714,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;
@@ -744,8 +744,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);
@@ -758,27 +758,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);
@@ -789,43 +788,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[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->modes = reported_addr(modes_list);
- fbp->mode_count = modes_count;
+
+ 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);
@@ -860,18 +857,21 @@ FEAT_END
#endif
#if defined (__aarch64__)
- uint64_t fb_attr = 0x00;
- if (fb.framebuffer_addr) {
+ // Find the most restrictive caching mode from all framebuffers to use
+ uint64_t fb_attr = (uint64_t)-1;
+
+ for (size_t i = 0; i < fbs_count; i++) {
int el = current_el();
uint64_t res;
+ // Figure out the caching mode used for this particular framebuffer
if (el == 1) {
asm volatile (
"at s1e1w, %1\n\t"
"isb\n\t"
"mrs %0, par_el1"
: "=r"(res)
- : "r"(fb.framebuffer_addr)
+ : "r"(fbs[i].framebuffer_addr)
: "memory");
} else if (el == 2) {
asm volatile (
@@ -879,7 +879,7 @@ FEAT_END
"isb\n\t"
"mrs %0, par_el1"
: "=r"(res)
- : "r"(fb.framebuffer_addr)
+ : "r"(fbs[i].framebuffer_addr)
: "memory");
} else {
panic(false, "Unexpected EL in limine_load");
@@ -888,8 +888,26 @@ FEAT_END
if (res & 1)
panic(false, "Address translation for framebuffer failed");
- fb_attr = res >> 56;
+ uint64_t new_attr = res >> 56;
+
+ // Use whatever we find first
+ if (fb_attr == (uint64_t)-1)
+ fb_attr = new_attr;
+ // Prefer Device memory over Normal memory
+ else if ((fb_attr & 0b11110000) && !(new_attr & 0b11110000))
+ fb_attr = new_attr;
+ // Prefer tighter Device memory (lower values)
+ else if (!(fb_attr & 0b11110000) && !(new_attr & 0b11110000) && fb_attr > new_attr)
+ fb_attr = new_attr;
+ // Use Normal non-cacheable otherwise (avoid trying to figure out how to downgrade inner vs outer).
+ else if ((fb_attr & 0b11110000) && (new_attr & 0b11110000))
+ fb_attr = 0b01000100; // Inner&outer Non-cacheable
+ // Otherwise do nothing (fb_attr is already more restrictive than new_attr).
}
+
+ // If no framebuffers are found, just zero out the MAIR entry
+ if (fb_attr == (uint64_t)-1)
+ fb_attr = 0;
#endif
void *stack = ext_mem_alloc(stack_size) + stack_size;
@@ -1034,10 +1052,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
}
