在内核项目的字符串中合并换行符时,自定义打印函数的输出无效

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

我正在开发一个内核程序来处理自定义输入的打印功能 OS。我正在关注 Poncho's 找到的第 2 个 YouTube 视频系列 here,我目前正在观看该系列的视频 4,他开始将数字类型添加为渲染器打印功能的输入。现在,我的代码和他的不完全一样,因为我做了一些修改。

-注意- 这不会直接编译,因为没有 main 函数。 _start 被此处未显示的 bootloader 调用或调用,但是我会将其添加到此问题的底部。

当我在内核中像这样使用 class 的打印功能时:

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

而我运行内核在emu。我正在显示以下输出:

This is some text
123456789
-123456789

以上是正确的,但是,当我尝试将解析换行符集的能力合并为 \n[=28=] 中的 const char* 作为如下例所示的字符串:

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

现在显示的输出是:

This is some text
 123456789
-123456789

此处,第二行的输出在调用 Print() 后显示的数值前面有一个 space,其字符串中有一个 \n。我不确定是什么导致我的代码出现这种情况。它是否与 while 条件或我如何递增和索引到 BasicRenderer::Print(const char* str) 中的字符串有关?还是来自 BasicRender::PutChar(char c)?还是在 to_string() 函数之一中?


这里是相关的实现代码...

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 == '[=14=]') {
        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;
}

这是声明的其余部分...

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

这里是调用上述 kernelbootloader 应用程序。

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    
}     

问题出在这里:

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

您不应该解析出 \n,因为这将作为换行符出现在字符串中。你想要的是:

if (*chr == '\n') {
    PutChar('\n');
    chr++;
}
...