Merge remote-tracking branch 'Kernel/master'

This commit is contained in:
EnderIce2
2024-11-20 05:00:33 +02:00
468 changed files with 112800 additions and 1 deletions

51
Kernel/library/bitmap.cpp Normal file
View File

@ -0,0 +1,51 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <bitmap.hpp>
bool Bitmap::Get(uint64_t index)
{
if (index > Size * 8)
return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex;
if ((Buffer[byteIndex] & bitIndexer) > 0)
return true;
return false;
}
bool Bitmap::Set(uint64_t index, bool value)
{
if (index > Size * 8)
return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex;
Buffer[byteIndex] &= ~bitIndexer;
if (value)
Buffer[byteIndex] |= bitIndexer;
return true;
}
bool Bitmap::operator[](uint64_t index) { return this->Get(index); }

28
Kernel/library/c/ctype.c Normal file
View File

@ -0,0 +1,28 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <ctype.h>
int tolower(int c)
{
return _tolower(c);
}
int toupper(int c)
{
return _toupper(c);
}

100
Kernel/library/c/stdio.cpp Normal file
View File

@ -0,0 +1,100 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <debug.h>
FILE __local_stdin = {.st = 0};
FILE __local_stdout = {.st = 1};
FILE __local_stderr = {.st = 2};
FILE *stdin = &__local_stdin;
FILE *stdout = &__local_stdout;
FILE *stderr = &__local_stderr;
EXTERNC int asprintf(char **strp, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int ret = vasprintf(strp, fmt, ap);
va_end(ap);
return ret;
}
#define va_copy(dest, src) __builtin_va_copy(dest, src)
EXTERNC int vasprintf(char **strp, const char *fmt, va_list ap)
{
va_list ap2;
va_copy(ap2, ap);
int len = vsnprintf(NULL, 0, fmt, ap2);
va_end(ap2);
if (len < 0)
{
return -1;
}
*strp = (char *)malloc(len + 1);
if (!*strp)
{
return -1;
}
int ret = vsnprintf(*strp, len + 1, fmt, ap);
if (ret < 0)
{
free(*strp);
*strp = NULL;
}
return ret;
}
int fprintf(FILE *stream, const char *format, ...)
{
switch (stream->st)
{
case 0:
{
error("fprintf() called with stdin");
return -1;
}
case 1:
{
va_list ap;
va_start(ap, format);
int ret = vprintf(format, ap);
va_end(ap);
return ret;
}
case 2:
{
va_list ap;
va_start(ap, format);
int ret = vprintf(format, ap);
va_end(ap);
return ret;
}
default:
return -1;
}
}
int fputs(const char *s, FILE *stream)
{
for (const char *c = s; *c; c++)
uart_wrapper(*c, NULL);
return 0;
}

View File

@ -0,0 +1,27 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <debug.h>
#include <cpu.hpp>
EXTERNC void abort()
{
error("abort() called");
CPU::Stop();
__builtin_unreachable();
}

512
Kernel/library/cargs.c Normal file
View File

@ -0,0 +1,512 @@
/*
MIT License
Copyright (c) 2022 Leonard Iklé
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
#pragma GCC diagnostic ignored "-Wsign-conversion"
#include <assert.h>
#include <cargs.h>
#include <convert.h>
#define CAG_OPTION_PRINT_DISTANCE 4
#define CAG_OPTION_PRINT_MIN_INDENTION 20
static void cag_option_print_value(const cag_option *option,
size_t *accessor_length, FILE *destination)
{
if (option->value_name != NULL)
{
*accessor_length += fprintf(destination, "=%s", option->value_name);
}
}
static void cag_option_print_letters(const cag_option *option, bool *first,
size_t *accessor_length, FILE *destination)
{
const char *access_letter;
access_letter = option->access_letters;
if (access_letter != NULL)
{
while (*access_letter)
{
if (*first)
{
*accessor_length += fprintf(destination, "-%c", *access_letter);
*first = false;
}
else
{
*accessor_length += fprintf(destination, ", -%c", *access_letter);
}
++access_letter;
}
}
}
static void cag_option_print_name(const cag_option *option, bool *first,
size_t *accessor_length, FILE *destination)
{
if (option->access_name != NULL)
{
if (*first)
{
*accessor_length += fprintf(destination, "--%s", option->access_name);
}
else
{
*accessor_length += fprintf(destination, ", --%s", option->access_name);
}
}
}
static size_t cag_option_get_print_indention(const cag_option *options,
size_t option_count)
{
size_t option_index, indention, result;
const cag_option *option;
result = CAG_OPTION_PRINT_MIN_INDENTION;
for (option_index = 0; option_index < option_count; ++option_index)
{
indention = CAG_OPTION_PRINT_DISTANCE;
option = &options[option_index];
if (option->access_letters != NULL && *option->access_letters)
{
indention += strlen(option->access_letters) * 4 - 2;
if (option->access_name != NULL)
{
indention += strlen(option->access_name) + 4;
}
}
else if (option->access_name != NULL)
{
indention += strlen(option->access_name) + 2;
}
if (option->value_name != NULL)
{
indention += strlen(option->value_name) + 1;
}
if (indention > result)
{
result = indention;
}
}
return result;
}
void cag_option_print(const cag_option *options, size_t option_count,
FILE *destination)
{
size_t option_index, indention, i, accessor_length;
const cag_option *option;
bool first;
indention = cag_option_get_print_indention(options, option_count);
for (option_index = 0; option_index < option_count; ++option_index)
{
option = &options[option_index];
accessor_length = 0;
first = true;
fputs(" ", destination);
cag_option_print_letters(option, &first, &accessor_length, destination);
cag_option_print_name(option, &first, &accessor_length, destination);
cag_option_print_value(option, &accessor_length, destination);
for (i = accessor_length; i < indention; ++i)
{
fputs(" ", destination);
}
fputs(" ", destination);
fputs(option->description, destination);
fprintf(destination, "\n");
}
}
void cag_option_prepare(cag_option_context *context, const cag_option *options,
size_t option_count, int argc, char **argv)
{
// This just initialized the values to the beginning of all the arguments.
context->options = options;
context->option_count = option_count;
context->argc = argc;
context->argv = argv;
context->index = 1;
context->inner_index = 0;
context->forced_end = false;
}
static const cag_option *cag_option_find_by_name(cag_option_context *context,
char *name, size_t name_size)
{
const cag_option *option;
size_t i;
// We loop over all the available options and stop as soon as we have found
// one. We don't use any hash map table, since there won't be that many
// arguments anyway.
for (i = 0; i < context->option_count; ++i)
{
option = &context->options[i];
// The option might not have an item name, we can just skip those.
if (option->access_name == NULL)
{
continue;
}
// Try to compare the name of the access name. We can use the name_size or
// this comparison, since we are guaranteed to have null-terminated access
// names.
if (strncmp(option->access_name, name, name_size) == 0)
{
return option;
}
}
return NULL;
}
static const cag_option *cag_option_find_by_letter(cag_option_context *context,
char letter)
{
const cag_option *option;
size_t i;
// We loop over all the available options and stop as soon as we have found
// one. We don't use any look up table, since there won't be that many
// arguments anyway.
for (i = 0; i < context->option_count; ++i)
{
option = &context->options[i];
// If this option doesn't have any access letters we will skip them.
if (option->access_letters == NULL)
{
continue;
}
// Verify whether this option has the access letter in it's access letter
// string. If it does, then this is our option.
if (strchr(option->access_letters, letter) != NULL)
{
return option;
}
}
return NULL;
}
static void cag_option_parse_value(cag_option_context *context,
const cag_option *option, char **c)
{
// And now let's check whether this option is supposed to have a value, which
// is the case if there is a value name set. The value can be either submitted
// with a '=' sign or a space, which means we would have to jump over to the
// next argv index. This is somewhat ugly, but we do it to behave the same as
// the other option parsers.
if (option->value_name != NULL)
{
if (**c == '=')
{
context->value = ++(*c);
}
else
{
// If the next index is larger or equal to the argument count, then the
// parameter for this option is missing. The user will know about this,
// since the value pointer of the context will be NULL because we don't
// set it here in that case.
if (context->argc > context->index + 1)
{
// We consider this argv to be the value, no matter what the contents
// are.
++context->index;
*c = context->argv[context->index];
context->value = *c;
}
}
// Move c to the end of the value, to not confuse the caller about our
// position.
while (**c)
{
++(*c);
}
}
}
static void cag_option_parse_access_name(cag_option_context *context, char **c)
{
const cag_option *option;
char *n;
// Now we need to extract the access name, which is any symbol up to a '=' or
// a '\0'.
n = *c;
while (**c && **c != '=')
{
++*c;
}
// Now this will obviously always be true, but we are paranoid. Sometimes. It
// doesn't hurt to check.
assert(*c >= n);
// Figure out which option this name belongs to. This might return NULL if the
// name is not registered, which means the user supplied an unknown option. In
// that case we return true to indicate that we finished with this option. We
// have to skip the value parsing since we don't know whether the user thinks
// this option has one or not. Since we don't set any identifier specifically,
// it will remain '?' within the context.
option = cag_option_find_by_name(context, n, (size_t)(*c - n));
if (option == NULL)
{
// Since this option is invalid, we will move on to the next index. There is
// nothing we can do about this.
++context->index;
return;
}
// We found an option and now we can specify the identifier within the
// context.
context->identifier = option->identifier;
// And now we try to parse the value. This function will also check whether
// this option is actually supposed to have a value.
cag_option_parse_value(context, option, c);
// And finally we move on to the next index.
++context->index;
}
static void cag_option_parse_access_letter(cag_option_context *context,
char **c)
{
const cag_option *option;
char *n = *c;
char *v;
// Figure out which option this letter belongs to. This might return NULL if
// the letter is not registered, which means the user supplied an unknown
// option. In that case we return true to indicate that we finished with this
// option. We have to skip the value parsing since we don't know whether the
// user thinks this option has one or not. Since we don't set any identifier
// specifically, it will remain '?' within the context.
option = cag_option_find_by_letter(context, n[context->inner_index]);
if (option == NULL)
{
++context->index;
context->inner_index = 0;
return;
}
// We found an option and now we can specify the identifier within the
// context.
context->identifier = option->identifier;
// And now we try to parse the value. This function will also check whether
// this option is actually supposed to have a value.
v = &n[++context->inner_index];
cag_option_parse_value(context, option, &v);
// Check whether we reached the end of this option argument.
if (*v == '\0')
{
++context->index;
context->inner_index = 0;
}
}
static void cag_option_shift(cag_option_context *context, int start, int option,
int end)
{
char *tmp;
int a_index, shift_index, shift_count, left_index, right_index;
shift_count = option - start;
// There is no shift is required if the start and the option have the same
// index.
if (shift_count == 0)
{
return;
}
// Lets loop through the option strings first, which we will move towards the
// beginning.
for (a_index = option; a_index < end; ++a_index)
{
// First remember the current option value, because we will have to save
// that later at the beginning.
tmp = context->argv[a_index];
// Let's loop over all option values and shift them one towards the end.
// This will override the option value we just stored temporarily.
for (shift_index = 0; shift_index < shift_count; ++shift_index)
{
left_index = a_index - shift_index;
right_index = a_index - shift_index - 1;
context->argv[left_index] = context->argv[right_index];
}
// Now restore the saved option value at the beginning.
context->argv[a_index - shift_count] = tmp;
}
// The new index will be before all non-option values, in such a way that they
// all will be moved again in the next fetch call.
context->index = end - shift_count;
}
static bool cag_option_is_argument_string(const char *c)
{
return *c == '-' && *(c + 1) != '\0';
}
static int cag_option_find_next(cag_option_context *context)
{
int next_index, next_option_index;
char *c;
// Prepare to search the next option at the next index.
next_index = context->index;
next_option_index = next_index;
// Grab a pointer to the string and verify that it is not the end. If it is
// the end, we have to return false to indicate that we finished.
c = context->argv[next_option_index];
if (context->forced_end || c == NULL || (uintptr_t)c == (uintptr_t)0xfffffffffffff000 /* TODO: workaround */)
{
return -1;
}
// Check whether it is a '-'. We need to find the next option - and an option
// always starts with a '-'. If there is a string "-\0", we don't consider it
// as an option neither.
while (!cag_option_is_argument_string(c))
{
c = context->argv[++next_option_index];
if (c == NULL)
{
// We reached the end and did not find any argument anymore. Let's tell
// our caller that we reached the end.
return -1;
}
}
// Indicate that we found an option which can be processed. The index of the
// next option will be returned.
return next_option_index;
}
bool cag_option_fetch(cag_option_context *context)
{
char *c;
int old_index, new_index;
// Reset our identifier to a question mark, which indicates an "unknown"
// option. The value is set to NULL, to make sure we are not carrying the
// parameter from the previous option to this one.
context->identifier = '?';
context->value = NULL;
// Check whether there are any options left to parse and remember the old
// index as well as the new index. In the end we will move the option junk to
// the beginning, so that non option arguments can be read.
old_index = context->index;
new_index = cag_option_find_next(context);
if (new_index >= 0)
{
context->index = new_index;
}
else
{
return false;
}
// Grab a pointer to the beginning of the option. At this point, the next
// character must be a '-', since if it was not the prepare function would
// have returned false. We will skip that symbol and proceed.
c = context->argv[context->index];
assert(*c == '-');
++c;
// Check whether this is a long option, starting with a double "--".
if (*c == '-')
{
++c;
// This might be a double "--" which indicates the end of options. If this
// is the case, we will not move to the next index. That ensures that
// another call to the fetch function will not skip the "--".
if (*c == '\0')
{
context->forced_end = true;
}
else
{
// We parse now the access name. All information about it will be written
// to the context.
cag_option_parse_access_name(context, &c);
}
}
else
{
// This is no long option, so we can just parse an access letter.
cag_option_parse_access_letter(context, &c);
}
// Move the items so that the options come first followed by non-option
// arguments.
cag_option_shift(context, old_index, new_index, context->index);
return context->forced_end == false;
}
char cag_option_get(const cag_option_context *context)
{
// We just return the identifier here.
return context->identifier;
}
const char *cag_option_get_value(const cag_option_context *context)
{
// We just return the internal value pointer of the context.
return context->value;
}
int cag_option_get_index(const cag_option_context *context)
{
// Either we point to a value item,
return context->index;
}

