feat: initial booting kernel, copy libc stuff from myke

This commit is contained in:
2023-03-22 21:02:22 +01:00
parent 591b6d61c5
commit 61fb439d72
26 changed files with 791 additions and 220 deletions

87
.gitignore vendored
View File

@@ -1,93 +1,8 @@
# Created by https://www.toptal.com/developers/gitignore/api/cmake,clion+all
# Edit at https://www.toptal.com/developers/gitignore?templates=cmake,clion+all
### CLion+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### CLion+all Patch ###
# Ignore everything but code style settings and run configurations
# that are supposed to be shared within teams.
.idea/*
!.idea/codeStyles
!.idea/runConfigurations
.idea/
### CMake ###
CMakeLists.txt.user

View File

@@ -1,5 +1,7 @@
project(yak)
cmake_minimum_required()
project(yak C ASM)
cmake_minimum_required(VERSION 3.24.0)
include(FetchContent)
add_subdirectory(yak-kernel)

View File

@@ -2,4 +2,4 @@
ISO=${1}
qemu-system-x86_64 -bios /usr/share/ovmf/x64/OVMF.fd -cdrom "${ISO}" #-S -s -d guest_errors
qemu-system-x86_64 -bios /usr/share/ovmf/x64/OVMF.fd -cdrom "${ISO}" -S -s -d guest_errors

View File

@@ -1,27 +1,57 @@
project(yak-kernel)
set(CMAKE_C_FLAGS "
-ffreestanding \
-fno-stack-protector \
-fno-stack-check \
-fno-lto \
-fno-pie \
-fno-pic \
-m64 \
-march=x86-64 \
-mabi=sysv \
-mno-80387 \
-mno-mmx \
-mno-sse \
-mno-sse2 \
-mno-red-zone \
-mcmodel=kernel")
set(CMAKE_EXE_LINKER_FLAGS "
-nostdlib \
-static \
-z max-page-size=0x1000 \
-T ${CMAKE_CURRENT_SOURCE_DIR}/linker.lds")
set(CMAKE_SYSROOT "/does-not-exist")
include_directories(../limine/include)
option(USE_LIMINE "Enable support for the limine boot protocol" ON)
add_executable(yak.elf main.c)
add_compile_options(
-ffreestanding
-fno-lto
-fno-pie
-fno-pic
-m64
--target=x86_64-pc-none-eabi
-mno-80387
-mno-mmx
-mno-sse
-mno-sse2
-mno-red-zone
-mcmodel=kernel
)
add_link_options(
-nostdlib
-static
-z max-page-size=0x1000
-T ${CMAKE_CURRENT_SOURCE_DIR}/linker.lds
)
FetchContent_Declare(printf_library
GIT_REPOSITORY https://github.com/eyalroz/printf.git
GIT_TAG v6.1.0)
FetchContent_GetProperties(printf_library)
if (NOT printf_library_POPULATED)
FetchContent_Populate(printf_library)
endif ()
if (NOT ${USE_LIMINE})
message(FATAL_ERROR "At least one boot protocol is required")
endif ()
file(GLOB KERNEL_SOURCES src/rt/*.c src/ulibc/*.c)
file(GLOB PLATFORM_GENERIC_SOURCES src/platform/generic/*.c)
if (${USE_LIMINE})
file(GLOB LIMINE_KERNEL_SOURCES src/rt/limine/*.c)
endif ()
if (NOT IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/${CMAKE_SYSTEM_PROCESSOR})
message(FATAL_ERROR "Unknown architecture ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/${CMAKE_SYSTEM_PROCESSOR}")
endif ()
file(GLOB PLATFORM_SPECIFIC_SOURCES src/platform/x86_64/*.c)
set(KERNEL_SOURCE_FILES ${KERNEL_SOURCES} ${LIMINE_KERNEL_SOURCES} ${PLATFORM_GENERIC_SOURCES} ${PLATFORM_SPECIFIC_SOURCES})
add_executable(yak.elf ${KERNEL_SOURCE_FILES})
target_link_libraries(yak.elf PRIVATE /usr/lib/clang/15.0.7/lib/linux/libclang_rt.builtins-x86_64.a)
target_include_directories(yak.elf PRIVATE include ../limine/include ${printf_library_SOURCE_DIR}/src)# ${printf_library_SOURCE_DIR}/src)

View File

@@ -0,0 +1,45 @@
//
// Created by rick on 10-03-21.
//
#ifndef NEW_KERNEL_ERRNO_H
#define NEW_KERNEL_ERRNO_H
extern int errno;
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#endif //NEW_KERNEL_ERRNO_H

View File

@@ -0,0 +1,2 @@
#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT 1
#include <printf/printf.h>

View File

@@ -0,0 +1,37 @@
//
// Created by rick on 10-03-21.
//
#ifndef NEW_KERNEL_STDLIB_H
#define NEW_KERNEL_STDLIB_H
#include <stdint.h>
#include <stddef.h>
void __attribute__((__noreturn__)) abort();
int atexit(void (*)(void));
int atoi(const char *);
char *itoa(uint32_t value, char *buffer, int base);
char *getenv(const char *);
int abs(int val);
long labs(long val);
long long llabs(long long val);
void qsort(void *base, size_t num, size_t size, int (*compar)(const void *, const void *));
long strtol(const char *nptr, char **endptr, int base);
void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
void *reallocarray(void *ptr, size_t nmemb, size_t size);
#endif //NEW_KERNEL_STDLIB_H

View File

@@ -0,0 +1,40 @@
//
// Created by rick on 01-02-21.
//
#ifndef NEW_KERNEL_STRING_H
#define NEW_KERNEL_STRING_H
#include <stddef.h>
void *memcpy(void *dst, const void *src, size_t amount);
void *memset(void *dst, int data, size_t amount);
void *memmove(void *dst, const void *src, size_t amount);
void *strcpy(char *dst, const char *src);
void *strncpy(char *dst, const char *src, size_t n);
size_t strlen(const char *str);
char *strchr(const char *s, char c);
char *strrchr(const char *s, char c);
int memcmp(const void *s1, const void *s2, size_t n);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
char *strdup(const char *s);
char *strndup(const char *s, size_t n);
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);
#endif //NEW_KERNEL_STRING_H

View File

@@ -0,0 +1,11 @@
//
// Created by rick on 10-03-21.
//
#ifndef NEW_KERNEL_PARAM_H
#define NEW_KERNEL_PARAM_H
#define MIN(a, b) (((a)<(b))?(a):(b))
#define MAX(a, b) (((a)>(b))?(a):(b))
#endif //NEW_KERNEL_PARAM_H

View File

@@ -0,0 +1,16 @@
/*
* types.h
*
* Created on: Nov 1, 2018
* Author: rick
*/
#ifndef KERNEL_LIBC_TYPES_H_
#define KERNEL_LIBC_TYPES_H_
#include <stdint.h>
#include <stddef.h>
typedef int pid_t;
#endif /* KERNEL_LIBC_TYPES_H_ */

View File

@@ -0,0 +1,12 @@
//
// Created by rick on 22-3-23.
//
#ifndef YAK_PLATFORM_H
#define YAK_PLATFORM_H
void platform_init();
void __attribute__((noreturn)) halt_forever();
#endif //YAK_PLATFORM_H

View File

@@ -0,0 +1,10 @@
//
// Created by rick on 22-3-23.
//
#ifndef YAK_KMAIN_H
#define YAK_KMAIN_H
void kmain();
#endif //YAK_KMAIN_H

View File

@@ -0,0 +1,18 @@
//
// Created by rick on 21-3-23.
//
#ifndef YAK_KPRINT_H
#define YAK_KPRINT_H
typedef void (*print_function)(char c);
void kprint_now(char* msg);
void kprint_putc_now(char c);
void kprint_register(print_function print);
void kprint_unregister(print_function print);
#endif //YAK_KPRINT_H

View File

@@ -0,0 +1,10 @@
//
// Created by rick on 21-3-23.
//
#ifndef YAK_PANIC_H
#define YAK_PANIC_H
void __attribute__((__noreturn__)) panic(char* reason);
#endif //YAK_PANIC_H

View File

@@ -3,7 +3,7 @@ OUTPUT_FORMAT(elf64-x86-64)
OUTPUT_ARCH(i386:x86-64)
/* We want the symbol _start to be our entry point */
ENTRY(_start)
ENTRY(kmain)
/* Define the program headers we want so the bootloader gives us the right */
/* MMU permissions */
@@ -40,6 +40,10 @@ SECTIONS
*(.data .data.*)
} :data
.limine_reqs : {
*(.limine_reqs)
} :data
/* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */
/* unnecessary zeros will be written to the binary. */
/* If you need, for example, .init_array and .fini_array, those should be placed */

View File

@@ -1,107 +0,0 @@
#include <stdint.h>
#include <stddef.h>
#include <limine.h>
// The Limine requests can be placed anywhere, but it is important that
// the compiler does not optimise them away, so, usually, they should
// be made volatile or equivalent.
static volatile struct limine_terminal_request terminal_request = {
.id = LIMINE_TERMINAL_REQUEST,
.revision = 0
};
// GCC and Clang reserve the right to generate calls to the following
// 4 functions even if they are not directly called.
// Implement them as the C specification mandates.
// DO NOT remove or rename these functions, or stuff will eventually break!
// They CAN be moved to a different .c file.
void *memcpy(void *dest, const void *src, size_t n) {
uint8_t *pdest = (uint8_t *) dest;
const uint8_t *psrc = (const uint8_t *) src;
for (size_t i = 0; i < n; i++) {
pdest[i] = psrc[i];
}
return dest;
}
void *memset(void *s, int c, size_t n) {
uint8_t *p = (uint8_t *) s;
for (size_t i = 0; i < n; i++) {
p[i] = (uint8_t) c;
}
return s;
}
void *memmove(void *dest, const void *src, size_t n) {
uint8_t *pdest = (uint8_t *) dest;
const uint8_t *psrc = (const uint8_t *) src;
if (src > dest) {
for (size_t i = 0; i < n; i++) {
pdest[i] = psrc[i];
}
} else if (src < dest) {
for (size_t i = n; i > 0; i--) {
pdest[i - 1] = psrc[i - 1];
}
}
return dest;
}
int memcmp(const void *s1, const void *s2, size_t n) {
const uint8_t *p1 = (const uint8_t *) s1;
const uint8_t *p2 = (const uint8_t *) s2;
for (size_t i = 0; i < n; i++) {
if (p1[i] != p2[i]) {
return p1[i] < p2[i] ? -1 : 1;
}
}
return 0;
}
// Our quick and dirty strlen() implementation.
size_t strlen(const char *str) {
size_t ret = 0;
while (*str++) {
ret++;
}
return ret;
}
// Halt and catch fire function.
static void hcf(void) {
__asm__ ("cli");
for (;;) {
__asm__ ("hlt");
}
}
// The following will be our kernel's entry point.
// If renaming _start() to something else, make sure to change the
// linker script accordingly.
void _start(void) {
// Ensure we got a terminal
if (terminal_request.response == NULL
|| terminal_request.response->terminal_count < 1) {
hcf();
}
// We should now be able to call the Limine terminal to print out
// a simple "Hello World" to screen.
const char *hello_msg = "Hello World";
struct limine_terminal *terminal = terminal_request.response->terminals[0];
terminal_request.response->write(terminal, hello_msg, strlen(hello_msg));
// We're done, just hang...
hcf();
}

View File

@@ -0,0 +1,14 @@
//
// Created by rick on 22-3-23.
//
#include <stdio.h>
#include <yak/platform/generic/platform.h>
void platform_init() {
printf("Init X86_64");
}
void __attribute__((noreturn)) halt_forever() {
__asm__("cli");
while (1) __asm__("hlt");
}

13
yak-kernel/src/rt/kmain.c Normal file
View File

@@ -0,0 +1,13 @@
#include <yak/rt/kmain.h>
#include <yak/rt/panic.h>
#include "yak/platform/generic/platform.h"
void kmain() {
// kmain is called from one of the bootloader implementations
// perform platform specific initialisation
platform_init();
// this should (eventually) be unreachable
panic("End of kmain");
}

View File

@@ -0,0 +1,44 @@
//
// Created by rick on 21-3-23.
//
#include <yak/rt/kprint.h>
#include <stddef.h>
#define MAX_PRINT_FUNCTIONS 8
print_function print_functions[MAX_PRINT_FUNCTIONS] = {0};
void kprint_now(char* msg) {
char* m = msg;
while (*m != 0) {
kprint_putc_now(*m);
m++;
}
}
void kprint_putc_now(char c) {
for (int i = 0; i < MAX_PRINT_FUNCTIONS; ++i) {
if (print_functions[i] != NULL) {
print_functions[i](c);
}
}
}
void kprint_register(print_function print) {
for (int i = 0; i < MAX_PRINT_FUNCTIONS; ++i) {
if (print_functions[i] == NULL) {
print_functions[i] = print;
break;
}
}
}
void kprint_unregister(print_function print) {
for (int i = 0; i < MAX_PRINT_FUNCTIONS; ++i) {
if (print_functions[i] == print) {
print_functions[i] = NULL;
break;
}
}
}

View File

@@ -0,0 +1,114 @@
//
// Created by rick on 21-3-23.
//
#include <stddef.h>
#include <stdio.h>
#include <limine.h>
#include <yak/rt/kprint.h>
#include <yak/rt/kmain.h>
static struct limine_bootloader_info_request limine_bootloader_info_request = {
.id = LIMINE_BOOTLOADER_INFO_REQUEST,
.revision = 0,
};
static struct limine_framebuffer_request limine_framebuffer_request = {
.id = LIMINE_FRAMEBUFFER_REQUEST,
.revision = 0,
};
static struct limine_terminal_request limine_terminal_request = {
.id = LIMINE_TERMINAL_REQUEST,
.revision = 0
};
// unused: 5 level paging
// unused: SMP
struct limine_memmap_request limine_memmap_request = {
.id = LIMINE_MEMMAP_REQUEST,
.revision = 0,
};
void limine_init();
struct limine_entry_point_request limine_entry_point_request = {
.id = LIMINE_ENTRY_POINT_REQUEST,
.revision = 0,
.entry = limine_init,
};
struct limine_kernel_file_request limine_kernel_file_request = {
.id = LIMINE_KERNEL_FILE_REQUEST,
.revision = 0,
};
struct limine_module_request limine_module_request = {
.id = LIMINE_MODULE_REQUEST,
.revision = 0,
};
struct limine_rsdp_request limine_rsdp_request = {
.id = LIMINE_RSDP_REQUEST,
.revision = 0,
};
struct limine_smbios_request limine_smbios_request = {
.id = LIMINE_SMBIOS_REQUEST,
.revision = 0,
};
struct limine_efi_system_table_request limine_efi_system_table_request = {
.id = LIMINE_EFI_SYSTEM_TABLE_REQUEST,
.revision = 0,
};
struct limine_boot_time_request limine_boot_time_request = {
.id = LIMINE_BOOT_TIME_REQUEST,
.revision = 0,
};
struct limine_kernel_address_request limine_kernel_address_request = {
.id = LIMINE_KERNEL_ADDRESS_REQUEST,
.revision = 0,
};
struct limine_dtb_request limine_dtb_request = {
.id = LIMINE_DTB_REQUEST,
.revision = 0,
};
static volatile __attribute__((used, section(".limine_reqs"))) void* limine_requests[] = {
&limine_bootloader_info_request,
&limine_framebuffer_request,
&limine_terminal_request,
&limine_memmap_request,
&limine_entry_point_request,
&limine_kernel_file_request,
&limine_module_request,
&limine_rsdp_request,
&limine_smbios_request,
&limine_efi_system_table_request,
&limine_boot_time_request,
&limine_kernel_address_request,
&limine_dtb_request,
NULL,
};
void limine_terminal_kprint(char c) {
limine_terminal_request.response->write(limine_terminal_request.response->terminals[0], &c, 1);
}
void limine_init() {
if (limine_terminal_request.response != NULL && limine_terminal_request.response->terminal_count >= 1) {
kprint_register(limine_terminal_kprint);
}
if (limine_bootloader_info_request.response != NULL) {
printf("Booted using limine from %s %s\n", limine_bootloader_info_request.response->name, limine_bootloader_info_request.response->version);
} else {
printf("Booted using limine from an unknown bootloader\n");
}
kmain();
}

15
yak-kernel/src/rt/panic.c Normal file
View File

@@ -0,0 +1,15 @@
//
// Created by rick on 21-3-23.
//
#include <yak/rt/panic.h>
#include "yak/rt/kprint.h"
#include "yak/platform/generic/platform.h"
void __attribute__((__noreturn__)) panic(char *reason) {
kprint_now(reason);
// todo stack trace
halt_forever();
}

View File

@@ -0,0 +1,21 @@
//
// Created by rick on 21-3-23.
//
#include <stdint.h>
#include <yak/rt/panic.h>
#if UINT32_MAX == UINTPTR_MAX
#define STACK_CHK_GUARD 0xe2dee396
#else
#define STACK_CHK_GUARD 0x595e9fbd94fda766
#endif
// todo this value should be unique every time the kernel starts
uintptr_t __stack_chk_guard = STACK_CHK_GUARD;
void __attribute__((__noreturn__)) __stack_chk_fail() {
panic("Stack Smashed");
}

View File

@@ -0,0 +1,10 @@
//
// Created by rick on 21-3-23.
//
#include <yak/rt/kprint.h>
void putchar_(char c) {
kprint_putc_now(c);
}
#include <printf/printf.c>

View File

@@ -0,0 +1,131 @@
/*
* libc.c
*
* Created on: Oct 11, 2018
* Author: rick
*/
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
/* everything of stdlib is implemented in this file except for:
* - qsort
**/
int abs(int val) {
return val >= 0 ? val : (val * -1);
}
long labs(long val) {
return val >= 0 ? val : (val * -1);
}
long long llabs(long long val) {
return val >= 0 ? val : (val * -1);
}
// next stolen form https://www.techiedelight.com/implement-itoa-function-in-c/
// inline function to swapc two numbers
void swapc(char *x, char *y) {
char t = *x;
*x = *y;
*y = t;
}
// function to reverse buffer[i..j]
char *reverse(char *buffer, int i, int j) {
while (i < j)
swapc(&buffer[i++], &buffer[j--]);
return buffer;
}
// Iterative function to implement itoa() function in C
char *itoa(uint32_t value, char *buffer, int base) {
// invalid input
if (base < 2 || base > 32)
return buffer;
int i = 0;
while (value) {
uint32_t r = value % base;
if (r >= 10)
buffer[i++] = 65 + (r - 10);
else
buffer[i++] = 48 + r;
value = value / base;
}
// if number is 0
if (i == 0)
buffer[i++] = '0';
// If base is 10 and value is negative, the resulting string
// is preceded with a minus sign (-)
// With any other base, value is always considered unsigned
if (value < 0 && base == 10)
buffer[i++] = '-';
buffer[i] = '\0'; // null terminate string
// reverse the string and return it
return reverse(buffer, 0, i - 1);
}
long strtol(const char *nptr, char **endptr, int base) {
if (base > 36) {
errno = EINVAL;
return -1;
}
char sign = '+';
long n = 0;
long i;
const char *c = nptr;
while (*c == ' ') {
c++;
}
if (*c == '+') {
c++;
} else if (*c == '-') {
sign = '-';
c++;
}
while (*c != '\0') {
n *= base;
if (*c >= '0' && *c <= '9') {
i = *c - '0';
} else if (*c >= 'a' && *c <= 'z') {
i = *c - 'a' + 10;
} else if (*c >= 'A' && *c <= 'Z') {
i = *c - 'A' + 10;
} else {
errno = EINVAL;
n = -1;
goto _set_endptr;
}
if (i >= base) {
errno = EINVAL;
n = -1;
goto _set_endptr;
}
if (i > (LONG_MAX - n)) {
errno = ERANGE;
n = sign == '-' ? LONG_MIN : LONG_MAX;
goto _set_endptr;
}
n += i;
c++;
}
if (sign == '-') {
n *= -1;
}
_set_endptr:
if (endptr != NULL) {
*endptr = c;
}
return n;
}

