Invalid output for a custom print function when incorporating newline characters within a string for a kernel project

-1

I'm in the process of working on a kernel program to handle printing capabilities of input for a custom OS. I'm following Poncho's 2nd YouTube Video series found here, I'm currently on Video 4 in the series where he starts to add numerical types as inputs to the renderer's print function. Now, my code isn't exactly like his as I made some modifications.

-Note- This won't compile directly as there is no main function. _start is being called or invoked by a bootloader that isn't shown here, I will however, add it to the bottom of this question.

When I use the class's print function like this within my kernel:

#include "BasicRenderer.h"

extern "C" void _start(Framebuffer* framebuffer, PSF1_FONT** fonts) {
    BasicRenderer = renderer(framebuffer, fonts); 
    renderer.Print("This is some text");
    renderer.Print('\n');
    renderer.Print(uint64_t(123456789));
    renderer.Print('\n');
    renderer.Print(int64_t(-123456789));

    return;
}

And I run the kernel in emu. I'm getting the following output displayed:

This is some text
123456789
-123456789

The above is correct, however, when I try to incorporate the ability to parse a newline set of characters being either \n or \0 within of a const char* that acts as a string as seen in the following example:

#include "BasicRenderer.h"

extern "C" void _start(Framebuffer* framebuffer, PSF1_FONT** fonts) {
    BasicRenderer = renderer(framebuffer, fonts); 
    renderer.Print("This is some text\n");
    renderer.Print(uint64_t(123456789));
    renderer.Print('\n');
    renderer.Print(int64_t(-123456789));

    return;
}

And now the displayed output is:

This is some text
 123456789
-123456789

Here, the output in the second line has a space preceding the numerical value to be displayed after the call to Print() that has a \n within its string. I'm not sure what is causing this in my code. Does it have to do with the while condition or how I'm incrementing and indexing into the character string within BasicRenderer::Print(const char* str)? Or is it coming from BasicRender::PutChar(char c)? Or is it within one of the to_string() functions?


Here is the relevant implementation code...

BasicRenderer.cpp

#include "BasicRenderer.h"

void BasicRenderer::Print(const char* str) {    
    char* chr = (char*)str;
    while(*chr != 0) {
        if ( (*chr == '\\') && ((*chr+1 == 'n') || (*chr+1 == '0')) ) {
            PutChar('\n');
            chr++;
            chr++;
        } else {
            PutChar(*chr);
            cursor_position_.x += 8;

            if (cursor_position_.x + 8 > framebuffer_->Width) {
                cursor_position_.x = 0;
                cursor_position_.y += 16;
            }
            chr++;
        }
    }
}

void BasicRenderer::Print(uint64_t val) {
    const char* str = to_string(val);
    Print(str);
}

void BasicRenderer::Print(int64_t val) {
    const char* str = to_string(val);
    Print(str);
}

void BasicRenderer::PutChar(char c) {       
    if (c == '\n' || c == '\0') {
        cursor_position_.x = 0;
        cursor_position_.y += 16;
    } 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++;
        }
    }
}

cstr.cpp

#include "cstr.h"

const char* to_string(uint64_t value) {
    static char output_uint_buffer[128];

    uint8_t size = 0;
    uint64_t sizeTest = value;
    while (sizeTest / 10 > 0) {
        sizeTest /= 10;
        size++;
    }

    uint8_t idx = 0;
    while (value / 10 > 0) {
        uint8_t remainder = value % 10;
        value /= 10;
        output_uint_buffer[size - idx] = remainder + '0';
        idx++;
    }
    uint8_t remainder = value % 10;
    output_uint_buffer[size-idx] = remainder + '0';
    output_uint_buffer[size + 1] = 0;
    return output_uint_buffer;
}

const char* to_string(int64_t value) {
    static char output_int_buffer[128];
    uint8_t isNegative = 0;

    if (value < 0) {
        isNegative = 1;
        value *= -1;
        output_int_buffer[0] = '-';
    }

    uint8_t size = 0;
    uint64_t sizeTest = value;
    while (sizeTest / 10 > 0) {
        sizeTest /= 10;
        size++;
    }

    uint8_t idx = 0;
    while (value / 10 > 0) {
        uint8_t remainder = value % 10;
        value /= 10;
        output_int_buffer[isNegative + size - idx] = remainder + '0';
        idx++;
    }
    uint8_t remainder = value % 10;
    output_int_buffer[isNegative + size - idx] = remainder + '0';
    output_int_buffer[isNegative + size + 1] = 0;
    return output_int_buffer;
}

