[WIP] Implementing "console" output and stuff.

This commit is contained in:
Patrick 2024-01-16 10:21:14 +01:00
parent e938f76823
commit 6ec9e0d320
21 changed files with 509 additions and 216 deletions

View File

@ -15,6 +15,7 @@ target = GetOption('target')
env = Environment(tools = ['default', 'compilation_db']) env = Environment(tools = ['default', 'compilation_db'])
env.Append(CCFLAGS = ['-g', '-O0']) env.Append(CCFLAGS = ['-g', '-O0'])
# env.Append(CCFLAGS = ['-O2'])
env['ISO_FILES'] = [] env['ISO_FILES'] = []
env = SConscript('bastl/SConscript', exports = 'env') env = SConscript('bastl/SConscript', exports = 'env')

View File

@ -24,7 +24,7 @@ public:
using iterator = pointer; using iterator = pointer;
using const_iterator = const_pointer; using const_iterator = const_pointer;
T _elements; T _elements[N];
constexpr reference operator[](size_type pos) noexcept constexpr reference operator[](size_type pos) noexcept
{ {

View File

@ -1,17 +1,54 @@
Import('env') Import('env')
def _resource(env, res, symbol):
def _generate_s(target, source, env):
with open(target[0].abspath, 'w') as f:
f.write(f'''
.section .rodata
.global {symbol}
.type {symbol} @object
.section .rodata
.global {symbol}_SIZE
.type {symbol}_SIZE @object
{symbol}:
.incbin "{res}"
{symbol}_END:
{symbol}_SIZE:
.int {symbol}_END - {symbol}
''')
with open(target[1].abspath, 'w') as f:
f.write(f'''
#pragma once
#include <stdint.h>
extern "C"
{{
extern const uint8_t {symbol}[];
extern const unsigned {symbol}_SIZE;
}}
''')
env.Command([f'{res}.s', f'{res}.hpp'.replace('src/', 'include/')], res, action = _generate_s)
env.AddMethod(_resource, 'Resource')
any_target_sources = Split(''' any_target_sources = Split('''
src/app/main.cpp src/app/main.cpp
src/libs/psf.cpp
src/os/draw.cpp src/os/draw.cpp
src/os/panic.cpp src/os/panic.cpp
src/os/tty.cpp src/os/tty.cpp
src/os/resources/lat9-08.psf.s
src/cstdlib/assert.cpp src/cstdlib/assert.cpp
src/cstdlib/stdio.cpp src/cstdlib/stdio.cpp
src/cstdlib/stdlib.cpp src/cstdlib/stdlib.cpp
src/cstdlib/string.cpp src/cstdlib/string.cpp
''') ''')
env.Resource(env.File('src/os/resources/lat9-08.psf').abspath, 'LAT9_08')
env.Append(KERNEL_SOURCES = [env.File(f) for f in any_target_sources]) env.Append(KERNEL_SOURCES = [env.File(f) for f in any_target_sources])

View File

@ -0,0 +1,77 @@
#pragma once
#if !defined(BAD_APPLE_OS_PSF_HPP_INCLUDED)
#define BAD_APPLE_OS_PSF_HPP_INCLUDED
#include <stddef.h>
#include <stdint.h>
namespace psf
{
inline const uint32_t MAGIC = 0x864ab572;
struct Header
{
uint32_t magic; /* magic bytes to identify PSF */
uint32_t version; /* zero */
uint32_t headersize; /* offset of bitmaps in file, 32 */
uint32_t flags; /* 0 if there's no unicode table */
uint32_t numglyph; /* number of glyphs */
uint32_t bytesperglyph; /* size of each glyph */
uint32_t height; /* height in pixels */
uint32_t width; /* width in pixels */
};
class Font
{
private:
const Header* mMemory = nullptr;
size_t mSize = 0;
public:
Font() noexcept = default;
Font(const Font&) = default;
private:
Font(const Header* memory, size_t size) noexcept : mMemory(memory), mSize(size) {}
public:
Font& operator=(const Font&) noexcept = default;
[[nodiscard]] uint32_t getGlyphWidth() const noexcept { return mMemory->width; }
[[nodiscard]] uint32_t getGlyphHeight() const noexcept { return mMemory->height; }
template<typename TColor, typename TDrawFn>
void writeGlyph(char chr, const TColor& fgColor, const TColor& bgColor, TDrawFn draw) const noexcept;
public:
[[nodiscard]] static bool create(const void* data, size_t size, Font& outFont) noexcept;
};
template<typename TColor, typename TDrawFn>
void Font::writeGlyph(char chr, const TColor& fgColor, const TColor& bgColor, TDrawFn draw) const noexcept
{
if (chr > mMemory->numglyph) {
chr = 0;
}
const uint8_t* glyphData = reinterpret_cast<const uint8_t*>(mMemory) + mMemory->headersize + chr * mMemory->bytesperglyph;
for (unsigned y = 0; y < mMemory->height; ++y)
{
for (unsigned x = 0; x < mMemory->width; ++x)
{
const unsigned idx = y * mMemory->width + x;
const unsigned byte = idx / 8;
const unsigned bit = idx % 8;
if (glyphData[byte] & (0b10000000 >> bit))
{
draw(x, y, fgColor);
}
else
{
draw(x, y, bgColor);
}
}
}
}
}
#endif // !defined(BAD_APPLE_OS_PSF_HPP_INCLUDED)

View File

@ -5,8 +5,13 @@
#define BAD_APPLE_OS_DRAW_HPP_INCLUDED #define BAD_APPLE_OS_DRAW_HPP_INCLUDED
#include <stdint.h> #include <stdint.h>
#include <array>
#include <vector> #include <vector>
namespace psf
{
class Font;
}
namespace draw namespace draw
{ {
const unsigned SIZE_FULL = static_cast<unsigned>(-1); const unsigned SIZE_FULL = static_cast<unsigned>(-1);
@ -19,6 +24,10 @@ struct Pixel
uint8_t reserved_ = 0; uint8_t reserved_ = 0;
}; };
inline Pixel PIXEL_WHITE = {255, 255, 255};
inline Pixel PIXEL_BLACK = {0, 0, 0};
extern const std::array<Pixel, 16> VGA_PIXELS;
class Framebuffer class Framebuffer
{ {
protected: protected:
@ -38,6 +47,7 @@ public:
[[nodiscard]] unsigned getPitch() const noexcept { return mPitch; } [[nodiscard]] unsigned getPitch() const noexcept { return mPitch; }
[[nodiscard]] unsigned getBufferSize() const noexcept { return mPitch * mHeight * sizeof(Pixel); } [[nodiscard]] unsigned getBufferSize() const noexcept { return mPitch * mHeight * sizeof(Pixel); }
const Pixel& getPixel(unsigned posX, unsigned posY) noexcept;
void setPixel(unsigned posX, unsigned posY, Pixel pixel) noexcept; void setPixel(unsigned posX, unsigned posY, Pixel pixel) noexcept;
}; };
@ -61,9 +71,15 @@ public:
}; };
void initializeDefaultFramebuffer(const Framebuffer& framebuffer) noexcept; void initializeDefaultFramebuffer(const Framebuffer& framebuffer) noexcept;
[[nodiscard]] const Framebuffer& getPrimaryFramebuffer() noexcept;
void setPixelDirect(unsigned posX, unsigned posY, Pixel pixel) noexcept; void setPixelDirect(unsigned posX, unsigned posY, Pixel pixel) noexcept;
void setPixel(unsigned posX, unsigned posY, Pixel pixel) noexcept; void setPixel(unsigned posX, unsigned posY, Pixel pixel) noexcept;
void flushPixels() noexcept; const Pixel& getPixel(unsigned posX, unsigned posY) noexcept;
void character(unsigned posX, unsigned posY, const psf::Font& font, char chr, const Pixel& fgColor = PIXEL_WHITE, const Pixel& bgColor = PIXEL_BLACK) noexcept;
void scrollBy(int scrollX, int scrollY, const Pixel& fillColor = PIXEL_BLACK) noexcept;
} }
#endif // !defined(BAD_APPLE_OS_FRAMEBUFFER_HPP_INCLUDED) #endif // !defined(BAD_APPLE_OS_FRAMEBUFFER_HPP_INCLUDED)

