Quantcast
Channel: Active questions tagged kernel - Stack Overflow
Viewing all articles
Browse latest Browse all 6502

Parsing Console Fonts from the ZAP Group for a custom kernel

$
0
0

In my EFI bootloader that is written in C, I'm loading in PSF1 Font files by the ZAP Group. Then I'm passing off my data structure of fonts to my kernel that is written in C++.

These fonts have 2 different versions. Version 1 is already supported by my font loading function in my bootloader and it is working within my kernel's frame buffer render. I am successfully able to render a basic font using the zap-light16.psf file. This font's glyph size is 8x16.

There are two structures associated to this font's file format when parsing and loading in the font file.

These are the original structures found in main.c bootloader

typedef struct {    unsigned char magic[2];    unsigned char mode;    unsigned charsize;} PSF1_HEADER;typedef struct {    PSF1_HEADER* psf1_Header;    void* glyphBuffer;} PSF1_FONT;

Here is the function to load the font:

PSF1_FONT* LoadPSF1Font(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable ) {    EFI_FILE* font = LoadFile(Directory, Path, ImageHandle, SystemTable);    if( font == NULL) return NULL;    PSF1_HEADER* fontHeader;    SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(PSF1_HEADER), (void**)&fontHeader);    UINTN size = sizeof(PSF1_HEADER);    font->Read(font, &size, fontHeader);    if (fontHeader->magic[0] != PSF1_MAGIC0 || fontHeader->magic[1] != PSF1_MAGIC1) return NULL;    UINTN glyphBufferSize = fontHeader->charsize * 256;    if (fontHeader->mode == 1) { // 512 glyphs        glyphBufferSize *= 2;    }    void* glyphBuffer;    font->SetPosition(font, sizeof(PSF1_HEADER));    SystemTable->BootServices->AllocatePool(EfiLoaderData, glyphBufferSize, (void**)&glyphBuffer);    font->Read(font, &glyphBufferSize, glyphBuffer);    PSF1_FONT* finishedFont;    SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(PSF1_FONT), (void**)&finishedFont);    finishedFont->psf1_Header = fontHeader;    finishedFont->glyphBuffer = glyphBuffer;    return finishedFont;}

Here is the LoadFile() function in case you need to see it:

EFI_FILE* LoadFile(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable) {    EFI_FILE* LoadedFile;    EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;    SystemTable->BootServices->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (void**)&LoadedImage);    EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* FileSystem;    SystemTable->BootServices->HandleProtocol(LoadedImage->DeviceHandle, &gEfiSimpleFileSystemProtocolGuid, (void**)&FileSystem);    if (Directory == NULL) {        FileSystem->OpenVolume(FileSystem, &Directory);    }    EFI_STATUS s = Directory->Open(Directory, &LoadedFile, Path, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY);    if (s != EFI_SUCCESS) {        return NULL;    }    return LoadedFile;}

In my efi-main function this is how I was calling it.

