diff --git a/SConstruct b/SConstruct index c649290..c3a7198 100644 --- a/SConstruct +++ b/SConstruct @@ -22,11 +22,16 @@ crti_o = env.Object('src/crt/crti.s') crtn_o = env.Object('src/crt/crtn.s') os_sources = Split(''' + src/app/main.cpp + src/kernel/boot.s src/kernel/startup.cpp src/os/tty.cpp + src/stdlib/assert.cpp + src/stdlib/stdio.cpp + src/stdlib/stdlib.cpp src/stdlib/string.cpp ''') env['LINKCOM'] = env['LINKCOM'].replace('$_LIBFLAGS', f'{crti_o[0]} {crtbegin_o} $_LIBFLAGS {crtend_o} {crtn_o[0]}') diff --git a/include/assert.h b/include/assert.h new file mode 100644 index 0000000..7ef16da --- /dev/null +++ b/include/assert.h @@ -0,0 +1,27 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_ASSERT_H_INCLUDED) +#define BAD_APPLE_OS_ASSERT_H_INCLUDED + +#include "./detail/common.h" + +BA_EXTERN_C_BEGIN + +#if defined(NDEBUG) +#define assert(condition) ((void) 0) +#else +#define assert(condition) \ +if (!(condition)) \ +{ \ + __ba__assert_fail(__FILE__, __LINE__, #condition); \ +} +#endif + +#if !defined(NDEBUG) +BA_CXX_NORETURN void __ba__assert_fail(const char* filename, int line, const char* condition) BA_CXX_NOEXCEPT; +#endif + +BA_EXTERN_C_END + +#endif // !defined(BAD_APPLE_OS_ASSERT_H_INCLUDED) diff --git a/include/cassert b/include/cassert new file mode 100644 index 0000000..42e727c --- /dev/null +++ b/include/cassert @@ -0,0 +1,9 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_CASSERT_INCLUDED) +#define BAD_APPLE_OS_CASSERT_INCLUDED + +#include + +#endif // !defined(BAD_APPLE_OS_CASSERT_INCLUDED) diff --git a/include/cstdio b/include/cstdio new file mode 100644 index 0000000..985a515 --- /dev/null +++ b/include/cstdio @@ -0,0 +1,16 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_CSTDIO_INCLUDED) +#define BAD_APPLE_OS_CSTDIO_INCLUDED + +#include + +namespace std +{ +using ::putchar; +using ::puts; +using ::printf; +} + +#endif // !defined(BAD_APPLE_OS_CSTDIO_INCLUDED) diff --git a/include/cstdlib b/include/cstdlib new file mode 100644 index 0000000..7daf01e --- /dev/null +++ b/include/cstdlib @@ -0,0 +1,14 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_CSTDLIB_INCLUDED) +#define BAD_APPLE_OS_CSTDLIB_INCLUDED + +#include + +namespace std +{ +using ::abort; +} + +#endif // !defined(BAD_APPLE_OS_CSTDLIB_INCLUDED) diff --git a/include/cstring b/include/cstring index 42753a9..25b0e3b 100644 --- a/include/cstring +++ b/include/cstring @@ -1,14 +1,19 @@ #pragma once -#if !defined(BAD_APPLE_OS_CSTRING_HPP_INCLUDED) -#define BAD_APPLE_OS_CSTRING_HPP_INCLUDED +#if !defined(BAD_APPLE_OS_CSTRING_INCLUDED) +#define BAD_APPLE_OS_CSTRING_INCLUDED #include namespace std { using ::strlen; + +using ::memcmp; +using ::memcpy; +using ::memmove; +using ::memset; } -#endif // !defined(BAD_APPLE_OS_CSTRING_HPP_INCLUDED) +#endif // !defined(BAD_APPLE_OS_CSTRING_INCLUDED) diff --git a/include/detail/attributes.h b/include/detail/common.h similarity index 66% rename from include/detail/attributes.h rename to include/detail/common.h index 0f04105..29c7a84 100644 --- a/include/detail/attributes.h +++ b/include/detail/common.h @@ -6,10 +6,16 @@ #if defined(__cplusplus) #define BA_CXX_NODISCARD [[nodiscard]] +#define BA_CXX_NORETURN [[noreturn]] #define BA_CXX_NOEXCEPT noexcept +#define BA_EXTERN_C_BEGIN extern "C" { +#define BA_EXTERN_C_END } #else #define BA_CXX_NODISCARD +#define BA_CXX_NORETURN #define BA_CXX_NOEXCEPT +#define BA_EXTERN_C_BEGIN +#define BA_EXTERN_C_END #endif #endif // !defined(BAD_APPLE_OS_DETAIL_ATTRIBUTES_H_INCLUDED) diff --git a/include/stdio.h b/include/stdio.h new file mode 100644 index 0000000..01fa7ca --- /dev/null +++ b/include/stdio.h @@ -0,0 +1,17 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_STDIO_H_INCLUDED) +#define BAD_APPLE_OS_STDIO_H_INCLUDED + +#include "./detail/common.h" + +BA_EXTERN_C_BEGIN + +int putchar(int chr) BA_CXX_NOEXCEPT; +int puts(const char* str) BA_CXX_NOEXCEPT; +int printf(const char* format, ...) BA_CXX_NOEXCEPT; + +BA_EXTERN_C_END + +#endif // !defined(BAD_APPLE_OS_STDIO_H_INCLUDED) diff --git a/include/stdlib.h b/include/stdlib.h new file mode 100644 index 0000000..a676de9 --- /dev/null +++ b/include/stdlib.h @@ -0,0 +1,15 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_STDLIB_H_INCLUDED) +#define BAD_APPLE_OS_STDLIB_H_INCLUDED + +#include "./detail/common.h" + +BA_EXTERN_C_BEGIN + +BA_CXX_NORETURN void abort(); + +BA_EXTERN_C_END + +#endif // !defined(BAD_APPLE_OS_STDLIB_H_INCLUDED) diff --git a/include/string.h b/include/string.h index e23b53a..a786765 100644 --- a/include/string.h +++ b/include/string.h @@ -6,14 +6,16 @@ #include -#include "./detail/attributes.h" +#include "./detail/common.h" -#if defined(__cplusplus) -extern "C" { -#endif +BA_EXTERN_C_BEGIN + +BA_CXX_NODISCARD int memcmp(const void* lhs, const void* rhs, size_t count) BA_CXX_NOEXCEPT; +void memcpy(void* dest, const void* src, size_t count) BA_CXX_NOEXCEPT; +void memmove(void* dest, const void* src, size_t count) BA_CXX_NOEXCEPT; +void* memset(void* dest, int value, size_t count) BA_CXX_NOEXCEPT; BA_CXX_NODISCARD size_t strlen(const char* str) BA_CXX_NOEXCEPT; -#if defined(__cplusplus) -} -#endif + +BA_EXTERN_C_END #endif // !defined(BAD_APPLE_OS_STRING_H_INCLUDED) diff --git a/src/app/main.cpp b/src/app/main.cpp new file mode 100644 index 0000000..72c9070 --- /dev/null +++ b/src/app/main.cpp @@ -0,0 +1,17 @@ + +#include + +#include + +extern "C" void main() +{ + std::puts("Hello, kernel World!"); + + while (true) + { + for (char chr = 'A'; chr <= 'Z'; ++chr) + { + std::printf("char: %c", chr); + } + } +} diff --git a/src/kernel/startup.cpp b/src/kernel/startup.cpp index 25b3697..8cd5b64 100644 --- a/src/kernel/startup.cpp +++ b/src/kernel/startup.cpp @@ -1,29 +1,12 @@ #include "os/tty.hpp" -/* Check if the compiler thinks you are targeting the wrong operating system. */ -#if defined(__linux__) -#error "You are not using a cross-compiler, you will most certainly run into trouble" -#endif - -/* This tutorial will only work for the 32-bit ix86 targets. */ -#if !defined(__i386__) -#error "This tutorial needs to be compiled with a ix86-elf compiler" -#endif +extern "C" void main(); extern "C" void kernel_main(void) { /* Initialize terminal interface */ tty::initialize(); - tty::write("Hello, kernel World!\n"); - - while (true) - { - for (char chr = 'A'; chr <= 'Z'; ++chr) - { - char buf[2] = {chr, '\n'}; - tty::write(buf, 2); - } - } + main(); } diff --git a/src/os/tty.cpp b/src/os/tty.cpp index 4ec42a6..ce008fe 100644 --- a/src/os/tty.cpp +++ b/src/os/tty.cpp @@ -35,16 +35,7 @@ void newline() else { // scrolling up - for (size_t y = 0; y < VGA_HEIGHT - 1; ++y) - { - // TODO: this is where I'd put my memcpy. If I had one. - for (size_t x = 0; x < VGA_WIDTH; ++x) - { - const size_t indexTo = y * VGA_WIDTH + x; - const size_t indexFrom = (y + 1) * VGA_WIDTH + x; - gTerminalBuffer[indexTo] = gTerminalBuffer[indexFrom]; - } - } + std::memmove(&gTerminalBuffer[0], &gTerminalBuffer[VGA_WIDTH], VGA_WIDTH * (VGA_HEIGHT - 1) * sizeof(uint16_t)); } } } @@ -74,6 +65,12 @@ void putEntryAt(char chr, VgaDoubleColor color, size_t posX, size_t posY) void putChar(char chr) { + if (chr == '\n') + { + newline(); + return; + } + putEntryAt(chr, gTerminalColor, gTerminalColumn, gTerminalRow); if (++gTerminalColumn == VGA_WIDTH) { @@ -85,14 +82,7 @@ void write(const char* data, size_t size) { for (size_t idx = 0; idx < size; idx++) { - if (data[idx] == '\n') - { - newline(); - } - else - { - putChar(data[idx]); - } + putChar(data[idx]); } } diff --git a/src/stdlib/assert.cpp b/src/stdlib/assert.cpp new file mode 100644 index 0000000..9f85db4 --- /dev/null +++ b/src/stdlib/assert.cpp @@ -0,0 +1,20 @@ + +#include + +#include +#include + +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)", filename, line, condition); + std::abort(); +} +#endif +} // extern "C" diff --git a/src/stdlib/stdio.cpp b/src/stdlib/stdio.cpp new file mode 100644 index 0000000..b37613b --- /dev/null +++ b/src/stdlib/stdio.cpp @@ -0,0 +1,118 @@ + +#include + +#include +#include +#include +#include "os/tty.hpp" + +extern "C" +{ +namespace +{ +int printInt(int value) +{ + if (value == 0) + { + putchar('0'); + return 1; + } + if (value < 0) + { + putchar('-'); + return printInt(-value) + 1; + } + + char digits[10]; // 2147483647 has 10 digits + char* pos = &digits[0]; + + while (value > 0) + { + *pos = static_cast('0' + (value % 10)); + value /= 10; + ++pos; + } + for (char* chr = pos - 1; chr >= digits; --chr) + { + putchar(*chr); + } + return pos - digits; +} +} + +int putchar(int chr) noexcept +{ + tty::putChar(static_cast(chr)); + return 0; +} + +int puts(const char* str) noexcept +{ + tty::write(str); + tty::putChar('\n'); + return 0; +} + +int printf(const char* format, ...) noexcept +{ + va_list parameters; + va_start(parameters, format); + + int result = 0; + const char* pos = format; + while (*pos != '\0') + { + if (*pos == '%') + { + ++pos; + switch (*pos) + { + case '%': + putchar('%'); + ++result; + break; + case '\0': + // TODO: invalid format string, do something + assert(!"Invalid format string, ends with %."); + va_end(parameters); + return -1; + case 'c': + { + const char chr = static_cast(va_arg(parameters, int)); + putchar(chr); + ++result; + break; + } + case 's': + { + const char* str = va_arg(parameters, const char*); + const size_t len = std::strlen(str); + + for (size_t idx = 0; idx < len; ++idx) + { + putchar(str[idx]); + } + result += static_cast(len); + break; + } + case 'd': + result += printInt(va_arg(parameters, int)); + break; + default: + assert(!"Invalid format string, unknown format identifier."); + va_end(parameters); + return -1; + } + } else + { + putchar(*pos); + } + ++pos; + } + va_end(parameters); + putchar('\n'); + ++result; + return result; +} +} // extern "C" + diff --git a/src/stdlib/stdlib.cpp b/src/stdlib/stdlib.cpp new file mode 100644 index 0000000..160085c --- /dev/null +++ b/src/stdlib/stdlib.cpp @@ -0,0 +1,12 @@ + +#include + +extern "C" +{ +void abort() +{ + __asm__ volatile("hlt"); + while(true) {}; + __builtin_unreachable(); +} +} // extern "C" diff --git a/src/stdlib/string.cpp b/src/stdlib/string.cpp index d29de0b..825ee5e 100644 --- a/src/stdlib/string.cpp +++ b/src/stdlib/string.cpp @@ -1,8 +1,59 @@ #include +#include + 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(lhs) + pos); + const unsigned char right = *(static_cast(rhs) + pos); + + if (left != right) { + return left - right; + } + } + return 0; +} + +void memcpy(void* dest, const void* src, size_t count) noexcept +{ + for (size_t pos = 0; pos < count; ++pos) + { + *(static_cast(dest) + pos) = *(static_cast(src) + pos); + } +} + +void memmove(void* dest, const void* src, size_t count) noexcept +{ + if (dest < src) + { + for (size_t pos = 0; pos < count; ++pos) + { + *(static_cast(dest) + pos) = *(static_cast(src) + pos); + } + } + else + { + for (size_t pos = 0; pos < count; ++pos) + { + *(static_cast(dest) + count - pos - 1) = *(static_cast(src) + count - pos - 1); + } + } +} + +void* memset(void* dest, int value, size_t count) noexcept +{ + for (size_t pos = 0; pos < count; ++pos) + { + *(static_cast(dest) + pos) = static_cast(value); + } + return dest; +} + size_t strlen(const char* str) noexcept { size_t len = 0;