From 7c507c27bf5b619c98b2e8cd023bca70b6ce8514 Mon Sep 17 00:00:00 2001 From: Liav A Date: Sun, 9 Feb 2020 16:28:56 +0200 Subject: [PATCH] LibBareMetal: Creating a new library for freestanding environments --- Libraries/LibBareMetal/IO.h | 103 +++++++++ Libraries/LibBareMetal/Makefile | 1 + Libraries/LibBareMetal/Output/Console.cpp | 97 ++++++++ Libraries/LibBareMetal/Output/Console.h | 78 +++++++ Libraries/LibBareMetal/Output/kprintf.cpp | 167 ++++++++++++++ Libraries/LibBareMetal/Output/kstdio.h | 56 +++++ Libraries/LibBareMetal/StdLib.cpp | 265 ++++++++++++++++++++++ Libraries/LibBareMetal/StdLib.h | 87 +++++++ 8 files changed, 854 insertions(+) create mode 100644 Libraries/LibBareMetal/IO.h create mode 100644 Libraries/LibBareMetal/Makefile create mode 100644 Libraries/LibBareMetal/Output/Console.cpp create mode 100644 Libraries/LibBareMetal/Output/Console.h create mode 100644 Libraries/LibBareMetal/Output/kprintf.cpp create mode 100644 Libraries/LibBareMetal/Output/kstdio.h create mode 100644 Libraries/LibBareMetal/StdLib.cpp create mode 100644 Libraries/LibBareMetal/StdLib.h diff --git a/Libraries/LibBareMetal/IO.h b/Libraries/LibBareMetal/IO.h new file mode 100644 index 0000000000..66e30b5510 --- /dev/null +++ b/Libraries/LibBareMetal/IO.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +#if defined(KERNEL) +# include +# include +#endif + +namespace IO { + +inline u8 in8(u16 port) +{ + u8 value; + asm volatile("inb %1, %0" + : "=a"(value) + : "Nd"(port)); + return value; +} + +inline u16 in16(u16 port) +{ + u16 value; + asm volatile("inw %1, %0" + : "=a"(value) + : "Nd"(port)); + return value; +} + +inline u32 in32(u16 port) +{ + u32 value; + asm volatile("inl %1, %0" + : "=a"(value) + : "Nd"(port)); + return value; +} + +inline void repeated_in16(u16 port, u8* buffer, int buffer_size) +{ + asm volatile("rep insw" + : "+D"(buffer), "+c"(buffer_size) + : "d"(port) + : "memory"); +} + +inline void out8(u16 port, u8 value) +{ + asm volatile("outb %0, %1" ::"a"(value), "Nd"(port)); +} + +inline void out16(u16 port, u16 value) +{ + asm volatile("outw %0, %1" ::"a"(value), "Nd"(port)); +} + +inline void out32(u16 port, u32 value) +{ + asm volatile("outl %0, %1" ::"a"(value), "Nd"(port)); +} + +inline void repeated_out16(u16 port, const u8* data, int data_size) +{ + asm volatile("rep outsw" + : "+S"(data), "+c"(data_size) + : "d"(port)); +} + +inline void delay() +{ + // ~3 microsecs + for (auto i = 0; i < 32; i++) { + IO::in8(0x80); + } +} + +} diff --git a/Libraries/LibBareMetal/Makefile b/Libraries/LibBareMetal/Makefile new file mode 100644 index 0000000000..720752f1eb --- /dev/null +++ b/Libraries/LibBareMetal/Makefile @@ -0,0 +1 @@ +include ../../Makefile.common diff --git a/Libraries/LibBareMetal/Output/Console.cpp b/Libraries/LibBareMetal/Output/Console.cpp new file mode 100644 index 0000000000..fce5c15146 --- /dev/null +++ b/Libraries/LibBareMetal/Output/Console.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +// Bytes output to 0xE9 end up on the Bochs console. It's very handy. +#define CONSOLE_OUT_TO_E9 + +static Console* s_the; + +Console& Console::the() +{ + ASSERT(s_the); + return *s_the; +} + +bool Console::is_initialized() +{ + return s_the != nullptr; +} + +Console::Console() +#if defined(KERNEL) + : CharacterDevice(5, 1) +#endif +{ + s_the = this; +} + +Console::~Console() +{ +} + +#if defined(KERNEL) +bool Console::can_read(const FileDescription&) const +{ + return false; +} + +ssize_t Console::read(FileDescription&, u8*, ssize_t) +{ + // FIXME: Implement reading from the console. + // Maybe we could use a ring buffer for this device? + return 0; +} + +ssize_t Console::write(FileDescription&, const u8* data, ssize_t size) +{ + if (!size) + return 0; + if (!m_implementation) + return 0; + for (ssize_t i = 0; i < size; ++i) + put_char(data[i]); + return size; +} +#endif + +void Console::put_char(char ch) +{ +#ifdef CONSOLE_OUT_TO_E9 + //if (ch != 27) + IO::out8(0xe9, ch); +#endif + m_logbuffer.enqueue(ch); + if (m_implementation) + m_implementation->on_sysconsole_receive(ch); +} + +ConsoleImplementation::~ConsoleImplementation() +{ +} diff --git a/Libraries/LibBareMetal/Output/Console.h b/Libraries/LibBareMetal/Output/Console.h new file mode 100644 index 0000000000..039a7958f0 --- /dev/null +++ b/Libraries/LibBareMetal/Output/Console.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#if defined(KERNEL) +# include +#endif + +class ConsoleImplementation { +public: + virtual ~ConsoleImplementation(); + virtual void on_sysconsole_receive(u8) = 0; +}; + +#if defined(KERNEL) +class Console final : public CharacterDevice { + AK_MAKE_ETERNAL +#elif defined(BOOTSTRAPPER) +class Console { +#endif +public: + static Console& the(); + static bool is_initialized(); + + Console(); +#if defined(KERNEL) + virtual ~Console() override; +#elif defined(BOOTSTRAPPER) + virtual ~Console(); +#endif + +#if defined(KERNEL) + // ^CharacterDevice + virtual bool can_read(const FileDescription&) const override; + virtual bool can_write(const FileDescription&) const override { return true; } + virtual ssize_t read(FileDescription&, u8*, ssize_t) override; + virtual ssize_t write(FileDescription&, const u8*, ssize_t) override; + virtual const char* class_name() const override { return "Console"; } +#endif + void set_implementation(ConsoleImplementation* implementation) + { + m_implementation = implementation; + } + + void put_char(char); + + const CircularQueue& logbuffer() const { return m_logbuffer; } + +private: + ConsoleImplementation* m_implementation { nullptr }; + CircularQueue m_logbuffer; +}; diff --git a/Libraries/LibBareMetal/Output/kprintf.cpp b/Libraries/LibBareMetal/Output/kprintf.cpp new file mode 100644 index 0000000000..e1a6f9ae3b --- /dev/null +++ b/Libraries/LibBareMetal/Output/kprintf.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include + +#if defined(KERNEL) +# include +#endif + +static bool serial_debug; + +void set_serial_debug(bool on_or_off) +{ + serial_debug = on_or_off; +} + +int get_serial_debug() +{ + return serial_debug; +} + +static void color_on() +{ + IO::out8(0xe9, 0x1b); + IO::out8(0xe9, '['); + IO::out8(0xe9, '3'); + IO::out8(0xe9, '6'); + IO::out8(0xe9, 'm'); +} + +static void color_off() +{ + IO::out8(0xe9, 0x1b); + IO::out8(0xe9, '['); + IO::out8(0xe9, '0'); + IO::out8(0xe9, 'm'); +} + +static void serial_putch(char ch) +{ + static bool serial_ready = false; + static bool was_cr = false; + + if (!serial_ready) { + IO::out8(0x3F8 + 1, 0x00); + IO::out8(0x3F8 + 3, 0x80); + IO::out8(0x3F8 + 0, 0x02); + IO::out8(0x3F8 + 1, 0x00); + IO::out8(0x3F8 + 3, 0x03); + IO::out8(0x3F8 + 2, 0xC7); + IO::out8(0x3F8 + 4, 0x0B); + + serial_ready = true; + } + + while ((IO::in8(0x3F8 + 5) & 0x20) == 0) + ; + + if (ch == '\n' && !was_cr) + IO::out8(0x3F8, '\r'); + + IO::out8(0x3F8, ch); + + if (ch == '\r') + was_cr = true; + else + was_cr = false; +} + +static void console_putch(char*&, char ch) +{ + if (serial_debug) + serial_putch(ch); + + // It would be bad to reach the assert in Console()::the() and do a stack overflow + + if (Console::is_initialized()) { + Console::the().put_char(ch); + } else { + IO::out8(0xe9, ch); + } +} + +int kprintf(const char* fmt, ...) +{ + color_on(); + va_list ap; + va_start(ap, fmt); + int ret = printf_internal(console_putch, nullptr, fmt, ap); + va_end(ap); + color_off(); + return ret; +} + +static void buffer_putch(char*& bufptr, char ch) +{ + *bufptr++ = ch; +} + +int sprintf(char* buffer, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = printf_internal(buffer_putch, buffer, fmt, ap); + buffer[ret] = '\0'; + va_end(ap); + return ret; +} + +static void debugger_out(char ch) +{ + if (serial_debug) + serial_putch(ch); + IO::out8(0xe9, ch); +} + +static void debugger_putch(char*&, char ch) +{ + debugger_out(ch); +} + +extern "C" int dbgputstr(const char* characters, int length) +{ + for (int i = 0; i < length; ++i) + debugger_out(characters[i]); + return 0; +} + +extern "C" int dbgprintf(const char* fmt, ...) +{ + color_on(); + va_list ap; + va_start(ap, fmt); + int ret = printf_internal(debugger_putch, nullptr, fmt, ap); + va_end(ap); + color_off(); + return ret; +} diff --git a/Libraries/LibBareMetal/Output/kstdio.h b/Libraries/LibBareMetal/Output/kstdio.h new file mode 100644 index 0000000000..e5e0b2c1ae --- /dev/null +++ b/Libraries/LibBareMetal/Output/kstdio.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +extern "C" { +int dbgprintf(const char* fmt, ...); +int dbgputstr(const char*, int); +int kprintf(const char* fmt, ...); +int sprintf(char* buf, const char* fmt, ...); +void set_serial_debug(bool on_or_off); +int get_serial_debug(); +} + +#if defined(KERNEL) || defined(BOOTSTRAPPER) +# define printf dbgprintf +#endif + +#ifndef __serenity__ +# define dbgprintf printf +#endif + +#ifdef __cplusplus + +template +inline int dbgputstr(const char (&array)[N]) +{ + return ::dbgputstr(array, N); +} + +#endif diff --git a/Libraries/LibBareMetal/StdLib.cpp b/Libraries/LibBareMetal/StdLib.cpp new file mode 100644 index 0000000000..698eeb934f --- /dev/null +++ b/Libraries/LibBareMetal/StdLib.cpp @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#ifdef KERNEL +# include +# include +# include +#endif + +#ifdef KERNEL +String copy_string_from_user(const char* user_str, size_t user_str_size) +{ + SmapDisabler disabler; + size_t length = strnlen(user_str, user_str_size); + return String(user_str, length); +} +#endif + +extern "C" { + +#ifdef KERNEL +void copy_to_user(void* dest_ptr, const void* src_ptr, size_t n) +{ + ASSERT(is_user_range(VirtualAddress(dest_ptr), n)); + SmapDisabler disabler; + memcpy(dest_ptr, src_ptr, n); +} + +void copy_from_user(void* dest_ptr, const void* src_ptr, size_t n) +{ + ASSERT(is_user_range(VirtualAddress(src_ptr), n)); + SmapDisabler disabler; + memcpy(dest_ptr, src_ptr, n); +} +#endif + +void* memcpy(void* dest_ptr, const void* src_ptr, size_t n) +{ + size_t dest = (size_t)dest_ptr; + size_t src = (size_t)src_ptr; + // FIXME: Support starting at an unaligned address. + if (!(dest & 0x3) && !(src & 0x3) && n >= 12) { + size_t size_ts = n / sizeof(size_t); + asm volatile( + "rep movsl\n" + : "=S"(src), "=D"(dest) + : "S"(src), "D"(dest), "c"(size_ts) + : "memory"); + n -= size_ts * sizeof(size_t); + if (n == 0) + return dest_ptr; + } + asm volatile( + "rep movsb\n" ::"S"(src), "D"(dest), "c"(n) + : "memory"); + return dest_ptr; +} + +void* memmove(void* dest, const void* src, size_t n) +{ + if (dest < src) + return memcpy(dest, src, n); + + u8* pd = (u8*)dest; + const u8* ps = (const u8*)src; + for (pd += n, ps += n; n--;) + *--pd = *--ps; + return dest; +} + +char* strcpy(char* dest, const char* src) +{ + auto* dest_ptr = dest; + auto* src_ptr = src; + while ((*dest_ptr++ = *src_ptr++) != '\0') + ; + return dest; +} + +char* strncpy(char* dest, const char* src, size_t n) +{ + size_t i; + for (i = 0; i < n && src[i] != '\0'; ++i) + dest[i] = src[i]; + for (; i < n; ++i) + dest[i] = '\0'; + return dest; +} + +#ifdef KERNEL +void memset_user(void* dest_ptr, int c, size_t n) +{ + ASSERT(is_user_range(VirtualAddress(dest_ptr), n)); + SmapDisabler disabler; + memset(dest_ptr, c, n); +} +#endif + +void* memset(void* dest_ptr, int c, size_t n) +{ + size_t dest = (size_t)dest_ptr; + // FIXME: Support starting at an unaligned address. + if (!(dest & 0x3) && n >= 12) { + size_t size_ts = n / sizeof(size_t); + size_t expanded_c = (u8)c; + expanded_c |= expanded_c << 8; + expanded_c |= expanded_c << 16; + asm volatile( + "rep stosl\n" + : "=D"(dest) + : "D"(dest), "c"(size_ts), "a"(expanded_c) + : "memory"); + n -= size_ts * sizeof(size_t); + if (n == 0) + return dest_ptr; + } + asm volatile( + "rep stosb\n" + : "=D"(dest), "=c"(n) + : "0"(dest), "1"(n), "a"(c) + : "memory"); + return dest_ptr; +} + +char* strrchr(const char* str, int ch) +{ + char* last = nullptr; + char c; + for (; (c = *str); ++str) { + if (c == ch) + last = const_cast(str); + } + return last; +} + +size_t strlen(const char* str) +{ + size_t len = 0; + while (*(str++)) + ++len; + return len; +} + +size_t strnlen(const char* str, size_t maxlen) +{ + size_t len = 0; + for (; len < maxlen && *str; str++) + len++; + return len; +} + +int strcmp(const char* s1, const char* s2) +{ + for (; *s1 == *s2; ++s1, ++s2) { + if (*s1 == 0) + return 0; + } + return *(const u8*)s1 < *(const u8*)s2 ? -1 : 1; +} + +char* strdup(const char* str) +{ + size_t len = strlen(str); + char* new_str = (char*)kmalloc(len + 1); + strcpy(new_str, str); + return new_str; +} + +int memcmp(const void* v1, const void* v2, size_t n) +{ + auto* s1 = (const u8*)v1; + auto* s2 = (const u8*)v2; + while (n-- > 0) { + if (*s1++ != *s2++) + return s1[-1] < s2[-1] ? -1 : 1; + } + return 0; +} + +int strncmp(const char* s1, const char* s2, size_t n) +{ + if (!n) + return 0; + do { + if (*s1 != *s2++) + return *(const unsigned char*)s1 - *(const unsigned char*)--s2; + if (*s1++ == 0) + break; + } while (--n); + return 0; +} + +char* strstr(const char* haystack, const char* needle) +{ + char nch; + char hch; + + if ((nch = *needle++) != 0) { + size_t len = strlen(needle); + do { + do { + if ((hch = *haystack++) == 0) + return nullptr; + } while (hch != nch); + } while (strncmp(haystack, needle, len) != 0); + --haystack; + } + return const_cast(haystack); +} + +[[noreturn]] void __cxa_pure_virtual() +{ + ASSERT_NOT_REACHED(); +} + +#ifdef KERNEL +void* realloc(void* p, size_t s) +{ + return krealloc(p, s); +} +#endif + +void free(void* p) +{ + return kfree(p); +} + +[[noreturn]] void __stack_chk_fail() +{ + ASSERT_NOT_REACHED(); +} + +[[noreturn]] void __stack_chk_fail_local() +{ + ASSERT_NOT_REACHED(); +} +} diff --git a/Libraries/LibBareMetal/StdLib.h b/Libraries/LibBareMetal/StdLib.h new file mode 100644 index 0000000000..280e5a73b7 --- /dev/null +++ b/Libraries/LibBareMetal/StdLib.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +#if defined(KERNEL) + +namespace AK { +class String; +} + +namespace Syscall { +struct StringArgument; +} + +AK::String copy_string_from_user(const char*, size_t); + +#endif + +extern "C" { + +static_assert(sizeof(size_t) == 4); + +#if defined(KERNEL) +void copy_to_user(void*, const void*, size_t); +void copy_from_user(void*, const void*, size_t); +void memset_user(void*, int, size_t); +#endif + +void* memcpy(void*, const void*, size_t); +char* strcpy(char*, const char*); +char* strncpy(char*, const char*, size_t); +int strncmp(const char* s1, const char* s2, size_t n); +char* strstr(const char* haystack, const char* needle); +int strcmp(char const*, const char*); +size_t strlen(const char*); +size_t strnlen(const char*, size_t); +void* memset(void*, int, size_t); +char* strdup(const char*); +int memcmp(const void*, const void*, size_t); +char* strrchr(const char* str, int ch); +void* memmove(void* dest, const void* src, size_t n); + +inline u16 ntohs(u16 w) { return (w & 0xff) << 8 | ((w >> 8) & 0xff); } +inline u16 htons(u16 w) { return (w & 0xff) << 8 | ((w >> 8) & 0xff); } +} + +#if defined(KERNEL) + +template +inline void copy_from_user(T* dest, const T* src) +{ + copy_from_user(dest, src, sizeof(T)); +} + +template +inline void copy_to_user(T* dest, const T* src) +{ + copy_to_user(dest, src, sizeof(T)); +} + +#endif