1120
Kernel/library/convert.cpp Normal file

File diff suppressed because it is too large Load Diff

96
Kernel/library/crc32.c Normal file
View File

@ -0,0 +1,96 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <crc32.h>
uint32_t LookupTable[256] =
{
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
uint32_t crc32(const uint8_t *Buffer, int Length)
{
uint32_t ret = 0xffffffff;
while (Length--)
{
ret = (ret << 8) ^ LookupTable[((ret >> 24) ^ *Buffer) & 255];
Buffer++;
}
return ret;
}

1507
Kernel/library/cwalk.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,30 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <cwalk.h>
#include <task.hpp>
#include "../kernel.h"
__aligned(16) static cwk_path_style path_style = CWK_STYLE_UNIX;
EXTERNC cwk_path_style *__cwalk_path_style(void)
{
if (unlikely(!TaskManager || !thisThread))
return &path_style;
return &thisThread->Info.PathStyle;
}

88
Kernel/library/dumper.cpp Normal file
View File

@ -0,0 +1,88 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "dumper.hpp"
#include <memory.hpp>
#include <printf.h>
#include <uart.hpp>
#include <lock.hpp>
#include <md5.h>
NewLock(DumperLock);
using namespace UniversalAsynchronousReceiverTransmitter;
int vprintf_dumper(const char *format, va_list list) { return vfctprintf(uart_wrapper, NULL, format, list); }
void WriteRaw(const char *format, ...)
{
va_list args;
va_start(args, format);
vprintf_dumper(format, args);
va_end(args);
}
void DumpData(const char *Description, void *Address, unsigned long Length)
{
if (Length == 0)
return;
SmartLock(DumperLock);
WriteRaw("-------------------------------------------------------------------------\n");
unsigned char *AddressChar = (unsigned char *)Address;
unsigned char Buffer[17];
unsigned long Iterate;
if (Description != nullptr)
WriteRaw("%s (%d bytes):\n", Description, Length);
for (Iterate = 0; Iterate < Length; Iterate++)
{
if ((Iterate % 16) == 0)
{
if (Iterate != 0)
WriteRaw(" %s\n", Buffer);
WriteRaw(" %04x ", Iterate);
}
WriteRaw(" %02x", AddressChar[Iterate]);
if ((AddressChar[Iterate] < 0x20) || (AddressChar[Iterate] > 0x7e))
Buffer[Iterate % 16] = '.';
else
Buffer[Iterate % 16] = AddressChar[Iterate];
Buffer[(Iterate % 16) + 1] = '\0';
}
while ((Iterate % 16) != 0)
{
WriteRaw(" ");
Iterate++;
}
WriteRaw(" %s\n", Buffer);
WriteRaw("-------------------------------------------------------------------------\n");
WriteRaw("Length: %ld bytes\n", Length);
uint8_t *result = md5File(AddressChar, Length);
WriteRaw("MD5: ");
for (int i = 0; i < 16; i++)
WriteRaw("%02x", result[i]);
kfree(result);
WriteRaw("\n-------------------------------------------------------------------------\n");
}

View File

@ -0,0 +1,254 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <kexcept/cxxabi.h>
#include <memory.hpp>
#include <debug.h>
#include <smp.hpp>
#include "../../kernel.h"
extern "C" _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *Exception);
using namespace __cxxabiv1;
atexit_func_entry_t __atexit_funcs[ATEXIT_MAX_FUNCS];
uarch_t __atexit_func_count = 0;
__cxa_eh_globals *__cxa_get_globals() noexcept
{
return &GetCurrentCPU()->Exception.globals;
}
/**
* @param f The destructor
* @param objptr The object to be destructed
* @param dso The DSO from which the object was obtained (unused in our case)
* @return Zero on success, non-zero on failure
*/
extern "C" int __cxa_atexit(void (*f)(void *), void *objptr, void *dso)
{
if (KernelSymbolTable)
{
debug("Registering atexit function for \"%s\" with destructor \"%s\"",
KernelSymbolTable->GetSymbol((uintptr_t)objptr),
KernelSymbolTable->GetSymbol((uintptr_t)f));
}
else
{
debug("Registering atexit function for %p with destructor %p",
objptr, f);
}
if (__atexit_func_count >= ATEXIT_MAX_FUNCS)
return -1;
__atexit_funcs[__atexit_func_count].destructor_func = f;
__atexit_funcs[__atexit_func_count].obj_ptr = objptr;
__atexit_funcs[__atexit_func_count].dso_handle = dso;
__atexit_func_count++;
return 0;
}
extern "C" void __cxa_finalize(void *f)
{
func("%p", f);
uarch_t i = __atexit_func_count;
if (f == nullptr)
{
while (i--)
{
if (__atexit_funcs[i].destructor_func)
{
if (KernelSymbolTable)
{
debug("Calling atexit function \"%s\"",
KernelSymbolTable->GetSymbol((uintptr_t)__atexit_funcs[i].destructor_func));
}
else
{
debug("Calling atexit function %p",
__atexit_funcs[i].destructor_func);
}
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
}
}
return;
}
while (i--)
{
if (__atexit_funcs[i].destructor_func == f)
{
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
__atexit_funcs[i].destructor_func = 0;
}
}
}
extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, _Unwind_Exception *ue_header, _Unwind_Context *context)
{
fixme("__gxx_personality_v0( %d %p %p %p %p ) called.", version, actions, exception_class, ue_header, context);
return _URC_NO_REASON;
}
extern "C" void *__cxa_begin_catch(void *thrown_object) noexcept
{
func("%p", thrown_object);
__cxa_exception *Exception = (__cxa_exception *)thrown_object - 1;
__cxa_eh_globals *Globals = __cxa_get_globals();
Exception->handlerCount++;
Globals->uncaughtExceptions--;
Exception->nextException = Globals->caughtExceptions;
Globals->caughtExceptions = Exception;
return Exception + 1;
}
extern "C" void __cxa_end_catch()
{
fixme("__cxa_end_catch() called.");
}
static __always_inline inline size_t align_exception_allocation_size(size_t a, size_t b)
{
return (a + b - 1) & ~(b - 1);
}
static __always_inline inline void INIT_EXCEPTION_CLASS(_Unwind_Exception_Class *c)
{
char *ptr = (char *)c;
ptr[0] = 'G';
ptr[1] = 'N';
ptr[2] = 'U';
ptr[3] = 'C';
ptr[4] = 'C';
ptr[5] = '+';
ptr[6] = '+';
ptr[7] = '\0';
}
void unexpected_header_stub() { fixme("unexpected() called."); }
void terminate_header_stub()
{
if (TaskManager && !TaskManager->IsPanic())
{
TaskManager->KillThread(thisThread, Tasking::KILL_CXXABI_EXCEPTION);
TaskManager->Yield();
}
error("No task manager to kill thread!");
CPU::Stop(); /* FIXME: Panic */
}
void exception_cleanup_stub(_Unwind_Reason_Code Code,
_Unwind_Exception *Exception)
{
fixme("exception_cleanup( %d %p ) called.",
Code, Exception);
}
extern "C" void *__cxa_allocate_exception(size_t thrown_size) throw()
{
debug("Allocating exception of size %d.", thrown_size);
size_t alloc_size = align_exception_allocation_size(thrown_size + sizeof(__cxa_exception), alignof(__cxa_exception));
__cxa_exception *Exception = (__cxa_exception *)kmalloc(alloc_size);
memset(Exception, 0, alloc_size);
return Exception + 1;
}
extern "C" __noreturn void __cxa_throw(void *thrown_object,
std::type_info *tinfo,
void (*dest)(void *))
{
trace("Throwing exception of type \"%s\". ( object: %p, destructor: %p )",
tinfo->name(), thrown_object, dest);
__cxa_eh_globals *Globals = __cxa_get_globals();
Globals->uncaughtExceptions++;
__cxa_exception *Exception = (__cxa_exception *)thrown_object - 1;
Exception->exceptionType = (std::type_info *)tinfo;
Exception->exceptionDestructor = dest;
Exception->unexpectedHandler = &unexpected_header_stub;
Exception->terminateHandler = &terminate_header_stub;
Exception->unwindHeader.exception_cleanup = &exception_cleanup_stub;
INIT_EXCEPTION_CLASS(&Exception->unwindHeader.exception_class);
Exception->adjustedPtr = thrown_object;
_Unwind_RaiseException(&Exception->unwindHeader);
__cxa_begin_catch(&Exception->unwindHeader);
error("Uncaught exception!");
CPU::Stop(); /* FIXME: Panic */
}
extern "C" void __cxa_rethrow()
{
fixme("__cxa_rethrow() called.");
}
extern "C" void __cxa_pure_virtual()
{
fixme("__cxa_pure_virtual() called.");
}
extern "C" void __cxa_throw_bad_array_new_length()
{
fixme("__cxa_throw_bad_array_new_length() called.");
}
extern "C" void __cxa_free_exception(void *thrown_exception)
{
fixme("__cxa_free_exception( %p ) called.",
thrown_exception);
}
__extension__ typedef int __guard __attribute__((mode(__DI__)));
extern "C" int __cxa_guard_acquire(__guard *g)
{
fixme("__cxa_guard_acquire( %p ) called.", g);
return !*(char *)(g);
}
extern "C" void __cxa_guard_release(__guard *g)
{
fixme("__cxa_guard_release( %p ) called.", g);
*(char *)g = 1;
}
extern "C" void __cxa_guard_abort(__guard *g)
{
fixme("__cxa_guard_abort( %p ) called.", g);
}
extern "C" __noreturn void __cxa_bad_typeid()
{
fixme("__cxa_bad_typeid() called.");
CPU::Stop(); /* FIXME: Crash the system */
}
extern "C" void *__cxa_get_exception_ptr(void *exceptionObject)
{
stub;
return nullptr;
}