View File

@ -0,0 +1 @@
*.hpp

View File

@ -35,12 +35,14 @@ struct VgaDoubleColor
VgaColor background : 4 = VgaColor::BLACK; VgaColor background : 4 = VgaColor::BLACK;
}; };
void initialize(); void initialize() noexcept;
void setColor(VgaDoubleColor color); void setColor(VgaDoubleColor color) noexcept;
void putEntryAt(char chr, VgaDoubleColor color, size_t posX, size_t posY); void putEntryAt(char chr, VgaDoubleColor color, size_t posX, size_t posY) noexcept;
void putChar(char chr); void putChar(char chr) noexcept;
void write(const char* data, size_t size); void write(const char* data, size_t size) noexcept;
void write(const char* data); void write(const char* data) noexcept;
bool setPSFFont(const void* data, size_t length) noexcept;
} // namespace tty } // namespace tty
#endif // OS_TTY_HPP_INCLUDED #endif // OS_TTY_HPP_INCLUDED

View File

@ -11,7 +11,7 @@ BA_EXTERN_C_BEGIN
int putchar(int chr) BA_CXX_NOEXCEPT; int putchar(int chr) BA_CXX_NOEXCEPT;
int puts(const char* str) BA_CXX_NOEXCEPT; int puts(const char* str) BA_CXX_NOEXCEPT;
int printf(const char* format, ...) BA_CXX_NOEXCEPT; int printf(const char* format, ...) BA_CXX_NOEXCEPT __attribute__((format(printf, 1, 2)));
int vprintf(const char* format, va_list vlist) BA_CXX_NOEXCEPT; int vprintf(const char* format, va_list vlist) BA_CXX_NOEXCEPT;
BA_EXTERN_C_END BA_EXTERN_C_END

View File

