feat: implemented errno, strtol. Started ustar. Reformatted headers and
code. Added some self-tests. Started prepwork for vfs.
This commit is contained in:
@@ -11,14 +11,20 @@
|
||||
#include <myke/mem/mem.h>
|
||||
#include <myke/mem/malloc.h>
|
||||
#include <myke/cpu/timer.h>
|
||||
#include <myke/drivers/pci.h>
|
||||
#include <myke/drivers/ide.h>
|
||||
#include <myke/drivers/pci/pci.h>
|
||||
#include <myke/drivers/pci/ide.h>
|
||||
#include <myke/fs/blockdev.h>
|
||||
#include <myke/fs/mbr.h>
|
||||
#include <readline/readline.h>
|
||||
#include <myke/attributes.h>
|
||||
#include <myke/util/power.h>
|
||||
|
||||
#ifdef ENABLE_SELF_TEST
|
||||
|
||||
#include <myke/debug/debug.h>
|
||||
|
||||
#endif
|
||||
|
||||
#define BOOTLOADER_NAME_MAX_LENGTH 64
|
||||
#define CMDLINE_MAX_LENGTH 256
|
||||
|
||||
@@ -44,16 +50,29 @@ void shutdown(const char *args);
|
||||
|
||||
void explode(const char *args);
|
||||
|
||||
#ifdef ENABLE_SELF_TEST
|
||||
|
||||
void exec_self_test(const char *args);
|
||||
|
||||
#endif
|
||||
|
||||
cmd_handler cmd_handlers[] = {
|
||||
{"help\0", help},
|
||||
{"echo\0", echo},
|
||||
{"print\0", print},
|
||||
{"ide\0", ide},
|
||||
{"help", help},
|
||||
{"echo", echo},
|
||||
{"print", print},
|
||||
{"ide", ide},
|
||||
{"shutdown", shutdown},
|
||||
{"explode", explode},
|
||||
{"explode", explode},
|
||||
#ifdef ENABLE_SELF_TEST
|
||||
{"self-test", exec_self_test},
|
||||
#endif
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
void exec_self_test(const char *args) {
|
||||
self_test();
|
||||
}
|
||||
|
||||
|
||||
void explode(const char *args) {
|
||||
uint32_t x = 0;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#define DEBUG_INIT
|
||||
|
||||
#include <myke/debug/debug.h>
|
||||
#include <myke/elf.h>
|
||||
#include <elf.h>
|
||||
#include <myke/libk/libk.h>
|
||||
#include <myke/libk/kprint.h>
|
||||
|
||||
|
||||
152
kernel/debug/self_test.c
Normal file
152
kernel/debug/self_test.c
Normal file
@@ -0,0 +1,152 @@
|
||||
//
|
||||
// Created by rick on 13-03-21.
|
||||
//
|
||||
|
||||
#ifdef ENABLE_SELF_TEST
|
||||
|
||||
#include <myke/debug/debug.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <myke/libk/libk.h>
|
||||
#include <errno.h>
|
||||
|
||||
void assert_int(int expected, int actual) {
|
||||
if (expected != actual) {
|
||||
debug_backtrace(true);
|
||||
k_panics("Assertion failed, integers not equal\n");
|
||||
}
|
||||
}
|
||||
|
||||
void assert_long(long expected, long actual) {
|
||||
if (expected != actual) {
|
||||
debug_backtrace(true);
|
||||
k_panics("Assertion failed, integers not equal\n");
|
||||
}
|
||||
}
|
||||
|
||||
void assert_long_long(long long expected, long long actual) {
|
||||
if (expected != actual) {
|
||||
debug_backtrace(true);
|
||||
k_panics("Assertion failed, integers not equal\n");
|
||||
}
|
||||
}
|
||||
|
||||
void assert_ptr(const void *expected, const void *actual) {
|
||||
if (expected != actual) {
|
||||
debug_backtrace(true);
|
||||
k_panics("Assertion failed, integers not equal\n");
|
||||
}
|
||||
}
|
||||
|
||||
void assert_array_equal(const uint8_t *a, const uint8_t *b, size_t size) {
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
if (a[i] != b[i]) {
|
||||
debug_backtrace(true);
|
||||
k_panics("Assertion failed, arrays differ\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assert_array_all_entries(const uint8_t *a, uint8_t value, size_t size) {
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
if (a[i] != value) {
|
||||
debug_backtrace(true);
|
||||
k_panics("Assertion failed, arrays differ\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_string() {
|
||||
// test strncmp
|
||||
assert_int(0, strncmp("abc", "abc", 3));
|
||||
assert_int(1, strncmp("abcd", "abc", 4));
|
||||
assert_int(-1, strncmp("abc", "abcd", 4));
|
||||
|
||||
// test strcmp
|
||||
assert_int(0, strcmp("abc", "abc"));
|
||||
assert_int(1, strcmp("abc", "abd"));
|
||||
assert_int(-1, strcmp("abc", "abb"));
|
||||
assert_int(-1, strcmp("abc", "abcd"));
|
||||
assert_int(1, strcmp("abcd", "abc"));
|
||||
|
||||
uint8_t array_a[8] = {0};
|
||||
uint8_t array_b[16] = {0};
|
||||
// memset
|
||||
assert_array_all_entries(array_b, 0, 16);
|
||||
memset(array_b, 1, 8);
|
||||
assert_array_all_entries(array_b, 1, 8);
|
||||
assert_array_all_entries(array_b + 8, 0, 8);
|
||||
memset(array_b, 1, 16);
|
||||
assert_array_all_entries(array_b, 1, 16);
|
||||
|
||||
// memcpy
|
||||
memcpy(array_b, array_a, 8);
|
||||
assert_array_all_entries(array_b, 0, 8);
|
||||
assert_array_all_entries(array_b + 8, 1, 8);
|
||||
memcpy(array_b + 8, array_a, 8);
|
||||
assert_array_all_entries(array_b + 8, 0, 16);
|
||||
|
||||
// strlen
|
||||
assert_int(3, strlen("abc"));
|
||||
assert_int(4, strlen("abcd"));
|
||||
assert_int(5, strlen("abcde"));
|
||||
assert_int(0, strlen(""));
|
||||
|
||||
// strchr
|
||||
const char *strchr_test = "abcdef";
|
||||
assert_ptr(&strchr_test[3], strchr(strchr_test, 'd'));
|
||||
assert_ptr(NULL, strchr(strchr_test, '9'));
|
||||
|
||||
// strcpy
|
||||
const char *strcpy_src_test = "abc\0def";
|
||||
char *strcpy_dst_test = "\0\0\0\0\0\0\0";
|
||||
const char *strcpy_expected_test = "abc\0\0\0\0";
|
||||
assert_int(0, strcpy(strcpy_dst_test, strcpy_src_test));
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wpointer-sign"
|
||||
assert_array_equal(strcpy_dst_test, strcpy_expected_test, 8);
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
void test_stdlib() {
|
||||
// abs
|
||||
assert_int(1, abs(1));
|
||||
assert_int(1, abs(-1));
|
||||
assert_int(0, abs(0));
|
||||
assert_int(0, abs(-0));
|
||||
|
||||
// labs
|
||||
assert_long(1l, labs(1l));
|
||||
assert_long(1l, labs(-1l));
|
||||
assert_long(0l, labs(0l));
|
||||
assert_long(0l, labs(-0l));
|
||||
|
||||
// llabs
|
||||
assert_long_long(1ll, llabs(1ll));
|
||||
assert_long_long(1ll, llabs(-1ll));
|
||||
assert_long_long(0ll, llabs(0ll));
|
||||
assert_long_long(0ll, llabs(-0ll));
|
||||
|
||||
assert_long(10, strtol("10", NULL, 10));
|
||||
assert_long(-10, strtol("-10", NULL, 10));
|
||||
assert_long(16, strtol("10", NULL, 16));
|
||||
assert_long(-16, strtol("-10", NULL, 16));
|
||||
assert_long(8, strtol("10", NULL, 8));
|
||||
assert_long(-8, strtol("-10", NULL, 8));
|
||||
assert_long(8, strtol("010", NULL, 8));
|
||||
assert_long(-8, strtol("-010", NULL, 8));
|
||||
assert_long(200, strtol("5K", NULL, 36));
|
||||
assert_long(-200, strtol("-5K", NULL, 36));
|
||||
assert_long(-200, strtol("-5k", NULL, 36));
|
||||
|
||||
errno = 0;
|
||||
assert_long(-1, strtol("A", NULL, 10));
|
||||
assert_int(errno, EINVAL);
|
||||
}
|
||||
|
||||
void self_test() {
|
||||
test_string();
|
||||
test_stdlib();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -8,11 +8,11 @@
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <myke/drivers/ide.h>
|
||||
#include <myke/drivers/pci/ide.h>
|
||||
#include <myke/debug/debug.h>
|
||||
#include <myke/drivers/ports.h>
|
||||
#include <myke/libk/kprint.h>
|
||||
#include <myke/drivers/pci.h>
|
||||
#include <myke/drivers/pci/pci.h>
|
||||
#include <myke/libk/libk.h>
|
||||
#include <myke/cpu/timer.h>
|
||||
#include <myke/fs/blockdev.h>
|
||||
@@ -377,7 +377,7 @@ bool ide_pci_init_channels(pci_device *device) {
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ide_block_dev_access(const block_device *device, uint8_t direction, uint32_t lba, uint8_t sectors, void *target) {
|
||||
ide_block_dev_access(const block_device_t *device, uint8_t direction, uint32_t lba, uint8_t sectors, void *target) {
|
||||
ide_block_device_info *info = device->device_info;
|
||||
uint8_t result = ide_access(direction, info->device_number, lba, sectors, target);
|
||||
if (result != 0) {
|
||||
@@ -399,7 +399,7 @@ void ide_register_block_devices() {
|
||||
info->device_number = i;
|
||||
info->print_error = 1;
|
||||
|
||||
block_device device = {
|
||||
block_device_t device = {
|
||||
.flags.present = 1,
|
||||
.flags.root_device = 1,
|
||||
.device_info = info,
|
||||
@@ -6,13 +6,13 @@
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <myke/drivers/pci.h>
|
||||
#include <myke/drivers/pci/pci.h>
|
||||
#include <myke/drivers/ports.h>
|
||||
#include <myke/libk/libk.h>
|
||||
|
||||
#ifdef ENABLE_PCIPP
|
||||
|
||||
#include <myke/drivers/pci_devices.h>
|
||||
#include <myke/drivers/pci/pci_devices.h>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#define MAX_BLOCK_DEVS 64
|
||||
|
||||
int last_block_dev = 0;
|
||||
block_device block_devices[MAX_BLOCK_DEVS] = {0};
|
||||
block_device_t block_devices[MAX_BLOCK_DEVS] = {0};
|
||||
|
||||
extern struct block_dev_driver __start_block_dev_driver[];
|
||||
extern struct block_dev_driver __stop_block_dev_driver[];
|
||||
@@ -25,12 +25,12 @@ extern struct block_dev_driver __stop_block_dev_driver[];
|
||||
semaphore_t *block_semaphore;
|
||||
bool blockdev_task_running = false;
|
||||
|
||||
uint8_t block_dev_register(block_device *device) {
|
||||
uint8_t block_dev_register(block_device_t *device) {
|
||||
if (last_block_dev >= MAX_BLOCK_DEVS - 1) {
|
||||
return BLOCK_DEV_REGISTER_FULL;
|
||||
}
|
||||
|
||||
memcpy((uint8_t *) &block_devices[last_block_dev++], (const uint8_t *) device, sizeof(block_device));
|
||||
memcpy((uint8_t *) &block_devices[last_block_dev++], (const uint8_t *) device, sizeof(block_device_t));
|
||||
|
||||
if (blockdev_task_running) {
|
||||
semaphore_signal(block_semaphore);
|
||||
@@ -38,7 +38,7 @@ uint8_t block_dev_register(block_device *device) {
|
||||
return BLOCK_DEV_REGISTER_OK;
|
||||
}
|
||||
|
||||
void block_dev_free(block_device *device) {
|
||||
void block_dev_free(block_device_t *device) {
|
||||
//todo
|
||||
k_panics("block dev free not supported");
|
||||
}
|
||||
@@ -51,6 +51,43 @@ int block_dev_num_not_scanned() {
|
||||
return not_scanned;
|
||||
}
|
||||
|
||||
bool block_dev_mount(char *identifier, char *driver_name) {
|
||||
bool result = true;
|
||||
block_device_t *device = NULL;
|
||||
for (int i = 0; i < last_block_dev; ++i) {
|
||||
if (strncmp(block_devices[i].identifier, identifier, 16) == 0) {
|
||||
device = &block_devices[i];
|
||||
}
|
||||
}
|
||||
if (identifier == NULL) {
|
||||
result = false;
|
||||
goto _end;
|
||||
}
|
||||
struct block_dev_driver *driver = NULL;
|
||||
for (size_t j = 0; j < NUM_DRIVERS; ++j) {
|
||||
if (strncmp(DRIVER(j)->name, driver_name, 16) == 0) {
|
||||
driver = DRIVER(j);
|
||||
}
|
||||
}
|
||||
if (driver == NULL) {
|
||||
result = false;
|
||||
goto _end;
|
||||
}
|
||||
uint8_t *lba0 = malloc(device->block_size);
|
||||
uint8_t read_result = device->access(device, BLOCK_DEV_DIRECTION_READ, 0, 1, lba0);
|
||||
if (read_result != BLOCK_DEV_ACCESS_OK) {
|
||||
result = false;
|
||||
goto _access_fail;
|
||||
}
|
||||
if (driver->check_device(device, lba0) != BLOCK_DEV_DRIVER_CHECK_OK) {
|
||||
result = false;
|
||||
}
|
||||
_access_fail:
|
||||
free(lba0);
|
||||
_end:
|
||||
return result;
|
||||
}
|
||||
|
||||
void block_dev_scan() {
|
||||
int c_last_block_dev = last_block_dev;
|
||||
for (int i = 0; i < c_last_block_dev; ++i) {
|
||||
@@ -62,9 +99,14 @@ void block_dev_scan() {
|
||||
goto _block_dev_scan_free;
|
||||
}
|
||||
for (size_t j = 0; j < NUM_DRIVERS; ++j) {
|
||||
// validate if driver is appropriate at all
|
||||
// don't use a root device driver (i.e. mbr) for a non-root device
|
||||
if (DRIVER(j)->flags.root_only && !block_devices[i].flags.root_device) continue;
|
||||
// only partitioning drivers are automatically assigned
|
||||
if (!DRIVER(i)->flags.partitioning) {
|
||||
continue;
|
||||
}
|
||||
// only root devices have partitions
|
||||
if (!block_devices[i].flags.root_device) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// let the driver test the disk
|
||||
uint8_t driver_result = DRIVER(j)->check_device(&block_devices[i], lba0);
|
||||
|
||||
@@ -107,7 +107,7 @@ void print_chars(char *chars, int amount) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t used fat_check_device(const block_device *device, uint8_t *first_sector) {
|
||||
uint8_t used fat_check_device(const block_device_t *device, uint8_t *first_sector) {
|
||||
fat_bpb bpb;
|
||||
memcpy((uint8_t *) &bpb, first_sector, sizeof(fat_bpb));
|
||||
if (bpb.bpb.sectors_per_fat == 0 || bpb.bpb.sectors_per_cluster == 0) {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <myke/fs/mbr.h>
|
||||
#include <myke/drivers/ide.h>
|
||||
#include <myke/drivers/pci/ide.h>
|
||||
#include <myke/fs/blockdev.h>
|
||||
#include <myke/attributes.h>
|
||||
|
||||
@@ -33,12 +33,12 @@ typedef struct {
|
||||
} packed mbr_table;
|
||||
|
||||
typedef struct {
|
||||
const block_device *device;
|
||||
const block_device_t *device;
|
||||
uint32_t start_lba;
|
||||
} mbr_block_driver_info;
|
||||
|
||||
uint8_t
|
||||
mbr_block_dev_access(const block_device *device, uint8_t direction, uint32_t lba, uint8_t sectors, void *target) {
|
||||
mbr_block_dev_access(const block_device_t *device, uint8_t direction, uint32_t lba, uint8_t sectors, void *target) {
|
||||
if (!device->flags.present || lba > device->num_lba) {
|
||||
return BLOCK_DEV_ACCESS_ERR;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ mbr_block_dev_access(const block_device *device, uint8_t direction, uint32_t lba
|
||||
return info->device->access(info->device, direction, actual_lba, sectors, target);
|
||||
}
|
||||
|
||||
uint8_t used mbr_check_device(const block_device *device, uint8_t *first_sector) {
|
||||
uint8_t used mbr_check_device(const block_device_t *device, uint8_t *first_sector) {
|
||||
mbr_table table;
|
||||
memcpy((uint8_t *) &table, first_sector + (device->block_size - sizeof(mbr_table)), sizeof(mbr_table));
|
||||
if (table.signature[0] != 0x55 && table.signature[1] != 0xAA) { // AA 55 but in little endian
|
||||
@@ -69,14 +69,16 @@ uint8_t used mbr_check_device(const block_device *device, uint8_t *first_sector)
|
||||
}
|
||||
}
|
||||
|
||||
int num_parts = 0;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (table.entries[i].system_id == 0) continue;
|
||||
num_parts += 1;
|
||||
|
||||
mbr_block_driver_info *info = malloc(sizeof(mbr_block_driver_info));
|
||||
info->device = device;
|
||||
info->start_lba = table.entries[i].start_lba;
|
||||
|
||||
block_device logical_device = {
|
||||
block_device_t logical_device = {
|
||||
.flags.present = 1,
|
||||
|
||||
.num_lba = table.entries[i].num_lbas,
|
||||
@@ -88,7 +90,10 @@ uint8_t used mbr_check_device(const block_device *device, uint8_t *first_sector)
|
||||
sprintf(logical_device.identifier, "%sp%d", device->identifier, i);
|
||||
|
||||
block_dev_register(&logical_device);
|
||||
}
|
||||
|
||||
if (num_parts == 0) {
|
||||
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
||||
}
|
||||
|
||||
return BLOCK_DEV_DRIVER_CHECK_OK;
|
||||
@@ -104,7 +109,7 @@ void mbr_read_from_ide(uint8_t ide_drive) {
|
||||
|
||||
BLOCK_DEV_DRIVER(200) = {
|
||||
.name = "mbr",
|
||||
.flags.root_only = 1,
|
||||
.flags.partitioning = 1,
|
||||
.check_device = mbr_check_device,
|
||||
.free_device = NULL, // todo
|
||||
};
|
||||
|
||||
96
kernel/fs/ustar.c
Normal file
96
kernel/fs/ustar.c
Normal file
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// Created by rick on 11-03-21.
|
||||
//
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <myke/fs/blockdev.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
char filename[100];
|
||||
uint64_t mode;
|
||||
uint64_t uid;
|
||||
uint64_t gid;
|
||||
char filesize[12];
|
||||
char lastmod[12];
|
||||
uint64_t checksum;
|
||||
char type;
|
||||
char linked[100];
|
||||
char magic[6];
|
||||
char version[2];
|
||||
char username[32];
|
||||
char groupname[32];
|
||||
uint64_t device_major;
|
||||
uint64_t device_minor;
|
||||
char prefix[155];
|
||||
} packed ustar_sector;
|
||||
|
||||
typedef struct {
|
||||
ustar_sector sector;
|
||||
uint32_t lba;
|
||||
} ustar_inode;
|
||||
|
||||
typedef struct {
|
||||
ustar_inode *first_inode;
|
||||
const block_device_t *device;
|
||||
} ustar_fs;
|
||||
|
||||
const char *ustar_magic = "ustar";
|
||||
const char *ustar_version = "00";
|
||||
|
||||
#define USTAR_TYPE_FILE '0'
|
||||
#define USTAR_TYPE_LINK '1'
|
||||
#define USTAR_TYPE_SYMBOL '2'
|
||||
#define USTAR_TYPE_CHAR '3'
|
||||
#define USTAR_TYPE_BLOCK '4'
|
||||
#define USTAR_TYPE_DIR '5'
|
||||
#define USTAR_TYPE_FIFO '6'
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
|
||||
long ustar_oct_to_long(char *oct, uint32_t size) {
|
||||
char value[size + 1];
|
||||
memcpy(value, oct, size);
|
||||
value[size] = 0;
|
||||
return strtol(value, NULL, 8);
|
||||
}
|
||||
|
||||
bool ustar_sector_valid(ustar_sector *sector) {
|
||||
return strncmp(ustar_magic, sector->magic, 6) == 0;
|
||||
}
|
||||
|
||||
ustar_sector *ustar_next(ustar_sector *current) {
|
||||
if (ustar_sector_valid(current)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
long filesize = ustar_oct_to_long(current->filesize, 12);
|
||||
|
||||
long offset = (((filesize + SECTOR_SIZE - 1) / SECTOR_SIZE) + 1) * SECTOR_SIZE;
|
||||
|
||||
ustar_sector *next = ((void *) current) + offset;
|
||||
return ustar_sector_valid(next) ? next : NULL;
|
||||
}
|
||||
|
||||
uint8_t ustar_check_device(const block_device_t *device, uint8_t *first_sector) {
|
||||
ustar_sector *sector = (ustar_sector *) first_sector;
|
||||
if (!ustar_sector_valid(sector)) {
|
||||
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
||||
}
|
||||
|
||||
ustar_fs *fs = malloc(sizeof(ustar_fs));
|
||||
fs->first_inode = malloc(sizeof(ustar_inode));
|
||||
memcpy(&fs->first_inode->sector, first_sector, sizeof(ustar_sector));
|
||||
fs->first_inode->lba = 0;
|
||||
fs->device = device;
|
||||
|
||||
return BLOCK_DEV_DRIVER_CHECK_OK;
|
||||
}
|
||||
|
||||
BLOCK_DEV_DRIVER(300) = {
|
||||
.name = "ustar",
|
||||
.check_device = ustar_check_device,
|
||||
.free_device = NULL,
|
||||
};
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <myke/cpu/timer.h>
|
||||
#include <myke/debug/debug.h>
|
||||
#include <myke/drivers/keyboard.h>
|
||||
#include <myke/drivers/pci.h>
|
||||
#include <myke/drivers/pci/pci.h>
|
||||
#include <myke/drivers/serial.h>
|
||||
#include <myke/drivers/vgascreen.h>
|
||||
#include <myke/fs/blockdev.h>
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* everything of stdlib is implemented in this file except for:
|
||||
* - qsort
|
||||
@@ -76,3 +78,57 @@ char *itoa(int value, char *buffer, int base) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ int memset(void *dst, int data, size_t amount) {
|
||||
}
|
||||
|
||||
|
||||
int strcpy(char *dst, char *src) {
|
||||
int strcpy(char *dst, const char *src) {
|
||||
return memcpy(dst, src, strlen(src) + 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#define TASK_STATE_STOPPED (1 << 6)
|
||||
#define TASK_STATE_ERROR (1 << 7)
|
||||
|
||||
int errno = 0;
|
||||
|
||||
typedef struct task {
|
||||
bool present: 1;
|
||||
@@ -31,6 +32,8 @@ typedef struct task {
|
||||
|
||||
uint32_t tid;
|
||||
|
||||
int errno;
|
||||
|
||||
struct task *next;
|
||||
|
||||
void *stack;
|
||||
@@ -142,10 +145,14 @@ void task_switch_next_inner(task_t *next_task) {
|
||||
}
|
||||
task_t *previous_task = current_task;
|
||||
current_task = next_task;
|
||||
if (previous_task->state == TASK_STATE_RUNNING) {
|
||||
previous_task->state = TASK_STATE_RUNNABLE;
|
||||
if (previous_task != NULL) {
|
||||
previous_task->errno = errno;
|
||||
if (previous_task->state == TASK_STATE_RUNNING) {
|
||||
previous_task->state = TASK_STATE_RUNNABLE;
|
||||
}
|
||||
}
|
||||
current_task->state = TASK_STATE_RUNNING;
|
||||
errno = current_task->errno;
|
||||
// switch task
|
||||
switch_task(previous_task == NULL ? NULL : &previous_task->task_registers, current_task->task_registers);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user