View File

@ -0,0 +1,25 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <debug.h>
void __dso_handle_stub()
{
stub;
}
/* extern */ void *__dso_handle = (void *)&__dso_handle_stub;

View File

@ -0,0 +1,47 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <kexcept/unwind.h>
#include <kexcept/cxxabi.h>
#include <debug.h>
#include <cpu.hpp>
#include <smp.hpp>
#include "../../kernel.h"
using namespace __cxxabiv1;
#if (1) /* Set to 0 to use a library or 1 to use this code */
extern "C" _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *object)
{
stub;
return _URC_NO_REASON;
}
extern "C" void _Unwind_Resume(struct _Unwind_Exception *object)
{
stub;
}
extern "C" _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception *exception_object)
{
stub;
return _URC_NO_REASON;
}
#endif // 0 or 1

View File

@ -0,0 +1,103 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <typeinfo>
#include <debug.h>
namespace __cxxabiv1
{
__class_type_info::~__class_type_info() {}
bool __class_type_info::__do_upcast(const __class_type_info *Destination,
const void *Object,
__upcast_result &__restrict Result) const
{
if (*this != *Destination)
return false;
Result.dst_ptr = Object;
Result.base_type = nonvirtual_base_type;
Result.part2dst = __contained_public;
return true;
}
bool __class_type_info::__do_upcast(const __class_type_info *DestinationType,
void **ObjectPointer) const
{
__upcast_result Result(__vmi_class_type_info::__flags_unknown_mask);
__do_upcast(DestinationType, *ObjectPointer, Result);
if (!((Result.part2dst &
__class_type_info::__contained_public) ==
__class_type_info::__contained_public))
return false;
*ObjectPointer = const_cast<void *>(Result.dst_ptr);
return true;
}
bool __class_type_info::__do_catch(const type_info *ThrowType,
void **ThrowObject,
unsigned Outer) const
{
if (*this == *ThrowType)
return true;
if (Outer >= 4)
return false;
return ThrowType->__do_upcast(this, ThrowObject);
}
bool __class_type_info::__do_dyncast(ptrdiff_t,
__sub_kind AccessPath,
const __class_type_info *DestinationType,
const void *ObjectPointer,
const __class_type_info *SourceType,
const void *SourcePointer,
__dyncast_result &__restrict Result) const
{
if (ObjectPointer == SourcePointer &&
*this == *SourceType)
{
Result.whole2src = AccessPath;
return false;
}
if (*this == *DestinationType)
{
Result.dst_ptr = ObjectPointer;
Result.whole2dst = AccessPath;
Result.dst2src = __not_contained;
return false;
}
return false;
}
__class_type_info::__sub_kind __class_type_info::__do_find_public_src(ptrdiff_t,
const void *ObjectPointer,
const __class_type_info *,
const void *SourcePointer) const
{
if (SourcePointer == ObjectPointer)
return __contained_public;
return __not_contained;
}
}

