Kernel: Fonts can now be parsed from the filesystem and set to terminal

We currently dont have a fallback font if we cannot get to filesystem
initialization, but that will come later. I can't test on real hardware
for this reason.
This commit is contained in:
Bananymous 2023-02-22 22:29:31 +02:00
parent 0e668738dc
commit a4980acc88
16 changed files with 78 additions and 58344 deletions

3
.gitignore vendored
View File

@ -3,6 +3,5 @@ isodir
sysroot sysroot
.vscode/ .vscode/
.idea/ .idea/
fonts/
bochsrc bochsrc
bx_enh_dbg.ini bx_enh_dbg.ini

View File

@ -37,7 +37,9 @@ sudo mkfs.ext2 $PARTITION2
sudo mount $PARTITION2 $MOUNT_DIR sudo mount $PARTITION2 $MOUNT_DIR
sudo cp -r sysroot/* ${MOUNT_DIR}/ sudo cp -r ${SYSROOT}/* ${MOUNT_DIR}/
sudo mkdir -p ${MOUNT_DIR}/usr/share/
sudo cp -r fonts ${MOUNT_DIR}/usr/share/
sudo grub-install --no-floppy --target=i386-pc --modules="normal ext2 multiboot" --boot-directory=${MOUNT_DIR}/boot $LOOP_DEV sudo grub-install --no-floppy --target=i386-pc --modules="normal ext2 multiboot" --boot-directory=${MOUNT_DIR}/boot $LOOP_DEV

BIN
fonts/lat0-08.psfu Normal file

Binary file not shown.

BIN
fonts/lat0-16.psfu Normal file

Binary file not shown.

BIN
fonts/zap-ext-vga16.psf Normal file

Binary file not shown.

BIN
fonts/zap-vga16.psf Normal file

Binary file not shown.

View File

@ -37,7 +37,7 @@ kernel/build_libc.o \
kernel/CPUID.o \ kernel/CPUID.o \
kernel/Debug.o \ kernel/Debug.o \
kernel/DiskIO.o \ kernel/DiskIO.o \
kernel/font.o \ kernel/Font.o \
kernel/FS/Ext2.o \ kernel/FS/Ext2.o \
kernel/FS/VirtualFileSystem.o \ kernel/FS/VirtualFileSystem.o \
kernel/Input.o \ kernel/Input.o \

View File

@ -12,6 +12,7 @@ public:
void write(const char* data, size_t size); void write(const char* data, size_t size);
void write_string(const char* data); void write_string(const char* data);
void set_cursor_position(uint32_t x, uint32_t y); void set_cursor_position(uint32_t x, uint32_t y);
void set_font(const Kernel::Font&);
uint32_t height() const { return m_height; } uint32_t height() const { return m_height; }
uint32_t width() const { return m_width; } uint32_t width() const { return m_width; }

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <kernel/Font.h>
#include <stdint.h> #include <stdint.h>
class TerminalDriver class TerminalDriver
@ -20,8 +22,8 @@ public:
}; };
public: public:
TerminalDriver(const Kernel::Font& font) : m_font(font) {}
virtual ~TerminalDriver() {} virtual ~TerminalDriver() {}
virtual uint32_t width() const = 0; virtual uint32_t width() const = 0;
virtual uint32_t height() const = 0; virtual uint32_t height() const = 0;
@ -29,6 +31,12 @@ public:
virtual void clear(Color) = 0; virtual void clear(Color) = 0;
virtual void set_cursor_position(uint32_t, uint32_t) = 0; virtual void set_cursor_position(uint32_t, uint32_t) = 0;
void set_font(const Kernel::Font& font) { m_font = font; };
const Kernel::Font& font() const { return m_font; }
private:
Kernel::Font m_font;
}; };
namespace TerminalColor namespace TerminalColor

View File

@ -1,16 +1,15 @@
#pragma once #pragma once
#include <kernel/font.h>
#include <kernel/TerminalDriver.h> #include <kernel/TerminalDriver.h>
class VesaTerminalDriver final : public TerminalDriver class VesaTerminalDriver final : public TerminalDriver
{ {
public: public:
static VesaTerminalDriver* create(); static VesaTerminalDriver* create(const Kernel::Font&);
~VesaTerminalDriver(); ~VesaTerminalDriver();
virtual uint32_t width() const override { return m_width / m_font.Width; } virtual uint32_t width() const override { return m_width / font().width(); }
virtual uint32_t height() const override { return m_height / m_font.Height; } virtual uint32_t height() const override { return m_height / font().height(); }
virtual void putchar_at(uint16_t, uint32_t, uint32_t, Color, Color) override; virtual void putchar_at(uint16_t, uint32_t, uint32_t, Color, Color) override;
virtual void clear(Color) override; virtual void clear(Color) override;
@ -18,13 +17,13 @@ public:
virtual void set_cursor_position(uint32_t, uint32_t) override; virtual void set_cursor_position(uint32_t, uint32_t) override;
private: private:
VesaTerminalDriver(uint32_t width, uint32_t height, uint32_t pitch, uint8_t bpp, uintptr_t address, bitmap_font font) VesaTerminalDriver(uint32_t width, uint32_t height, uint32_t pitch, uint8_t bpp, uintptr_t address, const Kernel::Font& font)
: m_width(width) : TerminalDriver(font)
, m_width(width)
, m_height(height) , m_height(height)
, m_pitch(pitch) , m_pitch(pitch)
, m_bpp(bpp) , m_bpp(bpp)
, m_address(address) , m_address(address)
, m_font(font)
{ } { }
void set_pixel(uint32_t, Color); void set_pixel(uint32_t, Color);
@ -35,7 +34,6 @@ private:
uint32_t m_pitch = 0; uint32_t m_pitch = 0;
uint8_t m_bpp = 0; uint8_t m_bpp = 0;
uintptr_t m_address = 0; uintptr_t m_address = 0;
bitmap_font m_font;
static constexpr Color s_cursor_color = TerminalColor::BRIGHT_WHITE; static constexpr Color s_cursor_color = TerminalColor::BRIGHT_WHITE;
}; };

View File

@ -1,271 +0,0 @@
#pragma once
// (c) 2009, 2010 Lutz Sammer, License: AGPLv3
/// bitmap font structure
struct bitmap_font {
unsigned char Width; ///< max. character width
unsigned char Height; ///< character height
unsigned short Chars; ///< number of characters in font
const unsigned char *Widths; ///< width of each character
const unsigned short *Index; ///< encoding to character index
const unsigned char *Bitmap; ///< bitmap of all characters
};
/// @{ defines to have human readable font files
#define ________ 0x00
#define _______X 0x01
#define ______X_ 0x02
#define ______XX 0x03
#define _____X__ 0x04
#define _____X_X 0x05
#define _____XX_ 0x06
#define _____XXX 0x07
#define ____X___ 0x08
#define ____X__X 0x09
#define ____X_X_ 0x0A
#define ____X_XX 0x0B
#define ____XX__ 0x0C
#define ____XX_X 0x0D
#define ____XXX_ 0x0E
#define ____XXXX 0x0F
#define ___X____ 0x10
#define ___X___X 0x11
#define ___X__X_ 0x12
#define ___X__XX 0x13
#define ___X_X__ 0x14
#define ___X_X_X 0x15
#define ___X_XX_ 0x16
#define ___X_XXX 0x17
#define ___XX___ 0x18
#define ___XX__X 0x19
#define ___XX_X_ 0x1A
#define ___XX_XX 0x1B
#define ___XXX__ 0x1C
#define ___XXX_X 0x1D
#define ___XXXX_ 0x1E
#define ___XXXXX 0x1F
#define __X_____ 0x20
#define __X____X 0x21
#define __X___X_ 0x22
#define __X___XX 0x23
#define __X__X__ 0x24
#define __X__X_X 0x25
#define __X__XX_ 0x26
#define __X__XXX 0x27
#define __X_X___ 0x28
#define __X_X__X 0x29
#define __X_X_X_ 0x2A
#define __X_X_XX 0x2B
#define __X_XX__ 0x2C
#define __X_XX_X 0x2D
#define __X_XXX_ 0x2E
#define __X_XXXX 0x2F
#define __XX____ 0x30
#define __XX___X 0x31
#define __XX__X_ 0x32
#define __XX__XX 0x33
#define __XX_X__ 0x34
#define __XX_X_X 0x35
#define __XX_XX_ 0x36
#define __XX_XXX 0x37
#define __XXX___ 0x38
#define __XXX__X 0x39
#define __XXX_X_ 0x3A
#define __XXX_XX 0x3B
#define __XXXX__ 0x3C
#define __XXXX_X 0x3D
#define __XXXXX_ 0x3E
#define __XXXXXX 0x3F
#define _X______ 0x40
#define _X_____X 0x41
#define _X____X_ 0x42
#define _X____XX 0x43
#define _X___X__ 0x44
#define _X___X_X 0x45
#define _X___XX_ 0x46
#define _X___XXX 0x47
#define _X__X___ 0x48
#define _X__X__X 0x49
#define _X__X_X_ 0x4A
#define _X__X_XX 0x4B
#define _X__XX__ 0x4C
#define _X__XX_X 0x4D
#define _X__XXX_ 0x4E
#define _X__XXXX 0x4F
#define _X_X____ 0x50
#define _X_X___X 0x51
#define _X_X__X_ 0x52
#define _X_X__XX 0x53
#define _X_X_X__ 0x54
#define _X_X_X_X 0x55
#define _X_X_XX_ 0x56
#define _X_X_XXX 0x57
#define _X_XX___ 0x58
#define _X_XX__X 0x59
#define _X_XX_X_ 0x5A
#define _X_XX_XX 0x5B
#define _X_XXX__ 0x5C
#define _X_XXX_X 0x5D
#define _X_XXXX_ 0x5E
#define _X_XXXXX 0x5F
#define _XX_____ 0x60
#define _XX____X 0x61
#define _XX___X_ 0x62
#define _XX___XX 0x63
#define _XX__X__ 0x64
#define _XX__X_X 0x65
#define _XX__XX_ 0x66
#define _XX__XXX 0x67
#define _XX_X___ 0x68
#define _XX_X__X 0x69
#define _XX_X_X_ 0x6A
#define _XX_X_XX 0x6B
#define _XX_XX__ 0x6C
#define _XX_XX_X 0x6D
#define _XX_XXX_ 0x6E
#define _XX_XXXX 0x6F
#define _XXX____ 0x70
#define _XXX___X 0x71
#define _XXX__X_ 0x72
#define _XXX__XX 0x73
#define _XXX_X__ 0x74
#define _XXX_X_X 0x75
#define _XXX_XX_ 0x76
#define _XXX_XXX 0x77
#define _XXXX___ 0x78
#define _XXXX__X 0x79
#define _XXXX_X_ 0x7A
#define _XXXX_XX 0x7B
#define _XXXXX__ 0x7C
#define _XXXXX_X 0x7D
#define _XXXXXX_ 0x7E
#define _XXXXXXX 0x7F
#define X_______ 0x80
#define X______X 0x81
#define X_____X_ 0x82
#define X_____XX 0x83
#define X____X__ 0x84
#define X____X_X 0x85
#define X____XX_ 0x86
#define X____XXX 0x87
#define X___X___ 0x88
#define X___X__X 0x89
#define X___X_X_ 0x8A
#define X___X_XX 0x8B
#define X___XX__ 0x8C
#define X___XX_X 0x8D
#define X___XXX_ 0x8E
#define X___XXXX 0x8F
#define X__X____ 0x90
#define X__X___X 0x91
#define X__X__X_ 0x92
#define X__X__XX 0x93
#define X__X_X__ 0x94
#define X__X_X_X 0x95
#define X__X_XX_ 0x96
#define X__X_XXX 0x97
#define X__XX___ 0x98
#define X__XX__X 0x99
#define X__XX_X_ 0x9A
#define X__XX_XX 0x9B
#define X__XXX__ 0x9C
#define X__XXX_X 0x9D
#define X__XXXX_ 0x9E
#define X__XXXXX 0x9F
#define X_X_____ 0xA0
#define X_X____X 0xA1
#define X_X___X_ 0xA2
#define X_X___XX 0xA3
#define X_X__X__ 0xA4
#define X_X__X_X 0xA5
#define X_X__XX_ 0xA6
#define X_X__XXX 0xA7
#define X_X_X___ 0xA8
#define X_X_X__X 0xA9
#define X_X_X_X_ 0xAA
#define X_X_X_XX 0xAB
#define X_X_XX__ 0xAC
#define X_X_XX_X 0xAD
#define X_X_XXX_ 0xAE
#define X_X_XXXX 0xAF
#define X_XX____ 0xB0
#define X_XX___X 0xB1
#define X_XX__X_ 0xB2
#define X_XX__XX 0xB3
#define X_XX_X__ 0xB4
#define X_XX_X_X 0xB5
#define X_XX_XX_ 0xB6
#define X_XX_XXX 0xB7
#define X_XXX___ 0xB8
#define X_XXX__X 0xB9
#define X_XXX_X_ 0xBA
#define X_XXX_XX 0xBB
#define X_XXXX__ 0xBC
#define X_XXXX_X 0xBD
#define X_XXXXX_ 0xBE
#define X_XXXXXX 0xBF
#define XX______ 0xC0
#define XX_____X 0xC1
#define XX____X_ 0xC2
#define XX____XX 0xC3
#define XX___X__ 0xC4
#define XX___X_X 0xC5
#define XX___XX_ 0xC6
#define XX___XXX 0xC7
#define XX__X___ 0xC8
#define XX__X__X 0xC9
#define XX__X_X_ 0xCA
#define XX__X_XX 0xCB
#define XX__XX__ 0xCC
#define XX__XX_X 0xCD
#define XX__XXX_ 0xCE
#define XX__XXXX 0xCF
#define XX_X____ 0xD0
#define XX_X___X 0xD1
#define XX_X__X_ 0xD2
#define XX_X__XX 0xD3
#define XX_X_X__ 0xD4
#define XX_X_X_X 0xD5
#define XX_X_XX_ 0xD6
#define XX_X_XXX 0xD7
#define XX_XX___ 0xD8
#define XX_XX__X 0xD9
#define XX_XX_X_ 0xDA
#define XX_XX_XX 0xDB
#define XX_XXX__ 0xDC
#define XX_XXX_X 0xDD
#define XX_XXXX_ 0xDE
#define XX_XXXXX 0xDF
#define XXX_____ 0xE0
#define XXX____X 0xE1
#define XXX___X_ 0xE2
#define XXX___XX 0xE3
#define XXX__X__ 0xE4
#define XXX__X_X 0xE5
#define XXX__XX_ 0xE6
#define XXX__XXX 0xE7
#define XXX_X___ 0xE8
#define XXX_X__X 0xE9
#define XXX_X_X_ 0xEA
#define XXX_X_XX 0xEB
#define XXX_XX__ 0xEC
#define XXX_XX_X 0xED
#define XXX_XXX_ 0xEE
#define XXX_XXXX 0xEF
#define XXXX____ 0xF0
#define XXXX___X 0xF1
#define XXXX__X_ 0xF2
#define XXXX__XX 0xF3
#define XXXX_X__ 0xF4
#define XXXX_X_X 0xF5
#define XXXX_XX_ 0xF6
#define XXXX_XXX 0xF7
#define XXXXX___ 0xF8
#define XXXXX__X 0xF9
#define XXXXX_X_ 0xFA
#define XXXXX_XX 0xFB
#define XXXXXX__ 0xFC
#define XXXXXX_X 0xFD
#define XXXXXXX_ 0xFE
#define XXXXXXXX 0xFF
/// @}

View File

@ -324,6 +324,21 @@ argument_done:
TTY_PRINTLN("{}", BAN::StringView((const char*)data.data(), data.size())); TTY_PRINTLN("{}", BAN::StringView((const char*)data.data(), data.size()));
} }
else if (arguments.front() == "loadfont")
{
if (!VirtualFileSystem::is_initialized())
return TTY_PRINTLN("VFS not initialized :(");
if (arguments.size() != 2)
return TTY_PRINTLN("usage: 'loadfont font_path'");
auto font_or_error = Font::load(arguments[1]);
if (font_or_error.is_error())
return TTY_PRINTLN("{}", font_or_error.error());
auto font = font_or_error.release_value();
m_tty->set_font(font);
}
else else
{ {
TTY_PRINTLN("unrecognized command '{}'", arguments.front()); TTY_PRINTLN("unrecognized command '{}'", arguments.front());

View File

@ -52,6 +52,14 @@ void TTY::set_cursor_position(uint32_t x, uint32_t y)
last_y = m_row = y; last_y = m_row = y;
} }
void TTY::set_font(const Kernel::Font& font)
{
m_terminal_driver->set_font(font);
for (uint32_t y = 0; y < m_height; y++)
for (uint32_t x = 0; x < m_width; x++)
render_from_buffer(x, y);
}
static uint16_t handle_unicode(uint8_t ch) static uint16_t handle_unicode(uint8_t ch)
{ {
static uint8_t unicode_left = 0; static uint8_t unicode_left = 0;

View File

@ -4,9 +4,7 @@
#include <kernel/multiboot.h> #include <kernel/multiboot.h>
#include <kernel/VesaTerminalDriver.h> #include <kernel/VesaTerminalDriver.h>
extern const struct bitmap_font font; VesaTerminalDriver* VesaTerminalDriver::create(const Kernel::Font& font)
VesaTerminalDriver* VesaTerminalDriver::create()
{ {
if (!(g_multiboot_info->flags & MULTIBOOT_FLAGS_FRAMEBUFFER)) if (!(g_multiboot_info->flags & MULTIBOOT_FLAGS_FRAMEBUFFER))
{ {
@ -73,29 +71,19 @@ void VesaTerminalDriver::set_pixel(uint32_t offset, Color color)
void VesaTerminalDriver::putchar_at(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg) void VesaTerminalDriver::putchar_at(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg)
{ {
uint32_t glyph_index = 0; const uint8_t* glyph = font().has_glyph(ch) ? font().glyph(ch) : font().glyph('?');
for (uint32_t i = 0; i < m_font.Chars; i++)
{
if (m_font.Index[i] == ch)
{
glyph_index = i;
break;
}
}
const uint8_t* glyph = m_font.Bitmap + glyph_index * m_font.Height; x *= font().width();
y *= font().height();
x *= m_font.Width;
y *= m_font.Height;
uint32_t row_offset = y * m_pitch + x * m_bpp / 8; uint32_t row_offset = y * m_pitch + x * m_bpp / 8;
for (uint32_t dy = 0; dy < m_font.Height && y + dy < m_height; dy++) for (uint32_t dy = 0; dy < font().height() && y + dy < m_height; dy++)
{ {
uint32_t pixel_offset = row_offset; uint32_t pixel_offset = row_offset;
for (uint32_t dx = 0; dx < m_font.Width && x + dx < m_width; dx++) for (uint32_t dx = 0; dx < font().width() && x + dx < m_width; dx++)
{ {
uint8_t bitmask = 1 << (font.Width - dx - 1); uint8_t bitmask = 1 << (font().width() - dx - 1);
set_pixel(pixel_offset, glyph[dy] & bitmask ? fg : bg); set_pixel(pixel_offset, glyph[dy * font().pitch()] & bitmask ? fg : bg);
pixel_offset += m_bpp / 8; pixel_offset += m_bpp / 8;
} }
row_offset += m_pitch; row_offset += m_pitch;
@ -128,38 +116,19 @@ void VesaTerminalDriver::clear(Color color)
void VesaTerminalDriver::set_cursor_position(uint32_t x, uint32_t y) void VesaTerminalDriver::set_cursor_position(uint32_t x, uint32_t y)
{ {
ASSERT(m_font.Height == 16 && m_font.Width == 8); uint32_t cursor_h = font().height() / 8;
constexpr uint8_t cursor[] = { uint32_t cursor_top = font().height() * 13 / 16;
________,
________,
________,
________,
________,
________,
________,
________,
________,
________,
________,
________,
________,
XXXXXXXX,
XXXXXXXX,
________,
};
x *= m_font.Width; x *= font().width();
y *= m_font.Height; y *= font().height();
uint32_t row_offset = y * m_pitch + x * m_bpp / 8; uint32_t row_offset = (y + cursor_top) * m_pitch + x * m_bpp / 8;
for (uint32_t dy = 0; dy < m_font.Height && y + dy < m_height; dy++) for (uint32_t dy = 0; dy < cursor_h; dy++)
{ {
uint32_t pixel_offset = row_offset; uint32_t pixel_offset = row_offset;
for (uint32_t dx = 0; dx < m_font.Width && x + dx < m_width; dx++) for (uint32_t dx = 0; dx < font().width(); dx++)
{ {
uint8_t bitmask = 1 << (font.Width - dx - 1); set_pixel(pixel_offset, s_cursor_color);
if (cursor[dy] & bitmask)
set_pixel(pixel_offset, s_cursor_color);
pixel_offset += m_bpp / 8; pixel_offset += m_bpp / 8;
} }
row_offset += m_pitch; row_offset += m_pitch;

File diff suppressed because it is too large Load Diff

View File

@ -76,29 +76,40 @@ extern "C" void kernel_main()
dprintln("kmalloc initialized"); dprintln("kmalloc initialized");
IDT::initialize(); IDT::initialize();
dprintln("IDT initialized"); dprintln("IDT initialized");
MMU::intialize(); MMU::intialize();
dprintln("MMU initialized"); dprintln("MMU initialized");
TerminalDriver* terminal_driver = VesaTerminalDriver::create(); //TerminalDriver* terminal_driver = VesaTerminalDriver::create();
ASSERT(terminal_driver); //ASSERT(terminal_driver);
dprintln("VESA initialized"); //dprintln("VESA initialized");
TTY* tty1 = new TTY(terminal_driver); //TTY* tty1 = new TTY(terminal_driver);
InterruptController::initialize(cmdline.force_pic); InterruptController::initialize(cmdline.force_pic);
dprintln("Interrupt controller initialized"); dprintln("Interrupt controller initialized");
PIT::initialize(); PIT::initialize();
dprintln("PIT initialized"); dprintln("PIT initialized");
if (!Input::initialize()) if (!Input::initialize())
return; return;
dprintln("8042 initialized"); dprintln("8042 initialized");
Scheduler::initialize(); Scheduler::initialize();
Scheduler& scheduler = Scheduler::get(); Scheduler& scheduler = Scheduler::get();
MUST(scheduler.add_thread(BAN::Function<void()>([] { DiskIO::initialize(); }))); MUST(scheduler.add_thread(BAN::Function<void()>(
MUST(scheduler.add_thread(BAN::Function<void()>([tty1] { Shell(tty1).run(); }))); []
{
DiskIO::initialize();
dprintln("Disk IO initialized");
auto font = MUST(Font::load("/usr/share/fonts/zap-ext-vga16.psf"));
dprintln("Font loaded");
Shell(new TTY(VesaTerminalDriver::create(font))).run();
}
)));
scheduler.start(); scheduler.start();
ASSERT(false); ASSERT(false);
} }