Moved stdlib to a seperate folder and added some more headers that are required for compiling libgcc (no implementation yet).
This commit is contained in:
20
targets/_any/stdlib/src/assert.cpp
Normal file
20
targets/_any/stdlib/src/assert.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#if !defined(NDEBUG)
|
||||
void __ba__assert_fail(const char* filename, int line, const char* condition) noexcept
|
||||
{
|
||||
std::printf(R"(
|
||||
Assertion failed:
|
||||
File: %s
|
||||
Line: %d
|
||||
Condition: %s)" "\n", filename, line, condition);
|
||||
std::abort();
|
||||
}
|
||||
#endif
|
||||
} // extern "C"
|
||||
239
targets/_any/stdlib/src/stdio.cpp
Normal file
239
targets/_any/stdlib/src/stdio.cpp
Normal file
@@ -0,0 +1,239 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdarg.h>
|
||||
#include "os/tty.hpp"
|
||||
#include "os/tools/printf_helper.hpp"
|
||||
#include "os/tools/ringbuffer.hpp"
|
||||
|
||||
#if defined(__baos_kernel_source__)
|
||||
#include "os/serial.hpp"
|
||||
#else
|
||||
#include "os/syscall.hpp"
|
||||
#endif
|
||||
|
||||
struct __file
|
||||
{
|
||||
protected:
|
||||
static constexpr unsigned BUFFER_SIZE = 4096;
|
||||
|
||||
baos::RingBuffer<char, BUFFER_SIZE> mBuffer;
|
||||
bool mEof = false;
|
||||
bool mError = false;
|
||||
protected:
|
||||
virtual bool underflow() noexcept = 0;
|
||||
public:
|
||||
[[nodiscard]] bool isEof() const noexcept { return mEof; }
|
||||
[[nodiscard]] bool isError() const noexcept { return mError; }
|
||||
|
||||
bool readChar(char& outChar) noexcept
|
||||
{
|
||||
while (!mBuffer.next(outChar)) {
|
||||
if (!underflow()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readLine(std::string& outLine) noexcept
|
||||
{
|
||||
outLine.clear();
|
||||
while(true)
|
||||
{
|
||||
while (mBuffer.empty()) {
|
||||
if (!underflow()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// first check if there is a \n in the stream
|
||||
std::size_t count = mBuffer.size();
|
||||
for (std::size_t idx = 0; idx < mBuffer.size(); ++idx)
|
||||
{
|
||||
if (mBuffer[idx] == '\n')
|
||||
{
|
||||
count = idx + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
outLine.reserve(outLine.size() + count);
|
||||
for (std::size_t idx = 0; idx < count; ++idx)
|
||||
{
|
||||
char chr = '\0';
|
||||
mBuffer.next(chr);
|
||||
outLine.append(chr);
|
||||
}
|
||||
|
||||
if (outLine.back() == '\n')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
struct RegularPrinter
|
||||
{
|
||||
void putchar(int chr) noexcept // NOLINT
|
||||
{
|
||||
::putchar(chr);
|
||||
}
|
||||
};
|
||||
|
||||
struct BufferPrinter
|
||||
{
|
||||
char* pos = nullptr;
|
||||
char* end = nullptr;
|
||||
|
||||
void putchar(int chr) noexcept // NOLINT
|
||||
{
|
||||
if (pos != end)
|
||||
{
|
||||
*pos = static_cast<char>(chr);
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class StdinFile : public __file
|
||||
{
|
||||
public:
|
||||
bool underflow() noexcept override
|
||||
{
|
||||
for (char chr : tty::readLine()) {
|
||||
mBuffer.append(chr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
StdinFile gStdin;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
FILE* __stdin = &gStdin;
|
||||
|
||||
// TODO: line-buffering
|
||||
int putchar(int chr) noexcept
|
||||
{
|
||||
#if defined(__baos_kernel_source__)
|
||||
tty::putChar(static_cast<char>(chr));
|
||||
if (chr == '\n')
|
||||
{
|
||||
serialWrite(PORT_COM1, '\r');
|
||||
serialWrite(PORT_COM1, '\n');
|
||||
}
|
||||
else
|
||||
{
|
||||
serialWrite(PORT_COM1, static_cast<std::uint8_t>(chr));
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
char asChar = static_cast<char>(chr);
|
||||
baos::doSyscall(baos::Syscall::FILE_WRITE, 0, &asChar, 1);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int puts(const char* str) noexcept
|
||||
{
|
||||
#if defined(__baos_kernel_source__)
|
||||
while (*str)
|
||||
{
|
||||
putchar(*str);
|
||||
++str;
|
||||
}
|
||||
putchar('\n');
|
||||
return 0;
|
||||
#else
|
||||
baos::doSyscall(baos::Syscall::FILE_WRITE, 0, str, std::strlen(str));
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int printf(const char* format, ...) noexcept
|
||||
{
|
||||
va_list parameters;
|
||||
va_start(parameters, format);
|
||||
const int result = vprintf(format, parameters);
|
||||
va_end(parameters);
|
||||
return result;
|
||||
}
|
||||
|
||||
int vprintf(const char* format, va_list vlist) BA_CXX_NOEXCEPT
|
||||
{
|
||||
return baos::PrintFHelper<RegularPrinter>().vprintf(format, vlist);
|
||||
}
|
||||
|
||||
int snprintf(char* buffer, size_t bufferSize, const char* format, ...) noexcept
|
||||
{
|
||||
va_list parameters;
|
||||
va_start(parameters, format);
|
||||
const int result = vsnprintf(buffer, bufferSize, format, parameters);
|
||||
va_end(parameters);
|
||||
return result;
|
||||
}
|
||||
|
||||
int vsnprintf(char* buffer, size_t bufferSize, const char* format, va_list vlist) noexcept
|
||||
{
|
||||
BufferPrinter printer{
|
||||
.pos = buffer,
|
||||
.end = bufferSize > 0 ? buffer + bufferSize - 1 : buffer
|
||||
};
|
||||
const int length = baos::PrintFHelper(printer).vprintf(format, vlist);
|
||||
if (bufferSize > 0)
|
||||
{
|
||||
buffer[std::min(static_cast<int>(bufferSize - 1), length)] = '\0';
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
int fgetc(FILE* stream) noexcept
|
||||
{
|
||||
char chr;
|
||||
if (!stream->readChar(chr))
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
return chr;
|
||||
}
|
||||
|
||||
char* fgets(char* buffer, int count, FILE* stream) noexcept
|
||||
{
|
||||
if (count < 1) {
|
||||
return nullptr;
|
||||
}
|
||||
if (count == 1)
|
||||
{
|
||||
*buffer = '\0';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
for (; pos < count - 1; ++pos)
|
||||
{
|
||||
if (!stream->readChar(buffer[pos]))
|
||||
{
|
||||
if (stream->isError() || pos == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
buffer[pos] = '\0';
|
||||
return buffer;
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
namespace std
|
||||
{
|
||||
bool fgetline(FILE* stream, std::string& outLine) noexcept
|
||||
{
|
||||
return stream->readLine(outLine);
|
||||
}
|
||||
}
|
||||
|
||||
124
targets/_any/stdlib/src/stdlib.cpp
Normal file
124
targets/_any/stdlib/src/stdlib.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include "os/memory.hpp"
|
||||
#include "os/tty.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
inline const size_t INIT_MALLOC_SPACE_ELEMENTS = 1024 * 1024;
|
||||
inline const size_t INIT_MALLOC_SPACE_BYTES = INIT_MALLOC_SPACE_ELEMENTS * alignof(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) <= alignof(max_align_t));
|
||||
static_assert(sizeof(AllocInfo) <= alignof(max_align_t));
|
||||
|
||||
MallocBlock* gNextBlock = nullptr;
|
||||
}
|
||||
|
||||
void __ba_initInitialHeap() noexcept
|
||||
{
|
||||
gNextBlock = reinterpret_cast<MallocBlock*>(gInitMallocSpace);
|
||||
gNextBlock->elements = INIT_MALLOC_SPACE_ELEMENTS;
|
||||
gNextBlock->nextBlock = nullptr;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void abort()
|
||||
{
|
||||
tty::write("Abort called!");
|
||||
__asm__ volatile("hlt");
|
||||
while(true) {};
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
baos::PageRange pages = baos::allocatePages({
|
||||
.numPages = std::max(1ul, baos::bytesToPages(size, /* bigPages = */ true)),
|
||||
.bigPages = true
|
||||
});
|
||||
if (!pages) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::span<std::uint8_t> memory = pages.getMemory();
|
||||
MallocBlock* newBlock = std::bit_cast<MallocBlock*>(memory.begin());
|
||||
newBlock->nextBlock = gNextBlock;
|
||||
newBlock->elements = memory.size();
|
||||
gNextBlock = newBlock;
|
||||
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int __cxa_atexit(void (*func)(void*), void* arg, void* dsoHandle)
|
||||
{
|
||||
(void) func;
|
||||
(void) arg;
|
||||
(void) dsoHandle;
|
||||
|
||||
// NOOP for now
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
} // extern "C"
|
||||
69
targets/_any/stdlib/src/string.cpp
Normal file
69
targets/_any/stdlib/src/string.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
int memcmp(const void* lhs, const void* rhs, size_t count) noexcept
|
||||
{
|
||||
for (size_t pos = 0; pos < count; ++pos)
|
||||
{
|
||||
const unsigned char left = *(static_cast<const unsigned char*>(lhs) + pos);
|
||||
const unsigned char right = *(static_cast<const unsigned char*>(rhs) + pos);
|
||||
|
||||
if (left != right) {
|
||||
return left - right;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(__x86_64__)
|
||||
void* memcpy(void* dest, const void* src, size_t count) noexcept
|
||||
{
|
||||
for (size_t pos = 0; pos < count; ++pos)
|
||||
{
|
||||
*(static_cast<uint8_t*>(dest) + pos) = *(static_cast<const uint8_t*>(src) + pos);
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
void* memmove(void* dest, const void* src, size_t count) noexcept
|
||||
{
|
||||
if (dest < src)
|
||||
{
|
||||
for (size_t pos = 0; pos < count; ++pos)
|
||||
{
|
||||
*(static_cast<uint8_t*>(dest) + pos) = *(static_cast<const uint8_t*>(src) + pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t pos = 0; pos < count; ++pos)
|
||||
{
|
||||
*(static_cast<uint8_t*>(dest) + count - pos - 1) = *(static_cast<const uint8_t*>(src) + count - pos - 1);
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
void* memset(void* dest, int value, size_t count) noexcept
|
||||
{
|
||||
for (size_t pos = 0; pos < count; ++pos)
|
||||
{
|
||||
*(static_cast<unsigned char*>(dest) + pos) = static_cast<unsigned char>(value);
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
size_t strlen(const char* str) noexcept
|
||||
{
|
||||
size_t len = 0;
|
||||
while (str[len] != '\0') {
|
||||
++len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user