View File

@ -0,0 +1,23 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <typeinfo>
namespace __cxxabiv1
{
__fundamental_type_info::~__fundamental_type_info() {}
}

View File

@ -0,0 +1,91 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <typeinfo>
namespace __cxxabiv1
{
__pbase_type_info::~__pbase_type_info() {}
bool __pbase_type_info::__do_catch(const type_info *ThrowType,
void **ThrowObject,
unsigned outer) const
{
#ifndef __GXX_RTTI
UNUSED(ThrowType);
UNUSED(ThrowObject);
UNUSED(outer);
return false;
#else
if (*this == *ThrowType)
return true;
if (*ThrowType == typeid(nullptr))
{
if (typeid(*this) == typeid(__pointer_type_info))
{
*ThrowObject = nullptr;
return true;
}
else if (typeid(*this) == typeid(__pointer_to_member_type_info))
{
if (this->Pointee->__is_function_p())
{
using pmf_type = void (__pbase_type_info::*)();
static const pmf_type pmf = nullptr;
*ThrowObject = const_cast<pmf_type *>(&pmf);
return true;
}
else
{
using pm_type = int __pbase_type_info::*;
static const pm_type pm = nullptr;
*ThrowObject = const_cast<pm_type *>(&pm);
return true;
}
}
}
if (typeid(*this) != typeid(*ThrowType))
return false;
if (!(outer & 1))
return false;
const __pbase_type_info *ThrownType =
static_cast<const __pbase_type_info *>(ThrowType);
unsigned TypeFlags = ThrownType->Flags;
const unsigned FlagQualificationMask = __transaction_safe_mask | __noexcept_mask;
unsigned ThrowFlagQualification = (TypeFlags & FlagQualificationMask);
unsigned CatchFlagQualification = (Flags & FlagQualificationMask);
if (ThrowFlagQualification & ~CatchFlagQualification)
TypeFlags &= CatchFlagQualification;
if (CatchFlagQualification & ~ThrowFlagQualification)
return false;
if (TypeFlags & ~Flags)
return false;
if (!(Flags & __const_mask))
outer &= ~1;
return __pointer_catch(ThrownType, ThrowObject, outer);
#endif
}
}

View File

@ -0,0 +1,45 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <typeinfo>
namespace __cxxabiv1
{
__pointer_type_info::~__pointer_type_info() {}
bool __pointer_type_info::__is_pointer_p() const { return true; }
bool __pointer_type_info::__pointer_catch(const __pbase_type_info *ThrownType,
void **ThrowObject,
unsigned Outer) const
{
#ifndef __GXX_RTTI
UNUSED(ThrownType);
UNUSED(ThrowObject);
UNUSED(Outer);
return false;
#else
if (Outer < 2 && *this->Pointee == typeid(void))
return !ThrownType->Pointee->__is_function_p();
return __pbase_type_info::__pointer_catch(ThrownType,
ThrowObject,
Outer);
#endif
}
}

View File

@ -0,0 +1,102 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <typeinfo>
#include <debug.h>
namespace __cxxabiv1
{
template <typename T>
inline const T *adjust_pointer(const void *Base,
ptrdiff_t Offset)
{
return reinterpret_cast<const T *>(reinterpret_cast<const char *>(Base) + Offset);
}
__si_class_type_info::~__si_class_type_info() {}
__class_type_info::__sub_kind __si_class_type_info::
__do_find_public_src(ptrdiff_t SourceToDestination,
const void *ObjectPointer,
const __class_type_info *SourceType,
const void *SourcePointer) const
{
if (SourcePointer == ObjectPointer && *this == *SourceType)
return __contained_public;
return this->BaseType->__do_find_public_src(SourceToDestination,
ObjectPointer,
SourceType,
SourcePointer);
}
bool __si_class_type_info::__do_dyncast(ptrdiff_t SourceToDestination,
__sub_kind AccessPath,
const __class_type_info *DestinationType,
const void *ObjectPointer,
const __class_type_info *SourceType,
const void *SourcePointer,
__dyncast_result &__restrict Result) const
{
if (*this == *DestinationType)
{
Result.dst_ptr = ObjectPointer;
Result.whole2dst = AccessPath;
if (SourceToDestination == -2)
{
Result.dst2src = __not_contained;
return false;
}
if (SourceToDestination >= 0)
{
Result.dst2src = adjust_pointer<void>(ObjectPointer,
SourceToDestination) == SourcePointer
? __contained_public
: __not_contained;
}
return false;
}
if (ObjectPointer == SourcePointer &&
*this == *SourceType)
{
Result.whole2src = AccessPath;
return false;
}
return this->BaseType->__do_dyncast(SourceToDestination,
AccessPath,
DestinationType,
ObjectPointer,
SourceType,
SourcePointer,
Result);
}
bool __si_class_type_info::__do_upcast(const __class_type_info *Destination,
const void *ObjectPointer,
__upcast_result &__restrict Result) const
{
if (__class_type_info::__do_upcast(Destination, ObjectPointer, Result))
return true;
return this->BaseType->__do_upcast(Destination, ObjectPointer, Result);
}
}

View File

@ -0,0 +1,42 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <typeinfo>
#include <debug.h>
namespace __cxxabiv1
{
__vmi_class_type_info::~__vmi_class_type_info()
{
}
void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
{
if (__do_upcast(other, &obj))
return obj;
return 0;
}
bool __vmi_class_type_info::__do_upcast(const __class_type_info *target, void **thrown_object) const
{
if (this == target)
return true;
stub;
return 0;
}
}

257
Kernel/library/md5.c Normal file
View File

