lib/fb: Clear the target framebuffer in fb_init under write-combining
diff --git a/common/drivers/vga_textmode.c b/common/drivers/vga_textmode.c
index 66a80367..0a5c5961 100644
--- a/common/drivers/vga_textmode.c
+++ b/common/drivers/vga_textmode.c
@@ -267,7 +267,7 @@ static void text_deinit(struct flanterm_context *_ctx, void (*_free)(void *, siz
}
void vga_textmode_init(bool managed) {
- term_notready(true);
+ term_notready();
if (quiet) {
return;
diff --git a/common/entry.s3.c b/common/entry.s3.c
index ddf2d6e4..d6b86ebb 100644
--- a/common/entry.s3.c
+++ b/common/entry.s3.c
@@ -211,7 +211,7 @@ noreturn void stage3_common(void) {
#endif
#endif
- term_notready(true);
+ term_notready();
#if defined (UEFI)
init_bli();
diff --git a/common/lib/fb.c b/common/lib/fb.c
index e9922e5f..57fffc90 100644
--- a/common/lib/fb.c
+++ b/common/lib/fb.c
@@ -6,13 +6,20 @@
#include <drivers/vbe.h>
#include <drivers/gop.h>
#include <mm/pmm.h>
+#include <mm/mtrr.h>
+#include <mm/efi_pt.h>
#include <sys/cpu.h>
struct fb_info *fb_fbs;
size_t fb_fbs_count = 0;
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 preserve_screen, bool keep_wc) {
+ if (quiet) {
+ preserve_screen = true;
+ }
+
#if defined (BIOS)
*ret = ext_mem_alloc(sizeof(struct fb_info));
if (init_vbe(*ret, target_width, target_height, target_bpp)) {
@@ -32,6 +39,45 @@ void fb_init(struct fb_info **ret, size_t *_fbs_count,
fb_fbs = *ret;
fb_fbs_count = *_fbs_count;
+
+ // Map the framebuffers as write-combining so the clear (and, when kept,
+ // terminal rendering) is fast. keep_wc leaves it active for the caller.
+ bool want_wc = keep_wc || !preserve_screen;
+
+#if defined (__i386__) || defined (__x86_64__)
+ if (want_wc) {
+ for (size_t i = 0; i < *_fbs_count; i++) {
+ uint64_t fb_size = (uint64_t)(*ret)[i].framebuffer_pitch
+ * (*ret)[i].framebuffer_height;
+ if (fb_size == 0) {
+ continue;
+ }
+#if defined (__x86_64__) && defined (UEFI)
+ efi_pt_set_fb_wc((*ret)[i].framebuffer_addr, fb_size);
+#else
+ mtrr_wc_add_fb_range((*ret)[i].framebuffer_addr, fb_size);
+#endif
+ }
+ }
+#endif
+
+ if (!preserve_screen) {
+ for (size_t i = 0; i < *_fbs_count; i++) {
+ fb_clear(&(*ret)[i]);
+ }
+ }
+
+#if defined (__i386__) || defined (__x86_64__)
+ if (want_wc && !keep_wc) {
+#if defined (__x86_64__) && defined (UEFI)
+ efi_pt_restore();
+#else
+ mtrr_restore();
+#endif
+ }
+#else
+ (void)want_wc;
+#endif
}
void fb_clear(struct fb_info *fb) {
diff --git a/common/lib/fb.h b/common/lib/fb.h
index bb55b8d2..cd25bce0 100644
--- a/common/lib/fb.h
+++ b/common/lib/fb.h
@@ -37,7 +37,8 @@ extern struct fb_info *fb_fbs;
extern size_t fb_fbs_count;
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 preserve_screen, bool keep_wc);
void fb_clear(struct fb_info *fb);
diff --git a/common/lib/gterm.c b/common/lib/gterm.c
index 4a352c7b..55f0599e 100644
--- a/common/lib/gterm.c
+++ b/common/lib/gterm.c
@@ -10,8 +10,6 @@
#include <lib/image.h>
#include <lib/rand.h>
#include <mm/pmm.h>
-#include <mm/mtrr.h>
-#include <mm/efi_pt.h>
#include <flanterm.h>
#include <flanterm_backends/fb.h>
#include <lib/term.h>
@@ -784,7 +782,7 @@ bool gterm_init(struct fb_info **_fbs, size_t *_fbs_count,
prev_valid = false;
if (quiet) {
- term_notready(true);
+ term_notready();
return false;
}
@@ -795,10 +793,10 @@ bool gterm_init(struct fb_info **_fbs, size_t *_fbs_count,
}
#endif
- term_notready(true);
+ term_notready();
// We force bpp to 32
- fb_init(&fbs, &fbs_count, width, height, 32);
+ fb_init(&fbs, &fbs_count, width, height, 32, true, true);
if (_fbs != NULL) {
*_fbs = fbs;
@@ -811,23 +809,6 @@ bool gterm_init(struct fb_info **_fbs, size_t *_fbs_count,
return false;
}
-#if defined (__i386__) || defined (__x86_64__)
- for (size_t i = 0; i < fbs_count; i++) {
- if (fbs[i].framebuffer_bpp != 32) {
- continue;
- }
- uint64_t fb_size = (uint64_t)fbs[i].framebuffer_pitch * fbs[i].framebuffer_height;
- if (fb_size == 0) {
- continue;
- }
-#if defined (__x86_64__) && defined (UEFI)
- efi_pt_set_fb_wc(fbs[i].framebuffer_addr, fb_size);
-#else
- mtrr_wc_add_fb_range(fbs[i].framebuffer_addr, fb_size);
-#endif
- }
-#endif
-
struct gterm_config cfg;
gterm_parse_config(config, &cfg);
diff --git a/common/lib/panic.s2.c b/common/lib/panic.s2.c
index bdd32220..91753fb6 100644
--- a/common/lib/panic.s2.c
+++ b/common/lib/panic.s2.c
@@ -67,7 +67,7 @@ noreturn void panic(bool allow_menu, const char *fmt, ...) {
getchar();
// This fixes a crash
- term_notready(true);
+ term_notready();
menu(false);
/*
diff --git a/common/lib/term.c b/common/lib/term.c
index 201c70d6..44e07a75 100644
--- a/common/lib/term.c
+++ b/common/lib/term.c
@@ -20,19 +20,7 @@ size_t terms_i = 0;
int term_backend = _NOT_READY;
-void term_notready(bool preserve_screen) {
- if (quiet) {
- preserve_screen = true;
- }
-
- if (!preserve_screen) {
- for (size_t i = 0; i < fb_fbs_count; i++) {
- if (fb_fbs[i].framebuffer_bpp == 32) {
- fb_clear(&fb_fbs[i]);
- }
- }
- }
-
+void term_notready(void) {
#if defined (__i386__) || defined (__x86_64__)
#if defined (__x86_64__) && defined (UEFI)
efi_pt_restore();
@@ -251,7 +239,7 @@ void term_fallback(void) {
int prev_backend = term_backend;
#endif
- term_notready(true);
+ term_notready();
terms = ext_mem_alloc(sizeof(void *));
terms_i = 1;
diff --git a/common/lib/term.h b/common/lib/term.h
index 2940aae4..8aa3159d 100644
--- a/common/lib/term.h
+++ b/common/lib/term.h
@@ -53,7 +53,7 @@ static 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(bool preserve_screen);
+void term_notready(void);
void term_fallback(void);
void _term_write(struct flanterm_context *term, uint64_t buf, uint64_t count);
diff --git a/common/protos/chainload.c b/common/protos/chainload.c
index a51315eb..1a885e4d 100644
--- a/common/protos/chainload.c
+++ b/common/protos/chainload.c
@@ -295,7 +295,7 @@ noreturn void chainload(char *config, char *cmdline) {
EFI_DEVICE_PATH_PROTOCOL *efi_file_path = build_relative_efi_file_path(image);
fclose(image);
- term_notready(false);
+ term_notready();
size_t req_width = 0, req_height = 0, req_bpp = 0;
@@ -305,7 +305,7 @@ noreturn void chainload(char *config, char *cmdline) {
struct fb_info *fbinfo;
size_t fb_count;
- fb_init(&fbinfo, &fb_count, req_width, req_height, req_bpp);
+ fb_init(&fbinfo, &fb_count, req_width, req_height, req_bpp, false, false);
size_t cmdline_len = strlen(cmdline);
CHAR16 *new_cmdline;
diff --git a/common/protos/limine.c b/common/protos/limine.c
index 8c6eb6ed..ddfa7350 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -1376,9 +1376,9 @@ FEAT_END
bool preserve_screen = get_request(LIMINE_FLANTERM_FB_INIT_PARAMS_REQUEST_ID) != NULL;
- term_notready(preserve_screen);
+ term_notready();
- fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp);
+ fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, preserve_screen, false);
if (fbs_count == 0) {
goto no_fb;
}
diff --git a/common/protos/linux_risc.c b/common/protos/linux_risc.c
index b33f0566..9c73cb3e 100644
--- a/common/protos/linux_risc.c
+++ b/common/protos/linux_risc.c
@@ -275,9 +275,9 @@ static void prepare_efi_tables(struct boot_param *p, char *config) {
struct fb_info *fbs;
size_t fbs_count;
- term_notready(false);
+ term_notready();
- fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp);
+ fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false, false);
// TODO(qookie): Let the user pick a framebuffer if there's > 1
if (fbs_count > 0) {
diff --git a/common/protos/linux_x86.c b/common/protos/linux_x86.c
index def4c088..1bec1f3b 100644
--- a/common/protos/linux_x86.c
+++ b/common/protos/linux_x86.c
@@ -544,7 +544,7 @@ no_modules:;
// Video
///////////////////////////////////////
- term_notready(false);
+ term_notready();
struct screen_info *screen_info = &boot_params->screen_info;
@@ -569,7 +569,7 @@ no_modules:;
#if defined (UEFI)
gop_force_16 = true;
#endif
- fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp);
+ fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false, false);
if (fbs_count == 0) {
#if defined (UEFI)
goto no_fb;
diff --git a/common/protos/multiboot1.c b/common/protos/multiboot1.c
index c856bf0f..dabfe142 100644
--- a/common/protos/multiboot1.c
+++ b/common/protos/multiboot1.c
@@ -405,7 +405,7 @@ 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);
- term_notready(false);
+ term_notready();
size_t req_width = 0;
size_t req_height = 0;
@@ -436,7 +436,7 @@ modeset:;
struct fb_info *fbs;
size_t fbs_count;
- fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp);
+ fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false, false);
if (fbs_count == 0) {
#if defined (UEFI)
goto skip_modeset;
diff --git a/common/protos/multiboot2.c b/common/protos/multiboot2.c
index fd16103b..699b98b0 100644
--- a/common/protos/multiboot2.c
+++ b/common/protos/multiboot2.c
@@ -757,7 +757,7 @@ reloc_fail:
tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
- term_notready(false);
+ term_notready();
size_t req_width = 0;
size_t req_height = 0;
@@ -786,7 +786,7 @@ modeset:;
struct fb_info *fbs;
size_t fbs_count;
- fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp);
+ fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false, false);
if (fbs_count == 0) {
#if defined (BIOS)
textmode:
