From 93b18e3730af9da642d7e4c1d5d045f97f184910 Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Mon, 30 Nov 2020 11:45:47 +0000 Subject: [PATCH] vt: if loader did pass the font via metadata, use it The built in 8x16 font may be way too small with large framebuffer resolutions, to improve readability, use loader provied font. --- sys/dev/vt/vt_core.c | 145 +++++++++++++++++++++++++++++++++++++++-- sys/kern/subr_module.c | 1 + sys/sys/font.h | 8 +++ sys/sys/linker.h | 1 + 4 files changed, 150 insertions(+), 5 deletions(-) diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c index a7cb21e12b5d..f840f7ba37f6 100644 --- a/sys/dev/vt/vt_core.c +++ b/sys/dev/vt/vt_core.c @@ -39,9 +39,11 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include +#include #include #include #include @@ -163,8 +165,15 @@ extern unsigned char vt_logo_image[]; const unsigned int vt_logo_sprite_height; #endif -/* Font. */ +/* + * Console font. vt_font_loader will be filled with font data passed + * by loader. If there is no font passed by boot loader, we use built in + * default. + */ extern struct vt_font vt_font_default; +static struct vt_font vt_font_loader; +static struct vt_font *vt_font_assigned = &vt_font_default; + #ifndef SC_NO_CUTPASTE extern struct vt_mouse_cursor vt_default_mouse_pointer; #endif @@ -1445,6 +1454,130 @@ vtterm_splash(struct vt_device *vd) } #endif +static struct vt_font * +parse_font_info_static(struct font_info *fi) +{ + struct vt_font *vfp; + uintptr_t ptr; + uint32_t checksum; + + if (fi == NULL) + return (NULL); + + ptr = (uintptr_t)fi; + /* + * Compute and verify checksum. The total sum of all the fields + * must be 0. + */ + checksum = fi->fi_width; + checksum += fi->fi_height; + checksum += fi->fi_bitmap_size; + for (unsigned i = 0; i < VFNT_MAPS; i++) + checksum += fi->fi_map_count[i]; + + if (checksum + fi->fi_checksum != 0) + return (NULL); + + ptr += sizeof(struct font_info); + ptr = roundup2(ptr, 8); + + vfp = &vt_font_loader; + vfp->vf_height = fi->fi_height; + vfp->vf_width = fi->fi_width; + for (unsigned i = 0; i < VFNT_MAPS; i++) { + if (fi->fi_map_count[i] == 0) + continue; + vfp->vf_map_count[i] = fi->fi_map_count[i]; + vfp->vf_map[i] = (vfnt_map_t *)ptr; + ptr += (fi->fi_map_count[i] * sizeof(vfnt_map_t)); + ptr = roundup2(ptr, 8); + } + vfp->vf_bytes = (uint8_t *)ptr; + return (vfp); +} + +static struct vt_font * +parse_font_info(struct font_info *fi) +{ + struct vt_font *vfp; + uintptr_t ptr; + uint32_t checksum; + size_t size; + + if (fi == NULL) + return (NULL); + + ptr = (uintptr_t)fi; + /* + * Compute and verify checksum. The total sum of all the fields + * must be 0. + */ + checksum = fi->fi_width; + checksum += fi->fi_height; + checksum += fi->fi_bitmap_size; + for (unsigned i = 0; i < VFNT_MAPS; i++) + checksum += fi->fi_map_count[i]; + + if (checksum + fi->fi_checksum != 0) + return (NULL); + + ptr += sizeof(struct font_info); + ptr = roundup2(ptr, 8); + + vfp = &vt_font_loader; + vfp->vf_height = fi->fi_height; + vfp->vf_width = fi->fi_width; + for (unsigned i = 0; i < VFNT_MAPS; i++) { + if (fi->fi_map_count[i] == 0) + continue; + vfp->vf_map_count[i] = fi->fi_map_count[i]; + size = fi->fi_map_count[i] * sizeof(vfnt_map_t); + vfp->vf_map[i] = malloc(size, M_VT, M_WAITOK | M_ZERO); + bcopy((vfnt_map_t *)ptr, vfp->vf_map[i], size); + ptr += size; + ptr = roundup2(ptr, 8); + } + vfp->vf_bytes = malloc(fi->fi_bitmap_size, M_VT, M_WAITOK | M_ZERO); + bcopy((uint8_t *)ptr, vfp->vf_bytes, fi->fi_bitmap_size); + return (vfp); +} + +static void +vt_init_font(void *arg) +{ + caddr_t kmdp; + struct font_info *fi; + struct vt_font *font; + + kmdp = preload_search_by_type("elf kernel"); + if (kmdp == NULL) + kmdp = preload_search_by_type("elf64 kernel"); + fi = MD_FETCH(kmdp, MODINFOMD_FONT, struct font_info *); + + font = parse_font_info(fi); + if (font != NULL) + vt_font_assigned = font; +} + +SYSINIT(vt_init_font, SI_SUB_KMEM, SI_ORDER_ANY, vt_init_font, &vt_consdev); + +static void +vt_init_font_static(void) +{ + caddr_t kmdp; + struct font_info *fi; + struct vt_font *font; + + kmdp = preload_search_by_type("elf kernel"); + if (kmdp == NULL) + kmdp = preload_search_by_type("elf64 kernel"); + fi = MD_FETCH(kmdp, MODINFOMD_FONT, struct font_info *); + + font = parse_font_info_static(fi); + if (font != NULL) + vt_font_assigned = font; +} + static void vtterm_cnprobe(struct terminal *tm, struct consdev *cp) { @@ -1491,9 +1624,11 @@ vtterm_cnprobe(struct terminal *tm, struct consdev *cp) vd->vd_windows[VT_CONSWINDOW] = vw; sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw)); + vt_init_font_static(); + /* Attach default font if not in TEXTMODE. */ if ((vd->vd_flags & VDF_TEXTMODE) == 0) { - vw->vw_font = vtfont_ref(&vt_font_default); + vw->vw_font = vtfont_ref(vt_font_assigned); vt_compute_drawable_area(vw); } @@ -2431,7 +2566,7 @@ vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data, } case PIO_VFONT_DEFAULT: { /* Reset to default font. */ - error = vt_change_font(vw, &vt_font_default); + error = vt_change_font(vw, vt_font_assigned); return (error); } case GIO_SCRNMAP: { @@ -2691,7 +2826,7 @@ vt_allocate_window(struct vt_device *vd, unsigned int window) vw->vw_kbdmode = K_XLATE; if ((vd->vd_flags & VDF_TEXTMODE) == 0) { - vw->vw_font = vtfont_ref(&vt_font_default); + vw->vw_font = vtfont_ref(vt_font_assigned); vt_compute_drawable_area(vw); } @@ -2788,7 +2923,7 @@ vt_resize(struct vt_device *vd) VT_LOCK(vd); /* Assign default font to window, if not textmode. */ if (!(vd->vd_flags & VDF_TEXTMODE) && vw->vw_font == NULL) - vw->vw_font = vtfont_ref(&vt_font_default); + vw->vw_font = vtfont_ref(vt_font_assigned); VT_UNLOCK(vd); /* Resize terminal windows */ diff --git a/sys/kern/subr_module.c b/sys/kern/subr_module.c index 6bc5b28accc4..02137adae27c 100644 --- a/sys/kern/subr_module.c +++ b/sys/kern/subr_module.c @@ -295,6 +295,7 @@ preload_bootstrap_relocate(vm_offset_t offset) /* Deal with the ones that we know we have to fix */ switch (hdr[0]) { case MODINFO_ADDR: + case MODINFO_METADATA|MODINFOMD_FONT: case MODINFO_METADATA|MODINFOMD_SSYM: case MODINFO_METADATA|MODINFOMD_ESYM: ptr = (vm_offset_t *)(curp + (sizeof(uint32_t) * 2)); diff --git a/sys/sys/font.h b/sys/sys/font.h index 71991a3c67b4..73b6d39683a6 100644 --- a/sys/sys/font.h +++ b/sys/sys/font.h @@ -57,6 +57,14 @@ enum vfnt_map_type { VFNT_MAPS /* Number of maps. */ }; +struct font_info { + int32_t fi_checksum; + uint32_t fi_width; + uint32_t fi_height; + uint32_t fi_bitmap_size; + uint32_t fi_map_count[VFNT_MAPS]; +}; + struct vfnt_map { uint32_t vfm_src; uint16_t vfm_dst; diff --git a/sys/sys/linker.h b/sys/sys/linker.h index 6780bffc4827..13274ecd1a7c 100644 --- a/sys/sys/linker.h +++ b/sys/sys/linker.h @@ -226,6 +226,7 @@ void *linker_hwpmc_list_objects(void); #define MODINFOMD_CTORS_SIZE 0x000b /* size of .ctors */ #define MODINFOMD_FW_HANDLE 0x000c /* Firmware dependent handle */ #define MODINFOMD_KEYBUF 0x000d /* Crypto key intake buffer */ +#define MODINFOMD_FONT 0x000e /* Console font */ #define MODINFOMD_NOCOPY 0x8000 /* don't copy this metadata to the kernel */ #define MODINFOMD_DEPLIST (0x4001 | MODINFOMD_NOCOPY) /* depends on */