@ -0,0 +1,257 @@
/*
* Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm
* and modified slightly to be functionally identical but condensed into control structures.
*/
#include <md5.h>
#include <memory.hpp>
#include <convert.h>
/*
* Constants defined by the MD5 algorithm
*/
#define A 0x67452301
#define B 0xefcdab89
#define C 0x98badcfe
#define D 0x10325476
static uint32_t S[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};
static uint32_t K[] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};
/*
* Bit-manipulation functions defined by the MD5 algorithm
*/
#define F(X, Y, Z) ((X & Y) | (~X & Z))
#define G(X, Y, Z) ((X & Z) | (Y & ~Z))
#define H(X, Y, Z) (X ^ Y ^ Z)
#define I(X, Y, Z) (Y ^ (X | ~Z))
/*
* Padding used to make the size (in bits) of the input congruent to 448 mod 512
*/
static uint8_t PADDING[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/*
* Initialize a context
*/
void md5Init(MD5Context *ctx)
{
ctx->size = (uint64_t)0;
ctx->buffer[0] = (uint32_t)A;
ctx->buffer[1] = (uint32_t)B;
ctx->buffer[2] = (uint32_t)C;
ctx->buffer[3] = (uint32_t)D;
}
/*
* Add some amount of input to the context
*
* If the input fills out a block of 512 bits, apply the algorithm (md5Step)
* and save the result in the buffer. Also updates the overall size.
*/
void md5Update(MD5Context *ctx, uint8_t *input_buffer, size_t input_len)
{
uint32_t input[16];
unsigned int offset = ctx->size % 64;
ctx->size += (uint64_t)input_len;
// Copy each byte in input_buffer into the next space in our context input
for (unsigned int i = 0; i < input_len; ++i)
{
ctx->input[offset++] = (uint8_t) * (input_buffer + i);
// If we've filled our context input, copy it into our local array input
// then reset the offset to 0 and fill in a new buffer.
// Every time we fill out a chunk, we run it through the algorithm
// to enable some back and forth between cpu and i/o
if (offset % 64 == 0)
{
for (unsigned int j = 0; j < 16; ++j)
{
// Convert to little-endian
// The local variable `input` our 512-bit chunk separated into 32-bit words
// we can use in calculations
input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 |
(uint32_t)(ctx->input[(j * 4) + 2]) << 16 |
(uint32_t)(ctx->input[(j * 4) + 1]) << 8 |
(uint32_t)(ctx->input[(j * 4)]);
}
md5Step(ctx->buffer, input);
offset = 0;
}
}
}
/*
* Pad the current input to get to 448 bytes, append the size in bits to the very end,
* and save the result of the final iteration into digest.
*/
void md5Finalize(MD5Context *ctx)
{
uint32_t input[16];
unsigned int offset = ctx->size % 64;
unsigned int padding_length = offset < 56 ? 56 - offset : (56 + 64) - offset;
// Fill in the padding and do the changes to size that resulted from the update
md5Update(ctx, PADDING, padding_length);
ctx->size -= (uint64_t)padding_length;
// Do a final update (internal to this function)
// Last two 32-bit words are the two halves of the size (converted from bytes to bits)
for (unsigned int j = 0; j < 14; ++j)
{
input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 |
(uint32_t)(ctx->input[(j * 4) + 2]) << 16 |
(uint32_t)(ctx->input[(j * 4) + 1]) << 8 |
(uint32_t)(ctx->input[(j * 4)]);
}
input[14] = (uint32_t)(ctx->size * 8);
#ifdef a32
input[15] = (uint32_t)((uint64_t)(((uint64_t)ctx->size >> 32) | ((uint64_t)ctx->size << 32)) >> 32);
#else
input[15] = (uint32_t)((ctx->size * 8) >> 32);
#endif
md5Step(ctx->buffer, input);
// Move the result into digest (convert from little-endian)
for (unsigned int i = 0; i < 4; ++i)
{
ctx->digest[(i * 4) + 0] = (uint8_t)((ctx->buffer[i] & 0x000000FF));
ctx->digest[(i * 4) + 1] = (uint8_t)((ctx->buffer[i] & 0x0000FF00) >> 8);
ctx->digest[(i * 4) + 2] = (uint8_t)((ctx->buffer[i] & 0x00FF0000) >> 16);
ctx->digest[(i * 4) + 3] = (uint8_t)((ctx->buffer[i] & 0xFF000000) >> 24);
}
}
/*
* Step on 512 bits of input with the main MD5 algorithm.
*/
void md5Step(uint32_t *buffer, uint32_t *input)
{
uint32_t AA = buffer[0];
uint32_t BB = buffer[1];
uint32_t CC = buffer[2];
uint32_t DD = buffer[3];
uint32_t E;
unsigned int j;
for (unsigned int i = 0; i < 64; ++i)
{
switch (i / 16)
{
case 0:
E = F(BB, CC, DD);
j = i;
break;
case 1:
E = G(BB, CC, DD);
j = ((i * 5) + 1) % 16;
break;
case 2:
E = H(BB, CC, DD);
j = ((i * 3) + 5) % 16;
break;
default:
E = I(BB, CC, DD);
j = (i * 7) % 16;
break;
}
uint32_t temp = DD;
DD = CC;
CC = BB;
BB = BB + rotateLeft(AA + E + K[i] + input[j], S[i]);
AA = temp;
}
buffer[0] += AA;
buffer[1] += BB;
buffer[2] += CC;
buffer[3] += DD;
}
/*
* Functions that will return a pointer to the hash of the provided input
*/
uint8_t *md5String(char *input)
{
MD5Context ctx;
md5Init(&ctx);
md5Update(&ctx, (uint8_t *)input, strlen(input));
md5Finalize(&ctx);
uint8_t *result = kmalloc(16);
if (result == NULL)
return (uint8_t *)"error";
memcpy(result, ctx.digest, 16);
return result;
}
uint8_t *md5File(uint8_t *buffer, size_t input_len)
{
char *input_buffer = (char *)buffer;
size_t input_size = input_len;
MD5Context ctx;
md5Init(&ctx);
while (input_size > 0)
{
size_t chunk_size = input_size > 1024 ? 1024 : input_size;
md5Update(&ctx, (uint8_t *)input_buffer, chunk_size);
input_buffer += chunk_size;
input_size -= chunk_size;
}
// while ((input_size = fread(input_buffer, 1, 1024, file)) > 0)
// {
// md5Update(&ctx, (uint8_t *)input_buffer, input_size);
// }
md5Finalize(&ctx);
uint8_t *result = kmalloc(16);
if (result == NULL)
return (uint8_t *)"error";
memcpy(result, ctx.digest, 16);
return result;
}
/*
* Rotates a 32-bit word left by n bits
*/
uint32_t rotateLeft(uint32_t x, uint32_t n)
{
return (x << n) | (x >> (32 - n));
}

351
Kernel/library/memop.c Normal file
View File

@ -0,0 +1,351 @@
#include <convert.h>
#include <memory.hpp>
#include <limits.h>
#include <debug.h>
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wsign-conversion"
/* Some of the functions are from musl library */
/* https://www.musl-libc.org/ */
/*
Copyright © 2005-2020 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
void *memcpy_unsafe(void *dest, const void *src, size_t n)
{
unsigned char *d = dest;
const unsigned char *s = src;
#ifdef __GNUC__
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define LS >>
#define RS <<
#else
#define LS <<
#define RS >>
#endif
typedef uint32_t __attribute__((__may_alias__)) u32;
uint32_t w, x;
for (; (uintptr_t)s % 4 && n; n--)
*d++ = *s++;
if ((uintptr_t)d % 4 == 0)
{
for (; n >= 16; s += 16, d += 16, n -= 16)
{
*(u32 *)(d + 0) = *(u32 *)(s + 0);
*(u32 *)(d + 4) = *(u32 *)(s + 4);
*(u32 *)(d + 8) = *(u32 *)(s + 8);
*(u32 *)(d + 12) = *(u32 *)(s + 12);
}
if (n & 8)
{
*(u32 *)(d + 0) = *(u32 *)(s + 0);
*(u32 *)(d + 4) = *(u32 *)(s + 4);
d += 8;
s += 8;
}
if (n & 4)
{
*(u32 *)(d + 0) = *(u32 *)(s + 0);
d += 4;
s += 4;
}
if (n & 2)
{
*d++ = *s++;
*d++ = *s++;
}
if (n & 1)
{
*d = *s;
}
return dest;
}
if (n >= 32)
{
switch ((uintptr_t)d % 4)
{
case 1:
{
w = *(u32 *)s;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
n -= 3;
for (; n >= 17; s += 16, d += 16, n -= 16)
{
x = *(u32 *)(s + 1);
*(u32 *)(d + 0) = (w LS 24) | (x RS 8);
w = *(u32 *)(s + 5);
*(u32 *)(d + 4) = (x LS 24) | (w RS 8);
x = *(u32 *)(s + 9);
*(u32 *)(d + 8) = (w LS 24) | (x RS 8);
w = *(u32 *)(s + 13);
*(u32 *)(d + 12) = (x LS 24) | (w RS 8);
}
break;
}
case 2:
{
w = *(u32 *)s;
*d++ = *s++;
*d++ = *s++;
n -= 2;
for (; n >= 18; s += 16, d += 16, n -= 16)
{
x = *(u32 *)(s + 2);
*(u32 *)(d + 0) = (w LS 16) | (x RS 16);
w = *(u32 *)(s + 6);
*(u32 *)(d + 4) = (x LS 16) | (w RS 16);
x = *(u32 *)(s + 10);
*(u32 *)(d + 8) = (w LS 16) | (x RS 16);
w = *(u32 *)(s + 14);
*(u32 *)(d + 12) = (x LS 16) | (w RS 16);
}
break;
}
case 3:
{
w = *(u32 *)s;
*d++ = *s++;
n -= 1;
for (; n >= 19; s += 16, d += 16, n -= 16)
{
x = *(u32 *)(s + 3);
*(u32 *)(d + 0) = (w LS 8) | (x RS 24);
w = *(u32 *)(s + 7);
*(u32 *)(d + 4) = (x LS 8) | (w RS 24);
x = *(u32 *)(s + 11);
*(u32 *)(d + 8) = (w LS 8) | (x RS 24);
w = *(u32 *)(s + 15);
*(u32 *)(d + 12) = (x LS 8) | (w RS 24);
}
break;
}
default:
break;
}
}
if (n & 16)
{
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
if (n & 8)
{
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
if (n & 4)
{
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
if (n & 2)
{
*d++ = *s++;
*d++ = *s++;
}
if (n & 1)
{
*d = *s;
}
return dest;
#endif
for (; n; n--)
*d++ = *s++;
return dest;
}
void *memset_unsafe(void *dest, int c, size_t n)
{
unsigned char *s = dest;
size_t k;
if (!n)
return dest;
s[0] = c;
s[n - 1] = c;
if (n <= 2)
return dest;
s[1] = c;
s[2] = c;
s[n - 2] = c;
s[n - 3] = c;
if (n <= 6)
return dest;
s[3] = c;
s[n - 4] = c;
if (n <= 8)
return dest;
k = -(uintptr_t)s & 3;
s += k;
n -= k;
n &= -4;
#ifdef __GNUC__
typedef uint32_t __attribute__((__may_alias__)) u32;
typedef uint64_t __attribute__((__may_alias__)) u64;
u32 c32 = ((u32)-1) / 255 * (unsigned char)c;
*(u32 *)(s + 0) = c32;
*(u32 *)(s + n - 4) = c32;
if (n <= 8)
return dest;
*(u32 *)(s + 4) = c32;
*(u32 *)(s + 8) = c32;
*(u32 *)(s + n - 12) = c32;
*(u32 *)(s + n - 8) = c32;
if (n <= 24)
return dest;
*(u32 *)(s + 12) = c32;
*(u32 *)(s + 16) = c32;
*(u32 *)(s + 20) = c32;
*(u32 *)(s + 24) = c32;
*(u32 *)(s + n - 28) = c32;
*(u32 *)(s + n - 24) = c32;
*(u32 *)(s + n - 20) = c32;
*(u32 *)(s + n - 16) = c32;
k = 24 + ((uintptr_t)s & 4);
s += k;
n -= k;
u64 c64 = c32 | ((u64)c32 << 32);
for (; n >= 32; n -= 32, s += 32)
{
*(u64 *)(s + 0) = c64;
*(u64 *)(s + 8) = c64;
*(u64 *)(s + 16) = c64;
*(u64 *)(s + 24) = c64;
}
#else
for (; n; n--, s++)
*s = c;
#endif
return dest;
}
void *memmove_unsafe(void *dest, const void *src, size_t n)
{
#ifdef __GNUC__
typedef __attribute__((__may_alias__)) size_t WT;
#define WS (sizeof(WT))
#endif
char *d = dest;
const char *s = src;
if (d == s)
return d;
if ((uintptr_t)s - (uintptr_t)d - n <= -2 * n)
return memcpy(d, s, n);
if (d < s)
{
#ifdef __GNUC__
if ((uintptr_t)s % WS == (uintptr_t)d % WS)
{
while ((uintptr_t)d % WS)
{
if (!n--)
return dest;
*d++ = *s++;
}
for (; n >= WS; n -= WS, d += WS, s += WS)
*(WT *)d = *(WT *)s;
}
#endif
for (; n; n--)
*d++ = *s++;
}
else
{
#ifdef __GNUC__
if ((uintptr_t)s % WS == (uintptr_t)d % WS)
{
while ((uintptr_t)(d + n) % WS)
{
if (!n--)
return dest;
d[n] = s[n];
}
while (n >= WS)
n -= WS, *(WT *)(d + n) = *(WT *)(s + n);
}
#endif
while (n)
n--, d[n] = s[n];
}
return dest;
}

1592
Kernel/library/printf.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,280 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <convert.h>
#include <memory.hpp>
#include <limits.h>
#include <debug.h>
#include <cpu.hpp>
/*
TODO: Replace these functions with even more optimized versions.
The current versions are fast but not as fast as they could be and also we need implementation for avx, not only sse.
*/
EXTERNC void *memcpy_sse(void *dest, const void *src, size_t n)
{
#if defined(a64)
char *d = (char *)dest;
const char *s = (const char *)src;
if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0)
{
size_t num_vectors = n / 16;
for (size_t i = 0; i < num_vectors; i++)
{
asmv("movaps (%0), %%xmm0\n"
"movaps %%xmm0, (%1)\n"
:
: "r"(s), "r"(d)
: "xmm0");
d += 16;
s += 16;
}
n -= num_vectors * 16;
}
else
{
size_t num_vectors = n / 16;
for (size_t i = 0; i < num_vectors; i++)
{
asmv("movups (%0), %%xmm0\n"
"movups %%xmm0, (%1)\n"
:
: "r"(s), "r"(d)
: "xmm0");
d += 16;
s += 16;
}
n -= num_vectors * 16;
}
memcpy_unsafe(d, s, n);
#endif // defined(a64)
return dest;
}
EXTERNC void *memcpy_sse2(void *dest, const void *src, size_t n)
{
#if defined(a64)
char *d = (char *)dest;
const char *s = (const char *)src;
if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0)
{
size_t num_vectors = n / 16;
for (size_t i = 0; i < num_vectors; i++)
{
asmv("movdqa (%0), %%xmm0\n"
"movdqa %%xmm0, (%1)\n"
:
: "r"(s), "r"(d)
: "xmm0");
d += 16;
s += 16;
}
n -= num_vectors * 16;
}
else
{
size_t num_vectors = n / 16;
for (size_t i = 0; i < num_vectors; i++)
{
asmv("movdqu (%0), %%xmm0\n"
"movdqu %%xmm0, (%1)\n"
:
: "r"(s), "r"(d)
: "xmm0");
d += 16;
s += 16;
}
n -= num_vectors * 16;
}
memcpy_unsafe(d, s, n);
#endif // defined(a64)
return dest;
}
EXTERNC void *memcpy_sse3(void *dest, const void *src, size_t n)
{
#if defined(a64)
char *d = (char *)dest;
const char *s = (const char *)src;
if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0)
{
size_t num_vectors = n / 16;
for (size_t i = 0; i < num_vectors; i++)
{
asmv("movdqa (%0), %%xmm0\n"
"movdqa %%xmm0, (%1)\n"
:
: "r"(s), "r"(d)
: "xmm0");
d += 16;
s += 16;
}
n -= num_vectors * 16;
}
else
{
size_t num_vectors = n / 16;
for (size_t i = 0; i < num_vectors; i++)
{
asmv("movdqu (%0), %%xmm0\n"
"movdqu %%xmm0, (%1)\n"
:
: "r"(s), "r"(d)
: "xmm0");
d += 16;
s += 16;
}
n -= num_vectors * 16;
}
memcpy_unsafe(d, s, n);
#endif // defined(a64)
return dest;
}
EXTERNC void *memcpy_ssse3(void *dest, const void *src, size_t n)
{
#if defined(a64)
char *d = (char *)dest;
const char *s = (const char *)src;
if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0)
{
size_t num_vectors = n / 16;
for (size_t i = 0; i < num_vectors; i++)
{
asmv("lddqu (%0), %%xmm0\n"
"movdqa %%xmm0, (%1)\n"
:
: "r"(s), "r"(d)
: "xmm0");
d += 16;
s += 16;
}
n -= num_vectors * 16;
}
else
{
size_t num_vectors = n / 16;
for (size_t i = 0; i < num_vectors; i++)
{
asmv("lddqu (%0), %%xmm0\n"
"movdqu %%xmm0, (%1)\n"
:
: "r"(s), "r"(d)
: "xmm0");
d += 16;
s += 16;
}
n -= num_vectors * 16;
}
memcpy_unsafe(d, s, n);
#endif // defined(a64)
return dest;
}
EXTERNC void *memcpy_sse4_1(void *dest, const void *src, size_t n)
{
#if defined(a64)
char *d = (char *)dest;
const char *s = (const char *)src;
if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0)
{
size_t num_vectors = n / 16;
for (size_t i = 0; i < num_vectors; i++)
{
asmv("movdqa (%0), %%xmm0\n"
"movdqa %%xmm0, (%1)\n"
:
: "r"(s), "r"(d)
: "xmm0");
d += 16;
s += 16;
}
n -= num_vectors * 16;
}
else
{
size_t num_vectors = n / 16;
for (size_t i = 0; i < num_vectors; i++)
{
asmv("movdqu (%0), %%xmm0\n"
"movdqu %%xmm0, (%1)\n"
:
: "r"(s), "r"(d)
: "xmm0");
d += 16;
s += 16;
}
n -= num_vectors * 16;
}
memcpy_unsafe(d, s, n);
#endif // defined(a64)
return dest;
}
EXTERNC void *memcpy_sse4_2(void *dest, const void *src, size_t n)
{
#if defined(a64)
char *d = (char *)dest;
const char *s = (const char *)src;
if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0)
{
size_t num_vectors = n / 16;
for (size_t i = 0; i < num_vectors; i++)
{
asmv("movdqa (%0), %%xmm0\n"
"movdqa %%xmm0, (%1)\n"
:
: "r"(s), "r"(d)
: "xmm0");
d += 16;
s += 16;
}
n -= num_vectors * 16;
}
else
{
size_t num_vectors = n / 16;
for (size_t i = 0; i < num_vectors; i++)
{
asmv("movdqu (%0), %%xmm0\n"
"movdqu %%xmm0, (%1)\n"
:
: "r"(s), "r"(d)
: "xmm0");
d += 16;
s += 16;
}
n -= num_vectors * 16;
}
memcpy_unsafe(d, s, n);
#endif // defined(a64)
return dest;
}