And here is the rest of the declarations...

BasicRender.h

#pragma once

#include "cstr.h"
#include "math.h"
#include "framebuffer.h"
#include "SimpleFonts.h"

class BasicRenderer {
public:
    BasicRenderer(Framebuffer* framebuffer, PSF1_FONT** fonts) :
      framebuffer_{framebuffer}, 
      fonts_{fonts}, 
      cursor_position_({0,0}),
      selected_font_{fonts_[0]},
      font_color_{0xFFFFFFFF} 
    {}

    void Print(const char* str);        
    void Print(char c) { PutChar(c); }    
    void Print(uint64_t val);
    void Print(int64_t val);

private:
    void PutChar(char c);

    Framebuffer* framebuffer_;
    Point cursor_position_;
    PSF1_FONT** fonts_;
    PSF1_FONT* selected_font_;
    unsigned int font_color_;
};

cstr.h

#pragma once

#include <stdint.h>

const char* to_string(uint64_t value);
const char* to_string(int64_t value);

math.h

#pragma once

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

Framebuffer.h

#pragma once

#include <stddef.h>

struct Framebuffer {
    void* BaseAddress;
    size_t BufferSize;
    unsigned int Width;
    unsigned int Height;
    unsigned int PixelsPerScanLine;
};

SimpleFonts.h

#pragma once

struct PSF1_HEADER {
    unsigned char magic[2];
    unsigned char mode;
    unsigned char charsize;
};

struct PSF1_FONT {
    PSF1_HEADER* psf1_Header;
    void* glyphBuffer;
};

Here is the bootloader application that invokes the above kernel.

main.c

#include <efi.h>    
#include <efilib.h>    
#include <elf.h>   

#define PSF1_MAGIC0 0x36    
#define PSF1_MAGIC1 0x04    

typedef unsigned long long size_t;    

typedef struct {    
    unsigned char magic[2];    
    unsigned char mode;    
    unsigned char charsize;    
} PSF1_HEADER;    

typedef struct {    
    PSF1_HEADER* psf1_Header;    
    void* glyphBuffer;    
} PSF1_FONT;    

typedef struct {    
    void* BaseAddress;    
    size_t BufferSize;    
    unsigned int Width;    
    unsigned int Height;
    unsigned int PixelsPerScanLine;    
} Framebuffer; Framebuffer framebuffer;

Framebuffer* InitializeGOP() {    
    EFI_GUID gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; 
    EFI_GRAPHICS_OUTPUT_PROTOCOL* gop;    
    EFI_STATUS status;    
    status = uefi_call_wrapper(BS->LocateProtocol, 3, &gopGuid, NULL, (void**)&gop);    
    if (EFI_ERROR(status)) {    
        Print(L"Unable to locate GOP\n\r");    
        return NULL;    
    } else {    
        Print(L"GOP located\n\r");
    }   

    framebuffer.BaseAddress = (void*)gop->Mode->FrameBufferBase;
    framebuffer.BufferSize = gop->Mode->FrameBufferSize;    
    framebuffer.Width = gop->Mode->Info->HorizontalResolution;    
    framebuffer.Height = gop->Mode->Info->VerticalResolution;    
    framebuffer.PixelsPerScanLine = gop->Mode->Info->PixelsPerScanLine;    

    return &framebuffer;    
}    

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

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 glyph mode    
        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;    
}    

int memcmp(const void* aptr, const void* bptr, size_t n) {    
    const unsigned char* a = aptr, *b = bptr;    
    for (size_t i = 0; i < n; i++) {    
        if (a[i] < b[i]) return -1;    
        else if(a[i] > b[i]) return 1;    
    }    
    return 0;    
}    

