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>
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;

View File

@ -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

View File

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

View File

@ -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

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) {
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;

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;
void vga_textmode_init(bool managed) {
if (term != NULL) {
term->deinit(term, pmm_free);
term = NULL;
}
term_notready();
if (quiet) {
return;
@ -270,6 +267,13 @@ void vga_textmode_init(bool managed) {
current_video_mode = 0x3;
}
terms = ext_mem_alloc(sizeof(void *));
terms_i = 1;
terms[0] = ext_mem_alloc(sizeof(struct term_context));
struct term_context *term = terms[0];
struct textmode_context *ctx = &term_local_struct;
term = &term_local_struct.term;

View File

@ -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

View File

@ -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
}

View File

@ -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;
uint8_t memory_model;
uint8_t red_mask_size;
uint8_t red_mask_shift;
uint8_t green_mask_size;
uint8_t green_mask_shift;
uint8_t blue_mask_size;
uint8_t blue_mask_shift;
bool default_res;
uint64_t framebuffer_addr;
struct edid_info_struct *edid;
uint64_t mode_count;
struct fb_info *mode_list;
};
bool fb_init(struct fb_info *ret,
void fb_init(struct fb_info **ret, size_t *_fbs_count,
uint64_t target_width, uint64_t target_height, uint16_t target_bpp);
struct fb_info *fb_get_mode_list(size_t *count);
void fb_clear(struct fb_info *fb);
#endif

View File

@ -360,8 +360,6 @@ static const uint8_t builtin_font[] = {
0x00, 0x00, 0x00, 0x00
};
struct fb_info fbinfo;
static struct image *background;
static size_t margin = 64;
@ -389,10 +387,10 @@ static inline uint32_t colour_blend(uint32_t fg, uint32_t bg) {
return ARGB(0, r, g, b);
}
static uint32_t blend_gradient_from_box(size_t x, size_t y, uint32_t bg_px, uint32_t hex) {
static uint32_t blend_gradient_from_box(struct fb_info *fb, size_t x, size_t y, uint32_t bg_px, uint32_t hex) {
size_t distance, x_distance, y_distance;
size_t gradient_stop_x = fbinfo.framebuffer_width - margin;
size_t gradient_stop_y = fbinfo.framebuffer_height - margin;
size_t gradient_stop_x = fb->framebuffer_width - margin;
size_t gradient_stop_y = fb->framebuffer_height - margin;
if (x < margin)
x_distance = margin - x;
@ -427,7 +425,7 @@ static size_t fixedp6_to_int(fixedp6 value) { return value / 64; }
static fixedp6 int_to_fixedp6(size_t value) { return value * 64; }
// Draw rect at coordinates, copying from the image to the fb and canvas, applying fn on every pixel
__attribute__((always_inline)) static inline void genloop(size_t xstart, size_t xend, size_t ystart, size_t yend, uint32_t (*blend)(size_t x, size_t y, uint32_t orig)) {
__attribute__((always_inline)) static inline void genloop(struct fb_info *fb, size_t xstart, size_t xend, size_t ystart, size_t yend, uint32_t (*blend)(struct fb_info *fb, size_t x, size_t y, uint32_t orig)) {
uint8_t *img = background->img;
const size_t img_width = background->img_width, img_height = background->img_height, img_pitch = background->pitch, colsize = background->bpp / 8;
@ -436,10 +434,10 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t
for (size_t y = ystart; y < yend; y++) {
size_t image_y = y % img_height, image_x = xstart % img_width;
const size_t off = img_pitch * (img_height - 1 - image_y);
size_t canvas_off = fbinfo.framebuffer_width * y;
size_t canvas_off = fb->framebuffer_width * y;
for (size_t x = xstart; x < xend; x++) {
uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off);
uint32_t i = blend(x, y, img_pixel);
uint32_t i = blend(fb, x, y, img_pixel);
bg_canvas[canvas_off + x] = i;
if (image_x++ == img_width) image_x = 0; // image_x = x % img_width, but modulo is too expensive
}
@ -450,10 +448,10 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t
for (size_t y = ystart; y < yend; y++) {
size_t image_y = y - background->y_displacement;
const size_t off = img_pitch * (img_height - 1 - image_y);
size_t canvas_off = fbinfo.framebuffer_width * y;
size_t canvas_off = fb->framebuffer_width * y;
if (image_y >= background->y_size) { /* external part */
for (size_t x = xstart; x < xend; x++) {
uint32_t i = blend(x, y, background->back_colour);
uint32_t i = blend(fb, x, y, background->back_colour);
bg_canvas[canvas_off + x] = i;
}
}
@ -462,7 +460,7 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t
size_t image_x = (x - background->x_displacement);
bool x_external = image_x >= background->x_size;
uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off);
uint32_t i = blend(x, y, x_external ? background->back_colour : img_pixel);
uint32_t i = blend(fb, x, y, x_external ? background->back_colour : img_pixel);
bg_canvas[canvas_off + x] = i;
}
}
@ -473,15 +471,15 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t
// so you can set x = xstart * ratio, and increment by ratio at each iteration
case IMAGE_STRETCHED:
for (size_t y = ystart; y < yend; y++) {
size_t img_y = (y * img_height) / fbinfo.framebuffer_height; // calculate Y with full precision
size_t img_y = (y * img_height) / fb->framebuffer_height; // calculate Y with full precision
size_t off = img_pitch * (img_height - 1 - img_y);
size_t canvas_off = fbinfo.framebuffer_width * y;
size_t canvas_off = fb->framebuffer_width * y;
size_t ratio = int_to_fixedp6(img_width) / fbinfo.framebuffer_width;
size_t ratio = int_to_fixedp6(img_width) / fb->framebuffer_width;
fixedp6 img_x = ratio * xstart;
for (size_t x = xstart; x < xend; x++) {
uint32_t img_pixel = *(uint32_t*)(img + fixedp6_to_int(img_x) * colsize + off);
uint32_t i = blend(x, y, img_pixel);
uint32_t i = blend(fb, x, y, img_pixel);
bg_canvas[canvas_off + x] = i;
img_x += ratio;
}
@ -490,17 +488,17 @@ __attribute__((always_inline)) static inline void genloop(size_t xstart, size_t
}
}
static uint32_t blend_external(size_t x, size_t y, uint32_t orig) { (void)x; (void)y; return orig; }
static uint32_t blend_internal(size_t x, size_t y, uint32_t orig) { (void)x; (void)y; return colour_blend(default_bg, orig); }
static uint32_t blend_margin(size_t x, size_t y, uint32_t orig) { return blend_gradient_from_box(x, y, orig, default_bg); }
static uint32_t blend_external(struct fb_info *fb, size_t x, size_t y, uint32_t orig) { (void)fb; (void)x; (void)y; return orig; }
static uint32_t blend_internal(struct fb_info *fb, size_t x, size_t y, uint32_t orig) { (void)fb; (void)x; (void)y; return colour_blend(default_bg, orig); }
static uint32_t blend_margin(struct fb_info *fb, size_t x, size_t y, uint32_t orig) { return blend_gradient_from_box(fb, x, y, orig, default_bg); }
static void loop_external(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_external); }
static void loop_margin(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_margin); }
static void loop_internal(size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(xstart, xend, ystart, yend, blend_internal); }
static void loop_external(struct fb_info *fb, size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(fb, xstart, xend, ystart, yend, blend_external); }
static void loop_margin(struct fb_info *fb, size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(fb, xstart, xend, ystart, yend, blend_margin); }
static void loop_internal(struct fb_info *fb, size_t xstart, size_t xend, size_t ystart, size_t yend) { genloop(fb, xstart, xend, ystart, yend, blend_internal); }
static void generate_canvas(void) {
static void generate_canvas(struct fb_info *fb) {
if (background) {
bg_canvas_size = fbinfo.framebuffer_width * fbinfo.framebuffer_height * sizeof(uint32_t);
bg_canvas_size = fb->framebuffer_width * fb->framebuffer_height * sizeof(uint32_t);
bg_canvas = ext_mem_alloc(bg_canvas_size);
int64_t margin_no_gradient = (int64_t)margin - margin_gradient;
@ -509,99 +507,76 @@ static void generate_canvas(void) {
margin_no_gradient = 0;
}
size_t scan_stop_x = fbinfo.framebuffer_width - margin_no_gradient;
size_t scan_stop_y = fbinfo.framebuffer_height - margin_no_gradient;
size_t scan_stop_x = fb->framebuffer_width - margin_no_gradient;
size_t scan_stop_y = fb->framebuffer_height - margin_no_gradient;
loop_external(0, fbinfo.framebuffer_width, 0, margin_no_gradient);
loop_external(0, fbinfo.framebuffer_width, scan_stop_y, fbinfo.framebuffer_height);
loop_external(0, margin_no_gradient, margin_no_gradient, scan_stop_y);
loop_external(scan_stop_x, fbinfo.framebuffer_width, margin_no_gradient, scan_stop_y);
loop_external(fb, 0, fb->framebuffer_width, 0, margin_no_gradient);
loop_external(fb, 0, fb->framebuffer_width, scan_stop_y, fb->framebuffer_height);
loop_external(fb, 0, margin_no_gradient, margin_no_gradient, scan_stop_y);
loop_external(fb, scan_stop_x, fb->framebuffer_width, margin_no_gradient, scan_stop_y);
size_t gradient_stop_x = fbinfo.framebuffer_width - margin;
size_t gradient_stop_y = fbinfo.framebuffer_height - margin;
size_t gradient_stop_x = fb->framebuffer_width - margin;
size_t gradient_stop_y = fb->framebuffer_height - margin;
if (margin_gradient) {
loop_margin(margin_no_gradient, scan_stop_x, margin_no_gradient, margin);
loop_margin(margin_no_gradient, scan_stop_x, gradient_stop_y, scan_stop_y);
loop_margin(margin_no_gradient, margin, margin, gradient_stop_y);
loop_margin(gradient_stop_x, scan_stop_x, margin, gradient_stop_y);
loop_margin(fb, margin_no_gradient, scan_stop_x, margin_no_gradient, margin);
loop_margin(fb, margin_no_gradient, scan_stop_x, gradient_stop_y, scan_stop_y);
loop_margin(fb, margin_no_gradient, margin, margin, gradient_stop_y);
loop_margin(fb, gradient_stop_x, scan_stop_x, margin, gradient_stop_y);
}
loop_internal(margin, gradient_stop_x, margin, gradient_stop_y);
loop_internal(fb, margin, gradient_stop_x, margin, gradient_stop_y);
} else {
bg_canvas = NULL;
}
}
static bool last_serial = false;
static char *last_config = NULL;
bool gterm_init(struct fb_info **_fbs, size_t *_fbs_count,
char *config, size_t width, size_t height) {
static struct fb_info *fbs;
static size_t fbs_count;
static bool prev_valid = false;
static char *prev_config;
static size_t prev_width, prev_height;
if (prev_valid && config == prev_config && width == prev_width && height == prev_height) {
*_fbs = fbs;
*_fbs_count = fbs_count;
reset_term();
return true;
}
prev_valid = false;
bool gterm_init(char *config, size_t width, size_t height) {
if (quiet) {
if (term != NULL) {
term->deinit(term, pmm_free);
term = NULL;
}
term_notready();
return false;
}
#if defined (UEFI)
if (serial || COM_OUTPUT) {
if (term != NULL) {
term->deinit(term, pmm_free);
term = NULL;
}
term_fallback();
return true;
}
#endif
if (term != NULL
&& term_backend == GTERM
&& fbinfo.default_res == true
&& width == 0
&& height == 0
&& fbinfo.framebuffer_bpp == 32
&& serial == last_serial
&& config == last_config) {
term->clear(term, true);
return true;
}
if (term != NULL
&& term_backend == GTERM
&& fbinfo.framebuffer_width == width
&& fbinfo.framebuffer_height == height
&& fbinfo.framebuffer_bpp == 32
&& serial == last_serial
&& config == last_config) {
term->clear(term, true);
return true;
}
if (term != NULL) {
term->deinit(term, pmm_free);
term = NULL;
}
term_notready();
// We force bpp to 32
if (!fb_init(&fbinfo, width, height, 32)) {
return false;
fb_init(&fbs, &fbs_count, width, height, 32);
if (_fbs != NULL) {
*_fbs = fbs;
}
if (_fbs_count != NULL) {
*_fbs_count = fbs_count;
}
// Ensure this is xRGB8888, we only support that for the menu
if (fbinfo.red_mask_size != 8
|| fbinfo.red_mask_shift != 16
|| fbinfo.green_mask_size != 8
|| fbinfo.green_mask_shift != 8
|| fbinfo.blue_mask_size != 8
|| fbinfo.blue_mask_shift != 0) {
if (fbs_count == 0) {
return false;
}
last_serial = serial;
last_config = config;
// default scheme
margin = 64;
margin_gradient = 4;
@ -702,20 +677,6 @@ bool gterm_init(char *config, size_t width, size_t height) {
margin_gradient = strtoui(theme_margin_gradient, NULL, 10);
}
if (background != NULL) {
char *background_layout = config_get_value(config, 0, "TERM_WALLPAPER_STYLE");
if (background_layout != NULL && strcmp(background_layout, "centered") == 0) {
char *background_colour = config_get_value(config, 0, "TERM_BACKDROP");
if (background_colour == NULL)
background_colour = "0";
uint32_t bg_col = strtoui(background_colour, NULL, 16);
image_make_centered(background, fbinfo.framebuffer_width, fbinfo.framebuffer_height, bg_col);
} else if (background_layout != NULL && strcmp(background_layout, "tiled") == 0) {
} else {
image_make_stretched(background, fbinfo.framebuffer_width, fbinfo.framebuffer_height);
}
}
size_t font_width = 8;
size_t font_height = 16;
size_t font_size = (font_width * font_height * FBTERM_FONT_GLYPHS) / 8;
@ -775,38 +736,105 @@ no_load_font:;
}
}
generate_canvas();
terms_i = 0;
terms = ext_mem_alloc(fbs_count * sizeof(void *));
term = fbterm_init(ext_mem_alloc,
(void *)(uintptr_t)fbinfo.framebuffer_addr,
fbinfo.framebuffer_width, fbinfo.framebuffer_height, fbinfo.framebuffer_pitch,
bg_canvas,
ansi_colours, ansi_bright_colours,
&default_bg, &default_fg,
font, font_width, font_height, font_spacing,
font_scale_x, font_scale_y,
margin);
for (size_t i = 0; i < fbs_count; i++) {
struct fb_info *fb = &fbs[i];
pmm_free(font, FONT_MAX);
if (bg_canvas != NULL) {
pmm_free(bg_canvas, bg_canvas_size);
// Ensure this is xRGB8888, we only support that for the menu
if (fb->red_mask_size != 8
|| fb->red_mask_shift != 16
|| fb->green_mask_size != 8
|| fb->green_mask_shift != 8
|| fb->blue_mask_size != 8
|| fb->blue_mask_shift != 0) {
continue;
}
if (background != NULL) {
char *background_layout = config_get_value(config, 0, "TERM_WALLPAPER_STYLE");
if (background_layout != NULL && strcmp(background_layout, "centered") == 0) {
char *background_colour = config_get_value(config, 0, "TERM_BACKDROP");
if (background_colour == NULL)
background_colour = "0";
uint32_t bg_col = strtoui(background_colour, NULL, 16);
image_make_centered(background, fb->framebuffer_width, fb->framebuffer_height, bg_col);
} else if (background_layout != NULL && strcmp(background_layout, "tiled") == 0) {
} else {
image_make_stretched(background, fb->framebuffer_width, fb->framebuffer_height);
}
}
generate_canvas(fb);
terms[terms_i] = fbterm_init(ext_mem_alloc,
(void *)(uintptr_t)fb->framebuffer_addr,
fb->framebuffer_width, fb->framebuffer_height, fb->framebuffer_pitch,
bg_canvas,
ansi_colours, ansi_bright_colours,
&default_bg, &default_fg,
font, font_width, font_height, font_spacing,
font_scale_x, font_scale_y,
margin);
if (terms[terms_i] != NULL) {
terms_i++;
}
if (bg_canvas != NULL) {
pmm_free(bg_canvas, bg_canvas_size);
}
}
if (term == NULL) {
pmm_free(font, FONT_MAX);
if (terms_i == 0) {
return false;
}
if (serial) {
term->cols = term->cols > 80 ? 80 : term->cols;
term->rows = term->rows > 24 ? 24 : term->rows;
for (size_t i = 0; i < terms_i; i++) {
struct term_context *term = terms[i];
if (serial) {
term->cols = term->cols > 80 ? 80 : term->cols;
term->rows = term->rows > 24 ? 24 : term->rows;
}
}
term->in_bootloader = true;
size_t min_cols = (size_t)-1;
size_t min_rows = (size_t)-1;
term_context_reinit(term);
term->full_refresh(term);
for (size_t i = 0; i < terms_i; i++) {
struct term_context *term = terms[i];
if (term->cols < min_cols) {
min_cols = term->cols;
}
if (term->rows < min_rows) {
min_rows = term->rows;
}
}
for (size_t i = 0; i < terms_i; i++) {
struct term_context *term = terms[i];
term->cols = min_cols;
term->rows = min_rows;
term->in_bootloader = true;
term_context_reinit(term);
term->full_refresh(term);
}
term_backend = GTERM;
prev_config = config;
prev_height = height;
prev_width = width;
prev_valid = true;
return true;
}

View File

@ -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

View File

@ -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);

View File

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

View File

@ -8,95 +8,28 @@
#include <drivers/vga_textmode.h>
#include <term/backends/framebuffer.h>
#if defined (BIOS)
int current_video_mode = -1;
#endif
struct term_context **terms = NULL;
size_t terms_i = 0;
int term_backend = _NOT_READY;
struct term_context *term;
void term_notready(void) {
for (size_t i = 0; i < terms_i; i++) {
struct term_context *term = terms[i];
static struct term_context term_local_struct;
// --- notready ---
static void notready_raw_putchar(struct term_context *ctx, uint8_t c) {
(void)ctx;
(void)c;
}
static void notready_clear(struct term_context *ctx, bool move) {
(void)ctx;
(void)move;
}
static void notready_void(struct term_context *ctx) {
(void)ctx;
}
static void notready_set_cursor_pos(struct term_context *ctx, size_t x, size_t y) {
(void)ctx;
(void)x; (void)y;
}
static void notready_get_cursor_pos(struct term_context *ctx, size_t *x, size_t *y) {
(void)ctx;
*x = 0;
*y = 0;
}
static void notready_size_t(struct term_context *ctx, size_t n) {
(void)ctx;
(void)n;
}
static bool notready_disable(struct term_context *ctx) {
(void)ctx;
return false;
}
static void notready_move_character(struct term_context *ctx, size_t a, size_t b, size_t c, size_t d) {
(void)ctx;
(void)a; (void)b; (void)c; (void)d;
}
static void notready_uint32_t(struct term_context *ctx, uint32_t n) {
(void)ctx;
(void)n;
}
static void notready_deinit(struct term_context *ctx, void (*_free)(void *, size_t)) {
(void)ctx;
(void)_free;
}
static void term_notready(void) {
if (term != NULL) {
term->deinit(term, pmm_free);
term = NULL;
}
term = &term_local_struct;
pmm_free(terms, terms_i * sizeof(void *));
term->raw_putchar = notready_raw_putchar;
term->clear = notready_clear;
term->enable_cursor = notready_void;
term->disable_cursor = notready_disable;
term->set_cursor_pos = notready_set_cursor_pos;
term->get_cursor_pos = notready_get_cursor_pos;
term->set_text_fg = notready_size_t;
term->set_text_bg = notready_size_t;
term->set_text_fg_bright = notready_size_t;
term->set_text_bg_bright = notready_size_t;
term->set_text_fg_rgb = notready_uint32_t;
term->set_text_bg_rgb = notready_uint32_t;
term->set_text_fg_default = notready_void;
term->set_text_bg_default = notready_void;
term->move_character = notready_move_character;
term->scroll = notready_void;
term->revscroll = notready_void;
term->swap_palette = notready_void;
term->save_state = notready_void;
term->restore_state = notready_void;
term->double_buffer_flush = notready_void;
term->full_refresh = notready_void;
term->deinit = notready_deinit;
term->cols = 80;
term->rows = 24;
terms_i = 0;
terms = NULL;
term_backend = _NOT_READY;
term_context_reinit(term);
term->in_bootloader = true;
}
// --- fallback ---
@ -162,7 +95,7 @@ static void fallback_scroll(struct term_context *ctx) {
(void)ctx;
size_t x, y;
fallback_get_cursor_pos(NULL, &x, &y);
fallback_set_cursor_pos(NULL, term->cols - 1, term->rows - 1);
fallback_set_cursor_pos(NULL, ctx->cols - 1, ctx->rows - 1);
fallback_raw_putchar(NULL, ' ');
fallback_set_cursor_pos(NULL, x, y);
}
@ -173,7 +106,7 @@ static size_t cursor_x = 0, cursor_y = 0;
static void fallback_scroll(struct term_context *ctx) {
(void)ctx;
gST->ConOut->SetCursorPosition(gST->ConOut, term->cols - 1, term->rows - 1);
gST->ConOut->SetCursorPosition(gST->ConOut, ctx->cols - 1, ctx->rows - 1);
CHAR16 string[2];
string[0] = ' ';
string[1] = 0;
@ -182,7 +115,7 @@ static void fallback_scroll(struct term_context *ctx) {
}
static void fallback_raw_putchar(struct term_context *ctx, uint8_t c) {
if (!ctx->scroll_enabled && cursor_x == term->cols - 1 && cursor_y == term->rows - 1) {
if (!ctx->scroll_enabled && cursor_x == ctx->cols - 1 && cursor_y == ctx->rows - 1) {
return;
}
gST->ConOut->EnableCursor(gST->ConOut, true);
@ -190,9 +123,9 @@ static void fallback_raw_putchar(struct term_context *ctx, uint8_t c) {
string[0] = c;
string[1] = 0;
gST->ConOut->OutputString(gST->ConOut, string);
if (++cursor_x >= term->cols) {
if (++cursor_x >= ctx->cols) {
cursor_x = 0;
if (++cursor_y >= term->rows) {
if (++cursor_y >= ctx->rows) {
cursor_y--;
}
}
@ -210,7 +143,7 @@ static void fallback_clear(struct term_context *ctx, bool move) {
static void fallback_set_cursor_pos(struct term_context *ctx, size_t x, size_t y) {
(void)ctx;
if (x >= term->cols || y >= term->rows) {
if (x >= ctx->cols || y >= ctx->rows) {
return;
}
gST->ConOut->SetCursorPosition(gST->ConOut, x, y);
@ -225,13 +158,45 @@ static void fallback_get_cursor_pos(struct term_context *ctx, size_t *x, size_t
}
#endif
static bool dummy_handle(void) {
return true;
}
void term_fallback(void) {
term_notready();
#if defined (UEFI)
if (!efi_boot_services_exited) {
#endif
terms = ext_mem_alloc(sizeof(void *));
terms_i = 1;
terms[0] = ext_mem_alloc(sizeof(struct term_context));
struct term_context *term = terms[0];
fallback_clear(NULL, true);
term->enable_cursor = (void *)dummy_handle;
term->disable_cursor = (void *)dummy_handle;
term->set_text_fg = (void *)dummy_handle;
term->set_text_bg = (void *)dummy_handle;
term->set_text_fg_bright = (void *)dummy_handle;
term->set_text_bg_bright = (void *)dummy_handle;
term->set_text_fg_rgb = (void *)dummy_handle;
term->set_text_bg_rgb = (void *)dummy_handle;
term->set_text_fg_default = (void *)dummy_handle;
term->set_text_bg_default = (void *)dummy_handle;
term->move_character = (void *)dummy_handle;
term->revscroll = (void *)dummy_handle;
term->swap_palette = (void *)dummy_handle;
term->save_state = (void *)dummy_handle;
term->restore_state = (void *)dummy_handle;
term->double_buffer_flush = (void *)dummy_handle;
term->full_refresh = (void *)dummy_handle;
term->deinit = (void *)dummy_handle;
term->raw_putchar = fallback_raw_putchar;
term->clear = fallback_clear;
term->set_cursor_pos = fallback_set_cursor_pos;
@ -264,7 +229,7 @@ extern void set_cursor_pos_helper(size_t x, size_t y);
static uint8_t xfer_buf[TERM_XFER_CHUNK];
#endif
static uint64_t context_size(void) {
static uint64_t context_size(struct term_context *term) {
switch (term_backend) {
#if defined (BIOS)
case TEXTMODE:
@ -285,7 +250,7 @@ static uint64_t context_size(void) {
}
}
static void context_save(uint64_t buf) {
static void context_save(struct term_context *term, uint64_t buf) {
switch (term_backend) {
#if defined (BIOS)
case TEXTMODE: {
@ -320,7 +285,7 @@ static void context_save(uint64_t buf) {
}
}
static void context_restore(uint64_t buf) {
static void context_restore(struct term_context *term, uint64_t buf) {
switch (term_backend) {
#if defined (BIOS)
case TEXTMODE: {
@ -355,19 +320,19 @@ static void context_restore(uint64_t buf) {
}
}
void _term_write(uint64_t buf, uint64_t count) {
void _term_write(struct term_context *term, uint64_t buf, uint64_t count) {
switch (count) {
case TERM_CTX_SIZE: {
uint64_t ret = context_size();
uint64_t ret = context_size(term);
memcpy32to64(buf, (uint64_t)(uintptr_t)&ret, sizeof(uint64_t));
return;
}
case TERM_CTX_SAVE: {
context_save(buf);
context_save(term, buf);
return;
}
case TERM_CTX_RESTORE: {
context_restore(buf);
context_restore(term, buf);
return;
}
case TERM_FULL_REFRESH: {

View File

@ -13,28 +13,46 @@ enum {
FALLBACK
};
#if defined (BIOS)
extern int current_video_mode;
extern int term_backend;
#endif
extern struct term_context *term;
extern struct term_context **terms;
extern size_t terms_i;
extern int term_backend;
#define TERM_CTX_SIZE ((uint64_t)(-1))
#define TERM_CTX_SAVE ((uint64_t)(-2))
#define TERM_CTX_RESTORE ((uint64_t)(-3))
#define TERM_FULL_REFRESH ((uint64_t)(-4))
#define FOR_TERM(...) do { \
for (size_t FOR_TERM_i = 0; FOR_TERM_i < terms_i; FOR_TERM_i++) { \
struct term_context *TERM = terms[FOR_TERM_i]; \
__VA_ARGS__ \
; \
} \
} while (0)
inline void reset_term(void) {
term->autoflush = true;
term->enable_cursor(term);
print("\e[2J\e[H");
term->double_buffer_flush(term);
for (size_t i = 0; i < terms_i; i++) {
struct term_context *term = terms[i];
print("\e[2J\e[H");
term_context_reinit(term);
term->in_bootloader = true;
term->enable_cursor(term);
term->double_buffer_flush(term);
}
}
inline void set_cursor_pos_helper(size_t x, size_t y) {
print("\e[%u;%uH", (int)y + 1, (int)x + 1);
}
void term_notready(void);
void term_fallback(void);
void _term_write(uint64_t buf, uint64_t count);
void _term_write(struct term_context *term, uint64_t buf, uint64_t count);
#endif

View File

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

View File

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

View File

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

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

View File

@ -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
///////////////////////////////////////

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->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
}

View File

@ -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
}