View File

@ -0,0 +1,60 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <convert.h>
#include <memory.hpp>
#include <limits.h>
#include <debug.h>
#include <cpu.hpp>
/*
TODO: Replace these functions with even more optimized versions.
The current versions are fast but not as fast as they could be and also we need implementation for avx, not only sse.
*/
// TODO: Implement these functions
EXTERNC void *memmove_sse(void *dest, const void *src, size_t n)
{
return memmove_unsafe(dest, src, n);
}
EXTERNC void *memmove_sse2(void *dest, const void *src, size_t n)
{
return memmove_sse(dest, src, n);
}
EXTERNC void *memmove_sse3(void *dest, const void *src, size_t n)
{
return memmove_sse(dest, src, n);
}
EXTERNC void *memmove_ssse3(void *dest, const void *src, size_t n)
{
return memmove_sse(dest, src, n);
}
EXTERNC void *memmove_sse4_1(void *dest, const void *src, size_t n)
{
return memmove_sse(dest, src, n);
}
EXTERNC void *memmove_sse4_2(void *dest, const void *src, size_t n)
{
return memmove_sse(dest, src, n);
}

View File

@ -0,0 +1,114 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <convert.h>
#include <memory.hpp>
#include <limits.h>
#include <debug.h>
#include <cpu.hpp>
/*
TODO: Replace these functions with even more optimized versions.
The current versions are fast but not as fast as they could be and also we need implementation for avx, not only sse.
*/
// TODO: Implement these functions
EXTERNC void *memset_sse(void *dest, int c, size_t n)
{
return memset_unsafe(dest, c, n);
}
EXTERNC void *memset_sse2(void *dest, int c, size_t n)
{
size_t i;
if ((size_t)dest & (16 - 1))
{
i = 0;
while (((size_t)dest + i) & (16 - 1) && i < n)
{
asmv("stosb\n"
:
: "D"((size_t)dest + i),
"a"(c));
i++;
}
}
else
i = 0;
for (; i + 64 <= n; i += 64)
{
asmv("movd %0, %%xmm0\n"
"movdqa %%xmm0, (%1)\n"
"movdqa %%xmm0, 16(%1)\n"
"movdqa %%xmm0, 32(%1)\n"
"movdqa %%xmm0, 48(%1)\n"
:
: "r"(c), "r"(((size_t)dest) + i)
: "xmm0");
}
asmv("rep stosb\n" ::"a"((size_t)(c)),
"D"(((size_t)dest) + i),
"c"(n - i));
i += n - i;
return (void *)(((size_t)dest) + i);
}
EXTERNC void *memset_sse3(void *dest, int c, size_t n)
{
return memset_sse2(dest, c, n);
}
EXTERNC void *memset_ssse3(void *dest, int c, size_t n)
{
return memset_sse2(dest, c, n);
}
EXTERNC void *memset_sse4_1(void *dest, int c, size_t n)
{
return memset_sse2(dest, c, n);
}
EXTERNC void *memset_sse4_2(void *dest, int c, size_t n)
{
#if defined(a64)
char *d = (char *)dest;
if (((uintptr_t)d & 0xF) == 0)
{
size_t num_vectors = n / 16;
for (size_t i = 0; i < num_vectors; i++)
{
asmv("movd %0, %%xmm0\n"
"pshufd $0, %%xmm0, %%xmm0\n"
"movdqa %%xmm0, (%1)\n"
:
: "r"(c), "r"(d)
: "xmm0");
d += 16;
}
n -= num_vectors * 16;
}
memset_unsafe(d, c, n);
#endif
return dest;
}