EFI_STATUS efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {    
    InitializeLib(ImageHandle, SystemTable);    
    Print(L"Hello World!\n\r");    
    EFI_FILE* Kernel = LoadFile(NULL, L"kernel.elf", ImageHandle, SystemTable);    
    if ( Kernel == NULL) {    
        Print(L"Could not load kernel \n\r");    
    } else {    
        Print(L"Kernel Loaded Successfully \n\r"); 
    }

    Elf64_Ehdr header; 
    {  
        UINTN FileInfoSize;    
        EFI_FILE_INFO* FileInfo;    
        Kernel->GetInfo(Kernel, &gEfiFileInfoGuid, &FileInfoSize, NULL);    
        SystemTable->BootServices->AllocatePool(EfiLoaderData, FileInfoSize, (void**)&FileInfo);    
        Kernel->GetInfo(Kernel, &gEfiFileInfoGuid, &FileInfoSize, (void**)&FileInfo);    
        UINTN size = sizeof(header);    
        Kernel->Read(Kernel, &size, &header);   
    }    

    if (    
        memcmp(&header.e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0 ||    
        header.e_ident[EI_CLASS] != ELFCLASS64 ||    
        header.e_ident[EI_DATA] != ELFDATA2LSB ||    
        header.e_type != ET_EXEC ||    
        header.e_machine != EM_X86_64 ||    
        header.e_version != EV_CURRENT    
    ) {    
        Print(L"kernel format is bad\r\n");    
    } else {    
        Print(L"kernel header successfully verified\r\n");    
    }    

    Elf64_Phdr* phdrs;    
    {    
        Kernel->SetPosition(Kernel, header.e_phoff);    
        UINTN size = header.e_phnum * header.e_phentsize;    
        SystemTable->BootServices->AllocatePool(EfiLoaderData, size, (void**)&phdrs);    
        Kernel->Read(Kernel, &size, phdrs);    
    }

    for (    
        Elf64_Phdr* phdr = phdrs;    
        (char*)phdr < (char*)phdrs + header.e_phnum * header.e_phentsize;    
        phdr = (Elf64_Phdr*)((char*)phdr + header.e_phentsize)      
    ) {    
        switch(phdr->p_type) {    
            case PT_LOAD: {    
                int pages = (phdr->p_memsz + 0x1000 - 1) / 0x1000;    
                Elf64_Addr segment = phdr->p_paddr;    
                SystemTable->BootServices->AllocatePages(AllocateAddress, EfiLoaderData, pages, &segment);    
                Kernel->SetPosition(Kernel, phdr->p_offset);    
                UINTN size = phdr->p_filesz;    
                Kernel->Read(Kernel, &size, (void*)segment);    
                break;    
            }    
        }    
    }   

    Print(L"Kernel Loaded\n\r");

    void (*KernelStart)(Framebuffer*, PSF1_FONT**) = ((__attribute__((sysv_abi)) void(*)(Framebuffer*, PSF1_FONT**) ) header.e_entry);    

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

    PSF1_FONT* newFontExt = LoadPSF1Font(NULL, L"zap-ext-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);
    }
    PSF1_FONT* fonts[] = {newFont, newFontExt};
    Framebuffer* newBuffer = InitializeGOP();

    Print(L"Base: 0x%x\n\rSize: 0x%x\n\rWidth: %d\n\rHeight: %d\n\rPixelsPerScanline: %d\n\r",
    newBuffer->BaseAddress, 
    newBuffer->BufferSize, 
    newBuffer->Width,
    newBuffer->Height, 
    newBuffer->PixelsPerScanLine);
    KernelStart(newBuffer, fonts);

    return EFI_SUCCESS; // Exit the UEFI application    
}     
c++
gcc
output
kernel
newline
asked on Stack Overflow Feb 19, 2021 by Francis Cugler • edited Feb 19, 2021 by Francis Cugler

1 Answer

2

The problem is here:

if ( (*chr == '\\') && ((*chr+1 == 'n') || (*chr+1 == '0')) ) {
    PutChar('\n');
    chr++;
    chr++;
}
...

You should not be parsing out \n since this will be present in the string as a linefeed character. What you want instead is:

if (*chr == '\n') {
    PutChar('\n');
    chr++;
}
...
answered on Stack Overflow Feb 19, 2021 by Paul Sanders

User contributions licensed under CC BY-SA 3.0