View File

@@ -0,0 +1,147 @@
//
// Created by rick on 01-02-21.
//
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/param.h>
void *memcpy(void *dst, const void *src, size_t amount) {
for (size_t i = 0; i < amount; i++) {
((char *) dst)[i] = ((const char *) src)[i];
}
return dst;
}
void *memset(void *dst, int data, size_t amount) {
for (size_t i = 0; i < amount; ++i) {
((char *) dst)[i] = (char) data;
}
return dst;
}
void *memmove(void *dst, const void *src, size_t amount) {
void *tmp = malloc(amount);
if (tmp == NULL) {
return NULL;
}
memcpy(dst, memcpy(tmp, src, amount), amount);
free(tmp);
return dst;
}
void *strcpy(char *dst, const char *src) {
return memcpy(dst, src, strlen(src) + 1);
}
void *strncpy(char *dst, const char *src, size_t n) {
return memcpy(dst, src, MIN(strlen(src), n) + 1);
}
size_t strlen(const char *str) {
int length = 0;
while (str[length] != 0) {
length++;
}
return length;
}
int strcmp(const char *s1, const char *s2) {
size_t len1 = strlen(s1);
size_t len2 = strlen(s2);
return strncmp(s1, s2, MAX(len1, len2));
}
char *strchr(const char *s, char c) {
size_t index = 0;
while (1) {
if (s[index] == c) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
return &s[index];
#pragma clang diagnostic pop
}
if (s[index] == 0) {
return NULL;
}
index++;
}
}
char *strrchr(const char *s, char c) {
size_t index = strlen(s);
while (1) {
if (s[index] == c) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
return &s[index];
#pragma clang diagnostic pop
}
if (index == 0) {
return NULL;
}
index--;
}
}
int memcmp(const void *s1, const void *s2, size_t n) {
uint8_t a, b;
for (size_t i = 0; i < n; ++i) {
a = ((uint8_t *) s1)[i];
b = ((uint8_t *) s2)[i];
if (a > b) return 1;
if (a < b) return -1;
}
return 0;
}
int strncmp(const char *s1, const char *s2, size_t n) {
for (size_t i = 0; i < n; ++i) {
if (s1[i] == 0 && s2[i] == 0) {
return 0;
}
if (s1[i] == 0) {
return -1;
}
if (s2[i] == 0) {
return 1;
}
if (s1[i] > s2[i]) {
return -1;
}
if (s1[i] < s2[i]) {
return 1;
}
}
return 0;
}
char *strcat(char *dest, const char *src) {
size_t count = strlen(src);
return strncat(dest, src, count);
}
char *strncat(char *dest, const char *src, size_t n) {
size_t start = strlen(dest);
for (size_t index = 0; index < n; index++) {
char val = src[index];
dest[start + index] = val;
if (val == 0) {
dest[start + index] = 0;
break;
}
}
return dest;
}
char *strdup(const char *s) {
return strndup(s, strlen(s));
}
char *strndup(const char *s, size_t n) {
char *new = malloc(n + 1);
memcpy(new, s, n);
new[n] = 0;
return new;
}

View File

@@ -0,0 +1,17 @@
//
// Created by rick on 21-3-23.
//
// TODO temporary to get compiling
#include <stdlib.h>
#include <yak/rt/panic.h>
void* malloc(size_t size) {
panic("Not Yet Implemented");
}
void free(void* ptr) {
panic("Not Yet Implemented");
}
int errno = 0;