@ -6,7 +6,7 @@
namespace namespace
{ {
inline const size_t INIT_MALLOC_SPACE_ELEMENTS = 1024; inline const size_t INIT_MALLOC_SPACE_ELEMENTS = 1024 * 1024;
inline const size_t INIT_MALLOC_SPACE_BYTES = INIT_MALLOC_SPACE_ELEMENTS * sizeof(max_align_t); inline const size_t INIT_MALLOC_SPACE_BYTES = INIT_MALLOC_SPACE_ELEMENTS * sizeof(max_align_t);
max_align_t gInitMallocSpace[INIT_MALLOC_SPACE_ELEMENTS]; max_align_t gInitMallocSpace[INIT_MALLOC_SPACE_ELEMENTS];

View File

@ -19,6 +19,7 @@ int memcmp(const void* lhs, const void* rhs, size_t count) noexcept
return 0; return 0;
} }
#if !defined(__x86_64__)
void memcpy(void* dest, const void* src, size_t count) noexcept void memcpy(void* dest, const void* src, size_t count) noexcept
{ {
for (size_t pos = 0; pos < count; ++pos) for (size_t pos = 0; pos < count; ++pos)
@ -26,6 +27,7 @@ void memcpy(void* dest, const void* src, size_t count) noexcept
*(static_cast<uint8_t*>(dest) + pos) = *(static_cast<const uint8_t*>(src) + pos); *(static_cast<uint8_t*>(dest) + pos) = *(static_cast<const uint8_t*>(src) + pos);
} }
} }
#endif
void memmove(void* dest, const void* src, size_t count) noexcept void memmove(void* dest, const void* src, size_t count) noexcept
{ {

View File

@ -0,0 +1,18 @@
#include "libs/psf.hpp"
namespace psf
{
bool Font::create(const void* data, size_t size, Font& outFont) noexcept
{
if (size < sizeof(Header)) {
return false;
}
const Header* header = static_cast<const Header*>(data);
if (header->magic != MAGIC) {
return false;
}
outFont = Font(header, size);
return true;
}
}

View File

@ -2,6 +2,7 @@
#include "os/draw.hpp" #include "os/draw.hpp"
#include <cstring> #include <cstring>
#include "libs/psf.hpp"
namespace draw namespace draw
{ {
@ -9,7 +10,39 @@ namespace
{ {
Framebuffer gFramebuffer; Framebuffer gFramebuffer;
OwningFramebuffer gDoubleBuffer; OwningFramebuffer gDoubleBuffer;
void scrollVertical(int scrollY, const Pixel& fillColor) noexcept
{
if (scrollY == 0) {
return;
}
const std::ptrdiff_t pixelOffset = scrollY * gFramebuffer.getPitch();
if (scrollY > 0)
{
// std::memmove(gFramebuffer.getBase(), gFramebuffer.getBase() + pixelOffset, gFramebuffer.getBufferSize() - (4 * pixelOffset));
// std::memset(gFramebuffer.getBase() + pixelOffset, 0, )
}
} }
}
const std::array<Pixel, 16> VGA_PIXELS = {
Pixel{0, 0, 0},
Pixel{0, 0, 170},
Pixel{0, 170, 0},
Pixel{170, 170, 0},
Pixel{170, 0, 0},
Pixel{170, 0, 170},
Pixel{170, 85, 0},
Pixel{170, 170, 170},
Pixel{85, 85, 85},
Pixel{85, 85, 255},
Pixel{85, 255, 85},
Pixel{85, 255, 255},
Pixel{255, 85, 85},
Pixel{255, 85, 255},
Pixel{255, 255, 85},
Pixel{255, 255, 255}
};
OwningFramebuffer::OwningFramebuffer(unsigned width, unsigned height, unsigned pitch) noexcept OwningFramebuffer::OwningFramebuffer(unsigned width, unsigned height, unsigned pitch) noexcept
: Framebuffer(nullptr, width, height, pitch) : Framebuffer(nullptr, width, height, pitch)
@ -18,6 +51,14 @@ OwningFramebuffer::OwningFramebuffer(unsigned width, unsigned height, unsigned p
mBase = mPixels.data(); mBase = mPixels.data();
} }
const Pixel& Framebuffer::getPixel(unsigned posX, unsigned posY) noexcept
{
if (posX >= mWidth || posY >= mHeight) {
return VGA_PIXELS[0]; // black
}
return mBase[posY * mPitch + posX];
}
void Framebuffer::setPixel(unsigned int posX, unsigned int posY, Pixel pixel) noexcept void Framebuffer::setPixel(unsigned int posX, unsigned int posY, Pixel pixel) noexcept
{ {
if (posX >= mWidth || posY > mHeight) { if (posX >= mWidth || posY > mHeight) {
@ -33,6 +74,11 @@ void initializeDefaultFramebuffer(const Framebuffer& framebuffer) noexcept
gDoubleBuffer = OwningFramebuffer::makeFrom(gFramebuffer); gDoubleBuffer = OwningFramebuffer::makeFrom(gFramebuffer);
} }
const Framebuffer& getPrimaryFramebuffer() noexcept
{
return gFramebuffer;
}
void setPixelDirect(unsigned posX, unsigned posY, Pixel pixel) noexcept void setPixelDirect(unsigned posX, unsigned posY, Pixel pixel) noexcept
{ {
gFramebuffer.setPixel(posX, posY, pixel); gFramebuffer.setPixel(posX, posY, pixel);
@ -42,11 +88,58 @@ void setPixelDirect(unsigned posX, unsigned posY, Pixel pixel) noexcept
void setPixel(unsigned posX, unsigned posY, Pixel pixel) noexcept void setPixel(unsigned posX, unsigned posY, Pixel pixel) noexcept
{ {
gDoubleBuffer.setPixel(posX, posY, pixel); setPixelDirect(posX, posY, pixel);
//gDoubleBuffer.setPixel(posX, posY, pixel);
} }
void flushPixels() noexcept const Pixel& getPixel(unsigned posX, unsigned posY) noexcept
{ {
std::memcpy(gFramebuffer.getBase(), gDoubleBuffer.getBase(), gFramebuffer.getBufferSize()); return gDoubleBuffer.getPixel(posX, posY);
}
void character(unsigned posX, unsigned posY, const psf::Font& font, char chr, const Pixel& fgColor, const Pixel& bgColor) noexcept
{
auto draw = [&](unsigned pxX, unsigned pxY, const Pixel& pixel)
{
setPixel(posX + pxX, posY + pxY, pixel);
};
font.writeGlyph(chr, fgColor, bgColor, draw);
}
void scrollBy(int scrollX, int scrollY, const Pixel& fillColor) noexcept
{
// if (scrollX == 0)
// {
// scrollVertical(scrollY, fillColor);
// return;
// }
const int width = static_cast<int>(gFramebuffer.getHeight());
const int height = static_cast<int>(gFramebuffer.getHeight());
const bool reverseX = scrollX < 0;
const bool reverseY = scrollY < 0;
for (int posY = 0; posY < height; ++posY)
{
if (reverseY) {
posY = height - posY - 1;
}
for (int posX = 0; posX < width; ++posX)
{
if (reverseX) {
posX = width - posX - 1;
}
int readX = static_cast<int>(posX) + scrollX;
int readY = static_cast<int>(posY) + scrollY;
if (readX < 0 || readX >= width || readY < 0 || readY >= height)
{
setPixel(posX, posY, fillColor);
}
else
{
setPixel(posX, posY, getPixel(readX, readY));
}
}
}
} }
} }

View File

@ -0,0 +1,3 @@
# these are generated from the resources
*.hpp
*.s

Binary file not shown.

View File

@ -2,18 +2,23 @@
#include "os/tty.hpp" #include "os/tty.hpp"
#include <cstring> #include <cstring>
#include <vector>
#include "libs/psf.hpp"
#include "os/draw.hpp"
#include "os/resources/lat9-08.psf.hpp"
namespace tty namespace tty
{ {
namespace namespace
{ {
inline const size_t VGA_WIDTH = 80;
inline const size_t VGA_HEIGHT = 25;
size_t gTerminalRow = 0; size_t gTerminalRow = 0;
size_t gTerminalColumn = 0; size_t gTerminalColumn = 0;
size_t gTerminalWidth = 0;
size_t gTerminalHeight = 0;
VgaDoubleColor gTerminalColor = VgaDoubleColor(); VgaDoubleColor gTerminalColor = VgaDoubleColor();
uint16_t* gTerminalBuffer = reinterpret_cast<uint16_t*>(0xB8000); // uint16_t* gTerminalBuffer = reinterpret_cast<uint16_t*>(0xB8000);
std::vector<uint16_t> gTerminalBuffer;
psf::Font gTerminalFont;
constexpr uint8_t vgaEntryColor(VgaDoubleColor color) constexpr uint8_t vgaEntryColor(VgaDoubleColor color)
{ {
@ -28,42 +33,40 @@ constexpr uint16_t vgaEntry(const unsigned char chr, const VgaDoubleColor color)
void newline() void newline()
{ {
gTerminalColumn = 0; gTerminalColumn = 0;
if (gTerminalRow < VGA_HEIGHT - 1) if (gTerminalRow < gTerminalHeight - 1)
{ {
++gTerminalRow; ++gTerminalRow;
} }
else else
{ {
// scrolling up draw::scrollBy(0, static_cast<int>(gTerminalFont.getGlyphHeight()) + 1);
std::memmove(&gTerminalBuffer[0], &gTerminalBuffer[VGA_WIDTH], VGA_WIDTH * (VGA_HEIGHT - 1) * sizeof(uint16_t));
} }
} }
} }
void initialize() void initialize() noexcept
{ {
for (size_t y = 0; y < VGA_HEIGHT; y++) setPSFFont(&LAT9_08[0], LAT9_08_SIZE);
{
for (size_t x = 0; x < VGA_WIDTH; x++)
{
const size_t index = y * VGA_WIDTH + x;
gTerminalBuffer[index] = vgaEntry(' ', gTerminalColor);
}
}
} }
void setColor(VgaDoubleColor color) void setColor(VgaDoubleColor color) noexcept
{ {
gTerminalColor = color; gTerminalColor = color;
} }
void putEntryAt(char chr, VgaDoubleColor color, size_t posX, size_t posY) void putEntryAt(char chr, VgaDoubleColor color, size_t posX, size_t posY) noexcept
{ {
const size_t index = posY * VGA_WIDTH + posX; draw::character(
gTerminalBuffer[index] = vgaEntry(chr, color); /* posX = */ (gTerminalFont.getGlyphWidth() + 1) * posX,
/* posY = */ (gTerminalFont.getGlyphHeight() + 1) * posY,
/* font = */ gTerminalFont,
/* chr = */ chr,
/* fgColor = */ draw::VGA_PIXELS[static_cast<uint8_t>(color.foreground)],
/* bgColor = */ draw::VGA_PIXELS[static_cast<uint8_t>(color.background)]
);
} }
void putChar(char chr) void putChar(char chr) noexcept
{ {
if (chr == '\n') if (chr == '\n')
{ {
@ -72,13 +75,13 @@ void putChar(char chr)
} }
putEntryAt(chr, gTerminalColor, gTerminalColumn, gTerminalRow); putEntryAt(chr, gTerminalColor, gTerminalColumn, gTerminalRow);
if (++gTerminalColumn == VGA_WIDTH) if (++gTerminalColumn == gTerminalWidth)
{ {
newline(); newline();
} }
} }
void write(const char* data, size_t size) void write(const char* data, size_t size) noexcept
{ {
for (size_t idx = 0; idx < size; idx++) for (size_t idx = 0; idx < size; idx++)
{ {
@ -86,8 +89,20 @@ void write(const char* data, size_t size)
} }
} }
void write(const char* data) void write(const char* data) noexcept
{ {
write(data, std::strlen(data)); write(data, std::strlen(data));
} }
bool setPSFFont(const void* data, size_t length) noexcept
{
psf::Font newFont;
if (!psf::Font::create(data, length, newFont)) {
return false;
}
gTerminalFont = newFont;
gTerminalWidth = draw::getPrimaryFramebuffer().getWidth() / (gTerminalFont.getGlyphWidth() + 1);
gTerminalHeight = draw::getPrimaryFramebuffer().getHeight() / (gTerminalFont.getGlyphHeight() + 1);
return true;
}
} }

View File

@ -28,6 +28,8 @@ crtn_o = kernel_env.Object('src/crt/crtn.s')
kernel_env['LINKCOM'] = env['LINKCOM'].replace('$_LIBFLAGS', f'{crti_o[0].abspath} {crtbegin_o} $_LIBFLAGS -lgcc {crtend_o} {crtn_o[0].abspath}') kernel_env['LINKCOM'] = env['LINKCOM'].replace('$_LIBFLAGS', f'{crti_o[0].abspath} {crtbegin_o} $_LIBFLAGS -lgcc {crtend_o} {crtn_o[0].abspath}')
kernel_sources = env['KERNEL_SOURCES'] + Split(''' kernel_sources = env['KERNEL_SOURCES'] + Split('''
src/cstdlib/memory.s
src/kernel/boot.s src/kernel/boot.s
src/kernel/startup.cpp src/kernel/startup.cpp
''') ''')
@ -37,7 +39,7 @@ prog_kernel = kernel_env.Program(
target = kernel_target, target = kernel_target,
source = kernel_sources source = kernel_sources
) )
kernel_env.Depends(prog_kernel, [crti_o, crtn_o]) kernel_env.Depends(prog_kernel, [crti_o, crtn_o] + kernel_sources)
kernel_env.Default(prog_kernel) kernel_env.Default(prog_kernel)
x86_64_iso_files = [ x86_64_iso_files = [
@ -69,7 +71,6 @@ uefi_env.Append(CPPPATH = ['/usr/include/efi', 'include'])
loader_sources = Split(''' loader_sources = Split('''
src/loader/main.cpp src/loader/main.cpp
src/loader/minimalloc.cpp
src/loader/miniprintf.cpp src/loader/miniprintf.cpp
''') ''')
loader_target = uefi_env.File('#loader.x86_64.efi') loader_target = uefi_env.File('#loader.x86_64.efi')

View File

@ -75,7 +75,34 @@ struct EfiDisplayInfo
struct EfiBootInfo struct EfiBootInfo
{ {
EfiMemoryMap memoryMap; EfiMemoryMap memoryMap;
EfiDisplayInfo displayInfo; EfiDisplayInfo displayInfo = {};
}; };
inline bool isEfiMemoryTypeUsable(UINT32 type) noexcept
{
switch (type)
{
case EfiLoaderCode:
case EfiLoaderData:
case EfiBootServicesCode:
case EfiBootServicesData:
case EfiConventionalMemory:
return true;
case EfiReservedMemoryType:
case EfiRuntimeServicesCode:
case EfiRuntimeServicesData:
case EfiUnusableMemory:
case EfiACPIReclaimMemory:
case EfiACPIMemoryNVS:
case EfiMemoryMappedIO:
case EfiMemoryMappedIOPortSpace:
case EfiPalCode:
case EfiMaxMemoryType:
default:
return false;
}
}
#endif // BOOT_HPP_INCLUDED #endif // BOOT_HPP_INCLUDED

View File

@ -0,0 +1,27 @@
.section .text
.global memcpy
.type memcpy @function
// int memcpy(void* dest [%rdi], void* src [%rsi], size_t count [%rdx])
//
memcpy:
cmpq %rdx, 4
jl memcpy_bytes
movq (%rsi), %rax
movq %rax, (%rdi)
addq $4, %rsi
addq $4, %rdi
subq $4, %rdx
jmp memcpy
memcpy_bytes:
cmpq %rdx, 0
je memcpy_end
movb (%rsi), %ah
movb %ah, (%rdi)
addq $1, %rsi
addq $1, %rdi
subq $1, %rdx
jmp memcpy_bytes
memcpy_end:
ret

View File

@ -1,5 +1,6 @@
#include <cstdio> #include <cstdio>
#include <cstring>
#include "boot.hpp" #include "boot.hpp"
#include "os/draw.hpp" #include "os/draw.hpp"
@ -14,8 +15,7 @@ void initHeapFromEfiMemoryMap(const EfiMemoryMap& memoryMap) noexcept
const uint64_t minAddr = reinterpret_cast<uint64_t>(&gKernelEnd); const uint64_t minAddr = reinterpret_cast<uint64_t>(&gKernelEnd);
for (const EFI_MEMORY_DESCRIPTOR& descriptor : memoryMap) for (const EFI_MEMORY_DESCRIPTOR& descriptor : memoryMap)
{ {
// TODO: what about other types? if (!isEfiMemoryTypeUsable(descriptor.Type))
if (descriptor.Type != EfiConventionalMemory)
{ {
continue; continue;
} }
@ -97,7 +97,7 @@ void kernel_main()
initGlobals(); initGlobals();
// init the heap (required for the double buffer) // init the heap (required for the double buffer)
initHeapFromEfiMemoryMap(gBootInfo->memoryMap); // initHeapFromEfiMemoryMap(gBootInfo->memoryMap);
// initialize the framebuffer // initialize the framebuffer
draw::initializeDefaultFramebuffer({ draw::initializeDefaultFramebuffer({
@ -108,18 +108,27 @@ void kernel_main()
}); });
// initialize terminal interface // initialize terminal interface
// tty::initialize(); tty::initialize();
// std::printf("Kernel End: %p\n", &gKernelEnd); // std::printf("Kernel End: %p\n", &gKernelEnd);
uint8_t test[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
uint8_t dest[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
std::memcpy(&dest[1], &test[3], 2);
for (int i = 0; i < 400; ++i)
{
std::printf("Hello font %d!\n", i);
}
#if 0
for (int x = 0; x < 100; ++x) for (int x = 0; x < 100; ++x)
{ {
for (int y = 0; y < 100; ++y) for (int y = 0; y < 100; ++y)
{ {
draw::setPixel(x, y, {.red = 255}); draw::setPixelDirect(x, y, {.red = 255});
} }
} }
draw::flushPixels(); #endif
//draw::flushPixels();
/* Initialize the heap */ /* Initialize the heap */
// assert(gMultibootHeader->flags & MULTIBOOT_INFO_MEM_MAP); // assert(gMultibootHeader->flags & MULTIBOOT_INFO_MEM_MAP);

View File

@ -5,13 +5,15 @@ extern "C"
} }
#include "boot.hpp" #include "boot.hpp"
#include "minielf.hpp" #include "minielf.hpp"
#include "minimalloc.hpp"
#include "miniprintf.hpp" #include "miniprintf.hpp"
// debug stuff // debug stuff
// #define DUMP_DISPLAY_MODES // #define DUMP_DISPLAY_MODES
// #define DUMP_MEMORY_MAP // #define DUMP_MEMORY_MAP
// #define DUMP_ELF // #define DUMP_ELF
#define PRINTLINE3(file, line) print(L"At: " file L":" #line L"\r\n")
#define PRINTLINE2(file, line) PRINTLINE3(file, line)
#define PRINTLINE() PRINTLINE2(__FILE__, __LINE__)
namespace namespace
{ {
@ -19,6 +21,21 @@ EFI_SYSTEM_TABLE* gSystemTable;
EFI_BOOT_SERVICES* gBootServices; EFI_BOOT_SERVICES* gBootServices;
EFI_GRAPHICS_OUTPUT_PROTOCOL* gGraphicsOutputProtocol; EFI_GRAPHICS_OUTPUT_PROTOCOL* gGraphicsOutputProtocol;
void* malloc(size_t size) noexcept
{
void* ptr = nullptr;
gBootServices->AllocatePool(EfiLoaderData, size, &ptr);
return ptr;
}
void free(void* ptr) noexcept
{
// if (ptr != nullptr)
// {
// gBootServices->FreePool(ptr);
// }
}
EFI_STATUS openImageVolume(EFI_HANDLE image, EFI_FILE_HANDLE& outHandle) EFI_STATUS openImageVolume(EFI_HANDLE image, EFI_FILE_HANDLE& outHandle)
{ {
EFI_LOADED_IMAGE* loadedImage = nullptr; EFI_LOADED_IMAGE* loadedImage = nullptr;
@ -112,18 +129,29 @@ EFI_STATUS getEfiMemoryMap(EfiMemoryMap& outMemoryMap)
UINTN mapKey = 0; UINTN mapKey = 0;
UINTN descriptorSize = 0; UINTN descriptorSize = 0;
UINT32 descriptorVersion = 0; UINT32 descriptorVersion = 0;
EFI_STATUS status = gBootServices->GetMemoryMap(&mapSize, nullptr, &mapKey, &descriptorSize, &descriptorVersion);
EFI_STATUS status = EFI_BUFFER_TOO_SMALL;
while (true)
{
status = gBootServices->GetMemoryMap(&mapSize, map, &mapKey, &descriptorSize, &descriptorVersion);
if (status != EFI_BUFFER_TOO_SMALL) { if (status != EFI_BUFFER_TOO_SMALL) {
return status; break;
}
if (map != nullptr)
{
free(map);
} }
map = static_cast<EFI_MEMORY_DESCRIPTOR*>(malloc(mapSize)); map = static_cast<EFI_MEMORY_DESCRIPTOR*>(malloc(mapSize));
if (map == nullptr) { if (map == nullptr) {
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
} }
status = gBootServices->GetMemoryMap(&mapSize, map, &mapKey, &descriptorSize, &descriptorVersion); }
if (EFI_ERROR(status)) if (EFI_ERROR(status))
{ {
free(map); if (map != nullptr)
{
gBootServices->FreePool(map);
}
return status; return status;
} }
outMemoryMap.mapSize = mapSize; outMemoryMap.mapSize = mapSize;
@ -150,7 +178,7 @@ EFI_STATUS getEfiGraphicsOutputProtocol(EFI_GRAPHICS_OUTPUT_PROTOCOL*& outGOP)
EFI_STATUS queryEfiDisplayModes(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*& outModes) EFI_STATUS queryEfiDisplayModes(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*& outModes)
{ {
UINTN sizeOfInfo = gGraphicsOutputProtocol->Mode->SizeOfInfo; UINTN sizeOfInfo = gGraphicsOutputProtocol->Mode->SizeOfInfo;
outModes = new EFI_GRAPHICS_OUTPUT_MODE_INFORMATION[gGraphicsOutputProtocol->Mode->MaxMode]; outModes = static_cast<EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*>(malloc(gGraphicsOutputProtocol->Mode->MaxMode * sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)));
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* buffer = static_cast<EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*>(malloc(sizeOfInfo)); EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* buffer = static_cast<EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*>(malloc(sizeOfInfo));
for (UINT32 modeIdx = 0; modeIdx < gGraphicsOutputProtocol->Mode->MaxMode; ++modeIdx) for (UINT32 modeIdx = 0; modeIdx < gGraphicsOutputProtocol->Mode->MaxMode; ++modeIdx)
@ -158,7 +186,7 @@ EFI_STATUS queryEfiDisplayModes(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*& outModes)
EFI_STATUS status = gGraphicsOutputProtocol->QueryMode(gGraphicsOutputProtocol, modeIdx, &sizeOfInfo, &buffer); EFI_STATUS status = gGraphicsOutputProtocol->QueryMode(gGraphicsOutputProtocol, modeIdx, &sizeOfInfo, &buffer);
if (EFI_ERROR(status)) if (EFI_ERROR(status))
{ {
delete[] outModes; free(outModes);
free(buffer); free(buffer);
return status; return status;
} }
@ -187,28 +215,76 @@ UINT32 findBestDisplayMode(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* displayModes)
return bestMode; return bestMode;
} }
bool isEfiMemoryTypeUsable(EFI_MEMORY_TYPE type) const char* efiStatusToString(EFI_STATUS status)
{ {
switch (type) switch (status)
{ {
case EfiLoaderCode: case EFI_SUCCESS:
case EfiLoaderData: return "EFI_SUCCESS";
case EfiBootServicesCode: case EFI_LOAD_ERROR:
case EfiBootServicesData: return "EFI_LOAD_ERROR";
case EfiConventionalMemory: case EFI_INVALID_PARAMETER:
return true; return "EFI_INVALID_PARAMETER";
case EfiReservedMemoryType: case EFI_UNSUPPORTED:
case EfiRuntimeServicesCode: return "EFI_UNSUPPORTED";
case EfiRuntimeServicesData: case EFI_BAD_BUFFER_SIZE:
case EfiUnusableMemory: return "EFI_BAD_BUFFER_SIZE";
case EfiACPIReclaimMemory: case EFI_BUFFER_TOO_SMALL:
case EfiACPIMemoryNVS: return "EFI_BUFFER_TOO_SMALL";
case EfiMemoryMappedIO: case EFI_NOT_READY:
case EfiMemoryMappedIOPortSpace: return "EFI_NOT_READY";
case EfiPalCode: case EFI_DEVICE_ERROR:
case EfiMaxMemoryType: return "EFI_DEVICE_ERROR";
case EFI_WRITE_PROTECTED:
return "EFI_WRITE_PROTECTED";
case EFI_OUT_OF_RESOURCES:
return "EFI_OUT_OF_RESOURCES";
case EFI_VOLUME_CORRUPTED:
return "EFI_VOLUME_CORRUPTED";
case EFI_VOLUME_FULL:
return "EFI_VOLUME_FULL";
case EFI_NO_MEDIA:
return "EFI_NO_MEDIA";
case EFI_MEDIA_CHANGED:
return "EFI_MEDIA_CHANGED";
case EFI_NOT_FOUND:
return "EFI_NOT_FOUND";
case EFI_ACCESS_DENIED:
return "EFI_ACCESS_DENIED";
case EFI_NO_RESPONSE:
return "EFI_NO_RESPONSE";
case EFI_NO_MAPPING:
return "EFI_NO_MAPPING";
case EFI_TIMEOUT:
return "EFI_TIMEOUT";
case EFI_NOT_STARTED:
return "EFI_NOT_STARTED";
case EFI_ALREADY_STARTED:
return "EFI_ALREADY_STARTED";
case EFI_ABORTED:
return "EFI_ABORTED";
case EFI_ICMP_ERROR:
return "EFI_ICMP_ERROR";
case EFI_TFTP_ERROR:
return "EFI_TFTP_ERROR";
case EFI_PROTOCOL_ERROR:
return "EFI_PROTOCOL_ERROR";
case EFI_INCOMPATIBLE_VERSION:
return "EFI_INCOMPATIBLE_VERSION";
case EFI_SECURITY_VIOLATION:
return "EFI_SECURITY_VIOLATION";
case EFI_CRC_ERROR:
return "EFI_CRC_ERROR";
case EFI_END_OF_MEDIA:
return "EFI_END_OF_MEDIA";
case EFI_END_OF_FILE:
return "EFI_END_OF_FILE";
case EFI_INVALID_LANGUAGE:
return "EFI_INVALID_LANGUAGE";
case EFI_COMPROMISED_DATA:
return "EFI_COMPROMISED_DATA";
default: default:
return false; return "UNKNOWN";
} }
} }
} }
@ -216,6 +292,7 @@ bool isEfiMemoryTypeUsable(EFI_MEMORY_TYPE type)
#define DIE_ON_ERROR(message) \ #define DIE_ON_ERROR(message) \
if (EFI_ERROR(status)) \ if (EFI_ERROR(status)) \
{ \ { \
printf("Status: %s\n", efiStatusToString(status)); \
printAndWait(message L"\r\n"); \ printAndWait(message L"\r\n"); \
return status; \ return status; \
} }
@ -226,11 +303,10 @@ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemT
gSystemTable = systemTable; gSystemTable = systemTable;
gBootServices = systemTable->BootServices; gBootServices = systemTable->BootServices;
initMiniMalloc();
initMiniPrintf(&putchar); initMiniPrintf(&putchar);
// this will be passed to the OS // this will be passed to the OS
EfiBootInfo* bootInfo = new EfiBootInfo; EfiBootInfo* bootInfo = static_cast<EfiBootInfo*>(malloc(sizeof(EfiBootInfo)));
gSystemTable->ConOut->ClearScreen(gSystemTable->ConOut); gSystemTable->ConOut->ClearScreen(gSystemTable->ConOut);
@ -246,6 +322,10 @@ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemT
status = gGraphicsOutputProtocol->SetMode(gGraphicsOutputProtocol, bestModeIdx); status = gGraphicsOutputProtocol->SetMode(gGraphicsOutputProtocol, bestModeIdx);
DIE_ON_ERROR(L"Error setting display mode."); DIE_ON_ERROR(L"Error setting display mode.");
UINTN consoleColumns, consoleRows;
status = gSystemTable->ConOut->QueryMode(gSystemTable->ConOut, gSystemTable->ConOut->Mode->Mode, &consoleColumns, &consoleRows);
DIE_ON_ERROR(L"Error fetching console mode.");
bootInfo->displayInfo = { bootInfo->displayInfo = {
.frameBufferBase = reinterpret_cast<void*>(gGraphicsOutputProtocol->Mode->FrameBufferBase), .frameBufferBase = reinterpret_cast<void*>(gGraphicsOutputProtocol->Mode->FrameBufferBase),
.frameBufferSize = gGraphicsOutputProtocol->Mode->FrameBufferSize, .frameBufferSize = gGraphicsOutputProtocol->Mode->FrameBufferSize,
@ -329,14 +409,24 @@ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemT
#if defined(DUMP_MEMORY_MAP) #if defined(DUMP_MEMORY_MAP)
int entry = -1; int entry = -1;
for (const EFI_MEMORY_DESCRIPTOR& descriptor : *memoryMap)
{
++entry;
// if (!isEfiMemoryTypeUsable(static_cast<EFI_MEMORY_TYPE>(descriptor->Type))) { UINTN leftThisPage = consoleRows - 1;
if (descriptor.Type != EfiConventionalMemory) { printf("ltp: %d\n", static_cast<int>(leftThisPage));
for (const EFI_MEMORY_DESCRIPTOR& descriptor : bootInfo->memoryMap)
{
if (!isEfiMemoryTypeUsable(descriptor.Type)) {
// if (descriptor.Type != EfiBootServicesCode) {
continue; continue;
} }
++entry;
if (leftThisPage == 0)
{
printAndWait(L"-- Any key to continue --\r\n");
leftThisPage = consoleRows;
}
--leftThisPage;
printf( printf(
"Entry %d: type=%d, physicalStart=0x%lX, numberOfPages=%ld\n", "Entry %d: type=%d, physicalStart=0x%lX, numberOfPages=%ld\n",
entry, entry,
@ -347,7 +437,7 @@ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemT
} }
// printing may have invalidated the map, get it again // printing may have invalidated the map, get it again
status = getEfiMemoryMap(*memoryMap); status = getEfiMemoryMap(bootInfo->memoryMap);
DIE_ON_ERROR("Error getting EFI memory map."); DIE_ON_ERROR("Error getting EFI memory map.");
#undef DUMP_MEMORY_MAP #undef DUMP_MEMORY_MAP
#endif // defined(DUMP_MEMORY_MAP) #endif // defined(DUMP_MEMORY_MAP)

View File

@ -1,126 +0,0 @@
#include <stddef.h>
namespace
{
inline const size_t INIT_MALLOC_SPACE_ELEMENTS = 1024;
inline const size_t INIT_MALLOC_SPACE_BYTES = INIT_MALLOC_SPACE_ELEMENTS * sizeof(max_align_t);
max_align_t gInitMallocSpace[INIT_MALLOC_SPACE_ELEMENTS];
struct MallocBlock
{
size_t elements;
MallocBlock* nextBlock;
};
struct AllocInfo
{
size_t elements;
};
static_assert(sizeof(MallocBlock) <= sizeof(max_align_t));
static_assert(sizeof(AllocInfo) <= sizeof(max_align_t));
MallocBlock* gNextBlock;
}
void initMiniMalloc()
{
gNextBlock = reinterpret_cast<MallocBlock*>(gInitMallocSpace);
gNextBlock->elements = INIT_MALLOC_SPACE_ELEMENTS;
gNextBlock->nextBlock = nullptr;
}
extern "C"
{
void* malloc(size_t size) noexcept
{
if (size == 0)
{
return nullptr;
}
const size_t requiredElements = (size + sizeof(max_align_t) - 1) / sizeof(max_align_t) + 1;
MallocBlock* prevBlock = nullptr;
for (MallocBlock* block = gNextBlock; block != nullptr; block = block->nextBlock)
{
if (block->elements >= requiredElements)
{
MallocBlock* newBlock = nullptr;
if (block->elements > requiredElements)
{
newBlock = reinterpret_cast<MallocBlock*>(reinterpret_cast<max_align_t*>(block) + requiredElements);
newBlock->nextBlock = block->nextBlock;
newBlock->elements = block->elements - requiredElements;
}
else
{
newBlock = block->nextBlock;
}
if (prevBlock != nullptr)
{
prevBlock->nextBlock = newBlock;
}
else
{
gNextBlock = newBlock;
}
AllocInfo* allocInfo = reinterpret_cast<AllocInfo*>(block);
allocInfo->elements = requiredElements;
return reinterpret_cast<max_align_t*>(block) + 1;
}
prevBlock = block;
}
return nullptr;
}
void free(void* memory) noexcept
{
if (memory == nullptr)
{
return;
}
MallocBlock* block = reinterpret_cast<MallocBlock*>(static_cast<max_align_t*>(memory) - 1);
block->nextBlock = gNextBlock;
gNextBlock = block;
}
}
void* operator new(size_t count)
{
if (void* ptr = malloc(count); ptr != nullptr)
{
return ptr;
}
// TODO: some kind of abort
}
void operator delete(void* data) noexcept
{
free(data);
}
void* operator new[](size_t count)
{
if (void* ptr = malloc(count); ptr != nullptr)
{
return ptr;
}
// TODO: some kind of abort
}
void operator delete[](void* data) noexcept
{
free(data);
}
void operator delete(void* data, size_t /* size */) noexcept
{
free(data);
}
void operator delete[](void* data, size_t /* size */) noexcept
{
free(data);
}