{    // ... code    PSF1_FONT* newFont = LoadPSF1Font(NULL, L"zap-light16.psf", ImageHandle, SystemTable);    if (newFont == NULL) {        Print(L"Font is not valid or is not found\n\r");    } else {        Print(L"Font found, char size = %d\n\r", newFont->psf1_Header->charsize);    }    // ... more code}

This is how I was passing it to my kernel from the bootloader. It is being stored in a struct with other objects such as the Framebuffer*, EFI_MEMORY_DESCRIPTOR* Map, the MapSize and the MapDescriptorSize...

typedef struct {    Framebuffer* framebuffer;    PSF1_FONT* font;    EFI_MEMORY_DESCRIPTOR* Map;    UINTN MapSize;    UINTN MapDescriptorSize;} BootInfo;

And back in efi_main It is being passed to the kernel via function pointer...

{     // ...code    void (*KernelStart)(BootInfo*) = ((__attribute____(sysv_abi)) void(*)(BootInfo*)) header.e_entry);    BootInfo bootInfo;    bootInfo.framebuffer = newBuffer; // defined elsewhere in this function    bootInfo.font = font;    bootInfo.Map = Map;    bootInfo.MapSize = MapSize;    bootInfo.MapDescriptorSize = DescriptorSize;    SystemTable->BootServices->ExitBootServices(ImageHandle, MapKey);    KernelStart(&bootInfo);    return EFI_SUCCESS;}

The above code works within my kernel that is running QEMU on Ubuntu latest version within Virtual Box latest version on my Windows 7 x64 machine. I'm using gnu-cpp cross compiler, and there are several make files within this project to help compile, link and build the project as well as aiding in loading the font files not shown here...

I was able to extend this to support a second font file that had the same version and size...

I just changed the BootInfo struct's PSF1_FONT* to a PSF1FONT** and named it fonts, and in my efi_main function where I loaded in my font, I repeated the process above with a different pointer variable name, then created an array and initialized that array with the two created fonts and changed the similar or related c++ struct within my kernel files to match that of this bootloader.

This was also working.

Now I'm in the process of extending this to also support version 2 and the rest of the font files that are available from Zap.org with differing font sizes.

Here's a table of the different fonts and their properties that I summarized from ZAP's website...

light16   glyphs 0x00-0xff  psf version 1  size 8x16 pixels  count 256  unicode Ylight16ext    glyphs 0x000-0x0ff    psf version 1    size 8x16 pixels    count 512    unicode Ylight18    glyphs 0x00-0xff    psf version 1    size 8x18 pixels    count 256    unicode Ylight18ext    glyphs 0x000-0x0ff    psf version 1    size 8x18 pixels    count 512    unicode Ylight20    glyphs 0x00-0xff     psf version 2    size 10x20 pixels    count 256    unicode Ylight20ext    glyphs 0x000-0x0ff    psf version 2    size 10x20 pixels    count 512    unicode Ylight24    glyphs 0x00-0x0ff    psf version 2    size 10x24 pixels    count 256    unicode Ylight24ext    glyphs 0x00-0x0ff    psf version 2    size 10x24 pixels    count 512    unicode Yvga09    glyphs 0x00-0xff    psf version 1    size 8x9 pixels    count 256    unicode Yvga09ext    glyphs 0x000-0x0ff    psf version 1    size 8x9 pixels    count 512    unicode Yvga16    glyphs 0x00-0xff    psf version 1    size 8x16 pixels    count 256    unicode Yvga16ext    glyphs 0x000-0x0ff    psf version 1    size 8x16 pixels     count 256    unicode Y

Now, within my kernel for the renderer, I have hardcoded values of 8 and 16 to control the cursor position when rendering the fonts. I want to change these to be variables for the currently loaded font. I need both width and height so I'm thinking about adding a Point struct to my bootloader, there is already a Point structure in my kernel...

typedef struct {    unsigned int x;    unsigned int y;} Point;

And then adding an instance of this within my PSF1_FONT struct as well as the version number which would now look like this:

typedef struct {    PSF1_HEADER* psf1_Header;    void* glyphBuffer;    Point fontSize;    unsigned int version;} PSF1_FONT;

This way when I pass it to my kernel, BasicRenderer class object will have direct access to the width and height of the loaded font.

Now to my question... I've searched through their documentations, their repositories etc... but I can not seem to find any irrelevant information about obtaining both of the glyphs dimensions. The only thing I have seen is the size but I believe that is determined by its height as most fonts are 8pixels in with and they use a 1 pixel space buffer... When I'm calling my LoadPSF1Font() function how do I or can I extract both the font's width and height from the font's header or glyph buffer? Or would I have to hard-code or pre-define these values within the boot when loading the font file?


Edit

Within in my kernel's BasicRenderer class, this is how I'm rendering a char from the font as it has access to the PSF1_FONT structure:

void BasicRenderer::RenderChar(char c) {            if (c == '\n' ) {        Newline();    } else {                unsigned int* pixPtr = (unsigned int*)framebuffer_->BaseAddress;        char* fontPtr = (char*)selected_font_->glyphBuffer + (c * selected_font_->psf1_Header->charsize);        for (unsigned long y = cursor_position_.y; y < cursor_position_.y + 16; y++) {            for (unsigned long x = cursor_position_.x; x < cursor_position_.x + 8; x++) {                if ((*fontPtr & (0b10000000 >> (x - cursor_position_.x))) > 0) {                    *(unsigned int*)(pixPtr + x + (y * framebuffer_->PixelsPerScanLine)) = font_color_;                }            }            fontPtr++;        }    }}

As you can see, it is referencing the psf1_Header's charsize member. Then it is moving the draw calls with hard coded values of 8 and 16. I would like to change these to Point fontSize and use fontSize.x and fontSize.y respectively...


Viewing all articles
Browse latest Browse all 6502

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>