video: Initial support for multiple framebuffers

This commit is contained in:
mintsuki 2022-11-18 23:59:31 +01:00
parent 9b68f081cf
commit d39baeaa80
22 changed files with 619 additions and 657 deletions

View File

@ -50,11 +50,7 @@ success:
#include <efi.h> #include <efi.h>
struct edid_info_struct *get_edid_info(void) { struct edid_info_struct *get_edid_info(EFI_HANDLE gop_handle) {
if (!gop_ready) {
goto fail;
}
struct edid_info_struct *buf = ext_mem_alloc(sizeof(struct edid_info_struct)); struct edid_info_struct *buf = ext_mem_alloc(sizeof(struct edid_info_struct));
EFI_STATUS status; EFI_STATUS status;

View File

@ -30,6 +30,14 @@ struct edid_info_struct {
uint8_t checksum; uint8_t checksum;
} __attribute__((packed)); } __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); struct edid_info_struct *get_edid_info(void);
#endif
#endif #endif

View File

@ -37,7 +37,7 @@ static void linear_mask_to_mask_shift(
// Most of this code taken from https://wiki.osdev.org/GOP // 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_STATUS status;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info; 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; 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; EFI_STATUS status;
if (!mode_to_fb_info(ret, mode)) { if (!mode_to_fb_info(ret, gop, mode)) {
return false; 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); 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"); printv("gop: Mode was already set, perfect!\n");
} else { } else {
status = gop->SetMode(gop, mode); status = gop->SetMode(gop, mode);
if (status) { if (status) {
current_video_mode = -1;
printv("gop: Failed to set video mode %x, moving on...\n", mode); printv("gop: Failed to set video mode %x, moving on...\n", mode);
return false; return false;
} }
} }
current_video_mode = mode;
ret->framebuffer_addr = gop->Mode->FrameBufferBase; ret->framebuffer_addr = gop->Mode->FrameBufferBase;
fb_clear(ret); 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; return true;
} }
struct fb_info *gop_get_mode_list(size_t *count) { static struct fb_info *get_mode_list(size_t *count, EFI_GRAPHICS_OUTPUT_PROTOCOL *gop) {
if (!gop_ready) {
return NULL;
}
UINTN modes_count = gop->Mode->MaxMode; UINTN modes_count = gop->Mode->MaxMode;
struct fb_info *ret = ext_mem_alloc(modes_count * sizeof(struct fb_info)); struct fb_info *ret = ext_mem_alloc(modes_count * sizeof(struct fb_info));
size_t actual_count = 0; size_t actual_count = 0;
for (size_t i = 0; i < modes_count; i++) { 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++; actual_count++;
} }
} }
@ -170,21 +171,8 @@ struct fb_info *gop_get_mode_list(size_t *count) {
return ret; return ret;
} }
#define INVALID_PRESET_MODE 0xffffffff void init_gop(struct fb_info **ret, size_t *_fbs_count,
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,
uint64_t target_width, uint64_t target_height, uint16_t target_bpp) { uint64_t target_width, uint64_t target_height, uint16_t target_bpp) {
gop_ready = false;
ret->default_res = false;
EFI_STATUS status; EFI_STATUS status;
EFI_HANDLE tmp_handles[1]; 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); status = gBS->LocateHandle(ByProtocol, &gop_guid, NULL, &handles_size, handles);
if (status != EFI_SUCCESS && status != EFI_BUFFER_TOO_SMALL) { if (status != EFI_SUCCESS && status != EFI_BUFFER_TOO_SMALL) {
return false; *_fbs_count = 0;
return;
} }
handles = ext_mem_alloc(handles_size); 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); status = gBS->LocateHandle(ByProtocol, &gop_guid, NULL, &handles_size, handles);
if (status != EFI_SUCCESS) { if (status != EFI_SUCCESS) {
pmm_free(handles, handles_size); pmm_free(handles, handles_size);
return false; *_fbs_count = 0;
return;
} }
gop_handle = handles[0]; size_t handles_count = handles_size / sizeof(EFI_HANDLE);
pmm_free(handles, handles_size);
status = gBS->HandleProtocol(gop_handle, &gop_guid, (void **)&gop); *ret = ext_mem_alloc(handles_count * sizeof(struct fb_info));
if (status != EFI_SUCCESS) {
return false;
}
gop_ready = true; const struct resolution fallback_resolutions[] = {
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[] = {
{ 0, 0, 0 }, // Overridden by EDID { 0, 0, 0 }, // Overridden by EDID
{ 0, 0, 0 }, // Overridden by preset { 0, 0, 0 }, // Overridden by preset
{ 1024, 768, 32 }, { 1024, 768, 32 },
@ -256,42 +215,76 @@ bool init_gop(struct fb_info *ret,
{ 640, 480, 16 } { 640, 480, 16 }
}; };
size_t fbs_count = 0;
for (size_t i = 0; i < handles_count; i++) {
struct fb_info *fb = &(*ret)[fbs_count];
uint64_t _target_width = target_width;
uint64_t _target_height = target_height;
uint64_t _target_bpp = 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; UINTN modes_count = gop->Mode->MaxMode;
size_t current_fallback = 0; size_t current_fallback = 0;
if (!target_width || !target_height || !target_bpp) { if (!_target_width || !_target_height || !_target_bpp) {
goto fallback; goto fallback;
} else { } else {
printv("gop: Requested resolution of %ux%ux%u\n", printv("gop: Requested resolution of %ux%ux%u\n",
target_width, target_height, target_bpp); _target_width, _target_height, _target_bpp);
} }
retry: retry:
for (size_t i = 0; i < modes_count; i++) { for (size_t j = 0; j < modes_count; j++) {
if (try_mode(ret, i, target_width, target_height, target_bpp)) { if (try_mode(fb, gop, j, _target_width, _target_height, _target_bpp, *ret, fbs_count)) {
gop_force_16 = false; goto success;
return true;
} }
} }
fallback: fallback:
ret->default_res = true;
if (current_fallback == 0) { if (current_fallback == 0) {
current_fallback++; current_fallback++;
struct edid_info_struct *edid_info = get_edid_info(); if (fb->edid != NULL) {
if (edid_info != NULL) { uint64_t edid_width = (uint64_t)fb->edid->det_timing_desc1[2];
uint64_t edid_width = (uint64_t)edid_info->det_timing_desc1[2]; edid_width += ((uint64_t)fb->edid->det_timing_desc1[4] & 0xf0) << 4;
edid_width += ((uint64_t)edid_info->det_timing_desc1[4] & 0xf0) << 4; uint64_t edid_height = (uint64_t)fb->edid->det_timing_desc1[5];
uint64_t edid_height = (uint64_t)edid_info->det_timing_desc1[5]; edid_height += ((uint64_t)fb->edid->det_timing_desc1[7] & 0xf0) << 4;
edid_height += ((uint64_t)edid_info->det_timing_desc1[7] & 0xf0) << 4; if (edid_width >= mode_info->HorizontalResolution
if (edid_width >= preset_mode_info.HorizontalResolution && edid_height >= mode_info->VerticalResolution) {
&& edid_height >= preset_mode_info.VerticalResolution) { _target_width = edid_width;
target_width = edid_width; _target_height = edid_height;
target_height = edid_height; _target_bpp = 32;
target_bpp = 32;
goto retry; goto retry;
} }
} }
@ -300,23 +293,33 @@ fallback:
if (current_fallback == 1) { if (current_fallback == 1) {
current_fallback++; current_fallback++;
if (try_mode(ret, preset_mode, 0, 0, 0)) { if (try_mode(fb, gop, preset_mode, 0, 0, 0, *ret, fbs_count)) {
gop_force_16 = false; goto success;
return true;
} }
} }
if (current_fallback < SIZEOF_ARRAY(fallback_resolutions)) { if (current_fallback < SIZEOF_ARRAY(fallback_resolutions)) {
current_fallback++; current_fallback++;
target_width = fallback_resolutions[current_fallback].width; _target_width = fallback_resolutions[current_fallback].width;
target_height = fallback_resolutions[current_fallback].height; _target_height = fallback_resolutions[current_fallback].height;
target_bpp = fallback_resolutions[current_fallback].bpp; _target_bpp = fallback_resolutions[current_fallback].bpp;
goto retry; goto retry;
} }
continue;
success:
fb->mode_list = get_mode_list(&fb->mode_count, gop);
fbs_count++;
}
pmm_free(handles, handles_size);
gop_force_16 = false; gop_force_16 = false;
return false;
*_fbs_count = fbs_count;
} }
#endif #endif

View File

@ -6,20 +6,13 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include <efi.h>
#include <lib/fb.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); 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_force_16;
extern bool gop_ready;
extern EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
extern EFI_HANDLE gop_handle;
#endif #endif
#endif #endif

View File

@ -187,8 +187,6 @@ bool init_vbe(struct fb_info *ret,
uint16_t target_width, uint16_t target_height, uint16_t target_bpp) { uint16_t target_width, uint16_t target_height, uint16_t target_bpp) {
printv("vbe: Initialising...\n"); printv("vbe: Initialising...\n");
ret->default_res = false;
size_t current_fallback = 0; size_t current_fallback = 0;
struct vbe_info_struct vbe_info; struct vbe_info_struct vbe_info;
@ -216,8 +214,6 @@ bool init_vbe(struct fb_info *ret,
}; };
if (!target_width || !target_height || !target_bpp) { if (!target_width || !target_height || !target_bpp) {
ret->default_res = true;
struct edid_info_struct *edid_info = get_edid_info(); struct edid_info_struct *edid_info = get_edid_info();
if (edid_info != NULL) { if (edid_info != NULL) {
int edid_width = (int)edid_info->det_timing_desc1[2]; int edid_width = (int)edid_info->det_timing_desc1[2];
@ -293,8 +289,6 @@ retry:
} }
fallback: fallback:
ret->default_res = true;
if (current_fallback < SIZEOF_ARRAY(fallback_resolutions)) { if (current_fallback < SIZEOF_ARRAY(fallback_resolutions)) {
target_width = fallback_resolutions[current_fallback].width; target_width = fallback_resolutions[current_fallback].width;
target_height = fallback_resolutions[current_fallback].height; target_height = fallback_resolutions[current_fallback].height;

View File

@ -253,10 +253,7 @@ static void text_deinit(struct term_context *_ctx, void (*_free)(void *, size_t)
static struct textmode_context term_local_struct; static struct textmode_context term_local_struct;
void vga_textmode_init(bool managed) { void vga_textmode_init(bool managed) {
if (term != NULL) { term_notready();
term->deinit(term, pmm_free);
term = NULL;
}
if (quiet) { if (quiet) {
return; return;
@ -270,6 +267,13 @@ void vga_textmode_init(bool managed) {
current_video_mode = 0x3; 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; struct textmode_context *ctx = &term_local_struct;
term = &term_local_struct.term; term = &term_local_struct.term;

View File

@ -38,6 +38,8 @@ noreturn void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
gST->ConOut->EnableCursor(gST->ConOut, false); gST->ConOut->EnableCursor(gST->ConOut, false);
init_memmap();
term_fallback(); term_fallback();
status = gBS->SetWatchdogTimer(0, 0x10000, 0, NULL); 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"); print("WARNING: Failed to disable watchdog timer!\n");
} }
init_memmap();
#if defined (__x86_64__) || defined (__i386__) #if defined (__x86_64__) || defined (__i386__)
init_gdt(); init_gdt();
#endif #endif

View File

@ -6,24 +6,23 @@
#include <drivers/gop.h> #include <drivers/gop.h>
#include <mm/pmm.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) { uint64_t target_width, uint64_t target_height, uint16_t target_bpp) {
bool r;
#if defined (BIOS) #if defined (BIOS)
r = init_vbe(ret, target_width, target_height, target_bpp); *ret = ext_mem_alloc(sizeof(struct fb_info));
#elif defined (UEFI) if (init_vbe(*ret, target_width, target_height, target_bpp)) {
r = init_gop(ret, target_width, target_height, target_bpp); *_fbs_count = 1;
#endif
return r; (*ret)->edid = get_edid_info();
} size_t mode_count;
(*ret)->mode_list = vbe_get_mode_list(&mode_count);
struct fb_info *fb_get_mode_list(size_t *count) { (*ret)->mode_count = mode_count;
#if defined (BIOS) } else {
return vbe_get_mode_list(count); *_fbs_count = 0;
pmm_free(*ret, sizeof(struct fb_info));
}
#elif defined (UEFI) #elif defined (UEFI)
return gop_get_mode_list(count); init_gop(ret, _fbs_count, target_width, target_height, target_bpp);
#endif #endif
} }

View File

@ -3,6 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <drivers/edid.h>
struct resolution { struct resolution {
uint64_t width; uint64_t width;
@ -23,15 +24,17 @@ struct fb_info {
uint8_t blue_mask_size; uint8_t blue_mask_size;
uint8_t blue_mask_shift; uint8_t blue_mask_shift;
bool default_res;
uint64_t framebuffer_addr; 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); 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); void fb_clear(struct fb_info *fb);
#endif #endif

View File

@ -360,8 +360,6 @@ static const uint8_t builtin_font[] = {
0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00
}; };
struct fb_info fbinfo;
static struct image *background; static struct image *background;
static size_t margin = 64; 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); 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 distance, x_distance, y_distance;
size_t gradient_stop_x = fbinfo.framebuffer_width - margin; size_t gradient_stop_x = fb->framebuffer_width - margin;
size_t gradient_stop_y = fbinfo.framebuffer_height - margin; size_t gradient_stop_y = fb->framebuffer_height - margin;
if (x < margin) if (x < margin)
x_distance = margin - x; 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; } 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 // 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; 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; 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++) { for (size_t y = ystart; y < yend; y++) {
size_t image_y = y % img_height, image_x = xstart % img_width; size_t image_y = y % img_height, image_x = xstart % img_width;
const size_t off = img_pitch * (img_height - 1 - image_y); 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++) { for (size_t x = xstart; x < xend; x++) {
uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off); 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; bg_canvas[canvas_off + x] = i;
if (image_x++ == img_width) image_x = 0; // image_x = x % img_width, but modulo is too expensive 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++) { for (size_t y = ystart; y < yend; y++) {
size_t image_y = y - background->y_displacement; size_t image_y = y - background->y_displacement;
const size_t off = img_pitch * (img_height - 1 - image_y); 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 */ if (image_y >= background->y_size) { /* external part */
for (size_t x = xstart; x < xend; x++) { 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; 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); size_t image_x = (x - background->x_displacement);
bool x_external = image_x >= background->x_size; bool x_external = image_x >= background->x_size;
uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off); 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; 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 // so you can set x = xstart * ratio, and increment by ratio at each iteration
case IMAGE_STRETCHED: case IMAGE_STRETCHED:
for (size_t y = ystart; y < yend; y++) { 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 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; fixedp6 img_x = ratio * xstart;
for (size_t x = xstart; x < xend; x++) { for (size_t x = xstart; x < xend; x++) {
uint32_t img_pixel = *(uint32_t*)(img + fixedp6_to_int(img_x) * colsize + off); 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; bg_canvas[canvas_off + x] = i;
img_x += ratio; 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_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(size_t x, size_t y, uint32_t orig) { (void)x; (void)y; return colour_blend(default_bg, 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(size_t x, size_t y, uint32_t orig) { return blend_gradient_from_box(x, y, orig, default_bg); } 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_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(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_margin); } 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(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_internal); } 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) { 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); bg_canvas = ext_mem_alloc(bg_canvas_size);
int64_t margin_no_gradient = (int64_t)margin - margin_gradient; int64_t margin_no_gradient = (int64_t)margin - margin_gradient;
@ -509,99 +507,76 @@ static void generate_canvas(void) {
margin_no_gradient = 0; margin_no_gradient = 0;
} }
size_t scan_stop_x = fbinfo.framebuffer_width - margin_no_gradient; size_t scan_stop_x = fb->framebuffer_width - margin_no_gradient;
size_t scan_stop_y = fbinfo.framebuffer_height - 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(fb, 0, fb->framebuffer_width, 0, margin_no_gradient);
loop_external(0, fbinfo.framebuffer_width, scan_stop_y, fbinfo.framebuffer_height); loop_external(fb, 0, fb->framebuffer_width, scan_stop_y, fb->framebuffer_height);
loop_external(0, margin_no_gradient, margin_no_gradient, scan_stop_y); loop_external(fb, 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, 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_x = fb->framebuffer_width - margin;
size_t gradient_stop_y = fbinfo.framebuffer_height - margin; size_t gradient_stop_y = fb->framebuffer_height - margin;
if (margin_gradient) { if (margin_gradient) {
loop_margin(margin_no_gradient, scan_stop_x, margin_no_gradient, margin); loop_margin(fb, 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(fb, margin_no_gradient, scan_stop_x, gradient_stop_y, scan_stop_y);
loop_margin(margin_no_gradient, margin, margin, gradient_stop_y); loop_margin(fb, margin_no_gradient, margin, margin, gradient_stop_y);
loop_margin(gradient_stop_x, scan_stop_x, 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 { } else {
bg_canvas = NULL; bg_canvas = NULL;
} }
} }
static bool last_serial = false; bool gterm_init(struct fb_info **_fbs, size_t *_fbs_count,
static char *last_config = NULL; char *config, size_t width, size_t height) {
static struct fb_info *fbs;
static size_t fbs_count;
bool gterm_init(char *config, size_t width, size_t height) { static bool prev_valid = false;
if (quiet) { static char *prev_config;
if (term != NULL) { static size_t prev_width, prev_height;
term->deinit(term, pmm_free);
term = NULL; 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;
if (quiet) {
term_notready();
return false; return false;
} }
#if defined (UEFI) #if defined (UEFI)
if (serial || COM_OUTPUT) { if (serial || COM_OUTPUT) {
if (term != NULL) {
term->deinit(term, pmm_free);
term = NULL;
}
term_fallback(); term_fallback();
return true; return true;
} }
#endif #endif
if (term != NULL term_notready();
&& 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;
}
// We force bpp to 32 // We force bpp to 32
if (!fb_init(&fbinfo, width, height, 32)) { fb_init(&fbs, &fbs_count, width, height, 32);
return false;
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 (fbs_count == 0) {
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) {
return false; return false;
} }
last_serial = serial;
last_config = config;
// default scheme // default scheme
margin = 64; margin = 64;
margin_gradient = 4; 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); 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_width = 8;
size_t font_height = 16; size_t font_height = 16;
size_t font_size = (font_width * font_height * FBTERM_FONT_GLYPHS) / 8; size_t font_size = (font_width * font_height * FBTERM_FONT_GLYPHS) / 8;
@ -775,11 +736,41 @@ no_load_font:;
} }
} }
generate_canvas(); terms_i = 0;
terms = ext_mem_alloc(fbs_count * sizeof(void *));
term = fbterm_init(ext_mem_alloc, for (size_t i = 0; i < fbs_count; i++) {
(void *)(uintptr_t)fbinfo.framebuffer_addr, struct fb_info *fb = &fbs[i];
fbinfo.framebuffer_width, fbinfo.framebuffer_height, fbinfo.framebuffer_pitch,
// 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, bg_canvas,
ansi_colours, ansi_bright_colours, ansi_colours, ansi_bright_colours,
&default_bg, &default_fg, &default_bg, &default_fg,
@ -787,26 +778,63 @@ no_load_font:;
font_scale_x, font_scale_y, font_scale_x, font_scale_y,
margin); margin);
pmm_free(font, FONT_MAX); if (terms[terms_i] != NULL) {
terms_i++;
}
if (bg_canvas != NULL) { if (bg_canvas != NULL) {
pmm_free(bg_canvas, bg_canvas_size); pmm_free(bg_canvas, bg_canvas_size);
} }
}
if (term == NULL) { pmm_free(font, FONT_MAX);
if (terms_i == 0) {
return false; return false;
} }
for (size_t i = 0; i < terms_i; i++) {
struct term_context *term = terms[i];
if (serial) { if (serial) {
term->cols = term->cols > 80 ? 80 : term->cols; term->cols = term->cols > 80 ? 80 : term->cols;
term->rows = term->rows > 24 ? 24 : term->rows; 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;
}
}
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->in_bootloader = true;
term_context_reinit(term); term_context_reinit(term);
term->full_refresh(term); term->full_refresh(term);
}
term_backend = GTERM; term_backend = GTERM;
prev_config = config;
prev_height = height;
prev_width = width;
prev_valid = true;
return true; return true;
} }

View File

@ -5,8 +5,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <lib/fb.h> #include <lib/fb.h>
extern struct fb_info fbinfo; bool gterm_init(struct fb_info **ret, size_t *_fbs_count,
char *config, size_t width, size_t height);
bool gterm_init(char *config, size_t width, size_t height);
#endif #endif

View File

@ -222,9 +222,7 @@ out:
#if defined (BIOS) #if defined (BIOS)
if (stage3_loaded) { if (stage3_loaded) {
#endif #endif
if (term != NULL) { FOR_TERM(term_write(TERM, print_buf, print_buf_i));
term_write(term, print_buf, print_buf_i);
}
#if defined (BIOS) #if defined (BIOS)
} else { } else {
s2_print(print_buf, print_buf_i); s2_print(print_buf, print_buf_i);

View File

@ -352,34 +352,34 @@ again:
static void reprint_string(int x, int y, const char *s) { static void reprint_string(int x, int y, const char *s) {
size_t orig_x, orig_y; size_t orig_x, orig_y;
term->disable_cursor(term); FOR_TERM(TERM->disable_cursor(TERM));
term->get_cursor_pos(term, &orig_x, &orig_y); terms[0]->get_cursor_pos(terms[0], &orig_x, &orig_y);
set_cursor_pos_helper(x, y); set_cursor_pos_helper(x, y);
print("%s", s); print("%s", s);
set_cursor_pos_helper(orig_x, orig_y); set_cursor_pos_helper(orig_x, orig_y);
term->enable_cursor(term); FOR_TERM(TERM->enable_cursor(TERM));
} }
static void cursor_back(void) { static void cursor_back(void) {
size_t x, y; size_t x, y;
term->get_cursor_pos(term, &x, &y); terms[0]->get_cursor_pos(terms[0], &x, &y);
if (x) { if (x) {
x--; x--;
} else if (y) { } else if (y) {
y--; y--;
x = term->cols - 1; x = terms[0]->cols - 1;
} }
set_cursor_pos_helper(x, y); set_cursor_pos_helper(x, y);
} }
static void cursor_fwd(void) { static void cursor_fwd(void) {
size_t x, y; size_t x, y;
term->get_cursor_pos(term, &x, &y); terms[0]->get_cursor_pos(terms[0], &x, &y);
if (x < term->cols - 1) { if (x < terms[0]->cols - 1) {
x++; x++;
} else { } else {
x = 0; x = 0;
if (y < term->rows - 1) { if (y < terms[0]->rows - 1) {
y++; y++;
} }
} }
@ -387,20 +387,20 @@ static void cursor_fwd(void) {
} }
void readline(const char *orig_str, char *buf, size_t limit) { void readline(const char *orig_str, char *buf, size_t limit) {
bool prev_autoflush = term->autoflush; bool prev_autoflush = terms[0]->autoflush;
term->autoflush = false; FOR_TERM(TERM->autoflush = false);
size_t orig_str_len = strlen(orig_str); size_t orig_str_len = strlen(orig_str);
memmove(buf, orig_str, orig_str_len); memmove(buf, orig_str, orig_str_len);
buf[orig_str_len] = 0; buf[orig_str_len] = 0;
size_t orig_x, orig_y; 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); print("%s", orig_str);
for (size_t i = orig_str_len; ; ) { for (size_t i = orig_str_len; ; ) {
term->double_buffer_flush(term); FOR_TERM(TERM->double_buffer_flush(TERM));
int c = getchar(); int c = getchar();
switch (c) { switch (c) {
case GETCHAR_CURSOR_LEFT: case GETCHAR_CURSOR_LEFT:
@ -460,11 +460,11 @@ void readline(const char *orig_str, char *buf, size_t limit) {
buf[i] = c; buf[i] = c;
i++; i++;
size_t prev_x, prev_y; 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(); cursor_fwd();
reprint_string(orig_x, orig_y, buf); reprint_string(orig_x, orig_y, buf);
// If cursor has wrapped around, move the line start position up one row // 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--; orig_y--;
print("\e[J"); // Clear the bottom line print("\e[J"); // Clear the bottom line
} }
@ -474,6 +474,6 @@ void readline(const char *orig_str, char *buf, size_t limit) {
} }
out: out:
term->double_buffer_flush(term); FOR_TERM(TERM->double_buffer_flush(TERM));
term->autoflush = prev_autoflush; FOR_TERM(TERM->autoflush = prev_autoflush);
} }

View File

@ -8,95 +8,28 @@
#include <drivers/vga_textmode.h> #include <drivers/vga_textmode.h>
#include <term/backends/framebuffer.h> #include <term/backends/framebuffer.h>
#if defined (BIOS)
int current_video_mode = -1; int current_video_mode = -1;
#endif
struct term_context **terms = NULL;
size_t terms_i = 0;
int term_backend = _NOT_READY; 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->deinit(term, pmm_free);
term = NULL;
} }
term = &term_local_struct; pmm_free(terms, terms_i * sizeof(void *));
term->raw_putchar = notready_raw_putchar; terms_i = 0;
term->clear = notready_clear; terms = NULL;
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;
term_backend = _NOT_READY; term_backend = _NOT_READY;
term_context_reinit(term);
term->in_bootloader = true;
} }
// --- fallback --- // --- fallback ---
@ -162,7 +95,7 @@ static void fallback_scroll(struct term_context *ctx) {
(void)ctx; (void)ctx;
size_t x, y; size_t x, y;
fallback_get_cursor_pos(NULL, &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_raw_putchar(NULL, ' ');
fallback_set_cursor_pos(NULL, x, y); 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) { static void fallback_scroll(struct term_context *ctx) {
(void)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]; CHAR16 string[2];
string[0] = ' '; string[0] = ' ';
string[1] = 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) { 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; return;
} }
gST->ConOut->EnableCursor(gST->ConOut, true); 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[0] = c;
string[1] = 0; string[1] = 0;
gST->ConOut->OutputString(gST->ConOut, string); gST->ConOut->OutputString(gST->ConOut, string);
if (++cursor_x >= term->cols) { if (++cursor_x >= ctx->cols) {
cursor_x = 0; cursor_x = 0;
if (++cursor_y >= term->rows) { if (++cursor_y >= ctx->rows) {
cursor_y--; 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) { static void fallback_set_cursor_pos(struct term_context *ctx, size_t x, size_t y) {
(void)ctx; (void)ctx;
if (x >= term->cols || y >= term->rows) { if (x >= ctx->cols || y >= ctx->rows) {
return; return;
} }
gST->ConOut->SetCursorPosition(gST->ConOut, x, y); 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 #endif
static bool dummy_handle(void) {
return true;
}
void term_fallback(void) { void term_fallback(void) {
term_notready(); term_notready();
#if defined (UEFI) #if defined (UEFI)
if (!efi_boot_services_exited) { if (!efi_boot_services_exited) {
#endif #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); 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->raw_putchar = fallback_raw_putchar;
term->clear = fallback_clear; term->clear = fallback_clear;
term->set_cursor_pos = fallback_set_cursor_pos; 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]; static uint8_t xfer_buf[TERM_XFER_CHUNK];
#endif #endif
static uint64_t context_size(void) { static uint64_t context_size(struct term_context *term) {
switch (term_backend) { switch (term_backend) {
#if defined (BIOS) #if defined (BIOS)
case TEXTMODE: 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) { switch (term_backend) {
#if defined (BIOS) #if defined (BIOS)
case TEXTMODE: { 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) { switch (term_backend) {
#if defined (BIOS) #if defined (BIOS)
case TEXTMODE: { 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) { switch (count) {
case TERM_CTX_SIZE: { 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)); memcpy32to64(buf, (uint64_t)(uintptr_t)&ret, sizeof(uint64_t));
return; return;
} }
case TERM_CTX_SAVE: { case TERM_CTX_SAVE: {
context_save(buf); context_save(term, buf);
return; return;
} }
case TERM_CTX_RESTORE: { case TERM_CTX_RESTORE: {
context_restore(buf); context_restore(term, buf);
return; return;
} }
case TERM_FULL_REFRESH: { case TERM_FULL_REFRESH: {

View File

@ -13,28 +13,46 @@ enum {
FALLBACK FALLBACK
}; };
#if defined (BIOS)
extern int current_video_mode; 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_SIZE ((uint64_t)(-1))
#define TERM_CTX_SAVE ((uint64_t)(-2)) #define TERM_CTX_SAVE ((uint64_t)(-2))
#define TERM_CTX_RESTORE ((uint64_t)(-3)) #define TERM_CTX_RESTORE ((uint64_t)(-3))
#define TERM_FULL_REFRESH ((uint64_t)(-4)) #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) { inline void reset_term(void) {
term->autoflush = true; for (size_t i = 0; i < terms_i; i++) {
term->enable_cursor(term); struct term_context *term = terms[i];
print("\e[2J\e[H"); print("\e[2J\e[H");
term_context_reinit(term);
term->in_bootloader = true;
term->enable_cursor(term);
term->double_buffer_flush(term); term->double_buffer_flush(term);
}
} }
inline void set_cursor_pos_helper(size_t x, size_t y) { inline void set_cursor_pos_helper(size_t x, size_t y) {
print("\e[%u;%uH", (int)y + 1, (int)x + 1); print("\e[%u;%uH", (int)y + 1, (int)x + 1);
} }
void term_notready(void);
void term_fallback(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 #endif

View File

@ -43,7 +43,8 @@ SECTIONS
term_write = .; term_write = .;
term_backend = .; term_backend = .;
term_fallback = .; term_fallback = .;
term = .; terms = .;
terms_i = .;
stage3_addr = .; stage3_addr = .;
#else #else
#ifdef LINKER_NOS2MAP #ifdef LINKER_NOS2MAP

View File

@ -168,17 +168,17 @@ static void putchar_tokencol(int type, char c) {
static bool editor_no_term_reset = false; static bool editor_no_term_reset = false;
char *config_entry_editor(const char *title, const char *orig_entry) { 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"); print("\e[2J\e[H");
size_t cursor_offset = 0; size_t cursor_offset = 0;
size_t entry_size = strlen(orig_entry); 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 window_offset = 0;
size_t line_size = term->cols - 2; size_t line_size = terms[0]->cols - 2;
bool display_overflow_error = false; bool display_overflow_error = false;
@ -214,12 +214,12 @@ refresh:
invalid_syntax = false; invalid_syntax = false;
print("\e[2J\e[H"); print("\e[2J\e[H");
term->disable_cursor(term); FOR_TERM(TERM->disable_cursor(TERM));
{ {
size_t x, y; size_t x, y;
print("\n"); print("\n");
term->get_cursor_pos(term, &x, &y); terms[0]->get_cursor_pos(terms[0], &x, &y);
set_cursor_pos_helper(term->cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), 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("\e[3%sm%s\e[37m", menu_branding_colour, menu_branding);
print("\n\n"); print("\n\n");
} }
@ -227,7 +227,7 @@ refresh:
print(" \e[32mESC\e[0m Discard and Exit \e[32mF10\e[0m Boot\n\n"); print(" \e[32mESC\e[0m Discard and Exit \e[32mF10\e[0m Boot\n\n");
print(serial ? "/" : "\xda"); 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) { switch (i) {
case 1: case 2: case 3: case 1: case 2: case 3:
if (window_offset > 0) { if (window_offset > 0) {
@ -237,7 +237,7 @@ refresh:
// FALLTHRU // FALLTHRU
default: { default: {
size_t title_length = strlen(title); 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); print("%s", title);
i += title_length - 1; i += title_length - 1;
} else { } else {
@ -248,7 +248,7 @@ refresh:
} }
size_t tmpx, tmpy; size_t tmpx, tmpy;
term->get_cursor_pos(term, &tmpx, &tmpy); terms[0]->get_cursor_pos(terms[0], &tmpx, &tmpy);
print(serial ? "\\" : "\xbf"); print(serial ? "\\" : "\xbf");
set_cursor_pos_helper(0, tmpy + 1); set_cursor_pos_helper(0, tmpy + 1);
print(serial ? "|" : "\xb3"); print(serial ? "|" : "\xb3");
@ -264,20 +264,20 @@ refresh:
&& current_line < window_offset + window_size && current_line < window_offset + window_size
&& current_line >= window_offset) { && current_line >= window_offset) {
size_t x, y; size_t x, y;
term->get_cursor_pos(term, &x, &y); terms[0]->get_cursor_pos(terms[0], &x, &y);
if (i == cursor_offset) { if (i == cursor_offset) {
cursor_x = x; cursor_x = x;
cursor_y = y; cursor_y = y;
printed_cursor = true; 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) { 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"); print(serial ? "|" : "\xb3");
set_cursor_pos_helper(0, tmpy + 1); set_cursor_pos_helper(0, tmpy + 1);
print(serial ? "\\" : "\xc0"); print(serial ? "\\" : "\xc0");
} else { } else {
term->get_cursor_pos(term, &tmpx, &tmpy); terms[0]->get_cursor_pos(terms[0], &tmpx, &tmpy);
print(serial ? "|" : "\xb3"); print(serial ? "|" : "\xb3");
set_cursor_pos_helper(0, tmpy + 1); set_cursor_pos_helper(0, tmpy + 1);
print(serial ? "|" : "\xb3"); print(serial ? "|" : "\xb3");
@ -295,7 +295,7 @@ refresh:
if (current_line < window_offset + window_size if (current_line < window_offset + window_size
&& current_line >= window_offset) { && current_line >= window_offset) {
if (i == cursor_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; printed_cursor = true;
} }
if (syntax_highlighting_enabled) { if (syntax_highlighting_enabled) {
@ -305,8 +305,8 @@ refresh:
} }
printed_early = true; printed_early = true;
size_t x, y; size_t x, y;
term->get_cursor_pos(term, &x, &y); terms[0]->get_cursor_pos(terms[0], &x, &y);
if (y == term->rows - 3) { if (y == terms[0]->rows - 3) {
print(serial ? ">" : "\x1a"); print(serial ? ">" : "\x1a");
set_cursor_pos_helper(0, y + 1); set_cursor_pos_helper(0, y + 1);
print(serial ? "\\" : "\xc0"); print(serial ? "\\" : "\xc0");
@ -323,7 +323,7 @@ refresh:
&& current_line < window_offset + window_size && current_line < window_offset + window_size
&& current_line >= window_offset && current_line >= window_offset
&& !printed_cursor) { && !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; printed_cursor = true;
} }
@ -370,35 +370,35 @@ refresh:
// syntax error alert // syntax error alert
if (validation_enabled) { if (validation_enabled) {
size_t x, y; size_t x, y;
term->get_cursor_pos(term, &x, &y); terms[0]->get_cursor_pos(terms[0], &x, &y);
set_cursor_pos_helper(0, term->rows - 1); set_cursor_pos_helper(0, terms[0]->rows - 1);
term->scroll_enabled = false; FOR_TERM(TERM->scroll_enabled = false);
if (invalid_syntax) { if (invalid_syntax) {
print("\e[31mConfiguration is INVALID.\e[0m"); print("\e[31mConfiguration is INVALID.\e[0m");
} else { } else {
print("\e[32mConfiguration is valid.\e[0m"); print("\e[32mConfiguration is valid.\e[0m");
} }
term->scroll_enabled = true; FOR_TERM(TERM->scroll_enabled = true);
set_cursor_pos_helper(x, y); set_cursor_pos_helper(x, y);
} }
if (current_line - window_offset < window_size) { if (current_line - window_offset < window_size) {
size_t x, y; size_t x, y;
for (size_t i = 0; i < (window_size - (current_line - window_offset)) - 1; i++) { for (size_t i = 0; i < (window_size - (current_line - window_offset)) - 1; i++) {
term->get_cursor_pos(term, &x, &y); terms[0]->get_cursor_pos(terms[0], &x, &y);
set_cursor_pos_helper(term->cols - 1, y); set_cursor_pos_helper(terms[0]->cols - 1, y);
print(serial ? "|" : "\xb3"); print(serial ? "|" : "\xb3");
set_cursor_pos_helper(0, y + 1); set_cursor_pos_helper(0, y + 1);
print(serial ? "|" : "\xb3"); print(serial ? "|" : "\xb3");
} }
term->get_cursor_pos(term, &x, &y); terms[0]->get_cursor_pos(terms[0], &x, &y);
set_cursor_pos_helper(term->cols - 1, y); set_cursor_pos_helper(terms[0]->cols - 1, y);
print(serial ? "|" : "\xb3"); print(serial ? "|" : "\xb3");
set_cursor_pos_helper(0, y + 1); set_cursor_pos_helper(0, y + 1);
print(serial ? "\\" : "\xc0"); 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) { switch (i) {
case 1: case 2: case 3: case 1: case 2: case 3:
if (current_line - window_offset >= window_size) { if (current_line - window_offset >= window_size) {
@ -410,22 +410,22 @@ refresh:
print(serial ? "-" : "\xc4"); print(serial ? "-" : "\xc4");
} }
} }
term->get_cursor_pos(term, &tmpx, &tmpy); terms[0]->get_cursor_pos(terms[0], &tmpx, &tmpy);
print(serial ? "/" : "\xd9"); print(serial ? "/" : "\xd9");
set_cursor_pos_helper(0, tmpy + 1); set_cursor_pos_helper(0, tmpy + 1);
if (display_overflow_error) { if (display_overflow_error) {
term->scroll_enabled = false; FOR_TERM(TERM->scroll_enabled = false);
print("\e[31mText buffer not big enough, delete something instead."); print("\e[31mText buffer not big enough, delete something instead.");
term->scroll_enabled = true; FOR_TERM(TERM->scroll_enabled = true);
display_overflow_error = false; display_overflow_error = false;
} }
// Hack to redraw the cursor // Hack to redraw the cursor
set_cursor_pos_helper(cursor_x, cursor_y); 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(); int c = getchar();
size_t buffer_len = strlen(buffer); size_t buffer_len = strlen(buffer);
@ -584,7 +584,7 @@ static void menu_init_term(void) {
if (menu_resolution != NULL) if (menu_resolution != NULL)
parse_resolution(&req_width, &req_height, &req_bpp, menu_resolution); 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) #if defined (BIOS)
vga_textmode_init(true); vga_textmode_init(true);
#elif defined (UEFI) #elif defined (UEFI)
@ -721,23 +721,23 @@ noreturn void _menu(bool first_run) {
size_t tree_offset = 0; size_t tree_offset = 0;
refresh: refresh:
if (selected_entry >= tree_offset + term->rows - 10) { if (selected_entry >= tree_offset + terms[0]->rows - 10) {
tree_offset = selected_entry - (term->rows - 11); tree_offset = selected_entry - (terms[0]->rows - 11);
} }
if (selected_entry < tree_offset) { if (selected_entry < tree_offset) {
tree_offset = selected_entry; 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"); print("\e[2J\e[H");
{ {
size_t x, y; size_t x, y;
print("\n"); print("\n");
term->get_cursor_pos(term, &x, &y); terms[0]->get_cursor_pos(terms[0], &x, &y);
set_cursor_pos_helper(term->cols / 2 - DIV_ROUNDUP(strlen(menu_branding), 2), 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("\e[3%sm%s\e[37m", menu_branding_colour, menu_branding);
print("\n\n\n\n"); print("\n\n\n\n");
} }
@ -746,14 +746,14 @@ refresh:
if (quiet) { if (quiet) {
quiet = false; quiet = false;
menu_init_term(); menu_init_term();
term->autoflush = false; FOR_TERM(TERM->autoflush = false);
term->disable_cursor(term); FOR_TERM(TERM->disable_cursor(TERM));
} }
print("Config file %s.\n\n", config_ready ? "contains no valid entries" : "not found"); 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("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("the root of the Limine source repository.\n\n");
print("Press a key to enter the Limine console..."); print("Press a key to enter the Limine console...");
term->double_buffer_flush(term); FOR_TERM(TERM->double_buffer_flush(TERM));
getchar(); getchar();
reset_term(); reset_term();
console(); console();
@ -761,10 +761,10 @@ refresh:
{ // Draw box around boot menu { // Draw box around boot menu
size_t x, y; size_t x, y;
term->get_cursor_pos(term, &x, &y); terms[0]->get_cursor_pos(terms[0], &x, &y);
print(serial ? "/" : "\xda"); 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) { switch (i) {
case 1: case 2: case 3: case 1: case 2: case 3:
if (tree_offset > 0) { if (tree_offset > 0) {
@ -777,16 +777,16 @@ refresh:
} }
print(serial ? "\\" : "\xbf"); 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); set_cursor_pos_helper(0, i);
print(serial ? "|" : "\xb3"); print(serial ? "|" : "\xb3");
set_cursor_pos_helper(term->cols - 1, i); set_cursor_pos_helper(terms[0]->cols - 1, i);
print(serial ? "|" : "\xb3"); print(serial ? "|" : "\xb3");
} }
set_cursor_pos_helper(0, term->rows - 2); set_cursor_pos_helper(0, terms[0]->rows - 2);
print(serial ? "\\" : "\xc0"); 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 ? "-" : "\xc4");
} }
print(serial ? "/" : "\xd9"); print(serial ? "/" : "\xd9");
@ -794,15 +794,15 @@ refresh:
set_cursor_pos_helper(x, y + 2); 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); &selected_menu_entry);
{ {
size_t x, y; 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) { if (tree_offset + (terms[0]->rows - 10) < max_entries) {
set_cursor_pos_helper(2, term->rows - 2); set_cursor_pos_helper(2, terms[0]->rows - 2);
print(serial ? "vvv" : "\x19\x19\x19"); print(serial ? "vvv" : "\x19\x19\x19");
} }
@ -813,7 +813,7 @@ refresh:
print(" \e[32mARROWS\e[0m Select \e[32mENTER\e[0m %s", print(" \e[32mARROWS\e[0m Select \e[32mENTER\e[0m %s",
selected_menu_entry->expanded ? "Collapse" : "Expand"); 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"); print("\e[32mC\e[0m Console");
set_cursor_pos_helper(x, y); set_cursor_pos_helper(x, y);
} }
@ -826,11 +826,11 @@ refresh:
if (skip_timeout == false) { if (skip_timeout == false) {
print("\n\n"); print("\n\n");
for (size_t i = timeout; i; i--) { for (size_t i = timeout; i; i--) {
set_cursor_pos_helper(0, term->rows - 1); set_cursor_pos_helper(0, terms[0]->rows - 1);
term->scroll_enabled = false; 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); 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; FOR_TERM(TERM->scroll_enabled = true);
term->double_buffer_flush(term); FOR_TERM(TERM->double_buffer_flush(TERM));
if ((c = pit_sleep_and_quit_on_keypress(1))) { if ((c = pit_sleep_and_quit_on_keypress(1))) {
skip_timeout = true; skip_timeout = true;
if (quiet) { if (quiet) {
@ -839,21 +839,21 @@ refresh:
goto timeout_aborted; goto timeout_aborted;
} }
print("\e[2K"); print("\e[2K");
term->double_buffer_flush(term); FOR_TERM(TERM->double_buffer_flush(TERM));
goto timeout_aborted; goto timeout_aborted;
} }
} }
goto autoboot; 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) { 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); 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 (;;) { for (;;) {
c = getchar(); c = getchar();
@ -896,7 +896,7 @@ timeout_aborted:
} }
if (!quiet) { if (!quiet) {
if (term_backend == FALLBACK) { if (term_backend == FALLBACK) {
if (!gterm_init(NULL, 0, 0)) { if (!gterm_init(NULL, NULL, NULL, 0, 0)) {
#if defined (BIOS) #if defined (BIOS)
vga_textmode_init(true); vga_textmode_init(true);
#elif defined (UEFI) #elif defined (UEFI)

View File

@ -216,10 +216,7 @@ noreturn void efi_chainload_file(char *config, struct file_handle *image) {
pmm_free(_ptr, image->size); pmm_free(_ptr, image->size);
fclose(image); fclose(image);
if (term != NULL) { term_notready();
term->deinit(term, pmm_free);
term = NULL;
}
size_t req_width = 0, req_height = 0, req_bpp = 0; 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) if (resolution != NULL)
parse_resolution(&req_width, &req_height, &req_bpp, resolution); parse_resolution(&req_width, &req_height, &req_bpp, resolution);
struct fb_info fbinfo; struct fb_info *fbinfo;
if (!fb_init(&fbinfo, req_width, req_height, req_bpp)) size_t fb_count;
panic(true, "chainload: Unable to set video mode"); fb_init(&fbinfo, &fb_count, req_width, req_height, req_bpp);
pmm_release_uefi_mem(); pmm_release_uefi_mem();

View File

@ -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); 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) { static void term_write_shim(uint64_t context, uint64_t buf, uint64_t count) {
(void)context; (void)context;
_term_write(buf, count); _term_write(terms[0], buf, count);
} }
noreturn void limine_load(char *config, char *cmdline) { noreturn void limine_load(char *config, char *cmdline) {
@ -670,10 +671,11 @@ FEAT_END
parse_resolution(&req_width, &req_height, &req_bpp, resolution); parse_resolution(&req_width, &req_height, &req_bpp, resolution);
} }
struct fb_info fb;
uint64_t *term_fb_ptr = NULL; uint64_t *term_fb_ptr = NULL;
struct fb_info *fbs;
size_t fbs_count;
// Terminal feature // Terminal feature
FEAT_START FEAT_START
struct limine_terminal_request *terminal_request = get_request(LIMINE_TERMINAL_REQUEST); 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"); 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 (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; goto term_fail;
} }
} else { } else {
if (!gterm_init(NULL, req_width, req_height)) { if (!gterm_init(&fbs, &fbs_count, NULL, req_width, req_height)) {
goto term_fail; goto term_fail;
} }
} }
@ -707,10 +709,8 @@ term_fail:
break; // next feature break; // next feature
} }
fb = fbinfo;
if (terminal_request->callback != 0) { if (terminal_request->callback != 0) {
term->callback = callback_shim; terms[0]->callback = callback_shim;
#if defined (__i386__) #if defined (__i386__)
actual_callback = (void *)limine_term_callback; actual_callback = (void *)limine_term_callback;
@ -739,8 +739,8 @@ term_fail:
term_fb_ptr = &terminal->framebuffer; term_fb_ptr = &terminal->framebuffer;
terminal->columns = term->cols; terminal->columns = terms[0]->cols;
terminal->rows = term->rows; terminal->rows = terms[0]->rows;
uint64_t *term_list = ext_mem_alloc(1 * sizeof(uint64_t)); uint64_t *term_list = ext_mem_alloc(1 * sizeof(uint64_t));
term_list[0] = reported_addr(terminal); term_list[0] = reported_addr(terminal);
@ -753,27 +753,26 @@ term_fail:
goto skip_fb_init; goto skip_fb_init;
FEAT_END FEAT_END
if (term != NULL) { term_notready();
term->deinit(term, pmm_free);
term = NULL;
}
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; goto no_fb;
} }
skip_fb_init: skip_fb_init:
memmap_alloc_range(fb.framebuffer_addr, for (size_t i = 0; i < fbs_count; i++) {
(uint64_t)fb.framebuffer_pitch * fb.framebuffer_height, memmap_alloc_range(fbs[i].framebuffer_addr,
(uint64_t)fbs[i].framebuffer_pitch * fbs[i].framebuffer_height,
MEMMAP_FRAMEBUFFER, 0, false, false, true); MEMMAP_FRAMEBUFFER, 0, false, false, true);
}
// Framebuffer feature // Framebuffer feature
FEAT_START FEAT_START
// For now we only support 1 framebuffer struct limine_framebuffer *fbp = ext_mem_alloc(fbs_count * sizeof(struct limine_framebuffer));
struct limine_framebuffer *fbp = ext_mem_alloc(sizeof(struct limine_framebuffer));
if (term_fb_ptr != NULL) { 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); struct limine_framebuffer_request *framebuffer_request = get_request(LIMINE_FRAMEBUFFER_REQUEST);
@ -784,43 +783,41 @@ FEAT_START
struct limine_framebuffer_response *framebuffer_response = struct limine_framebuffer_response *framebuffer_response =
ext_mem_alloc(sizeof(struct limine_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; framebuffer_response->revision = 1;
size_t modes_count; uint64_t *fb_list = ext_mem_alloc(fbs_count * sizeof(uint64_t));
struct fb_info *modes = fb_get_mode_list(&modes_count);
if (modes != NULL) { for (size_t i = 0; i < fbs_count; i++) {
uint64_t *modes_list = ext_mem_alloc(modes_count * sizeof(uint64_t)); uint64_t *modes_list = ext_mem_alloc(fbs[i].mode_count * sizeof(uint64_t));
for (size_t i = 0; i < modes_count; i++) { for (size_t j = 0; j < fbs[i].mode_count; j++) {
modes[i].memory_model = LIMINE_FRAMEBUFFER_RGB; fbs[i].mode_list[j].memory_model = LIMINE_FRAMEBUFFER_RGB;
modes_list[i] = reported_addr(&modes[i]); modes_list[j] = reported_addr(&fbs[i].mode_list[j]);
} }
fbp->modes = reported_addr(modes_list); fbp[i].modes = reported_addr(modes_list);
fbp->mode_count = modes_count; 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->memory_model = LIMINE_FRAMEBUFFER_RGB; fbp[i].memory_model = LIMINE_FRAMEBUFFER_RGB;
fbp->address = reported_addr((void *)(uintptr_t)fb.framebuffer_addr); fbp[i].address = reported_addr((void *)(uintptr_t)fbs[i].framebuffer_addr);
fbp->width = fb.framebuffer_width; fbp[i].width = fbs[i].framebuffer_width;
fbp->height = fb.framebuffer_height; fbp[i].height = fbs[i].framebuffer_height;
fbp->bpp = fb.framebuffer_bpp; fbp[i].bpp = fbs[i].framebuffer_bpp;
fbp->pitch = fb.framebuffer_pitch; fbp[i].pitch = fbs[i].framebuffer_pitch;
fbp->red_mask_size = fb.red_mask_size; fbp[i].red_mask_size = fbs[i].red_mask_size;
fbp->red_mask_shift = fb.red_mask_shift; fbp[i].red_mask_shift = fbs[i].red_mask_shift;
fbp->green_mask_size = fb.green_mask_size; fbp[i].green_mask_size = fbs[i].green_mask_size;
fbp->green_mask_shift = fb.green_mask_shift; fbp[i].green_mask_shift = fbs[i].green_mask_shift;
fbp->blue_mask_size = fb.blue_mask_size; fbp[i].blue_mask_size = fbs[i].blue_mask_size;
fbp->blue_mask_shift = fb.blue_mask_shift; fbp[i].blue_mask_shift = fbs[i].blue_mask_shift;
uint64_t *fb_list = ext_mem_alloc(1 * sizeof(uint64_t)); fb_list[i] = reported_addr(&fbp[i]);
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_response->framebuffers = reported_addr(fb_list);
framebuffer_request->response = reported_addr(framebuffer_response); framebuffer_request->response = reported_addr(framebuffer_response);
@ -1029,10 +1026,8 @@ FEAT_START
FEAT_END FEAT_END
// Clear terminal for kernels that will use the Limine terminal // Clear terminal for kernels that will use the Limine terminal
if (term != NULL) { FOR_TERM(term_write(TERM, "\e[2J\e[H", 7));
term_write(term, "\e[2J\e[H", 7); FOR_TERM(TERM->in_bootloader = false);
term->in_bootloader = false;
}
#if defined (__x86_64__) || defined (__i386__) #if defined (__x86_64__) || defined (__i386__)
#if defined (BIOS) #if defined (BIOS)

View File

@ -495,10 +495,7 @@ noreturn void linux_load(char *config, char *cmdline) {
// Video // Video
/////////////////////////////////////// ///////////////////////////////////////
if (term != NULL) { term_notready();
term->deinit(term, pmm_free);
term = NULL;
}
struct screen_info *screen_info = &boot_params->screen_info; struct screen_info *screen_info = &boot_params->screen_info;
@ -518,11 +515,13 @@ noreturn void linux_load(char *config, char *cmdline) {
if (resolution != NULL) if (resolution != NULL)
parse_resolution(&req_width, &req_height, &req_bpp, resolution); parse_resolution(&req_width, &req_height, &req_bpp, resolution);
struct fb_info fbinfo; struct fb_info *fbs;
size_t fbs_count;
#if defined (UEFI) #if defined (UEFI)
gop_force_16 = true; gop_force_16 = true;
#endif #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) #if defined (UEFI)
goto no_fb; goto no_fb;
#elif defined (BIOS) #elif defined (BIOS)
@ -531,8 +530,8 @@ set_textmode:;
screen_info->orig_video_mode = 3; screen_info->orig_video_mode = 3;
screen_info->orig_video_ega_bx = 3; screen_info->orig_video_ega_bx = 3;
screen_info->orig_video_lines = term->rows; screen_info->orig_video_lines = 25;
screen_info->orig_video_cols = term->cols; screen_info->orig_video_cols = 80;
screen_info->orig_video_points = 16; screen_info->orig_video_points = 16;
screen_info->orig_video_isVGA = VIDEO_TYPE_VGAC; screen_info->orig_video_isVGA = VIDEO_TYPE_VGAC;
@ -540,19 +539,23 @@ set_textmode:;
} else { } else {
screen_info->capabilities = VIDEO_CAPABILITY_64BIT_BASE | VIDEO_CAPABILITY_SKIP_QUIRKS; screen_info->capabilities = VIDEO_CAPABILITY_64BIT_BASE | VIDEO_CAPABILITY_SKIP_QUIRKS;
screen_info->flags = VIDEO_FLAGS_NOCURSOR; screen_info->flags = VIDEO_FLAGS_NOCURSOR;
screen_info->lfb_base = (uint32_t)fbinfo.framebuffer_addr; screen_info->lfb_base = (uint32_t)fbs[0].framebuffer_addr;
screen_info->ext_lfb_base = (uint32_t)(fbinfo.framebuffer_addr >> 32); screen_info->ext_lfb_base = (uint32_t)(fbs[0].framebuffer_addr >> 32);
screen_info->lfb_size = fbinfo.framebuffer_pitch * fbinfo.framebuffer_height; screen_info->lfb_size = fbs[0].framebuffer_pitch * fbs[0].framebuffer_height;
screen_info->lfb_width = fbinfo.framebuffer_width; screen_info->lfb_width = fbs[0].framebuffer_width;
screen_info->lfb_height = fbinfo.framebuffer_height; screen_info->lfb_height = fbs[0].framebuffer_height;
screen_info->lfb_depth = fbinfo.framebuffer_bpp; screen_info->lfb_depth = fbs[0].framebuffer_bpp;
screen_info->lfb_linelength = fbinfo.framebuffer_pitch; screen_info->lfb_linelength = fbs[0].framebuffer_pitch;
screen_info->red_size = fbinfo.red_mask_size; screen_info->red_size = fbs[0].red_mask_size;
screen_info->red_pos = fbinfo.red_mask_shift; screen_info->red_pos = fbs[0].red_mask_shift;
screen_info->green_size = fbinfo.green_mask_size; screen_info->green_size = fbs[0].green_mask_size;
screen_info->green_pos = fbinfo.green_mask_shift; screen_info->green_pos = fbs[0].green_mask_shift;
screen_info->blue_size = fbinfo.blue_mask_size; screen_info->blue_size = fbs[0].blue_mask_size;
screen_info->blue_pos = fbinfo.blue_mask_shift; 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) #if defined (BIOS)
screen_info->orig_video_isVGA = VIDEO_TYPE_VLFB; screen_info->orig_video_isVGA = VIDEO_TYPE_VLFB;
@ -564,12 +567,6 @@ set_textmode:;
#if defined (UEFI) #if defined (UEFI)
no_fb:; no_fb:;
#endif #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 // RSDP
/////////////////////////////////////// ///////////////////////////////////////

View File

@ -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->bootloader_name = (uint32_t)(size_t)lowmem_bootname - mb1_info_slide;
multiboot1_info->flags |= (1 << 9); multiboot1_info->flags |= (1 << 9);
if (term != NULL) { term_notready();
term->deinit(term, pmm_free);
term = NULL; size_t req_width = 0;
} size_t req_height = 0;
size_t req_bpp = 0;
if (header.flags & (1 << 2)) { if (header.flags & (1 << 2)) {
size_t req_width = header.fb_width; req_width = header.fb_width;
size_t req_height = header.fb_height; req_height = header.fb_height;
size_t req_bpp = header.fb_bpp; req_bpp = header.fb_bpp;
if (header.fb_mode == 0) { if (header.fb_mode == 0) {
#if defined (UEFI)
modeset:;
#endif
char *resolution = config_get_value(config, 0, "RESOLUTION"); char *resolution = config_get_value(config, 0, "RESOLUTION");
if (resolution != NULL) if (resolution != NULL)
parse_resolution(&req_width, &req_height, &req_bpp, resolution); parse_resolution(&req_width, &req_height, &req_bpp, resolution);
struct fb_info fbinfo; struct fb_info *fbs;
if (!fb_init(&fbinfo, req_width, req_height, req_bpp)) { size_t fbs_count;
fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp);
if (fbs_count == 0) {
#if defined (UEFI) #if defined (UEFI)
goto skip_modeset; goto skip_modeset;
#elif defined (BIOS) #elif defined (BIOS)
textmode:
vga_textmode_init(false); vga_textmode_init(false);
multiboot1_info->fb_addr = 0xb8000; multiboot1_info->fb_addr = 0xb8000;
multiboot1_info->fb_width = term->cols; multiboot1_info->fb_width = 80;
multiboot1_info->fb_height = term->rows; multiboot1_info->fb_height = 25;
multiboot1_info->fb_bpp = 16; multiboot1_info->fb_bpp = 16;
multiboot1_info->fb_pitch = 2 * term->cols; multiboot1_info->fb_pitch = 2 * 80;
multiboot1_info->fb_type = 2; multiboot1_info->fb_type = 2;
#endif #endif
} else { } else {
multiboot1_info->fb_addr = (uint64_t)fbinfo.framebuffer_addr; multiboot1_info->fb_addr = (uint64_t)fbs[0].framebuffer_addr;
multiboot1_info->fb_width = fbinfo.framebuffer_width; multiboot1_info->fb_width = fbs[0].framebuffer_width;
multiboot1_info->fb_height = fbinfo.framebuffer_height; multiboot1_info->fb_height = fbs[0].framebuffer_height;
multiboot1_info->fb_bpp = fbinfo.framebuffer_bpp; multiboot1_info->fb_bpp = fbs[0].framebuffer_bpp;
multiboot1_info->fb_pitch = fbinfo.framebuffer_pitch; multiboot1_info->fb_pitch = fbs[0].framebuffer_pitch;
multiboot1_info->fb_type = 1; multiboot1_info->fb_type = 1;
multiboot1_info->fb_red_mask_size = fbinfo.red_mask_size; multiboot1_info->fb_red_mask_size = fbs[0].red_mask_size;
multiboot1_info->fb_red_mask_shift = fbinfo.red_mask_shift; multiboot1_info->fb_red_mask_shift = fbs[0].red_mask_shift;
multiboot1_info->fb_green_mask_size = fbinfo.green_mask_size; multiboot1_info->fb_green_mask_size = fbs[0].green_mask_size;
multiboot1_info->fb_green_mask_shift = fbinfo.green_mask_shift; multiboot1_info->fb_green_mask_shift = fbs[0].green_mask_shift;
multiboot1_info->fb_blue_mask_size = fbinfo.blue_mask_size; multiboot1_info->fb_blue_mask_size = fbs[0].blue_mask_size;
multiboot1_info->fb_blue_mask_shift = fbinfo.blue_mask_shift; multiboot1_info->fb_blue_mask_shift = fbs[0].blue_mask_shift;
} }
} else { } else {
#if defined (UEFI) #if defined (UEFI)
print("multiboot1: Warning: Cannot use text mode with UEFI\n"); print("multiboot1: Warning: Cannot use text mode with UEFI\n");
struct fb_info fbinfo; goto modeset;
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;
#elif defined (BIOS) #elif defined (BIOS)
vga_textmode_init(false); goto textmode;
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;
#endif #endif
} }

View File

@ -516,29 +516,36 @@ noreturn void multiboot2_load(char *config, char* cmdline) {
tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
tag->common.size = sizeof(struct multiboot_tag_framebuffer); tag->common.size = sizeof(struct multiboot_tag_framebuffer);
if (term != NULL) { term_notready();
term->deinit(term, pmm_free);
term = NULL; size_t req_width = 0;
} size_t req_height = 0;
size_t req_bpp = 0;
if (fbtag) { if (fbtag) {
size_t req_width = fbtag->width; req_width = fbtag->width;
size_t req_height = fbtag->height; req_height = fbtag->height;
size_t req_bpp = fbtag->depth; req_bpp = fbtag->depth;
#if defined (UEFI)
modeset:;
#endif
char *resolution = config_get_value(config, 0, "RESOLUTION"); char *resolution = config_get_value(config, 0, "RESOLUTION");
if (resolution != NULL) if (resolution != NULL)
parse_resolution(&req_width, &req_height, &req_bpp, resolution); parse_resolution(&req_width, &req_height, &req_bpp, resolution);
struct fb_info fbinfo; struct fb_info *fbs;
if (!fb_init(&fbinfo, req_width, req_height, req_bpp)) { size_t fbs_count;
fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp);
if (fbs_count == 0) {
#if defined (BIOS) #if defined (BIOS)
textmode:
vga_textmode_init(false); vga_textmode_init(false);
tag->common.framebuffer_addr = 0xb8000; tag->common.framebuffer_addr = 0xb8000;
tag->common.framebuffer_pitch = 2 * term->cols; tag->common.framebuffer_pitch = 2 * 80;
tag->common.framebuffer_width = term->cols; tag->common.framebuffer_width = 80;
tag->common.framebuffer_height = term->rows; tag->common.framebuffer_height = 25;
tag->common.framebuffer_bpp = 16; tag->common.framebuffer_bpp = 16;
tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT; tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT;
#elif defined (UEFI) #elif defined (UEFI)
@ -549,54 +556,26 @@ noreturn void multiboot2_load(char *config, char* cmdline) {
} }
#endif #endif
} else { } else {
tag->common.framebuffer_addr = fbinfo.framebuffer_addr; tag->common.framebuffer_addr = fbs[0].framebuffer_addr;
tag->common.framebuffer_pitch = fbinfo.framebuffer_pitch; tag->common.framebuffer_pitch = fbs[0].framebuffer_pitch;
tag->common.framebuffer_width = fbinfo.framebuffer_width; tag->common.framebuffer_width = fbs[0].framebuffer_width;
tag->common.framebuffer_height = fbinfo.framebuffer_height; tag->common.framebuffer_height = fbs[0].framebuffer_height;
tag->common.framebuffer_bpp = fbinfo.framebuffer_bpp; tag->common.framebuffer_bpp = fbs[0].framebuffer_bpp;
tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB; // We only support RGB for VBE 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_field_position = fbs[0].red_mask_shift;
tag->framebuffer_red_mask_size = fbinfo.red_mask_size; tag->framebuffer_red_mask_size = fbs[0].red_mask_size;
tag->framebuffer_green_field_position = fbinfo.green_mask_shift; tag->framebuffer_green_field_position = fbs[0].green_mask_shift;
tag->framebuffer_green_mask_size = fbinfo.green_mask_size; tag->framebuffer_green_mask_size = fbs[0].green_mask_size;
tag->framebuffer_blue_field_position = fbinfo.blue_mask_shift; tag->framebuffer_blue_field_position = fbs[0].blue_mask_shift;
tag->framebuffer_blue_mask_size = fbinfo.blue_mask_size; tag->framebuffer_blue_mask_size = fbs[0].blue_mask_size;
} }
} else { } else {
#if defined (UEFI) #if defined (UEFI)
print("multiboot2: Warning: Cannot use text mode with UEFI\n"); print("multiboot2: Warning: Cannot use text mode with UEFI\n");
struct fb_info fbinfo; goto modeset;
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;
#elif defined (BIOS) #elif defined (BIOS)
vga_textmode_init(false); goto textmode;
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;
#endif #endif
} }