View File

@ -0,0 +1,122 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <convert.h>
#include <memory.hpp>
#include <limits.h>
#include <debug.h>
#include <cpu.hpp>
/*
TODO: Replace these functions with even more optimized versions.
The current versions are fast but not as fast as they could be and also we need implementation for avx, not only sse.
*/
long unsigned __strlen(const char s[])
{
size_t ret = (size_t)s;
asmv("._strlenLoop:"
"cmpb $0, 0(%1)\n"
"jz ._strlenExit\n"
"cmpb $0, 1(%1)\n"
"jz .scmp1\n"
"cmpb $0, 2(%1)\n"
"jz .scmp2\n"
"cmpb $0, 3(%1)\n"
"jz .scmp3\n"
"cmpb $0, 4(%1)\n"
"jz .scmp4\n"
"cmpb $0, 5(%1)\n"
"jz .scmp5\n"
"cmpb $0, 6(%1)\n"
"jz .scmp6\n"
"cmpb $0, 7(%1)\n"
"jz .scmp7\n"
"add $8, %1\n"
"jmp ._strlenLoop\n"
".scmp1:"
"inc %1\n"
"jmp ._strlenExit\n"
".scmp2:"
"add $2, %1\n"
"jmp ._strlenExit\n"
".scmp3:"
"add $3, %1\n"
"jmp ._strlenExit\n"
".scmp4:"
"add $4, %1\n"
"jmp ._strlenExit\n"
".scmp5:"
"add $5, %1\n"
"jmp ._strlenExit\n"
".scmp6:"
"add $6, %1\n"
"jmp ._strlenExit\n"
".scmp7:"
"add $7, %1\n"
"._strlenExit:"
"mov %1, %0\n"
: "=r"(ret) : "0"(ret));
return ret - (size_t)s;
}
long unsigned strlen_sse(const char s[])
{
return __strlen(s);
}
long unsigned strlen_sse2(const char s[])
{
return __strlen(s);
}
long unsigned strlen_sse3(const char s[])
{
return __strlen(s);
}
long unsigned strlen_ssse3(const char s[])
{
return __strlen(s);
}
long unsigned strlen_sse4_1(const char s[])
{
return __strlen(s);
}
long unsigned strlen_sse4_2(const char s[])
{
size_t ret;
asmv("mov $-16, %0\n"
"pxor %%xmm0, %%xmm0\n"
".strlen42Loop:"
"add $16, %0\n"
"pcmpistri $0x08, (%0,%1), %%xmm0\n"
"jnz .strlen42Loop\n"
"add %2, %0\n"
: "=a"(ret)
: "d"((size_t)s), "c"((size_t)s));
return ret;
}

View File

@ -0,0 +1,209 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <types.h>
#include <debug.h>
#include <atomic>
#include "../../kernel.h"
__aligned(16) static int errno_value = 0;
EXTERNC int *__errno_location(void)
{
if (unlikely(!TaskManager || !thisThread))
return &errno_value;
return &thisThread->ErrorNumber;
}
char *strerror(int errnum)
{
if (errnum < 0)
errnum = -errnum;
switch (errnum)
{
case EOK:
return (char *)"No error";
case E2BIG:
return (char *)"Argument list too long";
case EACCES:
return (char *)"Permission denied";
case EADDRINUSE:
return (char *)"Address in use";
case EADDRNOTAVAIL:
return (char *)"Address not available";
case EAFNOSUPPORT:
return (char *)"Address family not supported";
case EAGAIN:
return (char *)"Resource unavailable, try again";
case EALREADY:
return (char *)"Connection already in progress";
case EBADF:
return (char *)"Bad file descriptor";
case EBADMSG:
return (char *)"Bad message";
case EBUSY:
return (char *)"Device or resource busy";
case ECANCELED:
return (char *)"Operation canceled";
case ECHILD:
return (char *)"No child processes";
case ECONNABORTED:
return (char *)"Connection aborted";
case ECONNREFUSED:
return (char *)"Connection refused";
case ECONNRESET:
return (char *)"Connection reset";
case EDEADLK:
return (char *)"Resource deadlock would occur";
case EDESTADDRREQ:
return (char *)"Destination address required";
case EDOM:
return (char *)"Mathematics argument out of domain of function";
case EDQUOT:
return (char *)"Reserved";
case EEXIST:
return (char *)"File exists";
case EFAULT:
return (char *)"Bad address";
case EFBIG:
return (char *)"File too large";
case EHOSTUNREACH:
return (char *)"Host is unreachable";
case EIDRM:
return (char *)"Identifier removed";
case EILSEQ:
return (char *)"Illegal byte sequence";
case EINPROGRESS:
return (char *)"Operation in progress";
case EINTR:
return (char *)"Interrupted function";
case EINVAL:
return (char *)"Invalid argument";
case EIO:
return (char *)"I/O error";
case EISCONN:
return (char *)"Socket is connected";
case EISDIR:
return (char *)"Is a directory";
case ELOOP:
return (char *)"Too many levels of symbolic links";
case EMFILE:
return (char *)"File descriptor value too large";
case EMLINK:
return (char *)"Too many links";
case EMSGSIZE:
return (char *)"Message too large";
case EMULTIHOP:
return (char *)"Reserved";
case ENAMETOOLONG:
return (char *)"Filename too long";
case ENETDOWN:
return (char *)"Network is down";
case ENETRESET:
return (char *)"Connection aborted by network";
case ENETUNREACH:
return (char *)"Network unreachable";
case ENFILE:
return (char *)"Too many files open in system";
case ENOBUFS:
return (char *)"No buffer space available";
case ENODATA:
return (char *)"No message available on the STREAM head read queue";
case ENODEV:
return (char *)"No such device";
case ENOENT:
return (char *)"No such file or directory";
case ENOEXEC:
return (char *)"Executable file format error";
case ENOLCK:
return (char *)"No locks available";
case ENOLINK:
return (char *)"Reserved";
case ENOMEM:
return (char *)"Not enough space";
case ENOMSG:
return (char *)"No message of the desired type";
case ENOPROTOOPT:
return (char *)"Protocol not available";
case ENOSPC:
return (char *)"No space left on device";
case ENOSR:
return (char *)"No STREAM resources";
case ENOSTR:
return (char *)"Not a STREAM";
case ENOSYS:
return (char *)"Functionality not supported";
case ENOTCONN:
return (char *)"The socket is not connected";
case ENOTDIR:
return (char *)"Not a directory or a symbolic link to a directory";
case ENOTEMPTY:
return (char *)"Directory not empty";
case ENOTRECOVERABLE:
return (char *)"State not recoverable";
case ENOTSOCK:
return (char *)"Not a socket";
case ENOTSUP:
return (char *)"Not supported";
case ENOTTY:
return (char *)"Inappropriate I/O control operation";
case ENXIO:
return (char *)"No such device or address";
case EOPNOTSUPP:
return (char *)"Operation not supported on socket";
case EOVERFLOW:
return (char *)"Value too large to be stored in data type";
case EOWNERDEAD:
return (char *)"Previous owner died";
case EPERM:
return (char *)"Operation not permitted";
case EPIPE:
return (char *)"Broken pipe";
case EPROTO:
return (char *)"Protocol error";
case EPROTONOSUPPORT:
return (char *)"Protocol not supported";
case EPROTOTYPE:
return (char *)"Protocol wrong type for socket";
case ERANGE:
return (char *)"Result too large";
case EROFS:
return (char *)"Read-only file system";
case ESPIPE:
return (char *)"Invalid seek";
case ESRCH:
return (char *)"No such process";
case ESTALE:
return (char *)"Reserved";
case ETIME:
return (char *)"Stream ioctl() timeout";
case ETIMEDOUT:
return (char *)"Connection timed out";
case ETXTBSY:
return (char *)"Text file busy";
case EWOULDBLOCK:
return (char *)"Operation would block";
case EXDEV:
return (char *)"Cross-device link";
default:
return (char *)"Unknown error";
}
}

