Initial commit after splitting userspace from kernel tree
This commit is contained in:
commit
638edb5166
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
kernel-hdr
|
||||
build
|
96
Makefile
Normal file
96
Makefile
Normal file
@ -0,0 +1,96 @@
|
||||
O?=build
|
||||
STAGE=$(O)/stage
|
||||
KERNEL_HDRS?=kernel-hdr
|
||||
|
||||
CC=$(CROSS_COMPILE)gcc
|
||||
|
||||
DIRS=$(O) \
|
||||
$(O)/libc \
|
||||
$(STAGE)
|
||||
HDRS=$(shell find $(S) -type f -name "*.h")
|
||||
STAGE_BIN=$(STAGE)/init \
|
||||
$(STAGE)/bin/hexd \
|
||||
$(STAGE)/bin/ls \
|
||||
$(STAGE)/bin/reboot
|
||||
|
||||
CFLAGS=-ffreestanding \
|
||||
-nostdlib \
|
||||
-mno-sse \
|
||||
-mno-sse2 \
|
||||
-Ilibc/include \
|
||||
-ggdb \
|
||||
-O0 \
|
||||
-I$(KERNEL_HDRS)
|
||||
|
||||
usr_LDFLAGS=-nostdlib \
|
||||
-lgcc \
|
||||
-Tlibc/program.ld
|
||||
usr_STATIC_LIBS=$(O)/libc.a
|
||||
|
||||
libc_CRTI=$(O)/libc/crti.o
|
||||
libc_CRTN=$(O)/libc/crtn.o
|
||||
libc_OBJS=$(O)/libc/crt0.o \
|
||||
$(O)/libc/syscall.o \
|
||||
$(O)/libc/vsnprintf.o \
|
||||
$(O)/libc/printf.o \
|
||||
$(O)/libc/string.o \
|
||||
$(O)/libc/errno.o \
|
||||
$(O)/libc/stdio.o \
|
||||
$(O)/libc/init.o \
|
||||
$(O)/libc/malloc.o \
|
||||
$(O)/libc/dirent.o \
|
||||
$(O)/libc/signal.o \
|
||||
$(O)/libc/global.o \
|
||||
$(O)/libc/time.o
|
||||
|
||||
sys_CRTBEGIN=$(shell $(CC) $(CFLAGS) -print-file-name=crtbegin.o)
|
||||
sys_CRTEND=$(shell $(CC) $(CFLAGS) -print-file-name=crtend.o)
|
||||
|
||||
all: mkdirs $(O)/initrd.img
|
||||
|
||||
clean:
|
||||
rm -rf $(O)
|
||||
|
||||
$(O)/initrd.img: mkstage-etc $(STAGE_BIN)
|
||||
cd $(STAGE) && tar czf $(abspath $@) *
|
||||
|
||||
mkdirs:
|
||||
mkdir -p $(DIRS)
|
||||
|
||||
mkstage-etc:
|
||||
mkdir -p $(STAGE)/dev $(STAGE)/mnt $(STAGE)/bin
|
||||
cp -r etc $(STAGE)
|
||||
|
||||
# Application building
|
||||
$(STAGE)/init: init.c $(libc_CRTI) $(libc_CRTN) $(O)/libc.a
|
||||
@printf " CC\t%s\n" $(@:$(STAGE)/%=/%)
|
||||
@$(CC) -o $@ $(CFLAGS) $(usr_LDFLAGS) \
|
||||
$(libc_CRTI) \
|
||||
$(sys_CRTBEGIN) \
|
||||
init.c \
|
||||
$(sys_CRTEND) \
|
||||
$(libc_CRTN) \
|
||||
$(usr_STATIC_LIBS)
|
||||
|
||||
$(STAGE)/bin/%: core/bin/%.c $(libc_CRTI) $(libc_CRTN) $(O)/libc.a
|
||||
@printf " CC\t%s\n" $(@:$(STAGE)/%=/%)
|
||||
@$(CC) -o $@ $(CFLAGS) $(usr_LDFLAGS) \
|
||||
$(libc_CRTI) \
|
||||
$(sys_CRTBEGIN) \
|
||||
$< \
|
||||
$(sys_CRTEND) \
|
||||
$(libc_CRTN) \
|
||||
$(usr_STATIC_LIBS)
|
||||
|
||||
# libc building
|
||||
$(O)/libc.a: $(libc_OBJS)
|
||||
@printf " AR\t%s\n" $(@:$(O)/%=%)
|
||||
@$(AR) rcs $@ $(libc_OBJS)
|
||||
|
||||
$(O)/libc/%.o: libc/%.c $(HDRS)
|
||||
@printf " CC\t%s\n" $(@:$(O)/%=%)
|
||||
@$(CC) -c -o $@ $(CFLAGS) $<
|
||||
|
||||
$(O)/libc/%.o: libc/%.S
|
||||
@printf " AS\t%s\n" $(@:$(O)/%=%)
|
||||
@$(CC) -c -o $@ $(CFLAGS) $<
|
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
||||
Make a symlink to kernel headers (<kernel git tree>/include) directory named kernel-hdr or
|
||||
specify direct path using `KERNEL_HDRS` env variable, specify proper ``CROSS_COMPILE` and run
|
||||
make
|
95
core/bin/hexd.c
Normal file
95
core/bin/hexd.c
Normal file
@ -0,0 +1,95 @@
|
||||
#include <sys/fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define LINE_LENGTH 16
|
||||
|
||||
static void line_print(size_t off, const char *line, size_t len) {
|
||||
printf("%08x: ", off);
|
||||
for (size_t i = 0; i < LINE_LENGTH; ++i) {
|
||||
// XXX: This is needed because I didn't implement h/hh modifiers in printf
|
||||
uint64_t byte = (uint64_t) line[i] & 0xFF;
|
||||
if (i < len) {
|
||||
printf("%02x", byte);
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
if (i % 2) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
printf("| ");
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
// TODO: isprint?
|
||||
if (line[i] >= ' ') {
|
||||
printf("%c", line[i]);
|
||||
} else {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int fd;
|
||||
const char *path;
|
||||
char buf[512];
|
||||
char line[LINE_LENGTH];
|
||||
ssize_t bread;
|
||||
size_t offset;
|
||||
size_t linel;
|
||||
size_t n_full_zero;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("wrong\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
path = argv[1];
|
||||
printf("open file %s\n", path);
|
||||
|
||||
if ((fd = open(path, O_RDONLY, 0)) < 0) {
|
||||
perror(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
linel = 0;
|
||||
n_full_zero = 0;
|
||||
while ((bread = read(fd, buf, sizeof(buf))) > 0) {
|
||||
for (size_t i = 0; i < bread; ++i) {
|
||||
line[linel++] = buf[i];
|
||||
if (linel == LINE_LENGTH) {
|
||||
// Check if the line is all zeros
|
||||
int all_zeros = 1;
|
||||
for (size_t j = 0; j < LINE_LENGTH; ++j) {
|
||||
if (line[j]) {
|
||||
all_zeros = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (all_zeros) {
|
||||
++n_full_zero;
|
||||
} else {
|
||||
n_full_zero = 0;
|
||||
}
|
||||
|
||||
if (n_full_zero < 3) {
|
||||
line_print(offset, line, linel);
|
||||
} else if (n_full_zero == 3) {
|
||||
printf(" ... \n");
|
||||
}
|
||||
offset += LINE_LENGTH;
|
||||
linel = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (linel) {
|
||||
line_print(offset, line, linel);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
136
core/bin/ls.c
Normal file
136
core/bin/ls.c
Normal file
@ -0,0 +1,136 @@
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define LS_COLOR (1 << 0)
|
||||
#define LS_DETAIL (1 << 1)
|
||||
|
||||
#define COLOR_DIR "\033[36m"
|
||||
#define COLOR_DEV "\033[33m"
|
||||
#define COLOR_UNKNOWN "\033[43m"
|
||||
|
||||
#define COLOR_RESET "\033[0m"
|
||||
|
||||
static int ls_dir(const char *path, int flags) {
|
||||
int res;
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
struct stat ent_stat;
|
||||
char ent_path[512];
|
||||
char t;
|
||||
|
||||
if (!(dir = opendir(path))) {
|
||||
perror(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((ent = readdir(dir))) {
|
||||
if (ent->d_name[0] != '.') {
|
||||
if (flags & LS_DETAIL) {
|
||||
snprintf(ent_path, sizeof(ent_path), "%s/%s",
|
||||
strcmp(path, "") ? path : ".", ent->d_name);
|
||||
if (stat(ent_path, &ent_stat) != 0) {
|
||||
printf("?????????? ? ? ? ");
|
||||
} else {
|
||||
switch (ent_stat.st_mode & S_IFMT) {
|
||||
case S_IFDIR:
|
||||
t = 'd';
|
||||
break;
|
||||
case S_IFREG:
|
||||
t = '-';
|
||||
break;
|
||||
case S_IFBLK:
|
||||
t = 'b';
|
||||
break;
|
||||
case S_IFCHR:
|
||||
t = 'c';
|
||||
break;
|
||||
default:
|
||||
t = '?';
|
||||
break;
|
||||
}
|
||||
|
||||
printf("%c%c%c%c%c%c%c%c%c%c ",
|
||||
t,
|
||||
(ent_stat.st_mode & S_IRUSR) ? 'r' : '-',
|
||||
(ent_stat.st_mode & S_IWUSR) ? 'w' : '-',
|
||||
(ent_stat.st_mode & S_IXUSR) ? 'x' : '-',
|
||||
(ent_stat.st_mode & S_IRGRP) ? 'r' : '-',
|
||||
(ent_stat.st_mode & S_IWGRP) ? 'w' : '-',
|
||||
(ent_stat.st_mode & S_IXGRP) ? 'x' : '-',
|
||||
(ent_stat.st_mode & S_IROTH) ? 'r' : '-',
|
||||
(ent_stat.st_mode & S_IWOTH) ? 'w' : '-',
|
||||
(ent_stat.st_mode & S_IXOTH) ? 'x' : '-');
|
||||
|
||||
printf("%4u %4u %8u ",
|
||||
ent_stat.st_gid,
|
||||
ent_stat.st_uid,
|
||||
ent_stat.st_blocks);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & LS_COLOR) {
|
||||
switch (ent->d_type) {
|
||||
case DT_REG:
|
||||
break;
|
||||
case DT_BLK:
|
||||
case DT_CHR:
|
||||
write(STDOUT_FILENO, COLOR_DEV, 5);
|
||||
break;
|
||||
case DT_DIR:
|
||||
write(STDOUT_FILENO, COLOR_DIR, 5);
|
||||
break;
|
||||
default:
|
||||
write(STDOUT_FILENO, COLOR_UNKNOWN, 5);
|
||||
break;
|
||||
}
|
||||
}
|
||||
write(STDOUT_FILENO, ent->d_name, strlen(ent->d_name));
|
||||
if (flags & LS_COLOR) {
|
||||
write(STDOUT_FILENO, COLOR_RESET, 4);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Basic getopt-like features
|
||||
int first = -1;
|
||||
int flags = 0;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (argv[i][0] != '-') {
|
||||
first = i;
|
||||
break;
|
||||
} else {
|
||||
if (!strcmp(argv[i], "-c")) {
|
||||
flags |= LS_COLOR;
|
||||
} else if (!strcmp(argv[i], "-d")) {
|
||||
flags |= LS_DETAIL;
|
||||
} else {
|
||||
printf("Unknown option: %s\n", argv[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (first == -1) {
|
||||
ls_dir("", flags);
|
||||
} else {
|
||||
for (int i = first; i < argc; ++i) {
|
||||
if (first != argc - 1) {
|
||||
printf("%s:\n", argv[i]);
|
||||
}
|
||||
ls_dir(argv[i], flags);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
33
core/bin/reboot.c
Normal file
33
core/bin/reboot.c
Normal file
@ -0,0 +1,33 @@
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const char *arg = NULL;
|
||||
|
||||
if (argc == 2) {
|
||||
arg = argv[1];
|
||||
}
|
||||
|
||||
int res;
|
||||
unsigned int cmd = YGG_REBOOT_RESTART;
|
||||
|
||||
if (arg) {
|
||||
if (!strcmp(arg, "-s")) {
|
||||
cmd = YGG_REBOOT_POWER_OFF;
|
||||
} else if (!strcmp(arg, "-h")) {
|
||||
cmd = YGG_REBOOT_HALT;
|
||||
}
|
||||
}
|
||||
|
||||
if ((res = reboot(YGG_REBOOT_MAGIC1, YGG_REBOOT_MAGIC2, cmd, NULL)) < 0) {
|
||||
perror("reboot()");
|
||||
return res;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
usleep(1000000);
|
||||
}
|
||||
}
|
1
etc/file.txt
Normal file
1
etc/file.txt
Normal file
@ -0,0 +1 @@
|
||||
This file is inside the initrd.
|
410
init.c
Normal file
410
init.c
Normal file
@ -0,0 +1,410 @@
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <signal.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Cursor helpers
|
||||
|
||||
#define curs_save() \
|
||||
write(STDOUT_FILENO, "\033[s", 3)
|
||||
#define curs_unsave() \
|
||||
write(STDOUT_FILENO, "\033[u", 3)
|
||||
#define curs_set(row, col) \
|
||||
printf("\033[%d;%df", row, col)
|
||||
#define clear() \
|
||||
write(STDOUT_FILENO, "\033[2J", 4)
|
||||
|
||||
#define BOX_ANGLE_UL "\332"
|
||||
#define BOX_ANGLE_UR "\277"
|
||||
#define BOX_ANGLE_LL "\300"
|
||||
#define BOX_ANGLE_LR "\331"
|
||||
#define BOX_HOR "\304"
|
||||
#define BOX_VERT "\263"
|
||||
|
||||
//
|
||||
|
||||
extern __attribute__((noreturn)) void abort(void);
|
||||
|
||||
#define assert(x) \
|
||||
if (!(x)) abort()
|
||||
|
||||
struct builtin {
|
||||
const char *name;
|
||||
const char *desc;
|
||||
int (*run) (const char *arg);
|
||||
};
|
||||
|
||||
static int b_cd(const char *path);
|
||||
static int b_pwd(const char *_);
|
||||
static int b_cat(const char *path);
|
||||
static int b_curs(const char *arg);
|
||||
static int b_sleep(const char *arg);
|
||||
static int b_help(const char *arg);
|
||||
static int b_clear(const char *arg);
|
||||
|
||||
static struct builtin builtins[] = {
|
||||
{
|
||||
"cd",
|
||||
"Change working directory",
|
||||
b_cd,
|
||||
},
|
||||
{
|
||||
"pwd",
|
||||
"Print working directory",
|
||||
b_pwd,
|
||||
},
|
||||
{
|
||||
"cat",
|
||||
"Print file contents" /* Concatenate files */,
|
||||
b_cat
|
||||
},
|
||||
{
|
||||
"sleep",
|
||||
"Sleep N seconds",
|
||||
b_sleep
|
||||
},
|
||||
{
|
||||
"clear",
|
||||
"Clear terminal",
|
||||
b_clear,
|
||||
},
|
||||
{
|
||||
"help",
|
||||
"Please help me",
|
||||
b_help
|
||||
},
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static int b_cd(const char *arg) {
|
||||
int res;
|
||||
if (!arg) {
|
||||
arg = "";
|
||||
}
|
||||
|
||||
if ((res = chdir(arg)) < 0) {
|
||||
perror(arg);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int b_pwd(const char *arg) {
|
||||
char buf[512];
|
||||
if (!getcwd(buf, sizeof(buf))) {
|
||||
perror("getcwd()");
|
||||
return -1;
|
||||
} else {
|
||||
puts(buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b_cat(const char *arg) {
|
||||
char buf[512];
|
||||
int fd;
|
||||
ssize_t bread;
|
||||
|
||||
if (!arg) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((fd = open(arg, O_RDONLY, 0)) < 0) {
|
||||
perror(arg);
|
||||
return fd;
|
||||
}
|
||||
|
||||
while ((bread = read(fd, buf, sizeof(buf))) > 0) {
|
||||
write(STDOUT_FILENO, buf, bread);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b_curs(const char *arg) {
|
||||
char c;
|
||||
|
||||
size_t w = 60;
|
||||
size_t h = 20;
|
||||
size_t off_y = (25 - h) / 2 + 1;
|
||||
size_t off_x = (80 - w) / 2;
|
||||
|
||||
const char *lines[18] = {
|
||||
NULL,
|
||||
"Demo something",
|
||||
NULL,
|
||||
"Slow as hell"
|
||||
};
|
||||
|
||||
clear();
|
||||
|
||||
while (1) {
|
||||
printf("\033[47;30m");
|
||||
|
||||
curs_set(off_y, off_x);
|
||||
printf(BOX_ANGLE_UL);
|
||||
for (size_t i = 0; i < w; ++i) {
|
||||
printf(BOX_HOR);
|
||||
}
|
||||
printf(BOX_ANGLE_UR);
|
||||
|
||||
for (size_t i = 0; i < h - 2; ++i) {
|
||||
curs_set(off_y + 1 + i, off_x);
|
||||
printf(BOX_VERT);
|
||||
for (size_t j = 0; j < w; ++j) {
|
||||
printf(" ");
|
||||
}
|
||||
if (lines[i]) {
|
||||
curs_set(off_y + 1 + i, off_x + (w - strlen(lines[i])) / 2);
|
||||
printf("%s", lines[i]);
|
||||
}
|
||||
curs_set(off_y + 1 + i, off_x + w + 1);
|
||||
printf(BOX_VERT);
|
||||
}
|
||||
|
||||
curs_set(off_y + h - 3, off_x + (w - 8) / 2);
|
||||
printf("\033[0m\033[7m[ OK ]\033[47;30m");
|
||||
curs_set(off_y + h - 1, off_x);
|
||||
printf(BOX_ANGLE_LL);
|
||||
for (size_t i = 0; i < w; ++i) {
|
||||
printf(BOX_HOR);
|
||||
}
|
||||
printf(BOX_ANGLE_LR);
|
||||
|
||||
printf("\033[0m");
|
||||
|
||||
curs_set(1, 1);
|
||||
|
||||
if (read(STDIN_FILENO, &c, 1) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == 'q' || c == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
curs_set(1, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b_sleep(const char *arg) {
|
||||
if (!arg) {
|
||||
return -1;
|
||||
}
|
||||
int seconds = 0;
|
||||
while (*arg) {
|
||||
seconds *= 10;
|
||||
seconds += *arg - '0';
|
||||
++arg;
|
||||
}
|
||||
|
||||
struct timespec ts = { seconds, 0 };
|
||||
if ((seconds = nanosleep(&ts, NULL))) {
|
||||
perror("nanosleep()");
|
||||
return seconds;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b_clear(const char *arg) {
|
||||
clear();
|
||||
curs_set(1, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b_help(const char *arg) {
|
||||
if (arg) {
|
||||
// Describe a specific command
|
||||
for (size_t i = 0; builtins[i].run; ++i) {
|
||||
if (!strcmp(arg, builtins[i].name)) {
|
||||
printf("%s: %s\n", builtins[i].name, builtins[i].desc);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s: Unknown command\n", arg);
|
||||
return -1;
|
||||
} else {
|
||||
for (size_t i = 0; builtins[i].run; ++i) {
|
||||
printf("%s: %s\n", builtins[i].name, builtins[i].desc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void prompt(void) {
|
||||
char cwd[512];
|
||||
if (!getcwd(cwd, sizeof(cwd))) {
|
||||
cwd[0] = '?';
|
||||
cwd[1] = 0;
|
||||
}
|
||||
printf("\033[36mygg\033[0m %s > ", cwd);
|
||||
}
|
||||
|
||||
static int cmd_subproc_exec(const char *abs_path, const char *cmd, const char *e) {
|
||||
// Maximum of 8 arguments 64 chars each (63)
|
||||
// Split input argument into pieces by space
|
||||
char args[64 * 8] = {0};
|
||||
const char *p = e;
|
||||
const char *t = NULL;
|
||||
size_t argc = 0;
|
||||
while (p) {
|
||||
t = strchr(p, ' ');
|
||||
if (!t) {
|
||||
// Last argument
|
||||
assert(strlen(p) < 64);
|
||||
strcpy(&args[argc++ * 64], p);
|
||||
break;
|
||||
} else {
|
||||
assert(t - p < 64);
|
||||
strncpy(&args[argc * 64], p, t - p);
|
||||
args[(argc++ * 64) + (t - p)] = 0;
|
||||
p = t + 1;
|
||||
while (*p == ' ') {
|
||||
++p;
|
||||
}
|
||||
if (!*p) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill arg pointer array
|
||||
const char *argp[10] = { cmd };
|
||||
for (size_t i = 0; i < argc; ++i) {
|
||||
argp[i + 1] = &args[i * 64];
|
||||
}
|
||||
argp[argc + 1] = NULL;
|
||||
|
||||
int pid = fork();
|
||||
int res;
|
||||
int status;
|
||||
|
||||
switch (pid) {
|
||||
case -1:
|
||||
perror("fork()");
|
||||
return -1;
|
||||
case 0:
|
||||
if (execve(abs_path, argp, NULL) != 0) {
|
||||
perror("execve()");
|
||||
}
|
||||
exit(-1);
|
||||
default:
|
||||
if (waitpid(pid, &status) != 0) {
|
||||
perror("waitpid()");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int cmd_exec(const char *line) {
|
||||
char cmd[64];
|
||||
const char *e = strchr(line, ' ');
|
||||
|
||||
if (!e) {
|
||||
assert(strlen(line) < 64);
|
||||
strcpy(cmd, line);
|
||||
} else {
|
||||
assert(e - line < 64);
|
||||
strncpy(cmd, line, e - line);
|
||||
cmd[e - line] = 0;
|
||||
++e;
|
||||
while (*e == ' ') {
|
||||
++e;
|
||||
}
|
||||
}
|
||||
|
||||
if (e && !*e) {
|
||||
e = NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; builtins[i].run; ++i) {
|
||||
if (!strcmp(cmd, builtins[i].name)) {
|
||||
return builtins[i].run(e);
|
||||
}
|
||||
}
|
||||
|
||||
// If command starts with ./ or /, try to execute it
|
||||
if (((cmd[0] == '.' && cmd[1] == '/') || cmd[0] == '/') && access(cmd, X_OK) == 0) {
|
||||
return cmd_subproc_exec(cmd, cmd, e);
|
||||
}
|
||||
// Try to execute binary from /bin
|
||||
char path_buf[512];
|
||||
snprintf(path_buf, sizeof(path_buf), "/bin/%s", cmd);
|
||||
if (access(path_buf, X_OK) == 0) {
|
||||
return cmd_subproc_exec(path_buf, cmd, e);
|
||||
}
|
||||
|
||||
printf("%s: Unknown command\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (getpid() != 1) {
|
||||
printf("Won't work if PID is not 1\n");
|
||||
return -1;
|
||||
}
|
||||
char linebuf[512];
|
||||
char c;
|
||||
size_t l = 0;
|
||||
int res;
|
||||
|
||||
prompt();
|
||||
|
||||
#if 0
|
||||
if ((res = fork()) < 0) {
|
||||
perror("fork()");
|
||||
return -1;
|
||||
} else if (res == 0) {
|
||||
if (execve("/time", NULL, NULL) != 0) {
|
||||
perror("execve()");
|
||||
}
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
if (read(STDIN_FILENO, &c, 1) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '\b') {
|
||||
if (l) {
|
||||
linebuf[--l] = 0;
|
||||
printf("\033[D \033[D");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (c == '\n') {
|
||||
write(STDOUT_FILENO, &c, 1);
|
||||
linebuf[l] = 0;
|
||||
|
||||
if (!strcmp(linebuf, "exit")) {
|
||||
break;
|
||||
}
|
||||
|
||||
l = 0;
|
||||
if ((res = cmd_exec(linebuf)) != 0) {
|
||||
printf("\033[31m= %d\033[0m\n", res);
|
||||
}
|
||||
prompt();
|
||||
continue;
|
||||
}
|
||||
|
||||
linebuf[l++] = c;
|
||||
write(STDOUT_FILENO, &c, 1);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
25
libc/crt0.S
Normal file
25
libc/crt0.S
Normal file
@ -0,0 +1,25 @@
|
||||
.section .text
|
||||
.global _start
|
||||
.type _start, %function
|
||||
// Arguments:
|
||||
// %rdi - argp
|
||||
_start:
|
||||
movq $0, %rbp
|
||||
// For callee linkage
|
||||
pushq %rbp
|
||||
pushq %rbp
|
||||
movq %rsp, %rbp
|
||||
|
||||
push %rdi
|
||||
call __libc_init
|
||||
|
||||
call _init
|
||||
|
||||
mov __libc_argc, %rdi
|
||||
pop %rsi
|
||||
|
||||
// exit(main(argc, argv))
|
||||
call main
|
||||
movq %rax, %rdi
|
||||
call exit
|
||||
.size _start, . - _start
|
16
libc/crti.S
Normal file
16
libc/crti.S
Normal file
@ -0,0 +1,16 @@
|
||||
/* x86_64 crti.s */
|
||||
.section .init
|
||||
.global _init
|
||||
.type _init, @function
|
||||
_init:
|
||||
push %rbp
|
||||
movq %rsp, %rbp
|
||||
/* gcc will nicely put the contents of crtbegin.o's .init section here. */
|
||||
|
||||
.section .fini
|
||||
.global _fini
|
||||
.type _fini, @function
|
||||
_fini:
|
||||
push %rbp
|
||||
movq %rsp, %rbp
|
||||
/* gcc will nicely put the contents of crtbegin.o's .fini section here. */
|
10
libc/crtn.S
Normal file
10
libc/crtn.S
Normal file
@ -0,0 +1,10 @@
|
||||
/* x86_64 crtn.s */
|
||||
.section .init
|
||||
/* gcc will nicely put the contents of crtend.o's .init section here. */
|
||||
popq %rbp
|
||||
ret
|
||||
|
||||
.section .fini
|
||||
/* gcc will nicely put the contents of crtend.o's .fini section here. */
|
||||
popq %rbp
|
||||
ret
|
57
libc/dirent.c
Normal file
57
libc/dirent.c
Normal file
@ -0,0 +1,57 @@
|
||||
#include "dirent.h"
|
||||
#include "bits/syscall.h"
|
||||
#include <sys/fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
extern void *malloc(size_t count);
|
||||
extern void free(void *p);
|
||||
|
||||
struct DIR_private {
|
||||
int fd;
|
||||
struct dirent buf;
|
||||
};
|
||||
|
||||
DIR *opendir(const char *path) {
|
||||
int fd;
|
||||
DIR *res;
|
||||
|
||||
if (!(res = malloc(sizeof(struct DIR_private)))) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if ((fd = open(path, O_DIRECTORY | O_RDONLY, 0)) < 0) {
|
||||
fd = errno;
|
||||
free(res);
|
||||
errno = fd;
|
||||
// errno is set
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res->fd = fd;
|
||||
memset(&res->buf, 0, sizeof(res->buf));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void closedir(DIR *dirp) {
|
||||
if (!dirp) {
|
||||
return;
|
||||
}
|
||||
close(dirp->fd);
|
||||
free(dirp);
|
||||
}
|
||||
|
||||
struct dirent *readdir(DIR *dirp) {
|
||||
ssize_t res;
|
||||
if (!dirp) {
|
||||
errno = EBADF;
|
||||
return NULL;
|
||||
}
|
||||
if ((res = sys_readdir(dirp->fd, &dirp->buf)) <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
return &dirp->buf;
|
||||
}
|
57
libc/errno.c
Normal file
57
libc/errno.c
Normal file
@ -0,0 +1,57 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *err_strings0[35] = {
|
||||
"Success",
|
||||
"Operation not permitted",
|
||||
"No such file or directory",
|
||||
"No such process",
|
||||
"Interrupted system call",
|
||||
"I/O error",
|
||||
"No such device or address",
|
||||
"Argument list too long",
|
||||
"Exec format error",
|
||||
"Bad file number",
|
||||
"No child processes",
|
||||
"Try again",
|
||||
"Out of memory",
|
||||
"Permission denied",
|
||||
"Bad address",
|
||||
"Block device required",
|
||||
"Device or resource busy",
|
||||
"File exists",
|
||||
"Cross-device link",
|
||||
"No such device",
|
||||
"Not a directory",
|
||||
"Is a directory",
|
||||
"Invalid argument",
|
||||
"File table overflow",
|
||||
"Too many open files",
|
||||
"Not a typewriter",
|
||||
"Text file busy",
|
||||
"File too large",
|
||||
"No space left on device",
|
||||
"Illegal seek",
|
||||
"Read-only file system",
|
||||
"Too many links",
|
||||
"Broken pipe",
|
||||
"Math argument out of domain of func",
|
||||
"Math result not representable"
|
||||
};
|
||||
|
||||
int errno;
|
||||
|
||||
char *strerror(int n) {
|
||||
if (n >= 0 && n <= 34) {
|
||||
return (char *) err_strings0[n];
|
||||
}
|
||||
return (char *) "Unknown error";
|
||||
}
|
||||
|
||||
void perror(const char *e) {
|
||||
if (e && *e) {
|
||||
printf("%s: %s\n", e, strerror(errno));
|
||||
} else {
|
||||
puts(strerror(errno));
|
||||
}
|
||||
}
|
4
libc/global.c
Normal file
4
libc/global.c
Normal file
@ -0,0 +1,4 @@
|
||||
#include "bits/global.h"
|
||||
|
||||
void *__cur_brk;
|
||||
uint64_t __libc_argc = 0;
|
5
libc/include/bits/global.h
Normal file
5
libc/include/bits/global.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
extern void *__cur_brk;
|
||||
extern uint64_t __libc_argc;
|
7
libc/include/bits/printf.h
Normal file
7
libc/include/bits/printf.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
int printf(const char *fmt, ...);
|
||||
int snprintf(char *buf, size_t size, const char *fmt, ...);
|
||||
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
|
30
libc/include/bits/syscall.h
Normal file
30
libc/include/bits/syscall.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include <sys/fs/dirent.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
ssize_t read(int fd, void *buf, size_t count);
|
||||
ssize_t write(int fd, const void *buf, size_t count);
|
||||
int open(const char *filename, int flags, int mode);
|
||||
void close(int fd);
|
||||
int stat(const char *filename, struct stat *st);
|
||||
void *mmap(void *addr, size_t len, int prot, int flags, int fd, uintptr_t offset);
|
||||
int fork(void);
|
||||
int execve(const char *filename, const char *const argv[], const char *const envp[]);
|
||||
ssize_t sys_readdir(int fd, struct dirent *entp);
|
||||
int kill(int pid, int signum);
|
||||
void __kernel_signal(uintptr_t handler);
|
||||
__attribute__((noreturn)) void __kernel_sigret(void);
|
||||
int getpid(void);
|
||||
int chdir(const char *filename);
|
||||
char *getcwd(char *buf, size_t size);
|
||||
int nanosleep(const struct timespec *req, struct timespec *rem);
|
||||
int openpty(int *amaster, int *aslave);
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz);
|
||||
int reboot(int magic1, int magic2, unsigned int cmd, void *arg);
|
||||
int access(const char *filename, int mode);
|
||||
int waitpid(int pid, int *status);
|
||||
|
||||
__attribute__((noreturn)) void exit(int code);
|
8
libc/include/dirent.h
Normal file
8
libc/include/dirent.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include <sys/fs/dirent.h>
|
||||
|
||||
typedef struct DIR_private DIR;
|
||||
|
||||
DIR *opendir(const char *path);
|
||||
void closedir(DIR *dirp);
|
||||
struct dirent *readdir(DIR *dirp);
|
7
libc/include/errno.h
Normal file
7
libc/include/errno.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include <sys/errno.h>
|
||||
|
||||
extern int errno;
|
||||
|
||||
char *strerror(int errnum);
|
||||
void perror(const char *s);
|
8
libc/include/signal.h
Normal file
8
libc/include/signal.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include <sys/signum.h>
|
||||
|
||||
typedef void (*sighandler_t) (int);
|
||||
|
||||
sighandler_t signal(int signum, sighandler_t handler);
|
||||
|
||||
int raise(int signum);
|
6
libc/include/stdio.h
Normal file
6
libc/include/stdio.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
int puts(const char *s);
|
||||
int putchar(int c);
|
||||
|
||||
#include "bits/printf.h"
|
3
libc/include/stdlib.h
Normal file
3
libc/include/stdlib.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void abort(void);
|
17
libc/include/string.h
Normal file
17
libc/include/string.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include <sys/types.h>
|
||||
|
||||
void *memcpy(void *restrict dst, const void *restrict src, size_t cnt);
|
||||
void *memmove(void *dst, const void *src, size_t cnt);
|
||||
void *memset(void *dst, int v, size_t count);
|
||||
int memcmp(const void *a, const void *b, size_t count);
|
||||
|
||||
size_t strlen(const char *s);
|
||||
int strncmp(const char *a, const char *b, size_t lim);
|
||||
int strcmp(const char *a, const char *b);
|
||||
char *strchr(const char *a, int c);
|
||||
char *strrchr(const char *a, int c);
|
||||
char *strcpy(char *dst, const char *src);
|
||||
char *strncpy(char *dst, const char *src, size_t lim);
|
||||
char *strcat(char *dst, const char *src);
|
||||
char *strncat(char *dst, const char *src, size_t lim);
|
4
libc/include/time.h
Normal file
4
libc/include/time.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include <sys/time.h>
|
||||
|
||||
int usleep(long us);
|
10
libc/include/unistd.h
Normal file
10
libc/include/unistd.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "bits/syscall.h"
|
||||
#include <sys/reboot.h>
|
||||
|
||||
#define STDIN_FILENO 0
|
||||
#define STDOUT_FILENO 1
|
||||
#define STDERR_FILENO 2
|
||||
|
||||
void *sbrk(intptr_t diff);
|
||||
int reboot(int magic1, int magic2, unsigned int cmd, void *arg);
|
18
libc/init.c
Normal file
18
libc/init.c
Normal file
@ -0,0 +1,18 @@
|
||||
#include <errno.h>
|
||||
#include "bits/global.h"
|
||||
|
||||
extern char __heap_start;
|
||||
extern void __libc_signal_init(void);
|
||||
static const char *argp_dummy[] = { 0 };
|
||||
|
||||
void __libc_init(char **argp) {
|
||||
__libc_signal_init();
|
||||
__libc_argc = 0;
|
||||
if (argp) {
|
||||
while (argp[__libc_argc]) {
|
||||
++__libc_argc;
|
||||
}
|
||||
}
|
||||
__cur_brk = &__heap_start;
|
||||
errno = 0;
|
||||
}
|
15
libc/malloc.c
Normal file
15
libc/malloc.c
Normal file
@ -0,0 +1,15 @@
|
||||
#include <unistd.h>
|
||||
#include "bits/global.h"
|
||||
|
||||
// XXX: I'll implement a proper heap in the following commits
|
||||
void *malloc(size_t count) {
|
||||
void *p = __cur_brk;
|
||||
if (sbrk(count) == p) {
|
||||
return NULL;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void free(void *ptr) {
|
||||
|
||||
}
|
25
libc/printf.c
Normal file
25
libc/printf.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include "bits/printf.h"
|
||||
#include <unistd.h>
|
||||
#define PRINTF_BUFFER_SIZE 1024
|
||||
|
||||
int printf(const char *fmt, ...) {
|
||||
char buf[PRINTF_BUFFER_SIZE];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int res = vsnprintf(buf, PRINTF_BUFFER_SIZE, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
// TODO: use libc's FILE * instead
|
||||
return write(STDOUT_FILENO, buf, res);
|
||||
}
|
||||
|
||||
int snprintf(char *buf, size_t lim, const char *fmt, ...) {
|
||||
va_list args;
|
||||
int res;
|
||||
|
||||
va_start(args, fmt);
|
||||
res = vsnprintf(buf, PRINTF_BUFFER_SIZE, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return res;
|
||||
}
|
35
libc/program.ld
Normal file
35
libc/program.ld
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Userspace program linker script,
|
||||
* partially derived from GCC's -static one
|
||||
*/
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS {
|
||||
. = 0x400000;
|
||||
|
||||
.text : ALIGN(4K) {
|
||||
KEEP (*(SORT_NONE(.init)))
|
||||
*(.text)
|
||||
KEEP (*(SORT_NONE(.fini)))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
}
|
||||
|
||||
.rodata : {
|
||||
*(.rodata)
|
||||
*(.eh_frame)
|
||||
}
|
||||
|
||||
.data : ALIGN(4K) {
|
||||
*(.data)
|
||||
}
|
||||
|
||||
.bss : ALIGN(4K) {
|
||||
*(.bss)
|
||||
}
|
||||
|
||||
__program_end = .;
|
||||
__heap_start = .;
|
||||
}
|
71
libc/signal.c
Normal file
71
libc/signal.c
Normal file
@ -0,0 +1,71 @@
|
||||
#include <bits/syscall.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static sighandler_t signal_handlers[16] = {0};
|
||||
|
||||
void SIG_IGN(int signum) {
|
||||
printf("Ignored: %d\n", signum);
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
void SIG_DFL(int signum) {
|
||||
int pid = getpid();
|
||||
|
||||
switch (signum) {
|
||||
case SIGKILL:
|
||||
printf("%d: killed\n", pid);
|
||||
break;
|
||||
case SIGABRT:
|
||||
printf("%d: aborted\n", pid);
|
||||
break;
|
||||
case SIGSEGV:
|
||||
printf("%d: segmentation fault\n", pid);
|
||||
break;
|
||||
default:
|
||||
printf("%d: signal %d\n", pid, signum);
|
||||
break;
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void __libc_signal_handle(int signum) {
|
||||
if (signum >= 16) {
|
||||
SIG_DFL(signum);
|
||||
} else {
|
||||
signal_handlers[signum](signum);
|
||||
}
|
||||
|
||||
__kernel_sigret();
|
||||
}
|
||||
|
||||
void __libc_signal_init(void) {
|
||||
for (size_t i = 0; i < 16; ++i) {
|
||||
signal_handlers[i] = SIG_DFL;
|
||||
}
|
||||
|
||||
__kernel_signal((uintptr_t) __libc_signal_handle);
|
||||
}
|
||||
|
||||
sighandler_t signal(int signum, sighandler_t new_handler) {
|
||||
sighandler_t old_handler;
|
||||
|
||||
if (signum >= 16) {
|
||||
printf("Fuck\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
old_handler = signal_handlers[signum];
|
||||
signal_handlers[signum] = new_handler;
|
||||
return old_handler;
|
||||
}
|
||||
|
||||
int raise(int signum) {
|
||||
return kill(getpid(), signum);
|
||||
}
|
||||
|
||||
void abort(void) {
|
||||
kill(getpid(), SIGABRT);
|
||||
}
|
22
libc/stdio.c
Normal file
22
libc/stdio.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int puts(const char *s) {
|
||||
size_t l = strlen(s);
|
||||
int w = write(STDOUT_FILENO, s, l);
|
||||
char c = '\n';
|
||||
|
||||
if (w == l) {
|
||||
write(STDOUT_FILENO, &c, 1);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
int putchar(int c) {
|
||||
int res;
|
||||
if ((res = write(STDOUT_FILENO, &c, 1)) < 0) {
|
||||
return res;
|
||||
}
|
||||
return c;
|
||||
}
|
167
libc/string.c
Normal file
167
libc/string.c
Normal file
@ -0,0 +1,167 @@
|
||||
#include <string.h>
|
||||
|
||||
char *strcat(char *dst, const char *src) {
|
||||
size_t l = strlen(dst);
|
||||
strcpy(dst + l, src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *strncat(char *dst, const char *src, size_t lim) {
|
||||
size_t l = strlen(dst);
|
||||
if (l < lim) {
|
||||
return dst;
|
||||
}
|
||||
size_t r = lim - l;
|
||||
strncpy(dst + l, src, r);
|
||||
return dst;
|
||||
}
|
||||
|
||||
size_t strlen(const char *a) {
|
||||
size_t s = 0;
|
||||
while (*a++) {
|
||||
++s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
int strncmp(const char *a, const char *b, size_t n) {
|
||||
size_t c = 0;
|
||||
for (; c < n && (*a || *b); ++c, ++a, ++b) {
|
||||
if (*a != *b) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strcmp(const char *a, const char *b) {
|
||||
if (a == b) {
|
||||
return 0;
|
||||
}
|
||||
if (a == NULL || b == NULL) {
|
||||
return -1;
|
||||
}
|
||||
for (; *a || *b; ++a, ++b) {
|
||||
if (*a != *b) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *strcpy(char *dst, const char *src) {
|
||||
size_t i;
|
||||
for (i = 0; src[i]; ++i) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
dst[i] = 0;
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *strncpy(char *dst, const char *src, size_t lim) {
|
||||
size_t i = 0;
|
||||
while (i < lim) {
|
||||
if (!src[i]) {
|
||||
dst[i] = 0;
|
||||
return dst;
|
||||
}
|
||||
dst[i] = src[i];
|
||||
++i;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *strchr(const char *s, int c) {
|
||||
while (*s) {
|
||||
if (*s == (char) c) {
|
||||
return (char *) s;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *strrchr(const char *s, int c) {
|
||||
ssize_t l = (ssize_t) strlen(s);
|
||||
if (!l) {
|
||||
return NULL;
|
||||
}
|
||||
while (l >= 0) {
|
||||
if (s[l] == (char) c) {
|
||||
return (char *) &s[l];
|
||||
}
|
||||
--l;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int memcmp(const void *a, const void *b, size_t n) {
|
||||
const char *l = a;
|
||||
const char *r = b;
|
||||
for (; n && *l == *r; --n, ++l, ++r);
|
||||
return n ? *l - *r : 0;
|
||||
}
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t n) {
|
||||
char *d = dest;
|
||||
const char *s = src;
|
||||
|
||||
if (d == s) {
|
||||
return d;
|
||||
}
|
||||
|
||||
if ((s + n) <= d || (d + n) <= s) {
|
||||
return memcpy(d, s, n);
|
||||
}
|
||||
|
||||
if (d < s) {
|
||||
if (((uintptr_t) s) % sizeof(size_t) == ((uintptr_t) d) % sizeof(size_t)) {
|
||||
while (((uintptr_t) d) % sizeof(size_t)) {
|
||||
if (!n--) {
|
||||
return dest;
|
||||
}
|
||||
*d++ = *s++;
|
||||
}
|
||||
for (; n >= sizeof(size_t); n -= sizeof(size_t), d += sizeof(size_t), s += sizeof(size_t)) {
|
||||
*((size_t *) d) = *((size_t *) s);
|
||||
}
|
||||
}
|
||||
for (; n; n--) {
|
||||
*d++ = *s++;
|
||||
}
|
||||
} else {
|
||||
if (((uintptr_t) s) % sizeof(size_t) == ((uintptr_t) d) % sizeof(size_t)) {
|
||||
while (((uintptr_t) (d + n)) % sizeof(size_t)) {
|
||||
if (!n--) {
|
||||
return dest;
|
||||
}
|
||||
d[n] = s[n];
|
||||
}
|
||||
while (n >= sizeof(size_t)) {
|
||||
n -= sizeof(size_t);
|
||||
*((size_t *) (d + n)) = *((size_t *) (s + n));
|
||||
}
|
||||
}
|
||||
while (n) {
|
||||
n--;
|
||||
d[n] = s[n];
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *memset(void *blk, int v, size_t sz) {
|
||||
for (size_t i = 0; i < sz; ++i) {
|
||||
((char *) blk)[i] = v;
|
||||
}
|
||||
return blk;
|
||||
}
|
||||
|
||||
void *memcpy(void *dst, const void *src, size_t sz) {
|
||||
for (size_t i = 0; i < sz; ++i) {
|
||||
((char *) dst)[i] = ((const char *) src)[i];
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
179
libc/syscall.c
Normal file
179
libc/syscall.c
Normal file
@ -0,0 +1,179 @@
|
||||
#include "bits/syscall.h"
|
||||
#include "bits/global.h"
|
||||
#include <errno.h>
|
||||
|
||||
#define ASM_REGISTER(name) \
|
||||
register uint64_t name asm (#name)
|
||||
|
||||
#define ASM_SYSCALL0(r0) ({ \
|
||||
ASM_REGISTER(rax) = (uint64_t) (r0); \
|
||||
asm volatile ("syscall":::"memory"); \
|
||||
rax; \
|
||||
})
|
||||
|
||||
#define ASM_SYSCALL1(r0, r1) ({ \
|
||||
ASM_REGISTER(rdi) = (uint64_t) (r1); \
|
||||
/*
|
||||
* Should be the last one because memory accesses for arguments
|
||||
* fuck up %rax
|
||||
*/ \
|
||||
ASM_REGISTER(rax) = (uint64_t) (r0); \
|
||||
asm volatile ("syscall":::"memory"); \
|
||||
rax; \
|
||||
})
|
||||
|
||||
#define ASM_SYSCALL2(r0, r1, r2) ({ \
|
||||
ASM_REGISTER(rdi) = (uint64_t) (r1); \
|
||||
ASM_REGISTER(rsi) = (uint64_t) (r2); \
|
||||
/*
|
||||
* Should be the last one because memory accesses for arguments
|
||||
* fuck up %rax
|
||||
*/ \
|
||||
ASM_REGISTER(rax) = (uint64_t) (r0); \
|
||||
asm volatile ("syscall":::"memory", "rax", "rdi", "rsi", "rdx"); \
|
||||
rax; \
|
||||
})
|
||||
|
||||
#define ASM_SYSCALL3(r0, r1, r2, r3) ({ \
|
||||
ASM_REGISTER(rdi) = (uint64_t) (r1); \
|
||||
ASM_REGISTER(rsi) = (uint64_t) (r2); \
|
||||
ASM_REGISTER(rdx) = (uint64_t) (r3); \
|
||||
/*
|
||||
* Should be the last one because memory accesses for arguments
|
||||
* fuck up %rax
|
||||
*/ \
|
||||
ASM_REGISTER(rax) = (uint64_t) (r0); \
|
||||
asm volatile ("syscall":::"memory", "rax", "rdi", "rsi", "rdx"); \
|
||||
rax; \
|
||||
})
|
||||
|
||||
#define ASM_SYSCALL4(r0, r1, r2, r3, r4) ({ \
|
||||
ASM_REGISTER(rdi) = (uint64_t) (r1); \
|
||||
ASM_REGISTER(rsi) = (uint64_t) (r2); \
|
||||
ASM_REGISTER(rdx) = (uint64_t) (r3); \
|
||||
ASM_REGISTER(r10) = (uint64_t) (r4); \
|
||||
/*
|
||||
* Should be the last one because memory accesses for arguments
|
||||
* fuck up %rax
|
||||
*/ \
|
||||
ASM_REGISTER(rax) = (uint64_t) (r0); \
|
||||
asm volatile ("syscall":::"memory", "rax", "rdi", "rsi", "rdx", "r10"); \
|
||||
rax; \
|
||||
})
|
||||
|
||||
#define SET_ERRNO(t, r) ({ \
|
||||
t res = (t) r; \
|
||||
if (res < 0) { \
|
||||
errno = -res; \
|
||||
} \
|
||||
((int) res) < 0 ? (t) -1 : res; \
|
||||
})
|
||||
|
||||
ssize_t write(int fd, const void *buf, size_t count) {
|
||||
return SET_ERRNO(ssize_t, ASM_SYSCALL3(SYSCALL_NR_WRITE, fd, buf, count));
|
||||
}
|
||||
|
||||
ssize_t read(int fd, void *buf, size_t count) {
|
||||
return SET_ERRNO(ssize_t, ASM_SYSCALL3(SYSCALL_NR_READ, fd, buf, count));
|
||||
}
|
||||
|
||||
ssize_t sys_readdir(int fd, struct dirent *entp) {
|
||||
return SET_ERRNO(ssize_t, ASM_SYSCALL2(SYSCALL_NR_READDIR, fd, entp));
|
||||
}
|
||||
|
||||
int open(const char *filename, int flags, int mode) {
|
||||
return SET_ERRNO(int, ASM_SYSCALL3(SYSCALL_NR_OPEN, filename, flags, mode));
|
||||
}
|
||||
|
||||
void close(int fd) {
|
||||
(void) ASM_SYSCALL1(SYSCALL_NR_CLOSE, fd);
|
||||
}
|
||||
|
||||
int stat(const char *filename, struct stat *st) {
|
||||
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NR_STAT, filename, st));
|
||||
}
|
||||
|
||||
int brk(void *addr) {
|
||||
return SET_ERRNO(int, ASM_SYSCALL1(SYSCALL_NR_BRK, addr));
|
||||
}
|
||||
|
||||
int fork(void) {
|
||||
return SET_ERRNO(int, ASM_SYSCALL0(SYSCALL_NR_FORK));
|
||||
}
|
||||
|
||||
int execve(const char *filename, const char *const argv[], const char *const envp[]) {
|
||||
return SET_ERRNO(int, ASM_SYSCALL3(SYSCALL_NR_EXECVE, filename, argv, envp));
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) void exit(int code) {
|
||||
(void) ASM_SYSCALL1(SYSCALL_NR_EXIT, code);
|
||||
while (1);
|
||||
}
|
||||
|
||||
int kill(int pid, int signum) {
|
||||
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NR_KILL, pid, signum));
|
||||
}
|
||||
|
||||
void __kernel_signal(uintptr_t entry) {
|
||||
(void) ASM_SYSCALL1(SYSCALL_NRX_SIGNAL, entry);
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) void __kernel_sigret(void) {
|
||||
(void) ASM_SYSCALL0(SYSCALL_NRX_SIGRET);
|
||||
while (1);
|
||||
}
|
||||
|
||||
int getpid(void) {
|
||||
return ASM_SYSCALL0(SYSCALL_NR_GETPID);
|
||||
}
|
||||
|
||||
int chdir(const char *filename) {
|
||||
return SET_ERRNO(int, ASM_SYSCALL1(SYSCALL_NR_CHDIR, filename));
|
||||
}
|
||||
|
||||
char *getcwd(char *buf, size_t lim) {
|
||||
if (SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NR_GETCWD, buf, lim)) == 0) {
|
||||
return buf;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NR_NANOSLEEP, req, rem));
|
||||
}
|
||||
|
||||
int openpty(int *master, int *slave) {
|
||||
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NRX_OPENPTY, master, slave));
|
||||
}
|
||||
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz) {
|
||||
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NR_GETTIMEOFDAY, tv, tz));
|
||||
}
|
||||
|
||||
int reboot(int magic1, int magic2, unsigned int cmd, void *arg) {
|
||||
return SET_ERRNO(int, ASM_SYSCALL4(SYSCALL_NR_REBOOT, magic1, magic2, cmd, arg));
|
||||
}
|
||||
|
||||
int access(const char *filename, int mode) {
|
||||
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NR_ACCESS, filename, mode));
|
||||
}
|
||||
|
||||
int waitpid(int pid, int *status) {
|
||||
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NRX_WAITPID, pid, status));
|
||||
}
|
||||
|
||||
// Although sbrk() is implemented in userspace, I guess it should also be here
|
||||
void *sbrk(intptr_t inc) {
|
||||
if (inc == 0) {
|
||||
return __cur_brk;
|
||||
}
|
||||
|
||||
void *new_brk = (void *) ((uintptr_t) __cur_brk + inc);
|
||||
|
||||
if (brk(new_brk) != 0) {
|
||||
return __cur_brk;
|
||||
} else {
|
||||
return __cur_brk = new_brk;
|
||||
}
|
||||
}
|
7
libc/time.c
Normal file
7
libc/time.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include "time.h"
|
||||
#include "bits/syscall.h"
|
||||
|
||||
int usleep(long us) {
|
||||
struct timespec tv = { us / 1000000, (us % 1000) * 1000 };
|
||||
return nanosleep(&tv, NULL);
|
||||
}
|
255
libc/vsnprintf.c
Normal file
255
libc/vsnprintf.c
Normal file
@ -0,0 +1,255 @@
|
||||
#include "bits/printf.h"
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
union printfv {
|
||||
int value_int;
|
||||
unsigned int value_uint;
|
||||
long value_long;
|
||||
uint32_t value_uint32;
|
||||
uint64_t value_uint64;
|
||||
uintptr_t value_ptr;
|
||||
const char *value_str;
|
||||
};
|
||||
|
||||
static const char *s_print_xs_set0 = "0123456789abcdef";
|
||||
static const char *s_print_xs_set1 = "0123456789ABCDEF";
|
||||
|
||||
static int vsnprintf_ds(int64_t x, char *res, int s, int sz) {
|
||||
if (!x) {
|
||||
res[0] = '0';
|
||||
res[1] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int c;
|
||||
uint64_t v;
|
||||
|
||||
if (sz) {
|
||||
if (s && x < 0) {
|
||||
v = (uint64_t) -x;
|
||||
} else {
|
||||
s = 0;
|
||||
v = (uint64_t) x;
|
||||
}
|
||||
} else {
|
||||
if (s && ((int32_t) x) < 0) {
|
||||
v = (uint64_t) -((int32_t) x);
|
||||
} else {
|
||||
s = 0;
|
||||
v = (uint64_t) x;
|
||||
}
|
||||
}
|
||||
|
||||
c = 0;
|
||||
|
||||
while (v) {
|
||||
res[c++] = '0' + v % 10;
|
||||
v /= 10;
|
||||
}
|
||||
|
||||
if (s) {
|
||||
res[c++] = '-';
|
||||
}
|
||||
|
||||
res[c] = 0;
|
||||
|
||||
for (int i = 0, j = c - 1; i < j; ++i, --j) {
|
||||
res[i] ^= res[j];
|
||||
res[j] ^= res[i];
|
||||
res[i] ^= res[j];
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static int vsnprintf_xs(uint64_t v, char *res, const char *set) {
|
||||
if (!v) {
|
||||
res[0] = '0';
|
||||
res[1] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int c = 0;
|
||||
|
||||
while (v) {
|
||||
res[c++] = set[v & 0xF];
|
||||
v >>= 4;
|
||||
}
|
||||
|
||||
res[c] = 0;
|
||||
|
||||
for (int i = 0, j = c - 1; i < j; ++i, --j) {
|
||||
res[i] ^= res[j];
|
||||
res[j] ^= res[i];
|
||||
res[i] ^= res[j];
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int vsnprintf(char *buf, size_t len, const char *fmt, va_list args) {
|
||||
union printfv val;
|
||||
char cbuf[64];
|
||||
size_t p = 0;
|
||||
// padn > 0:
|
||||
// --------vvvvv
|
||||
// padn < 0:
|
||||
// vvvv----------
|
||||
int padn;
|
||||
char padc;
|
||||
int pads;
|
||||
int clen;
|
||||
char c;
|
||||
|
||||
#define __putc(ch) \
|
||||
if (p == len - 1) { \
|
||||
goto __end; \
|
||||
} else { \
|
||||
buf[p++] = ch; \
|
||||
}
|
||||
|
||||
#define __puts(s, l) \
|
||||
if (padn >= 0) { \
|
||||
if (l < padn) { \
|
||||
size_t padd = padn - l; \
|
||||
if (p + padd < len + 1) { \
|
||||
memset(buf + p, padc, padd); \
|
||||
p += padd; \
|
||||
} else { \
|
||||
memset(buf + p, padc, len - 1 - p); \
|
||||
p = len - 1; \
|
||||
goto __end; \
|
||||
} \
|
||||
} \
|
||||
if (p + l < len + 1) { \
|
||||
strncpy(buf + p, s, l); \
|
||||
p += l; \
|
||||
} else { \
|
||||
strncpy(buf + p, s, len - 1 - p); \
|
||||
p = len - 1; \
|
||||
goto __end; \
|
||||
} \
|
||||
} else { \
|
||||
padn = -padn; \
|
||||
if (p + l < len + 1) { \
|
||||
strncpy(buf + p, s, l); \
|
||||
p += l; \
|
||||
} else { \
|
||||
strncpy(buf + p, s, len - 1 - p); \
|
||||
p = len - 1; \
|
||||
goto __end; \
|
||||
} \
|
||||
if (l < padn) { \
|
||||
size_t padd = padn - l; \
|
||||
if (p + padd < len + 1) { \
|
||||
memset(buf + p, padc, padd); \
|
||||
p += padd; \
|
||||
} else { \
|
||||
memset(buf + p, padc, len - 1 - p); \
|
||||
p = len - 1; \
|
||||
goto __end; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
while ((c = *fmt)) {
|
||||
switch (c) {
|
||||
case '%':
|
||||
c = *++fmt;
|
||||
padn = 0;
|
||||
padc = ' ';
|
||||
pads = 1;
|
||||
|
||||
if (c == '0') {
|
||||
padc = c;
|
||||
c = *++fmt;
|
||||
}
|
||||
if (c == '-') {
|
||||
pads = -1;
|
||||
c = *++fmt;
|
||||
}
|
||||
|
||||
while (c >= '0' && c <= '9') {
|
||||
padn *= 10;
|
||||
padn += c - '0';
|
||||
c = *++fmt;
|
||||
}
|
||||
|
||||
padn *= pads;
|
||||
|
||||
switch (c) {
|
||||
case 'l':
|
||||
// Not supported
|
||||
return -1;
|
||||
|
||||
case 's':
|
||||
if ((val.value_str = va_arg(args, const char *))) {
|
||||
__puts(val.value_str, strlen(val.value_str));
|
||||
} else {
|
||||
__puts("(null)", 6);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
val.value_ptr = va_arg(args, uintptr_t);
|
||||
__putc('0');
|
||||
__putc('x');
|
||||
padn = sizeof(uintptr_t) * 2;
|
||||
padc = '0';
|
||||
clen = vsnprintf_xs(val.value_ptr, cbuf, s_print_xs_set0);
|
||||
__puts(cbuf, clen);
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
case 'd':
|
||||
val.value_int = va_arg(args, int);
|
||||
clen = vsnprintf_ds(val.value_int, cbuf, 1, 1);
|
||||
__puts(cbuf, clen);
|
||||
break;
|
||||
case 'u':
|
||||
val.value_uint = va_arg(args, unsigned int);
|
||||
clen = vsnprintf_ds(val.value_uint, cbuf, 0, 1);
|
||||
__puts(cbuf, clen);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
val.value_uint32 = va_arg(args, uint32_t);
|
||||
clen = vsnprintf_xs(val.value_uint32, cbuf, s_print_xs_set0);
|
||||
__puts(cbuf, clen);
|
||||
break;
|
||||
case 'X':
|
||||
val.value_uint32 = va_arg(args, uint32_t);
|
||||
clen = vsnprintf_xs(val.value_uint32, cbuf, s_print_xs_set1);
|
||||
__puts(cbuf, clen);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
val.value_int = va_arg(args, int);
|
||||
__putc(val.value_int);
|
||||
break;
|
||||
|
||||
default:
|
||||
__putc('%');
|
||||
__putc(c);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
__putc(c);
|
||||
break;
|
||||
}
|
||||
|
||||
++fmt;
|
||||
}
|
||||
|
||||
#undef __puts
|
||||
#undef __putc
|
||||
|
||||
__end:
|
||||
buf[p] = 0;
|
||||
return p;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user