View File

@ -0,0 +1,111 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <mutex>
#include <algorithm>
#include <assert.h>
#include <cpu.hpp>
#include "../../kernel.h"
using namespace Tasking;
namespace std
{
void mutex::lock()
{
RetryLock:
bool Result = this->Locked.exchange(true, std::memory_order_acquire);
TCB *tcb = thisThread;
assert(tcb != nullptr);
if (Result == true)
{
debug("%#lx: Mutex is locked, blocking task %d (\"%s\" : %d)", this,
tcb->ID, tcb->Parent->Name, tcb->Parent->ID);
this->Waiting.push_back(tcb);
tcb->Block();
TaskManager->Yield();
goto RetryLock;
}
this->Holder = tcb;
this->Waiting.remove(tcb);
debug("%#lx: Mutex locked by task %d (\"%s\" : %d)", this,
tcb->ID, tcb->Parent->Name, tcb->Parent->ID);
}
bool mutex::try_lock()
{
bool Result = this->Locked.exchange(true, std::memory_order_acquire);
TCB *tcb = thisThread;
assert(tcb != nullptr);
if (Result == true)
{
debug("%#lx: Mutex is locked, task %d (\"%s\" : %d) failed to lock", this,
tcb->ID, tcb->Parent->Name, tcb->Parent->ID);
return false;
}
this->Holder = tcb;
this->Waiting.remove(tcb);
debug("%#lx: Mutex locked by task %d (\"%s\" : %d)", this,
tcb->ID, tcb->Parent->Name, tcb->Parent->ID);
return true;
}
void mutex::unlock()
{
TCB *tcb = thisThread;
assert(tcb != nullptr);
assert(this->Holder == tcb);
this->Holder = nullptr;
this->Locked.store(false, std::memory_order_release);
if (this->Waiting.empty())
{
debug("%#lx: Mutex unlocked, no tasks to unblock", this);
return;
}
TCB *Next = this->Waiting.front();
this->Waiting.pop_front();
debug("%#lx: Mutex unlocked, task %d (\"%s\" : %d) unblocked", this,
Next->ID, Next->Parent->Name, Next->Parent->ID);
Next->Unblock();
}
mutex::mutex()
{
debug("%#lx: Creating mutex", this);
}
mutex::~mutex()
{
debug("%#lx: Destroying mutex", this);
assert(this->Holder == nullptr);
assert(this->Waiting.empty());
}
}

View File

@ -0,0 +1,82 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <new>
#include <memory.hpp>
#include <stdexcept>
void *operator new(std::size_t count)
{
if (count == 0)
++count;
if (void *ptr = kmalloc(count))
return ptr;
throw std::bad_alloc{};
}
void *operator new[](std::size_t count)
{
if (count == 0)
++count;
if (void *ptr = kmalloc(count))
return ptr;
throw std::bad_alloc{};
}
// void *operator new(std::size_t count, std::align_val_t al)
// void *operator new[](std::size_t count, std::align_val_t al)
// void *operator new(std::size_t count, const std::nothrow_t &tag)
// void *operator new[](std::size_t count, const std::nothrow_t &tag)
// void *operator new(std::size_t count, std::align_val_t al, const std::nothrow_t &)
// void *operator new[](std::size_t count, std::align_val_t al, const std::nothrow_t &)
void *operator new(std::size_t, void *ptr) noexcept { return ptr; }
// void *operator new[](std::size_t count, void *ptr) noexcept
// void *operator new(std::size_t count, ...)
// void *operator new[](std::size_t count, ...)
// void *operator new(std::size_t count, std::align_val_t al, ...)
// void *operator new[](std::size_t count, std::align_val_t al, ...)
void operator delete(void *ptr) noexcept { kfree(ptr); }
void operator delete[](void *ptr) noexcept { kfree(ptr); }
// void operator delete(void *ptr, std::align_val_t al) noexcept
// void operator delete[](void *ptr, std::align_val_t al) noexcept
void operator delete(void *ptr, std::size_t) noexcept { kfree(ptr); }
void operator delete[](void *ptr, std::size_t sz) noexcept { kfree(ptr); }
void operator delete(void *ptr, std::size_t sz, std::align_val_t al) noexcept { kfree(ptr); }
// void operator delete[](void *ptr, std::size_t sz, std::align_val_t al) noexcept
// void operator delete(void *ptr, const std::nothrow_t &tag) noexcept
// void operator delete[](void *ptr, const std::nothrow_t &tag) noexcept
// void operator delete(void *ptr, std::align_val_t al, const std::nothrow_t &tag) noexcept
// void operator delete[](void *ptr, std::align_val_t al, const std::nothrow_t &tag) noexcept
// void operator delete(void *ptr, void *place) noexcept
// void operator delete[](void *ptr, void *place) noexcept
// void operator delete(void *ptr, ...)
// void operator delete[](void *ptr, ...)

View File

@ -0,0 +1,41 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <string>
#include <printf.h>
namespace std
{
int sprintf(char *s, const char *format, ...)
{
va_list args;
va_start(args, format);
int ret = vsprintf(s, format, args);
va_end(args);
return ret;
}
int snprintf(char *s, size_t count, const char *format, ...)
{
va_list args;
va_start(args, format);
int ret = vsnprintf(s, count, format, args);
va_end(args);
return ret;
}
}

View File

@ -0,0 +1,44 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <typeinfo>
#include <debug.h>
namespace std
{
type_info::~type_info() {}
bool type_info::__do_catch(const type_info *ThrowType,
void **ThrowObject,
unsigned Outer) const
{
stub;
UNUSED(ThrowType);
UNUSED(ThrowObject);
UNUSED(Outer);
return false;
}
bool type_info::__do_upcast(const __cxxabiv1::__class_type_info *Target,
void **ObjectPointer) const
{
stub;
UNUSED(Target);
UNUSED(ObjectPointer);
return false;
}
}

47
Kernel/library/targp.c Normal file
View File

@ -0,0 +1,47 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <targp.h>
#include <memory.hpp>
#include <convert.h>
void targp_parse(const char *cmd, char **argv, int *argc)
{
const char delim[] = " ";
char *token = strtok((char *)cmd, delim);
while (token != NULL)
{
char *quote = strchr(token, '"');
if (quote != NULL)
{
memmove(quote, quote + 1, strlen(quote));
char *endQuote = strchr(quote, '"');
if (endQuote != NULL)
*endQuote = '\0';
}
char *arg = (char *)kmalloc(strlen(token) + 1);
strcpy(arg, token);
argv[(*argc)++] = arg;
token = strtok(NULL, delim);
}
argv[(*argc)] = NULL;
}