├── README ├── .gitmodules ├── .gdbinit ├── tarfs ├── src │ ├── loop.c │ ├── hello.c │ ├── echo.c │ ├── env.c │ ├── name.c │ ├── pagefault.c │ ├── debug.c │ ├── terminal_src │ │ ├── keyboard.h │ │ ├── Rules.mk │ │ ├── terminal.h │ │ ├── main.c │ │ ├── keyboard.c │ │ └── terminal.c │ ├── signal.c │ ├── ls.c │ ├── init.c │ ├── Rules.mk │ ├── escape.c │ └── sh.c └── hello.txt ├── util ├── decode ├── bochsrc.txt ├── colorize.sh ├── colormake ├── qemul.sh ├── common.sh └── makedisk.sh ├── kernel ├── include │ ├── keyboard.h │ ├── debug.h │ ├── synch.h │ ├── version.h │ ├── serial.h │ ├── signals.h │ ├── pmm.h │ ├── timer.h │ ├── common.h │ ├── scheduler.h │ ├── k_heap.h │ ├── trees.h │ ├── Link.ld │ ├── tarfs.h │ ├── procmm.h │ ├── k_debug.h │ ├── lists.h │ ├── arch.h │ ├── thread.h │ ├── elf.h │ ├── multiboot.h │ ├── process.h │ ├── vmm.h │ ├── k_syscall.h │ ├── vfs.h │ └── idt.h ├── arch │ ├── synch.S │ ├── int.S │ └── idt.c ├── boot │ ├── version.c │ ├── boot.S │ └── kinit.c ├── syscall │ ├── sys_debug.c │ ├── sys_system.c │ ├── sys_mem.c │ ├── syscall.c │ ├── sys_process.c │ └── sys_fs.c ├── drivers │ ├── timer.c │ ├── serial.c │ ├── keyboard.c │ └── debug.c ├── Rules.mk ├── fs │ ├── debug_dev.c │ ├── pipes.c │ ├── tarfs.c │ └── vfs.c ├── proc │ ├── scheduler.c │ ├── thread.c │ ├── elf.c │ ├── process.c │ └── signals.c ├── fault │ └── page_fault.c └── mem │ ├── pmm.c │ └── vmm.c ├── toolchain ├── myos │ ├── crt0.S │ ├── configure.ac │ ├── include │ │ ├── sys │ │ │ └── dirent.h │ │ └── syscalls.h │ ├── Makefile.am │ ├── dirent.c │ ├── syscall.S │ └── syscalls.c ├── Rules.mk ├── newlib.patch ├── gcc.patch ├── binutils.patch ├── rebuild_toolchain.sh └── rebuild_newlib.sh ├── .lvimrc ├── Rules.mk └── Makefile /README: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.gdbinit: -------------------------------------------------------------------------------- 1 | file build/kernel/kernel 2 | target remote localhost:1234 3 | 4 | -------------------------------------------------------------------------------- /tarfs/src/loop.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | for(;;); 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /tarfs/hello.txt: -------------------------------------------------------------------------------- 1 | Hi. 2 | 3 | This is a file in the tarfs file system. 4 | 5 | New row! 6 | -------------------------------------------------------------------------------- /util/decode: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | i586-pc-myos-objdump -S $1 | vim -R - "+set ft=cmix" 4 | -------------------------------------------------------------------------------- /tarfs/src/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | 6 | printf("Hello, world!"); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /kernel/include/keyboard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define KBD_DATA_PORT 0x60 4 | #define KBD_STATUS_PORT 0x64 5 | 6 | void keyboard_init(); 7 | -------------------------------------------------------------------------------- /util/bochsrc.txt: -------------------------------------------------------------------------------- 1 | display_library: x, options="gui_debug" 2 | ata0-master: type=disk, path="image.img", translation=lba, cylinders=325, heads=2, spt=63 3 | boot: disk 4 | -------------------------------------------------------------------------------- /tarfs/src/echo.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) 4 | { 5 | int i; 6 | for(i = 1; i < argc; i++) 7 | printf("%s ", argv[i]); 8 | printf("\n"); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /toolchain/myos/crt0.S: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_MODE 2 | .global _start 3 | .extern _init 4 | .extern _exit 5 | _start: 6 | push %ecx 7 | call _init 8 | call _exit 9 | .wait: hlt 10 | jmp .wait 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /kernel/include/debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef __ASSEMBLER__ 4 | 5 | #define BREAK asm volatile ("xchg %bx, %bx;"); 6 | 7 | #endif 8 | #ifdef __ASSEMBLER__ 9 | 10 | #define BREAK xchg bx, bx 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /toolchain/myos/configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ(2.59) 2 | AC_INIT([newlib], [NEWLIB_VERSION]) 3 | AC_CONFIG_SRCDIR([crt0.S]) 4 | AC_CONFIG_AUX_DIR(../../../..) 5 | NEWLIB_CONFIGURE(../../..) 6 | AC_CONFIG_FILES([Makefile]) 7 | AC_OUTPUT 8 | -------------------------------------------------------------------------------- /kernel/arch/synch.S: -------------------------------------------------------------------------------- 1 | # Bussy waiting for now... 2 | .global spin_lock 3 | 4 | spin_lock: 5 | mov 4(%esp), %edx 6 | mov $0, %eax 7 | mov $1, %ecx 8 | .retry: 9 | xor %eax, %eax 10 | lock cmpxchg %cl, (%edx) 11 | jnz .retry 12 | 13 | ret 14 | -------------------------------------------------------------------------------- /tarfs/src/env.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | extern char **environ; 7 | 8 | int i = 0; 9 | while(environ[i]) 10 | { 11 | printf("%s\n",environ[i]); 12 | i++; 13 | } 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /kernel/include/synch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __ASSEMBLER__ 4 | 5 | #else 6 | 7 | #include 8 | 9 | typedef uintptr_t semaphore_t; 10 | 11 | void spin_lock(semaphore_t *lock); 12 | 13 | #define spin_unlock(addr) (*(addr)=0) 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /kernel/include/version.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | char * __kernel_git_hash; 4 | char * __kernel_git_date; 5 | int __kernel_git_dirty; 6 | char * __kernel_git_message; 7 | char * __kernel_git_branch; 8 | 9 | char * __kernel_build_date; 10 | char * __kernel_build_time; 11 | 12 | -------------------------------------------------------------------------------- /kernel/include/serial.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define SERIAL_COM1 0x3f8 4 | #define SERIAL_COM2 0x2f8 5 | #define SERIAL_COM3 0x3e8 6 | #define SERIAL_COM4 0x2e8 7 | 8 | void init_serial(short port); 9 | void serial_send(short port, char c); 10 | void serial_debug(char *str, ...); 11 | -------------------------------------------------------------------------------- /kernel/include/signals.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | 6 | int signal_process(int pid, int signum); 7 | sig_t switch_handler(int signum, sig_t handler); 8 | void return_from_signal(registers_t *r); 9 | thread_t *handle_signals(thread_t *th); 10 | -------------------------------------------------------------------------------- /tarfs/src/name.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | char name[128]; 7 | printf("Hi! What's your name?\n"); 8 | fgets(name, 128, stdin); 9 | int len = strlen(name); 10 | name[len-1] = '\0'; 11 | printf("Hello, %s.", name); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /tarfs/src/pagefault.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, const char *argv[]) 4 | { 5 | (void)argc; 6 | (void)argv; 7 | 8 | char *string = (char *)0x12345678; 9 | 10 | printf("Causing page fault!\n"); 11 | sprintf(string, "Page fault!"); 12 | printf("Page fault caused.\n"); 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /tarfs/src/debug.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char **argv) 10 | { 11 | (void)argc; 12 | _syscall_pdbg(); 13 | execvp(argv[1], &argv[1]); 14 | return 1; 15 | } 16 | -------------------------------------------------------------------------------- /tarfs/src/terminal_src/keyboard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define SCANCODE_CTRL 0x1D 4 | #define SCANCODE_LSHIFT 0x2A 5 | #define SCANCODE_RSHIFT 0x36 6 | #define SCANCODE_ALT 0x38 7 | #define SCANCODE_CAPSLOCK 0x3A 8 | 9 | int kbd_shift; 10 | int kbd_ctrl; 11 | int kbd_alt; 12 | 13 | void keyboard_init(); 14 | unsigned char keyboard_decode(unsigned char scancode); 15 | -------------------------------------------------------------------------------- /kernel/boot/version.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | char * __kernel_git_hash = GITHASH; 5 | char * __kernel_git_date = GITDATE; 6 | int __kernel_git_dirty = GITDIRTY; 7 | char * __kernel_git_message = GITMESSAGE; 8 | char * __kernel_git_branch = GITBRANCH; 9 | 10 | char * __kernel_build_date = __DATE__; 11 | char * __kernel_build_time = __TIME__; 12 | -------------------------------------------------------------------------------- /kernel/include/pmm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #define PAGE_MASK 0xFFFFF000 6 | #define PAGE_FLAG_MASK 0xFFF 7 | #define PAGE_SIZE 0x1000 8 | #define PMM_STACK_ENTRIES_PER_PAGE 0x400 9 | 10 | #ifndef __ASSEMBLER__ 11 | 12 | uintptr_t pmm_alloc_page(); 13 | void pmm_free_page(uintptr_t page); 14 | void pmm_init(mboot_info_t *mboot); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /tarfs/src/terminal_src/Rules.mk: -------------------------------------------------------------------------------- 1 | sp := $(sp).x 2 | dirstack_$(sp) := $(d) 3 | d := $(dir) 4 | 5 | OBJS_$(d) := $(call findsource,$(d),c,5,$(builddir)) 6 | DEPS_$(d) := $(patsubst %,%.d,$(TGTS_$(d))) 7 | 8 | terminal_$(d) := $(builddir)/tarfs/src/terminal 9 | TAR_TGTS += $(terminal_$(d)) 10 | 11 | $(terminal_$(d)): $(OBJS_$(d)) 12 | $(LINK) 13 | 14 | d := $(dirstack_$(sp)) 15 | sp :=$(basename $(sp)) 16 | -------------------------------------------------------------------------------- /kernel/include/timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define PIT_CMD_PORT 0x43 6 | #define PIT_CH0_DATA_PORT 0x40 7 | 8 | #define PIT_USE_CH0 0x00 9 | #define PIT_ACCESS_LOHI 0x30 10 | #define PIT_MODE_3 0x06 11 | 12 | #define PIT_DIVISOR_CONST 1193180 13 | 14 | #ifndef __ASSEMBLER__ 15 | 16 | void timer_init(uint32_t freq); 17 | registers_t *timer_tick(registers_t *r); 18 | 19 | #endif 20 | 21 | -------------------------------------------------------------------------------- /kernel/include/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef __ASSEMBLER__ 4 | 5 | #define min(x,y) \ 6 | ({__typeof__(x) x_ = (x); \ 7 | __typeof__(y) y_ = (y); \ 8 | (x_ < y_)?x_:y_; }) 9 | 10 | #define max(x,y) \ 11 | ({__typeof__(x) x_ = (x); \ 12 | __typeof__(y) y_ = (y); \ 13 | (x_ > y_)?x_:y_; }) 14 | 15 | #define swap(x,y) \ 16 | ({ __typeof__(x) temp_ = (x); \ 17 | x = y; \ 18 | y = temp_; }) 19 | 20 | #define TRUE 1 21 | #define FALSE 0 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /toolchain/myos/include/sys/dirent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | typedef struct dirent { 5 | uint32_t ino; 6 | char name[256]; 7 | } dirent; 8 | 9 | typedef struct DIR { 10 | int fd; 11 | int cur_entry; 12 | } DIR; 13 | 14 | DIR *opendir(const char *dirname); 15 | int closedir(DIR *dirp); 16 | struct dirent *readdir(DIR *dirp); 17 | int dirfd(DIR *dirp); 18 | void rewinddir(DIR *dirp); 19 | void seekdir(DIR *dirp, int pos); 20 | int telldir(DIR *dirp); 21 | -------------------------------------------------------------------------------- /util/colorize.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | C_NO=`echo -e "\\033[0m"` 4 | C_RED=`echo -e "\\033[31m"` 5 | C_GREEN=`echo -e "\\033[32m"` 6 | C_YELLOW=`echo -e "\\033[33m"` 7 | C_BLUE=`echo -e "\\033[36m"` 8 | 9 | while read line; do 10 | echo $line | sed \ 11 | -e "s/\(\[info\]\)/${C_BLUE}\1${C_NO}/" \ 12 | -e "s/\(\[status\]\)/${C_GREEN}\1${C_NO}/" \ 13 | -e "s/\(\[warning\]\)/${C_YELLOW}\1${C_NO}/" \ 14 | -e "s/\(\[error\]\)/${C_RED}\1${C_NO}/" 15 | done 16 | 17 | -------------------------------------------------------------------------------- /tarfs/src/signal.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int kill(pid_t pid, int sig); 6 | 7 | int variable = 1; 8 | void handler(int a) 9 | { 10 | variable = 2; 11 | printf("Signal handler got %d\n", a); 12 | fflush(stdout); 13 | } 14 | 15 | int main() 16 | { 17 | printf("Registering signal handler\n"); 18 | signal(2, &handler); 19 | printf("Sending kill request\n"); 20 | kill(getpid(), 2); 21 | printf("Variable=%d\n", variable); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /kernel/syscall/sys_debug.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | KDEF_SYSCALL(printf, r) 9 | { 10 | process_stack stack = init_pstack(); 11 | 12 | spin_lock(&debug_sem); 13 | debug((char *)stack[0], stack[1], stack[2], stack[3], stack[4], stack[5], stack[6]); 14 | debug("<%x:%x>", current->proc->pid, current->tid); 15 | spin_unlock(&debug_sem); 16 | r->edx = SYSCALL_OK; 17 | return r; 18 | } 19 | -------------------------------------------------------------------------------- /toolchain/Rules.mk: -------------------------------------------------------------------------------- 1 | sp := $(sp).x 2 | dirstack_$(sp) := $(d) 3 | d := $(dir) 4 | 5 | PREFIX=/usr/local/Cellar/osdev/1.0 6 | TARGET=i586-pc-myos 7 | export PREFIX TARGET 8 | 9 | TGT_LIB := $(PREFIX)/$(TARGET)/lib/libc.a 10 | TGT_TOOLCHAIN := /usr/local/bin/$(TARGET)-gcc 11 | 12 | OBJS_$(d) := $(shell find $(d)/myos -name "*") 13 | 14 | $(TGT_LIB): $(OBJS_$(d)) 15 | toolchain/rebuild_newlib.sh force 16 | 17 | $(TGT_TOOLCHAIN): 18 | toolchain/rebuild_toolchain.sh 19 | 20 | d := $(dirstack_$(sp)) 21 | sp := $(basename $(sp)) 22 | -------------------------------------------------------------------------------- /tarfs/src/ls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) 6 | { 7 | DIR *dirp; 8 | if(argc > 1) 9 | dirp = opendir(argv[1]); 10 | else 11 | dirp = opendir("/"); 12 | if(!dirp) 13 | { 14 | printf("ls: %s : No such directory\n", argv[1]); 15 | return 1; 16 | } 17 | rewinddir(dirp); 18 | struct dirent *de; 19 | printf("ls:\n"); 20 | while((de = readdir(dirp))) 21 | printf("%s\n", de->name); 22 | closedir(dirp); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /tarfs/src/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | extern char **environ; 9 | 10 | int main() 11 | { 12 | setenv("HOME","/",1); 13 | setenv("PATH","/bin:/usr/sbin:/bin",1); 14 | 15 | while(1) 16 | { 17 | int pid = fork(); 18 | if(pid) 19 | { 20 | _syscall_waitpid(pid); 21 | } else { 22 | char *command[] = {"/bin/terminal", "/bin/sh", 0}; 23 | execve(command[0], command, environ); 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /util/colormake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | C_NO=`echo -e "\\033[0m"` 4 | C_RED=`echo -e "\\033[31m"` 5 | C_GREEN=`echo -e "\\033[32m"` 6 | C_YELLOW=`echo -e "\\033[33m"` 7 | C_BLUE=`echo -e "\\033[36m"` 8 | 9 | function colorize() { 10 | exec $@ | sed \ 11 | -e "s/\(^make[^ ]*\)/${C_BLUE}\1${C_NO}/" \ 12 | -e "s/\(.* [Ee]rror:\)/${C_RED}\1${C_NO}/" \ 13 | -e "s/\(.* [Ww]arning:\)/${C_YELLOW}\1${C_NO}/" 14 | } 15 | 16 | if [ "$1" = "log" ]; then 17 | colorize cat errors.log 18 | else 19 | exec make "$@" 2> >( colorize tee errors.log ) 20 | fi 21 | 22 | -------------------------------------------------------------------------------- /kernel/include/scheduler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #ifndef __ASSEMBLER__ 5 | 6 | typedef struct 7 | { 8 | struct thread_struct *prev; 9 | struct thread_struct *next; 10 | } thread_list_t; 11 | 12 | void scheduler_insert(thread_t *th); 13 | void scheduler_cheat(thread_t *th); 14 | void scheduler_remove(thread_t *th); 15 | thread_t *scheduler_next(); 16 | void scheduler_init(); 17 | 18 | void scheduler_list(list_head_t *list); 19 | 20 | void scheduler_sleep(thread_t *th, list_head_t *list); 21 | void scheduler_wake(list_head_t *list); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /kernel/include/k_heap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #ifndef __ASSEMBLER__ 5 | 6 | typedef struct heap_header_struct 7 | { 8 | struct heap_header_struct *prev, *next; 9 | uint32_t allocated : 1; 10 | uint32_t size : 31; 11 | } chunk_t; 12 | 13 | #define chunk_head(a) ((chunk_t *)((uint32_t)a-sizeof(chunk_t))) 14 | #define chunk_data(c) ((void *)((uint32_t)c + sizeof(chunk_t))) 15 | 16 | void *kmalloc(uint32_t size); 17 | void *kcalloc(uint32_t size); 18 | void *kvalloc(uint32_t size); 19 | void kfree(void *a); 20 | 21 | int kheap_setup; 22 | 23 | #endif 24 | 25 | -------------------------------------------------------------------------------- /.lvimrc: -------------------------------------------------------------------------------- 1 | let $SCRPATH=expand(":p:h") 2 | set path=$SCRPATH/**,/usr/local/Cellar/osdev/1.0/i586-pc-myos/include 3 | 4 | let NERDTreeIgnore = ['\.o$'] 5 | 6 | 7 | let g:syntastic_c_include_dirs = [ '/usr/local/Cellar/osdev/1.0/i586-pc-myos/include', 'kernel/include' ] 8 | "let g:syntastic_c_checker = 'clang -fsyntax-only -Wall -Wextra -pedantic' 9 | let g:syntastic_c_compiler = 'clang' 10 | let g:syntastic_c_compiler_options = '-fsyntax-only -Wall -Wextra -pedantic -Wno-gnu -m32' 11 | let g:syntastic_c_check_header = 1 12 | 13 | call unite#custom#source('file_rec/async', 'ignore_pattern', 'newlib\|build') 14 | call unite#custom#source('file_rec', 'ignore_pattern', 'newlib\|build') 15 | -------------------------------------------------------------------------------- /kernel/include/trees.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef __ASSEMBLER__ 3 | 4 | #include 5 | #include 6 | 7 | typedef struct tree_node 8 | { 9 | void *item; 10 | list_head_t children; 11 | struct tree_node *parent; 12 | list_t siblings; 13 | } tree_node_t; 14 | 15 | typedef struct 16 | { 17 | tree_node_t *root; 18 | } tree_t; 19 | 20 | #define init_tree(tree) \ 21 | tree.root=(tree_node_t *)0; 22 | 23 | #define init_tree_node(node) \ 24 | init_list(node->children); \ 25 | init_list(node->siblings); \ 26 | node->parent = 0; 27 | 28 | #define tree_make_child(par, chl) \ 29 | chl->parent = par; \ 30 | append_to_list(par->children, chl->siblings) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /toolchain/myos/Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = cygnus dejagnu 2 | INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS) 3 | AM_CCASFLAGS = $(INCLUDES) 4 | 5 | noinst_LIBRARIES = lib.a 6 | 7 | if MAY_SUPPLY_SYSCALLS 8 | extra_objs = $(lpfx)syscalls.o $(lpfx)syscall.o $(lpfx)dirent.o 9 | else 10 | extra_objs = 11 | endif 12 | 13 | lib_a_SOURCES = 14 | lib_a_LIBADD = $(extra_objs) 15 | EXTRA_lib_a_SOURCES = syscalls.c crt0.S syscall.S dirent.c 16 | lib_a_DEPENDENCIES = $(extra_objs) 17 | lib_a_CCASFLAGS = $(AM_CCASFLAGS) 18 | lib_a_CFLAGS = $(AM_CFLAGS) 19 | 20 | if MAY_SUPPLY_SYSCALLS 21 | all: crt0.o 22 | endif 23 | 24 | ACLOCAL_AMFLAGS = -I ../../.. 25 | CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host 26 | -------------------------------------------------------------------------------- /kernel/include/Link.ld: -------------------------------------------------------------------------------- 1 | ENTRY(start) 2 | 3 | SECTIONS { 4 | . = 0xC0100000; 5 | .text : AT(ADDR(.text) - 0xC0000000) 6 | { 7 | code = .; 8 | *(.text) 9 | . = ALIGN(4096); 10 | } 11 | .rodata : AT(ADDR(.rodata) - 0xC0000000) 12 | { 13 | rodata = .; 14 | *(.rodata*) 15 | . = ALIGN(4096); 16 | } 17 | .data : AT(ADDR(.data) - 0xC0000000) 18 | { 19 | data = .; 20 | *(.data) 21 | . = ALIGN(4096); 22 | } 23 | .eh_frame : AT(ADDR(.eh_frame) - 0xC0000000) 24 | { 25 | eh_frame = .; 26 | *(.eh_frame) 27 | . = ALIGN(4096); 28 | } 29 | .bss : AT(ADDR(.bss) - 0xC0000000) 30 | { 31 | bss = .; 32 | *(.bss) 33 | . = ALIGN(4096); 34 | } 35 | 36 | _end = .; 37 | } 38 | -------------------------------------------------------------------------------- /tarfs/src/terminal_src/terminal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #define NUM_TERM 8 6 | 7 | struct terminal 8 | { 9 | int32_t rows; 10 | int32_t cols; 11 | int32_t csr_row; 12 | int32_t csr_col; 13 | uint16_t *buffer; 14 | uint8_t fg_color; 15 | uint8_t bg_color; 16 | uint8_t current_style; 17 | int read_fd[2]; 18 | FILE *read_pipe[2]; 19 | int write_fd[2]; 20 | FILE *write_pipe[2]; 21 | int pid; 22 | }; 23 | 24 | uint16_t *vidmem; 25 | struct terminal *vterm[NUM_TERM]; 26 | uint32_t active_vterm; 27 | 28 | void copybuffer(struct terminal *t); 29 | struct terminal *new_terminal(uint32_t rows, uint32_t cols, char **argv); 30 | void terminal_putch(struct terminal *t, char c); 31 | void terminal_init(int num, uint32_t rows, uint32_t cols, char **argv); 32 | void screen_init(); 33 | -------------------------------------------------------------------------------- /tarfs/src/Rules.mk: -------------------------------------------------------------------------------- 1 | sp := $(sp).x 2 | dirstack_$(sp) := $(d) 3 | d := $(dir) 4 | 5 | TAR_TGTS := 6 | 7 | dir := $(d)/terminal_src 8 | include $(dir)/Rules.mk 9 | 10 | TGT_TARFS := $(builddir)/tarfs.tar 11 | 12 | OBJS_$(d) := $(call findsource,$(d),c,1,$(builddir)) 13 | TGTS_$(d) := $(patsubst %.o,%,$(OBJS_$(d))) 14 | DEPS_$(d) := $(patsubst %,%.d,$(TGTS_$(d))) 15 | TAR_TGTS += $(TGTS_$(d)) 16 | 17 | CLEAN := $(CLEAN) $(TGTS_$(d)) $(TGT_TARFS) 18 | CLEAN += $(addprefix tarfs/bin/, $(notdir $(TGTS_$(d)))) $(DEPS_$(d)) 19 | 20 | $(TGT_TARFS): $(TAR_TGTS) 21 | @mkdir -p tarfs/bin 22 | @mkdir -p tarfs/dev 23 | @mkdir -p tarfs/mnt 24 | @mkdir -p tarfs/mnt/tarfs 25 | cp $^ tarfs/bin 26 | tar -cf build/tarfs.tar tarfs/* 27 | 28 | ifneq ($(MAKECMDGOALS),clean) 29 | -include $(DEPS_$(d)) 30 | endif 31 | d := $(dirstack_$(sp)) 32 | sp := $(basename $(sp)) 33 | -------------------------------------------------------------------------------- /kernel/drivers/timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | uint32_t ticks; 8 | 9 | void timer_init(uint32_t freq) 10 | { 11 | // Enables the PIT with frequency freq 12 | 13 | ticks = 0; 14 | 15 | register_int_handler(IRQ2INT(IRQ_TIMER), timer_tick); 16 | 17 | outb(PIT_CMD_PORT, PIT_USE_CH0 | PIT_ACCESS_LOHI | PIT_MODE_3); 18 | uint32_t divisor = PIT_DIVISOR_CONST/freq; 19 | outb(PIT_CH0_DATA_PORT, (divisor & 0xFF)); 20 | outb(PIT_CH0_DATA_PORT, ((divisor >> 8) & 0xFF)); 21 | } 22 | 23 | registers_t *timer_tick(registers_t *r) 24 | { 25 | // This should be kept as short as possible unless scheduling is 26 | // needed. 27 | // 28 | // Actually, this kind of needs a reworking and some planning... 29 | 30 | ticks ++; 31 | if(ticks %10 == 0) 32 | { 33 | schedule(); 34 | } 35 | return r; 36 | } 37 | -------------------------------------------------------------------------------- /util/qemul.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # if tmux info | grep $TTY ; then 4 | if [[ -n $TMUX ]]; then 5 | echo > serial.out 6 | # tmux split-window -h 'qemu-system-i386 -kernel build/kernel/kernel -initrd "build/tarfs.tar" -curses -monitor telnet:localhost:4444,server -s -S -serial file:serial.out' 7 | # tmux split-window -h 'qemu-system-i386 -hda image.img -curses -monitor telnet:localhost:4444,server -s -S -serial file:serial.out' 8 | tmux split-window -dh -t 0 'sleep 1; i586-elf-gdb' 9 | tmux split-window -dv -t 0 'tail -f serial.out | util/colorize.sh' 10 | # qemu-system-i386 -hda image.img -vnc :1 -monitor stdio -s -S -serial file:serial.out 11 | qemu-system-i386 -hda image.img -vnc :5500,reverse -monitor stdio -s -S -serial file:serial.out 12 | tmux kill-pane -a -t 0 13 | 14 | else 15 | qemu-system-i386 -kernel build/kernel/kernel -initrd "build/tarfs.tar" -display curses -monitor stdio -s -S 16 | fi 17 | -------------------------------------------------------------------------------- /kernel/syscall/sys_system.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #undef errno 13 | extern int errno; 14 | 15 | 16 | clock_t times(struct tms *buf) 17 | { 18 | (void)buf; 19 | errno = 0; 20 | return -1; 21 | } 22 | KDEF_SYSCALL(times, r) 23 | { 24 | process_stack stack = init_pstack(); 25 | r->eax = times((struct tms *)stack[0]); 26 | r->edx = errno; 27 | return r; 28 | } 29 | 30 | 31 | KDEF_SYSCALL(vidmem, r) 32 | { 33 | new_area(current->proc, 0xB8000, 0xB9000, MM_FLAG_READ | MM_FLAG_WRITE | MM_FLAG_NOSHARE, MM_TYPE_DATA); 34 | pmm_free_page(vmm_page_get(0xB8000)); 35 | vmm_page_set(0xB8000, vmm_page_val(0xB8000, PAGE_PRESENT | PAGE_WRITE | PAGE_USER)); 36 | 37 | r->eax = 0xB8000; 38 | 39 | return r; 40 | } 41 | -------------------------------------------------------------------------------- /kernel/drivers/serial.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void init_serial(short port) 9 | { 10 | outb((short)(port + 1), 0x00); 11 | outb((short)(port + 3), 0x80); 12 | outb((short)(port + 0), 0x03); 13 | outb((short)(port + 1), 0x00); 14 | outb((short)(port + 3), 0x03); 15 | outb((short)(port + 2), 0xC7); 16 | outb((short)(port + 4), 0x0B); 17 | } 18 | 19 | void serial_send(short port, char c) { 20 | while (!(inb((short)(SERIAL_COM1 + 5))&0x20)); 21 | 22 | outb(port, c); 23 | } 24 | 25 | extern int debug_enabled; 26 | void serial_debug(char *str, ...) 27 | { 28 | if(!debug_enabled) 29 | return; 30 | va_list args; 31 | va_start(args, str); 32 | 33 | char *buf; 34 | 35 | vasprintf(&buf, str, args); 36 | unsigned int i; 37 | for(i = 0; i < strlen(buf); i++) 38 | serial_send(SERIAL_COM1, buf[i]); 39 | 40 | free(buf); 41 | va_end(args); 42 | } 43 | 44 | 45 | -------------------------------------------------------------------------------- /tarfs/src/escape.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, const char *argv[]) 4 | { 5 | (void)argc; 6 | (void)argv; 7 | printf("Clearing screen \033[2J\n"); 8 | printf("Right:\033[5Chere\n"); 9 | printf("Left: .\033[5Dhere\n"); 10 | printf("Down:\033[2BUp:\033[1ABack\n"); 11 | printf("Failed code \033[25;34;12x end\n"); 12 | printf("\033[0;3HPosition\n"); 13 | printf("\033[6;0fPosition2\n"); 14 | printf("1234567890\033[3Dc\033[K\n"); 15 | 16 | int i,j; 17 | for(i = 0; i < 8; i++) 18 | { 19 | printf("\033[0m"); 20 | for(j = 0; j < 8; j++) 21 | { 22 | printf("\033[3%d;4%dmX",i,j); 23 | } 24 | printf("\033[0;1m"); 25 | for(j = 0; j < 8; j++) 26 | { 27 | printf("\033[3%d;4%dmX",i,j); 28 | } 29 | printf("\033[0;7m"); 30 | for(j = 0; j < 8; j++) 31 | { 32 | printf("\033[3%d;4%dmX",i,j); 33 | } 34 | printf("\033[0;1;7m"); 35 | for(j = 0; j < 8; j++) 36 | { 37 | printf("\033[3%d;4%dmX",i,j); 38 | } 39 | printf("\n"); 40 | } 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /Rules.mk: -------------------------------------------------------------------------------- 1 | .SUFFIXES: 2 | .SUFFIXES: .c .S .o 3 | 4 | 5 | all: kernel tarfs tags 6 | 7 | ### Modules 8 | dir := toolchain 9 | include $(dir)/Rules.mk 10 | dir := kernel 11 | include $(dir)/Rules.mk 12 | dir := tarfs/src 13 | include $(dir)/Rules.mk 14 | 15 | imagefile := image.img 16 | CLEAN := $(CLEAN) $(imagefile) 17 | .SECONDARY: $(CLEAN) 18 | 19 | ### General targets 20 | .PHONY: kernel tarfs image 21 | kernel: $(TGT_KERNEL) 22 | tarfs: $(TGT_TARFS) 23 | image: $(imagefile) 24 | 25 | image.img: $(TGT_KERNEL) $(TGT_TARFS) 26 | @util/makedisk.sh 27 | 28 | ### Special targets 29 | .PHONY: emul clean tags 30 | emul: $(imagefile) 31 | @util/qemul.sh 32 | clean: 33 | rm -f $(CLEAN) 34 | tags: 35 | ctags -R . 36 | 37 | ### Build rules 38 | $(builddir)/%.o: %.[cS] $(TGT_TOOLCHAIN) $(TGT_LIB) 39 | @mkdir -p $(dir $@) 40 | $(COMP) 41 | %(builddir)/%: %.o $(TGT_TOOLCHAIN) $(TGT_LIB) 42 | @mkdir -p $(dir $@) 43 | $(LINK) 44 | %(builddir)/%: %.c $(TGT_TOOLCHAIN) $(TGT_LIB) 45 | @mkdir -p $(dir $@) 46 | $(COMPLINK) 47 | $(builddir)/%.d: %.[cS] $(TGT_TOOLCHAIN) $(TGT_LIB) 48 | @mkdir -p $(dir $@) 49 | $(DEP) 50 | -------------------------------------------------------------------------------- /toolchain/myos/dirent.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | DIR *opendir(const char *dirname) 10 | { 11 | int fd = open(dirname, O_RDONLY, 0); 12 | if(fd == -1) 13 | return 0; 14 | 15 | DIR *dir = (DIR *)calloc(1, sizeof(DIR)); 16 | dir->fd = fd; 17 | dir->cur_entry = -1; 18 | return dir; 19 | } 20 | int closedir(DIR *dirp) 21 | { 22 | if(dirp->fd) 23 | return close(dirp->fd); 24 | return -1; 25 | } 26 | struct dirent *readdir(DIR *dirp) 27 | { 28 | static struct dirent de; 29 | dirp->cur_entry++; 30 | int ret = _syscall_readdir(dirp->fd, dirp->cur_entry, &de); 31 | if(ret) 32 | { 33 | memset(&de, 0, sizeof(struct dirent)); 34 | return 0; 35 | } 36 | return &de; 37 | } 38 | int dirfd(DIR *dirp) 39 | { 40 | return dirp->fd; 41 | } 42 | void rewinddir(DIR *dirp) 43 | { 44 | dirp->cur_entry = -1; 45 | } 46 | void seekdir(DIR *dirp, int pos) 47 | { 48 | dirp->cur_entry = pos; 49 | } 50 | int telldir(DIR *dirp) 51 | { 52 | return dirp->cur_entry; 53 | } 54 | -------------------------------------------------------------------------------- /kernel/include/tarfs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #ifndef __ASSEMBLER__ 7 | typedef struct 8 | { 9 | unsigned char name[100]; 10 | unsigned char mode[8]; 11 | unsigned char uid[8]; 12 | unsigned char gid[8]; 13 | unsigned char size[12]; 14 | unsigned char mtime[12]; 15 | unsigned char checksum[8]; 16 | unsigned char type[1]; 17 | unsigned char linkname[100]; 18 | unsigned char tar_indicator[6]; 19 | unsigned char tar_version[2]; 20 | unsigned char owner[32]; 21 | unsigned char group[32]; 22 | unsigned char device_major[8]; 23 | unsigned char device_minor[8]; 24 | unsigned char prefix[155]; 25 | }__attribute__((packed)) tar_header_t; 26 | 27 | typedef struct 28 | { 29 | char *name; 30 | tar_header_t *tar; 31 | INODE buffer; 32 | uint32_t users; 33 | } tarfs_entry_t; 34 | 35 | #define TAR_TYPE_FILE 0 36 | #define TAR_TYPE_LINK '1' 37 | #define TAR_TYPE_SYMLINK '2' 38 | #define TAR_TYPE_CHARDEV '3' 39 | #define TAR_TYPE_BLOCKDEV '4' 40 | #define TAR_TYPE_DIR '5' 41 | #define TAR_TYPE_FIFO '6' 42 | #define TAR_TYPE_CONT '7' 43 | 44 | INODE tarfs_init(tar_header_t *tar); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /kernel/Rules.mk: -------------------------------------------------------------------------------- 1 | sp := $(sp).x 2 | dirstack_$(sp) := $(d) 3 | d := $(dir) 4 | 5 | TGT_KERNEL := $(builddir)/kernel/kernel 6 | # Find all source files in the kernel subdirectories 7 | # boot.S and kinit.o should be linked first, so they are added 8 | # separately. 9 | OBJS_$(d) := $(builddir)/kernel/boot/boot.o 10 | OBJS_$(d) += $(builddir)/kernel/boot/kinit.o 11 | OBJS_$(d) += $(call findsource,$(d),S,5,$(builddir)) 12 | OBJS_$(d) += $(call findsource,$(d),c,5,$(builddir)) 13 | DEPS_$(d) := $(patsubst %.o,%.d,$(OBJS_$(d))) 14 | 15 | 16 | CLEAN := $(CLEAN) $(OBJS_$(d)) $(TGT_KERNEL) $(DEPS_$(d)) 17 | 18 | $(OBJS_$(d)) $(DEPS_$(d)): CF_TGT := -I$(d)/include -DKERNEL_MODE 19 | $(TGT_KERNEL): LF_TGT := -nostdlib -T $(d)/include/Link.ld 20 | $(TGT_KERNEL): LL_TGT := -lkernel 21 | 22 | # Add git status to version.o 23 | versionfile := $(builddir)/kernel/boot/version.o 24 | $(versionfile): CF_TGT += $(GITFLAGS) 25 | 26 | # If anything was rebuilt in the kernel, rebuilt version.o again 27 | $(TGT_KERNEL): $(OBJS_$(d)) 28 | $(RM) -f $(versionfile) 29 | $(MAKE) $(versionfile) 30 | $(LINK) 31 | 32 | ifneq ($(MAKECMDGOALS),clean) 33 | -include $(DEPS_$(d)) 34 | endif 35 | d := $(dirstack_$(sp)) 36 | sp := $(basename $(sp)) 37 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ### Common flags 2 | # 3 | CF_ALL = -ggdb -Wall -Wextra -std=gnu99 4 | LF_ALL = 5 | LL_ALL = 6 | 7 | builddir := build 8 | 9 | ### Build commands 10 | CC = i586-pc-myos-gcc 11 | COMP = $(CC) $(CF_ALL) $(CF_TGT) -o $@ -c $< 12 | LINK = $(CC) $(LF_ALL) $(LF_TGT) -o $@ $^ $(LL_TGT) $(LL_ALL) 13 | COMPLINK = $(CC) $(CF_ALL) $(CF_TGT) $(LF_ALL) $(LF_TGT) \ 14 | -o $@ $< $(LL_TGT) $(LL_ALL) 15 | DEP = $(CC) -M $(CF_ALL) $(CF_TGT) $< \ 16 | -o $@ -MT "$(builddir)/$*.o $(builddir)/$*.d" 17 | 18 | ### Git status flags 19 | GITHASH := $(shell git log -1 --pretty="tformat:%h") 20 | GITDATE := $(shell git log -1 --pretty="tformat:%cd") 21 | GITDIRTY := $(shell [[ -n `git status -s 2> /dev/null` ]] && echo 1 || echo 0) 22 | GITMESSAGE := $(shell git log -1 --pretty="tformat:%s") 23 | GITBRANCH := $(shell git log -1 --pretty="tformat:%d") 24 | GITFLAGS := -DGITHASH='"$(GITHASH)"' \ 25 | -DGITDATE='"$(GITDATE)"' \ 26 | -DGITDIRTY='$(GITDIRTY)' \ 27 | -DGITMESSAGE='"$(GITMESSAGE)"' \ 28 | -DGITBRANCH='"$(GITBRANCH)"' 29 | 30 | ### Common functions 31 | # $(call findsource, suffix, dir, depth, builddir) 32 | findsource = $(addprefix $(4)/, \ 33 | $(patsubst %.$(2), %.o, \ 34 | $(shell find $(1) -maxdepth $(3) -name "*.$(2)"))) 35 | 36 | 37 | include Rules.mk 38 | -------------------------------------------------------------------------------- /kernel/fs/debug_dev.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | 9 | int32_t debug_open(INODE ino, uint32_t mode) 10 | { 11 | (void)ino; 12 | (void)mode; 13 | return 0; 14 | } 15 | int32_t debug_close(INODE ino) 16 | { 17 | (void)ino; 18 | return 0; 19 | } 20 | 21 | uint32_t debug_write(INODE node, void *buffer, uint32_t size, uint32_t offset) 22 | { 23 | (void)node; 24 | (void)offset; 25 | char *buf = calloc(size+1, 1); 26 | memcpy(buf, buffer, size); 27 | /* kdbg_puts(buf); */ 28 | serial_debug(buf); 29 | free(buf); 30 | return size; 31 | } 32 | 33 | int32_t debug_stat(INODE node, struct stat *st) 34 | { 35 | (void)node; 36 | memset(st, 0, sizeof(struct stat)); 37 | st->st_mode = S_IFCHR; 38 | return 0; 39 | } 40 | 41 | int32_t debug_isatty(INODE node) 42 | { 43 | (void)node; 44 | return 1; 45 | } 46 | 47 | vfs_driver_t debug_driver = 48 | { 49 | debug_open, 50 | debug_close, 51 | 0, 52 | debug_write, 53 | 0, 54 | 0, 55 | debug_stat, 56 | debug_isatty, 57 | 0, 58 | 0, 59 | 0, 60 | 0 61 | }; 62 | 63 | INODE debug_dev_init() 64 | { 65 | INODE node = calloc(1, sizeof(vfs_node_t)); 66 | strcpy(node->name, "debug"); 67 | node->d = &debug_driver; 68 | node->type = FS_CHARDEV; 69 | return node; 70 | } 71 | -------------------------------------------------------------------------------- /tarfs/src/terminal_src/main.c: -------------------------------------------------------------------------------- 1 | #include "terminal.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "keyboard.h" 8 | #include 9 | 10 | int kill(int pid, int sig); 11 | char **command; 12 | 13 | void switch_vterm(int num) 14 | { 15 | if(num <0 || num > 4) 16 | return; 17 | if(!vterm[num]) 18 | terminal_init(num, 25, 80, command); 19 | active_vterm = num; 20 | copybuffer(vterm[num]); 21 | } 22 | 23 | int main(int argc, char **argv) 24 | { 25 | (void)argc; 26 | 27 | screen_init(); 28 | keyboard_init(); 29 | 30 | command = &argv[1]; 31 | 32 | // Start with a single vterm 33 | switch_vterm(0); 34 | 35 | while(1) 36 | { 37 | char c, d; 38 | c = fgetc(stdin); 39 | d = keyboard_decode(c); 40 | if(kbd_ctrl) 41 | { 42 | switch(d) 43 | { 44 | case '1': 45 | case '2': 46 | case '3': 47 | case '4': 48 | switch_vterm(d-'1'); 49 | continue; 50 | break; 51 | case 'c': 52 | kill(vterm[active_vterm]->pid, 2); 53 | continue; 54 | default: 55 | ; 56 | } 57 | } 58 | if(d) 59 | { 60 | terminal_putch(vterm[active_vterm], d); 61 | copybuffer(vterm[active_vterm]); 62 | write(vterm[active_vterm]->read_fd[1], &d, 1); 63 | } 64 | } 65 | 66 | for(;;); 67 | } 68 | -------------------------------------------------------------------------------- /util/common.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | if [ -z $TARGET ]; then 6 | TARGET=i586-pc-myos 7 | fi 8 | if [ -z $PREFIX ]; then 9 | PREFIX=/usr/local/Cellar/osdev/1.0 10 | fi 11 | 12 | TEMPDIR=~/osdev/ 13 | 14 | CLR_NO="\\033[0m" 15 | CLR_RED="\\033[31m" 16 | CLR_GREEN="\\033[32m" 17 | CLR_YELLOW="\\033[33m" 18 | CLR_BLUE="\\033[36m" 19 | 20 | if [ -z $BUILDDIR ]; then 21 | BUILDDIR=$BUILDROOT/build 22 | fi 23 | 24 | function gototmp() { 25 | mkdir -p $TEMPDIR 26 | pushd $TEMPDIR 27 | } 28 | 29 | function dropout() { 30 | echo -e "${CLR_RED}SOMETHING FAILED!${CLR_NO}" 31 | if [ -f ${TEMPDIR}/error.log ]; then 32 | cat ${TEMPDIR}/error.log 33 | fi 34 | exit 1 35 | } 36 | 37 | # Download name url file 38 | function download() { 39 | echo "Downloading $1" 40 | if [ ! -f "$3" ]; then 41 | curl -# -O "$2/$3" 42 | echo " Done" 43 | else 44 | echo " Already downloaded" 45 | fi 46 | } 47 | 48 | # Clone name git 49 | function gitclone() { 50 | echo "Cloning $1" 51 | if [ ! -d "$1" ]; then 52 | git clone --depth=1 $2 53 | echo " Done" 54 | else 55 | echo " Already downloaded" 56 | fi 57 | } 58 | 59 | # Extract file 60 | function unzip() { 61 | echo "Extracting $1" 62 | tar -xf $1 63 | } 64 | 65 | # Patch files 66 | function dopatch() { 67 | echo "Applying patch to $1" 68 | pushd $2 69 | patch -p1 -N < $3 70 | popd 71 | } 72 | 73 | -------------------------------------------------------------------------------- /kernel/include/procmm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #ifndef __ASSEMBLER__ 7 | 8 | 9 | typedef struct mem_area_struct 10 | { 11 | uintptr_t start; 12 | uintptr_t end; 13 | uint32_t flags; 14 | uint32_t type; 15 | list_t mem; 16 | list_t copies; 17 | process_t *owner; 18 | } mem_area_t; 19 | 20 | #define MM_FLAG_READ (1<<0) 21 | #define MM_FLAG_WRITE (1<<1) 22 | #define MM_FLAG_SHARED (1<<2) 23 | #define MM_FLAG_NOSHARE (1<<3) 24 | #define MM_FLAG_COW (1<<4) 25 | #define MM_FLAG_GROWSDOWN (1<<5) 26 | #define MM_FLAG_AUTOGROW (1<<6) 27 | #define MM_FLAG_ADDONUSE (1<<7) 28 | 29 | #define MM_TYPE_DATA 1 30 | #define MM_TYPE_ARG 4 31 | #define MM_TYPE_ENV 5 32 | #define MM_TYPE_STACK 6 33 | 34 | void init_procmm(process_t *p); 35 | 36 | mem_area_t *new_area(process_t *p, uintptr_t start, uintptr_t end, uint32_t flags, uint32_t type); 37 | 38 | mem_area_t *split_area(mem_area_t *ma, uintptr_t start, uintptr_t end); 39 | mem_area_t *glue_area(mem_area_t *ma); 40 | 41 | mem_area_t *find_including(process_t *p, uintptr_t addr); 42 | mem_area_t *find_above(process_t *p, uintptr_t addr); 43 | 44 | void share_area(process_t *copy, mem_area_t *ma); 45 | 46 | void print_areas(process_t *p); 47 | 48 | uint32_t procmm_handle_page_fault(uintptr_t address, uint32_t flags); 49 | int procmm_check_address(uintptr_t address); 50 | 51 | void procmm_fork(process_t *parent, process_t *child); 52 | void procmm_exit(process_t *proc); 53 | void procmm_removeall(process_t *proc); 54 | #endif 55 | -------------------------------------------------------------------------------- /kernel/include/k_debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #define VIDMEM 0xC00B8000 7 | 8 | #define SCRN_W 80 9 | #define SCRN_H 25 10 | 11 | #define VGA_STYLE(text,bckg) text | bckg 12 | 13 | #define BLACK 0x0 14 | #define BLUE 0x01 15 | #define GREEN 0x02 16 | #define CYAN 0x03 17 | #define RED 0x04 18 | #define MAGENTA 0x05 19 | #define BROWN 0x06 20 | #define GRAY 0x07 21 | #define LBLACK 0x08 22 | #define LBLUE 0x09 23 | #define LGREEN 0x0A 24 | #define LCYAN 0x0B 25 | #define LRED 0x0C 26 | #define LMAGENTA 0x0D 27 | #define LBROWN 0x0E 28 | #define LGRAY 0x0F 29 | #define WHITE 0x0F 30 | 31 | #ifndef __ASSEMBLER__ 32 | 33 | 34 | void kdbg_init(); 35 | void kdbg_scroll(); 36 | void kdbg_putch(uint8_t c, uint8_t style); 37 | void kdbg_setpos(uint32_t x, uint32_t y); 38 | void kdbg_getpos(uint32_t *x, uint32_t *y); 39 | void kdbg_puts(char *str); 40 | void kdbg_printf(char *str, ...); 41 | 42 | int kdbg_num2str(uint32_t num, uint32_t base, char *buf); 43 | void kdbg_setclr(uint32_t style); 44 | 45 | void print_stack_trace(); 46 | 47 | semaphore_t debug_sem; 48 | 49 | #ifndef NDEBUG 50 | 51 | /* #define debug kdbg_printf */ 52 | #define debug serial_debug 53 | #define assert(n) ({if(!(n)){ \ 54 | debug("\n WARNING! \n Assertion failed (%s)", #n); \ 55 | debug(": %s line %d", __FILE__, __LINE__- 2); \ 56 | for(;;);}}) 57 | 58 | #define panic(n) \ 59 | ({ debug(n); \ 60 | for(;;);}) 61 | #else 62 | 63 | #define debug(...) 64 | #define assert(n) 65 | 66 | #endif 67 | 68 | #endif 69 | 70 | -------------------------------------------------------------------------------- /toolchain/newlib.patch: -------------------------------------------------------------------------------- 1 | diff --git a/config.sub b/config.sub 2 | index 8b612ab..20bad11 100755 3 | --- a/config.sub 4 | +++ b/config.sub 5 | @@ -1354,7 +1354,7 @@ case $os in 6 | | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ 7 | | -sym* | -kopensolaris* | -plan9* \ 8 | | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ 9 | - | -aos* | -aros* \ 10 | + | -myos* | -aos* | -aros* \ 11 | | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ 12 | | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ 13 | | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ 14 | diff --git a/newlib/configure.host b/newlib/configure.host 15 | index e7047f0..a43cd09 100644 16 | --- a/newlib/configure.host 17 | +++ b/newlib/configure.host 18 | @@ -434,6 +434,10 @@ case "${host}" in 19 | h8500-*-elf*) 20 | sys_dir=h8500hms 21 | ;; 22 | + i[3-7]86-*-myos*) 23 | + sys_dir=myos 24 | + newlib_cflags="${newlib_cflags} -DSIGNAL_PROVIDED" 25 | + ;; 26 | i[34567]86-*-rdos*) 27 | sys_dir=rdos 28 | newlib_cflags="${newlib_cflags} -DMISSING_SYSCALL_NAMES" 29 | diff --git a/newlib/libc/sys/configure.in b/newlib/libc/sys/configure.in 30 | index c355659..7a0f674 100644 31 | --- a/newlib/libc/sys/configure.in 32 | +++ b/newlib/libc/sys/configure.in 33 | @@ -22,6 +22,7 @@ fi 34 | 35 | if test -n "${sys_dir}"; then 36 | case ${sys_dir} in 37 | + myos) AC_CONFIG_SUBDIRS(myos) ;; 38 | a29khif) AC_CONFIG_SUBDIRS(a29khif) ;; 39 | arc) AC_CONFIG_SUBDIRS(arc) ;; 40 | arm) AC_CONFIG_SUBDIRS(arm) ;; 41 | -------------------------------------------------------------------------------- /kernel/include/lists.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // This should move to the library sooner or later (rather sooner) 3 | #ifndef __ASSEMBLER__ 4 | #include 5 | 6 | typedef struct list_struct 7 | { 8 | struct list_struct *prev; 9 | struct list_struct *next; 10 | } list_t; 11 | 12 | typedef list_t list_head_t; 13 | 14 | #define for_each_in_list(head, item) \ 15 | for((item) = (head); ((item) = (item)->next) != (head); ) 16 | #define list_offsetof(type, member) ((uint32_t) ( (char *)&((type *)0)->member - (char *)0)) 17 | #define list_entry(ptr, type, member) ({\ 18 | const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ 19 | (type *)( (char *)__mptr - list_offsetof(type,member));}) 20 | 21 | #define list_empty(head) \ 22 | ((head).next == &(head)) 23 | 24 | #define init_list(head) \ 25 | head.next = &(head);\ 26 | head.prev = &(head) 27 | 28 | #define append_to_list(head, item) \ 29 | (item).prev = (head).prev; \ 30 | (item).next = &(head); \ 31 | (item).prev->next = &(item); \ 32 | (item).next->prev = &(item); 33 | 34 | #define remove_from_list(item) \ 35 | (item).prev->next = (item).next; \ 36 | (item).next->prev = (item).prev; \ 37 | (item).next = &(item); \ 38 | (item).prev = &(item) 39 | 40 | #define list_insert_to_left(right, item) \ 41 | (item).prev = (right).prev; \ 42 | (item).next = &(right); \ 43 | (right).prev->next = &(item); \ 44 | (right).prev = &(item) 45 | 46 | #define list_insert_to_right(left, item) \ 47 | (item).prev = &(left); \ 48 | (item).next = (left).next; \ 49 | (left).next->prev = &(item); \ 50 | (left).next = &(item) 51 | 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /kernel/include/arch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #ifndef __ASSEMBLER__ 5 | 6 | #define outb(port, val) \ 7 | __asm__ volatile ("outb %%al, %0" : : "dN" ((uint16_t)port), "a" ((uint16_t)val)) 8 | 9 | #define outw(port, val) \ 10 | __asm__ volatile ("outw %1, %0" : : "dN" ((uint16_t)port), "a" ((uint16_t)val)) 11 | 12 | #define inb(port) ({ \ 13 | uint8_t __ret; \ 14 | __asm__ volatile ("inb %1, %0" : "=a" (__ret) : "dN" ((uint16_t)port)); \ 15 | __ret; }) 16 | 17 | #define inw(port) ({ \ 18 | uint16_t __ret; \ 19 | __asm__ volatile ("inw %1, %0" : "=a" (__ret) : "dN" ((uint16_t)port)); \ 20 | __ret; }) 21 | 22 | #define enable_interrupts() __asm__("sti") 23 | 24 | #define disable_interrupts() __asm__("cli"); 25 | 26 | typedef struct 27 | { 28 | uint32_t ds; 29 | uint32_t edi, esi, ebp, esp; 30 | uint32_t ebx, edx, ecx, eax; 31 | uint32_t int_no, err_code; 32 | uint32_t eip; 33 | uint32_t cs; 34 | uint32_t eflags, useresp, ss; 35 | } registers_t; 36 | 37 | #define print_registers(r) \ 38 | debug("eax:%x ebx:%x ecx:%x edx:%x\n", (r)->eax, (r)->ebx, (r)->ecx, (r)->edx); \ 39 | debug("edi:%x esi:%x ebp:%x esp:%x\n", (r)->edi, (r)->esi, (r)->ebp, (r)->esp); \ 40 | debug("eip:%x\ncs:%x ds:%x ss:%x\n", (r)->eip, (r)->cs, (r)->ds, (r)->ss); \ 41 | debug("useresp:%x\neflags%x %b\n", (r)->useresp, (r)->eflags, (r)->eflags); \ 42 | debug("int_no:%x, err_code:%x %b\n", (r)->int_no, (r)->err_code, (r)->err_code); 43 | 44 | #endif 45 | 46 | #ifdef __ASSEMBLER__ 47 | 48 | .macro SetSegments val reg 49 | mov \val, %e\reg 50 | mov %\reg, %ds 51 | mov %\reg, %es 52 | mov %\reg, %fs 53 | mov %\reg, %gs 54 | mov %\reg, %ss 55 | .endm 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /kernel/include/thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifndef __ASSEMBLER__ 10 | 11 | struct process_struct; 12 | 13 | typedef struct thread_struct 14 | { 15 | registers_t r; 16 | uint32_t tid; 17 | uint32_t state; 18 | list_t tasks; 19 | list_t process_threads; 20 | registers_t *kernel_thread; 21 | struct process_struct *proc; 22 | list_t waiting; 23 | } thread_t; 24 | 25 | #define THREAD_STATE_READY 0x1 26 | #define THREAD_STATE_WAITING 0x2 27 | #define THREAD_STATE_FINISHED 0x3 28 | 29 | // Changing this will require chaning kvalloc and all calls to it and current_thread_info() 30 | #define MAX_THREAD_STACK_SIZE PAGE_SIZE 31 | #define MIN_THREAD_STACK_SIZE (sizeof(uint32_t) * 100) 32 | 33 | #define THREAD_STACK_SIZE (MAX_THREAD_STACK_SIZE - sizeof(thread_t) + sizeof(registers_t)) 34 | #define THREAD_STACK_SPACE (THREAD_STACK_SIZE - sizeof(registers_t)) 35 | 36 | 37 | typedef struct thread_info_struct 38 | { 39 | uint8_t stackspace[THREAD_STACK_SPACE]; 40 | thread_t tcb; 41 | } thread_info_t; 42 | 43 | thread_info_t *boot_thread; 44 | uint32_t kernel_booted; 45 | 46 | thread_info_t *current_thread_info(); 47 | 48 | #define current ((thread_t *)(¤t_thread_info()->tcb)) 49 | #define stack_from_thinfo(info) ((uint32_t)&info->tcb.tid) 50 | #define tcb_from_thinfo(info) ((thread_t *)(info->tcb)) 51 | #define thinfo_from_tcb(tcb) ((thread_info_t *)((uint32_t)(tcb)-THREAD_STACK_SPACE)) 52 | #define stack_from_tcb(tcb) (&tcb->tid) 53 | 54 | thread_t *new_thread(void (*func)(void), uint8_t user); 55 | void free_thread(thread_t *th); 56 | registers_t *switch_kernel_thread(registers_t *r); 57 | thread_t *clone_thread(thread_t *th); 58 | 59 | #define STRINGIFY(x) #x 60 | #define TOSTRING(x) STRINGIFY(x) 61 | #define schedule() __asm__ volatile("int $" TOSTRING(INT_SCHEDULE)) 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /kernel/syscall/sys_mem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #undef errno 9 | extern int errno; 10 | 11 | uintptr_t kmem_top = KERNEL_HEAP_START; 12 | uintptr_t kmem_ptr = KERNEL_HEAP_START; 13 | 14 | void *sbrk(int incr) 15 | { 16 | // sbrk as called from the kernel 17 | 18 | if(kmem_ptr + incr >= KERNEL_HEAP_END) 19 | { 20 | debug("[error] Out of memory space for kernel!\n"); 21 | errno = ENOMEM; 22 | return 0; 23 | } 24 | while(kmem_top < kmem_ptr + incr) 25 | { 26 | vmm_page_set(kmem_top, vmm_page_val(pmm_alloc_page(), PAGE_PRESENT | PAGE_WRITE)); 27 | kmem_top += PAGE_SIZE; 28 | } 29 | kmem_ptr = kmem_ptr + incr; 30 | errno = SYSCALL_OK; 31 | return (void *)(kmem_ptr-incr); 32 | } 33 | 34 | void *usr_sbrk(int incr) 35 | { 36 | errno = 0; 37 | process_t *p = current->proc; 38 | 39 | if((p->mm.data_end + incr) > KERNEL_OFFSET) 40 | { 41 | errno = ENOMEM; 42 | return (void *)-1; 43 | } 44 | 45 | mem_area_t *area = find_including(p, p->mm.data_end); 46 | if(area) 47 | { 48 | if(area->end > (p->mm.data_end + incr)) 49 | { 50 | // The existing areas are enough 51 | } else { 52 | // Extend the area 53 | new_area(p, area->end, p->mm.data_end + incr, MM_FLAG_READ | MM_FLAG_WRITE , MM_TYPE_DATA); 54 | } 55 | } else { 56 | // Create a new area 57 | new_area(p, p->mm.data_end, p->mm.data_end + incr, MM_FLAG_READ | MM_FLAG_WRITE, MM_TYPE_DATA); 58 | } 59 | 60 | p->mm.data_end = p->mm.data_end + incr; 61 | return (void *)(p->mm.data_end - incr); 62 | } 63 | 64 | KDEF_SYSCALL(sbrk, r) 65 | { 66 | // sbrk as called by user processes 67 | 68 | process_stack stack = init_pstack(); 69 | uint32_t size = stack[0]; 70 | 71 | // Return start of new area 72 | r->eax = (uint32_t)usr_sbrk(size); 73 | 74 | r->edx = errno; 75 | return r; 76 | } 77 | -------------------------------------------------------------------------------- /kernel/include/elf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #ifndef __ASSEMBLER__ 8 | 9 | #define ELF_ST_BIND(i) ((i)>>4) 10 | #define ELF_ST_TYPE(i) ((i)&0xF) 11 | #define ELF_ST_INFO(b,t) (((b)<<4)+((t)&0xF)) 12 | 13 | typedef struct 14 | { 15 | uint8_t identity[16]; 16 | uint16_t type; 17 | uint16_t machine; 18 | uint32_t version; 19 | uint32_t entry; 20 | uint32_t ph_offset; 21 | uint32_t sh_offset; 22 | uint32_t flags; 23 | uint16_t header_size; 24 | uint16_t ph_size; 25 | uint16_t ph_num; 26 | uint16_t sh_size; 27 | uint16_t sh_num; 28 | uint16_t strtab_index; 29 | }__attribute__((packed)) elf_header; 30 | 31 | #define ELF_TYPE_EXECUTABLE 0x2 32 | 33 | typedef struct 34 | { 35 | uint32_t type; 36 | uint32_t offset; 37 | uint32_t virtual_address; 38 | uint32_t physical_address; 39 | uint32_t file_size; 40 | uint32_t mem_size; 41 | uint32_t flags; 42 | uint32_t align; 43 | }__attribute__((packed)) elf_phead; 44 | 45 | #define ELF_PT_LOAD 0x1 46 | 47 | #define ELF_PT_X 0x1 48 | #define ELF_PT_R 0x2 49 | #define ELF_PT_W 0x4 50 | 51 | typedef struct 52 | { 53 | uint32_t name; 54 | uint32_t type; 55 | uint32_t flags; 56 | uint32_t address; 57 | uint32_t offset; 58 | uint32_t size; 59 | uint32_t link; 60 | uint32_t info; 61 | uint32_t address_align; 62 | uint32_t entry_size; 63 | }__attribute__((packed)) elf_section_head; 64 | 65 | typedef struct 66 | { 67 | uint32_t name; 68 | uint32_t value; 69 | uint32_t size; 70 | uint8_t info; 71 | uint8_t other; 72 | uint16_t shindex; 73 | }__attribute__((packed)) elf_symbol; 74 | 75 | typedef struct 76 | { 77 | elf_symbol *symtab; 78 | uint32_t symtab_size; 79 | uint8_t *strtab; 80 | uint32_t strtab_size; 81 | }__attribute__((packed)) elf_t; 82 | 83 | elf_t kernel_elf; 84 | 85 | void kernel_elf_init(mboot_info_t *mboot); 86 | char *kernel_lookup_symbol(uint32_t addr); 87 | 88 | int load_elf(INODE file); 89 | int is_elf(INODE file); 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /kernel/syscall/syscall.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | syscall_t syscall_handlers[NUM_SYSCALLS]; 12 | 13 | void syscall_init() 14 | { 15 | memset(syscall_handlers, 0 , NUM_SYSCALLS*sizeof(syscall_t *)); 16 | register_int_handler(INT_SYSCALL, syscall_handler); 17 | 18 | KREG_SYSCALL(exit, SYSCALL_EXIT); 19 | KREG_SYSCALL(close, SYSCALL_CLOSE); 20 | KREG_SYSCALL(execve, SYSCALL_EXECVE); 21 | KREG_SYSCALL(fork, SYSCALL_FORK); 22 | KREG_SYSCALL(fstat, SYSCALL_FSTAT); 23 | KREG_SYSCALL(getpid, SYSCALL_GETPID); 24 | KREG_SYSCALL(isatty, SYSCALL_ISATTY); 25 | KREG_SYSCALL(kill, SYSCALL_KILL); 26 | KREG_SYSCALL(link, SYSCALL_LINK); 27 | KREG_SYSCALL(lseek, SYSCALL_LSEEK); 28 | KREG_SYSCALL(open, SYSCALL_OPEN); 29 | KREG_SYSCALL(read, SYSCALL_READ); 30 | KREG_SYSCALL(sbrk, SYSCALL_SBRK); 31 | KREG_SYSCALL(stat, SYSCALL_STAT); 32 | KREG_SYSCALL(times, SYSCALL_TIMES); 33 | KREG_SYSCALL(unlink, SYSCALL_UNLINK); 34 | KREG_SYSCALL(wait, SYSCALL_WAIT); 35 | KREG_SYSCALL(write, SYSCALL_WRITE); 36 | KREG_SYSCALL(waitpid, SYSCALL_WAITPID); 37 | KREG_SYSCALL(yield, SYSCALL_YIELD); 38 | KREG_SYSCALL(signal, SYSCALL_SIGNAL); 39 | KREG_SYSCALL(readdir, SYSCALL_READDIR); 40 | KREG_SYSCALL(dup, SYSCALL_DUP); 41 | KREG_SYSCALL(dup2, SYSCALL_DUP2); 42 | KREG_SYSCALL(pipe, SYSCALL_PIPE); 43 | KREG_SYSCALL(thread_fork, SYSCALL_THREAD); 44 | 45 | KREG_SYSCALL(printf, SYSCALL_PRINTF); 46 | KREG_SYSCALL(process_debug, SYSCALL_PDBG); 47 | KREG_SYSCALL(vidmem, SYSCALL_VIDMEM); 48 | 49 | } 50 | 51 | registers_t *syscall_handler(registers_t *r) 52 | { 53 | 54 | if(syscall_handlers[r->eax]) 55 | r = syscall_handlers[r->eax](r); 56 | else 57 | r->edx = ERROR_NOSYSCALL; 58 | 59 | return r; 60 | } 61 | 62 | syscall_t register_syscall(uint32_t num, syscall_t handler) 63 | { 64 | syscall_t ret = syscall_handlers[num]; 65 | 66 | syscall_handlers[num] = handler; 67 | 68 | return ret; 69 | } 70 | -------------------------------------------------------------------------------- /kernel/arch/int.S: -------------------------------------------------------------------------------- 1 | 2 | # This line is required since newlib is not assembler safe. 3 | # Shame on you, newlib maintainers! 4 | #define _STDINT_H 5 | 6 | #include 7 | #include 8 | 9 | # Reload IDT 10 | .global idt_flush 11 | .func idt_flush 12 | idt_flush: 13 | mov 4(%esp), %eax 14 | lidt (%eax) 15 | ret 16 | .endfunc 17 | 18 | # Reload TSS 19 | .global tss_flush 20 | .func tss_flush 21 | tss_flush: 22 | mov 4(%esp), %eax 23 | ltr %ax 24 | ret 25 | .endfunc 26 | 27 | # ISR stubs 28 | INTNOERR 0 29 | INTNOERR 1 30 | INTNOERR 2 31 | INTNOERR 3 32 | INTNOERR 4 33 | INTNOERR 5 34 | INTNOERR 6 35 | INTNOERR 7 36 | INTERR 8 37 | INTNOERR 9 38 | INTERR 10 39 | INTERR 11 40 | INTERR 12 41 | INTERR 13 42 | INTERR 14 43 | INTNOERR 15 44 | INTNOERR 16 45 | INTNOERR 17 46 | INTNOERR 18 47 | INTNOERR 19 48 | INTNOERR 20 49 | INTNOERR 21 50 | INTNOERR 22 51 | INTNOERR 23 52 | INTNOERR 24 53 | INTNOERR 25 54 | INTNOERR 26 55 | INTNOERR 27 56 | INTNOERR 28 57 | INTNOERR 29 58 | INTNOERR 30 59 | INTNOERR 31 60 | INTNOERR 32 61 | INTNOERR 33 62 | INTNOERR 34 63 | INTNOERR 35 64 | INTNOERR 36 65 | INTNOERR 37 66 | INTNOERR 38 67 | INTNOERR 39 68 | INTNOERR 40 69 | INTNOERR 41 70 | INTNOERR 42 71 | INTNOERR 43 72 | INTNOERR 44 73 | INTNOERR 45 74 | INTNOERR 46 75 | INTNOERR 47 76 | 77 | INTNOERR 128 78 | INTNOERR 255 79 | INTNOERR 130 80 | 81 | .extern idt_handler 82 | 83 | # Common ISR stub 84 | # Push all registers to stack and jump to c 85 | .global int_stub 86 | .func int_stub 87 | int_stub: 88 | pusha 89 | xor %ecx, %ecx 90 | mov %ds, %cx 91 | push %ecx 92 | 93 | SetSegments $0x10, cx 94 | 95 | push %esp 96 | call idt_handler 97 | mov %eax, %esp 98 | .endfunc 99 | 100 | # Return from interrupt 101 | # Pop all registers and perform iret 102 | .global int_return 103 | .func int_return 104 | int_return: 105 | pop %eax 106 | mov %ax, %ds 107 | mov %ax, %es 108 | mov %ax, %fs 109 | mov %ax, %gs 110 | 111 | popa 112 | add $8, %esp 113 | 114 | iret 115 | .endfunc 116 | 117 | -------------------------------------------------------------------------------- /kernel/include/multiboot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define MBOOT_FLAG_MEM 0x001 4 | #define MBOOT_FLAG_DEVICE 0x002 5 | #define MBOOT_FLAG_CMD 0x004 6 | #define MBOOT_FLAG_MODS 0x008 7 | #define MBOOT_FLAG_AOUT 0x010 8 | #define MBOOT_FLAG_ELF 0x020 9 | #define MBOOT_FLAG_MMAP 0x040 10 | #define MBOOT_FLAG_DRIVES 0x080 11 | #define MBOOT_FLAG_CONFIG 0x100 12 | #define MBOOT_FLAG_NAME 0x200 13 | #define MBOOT_FLAG_APM 0x400 14 | #define MBOOT_FLAG_VBE 0x800 15 | 16 | #define MBOOT_PAGE_ALIGNED_FLAG 0x01 17 | #define MBOOT_MEMORY_INFO_FLAG 0x02 18 | 19 | #define MBOOT_MAGIC1 0x1BADB002 20 | #define MBOOT_MAGIC2 0x2BADB002 21 | 22 | #define MBOOT_MEM_FLAG_FREE 0x1 23 | 24 | 25 | #define MBOOT_HEADER_FLAGS (MBOOT_PAGE_ALIGNED_FLAG | MBOOT_MEMORY_INFO_FLAG) 26 | #define MBOOT_HEADER_CHECKSUM -(MBOOT_HEADER_FLAGS + MBOOT_MAGIC1) 27 | 28 | 29 | #ifndef __ASSEMBLER__ 30 | 31 | typedef struct mboot_info_st 32 | { 33 | uint32_t flags; 34 | uint32_t mem_lower; 35 | uint32_t mem_upper; 36 | uint32_t boot_device; 37 | uint32_t cmdline; 38 | uint32_t mods_count; 39 | uint32_t mods_addr; 40 | uint32_t symbol_num; 41 | uint32_t symbol_size; 42 | uint32_t symbol_addr; 43 | uint32_t symbol_shndx; 44 | uint32_t mmap_length; 45 | uint32_t mmap_addr; 46 | uint32_t drives_length; 47 | uint32_t drives_addr; 48 | uint32_t config_table; 49 | uint32_t boot_load_name; 50 | uint32_t apm_table; 51 | uint32_t vbe_control_info; 52 | uint32_t vbe_mode_info; 53 | uint32_t vbe_mode; 54 | uint32_t vbe_interface_seg; 55 | uint32_t vbe_interface_off; 56 | uint32_t vbe_interface_len; 57 | }__attribute__((packed)) mboot_info_t; 58 | 59 | typedef struct mboot_mods_st 60 | { 61 | uint32_t mod_start; 62 | uint32_t mod_end; 63 | uint8_t string[4]; 64 | uint32_t reserved; 65 | }__attribute__((packed)) mboot_mod_t; 66 | 67 | typedef struct mboot_mmap_entry_st 68 | { 69 | uint32_t size; 70 | uint32_t base_addr_lower; 71 | uint32_t base_addr_upper; 72 | uint32_t length_lower; 73 | uint32_t length_upper; 74 | uint32_t type; 75 | }__attribute__((packed)) mboot_mmap_entry_t; 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /kernel/include/process.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #ifndef __ASSEMBLER__ 12 | 13 | #define NUM_FILEDES 256 14 | #define NUM_SIGNALS 32 15 | 16 | #define PROC_FLAG_DEBUG 0x1 17 | 18 | struct thread_struct; 19 | 20 | 21 | typedef struct process_mem_struct 22 | { 23 | uintptr_t code_start; 24 | uintptr_t code_end; 25 | uintptr_t code_entry; 26 | uintptr_t arg_start; 27 | uintptr_t arg_end; 28 | uintptr_t env_start; 29 | uintptr_t env_end; 30 | uintptr_t data_end; 31 | uintptr_t stack_limit; 32 | list_head_t mem; 33 | } process_mem_t; 34 | 35 | typedef struct 36 | { 37 | INODE ino; 38 | uint32_t offset; 39 | uint32_t flags; 40 | uint32_t users; 41 | } file_desc_t; 42 | 43 | #define fd_get(fd) { (fd)->users++; } 44 | #define fd_put(fd) { (fd)->users--; if(!(fd)->users)free(fd); } 45 | 46 | typedef struct process_struct 47 | { 48 | uint32_t pid; 49 | uint32_t state; 50 | uint32_t flags; 51 | struct process_struct *parent; 52 | struct process_struct *child; 53 | struct process_struct *older_sibling; 54 | struct process_struct *younger_sibling; 55 | 56 | char *cmdline; 57 | 58 | list_head_t threads; 59 | list_head_t proc_list; 60 | uintptr_t pd; 61 | semaphore_t pd_sem; 62 | 63 | list_head_t waiting; 64 | uint32_t exit_code; 65 | 66 | process_mem_t mm; 67 | 68 | file_desc_t *fd[NUM_FILEDES]; 69 | 70 | sig_t signal_handler[NUM_SIGNALS]; 71 | uint8_t signal_blocked[NUM_SIGNALS]; 72 | list_head_t signal_queue; 73 | } process_t; 74 | 75 | typedef struct 76 | { 77 | uint32_t sig; 78 | uint32_t sender; 79 | list_head_t queue; 80 | } signal_t; 81 | 82 | #define PROC_STATE_RUNNING 0x1 83 | #define PROC_STATE_WAITING 0x2 84 | #define PROC_STATE_FINISHED 0x3 85 | 86 | void switch_process(process_t *proc); 87 | process_t *process_init(void (*func)(void)); 88 | 89 | 90 | process_t *get_process(uint32_t pid); 91 | process_t *alloc_process(); 92 | process_t *fork_process(); 93 | void free_process(process_t *p); 94 | void exit_process(process_t *proc, uint32_t exit_code); 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /kernel/include/vmm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #define USER_STACK_BOTTOM 0xB0000000 7 | #define USER_STACK_TOP 0xBFFFF000 8 | #define KERNEL_OFFSET 0xC0000000 9 | #define KERNEL_HEAP_START 0xE0000000 10 | #define KERNEL_HEAP_END 0xF0000000 11 | #define PMM_PAGE_STACK 0xFE000000 12 | #define VMM_TEMP2 0xFF7FE000 13 | #define VMM_TEMP1 0xFF7FF000 14 | #define VMM_EXPAGE_TABLES 0xFF800000 15 | #define VMM_EXPAGE_DIR 0xFFBFF000 16 | #define VMM_PAGE_TABLES 0xFFC00000 17 | #define VMM_PAGE_DIR 0xFFFFF000 18 | 19 | #define SIGNAL_RETURN_ADDRESS 0xDEAD5165 20 | #define THREAD_RETURN_ADDRESS 0xDEAD3EAD 21 | 22 | #define PAGE_PRESENT 0x1 23 | #define PAGE_WRITE 0x2 24 | #define PAGE_USER 0x4 25 | 26 | #define VMM_PAGES_PER_TABLE 1024 27 | 28 | #define PF_PRESENT 0x1 29 | #define PF_WRITE 0x2 30 | #define PF_USER 0x4 31 | 32 | #define vmm_page_val(page, flags) \ 33 | (((page) & PAGE_MASK) | ((flags) & PAGE_FLAG_MASK)) 34 | #define vmm_table_idx(page) (page >> 12) 35 | #define vmm_dir_idx(page) (page >> 22) 36 | 37 | #ifdef __ASSEMBLER__ 38 | 39 | #define vmm_flush_tlb(page) invlpg (page) 40 | 41 | #else 42 | 43 | #define vmm_flush_tlb(page) \ 44 | __asm__ volatile ("invlpg (%0)" : : "a" (page & PAGE_MASK)) 45 | 46 | #define assert_higher(val) \ 47 | ((uint32_t)(val) > KERNEL_OFFSET)?(val):(__typeof__((val)))((uint32_t)(val) \ 48 | + KERNEL_OFFSET) 49 | 50 | typedef uintptr_t page_dir_t; 51 | 52 | page_dir_t kernel_pd; 53 | semaphore_t kernel_pd_sem; 54 | semaphore_t exdir_sem; 55 | semaphore_t temp_sem; // VMM_TEMPn addresses 56 | 57 | void vmm_pd_set(page_dir_t pd); 58 | uintptr_t vmm_page_get(uintptr_t page); 59 | uintptr_t vmm_table_get(uintptr_t page); 60 | void vmm_table_set(uintptr_t page, uintptr_t value); 61 | void vmm_page_set(uintptr_t page, uintptr_t value); 62 | 63 | page_dir_t vmm_exdir_set(page_dir_t pd); 64 | uintptr_t vmm_expage_get(uintptr_t page); 65 | uintptr_t vmm_extable_get(uintptr_t page); 66 | void vmm_extable_set(uintptr_t page, uintptr_t value); 67 | void vmm_expage_set(uintptr_t page, uintptr_t value); 68 | 69 | void vmm_clear_page(uintptr_t page); 70 | void vmm_copy_page(uintptr_t src, uintptr_t dst); 71 | 72 | page_dir_t vmm_clone_pd(); 73 | 74 | void vmm_init(uint32_t kernel_size); 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /toolchain/myos/syscall.S: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | #ifndef KERNEL_MODE 5 | 6 | .align 4 7 | .global syscall_errno 8 | syscall_errno: 9 | .int 0x00000000 10 | 11 | .global _syscall_exit 12 | DEF_SYSCALL(exit, SYSCALL_EXIT) 13 | 14 | .global _syscall_close 15 | DEF_SYSCALL(close, SYSCALL_CLOSE) 16 | 17 | .global _syscall_execve 18 | DEF_SYSCALL(execve, SYSCALL_EXECVE) 19 | 20 | .global _syscall_fork 21 | DEF_SYSCALL(fork, SYSCALL_FORK) 22 | 23 | .global _syscall_fstat 24 | DEF_SYSCALL(fstat, SYSCALL_FSTAT) 25 | 26 | .global _syscall_getpid 27 | DEF_SYSCALL(getpid, SYSCALL_GETPID) 28 | 29 | .global _syscall_isatty 30 | DEF_SYSCALL(isatty, SYSCALL_ISATTY) 31 | 32 | .global _syscall_kill 33 | DEF_SYSCALL(kill, SYSCALL_KILL) 34 | 35 | .global _syscall_link 36 | DEF_SYSCALL(link, SYSCALL_LINK) 37 | 38 | .global _syscall_lseek 39 | DEF_SYSCALL(lseek, SYSCALL_LSEEK) 40 | 41 | .global _syscall_open 42 | DEF_SYSCALL(open, SYSCALL_OPEN) 43 | 44 | .global _syscall_read 45 | DEF_SYSCALL(read, SYSCALL_READ) 46 | 47 | .global _syscall_sbrk 48 | DEF_SYSCALL(sbrk, SYSCALL_SBRK) 49 | 50 | .global _syscall_stat 51 | DEF_SYSCALL(stat, SYSCALL_STAT) 52 | 53 | .global _syscall_times 54 | DEF_SYSCALL(times, SYSCALL_TIMES) 55 | 56 | .global _syscall_unlink 57 | DEF_SYSCALL(unlink, SYSCALL_UNLINK) 58 | 59 | .global _syscall_wait 60 | DEF_SYSCALL(wait, SYSCALL_WAIT) 61 | 62 | .global _syscall_write 63 | DEF_SYSCALL(write, SYSCALL_WRITE) 64 | 65 | .global _syscall_waitpid 66 | DEF_SYSCALL(waitpid, SYSCALL_WAITPID) 67 | 68 | .global _syscall_yield 69 | DEF_SYSCALL(yield, SYSCALL_YIELD) 70 | 71 | .global _syscall_signal 72 | DEF_SYSCALL(signal, SYSCALL_SIGNAL) 73 | 74 | .global _syscall_pdbg 75 | DEF_SYSCALL(pdbg, SYSCALL_PDBG) 76 | 77 | .global _syscall_readdir 78 | DEF_SYSCALL(readdir, SYSCALL_READDIR) 79 | 80 | .global _syscall_dup 81 | DEF_SYSCALL(dup, SYSCALL_DUP) 82 | 83 | .global _syscall_dup2 84 | DEF_SYSCALL(dup2, SYSCALL_DUP2) 85 | 86 | .global _syscall_pipe 87 | DEF_SYSCALL(pipe, SYSCALL_PIPE) 88 | 89 | .global _syscall_thread 90 | DEF_SYSCALL(thread, SYSCALL_THREAD) 91 | 92 | 93 | .global _syscall_vidmem 94 | DEF_SYSCALL(vidmem, SYSCALL_VIDMEM) 95 | 96 | .global _syscall_printf 97 | DEF_SYSCALL(printf, SYSCALL_PRINTF) 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /util/makedisk.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | if [ -z $BUILDROOT ]; then 6 | BUILDROOT=$DIR/.. 7 | fi 8 | 9 | . $BUILDROOT/util/common.sh 10 | 11 | GRUBDIR=$TEMPDIR/grub-0.97-i386-pc 12 | 13 | DISKSIZE="20M" 14 | DISKFILE="image.img" 15 | 16 | gototmp 17 | if [ ! -d $GRUBDIR ]; then 18 | download "grub-legacy" "ftp://alpha.gnu.org/gnu/grub" "grub-0.97-i386-pc.tar.gz" 19 | unzip "grub-0.97-i386-pc.tar.gz" 20 | fi 21 | 22 | type dito-generate >/dev/null 2>&1 23 | if [ $? != 0 ]; then 24 | gitclone "dito" "https://github.com/thomasloven/dito.git" 25 | pushd dito 26 | make || dropout 27 | make install-homebrew || dropout 28 | popd 29 | fi 30 | popd 31 | 32 | if [ "$1" = "force" ]; then 33 | rm -f $DISKFILE 34 | fi 35 | 36 | if [ ! -f $DISKFILE ]; then 37 | # Generate image and transfer stage2 38 | dito-generate $DISKFILE $DISKSIZE 39 | dito-format $DISKFILE:1 ext2 || dropout 40 | dito-mkdir ext2:$DISKFILE:1:/boot || dropout 41 | dito-mkdir ext2:$DISKFILE:1:/boot/grub || dropout 42 | dito-cp $GRUBDIR/boot/grub/stage2 ext2:$DISKFILE:1:/boot/grub/stage2 || dropout 43 | 44 | # Edit data in grub stages 1 and 1.5 45 | # Stage 1.5 address 46 | printf '\x20' | dd of=$GRUBDIR/boot/grub/stage1 bs=1 seek=67 count=1 conv=notrunc || dropout 47 | # Stage 1.5 segment 48 | printf '\x02' | dd of=$GRUBDIR/boot/grub/stage1 bs=1 seek=73 count=1 conv=notrunc || dropout 49 | 50 | # Stage 1.5 block count 51 | printf '\x12' | dd of=$GRUBDIR/boot/grub/e2fs_stage1_5 bs=1 seek=508 count=1 conv=notrunc || dropout 52 | # Stage 1.5 disk and partition 53 | printf '\x00\xff\xff\xff' | dd of=$GRUBDIR/boot/grub/e2fs_stage1_5 bs=1 seek=535 count=4 conv=notrunc || dropout 54 | 55 | # Transfer grub stages 1 and 1.5 56 | dd if=$GRUBDIR/boot/grub/stage1 of=$DISKFILE bs=1 count=445 conv=notrunc || dropout 57 | dd if=$GRUBDIR/boot/grub/e2fs_stage1_5 of=$DISKFILE bs=512 seek=1 conv=notrunc || dropout 58 | 59 | # Add Grub menu file 60 | dito-cp - ext2:$DISKFILE:1:/boot/grub/menu.lst << EOF 61 | default 0 62 | timeout 0 63 | 64 | title os5 65 | root (hd0,0) 66 | kernel /boot/kernel 67 | module /boot/tarfs 68 | EOF 69 | 70 | fi 71 | 72 | # Copy kernel and tarfs 73 | dito-rm ext2:$DISKFILE:1:/boot/kernel 74 | dito-rm ext2:$DISKFILE:1:/boot/tarfs 75 | dito-cp $BUILDDIR/kernel/kernel ext2:$DISKFILE:1:/boot/kernel 76 | dito-cp $BUILDDIR/tarfs.tar ext2:$DISKFILE:1:/boot/tarfs 77 | 78 | -------------------------------------------------------------------------------- /toolchain/gcc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/config.sub b/config.sub 2 | index 707e9e2..2caadab 100755 3 | --- a/config.sub 4 | +++ b/config.sub 5 | @@ -1359,7 +1359,7 @@ case $os in 6 | | -sym* | -kopensolaris* | -plan9* \ 7 | | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ 8 | | -aos* | -aros* \ 9 | - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ 10 | + | -myos* | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ 11 | | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ 12 | | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ 13 | | -bitrig* | -openbsd* | -solidbsd* \ 14 | diff --git a/gcc/config.gcc b/gcc/config.gcc 15 | index efb74f7..7b13d16 100644 16 | --- a/gcc/config.gcc 17 | +++ b/gcc/config.gcc 18 | @@ -576,6 +576,12 @@ tm_defines="$tm_defines LIBC_GLIBC=1 LIBC_UCLIBC=2 LIBC_BIONIC=3" 19 | 20 | # Common parts for widely ported systems. 21 | case ${target} in 22 | +*-*-myos*) 23 | + extra_parts="crtbegin.o crtend.o" 24 | + gas=yes 25 | + gnu_ld=yes 26 | + default_use_cxa_atexit=yes 27 | + ;; 28 | *-*-darwin*) 29 | tmake_file="t-darwin ${cpu_type}/t-darwin" 30 | tm_file="${tm_file} darwin.h" 31 | @@ -839,6 +845,11 @@ case ${target} in 32 | esac 33 | 34 | case ${target} in 35 | +i[3-7]86-*-myos*) 36 | + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h i386/i386elf.h myos.h" 37 | + tmake_file="i386/t-i386elf t-svr4" 38 | + use_fixproto=yes 39 | + ;; 40 | aarch64*-*-elf) 41 | tm_file="${tm_file} dbxelf.h elfos.h newlib-stdint.h" 42 | tm_file="${tm_file} aarch64/aarch64-elf.h aarch64/aarch64-elf-raw.h" 43 | diff --git a/gcc/config/myos.h b/gcc/config/myos.h 44 | new file mode 100644 45 | index 0000000..36bb00f 46 | --- /dev/null 47 | +++ b/gcc/config/myos.h 48 | @@ -0,0 +1,11 @@ 49 | +#undef TARGET_OS_CPP_BUILTINS 50 | +#define TARGET_OS_CPP_BUILTINS() \ 51 | + do { \ 52 | + builtin_define_std ("myos"); \ 53 | + builtin_define_std ("unix"); \ 54 | + builtin_assert ("system=myos"); \ 55 | + builtin_assert ("system=unix"); \ 56 | + } while(0); 57 | + 58 | +//#undef TARGET_VERSION 59 | +//#define TARGET_VERSION fprintf(stderr, " (i386 myos)"); 60 | diff --git a/libgcc/config.host b/libgcc/config.host 61 | index 9c47e1b..7e7dcfc 100644 62 | --- a/libgcc/config.host 63 | +++ b/libgcc/config.host 64 | @@ -1148,6 +1148,10 @@ mep*-*-*) 65 | tmake_file="mep/t-mep t-fdpbit" 66 | extra_parts="crtbegin.o crtend.o" 67 | ;; 68 | +i[3-7]86-*-myos*) 69 | + extra_parts="crtbegin.o crtend.o" 70 | + tmake_file="$tmake_file i386/t-crtstuff" 71 | + ;; 72 | *) 73 | echo "*** Configuration ${host} not supported" 1>&2 74 | exit 1 75 | -------------------------------------------------------------------------------- /kernel/include/k_syscall.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | #ifndef __ASSEMBLER__ 12 | 13 | #define NUM_SYSCALLS 256 14 | 15 | typedef registers_t *(*syscall_t)(registers_t *); 16 | 17 | #define KDECL_SYSCALL(name) \ 18 | registers_t *k_syscall_##name(registers_t *) 19 | 20 | #define KDEF_SYSCALL(name, r) \ 21 | registers_t *k_syscall_##name(registers_t *r) 22 | 23 | #define KREG_SYSCALL(name, num) \ 24 | register_syscall(num, &k_syscall_##name); 25 | 26 | typedef uintptr_t* process_stack; 27 | #define init_pstack() \ 28 | (r->cs & 0x3)? \ 29 | (uintptr_t *)(r->useresp + 0x4): \ 30 | (uintptr_t *)(&r->ss) 31 | 32 | #define is_kernel() \ 33 | (!(r->cs & 0x3)) 34 | 35 | 36 | registers_t *syscall_handler(registers_t *r); 37 | syscall_t register_syscall(uint32_t num, syscall_t handler); 38 | void syscall_init(); 39 | 40 | KDECL_SYSCALL(printf); 41 | 42 | // sys_process.c 43 | void _exit(); 44 | KDECL_SYSCALL(exit); 45 | int execve(char *name, char **argv, char **env); 46 | KDECL_SYSCALL(execve); 47 | int fork(); 48 | KDECL_SYSCALL(fork); 49 | int getpid(); 50 | KDECL_SYSCALL(getpid); 51 | int kill(int pid, int sig); 52 | KDECL_SYSCALL(kill); 53 | int wait(int *status); 54 | KDECL_SYSCALL(wait); 55 | int waitpid(int pid); 56 | KDECL_SYSCALL(waitpid); 57 | void yield(); 58 | KDECL_SYSCALL(yield); 59 | sig_t signal(int sig, sig_t handler); 60 | KDECL_SYSCALL(signal); 61 | KDECL_SYSCALL(process_debug); 62 | KDECL_SYSCALL(thread_fork); 63 | 64 | // sys_mem.c 65 | void *sbrk(int incr); 66 | KDECL_SYSCALL(sbrk); 67 | 68 | // sys_fs.c 69 | int close(int file); 70 | KDECL_SYSCALL(close); 71 | int fstat(int file, struct stat *st); 72 | KDECL_SYSCALL(fstat); 73 | int isatty(int file); 74 | KDECL_SYSCALL(isatty); 75 | int link(char *old, char *new); 76 | KDECL_SYSCALL(link); 77 | int lseek(int file, int ptr, int dir); 78 | KDECL_SYSCALL(lseek); 79 | int open(const char *name, int flags, ...); 80 | KDECL_SYSCALL(open); 81 | int read(int file, char *ptr, int len); 82 | KDECL_SYSCALL(read); 83 | int stat(const char *file, struct stat *st); 84 | KDECL_SYSCALL(stat); 85 | int unlink(char *name); 86 | KDECL_SYSCALL(unlink); 87 | int write(int file, char *ptr, int len); 88 | KDECL_SYSCALL(write); 89 | struct dirent *readdir(DIR *dirp); 90 | KDECL_SYSCALL(readdir); 91 | int dup(int fildes); 92 | KDECL_SYSCALL(dup); 93 | int dup2(int fildes1, int fildes2); 94 | KDECL_SYSCALL(dup2); 95 | int pipe(int fildes[2]); 96 | KDECL_SYSCALL(pipe); 97 | 98 | // sys_system.c 99 | clock_t times(struct tms *buf); 100 | KDECL_SYSCALL(times); 101 | 102 | KDECL_SYSCALL(vidmem); 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /kernel/boot/boot.S: -------------------------------------------------------------------------------- 1 | #define _STDINT_H 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | .section .bss 9 | 10 | .align 0x8 11 | 12 | # Stack for booting 13 | .global BootStack 14 | BootStackTop: 15 | .lcomm buff, 2*PAGE_SIZE - 1 16 | BootStack: 17 | 18 | .section .data 19 | 20 | .align 0x1000 21 | 22 | # Page directory for booting up. 23 | # First four megabytes are identity mapped as well as 24 | # mapped to 0xC0000000 25 | .global BootPageDirectory 26 | BootPageDirectory: 27 | .long (BootPageTable - KERNEL_OFFSET)+(PAGE_PRESENT | PAGE_WRITE) 28 | .rept (vmm_dir_idx(KERNEL_OFFSET) - 1) 29 | .long 0x0 30 | .endr 31 | .long (BootPageTable - KERNEL_OFFSET)+(PAGE_PRESENT | PAGE_WRITE) 32 | .rept (1022 - vmm_dir_idx(KERNEL_OFFSET)) 33 | .long 0x0 34 | .endr 35 | .long (BootPageDirectory - KERNEL_OFFSET)+(PAGE_PRESENT | PAGE_WRITE) 36 | 37 | BootPageTable: 38 | .set i, 0 39 | .rept 1024 40 | .long((i << 12) | PAGE_PRESENT | PAGE_WRITE) 41 | .set i, (i+1) 42 | .endr 43 | 44 | # Hard-coded GDT. 45 | # GDT pointer is wrapped into the first entry 46 | .global gdt 47 | gdt_ptr: 48 | gdt: 49 | .short 0x002F 50 | .long gdt 51 | .short 0x0000 52 | .long 0x0000FFFF, 0x00CF9A00 53 | .long 0x0000FFFF, 0x00CF9200 54 | .long 0x0000FFFF, 0x00CFFA00 55 | .long 0x0000FFFF, 0x00CFF200 56 | .long 0x00000000, 0x00000000 57 | 58 | .section .text 59 | 60 | .align 4 61 | 62 | # GRUB Multiboot data 63 | MultiBootHeader: 64 | .long MBOOT_MAGIC1 65 | .long MBOOT_HEADER_FLAGS 66 | .long MBOOT_HEADER_CHECKSUM 67 | 68 | # Kernel start point 69 | .global start 70 | .func start 71 | start: 72 | cli 73 | 74 | # Load page directory and enable paging 75 | mov $(BootPageDirectory - KERNEL_OFFSET), %ecx 76 | mov %ecx, %cr3 77 | mov %cr0, %ecx 78 | or $0x80000000, %ecx 79 | mov %ecx, %cr0 80 | lea (.higherHalf), %ecx 81 | jmp *%ecx 82 | 83 | .higherHalf: 84 | # Load GDT 85 | mov $gdt_ptr, %ecx 86 | lgdt (%ecx) 87 | 88 | SetSegments $0x10, cx 89 | jmp $0x8, $.gdtLoaded 90 | 91 | .gdtLoaded: 92 | # Clear the identity mapping from the page directory 93 | mov $BootPageDirectory, %edx 94 | xor %ecx, %ecx 95 | mov %ecx, (%edx) 96 | vmm_flush_tlb(0) 97 | 98 | # Load a stack for booting 99 | mov $BootStack, %esp 100 | mov $0x0, %ebp 101 | 102 | # eax contains the magic number from GRUB 0x2BADB002 103 | push %eax 104 | 105 | # ebx contains the address of the Multiboot information structure 106 | add $KERNEL_OFFSET, %ebx 107 | push %ebx 108 | 109 | # Call the c function for setting up 110 | .extern kinit 111 | call kinit 112 | mov %eax, %esp 113 | .extern int_return 114 | jmp int_return 115 | .loop: 116 | jmp .loop 117 | .end 118 | .endfunc 119 | -------------------------------------------------------------------------------- /kernel/proc/scheduler.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | list_head_t run_queue; 11 | 12 | semaphore_t scheduler_sem; 13 | 14 | void scheduler_insert(thread_t *th) 15 | { 16 | spin_lock(&scheduler_sem); 17 | append_to_list(run_queue, th->tasks); 18 | spin_unlock(&scheduler_sem); 19 | } 20 | void scheduler_cheat(thread_t *th) 21 | { 22 | spin_lock(&scheduler_sem); 23 | th->tasks.next = run_queue.next; 24 | (run_queue.next)->prev = &th->tasks; 25 | th->tasks.prev = &run_queue; 26 | run_queue.next = &th->tasks; 27 | /* list_insert_to_right(run_queue, th->tasks); */ 28 | spin_unlock(&scheduler_sem); 29 | } 30 | 31 | void scheduler_remove(thread_t *th) 32 | { 33 | spin_lock(&scheduler_sem); 34 | remove_from_list(th->tasks); 35 | spin_unlock(&scheduler_sem); 36 | } 37 | 38 | thread_t *scheduler_next() 39 | { 40 | // Returns the first thread on the run queue without removing it. 41 | 42 | if(run_queue.next != &run_queue) 43 | return list_entry(run_queue.next, thread_t, tasks); 44 | else 45 | { 46 | return 0; 47 | for(;;); 48 | } 49 | } 50 | 51 | void scheduler_init() 52 | { 53 | // Setup the list of ready-to-run threads 54 | 55 | spin_lock(&scheduler_sem); 56 | init_list(run_queue); 57 | spin_unlock(&scheduler_sem); 58 | } 59 | 60 | void scheduler_list(list_head_t *list) 61 | { 62 | // Print the threads on a list for debugging. 63 | // If no list is supplied, prints the run queue. 64 | 65 | if(list == 0) 66 | list = &run_queue; 67 | spin_lock(&scheduler_sem); 68 | list_t *i; 69 | for_each_in_list(list, i) 70 | { 71 | thread_t *th = list_entry(i, thread_t, tasks); 72 | debug("(%x:%x)->",th->proc->pid, th->tid); 73 | } 74 | spin_unlock(&scheduler_sem); 75 | } 76 | 77 | void scheduler_sleep(thread_t *th, list_head_t *list) 78 | { 79 | // Removes a thread from the queue it's currently on and puts it to 80 | // sleep on the supplied queue. 81 | 82 | spin_lock(&scheduler_sem); 83 | remove_from_list(th->tasks); 84 | th->state = THREAD_STATE_WAITING; 85 | append_to_list(*list, th->tasks); 86 | spin_unlock(&scheduler_sem); 87 | } 88 | 89 | void scheduler_wake(list_head_t *list) 90 | { 91 | // Wakes all threads on the supplied list and puts them in the run 92 | // queue. 93 | 94 | spin_lock(&scheduler_sem); 95 | list_t *i = list->next;; 96 | while(i != list) 97 | { 98 | thread_t *th = list_entry(i, thread_t, tasks); 99 | i = i->next; 100 | remove_from_list(th->tasks); 101 | append_to_list(run_queue, th->tasks); 102 | th->state = THREAD_STATE_READY; 103 | } 104 | spin_unlock(&scheduler_sem); 105 | } 106 | 107 | -------------------------------------------------------------------------------- /kernel/boot/kinit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | int debug_enabled = 0; 27 | 28 | void _idle(void) 29 | { 30 | // Idle task. Runs when there are no others on the run queue. 31 | for(;;) 32 | { 33 | __asm__ ("sti; hlt"); 34 | } 35 | } 36 | 37 | 38 | registers_t *kinit(mboot_info_t *mboot, uint32_t mboot_magic) 39 | { 40 | 41 | kdbg_init(); 42 | assert(mboot_magic == MBOOT_MAGIC2); 43 | 44 | mboot_mod_t *mods = (mboot_mod_t *)(assert_higher(mboot->mods_addr)); 45 | 46 | kernel_elf_init(mboot); 47 | pmm_init(mboot); 48 | vmm_init(mods[0].mod_end); 49 | idt_init(); 50 | tss_init(); 51 | 52 | register_int_handler(INT_PF, page_fault_handler); 53 | register_int_handler(INT_SCHEDULE, switch_kernel_thread); 54 | 55 | scheduler_init(); 56 | timer_init(500); 57 | /* vfs_init(); */ 58 | syscall_init(); 59 | process_init((void(*)(void))&_idle); 60 | 61 | tar_header_t *tarfs_location = assert_higher((tar_header_t *)mods[0].mod_start); 62 | debug_enabled = 1; 63 | 64 | debug("[info] Mboot flags %x\n", mboot->mods_addr); 65 | debug("[info] Mounting tarfs as root\n"); 66 | vfs_init(); 67 | vfs_mount("/", tarfs_init(tarfs_location)); 68 | vfs_mount("/mnt/tarfs", tarfs_init(tarfs_location)); 69 | vfs_mount("/dev/debug", debug_dev_init()); 70 | keyboard_init(); 71 | 72 | fopen("/dev/debug", "w"); 73 | fopen("/dev/debug", "w"); 74 | /* for(;;); */ 75 | 76 | /* vfs_mount("/", tarfs_init(tarfs_location)); */ 77 | /* keyboard_init(); */ 78 | /* vfs_mount("/dev/debug", debug_dev_init()); */ 79 | 80 | /* fopen("/dev/kbd", "r"); */ 81 | /* fopen("/dev/debug", "w"); */ 82 | /* fopen("/dev/debug", "w"); */ 83 | 84 | execve("/bin/init",0,0); 85 | 86 | debug("[status]========================\n"); 87 | debug("[status] Os5 by Thomas Lovén\n"); 88 | debug("[status] Kernel git data: [%s (%s)] %s\n", __kernel_git_hash, (__kernel_git_dirty)?"dirty":"clean", __kernel_git_date); 89 | debug("[status] %s: %s\n", __kernel_git_branch, __kernel_git_message); 90 | debug("[status] Kernel compilation: %s %s\n", __kernel_build_date, __kernel_build_time); 91 | debug("[status]========================\n"); 92 | 93 | thread_t *init = new_thread((void(*)(void))current->proc->mm.code_entry,1); 94 | init->proc = current->proc; 95 | 96 | debug("[status] Kernel booted\n"); 97 | return switch_kernel_thread(0); 98 | } 99 | -------------------------------------------------------------------------------- /kernel/fault/page_fault.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | registers_t *page_fault_handler(registers_t *r) 11 | { 12 | // Page fault handler 13 | 14 | // Get the faulting address from the cr2 register 15 | uint32_t fault_address; 16 | __asm__ volatile("mov %%cr2, %0" : "=r" (fault_address)); 17 | 18 | // If the procmm can handle the fault, let it do so and return to the 19 | // thread. 20 | if(!procmm_handle_page_fault(fault_address, r->err_code)) 21 | return r; 22 | 23 | if(!(r->cs & 0x3)) 24 | { 25 | // The faulting thread was running in kernel mode 26 | 27 | if(fault_address >= KERNEL_OFFSET && !(r->err_code & PF_PRESENT)) 28 | { 29 | int handled = 0; 30 | spin_lock(&exdir_sem); 31 | page_dir_t old_exdir = vmm_exdir_set(kernel_pd); 32 | uintptr_t pt_val = vmm_extable_get(fault_address); 33 | if(pt_val & PAGE_PRESENT) 34 | { 35 | // Kernel tried to access a page table that's not in the current page 36 | // directory but exists in the master directory. So just copy it over. 37 | 38 | vmm_table_set(fault_address, pt_val); 39 | handled = 1; 40 | } 41 | vmm_exdir_set(old_exdir); 42 | spin_unlock(&exdir_sem); 43 | 44 | if(handled) 45 | return r; 46 | } 47 | 48 | // Processor was in kernel mode 49 | disable_interrupts(); 50 | debug("[error]Page fault in kernel!\n"); 51 | debug(" At: %x\n", fault_address); 52 | debug(" Code: %x (%s,%s,%s)\n", r->err_code, \ 53 | (r->err_code & 0x4)?"user":"kernel", \ 54 | (r->err_code & 0x2)?"write":"read", \ 55 | (r->err_code & 0x1)?"protection":"non-present"); 56 | print_registers(r); 57 | /*print_stack_trace();*/ 58 | for(;;); 59 | 60 | } else { 61 | 62 | if(fault_address == SIGNAL_RETURN_ADDRESS) 63 | { 64 | return_from_signal(r); 65 | } 66 | 67 | // Processor was in user mode 68 | if(current->proc->flags & PROC_FLAG_DEBUG) 69 | { 70 | debug("[error]Page fault hapened!\n"); 71 | debug("[error] At: %x\n", fault_address); 72 | debug("[error] Code: %x (%s,%s,%s)\n", r->err_code, \ 73 | (r->err_code & 0x4)?"user":"kernel", \ 74 | (r->err_code & 0x2)?"write":"read", \ 75 | (r->err_code & 0x1)?"protection":"non-present"); 76 | debug("[error] From thread: %x\n", current->tid); 77 | debug("[error] From process: %x\n", current->proc->pid); 78 | if(current->proc->cmdline) 79 | debug("Name: %s\n", current->proc->cmdline); 80 | print_registers(r); 81 | } 82 | 83 | signal_process(current->proc->pid, SIGSEGV); 84 | schedule(); 85 | 86 | debug("[error]Shouldn't reach this point...\n"); 87 | for(;;); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /tarfs/src/terminal_src/keyboard.c: -------------------------------------------------------------------------------- 1 | #include "keyboard.h" 2 | 3 | 4 | int kbd_map[128] = 5 | { 6 | -1, '\033', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', 7 | '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 8 | 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 9 | 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, 10 | '*', 11 | '0', 12 | ' ', 13 | 0, 14 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //F-keys 15 | 0, 16 | 0, 17 | '7', '8', '9', 18 | '-', 19 | '4', '5', '6', 20 | '+', 21 | '1', '2', '3', 22 | '0', 23 | '.', 24 | -1, -1, -1, 25 | 0, //F11 26 | 0, //F12 27 | -1 28 | }; 29 | 30 | int kbd_mapS[128] = 31 | { 32 | -1, '\033', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', 33 | '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', 34 | 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 35 | 0, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, 36 | '*', 37 | '0', 38 | ' ', 39 | 0, 40 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41 | 0, 42 | 0, 43 | '7', '8', '9', 44 | '-', 45 | '4', '5', '6', 46 | '+', 47 | '1', '2', '3', 48 | '0', 49 | '.', 50 | -1, -1, -1, 51 | 0, 52 | 0, 53 | -1 54 | }; 55 | 56 | int kbd_multi; 57 | 58 | void keyboard_init() 59 | { 60 | kbd_shift = 0; 61 | kbd_ctrl = 0; 62 | kbd_alt = 0; 63 | kbd_multi = 0; 64 | } 65 | 66 | unsigned char keyboard_decode(unsigned char scancode) 67 | { 68 | unsigned char retval = 0; 69 | 70 | if(scancode & 0x80) 71 | { 72 | 73 | // Key up 74 | switch(scancode & 0x7F) 75 | { 76 | case 0x60: // 0xE0 & 0x7F 77 | break; 78 | case SCANCODE_CAPSLOCK: 79 | case SCANCODE_CTRL: 80 | kbd_ctrl = 0; 81 | break; 82 | 83 | case SCANCODE_ALT: 84 | kbd_alt = 0; 85 | break; 86 | 87 | case SCANCODE_LSHIFT: 88 | case SCANCODE_RSHIFT: 89 | kbd_shift = 0; 90 | break; 91 | 92 | default: 93 | break; 94 | } 95 | 96 | } else { 97 | 98 | // Key down 99 | switch(scancode) 100 | { 101 | case SCANCODE_CAPSLOCK: 102 | case SCANCODE_CTRL: 103 | kbd_ctrl = 1; 104 | break; 105 | 106 | case SCANCODE_ALT: 107 | kbd_alt = 1; 108 | break; 109 | 110 | case SCANCODE_LSHIFT: 111 | case SCANCODE_RSHIFT: 112 | kbd_shift = 1; 113 | break; 114 | 115 | default: 116 | if (kbd_map[scancode] == -1) 117 | break; 118 | if(kbd_shift) 119 | retval = (unsigned char)kbd_mapS[scancode]; 120 | else 121 | retval = (unsigned char) kbd_map[scancode]; 122 | break; 123 | } 124 | 125 | } 126 | 127 | if(scancode == 0xE0) 128 | kbd_multi = 1; 129 | else 130 | kbd_multi = 0; 131 | return retval; 132 | } 133 | -------------------------------------------------------------------------------- /kernel/include/vfs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #ifndef __ASSEMBLER__ 7 | #include 8 | 9 | #define VFS_FLAG_ISATTY 0x100000 10 | #define VFS_FLAG_PIPE 0x110000 11 | 12 | #define FS_FILE 0x1 13 | #define FS_DIRECTORY 0x2 14 | #define FS_CHARDEV 0x3 15 | #define FS_BLOCKDEV 0x4 16 | #define FS_PIPE 0x5 17 | #define FS_SYMLINK 0x6 18 | #define FS_MOUNT 0x8 19 | #define FS_TYPE_MASK 0x7 20 | 21 | struct vfs_node_st; 22 | typedef struct vfs_node_st * INODE; 23 | 24 | typedef struct dirent_st { 25 | INODE ino; 26 | char name[256]; 27 | } dirent_t; 28 | 29 | struct vfs_fstat_st 30 | { 31 | uint32_t size; 32 | uint32_t mode; 33 | }; 34 | 35 | typedef struct vfs_driver_st 36 | { 37 | int32_t (*open)(INODE, uint32_t); 38 | int32_t (*close)(INODE); 39 | uint32_t (*read)(INODE, void *, uint32_t, uint32_t); 40 | uint32_t (*write)(INODE, void *, uint32_t, uint32_t); 41 | int32_t (*link)(INODE, INODE, const char *); 42 | int32_t (*unlink)(INODE, const char *); 43 | int32_t (*stat)(INODE, struct stat *st); 44 | int32_t (*isatty)(INODE); 45 | int32_t (*mkdir)(INODE, const char *); 46 | dirent_t *(*readdir)(INODE, uint32_t); 47 | INODE (*finddir)(INODE, const char *); 48 | void (*flush)(INODE); 49 | } vfs_driver_t; 50 | 51 | #define VFS_NAME_SZ 256 52 | 53 | typedef struct vfs_node_st 54 | { 55 | char name[VFS_NAME_SZ]; 56 | INODE parent; 57 | INODE child; 58 | INODE older, younger; 59 | vfs_driver_t *d; 60 | uint32_t type; 61 | uint32_t length; 62 | uint32_t users; 63 | 64 | // Driver data 65 | void *data; 66 | uint32_t flags; 67 | } vfs_node_t; 68 | 69 | #define in_vfs_tree(node) ((node)->parent != 0) 70 | 71 | typedef struct vfs_pipe 72 | { 73 | char *buffer; 74 | uint32_t size; 75 | uint32_t read_pos; 76 | uint32_t write_pos; 77 | uint32_t readers; 78 | uint32_t writers; 79 | semaphore_t semaphore; 80 | list_head_t waiting; 81 | } vfs_pipe_t; 82 | 83 | #define PIPE_READ 0x1 84 | #define PIPE_WRITE 0x2 85 | 86 | int32_t vfs_open(INODE ino, uint32_t flags); 87 | int32_t vfs_close(INODE ino); 88 | uint32_t vfs_read(INODE ino, void *ptr, uint32_t length, uint32_t offset); 89 | uint32_t vfs_write(INODE ino, void *ptr, uint32_t length, uint32_t offset); 90 | int32_t vfs_link(INODE ino, INODE parent, const char *name); 91 | int32_t vfs_unlink(INODE ino, const char *name); 92 | int32_t vfs_stat(INODE ino, struct stat *st); 93 | int32_t vfs_isatty(INODE ino); 94 | int32_t vfs_mkdir(INODE ino, const char *name); 95 | dirent_t *vfs_readdir(INODE ino, uint32_t num); 96 | INODE vfs_finddir(INODE ino, const char *name); 97 | 98 | void vfs_free(INODE ino); 99 | void vfs_init(); 100 | INODE vfs_umount(const char *path); 101 | INODE vfs_namei(const char *path); 102 | INODE vfs_mount(const char *path, INODE root); 103 | 104 | char *canonicalize_path(const char *path, const char *prefix); 105 | 106 | void vfs_print_tree(); 107 | 108 | // Defined in fs/debug_dev.c 109 | INODE debug_dev_init(); 110 | uint32_t new_pipe(uint32_t size, INODE *nodes); 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /tarfs/src/sh.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define BUF_SIZE 1024 10 | 11 | int fg_pid = 0; 12 | 13 | void _syscall_waitpid(uint32_t pid); 14 | 15 | char buffer2[BUF_SIZE]; 16 | 17 | char *parse_command(char *buffer) 18 | { 19 | char *p = buffer; 20 | char *p2 = buffer2; 21 | 22 | int i = 0; 23 | char env[64]; 24 | while(*p) 25 | { 26 | if(p2 > &buffer2[BUF_SIZE]) 27 | return 0; 28 | switch(*p) 29 | { 30 | case '$': 31 | p++; 32 | i = 0; 33 | while((*p != '\0') && isalnum((int)*p) && (i < 64)) 34 | { 35 | env[i++] = *p++; 36 | } 37 | env[i] = '\0'; 38 | 39 | char *var = getenv(env); 40 | if(var) 41 | { 42 | for(i = 0; i < (int)strlen(var); i++) 43 | { 44 | *p2 = var[i]; 45 | p2++; 46 | } 47 | p2--; 48 | } 49 | break; 50 | case '\n': 51 | *p2 = '\0'; 52 | break; 53 | default: 54 | *p2 = *p; 55 | } 56 | 57 | p++; 58 | p2++; 59 | } 60 | *p2 = '\0'; 61 | return buffer2; 62 | } 63 | 64 | char **tokenize_command(char *line) 65 | { 66 | char *command = strdup(line); 67 | int numtokens = 1; 68 | int i = 0; 69 | while(command[i]) 70 | { 71 | if(command[i] == ' ') 72 | { 73 | numtokens++; 74 | } 75 | i++; 76 | } 77 | char **tokens = calloc(numtokens+1, sizeof(char *)); 78 | tokens[0] = command; 79 | i = 0; 80 | int t = 1; 81 | while(command[i]) 82 | { 83 | if(command[i] == ' ') 84 | { 85 | tokens[t++] = &command[i+1]; 86 | command[i] = '\0'; 87 | } 88 | i++; 89 | } 90 | tokens[t] = 0; 91 | 92 | return tokens; 93 | } 94 | 95 | void print_prompt() 96 | { 97 | if(getenv("PS1")) 98 | { 99 | printf("%s", getenv("PS1")); 100 | } else { 101 | setenv("PS1","$ ",1); 102 | printf("$ "); 103 | } 104 | } 105 | 106 | int kill(int, int); 107 | void signal_transfer(int signum) 108 | { 109 | if(fg_pid) 110 | kill(fg_pid, signum); 111 | } 112 | 113 | int main(int argc, char **argv) 114 | { 115 | (void)argc; 116 | char line[BUF_SIZE]; 117 | 118 | signal(2, &signal_transfer); 119 | 120 | while(1) 121 | { 122 | print_prompt(); 123 | fflush(stdout); 124 | 125 | fgets(line, BUF_SIZE, stdin); 126 | uint32_t len = strlen(line); 127 | 128 | if(len > 1) 129 | { 130 | line[len-1] = '\0'; 131 | char *line2 = parse_command(line); 132 | char **tokens = tokenize_command(line2); 133 | 134 | if(strchr(line2, '=')) 135 | { 136 | putenv(line2); 137 | continue; 138 | } 139 | 140 | fg_pid = fork(); 141 | if(fg_pid) 142 | { 143 | _syscall_waitpid(fg_pid); 144 | fg_pid = 0; 145 | } else { 146 | if(execvp(tokens[0], tokens)) 147 | printf("%s: command not found: %s\n", argv[0], tokens[0]); 148 | free(tokens); 149 | return -1; 150 | } 151 | } 152 | 153 | } 154 | return 0; 155 | } 156 | -------------------------------------------------------------------------------- /toolchain/binutils.patch: -------------------------------------------------------------------------------- 1 | diff --git a/bfd/config.bfd b/bfd/config.bfd 2 | index 5324d39..b5becca 100644 3 | --- a/bfd/config.bfd 4 | +++ b/bfd/config.bfd 5 | @@ -161,6 +161,10 @@ case "${targ}" in 6 | ;; 7 | 8 | # START OF targmatch.h 9 | + i[3-7]86-*-myos*) 10 | + targ_defvec=bfd_elf32_i386_vec 11 | + targ_selvecs=i386coff_vec 12 | + ;; 13 | #ifdef BFD64 14 | aarch64-*-elf) 15 | targ_defvec=bfd_elf64_littleaarch64_vec 16 | diff --git a/config.sub b/config.sub 17 | index 8b612ab..20bad11 100755 18 | --- a/config.sub 19 | +++ b/config.sub 20 | @@ -1354,7 +1354,7 @@ case $os in 21 | | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ 22 | | -sym* | -kopensolaris* | -plan9* \ 23 | | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ 24 | - | -aos* | -aros* \ 25 | + | -myos* | -aos* | -aros* \ 26 | | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ 27 | | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ 28 | | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ 29 | diff --git a/gas/configure.tgt b/gas/configure.tgt 30 | index 77c1d9b..86efd5c 100644 31 | --- a/gas/configure.tgt 32 | +++ b/gas/configure.tgt 33 | @@ -270,6 +270,7 @@ case ${generic_target} in 34 | i386-*-chaos) fmt=elf ;; 35 | i386-*-rdos*) fmt=elf ;; 36 | i386-*-darwin*) fmt=macho ;; 37 | + i386-*-myos*) fmt=elf ;; 38 | 39 | i860-*-*) fmt=elf endian=little ;; 40 | 41 | diff --git a/ld/Makefile.in b/ld/Makefile.in 42 | index 21fd6b8..82e01b4 100644 43 | --- a/ld/Makefile.in 44 | +++ b/ld/Makefile.in 45 | @@ -2748,6 +2748,9 @@ eelf32xtensa.c: $(srcdir)/emulparams/elf32xtensa.sh $(ELF_DEPS) \ 46 | eelf_i386.c: $(srcdir)/emulparams/elf_i386.sh \ 47 | $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} 48 | ${GENSCRIPTS} elf_i386 "$(tdir_elf_i386)" 49 | +emyos_i386.c: $(srcdir)/emulparams/myos_i386.sh \ 50 | + $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} 51 | + ${GENSCRIPTS} myos_i386 "$(tdir_myos_i386)" 52 | eelf_i386_be.c: $(srcdir)/emulparams/elf_i386_be.sh \ 53 | $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} 54 | ${GENSCRIPTS} elf_i386_be "$(tdir_elf_i386_be)" 55 | diff --git a/ld/configure.tgt b/ld/configure.tgt 56 | index c0291c8..f1dfb14 100644 57 | --- a/ld/configure.tgt 58 | +++ b/ld/configure.tgt 59 | @@ -306,6 +306,7 @@ i[3-7]86-*-mach*) targ_emul=i386mach ;; 60 | i[3-7]86-*-gnu*) targ_emul=elf_i386 ;; 61 | i[3-7]86-*-msdos*) targ_emul=i386msdos; targ_extra_emuls=i386aout ;; 62 | i[3-7]86-*-moss*) targ_emul=i386moss; targ_extra_emuls=i386msdos ;; 63 | +i[3-7]86-*-myos*) targ_emul=myos_i386 ;; 64 | i[3-7]86-*-winnt*) targ_emul=i386pe ; 65 | targ_extra_ofiles="deffilep.o pe-dll.o" ;; 66 | i[3-7]86-*-pe) targ_emul=i386pe ; 67 | diff --git a/ld/emulparams/myos_i386.sh b/ld/emulparams/myos_i386.sh 68 | new file mode 100644 69 | index 0000000..5fafdfb 70 | --- /dev/null 71 | +++ b/ld/emulparams/myos_i386.sh 72 | @@ -0,0 +1,13 @@ 73 | +SCRIPT_NAME=elf 74 | +OUTPUT_FORMAT=elf32-i386 75 | +TEXT_START_ADDR=0x1000000 76 | +MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" 77 | +COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)" 78 | +ARCH=i386 79 | +MACHINE= 80 | +NOP=90909090 81 | +TEMPLATE_NAME=elf32 82 | +GENERATE_SHLIB_SCRIPT=yes 83 | +GENERATE_PIE_SCRIPT=yes 84 | +NO_SMALL_DATA=yes 85 | +SEPARATE_GOTPLT=12 86 | -------------------------------------------------------------------------------- /kernel/include/idt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #define NUM_INTERRUPTS 256 6 | 7 | #define MPIC_CMD_PORT 0x20 8 | #define MPIC_DATA_PORT 0x21 9 | #define SPIC_CMD_PORT 0xA0 10 | #define SPIC_DATA_PORT 0xA1 11 | 12 | #define IDT_PRESENT 0x80 13 | #define IDT_DPL_0 0x00 14 | #define IDT_DPL_1 0x20 15 | #define IDT_DPL_2 0x40 16 | #define IDT_DPL_3 0x60 17 | 18 | #define IDT_TASK_GATE 0x05 19 | #define IDT_INT_GATE 0x0E 20 | #define IDT_TRAP_GATE 0x0F 21 | 22 | #define GDT_TSS 0x5 23 | 24 | #define SEG_KERNEL_CODE 0x08 25 | #define SEG_KERNEL_DATA 0x10 26 | #define SEG_USER_CODE 0x18 27 | #define SEG_USER_DATA 0x20 28 | #define SEG_TSS 0x28 29 | 30 | #define ISIRQ(num) ((num >= 32) && (num <= 47)) 31 | #define INT2IRQ(num) (num - 32) 32 | #define IRQ2INT(num) (num + 32) 33 | 34 | #define PIC_EOI 0x20 35 | 36 | #define EFL_CPL3 0x3000 37 | #define EFL_INT 0x200 38 | 39 | #define INT_GPF 0xD 40 | #define INT_PF 0xE 41 | #define INT_SYSCALL 0x80 42 | #define INT_SCHEDULE 0x82 43 | 44 | #define IRQ_TIMER 0 45 | #define IRQ_KBD 1 46 | 47 | 48 | #ifndef __ASSEMBLER__ 49 | 50 | typedef struct interrupt_descriptor 51 | { 52 | uint16_t base_l; 53 | uint16_t segment; 54 | uint8_t reserved; 55 | uint8_t flags; 56 | uint16_t base_h; 57 | } __attribute__((packed)) idt_entry_t; 58 | 59 | #define idt_set_base(IDT, BASE) \ 60 | (IDT).base_l = (uint16_t)((BASE) & 0xFFFF); \ 61 | (IDT).base_h = (uint16_t)((BASE) >> 16); 62 | 63 | struct idt_pointer 64 | { 65 | uint16_t size; 66 | uint32_t offset; 67 | } __attribute__((packed)); 68 | 69 | typedef struct gdt_struct 70 | { 71 | uint16_t limit_l; 72 | uint16_t base_l; 73 | uint8_t base_m; 74 | uint8_t access; 75 | uint8_t limit_h: 4; 76 | uint8_t flags :4; 77 | uint8_t base_h; 78 | }__attribute__((packed)) gdt_entry_t; 79 | 80 | #define set_gdt_base(GDT, BASE) \ 81 | (GDT).base_l = ((BASE) & 0xFFFF); \ 82 | (GDT).base_m = (((BASE) >> 16) & 0xFF); \ 83 | (GDT).base_h = (((BASE) >> 24) & 0xFF); 84 | 85 | #define set_gdt_limit(GDT, LIMIT) \ 86 | (GDT).limit_l = ((LIMIT) & 0xFF); \ 87 | (GDT).limit_h = (((LIMIT) & 0x0F)); 88 | 89 | typedef struct tss_struct 90 | { 91 | uint32_t ptl; 92 | uint32_t esp0; 93 | uint32_t ss0; 94 | uint32_t unused[15]; 95 | uint32_t es, cs, ss, ds, fs, gs; 96 | uint32_t ldt; 97 | uint16_t trap, iomap; 98 | }__attribute__((packed)) tss_t; 99 | 100 | typedef void (*isr_t)(void); 101 | typedef registers_t *(*int_handler_t)(registers_t *); 102 | 103 | void idt_init(); 104 | void tss_init(); 105 | 106 | registers_t *idt_handler(registers_t *t); 107 | int_handler_t register_int_handler(uint32_t num, int_handler_t handler); 108 | 109 | tss_t global_tss; 110 | 111 | registers_t *page_fault_handler(registers_t *t); 112 | 113 | extern void idt_flush(uint32_t idt); 114 | extern void tss_flush(uint32_t segment); 115 | 116 | #define set_kernel_stack(stack) global_tss.esp0 = (uint32_t)(stack) 117 | 118 | #else // ifndef __ASSEMBLER__ 119 | 120 | .macro INTNOERR num 121 | .global isr\num 122 | .func isr\num 123 | isr\num: 124 | cli 125 | push $0 126 | push $\num 127 | jmp int_stub 128 | .endfunc 129 | .endm 130 | 131 | .macro INTERR num 132 | .global isr\num 133 | .func isr\num 134 | isr\num: 135 | cli 136 | push $\num 137 | jmp int_stub 138 | .endfunc 139 | .endm 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /kernel/proc/thread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | // If this line throws an error, the size of the kernel thread stack has grown too small. Please change MIN_THREAD_STACK_SIZE or thread_t in thread.h 19 | // Or rather yet, change how the stack is allocated so that it works for all sizes... 20 | uint32_t size_checker[1-2*!(THREAD_STACK_SPACE > MIN_THREAD_STACK_SIZE)]; 21 | 22 | uint32_t next_tid=1; 23 | 24 | thread_info_t *current_thread_info() 25 | { 26 | if(!kernel_booted) 27 | return boot_thread; 28 | 29 | thread_info_t *ti; 30 | ti = (thread_info_t *)((uint32_t)&ti & PAGE_MASK); 31 | return ti; 32 | } 33 | 34 | thread_t *alloc_thread() 35 | { 36 | thread_info_t *th_info = valloc(sizeof(thread_info_t)); 37 | memset(&th_info->tcb, 0, sizeof(thread_t)); 38 | 39 | th_info->tcb.tid = next_tid++; 40 | 41 | init_list(th_info->tcb.tasks); 42 | init_list(th_info->tcb.process_threads); 43 | init_list(th_info->tcb.waiting); 44 | 45 | return &th_info->tcb; 46 | } 47 | 48 | void free_thread(thread_t *th) 49 | { 50 | scheduler_remove(th); 51 | 52 | remove_from_list(th->tasks); 53 | remove_from_list(th->process_threads); 54 | 55 | thread_info_t *th_info = thinfo_from_tcb(th); 56 | free(th_info); 57 | } 58 | 59 | thread_t *new_thread(void (*func)(void), uint8_t user) 60 | { 61 | thread_t *th = alloc_thread(); 62 | 63 | th->r.eip = (uint32_t)func; 64 | if(user) 65 | { 66 | th->r.useresp = USER_STACK_TOP; 67 | th->r.ebp = th->r.useresp; 68 | 69 | th->r.cs = SEG_USER_CODE | 0x3; 70 | th->r.ds = SEG_USER_DATA | 0x3; 71 | th->r.ss = SEG_USER_DATA | 0x3; 72 | } else { 73 | th->r.cs = SEG_KERNEL_CODE; 74 | th->r.ds = SEG_KERNEL_DATA; 75 | th->r.ss = SEG_KERNEL_DATA; 76 | } 77 | 78 | th->state = THREAD_STATE_READY; 79 | scheduler_insert(th); 80 | 81 | th->kernel_thread = &th->r; 82 | 83 | return th; 84 | } 85 | 86 | thread_t *clone_thread(thread_t *th) 87 | { 88 | thread_t *new = alloc_thread(); 89 | 90 | uint32_t tid = new->tid; 91 | memcpy(new, th, sizeof(thread_t)); 92 | new->tid = tid; 93 | 94 | init_list(new->tasks); 95 | init_list(new->process_threads); 96 | 97 | new->kernel_thread = &new->r; 98 | 99 | return new; 100 | } 101 | 102 | void clean_threads(process_t *p) 103 | { 104 | list_t *i = (&p->threads)->next; 105 | while (i != &p->threads) 106 | { 107 | thread_t *th = list_entry(i, thread_t, process_threads); 108 | i = i->next; 109 | if(th->state == THREAD_STATE_FINISHED && th !=current) 110 | { 111 | free_thread(th); 112 | } 113 | } 114 | } 115 | 116 | 117 | registers_t *switch_kernel_thread(registers_t *r) 118 | { 119 | if(r && r != &boot_thread->tcb.r) 120 | { 121 | current->kernel_thread = r; 122 | if(current->state == THREAD_STATE_READY) 123 | scheduler_insert(current); 124 | } 125 | 126 | thread_t *next = scheduler_next(); 127 | if(!next) 128 | next = &boot_thread->tcb; 129 | else 130 | scheduler_remove(next); 131 | 132 | switch_process(next->proc); 133 | 134 | clean_threads(next->proc); 135 | 136 | kernel_booted = TRUE; 137 | 138 | return next->kernel_thread; 139 | } 140 | -------------------------------------------------------------------------------- /toolchain/myos/include/syscalls.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | 5 | #define SYSCALL_EXIT 0x1 6 | #define SYSCALL_CLOSE 0x2 7 | #define SYSCALL_EXECVE 0x3 8 | #define SYSCALL_FORK 0x4 9 | #define SYSCALL_FSTAT 0x5 10 | #define SYSCALL_GETPID 0x6 11 | #define SYSCALL_ISATTY 0x7 12 | #define SYSCALL_KILL 0x8 13 | #define SYSCALL_LINK 0x9 14 | #define SYSCALL_LSEEK 0xa 15 | #define SYSCALL_OPEN 0xb 16 | #define SYSCALL_READ 0xc 17 | #define SYSCALL_SBRK 0xd 18 | #define SYSCALL_STAT 0xe 19 | #define SYSCALL_TIMES 0xf 20 | #define SYSCALL_UNLINK 0x10 21 | #define SYSCALL_WAIT 0x11 22 | #define SYSCALL_WRITE 0x12 23 | #define SYSCALL_WAITPID 0x13 24 | #define SYSCALL_YIELD 0x14 25 | #define SYSCALL_SIGNAL 0x15 26 | #define SYSCALL_READDIR 0x16 27 | #define SYSCALL_DUP 0x17 28 | #define SYSCALL_DUP2 0x18 29 | #define SYSCALL_PIPE 0x19 30 | #define SYSCALL_THREAD 0x1A 31 | 32 | #define SYSCALL_PDBG 0xF0 33 | #define SYSCALL_PRINTF 0xF1 34 | #define SYSCALL_VIDMEM 0xF2 35 | 36 | #define SYSCALL_OK 0x00 37 | #define ERROR_NOSYSCALL 0x01 38 | 39 | #ifndef KERNEL_MODE 40 | #ifndef __ASSEMBLER__ 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | int syscall_errno; 48 | 49 | #define DECL_SYSCALL0(name) \ 50 | int _syscall_##name() 51 | #define DECL_SYSCALL1(name, P1) \ 52 | int _syscall_##name(P1) 53 | #define DECL_SYSCALL2(name, P1, P2) \ 54 | int _syscall_##name(P1, P2) 55 | #define DECL_SYSCALL3(name, P1, P2, P3) \ 56 | int _syscall_##name(P1, P2, P3) 57 | #define DECL_SYSCALL1E(name, P1) \ 58 | int _syscall_##name(P1, ...) 59 | 60 | 61 | DECL_SYSCALL1(exit, int); 62 | DECL_SYSCALL1(close, int); 63 | DECL_SYSCALL3(execve, const char *, char *const*, char **); 64 | DECL_SYSCALL0(fork); 65 | DECL_SYSCALL2(fstat, int, struct stat *); 66 | DECL_SYSCALL0(getpid); 67 | DECL_SYSCALL1(isatty, int); 68 | DECL_SYSCALL2(kill, int, int); 69 | DECL_SYSCALL2(link, char *, char *); 70 | DECL_SYSCALL3(lseek, int, int, int); 71 | DECL_SYSCALL3(open, const char *, int, int); 72 | DECL_SYSCALL3(read, int, char *, int); 73 | DECL_SYSCALL1(sbrk, int); 74 | DECL_SYSCALL2(stat, const char *, struct stat *); 75 | DECL_SYSCALL1(times, struct tms *); 76 | DECL_SYSCALL1(unlink, char *); 77 | DECL_SYSCALL1(wait, int *); 78 | DECL_SYSCALL3(write, int, char *, int); 79 | DECL_SYSCALL1(waitpid, int); 80 | DECL_SYSCALL0(yield); 81 | DECL_SYSCALL2(signal, int, sighandler_t); 82 | DECL_SYSCALL3(readdir, int, int, struct dirent *); 83 | DECL_SYSCALL1(dup, int); 84 | DECL_SYSCALL2(dup2, int, int); 85 | DECL_SYSCALL1(pipe, int[]); 86 | DECL_SYSCALL3(thread, void *, void *, int); 87 | 88 | DECL_SYSCALL1E(printf, char *); 89 | DECL_SYSCALL0(pdbg); 90 | DECL_SYSCALL0(vidmem); 91 | 92 | #define outb(port, val) \ 93 | __asm__ volatile ("outb %%al, %0" : : "dN" ((uint16_t)port), "a" ((uint16_t)val)) 94 | 95 | #define outw(port, val) \ 96 | __asm__ volatile ("outw %1, %0" : : "dN" ((uint16_t)port), "a" ((uint16_t)val)) 97 | 98 | #define inb(port) ({ \ 99 | uint8_t __ret; \ 100 | __asm__ volatile ("inb %1, %0" : "=a" (__ret) : "dN" ((uint16_t)port)); \ 101 | __ret; }) 102 | 103 | #define inw(port) ({ \ 104 | uint16_t __ret; \ 105 | __asm__ volatile ("inw %1, %0" : "=a" (__ret) : "dN" ((uint16_t)port)); \ 106 | __ret; }) 107 | 108 | 109 | 110 | #else 111 | 112 | #define DEF_SYSCALL(name, num) \ 113 | _syscall_##name: \ 114 | defsyscall num 115 | 116 | .macro defsyscall num 117 | mov $\num, %eax 118 | int $0x80 119 | mov %edx, (syscall_errno) 120 | ret 121 | .endm 122 | 123 | #endif 124 | #endif 125 | -------------------------------------------------------------------------------- /kernel/drivers/keyboard.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | unsigned char kbd_map[128] = 13 | { 14 | 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', 15 | '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 16 | 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 17 | 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, 18 | '*', 19 | '0', 20 | ' ', 21 | 0, 22 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23 | 0, 24 | 0, 25 | 0, 26 | 0, 27 | 0, 28 | '-', 29 | 0, 30 | 0, 31 | 0, 32 | '+', 33 | 0, 34 | 0, 35 | 0, 36 | 0, 37 | 0, 38 | 0, 0, 0, 39 | 0, 40 | 0, 41 | 0 42 | }; 43 | 44 | unsigned char kbd_mapS[128] = 45 | { 46 | 0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', 47 | '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', 48 | 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 49 | 0, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, 50 | '*', 51 | '0', 52 | ' ', 53 | 0, 54 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55 | 0, 56 | 0, 57 | 0, 58 | 0, 59 | 0, 60 | '-', 61 | 0, 62 | 0, 63 | 0, 64 | '+', 65 | 0, 66 | 0, 67 | 0, 68 | 0, 69 | 0, 70 | 0, 0, 0, 71 | 0, 72 | 0, 73 | 0 74 | }; 75 | 76 | INODE keyboard_pipe; 77 | INODE keyboard_raw; 78 | char kbd_state = 0; 79 | 80 | unsigned char keyboard_decode(unsigned char scancode) 81 | { 82 | if(scancode & 0x80) 83 | { 84 | // Release key 85 | scancode = scancode & 0x7F; 86 | if(scancode == 0x2A || scancode == 0x36) 87 | { 88 | // Release shift 89 | kbd_state = 0; 90 | } 91 | return 0; 92 | } else { 93 | // Press key 94 | if(scancode == 0x2A || scancode == 0x36) 95 | { 96 | // Shift key 97 | kbd_state = 1; 98 | return 0; 99 | } 100 | 101 | if(kbd_state == 1) 102 | return kbd_mapS[scancode]; 103 | else 104 | return kbd_map[scancode]; 105 | } 106 | } 107 | 108 | registers_t *keyboard_handler(registers_t *r) 109 | { 110 | unsigned char code[2] = { 0, '\0'}; 111 | unsigned char scancode; 112 | while(inb(KBD_STATUS_PORT) & 0x2); 113 | 114 | scancode = inb(KBD_DATA_PORT); 115 | 116 | // Write ascii to /dev/kbd and the raw scancode 117 | // to /dev/kbdraw 118 | code[0] = keyboard_decode(scancode); 119 | if(code[0]) 120 | { 121 | /* vfs_write(keyboard_pipe, (char *)code, 1, 0); */ 122 | // Echo key to stdout 123 | /* fputc((int)code[0], stdout); */ 124 | /* fflush(stdout); */ 125 | } 126 | code[0] = scancode; 127 | vfs_write(keyboard_raw, (char *)code, 1, 0); 128 | vfs_write(keyboard_pipe, (char *)code, 1, 0); 129 | 130 | return r; 131 | } 132 | 133 | void keyboard_init() 134 | { 135 | INODE tmp[2]; 136 | new_pipe(1024, tmp); 137 | keyboard_pipe = tmp[1]; 138 | /* vfs_mount("/dev/kbd", tmp[0]); */ 139 | vfs_open(keyboard_pipe, O_WRONLY); 140 | 141 | // Make keyboard stdin (first entry in file descriptor table) 142 | process_t *p = current->proc; 143 | p->fd[0] = calloc(1, sizeof(file_desc_t)); 144 | fd_get(p->fd[0]); 145 | p->fd[0]->ino = tmp[0]; 146 | p->fd[0]->flags = O_RDONLY; 147 | vfs_open(tmp[0], O_RDONLY); 148 | 149 | new_pipe(1024, tmp); 150 | keyboard_raw = tmp[1]; 151 | vfs_mount("/dev/kbdraw", tmp[0]); 152 | vfs_open(keyboard_raw, O_WRONLY); 153 | 154 | register_int_handler(IRQ2INT(IRQ_KBD), keyboard_handler); 155 | } 156 | -------------------------------------------------------------------------------- /kernel/mem/pmm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | uint8_t pmm_running; 11 | uintptr_t pmm_pos; 12 | 13 | uintptr_t *pmm_page_stack_max = (uintptr_t *)PMM_PAGE_STACK; 14 | uintptr_t *pmm_page_stack_ptr = (uintptr_t *)PMM_PAGE_STACK; 15 | 16 | semaphore_t pmm_sem; 17 | 18 | uintptr_t pmm_alloc_page() 19 | { 20 | // Hand out the physical address of a page of free memory. 21 | 22 | // If the PMM has not been completely setup (e.g. during setup of the 23 | // PMM), just allocate pages from right after where the kernel is 24 | // loaded. This should need to be done, like, twice or so. 25 | // No big waste. 26 | if(pmm_running == FALSE) 27 | { 28 | pmm_pos += PAGE_SIZE; 29 | return pmm_pos - PAGE_SIZE; 30 | } 31 | 32 | if ( pmm_page_stack_ptr == (uintptr_t *)PMM_PAGE_STACK) 33 | { 34 | // At bottom of page stack 35 | panic("Out of memory!"); 36 | } 37 | 38 | spin_lock(&pmm_sem); 39 | uintptr_t ret; 40 | 41 | if(pmm_page_stack_ptr < (pmm_page_stack_max - PMM_STACK_ENTRIES_PER_PAGE)) 42 | { 43 | // If a page of the stack area is freed, hand out that page 44 | // instead. 45 | pmm_page_stack_max = pmm_page_stack_max - PMM_STACK_ENTRIES_PER_PAGE; 46 | ret = vmm_page_get((uintptr_t)pmm_page_stack_max) & PAGE_MASK; 47 | vmm_page_set((uintptr_t)pmm_page_stack_max, 0); 48 | } else { 49 | // Otherwise, return the page at the top of the stack. 50 | pmm_page_stack_ptr--; 51 | ret = *pmm_page_stack_ptr; 52 | } 53 | 54 | spin_unlock(&pmm_sem); 55 | return ret; 56 | } 57 | 58 | void pmm_free_page(uintptr_t page) 59 | { 60 | // Returns a physical page to the free page stack. 61 | // Does not check if the page is already on the stack. 62 | 63 | page &= PAGE_MASK; 64 | 65 | if(page < pmm_pos + PAGE_SIZE) // Two pages are required for initial setup 66 | return; 67 | 68 | spin_lock(&pmm_sem); 69 | // If a new page is needed to fit the stack, use the one we just 70 | // got. 71 | if(pmm_page_stack_ptr >= pmm_page_stack_max) 72 | { 73 | vmm_page_set((uintptr_t)pmm_page_stack_max, vmm_page_val(page, PAGE_PRESENT | PAGE_WRITE)); 74 | pmm_page_stack_max = pmm_page_stack_max + PMM_STACK_ENTRIES_PER_PAGE; 75 | } else { 76 | // Otherwise put the new page on top of the stack. 77 | *pmm_page_stack_ptr = page; 78 | pmm_page_stack_ptr++; 79 | } 80 | 81 | // As soon as there is a page on the stack, the PMM is ready to go. 82 | pmm_running = TRUE; 83 | spin_unlock(&pmm_sem); 84 | } 85 | 86 | void pmm_init(mboot_info_t *mboot) 87 | { 88 | // Setup physical memory manager. 89 | // Takes a multiboot memory map as argument. 90 | 91 | mboot_mod_t *mods = (mboot_mod_t *)(assert_higher(mboot->mods_addr)); 92 | pmm_pos = (mboot->mem_upper + PAGE_SIZE) & PAGE_MASK; 93 | if(pmm_pos < (mods[mboot->mods_count-1].mod_end)) 94 | pmm_pos = (mods[mboot->mods_count-1].mod_end + PAGE_SIZE) & PAGE_MASK; 95 | pmm_running = FALSE; 96 | 97 | // Fill physical page stack with free pages from memory map. 98 | mboot_mmap_entry_t *me = (mboot_mmap_entry_t *)(assert_higher(mboot->mmap_addr)); 99 | uintptr_t mmap_end = assert_higher(mboot->mmap_addr) + mboot->mmap_length; 100 | while ((uintptr_t)me < mmap_end) 101 | { 102 | if(me->type == MBOOT_MEM_FLAG_FREE) 103 | { 104 | uint32_t j; 105 | for(j = me->base_addr_lower; j <= (me->base_addr_lower + me->length_lower); j += PAGE_SIZE) 106 | { 107 | pmm_free_page(j); 108 | } 109 | } 110 | me = (mboot_mmap_entry_t *)((uint32_t)me + me->size + sizeof(uint32_t)); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /kernel/fs/pipes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | int32_t pipe_open(INODE ino, uint32_t flags) 15 | { 16 | (void)flags; 17 | vfs_pipe_t *pipe = (vfs_pipe_t *)ino->data; 18 | if(ino->flags == PIPE_READ) 19 | pipe->readers = pipe->readers + 1; 20 | if(ino->flags == PIPE_WRITE) 21 | pipe->writers = pipe->writers + 1; 22 | return 0; 23 | } 24 | int32_t pipe_close(INODE ino) 25 | { 26 | vfs_pipe_t *pipe = (vfs_pipe_t *)ino->data; 27 | if(ino->flags == PIPE_READ) 28 | pipe->readers = pipe->readers - 1; 29 | if(ino->flags == PIPE_WRITE) 30 | pipe->writers = pipe->writers - 1; 31 | if(!pipe->readers && !pipe->writers) 32 | { 33 | // Destroy pipe 34 | } 35 | return 0; 36 | } 37 | uint32_t pipe_read(INODE ino, void *buffer, uint32_t size, uint32_t offset) 38 | { 39 | (void)offset; 40 | vfs_pipe_t *pipe = (vfs_pipe_t *)ino->data; 41 | uint32_t read = 0; 42 | while(read == 0) 43 | { 44 | spin_lock(&pipe->semaphore); 45 | if(!pipe->writers) 46 | { 47 | ((char *)buffer)[read++] = EOF; 48 | spin_unlock(&pipe->semaphore); 49 | return read; 50 | } 51 | while((pipe->write_pos - pipe->read_pos > 0) && read < size) 52 | { 53 | ((char *)buffer)[read] = pipe->buffer[pipe->read_pos % pipe->size]; 54 | read++; 55 | pipe->read_pos++; 56 | } 57 | spin_unlock(&pipe->semaphore); 58 | scheduler_wake(&pipe->waiting); 59 | 60 | if(read == 0) 61 | { 62 | scheduler_sleep(current, &pipe->waiting); 63 | schedule(); 64 | } 65 | } 66 | return read; 67 | } 68 | uint32_t pipe_write(INODE ino, void *buffer, uint32_t size, uint32_t offset) 69 | { 70 | (void)offset; 71 | vfs_pipe_t *pipe = (vfs_pipe_t *)ino->data; 72 | uint32_t written = 0; 73 | while(written < size) 74 | { 75 | spin_lock(&pipe->semaphore); 76 | if(!pipe->readers) 77 | { 78 | while(written < size) 79 | { 80 | pipe->buffer[pipe->write_pos % pipe->size] = ((char *)buffer)[written]; 81 | written++; 82 | pipe->write_pos++; 83 | } 84 | } else { 85 | while((pipe->write_pos - pipe->read_pos) < pipe->size && written < size) 86 | { 87 | pipe->buffer[pipe->write_pos % pipe->size] = ((char *)buffer)[written]; 88 | written++; 89 | pipe->write_pos++; 90 | } 91 | } 92 | spin_unlock(&pipe->semaphore); 93 | scheduler_wake(&pipe->waiting); 94 | if(written < size) 95 | { 96 | scheduler_sleep(current, &pipe->waiting); 97 | schedule(); 98 | } 99 | } 100 | return written; 101 | } 102 | int32_t pipe_stat(INODE node, struct stat *st) 103 | { 104 | (void)node; 105 | memset(st, 0, sizeof(struct stat)); 106 | st->st_mode = S_IFCHR; 107 | return 0; 108 | } 109 | int32_t pipe_isatty(INODE node) 110 | { 111 | (void)node; 112 | return 1; 113 | } 114 | 115 | 116 | vfs_driver_t pipe_driver = 117 | { 118 | pipe_open, 119 | pipe_close, 120 | pipe_read, 121 | pipe_write, 122 | 0, 123 | 0, 124 | pipe_stat, 125 | pipe_isatty, 126 | 0, 127 | 0, 128 | 0, 129 | 0 130 | }; 131 | 132 | uint32_t new_pipe(uint32_t size, INODE *nodes) 133 | { 134 | vfs_pipe_t *pipe = calloc(1, sizeof(vfs_pipe_t)); 135 | pipe->buffer = malloc(size); 136 | pipe->size = size; 137 | spin_unlock(&pipe->semaphore); 138 | init_list(pipe->waiting); 139 | 140 | 141 | // Read inode 142 | nodes[0] = calloc(1, sizeof(vfs_node_t)); 143 | strcpy(nodes[0]->name, "[pipe]"); 144 | nodes[0]->d = &pipe_driver; 145 | nodes[0]->type = FS_PIPE; 146 | nodes[0]->data = pipe; 147 | nodes[0]->flags = PIPE_READ; 148 | 149 | // Write inode 150 | nodes[1] = calloc(1, sizeof(vfs_node_t)); 151 | strcpy(nodes[1]->name, "[pipe]"); 152 | nodes[1]->d = &pipe_driver; 153 | nodes[1]->type = FS_PIPE; 154 | nodes[1]->data = pipe; 155 | nodes[1]->flags = PIPE_WRITE; 156 | 157 | return 0; 158 | } 159 | -------------------------------------------------------------------------------- /kernel/proc/elf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void kernel_elf_init(mboot_info_t *mboot) 11 | { 12 | // Load data about the kernel executable for use in debugging. 13 | 14 | elf_section_head *sections = assert_higher((elf_section_head *)mboot->symbol_addr); 15 | 16 | uint32_t stringtab = (uint32_t)(assert_higher(sections[mboot->symbol_shndx].address)); 17 | uint32_t i; 18 | for(i=0; i < mboot->symbol_num; i++) 19 | { 20 | // We want to find the string and symbol tables. 21 | char *name = (char *) stringtab + sections[i].name; 22 | if(!strcmp(name,".strtab")) 23 | { 24 | kernel_elf.strtab = assert_higher((uint8_t *)sections[i].address); 25 | kernel_elf.strtab_size = sections[i].size; 26 | } 27 | if(!strcmp(name,".symtab")) 28 | { 29 | kernel_elf.symtab = assert_higher((elf_symbol *)sections[i].address); 30 | kernel_elf.symtab_size = sections[i].size; 31 | } 32 | } 33 | } 34 | 35 | char *kernel_lookup_symbol(uint32_t addr) 36 | { 37 | // Finds the name of the kernel function at addr. 38 | // Requires kernel_elf_init to be run first. 39 | 40 | uint32_t i; 41 | 42 | for(i=0; i < (kernel_elf.symtab_size/sizeof(elf_symbol)); i++) 43 | { 44 | if (ELF_ST_TYPE(kernel_elf.symtab[i].info) != 0x2) 45 | continue; 46 | if ((addr >= kernel_elf.symtab[i].value) && (addr < (kernel_elf.symtab[i].value + kernel_elf.symtab[i].size))) 47 | { 48 | char *name = (char *)((uint32_t)kernel_elf.strtab + kernel_elf.symtab[i].name); 49 | return name; 50 | } 51 | } 52 | return 0; 53 | } 54 | 55 | 56 | void load_elf_segment(INODE file, elf_phead *phead) 57 | { 58 | uint32_t flags = MM_FLAG_READ; 59 | if(phead->flags & ELF_PT_W) flags |= MM_FLAG_WRITE; 60 | uint32_t type = MM_TYPE_DATA; 61 | 62 | uint32_t memsize = phead->mem_size; // Size in memory 63 | uint32_t filesize = phead->file_size; // Size in file 64 | uint32_t mempos = phead->virtual_address; // Offset in memory 65 | uint32_t filepos = phead->offset; // Offset in file 66 | 67 | new_area(current->proc, mempos, mempos + memsize, flags, type); 68 | 69 | if(memsize == 0) return; // Nothing to load 70 | 71 | // Read the data right into memory 72 | vfs_read(file, (char *)mempos, filesize, filepos); 73 | // Fill the rest of the area with zeros 74 | memset((void *)(mempos + filesize), 0, memsize-filesize); 75 | } 76 | 77 | int _is_elf(elf_header *elf) 78 | { 79 | int iself = -1; 80 | 81 | if((elf->identity[0] == 0x7f) && !strncmp((char *)&elf->identity[1], "ELF", 3)) 82 | iself = 0; 83 | 84 | if(iself != -1) 85 | iself = elf->type; 86 | 87 | return iself; 88 | } 89 | int is_elf(INODE file) 90 | { 91 | elf_header *elf = malloc(sizeof(elf_header)); 92 | vfs_read(file, (char *)elf, sizeof(elf_header), 0); 93 | 94 | int iself = _is_elf(elf); 95 | 96 | free(elf); 97 | return iself; 98 | } 99 | 100 | int load_elf(INODE file) 101 | { 102 | // Read elf header from the file 103 | elf_header *elf = malloc(sizeof(elf_header)); 104 | vfs_read(file, (char *)elf, sizeof(elf_header), 0); 105 | 106 | // Check if the file is actually an elf executable 107 | if(_is_elf(elf) != ELF_TYPE_EXECUTABLE) 108 | return -1; 109 | 110 | // Read program headers from the file 111 | elf_phead *phead = malloc(sizeof(elf_phead)*elf->ph_num); 112 | vfs_read(file, (char *)phead, sizeof(elf_phead)*elf->ph_num, elf->ph_offset); 113 | 114 | // Prepare the memory manager 115 | process_mem_t *mm = ¤t->proc->mm; 116 | mm->code_start = ~0x0; 117 | mm->code_end = 0x0; 118 | 119 | uint32_t i; 120 | for(i=0; i < elf->ph_num; i++) 121 | { 122 | if(phead[i].type == ELF_PT_LOAD) 123 | { 124 | // If the current segment is loadable, load it and adjust 125 | // code area pointers accordingly. 126 | uintptr_t start = phead[i].virtual_address; 127 | uintptr_t end = start + phead[i].mem_size; 128 | if(start < mm->code_start) 129 | mm->code_start = start; 130 | if(end > mm->code_end) 131 | mm->code_end = end; 132 | 133 | load_elf_segment(file, &phead[i]); 134 | } 135 | } 136 | 137 | mm->data_end = mm->code_end; 138 | mm->code_entry = elf->entry; 139 | free(phead); 140 | free(elf); 141 | return 0; 142 | } 143 | 144 | -------------------------------------------------------------------------------- /kernel/proc/process.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | uint32_t next_pid = 1; 15 | 16 | extern int debug_enabled; 17 | 18 | list_head_t process_list; 19 | 20 | process_t *alloc_process() 21 | { 22 | process_t *p = malloc(sizeof(process_t)); 23 | memset(p, 0, sizeof(process_t)); 24 | 25 | p->pid = next_pid++; 26 | 27 | init_list(p->threads); 28 | init_list(p->proc_list); 29 | init_list(p->waiting); 30 | init_list(p->signal_queue); 31 | 32 | int i; 33 | for(i = 0; i < NUM_SIGNALS; i++) 34 | { 35 | p->signal_handler[i] = SIG_DFL; 36 | } 37 | 38 | append_to_list(process_list, p->proc_list); 39 | 40 | init_procmm(p); 41 | 42 | return p; 43 | 44 | } 45 | 46 | process_t *get_process(uint32_t pid) 47 | { 48 | list_t *i; 49 | for_each_in_list(&process_list, i) 50 | { 51 | process_t *p = list_entry(i, process_t, proc_list); 52 | if(p->pid == pid) 53 | return p; 54 | } 55 | return 0; 56 | } 57 | 58 | void free_process(process_t *proc) 59 | { 60 | 61 | list_t *i = (&proc->threads)->next; 62 | while (i != &proc->threads) 63 | { 64 | thread_t *th = list_entry(i, thread_t, process_threads); 65 | i = i->next; 66 | if(th != current) 67 | free_thread(th); 68 | } 69 | 70 | // Make init adopt all the processes children 71 | process_t *init = list_entry(process_list.next, process_t, proc_list); 72 | if(proc->child) 73 | { 74 | process_t *ch = proc->child; 75 | process_t *i = ch; 76 | while(i->older_sibling) 77 | { 78 | i->parent = init; 79 | i = i->older_sibling; 80 | } 81 | i->older_sibling = init->child; 82 | i->older_sibling->younger_sibling = i; 83 | init->child = ch; 84 | } 85 | 86 | // Remove from list of process tree 87 | process_t *parent = proc->parent; 88 | if(parent->child == proc) 89 | { 90 | if(proc->younger_sibling) 91 | parent->child = proc->younger_sibling; 92 | else if(proc->older_sibling) 93 | parent->child = proc->older_sibling; 94 | else 95 | parent->child = 0; 96 | } 97 | if(proc->older_sibling) 98 | proc->older_sibling->younger_sibling = proc->younger_sibling; 99 | if(proc->younger_sibling) 100 | proc->younger_sibling->older_sibling = proc->older_sibling; 101 | 102 | remove_from_list(proc->proc_list); 103 | 104 | procmm_exit(proc); 105 | 106 | free(proc); 107 | } 108 | 109 | void exit_process(process_t *proc, uint32_t exit_code) 110 | { 111 | proc->exit_code = exit_code; 112 | list_t *i = (&proc->threads)->next; 113 | while (i != &proc->threads) 114 | { 115 | thread_t *th = list_entry(i, thread_t, process_threads); 116 | i = i->next; 117 | if(th != current) 118 | free_thread(th); 119 | } 120 | 121 | proc->state = PROC_STATE_FINISHED; 122 | 123 | current->state = THREAD_STATE_FINISHED; 124 | 125 | scheduler_wake(&proc->waiting); 126 | } 127 | 128 | void switch_process(process_t *proc) 129 | { 130 | vmm_pd_set(proc->pd); 131 | } 132 | 133 | 134 | process_t *process_init(void (*func)(void)) 135 | { 136 | 137 | init_list(process_list); 138 | 139 | process_t *proc = alloc_process(); 140 | proc->pd = vmm_clone_pd(); 141 | 142 | thread_t *th = new_thread(func,0); 143 | append_to_list(proc->threads, th->process_threads); 144 | /* scheduler_remove(th); */ 145 | th->proc = proc; 146 | 147 | th->r.eflags = EFL_INT; 148 | set_kernel_stack(stack_from_tcb(th)); 149 | 150 | boot_thread = thinfo_from_tcb(th); 151 | 152 | switch_process(proc); 153 | 154 | return proc; 155 | } 156 | 157 | process_t *fork_process() 158 | { 159 | process_t *parent = current->proc; 160 | process_t *child = alloc_process(); 161 | 162 | // Clone memory map (copy on write for everything) 163 | procmm_fork(parent, child); 164 | // Clone page directory 165 | child->pd = vmm_clone_pd(); 166 | // Clone file descriptors 167 | memcpy(child->fd, parent->fd, sizeof(file_desc_t *)*NUM_FILEDES); 168 | int i; 169 | for(i = 0; i < NUM_FILEDES; i++) 170 | { 171 | if(child->fd[i]) 172 | { 173 | /* INODE pnode = child->fd[i]->ino; */ 174 | /* INODE cnode = child->fd[i]->ino = malloc(sizeof(vfs_node_t)); */ 175 | /* memcpy(cnode, pnode, sizeof(vfs_node_t)); */ 176 | fd_get(child->fd[i]); 177 | vfs_open(child->fd[i]->ino, child->fd[i]->flags); 178 | } 179 | } 180 | // Copy signal handler table 181 | memcpy(child->signal_handler, parent->signal_handler, sizeof(uintptr_t)*NUM_SIGNALS); 182 | init_list(child->signal_queue); 183 | 184 | child->cmdline = strdup(parent->cmdline); 185 | 186 | // Fix the family 187 | child->parent = parent; 188 | child->older_sibling = parent->child; 189 | if(child->older_sibling) 190 | child->older_sibling->younger_sibling = child; 191 | parent->child = child; 192 | 193 | thread_t *th = clone_thread(current); 194 | append_to_list(child->threads, th->process_threads); 195 | th->proc = child; 196 | 197 | return child; 198 | } 199 | 200 | -------------------------------------------------------------------------------- /kernel/drivers/debug.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | uint16_t *vidmem = (uint16_t *)VIDMEM; 12 | 13 | uint32_t scrn_x, scrn_y; 14 | 15 | uint8_t text_style; 16 | 17 | void kdbg_setcursor() 18 | { 19 | unsigned short position = scrn_y*80 + scrn_x; 20 | 21 | outb(0x3D4, 0x0F); 22 | outb(0x3D5, (unsigned char)(position & 0xFF)); 23 | outb(0x3D4, 0x0E); 24 | outb(0x3D5, (unsigned char)(position >> 8) & 0xF); 25 | } 26 | 27 | void kdbg_init() 28 | { 29 | // Setup screen for printing during kernel development. 30 | 31 | scrn_x = scrn_y = 0; 32 | text_style = VGA_STYLE(GRAY, BLACK); 33 | memset((uint8_t *)vidmem, 0x0, SCRN_W*SCRN_H*2); 34 | debug_sem = 0; 35 | init_serial(SERIAL_COM1); 36 | } 37 | 38 | void kdbg_setpos(uint32_t x, uint32_t y) 39 | { 40 | scrn_x = x; 41 | scrn_y = y; 42 | } 43 | 44 | void kdbg_getpos(uint32_t *x, uint32_t *y) 45 | { 46 | x[0] = scrn_x; 47 | y[0] = scrn_y; 48 | } 49 | 50 | void kdbg_scroll() 51 | { 52 | // Automatically scroll screen until the last row is clear. 53 | 54 | while (scrn_y > SCRN_H-1) 55 | { 56 | uint32_t i; 57 | for(i=0; i < SCRN_W*(SCRN_H-1); i++) 58 | vidmem[i] = vidmem[i+SCRN_W]; 59 | for(i=SCRN_W*(SCRN_H-1); i= SCRN_W) 90 | { 91 | scrn_x = 0; 92 | scrn_y++; 93 | } 94 | kdbg_scroll(); 95 | kdbg_setcursor(); 96 | str++; 97 | } 98 | } 99 | 100 | void kdbg_printf(char *str, ...) 101 | { 102 | va_list args; 103 | va_start(args, str); 104 | char buf[255]; 105 | uint32_t num; 106 | while(*str) 107 | { 108 | if(*str == '\n') // Newline 109 | { 110 | scrn_x = 0; 111 | scrn_y++; 112 | } 113 | else if(*str == '%') 114 | { 115 | str++; 116 | switch(*str) 117 | { 118 | case 'b': // binary number 119 | num = va_arg(args, uint32_t); 120 | kdbg_num2str(num, 2, buf); 121 | kdbg_printf(buf); 122 | kdbg_printf("b"); 123 | break; 124 | case 'o': // octal number 125 | num = va_arg(args, uint32_t); 126 | kdbg_num2str(num, 8, buf); 127 | kdbg_printf("0"); 128 | kdbg_printf(buf); 129 | break; 130 | case 'd': // decimal number 131 | num = va_arg(args, uint32_t); 132 | kdbg_num2str(num, 10, buf); 133 | kdbg_printf(buf); 134 | break; 135 | case 'x': // hexadecimal number 136 | num = va_arg(args, uint32_t); 137 | kdbg_num2str(num, 16, buf); 138 | kdbg_printf("0x"); 139 | kdbg_printf(buf); 140 | break; 141 | case 's': // string 142 | kdbg_printf(va_arg(args, char *)); 143 | break; 144 | case 'c': // char 145 | num = va_arg(args, uint32_t); 146 | kdbg_putch((char)num, text_style); 147 | scrn_x++; 148 | break; 149 | default: 150 | str--; 151 | kdbg_putch(*str, text_style); 152 | scrn_x++; 153 | } 154 | } 155 | else if(isprint((unsigned char)*str)) 156 | { 157 | kdbg_putch(*str, text_style); 158 | scrn_x++; 159 | } 160 | else 161 | { 162 | // Ignore non-printable characters 163 | ; 164 | } 165 | if(scrn_x >= SCRN_W) 166 | { 167 | scrn_x = 0; 168 | scrn_y++; 169 | } 170 | kdbg_scroll(); 171 | kdbg_setcursor(); 172 | str++; 173 | } 174 | va_end(args); 175 | 176 | } 177 | 178 | int kdbg_num2str(uint32_t num, uint32_t base, char *buf) 179 | { 180 | // Converts number num to a string in base base and puts it in buf. 181 | // Does not add pre- or suffixes. 182 | 183 | if(num == 0) 184 | { 185 | buf[0] = '0'; 186 | buf[1] = '\0'; 187 | return 0; 188 | } 189 | 190 | uint32_t i=0, j=0; 191 | 192 | while(num > 0) 193 | { 194 | if(num%base < 10) 195 | buf[i++] = (char)((uint32_t)'0' + num%base); 196 | else 197 | buf[i++] = (char)((uint32_t)'A' + num%base-10); 198 | num /= base; 199 | } 200 | 201 | // Flip string around 202 | for(i--, j=0; j 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | void sighandler_ignore(int num) 14 | { 15 | (void)num; 16 | return; 17 | } 18 | void sighandler_terminate(int num) 19 | { 20 | // Terminate process 21 | fprintf(stderr, "Process %x terminated by signal %x\n", \ 22 | current->proc->pid, num); 23 | _exit(num); 24 | return; 25 | } 26 | void sighandler_coredump(int num) 27 | { 28 | // Core dump and terminate 29 | (void)num; 30 | fprintf(stderr, "Process %x terminated by signal %x\n", \ 31 | current->proc->pid, num); 32 | fprintf(stderr, "Should make a core dump...\n"); 33 | _exit(num); 34 | return; 35 | } 36 | void sighandler_stop(int num) 37 | { 38 | // Stop process 39 | (void)num; 40 | return; 41 | } 42 | void sighandler_continue(int num) 43 | { 44 | // Continue stopped process 45 | (void)num; 46 | return; 47 | } 48 | 49 | 50 | sig_t default_sign[] = { 51 | 0, 52 | sighandler_terminate, // 1: SIGHUP 53 | sighandler_terminate, // 2: SIGING 54 | sighandler_coredump, // 3: SIGQUIT 55 | sighandler_coredump, // 4: SIGILL 56 | sighandler_coredump, // 5: SIGTRAP 57 | sighandler_coredump, // 6: SIGABRT 58 | sighandler_coredump, // 7: SIGEMT 59 | sighandler_coredump, // 8: SIGFPE 60 | sighandler_terminate, // 9: SIGKILL 61 | sighandler_coredump, // 10: SIGBUS 62 | sighandler_coredump, // 11: SIGSEGV 63 | sighandler_coredump, // 12: SIGSYS 64 | sighandler_terminate, // 13: SIGPIPE 65 | sighandler_terminate, // 14: SIGALRM 66 | sighandler_terminate, // 15: SIGTERM 67 | sighandler_terminate, // 16: SIGUSR1 68 | sighandler_terminate, // 17: SIGUSR2 69 | sighandler_ignore, // 18: SIGCHILD 70 | sighandler_ignore, // 19: SIGPWR 71 | sighandler_ignore, // 20: SIGWINCH 72 | sighandler_ignore, // 21: SIGURG 73 | sighandler_ignore, // 22: SIGPOLL 74 | sighandler_stop, // 23: SIGSTOP 75 | sighandler_stop, // 24: SIGTSTP 76 | sighandler_continue, // 25: SIGCONT 77 | sighandler_stop, // 26: SIGTTIN 78 | sighandler_stop, // 27: SIGTTOU 79 | sighandler_terminate, // 28: SIGVTALRM 80 | sighandler_terminate, // 29: SIGPROF 81 | sighandler_coredump, // 30: SIGXCPU 82 | sighandler_coredump, // 31: SIGXFSZ 83 | sighandler_ignore, // 32: SIGWAITING 84 | }; 85 | 86 | int signal_process(int pid, int signum) 87 | { 88 | process_t *p = get_process(pid); 89 | if(!p) 90 | return -1; 91 | if(p->state == PROC_STATE_FINISHED) 92 | return -1; 93 | 94 | signal_t *signal = malloc(sizeof(signal_t)); 95 | signal->sig = signum; 96 | signal->sender = current->proc->pid; 97 | init_list(signal->queue); 98 | append_to_list(p->signal_queue, signal->queue); 99 | if(p == current->proc) 100 | { 101 | // Handle signals immediately 102 | handle_signals(current); 103 | } 104 | list_t *i = p->threads.next; 105 | thread_t *th = list_entry(i, thread_t, process_threads); 106 | if(th->state == THREAD_STATE_WAITING) 107 | { 108 | // Handle signals now 109 | handle_signals(th); 110 | } 111 | return 0; 112 | } 113 | 114 | sig_t switch_handler(int signum, sig_t handler) 115 | { 116 | if(signum == SIGKILL) 117 | { 118 | // Never replace signal 9 119 | return SIG_DFL; 120 | } 121 | sig_t old = current->proc->signal_handler[signum]; 122 | current->proc->signal_handler[signum] = handler; 123 | return old; 124 | } 125 | 126 | void return_from_signal(registers_t *r) 127 | { 128 | (void)r; 129 | thread_t *th = current; 130 | scheduler_wake(&th->waiting); 131 | th->state = THREAD_STATE_FINISHED; 132 | scheduler_remove(th); 133 | 134 | schedule(); 135 | } 136 | 137 | thread_t *handle_signals(thread_t *th) 138 | { 139 | signal_t *signal = 0; 140 | list_t *i; 141 | for_each_in_list(&th->proc->signal_queue, i) 142 | { 143 | signal = list_entry(i, signal_t, queue); 144 | if(th->proc->signal_blocked[signal->sig]) 145 | continue; // The signal is blocked 146 | break; 147 | } 148 | if(signal) 149 | { 150 | // Handle signal 151 | if(th->proc->signal_handler[signal->sig] == SIG_IGN) 152 | { 153 | // Ignore 154 | remove_from_list(signal->queue); 155 | free(signal); 156 | } else if(th->proc->signal_handler[signal->sig] == SIG_DFL) 157 | { 158 | // Default 159 | sig_t handler = default_sign[signal->sig]; 160 | int signum = signal->sig; 161 | remove_from_list(signal->queue); 162 | free(signal); 163 | handler(signum); 164 | } else 165 | { 166 | // Custom 167 | switch_process(th->proc); 168 | sig_t handler = th->proc->signal_handler[signal->sig]; 169 | thread_t *h = new_thread((void (*)(void))handler, 1); 170 | 171 | append_to_list(th->proc->threads, h->process_threads); 172 | h->proc = th->proc; 173 | uint32_t *stack = (uint32_t *)th->r.useresp; 174 | *--stack = signal->sig; 175 | *--stack = SIGNAL_RETURN_ADDRESS; 176 | h->r.useresp = h->r.ebp = (uint32_t) stack; 177 | remove_from_list(signal->queue); 178 | free(signal); 179 | 180 | scheduler_remove(h); 181 | scheduler_sleep(th, &h->waiting); 182 | scheduler_cheat(h); 183 | schedule(); 184 | } 185 | } 186 | 187 | return th; 188 | } 189 | -------------------------------------------------------------------------------- /toolchain/rebuild_toolchain.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | if [ -z $BUILDROOT ]; then 5 | BUILDROOT=$DIR/.. 6 | fi 7 | 8 | . $BUILDROOT/util/common.sh 9 | 10 | binutilsv=binutils-2.24 11 | gccv=gcc-4.8.2 12 | 13 | function rebuild_binutils() { 14 | pushd $TEMPDIR >/dev/null 15 | 16 | ### Download and extract binutils 17 | # 18 | echo -e "${CLR_NO} Downloading ${CLR_BLUE}${binutilsv}${CLR_NO}" 19 | if [ ! -d $binutilsv ]; then 20 | download "Binutils" "ftp://ftp.gnu.org/gnu/binutils/" "${binutilsv}.tar.gz" 2>${TEMPDIR}/error.log || dropout 21 | echo -e "extracting" 22 | unzip "${binutilsv}.tar.gz" >/dev/null 2>${TEMPDIR}/error.log || dropout 23 | fi 24 | echo -en "${CLR_NO} Downloading ${CLR_BLUE}${binutilsv}${CLR_NO} ... " 25 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 26 | 27 | ### Patch binutils 28 | # 29 | echo -en "${CLR_NO} Patching ${CLR_BLUE}binutils${CLR_NO} ... " 30 | if [ ! -f $binutilsv/.patched ]; then 31 | dopatch "Binutils" $binutilsv $BUILDROOT/toolchain/binutils.patch >/dev/null 2>${TEMPDIR}/error.log || dropout 32 | touch $binutilsv/.patched 33 | fi 34 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 35 | 36 | ### Create or empty build directory 37 | # 38 | mkdir -p build-binutils 39 | pushd build-binutils >/dev/null 40 | rm -rf * 41 | 42 | ### ./configure 43 | # 44 | echo -en "${CLR_NO} Configuring ${CLR_BLUE}binutils${CLR_NO} ... " 45 | ../${binutilsv}/configure --disable-werror --target=$TARGET --prefix=$PREFIX >/dev/null 2>${TEMPDIR}/error.log || dropout 46 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 47 | 48 | ### make 49 | # 50 | echo -en "${CLR_NO} Building ${CLR_BLUE}binutils${CLR_NO} ... " 51 | make -j >/dev/null 2>${TEMPDIR}/error.log || dropout 52 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 53 | 54 | ### make install 55 | # 56 | echo -en "${CLR_NO} Installing ${CLR_BLUE}binutils${CLR_NO} ... " 57 | make install >/dev/null 2>${TEMPDIR}/error.log || dropout 58 | rm -r $PREFIX/share/locale 59 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 60 | 61 | popd >/dev/null 62 | popd >/dev/null 63 | 64 | ### Install homebrew links 65 | # 66 | brew unlink osdev 67 | brew link osdev 68 | } 69 | 70 | function rebuild_gcc() { 71 | pushd $TEMPDIR >/dev/null 72 | 73 | ### Download and extract gcc 74 | # 75 | echo -e "${CLR_NO} Downloading ${CLR_BLUE}${gccv}${CLR_NO}" 76 | if [ ! -d $gccv ]; then 77 | download "gcc" "ftp://ftp.gnu.org/gnu/gcc/${gccv}/" "${gccv}.tar.gz" 2>${TEMPDIR}/error.log || dropout 78 | echo -e "extracting" 79 | unzip "${gccv}.tar.gz" >/dev/null 2>${TEMPDIR}/error.log || dropout 80 | fi 81 | echo -en "${CLR_NO} Downloading ${CLR_BLUE}${gccv}${CLR_NO} ... " 82 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 83 | 84 | ### Patch gcc 85 | # 86 | echo -en "${CLR_NO} Patching ${CLR_BLUE}gcc${CLR_NO} ... " 87 | if [ ! -f $gccv/.patched ]; then 88 | dopatch "gcc" $gccv $BUILDROOT/toolchain/gcc.patch >/dev/null 2>${TEMPDIR}/error.log || dropout 89 | touch $gccv/.patched 90 | fi 91 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 92 | 93 | ### Create or empty build directory 94 | # 95 | mkdir -p build-gcc 96 | pushd build-gcc >/dev/null 97 | rm -rf * 98 | 99 | ### ./configure 100 | # 101 | echo -en "${CLR_NO} Configuring ${CLR_BLUE}gcc${CLR_NO} ... " 102 | ../${gccv}/configure --target=$TARGET --prefix=$PREFIX --disable-nls --enable-languages=c,c++ >/dev/null 2>${TEMPDIR}/error.log || dropout 103 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 104 | 105 | ### make gcc 106 | # 107 | echo -en "${CLR_NO} Building ${CLR_BLUE}gcc${CLR_NO} ... " 108 | make all-gcc -j >/dev/null 2>${TEMPDIR}/error.log || dropout 109 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 110 | 111 | ### make install gcc 112 | # 113 | echo -en "${CLR_NO} Installing ${CLR_BLUE}binutils${CLR_NO} ... " 114 | make install-gcc >/dev/null 2>${TEMPDIR}/error.log || dropout 115 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 116 | 117 | ### make libgcc 118 | # 119 | echo -en "${CLR_NO} Building ${CLR_BLUE}libgcc${CLR_NO} ... " 120 | make all-target-libgcc >/dev/null -j 2>${TEMPDIR}/error.log || dropout 121 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 122 | 123 | ### make install libgcc 124 | # 125 | echo -en "${CLR_NO} Installing ${CLR_BLUE}libgcc${CLR_NO} ... " 126 | make install-target-libgcc >/dev/null 2>${TEMPDIR}/error.log || dropout 127 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 128 | 129 | popd >/dev/null 130 | popd >/dev/null 131 | 132 | ### Install homebrew links 133 | # 134 | brew unlink osdev >/dev/null 135 | brew link osdev >/dev/null 136 | } 137 | 138 | rm ${TEMPDIR}/error.log 139 | 140 | type brew >/dev/null 2>&1 141 | if [ $? != 0 ]; then 142 | echo -e "${CLR_RED} Homebrew was not found!${CLR_NO}" 143 | echo "This build tool relies on homebrew for osx." 144 | echo "If you're on a mac, I recommend you look it up" 145 | echo "http://brew.sh" 146 | echo "" 147 | echo "If you're not on a mac, I can't help you." 148 | echo "I appologize for the inconvenience." 149 | dropout 150 | fi 151 | 152 | echo -en "${CLR_NO} Checking for ${CLR_BLUE}binutils${CLR_NO} ... " 153 | type ${TARGET}-ld >/dev/null 2>&1 154 | if [ $? != 0 ]; then 155 | echo -e "${CLR_YELLOW}[Missing]${CLR_NO}" 156 | echo -e "${CLR_BLUE} Building binutils${CLR_NO}" 157 | rebuild_binutils 158 | else 159 | echo -e "${CLR_GREEN}[OK]${CLR_NO}" 160 | fi 161 | 162 | echo -en "${CLR_NO} Checking for ${CLR_BLUE}gcc${CLR_NO} ... " 163 | type ${TARGET}-gcc >/dev/null 2>&1 164 | if [ $? != 0 ]; then 165 | echo -e "${CLR_YELLOW}[Missing]${CLR_NO}" 166 | echo -e "${CLR_BLUE} Building binutils${CLR_NO}" 167 | rebuild_gcc 168 | else 169 | echo -e "${CLR_GREEN}[OK]${CLR_NO}" 170 | fi 171 | -------------------------------------------------------------------------------- /kernel/fs/tarfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | vfs_driver_t tarfs_driver; 13 | 14 | void tartree_add_node(tree_t *tree, tar_header_t *tar, char *path) 15 | { 16 | char *p = strdup(path); 17 | char *s = p; 18 | tree_node_t *node = tree->root; 19 | 20 | p = strchr(p, '/'); 21 | 22 | for(p = strtok(p, "/"); p; p= strtok(NULL, "/")) 23 | { 24 | int found = 0; 25 | list_t *l; 26 | for_each_in_list(&node->children, l) 27 | { 28 | tree_node_t *tn = list_entry(l, tree_node_t, siblings); 29 | tarfs_entry_t *entry = tn->item; 30 | if(!strcmp(entry->name, p)) 31 | { 32 | found = 1; 33 | node = tn; 34 | break; 35 | } 36 | } 37 | if(!found) 38 | { 39 | tree_node_t *new = malloc(sizeof(tree_node_t)); 40 | init_tree_node(new); 41 | tarfs_entry_t *n = new->item = calloc(1, sizeof(tarfs_entry_t)); 42 | n->name = strdup(p); 43 | n->tar = tar; 44 | 45 | tree_make_child(node, new); 46 | node = new; 47 | } 48 | } 49 | free(s); 50 | } 51 | 52 | tree_t *build_tar_tree(tar_header_t *tar, INODE node) 53 | { 54 | tree_t *tree = malloc(sizeof(tree_t)); 55 | 56 | tree_node_t *root = tree->root = malloc(sizeof(tree_node_t)); 57 | init_tree_node(root); 58 | tarfs_entry_t *n = calloc(1, sizeof(tarfs_entry_t)); 59 | 60 | char *s = strdup((const char *)tar->name); 61 | n->name = strdup(strtok(s, "/")); 62 | free(s); 63 | n->tar = tar; 64 | root->item = n; 65 | n->buffer = node; 66 | n->users = 1; 67 | 68 | while(tar->name[0]) 69 | { 70 | tartree_add_node(tree, tar, (char *)&tar->name); 71 | uint32_t size; 72 | sscanf((char *)&tar->size, "%o", &size); 73 | tar = (tar_header_t *)((uint32_t)tar + size + 512); 74 | if((uint32_t)tar % 512) 75 | tar = (tar_header_t *)((uint32_t)tar + 512 - ((uint32_t)tar%512)); 76 | } 77 | 78 | return tree; 79 | } 80 | 81 | INODE tar_get_inode(tree_node_t *tn) 82 | { 83 | tarfs_entry_t *entry = tn->item; 84 | if(entry->buffer) 85 | { 86 | entry->users++; 87 | return entry->buffer; 88 | } 89 | 90 | INODE node = entry->buffer = calloc(1, sizeof(vfs_node_t)); 91 | strcpy(node->name, entry->name); 92 | node->d = &tarfs_driver; 93 | node->data = (void *)tn; 94 | sscanf((char *)&entry->tar->size, "%o", &node->length); 95 | if(entry->tar->type[0] == TAR_TYPE_DIR) 96 | { 97 | node->type = FS_DIRECTORY; 98 | } else { 99 | node->type = FS_FILE; 100 | } 101 | entry->users = 1; 102 | 103 | return node; 104 | } 105 | 106 | 107 | void flush_tar(INODE node) 108 | { 109 | tree_node_t *tn = node->data; 110 | tarfs_entry_t *entry = tn->item; 111 | if(entry->buffer != node) 112 | { 113 | debug("[error] Free bad tars inode %x %x %s\n", node, entry->buffer, node->name); 114 | } 115 | entry->users--; 116 | if(entry->users == 0) 117 | { 118 | free(entry->buffer); 119 | entry->buffer = 0; 120 | } 121 | } 122 | 123 | uint32_t read_tar(INODE node, void *buffer, uint32_t size, uint32_t offset) 124 | { 125 | tree_node_t *tn = (tree_node_t *)node->data; 126 | tarfs_entry_t *te = (tarfs_entry_t *)tn->item; 127 | tar_header_t *tar = te->tar; 128 | 129 | uint32_t tsz; 130 | sscanf((char *)&tar->size, "%o", &tsz); 131 | if(offset > tsz) return 0; 132 | 133 | if((size + offset) > tsz) 134 | size = tsz - offset; 135 | 136 | offset = offset + (uint32_t)tar + 512; 137 | 138 | memcpy(buffer, (void *)offset, size); 139 | if(size == tsz - offset) 140 | { 141 | ((char *)buffer)[size] = EOF; 142 | } 143 | return size; 144 | } 145 | 146 | uint32_t write_tar(INODE node, void *buffer, uint32_t size, uint32_t offset) 147 | { 148 | (void)node; 149 | (void)buffer; 150 | (void)size; 151 | (void)offset; 152 | return 0; 153 | } 154 | 155 | int32_t open_tar(INODE node, uint32_t flags) 156 | { 157 | (void)node; 158 | (void)flags; 159 | return 0; 160 | } 161 | 162 | int32_t close_tar(INODE node) 163 | { 164 | (void)node; 165 | return 0; 166 | } 167 | 168 | dirent_t *tar_readdir(INODE node, uint32_t index) 169 | { 170 | tree_node_t *tn = (tree_node_t *)node->data; 171 | dirent_t *de = calloc(1, sizeof(dirent_t)); 172 | 173 | if(index == 0) 174 | { 175 | // Special case for . 176 | strcpy(de->name, "."); 177 | de->ino = tar_get_inode(tn); 178 | return de; 179 | } 180 | if(index == 1) 181 | { 182 | // Special case for .. 183 | strcpy(de->name, ".."); 184 | de->ino = tar_get_inode(tn->parent); 185 | return de; 186 | } 187 | index--; 188 | 189 | list_t *l = 0; 190 | for_each_in_list(&tn->children, l) 191 | { 192 | index--; 193 | if(!index) break; 194 | } 195 | if(index) 196 | { 197 | // Reached end of directory 198 | free(de); 199 | return 0; 200 | } 201 | 202 | tree_node_t *cn = list_entry(l, tree_node_t, siblings); 203 | tarfs_entry_t *entry = cn->item; 204 | 205 | strcpy(de->name, entry->name); 206 | de->ino = tar_get_inode(cn); 207 | return de; 208 | } 209 | 210 | INODE tar_finddir(INODE dir, const char *name) 211 | { 212 | tree_node_t *tn = (tree_node_t *)dir->data; 213 | list_t *l; 214 | tarfs_entry_t *entry = 0; 215 | tree_node_t *cn = 0; 216 | 217 | // Special cases for . and .. 218 | if(!strcmp(name, ".")) 219 | return tar_get_inode(tn); 220 | if(!strcmp(name, "..")) 221 | return tar_get_inode(tn->parent); 222 | 223 | for_each_in_list(&tn->children, l) 224 | { 225 | cn = list_entry(l, tree_node_t, siblings); 226 | entry = cn->item; 227 | if(!strcmp(entry->name, name)) 228 | { 229 | return tar_get_inode(cn); 230 | } 231 | } 232 | 233 | return 0; 234 | } 235 | 236 | 237 | 238 | vfs_driver_t tarfs_driver = 239 | { 240 | open_tar, 241 | close_tar, 242 | read_tar, 243 | write_tar, 244 | 0, 245 | 0, 246 | 0, 247 | 0, 248 | 0, 249 | tar_readdir, 250 | tar_finddir, 251 | flush_tar 252 | }; 253 | 254 | INODE tarfs_init(tar_header_t *tar) 255 | { 256 | vfs_node_t *node = calloc(1,sizeof(vfs_node_t)); 257 | strcpy(node->name, "tarfs"); 258 | node->d = &tarfs_driver; 259 | node->type = FS_DIRECTORY; 260 | 261 | tree_t *tar_tree = build_tar_tree(tar, node); 262 | node->data = tar_tree->root; 263 | free(tar_tree); 264 | 265 | return node; 266 | } 267 | -------------------------------------------------------------------------------- /toolchain/myos/syscalls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #undef errno 12 | extern int errno; 13 | 14 | #define NDEBUG 15 | extern char **environ; 16 | 17 | #ifndef KERNEL_MODE 18 | 19 | char *__env[1] = { 0 }; 20 | 21 | void _init(uint32_t *args) 22 | { 23 | /* _init_signal(); */ 24 | 25 | int argc; 26 | char **argv; 27 | if(args) 28 | { 29 | argc = args[0]; 30 | argv = (char **)args[1]; 31 | environ = (char **)args[2]; 32 | } else { 33 | argc = 0; 34 | argv = 0; 35 | environ = __env; 36 | } 37 | 38 | exit(main(argc, argv)); 39 | for(;;); 40 | } 41 | 42 | 43 | void _exit(int rc) 44 | { 45 | #ifndef NDEBUG 46 | _syscall_printf("\n Syscall _exit(%x)", rc); 47 | #endif 48 | 49 | _syscall_exit(rc); 50 | for(;;); 51 | } 52 | 53 | int close(int file) 54 | { 55 | #ifndef NDEBUG 56 | _syscall_printf("\n Syscall close(%x)", file); 57 | #endif 58 | 59 | int ret = _syscall_close(file); 60 | errno = syscall_errno; 61 | return ret; 62 | } 63 | 64 | int execve(const char *name, char *const argv[], char *env[]) 65 | { 66 | #ifndef NDEBUG 67 | _syscall_printf("\n Syscall execve(%s, %x, %x)", name, argv, env); 68 | #endif 69 | /* errno = ENOMEM; */ 70 | /* return -1; */ 71 | int ret = _syscall_execve(name, argv, env); 72 | errno = syscall_errno; 73 | return ret; 74 | } 75 | 76 | int fork() 77 | { 78 | #ifndef NDEBUG 79 | _syscall_printf("\n Syscall fork()"); 80 | #endif 81 | int ret = _syscall_fork(); 82 | errno = syscall_errno; 83 | return ret; 84 | } 85 | 86 | int fstat(int file, struct stat *st) 87 | { 88 | #ifndef NDEBUG 89 | _syscall_printf("\n Syscall fstat(%x, %x)",file, st); 90 | #endif 91 | /* st->st_mode = S_IFCHR; */ 92 | /* return -1; */ 93 | int ret = _syscall_fstat(file, st); 94 | errno = syscall_errno; 95 | return ret; 96 | } 97 | 98 | int getpid() 99 | { 100 | #ifndef NDEBUG 101 | _syscall_printf("\n Syscall getpid()"); 102 | #endif 103 | 104 | int ret = _syscall_getpid(); 105 | errno = syscall_errno; 106 | return ret; 107 | } 108 | 109 | int isatty(int file) 110 | { 111 | #ifndef NDEBUG 112 | _syscall_printf("\n Syscall isatty(%x)", file); 113 | #endif 114 | /* return 1; */ 115 | int ret = _syscall_isatty(file); 116 | errno = syscall_errno; 117 | return ret; 118 | } 119 | 120 | int kill(int pid, int sig) 121 | { 122 | #ifndef NDEBUG 123 | _syscall_printf("\n Syscall kill(%x, %x)", pid, sig); 124 | #endif 125 | /* errno = EINVAL; */ 126 | /* return -1; */ 127 | int ret = _syscall_kill(pid, sig); 128 | errno = syscall_errno; 129 | return ret; 130 | } 131 | 132 | int link(char *old, char *new) 133 | { 134 | #ifndef NDEBUG 135 | _syscall_printf("\n Syscall link(%s, %s)", old, new); 136 | #endif 137 | /* errno=EMLINK; */ 138 | /* return -1; */ 139 | int ret = _syscall_link(old, new); 140 | errno = syscall_errno; 141 | return ret; 142 | } 143 | 144 | int lseek(int file, int ptr, int dir) 145 | { 146 | #ifndef NDEBUG 147 | _syscall_printf("\n Syscall lseek(%x, %x, %x)", file, ptr, dir); 148 | #endif 149 | /* return 0; */ 150 | int ret = _syscall_lseek(file, ptr, dir); 151 | errno = syscall_errno; 152 | return ret; 153 | } 154 | 155 | int open(const char *name, int flags, ...) 156 | { 157 | #ifndef NDEBUG 158 | _syscall_printf("\n Syscall open(%s %x)", name, flags); 159 | #endif 160 | int ret = _syscall_open(name, flags, 0); 161 | errno = syscall_errno; 162 | return ret; 163 | } 164 | 165 | int read(int file, char *ptr, int len) 166 | { 167 | #ifndef NDEBUG 168 | _syscall_printf("\n Syscall read(%x, %x, %x)", file, ptr, len); 169 | #endif 170 | /* return 0; */ 171 | int ret = _syscall_read(file, ptr, len); 172 | errno = syscall_errno; 173 | return ret; 174 | } 175 | 176 | void *sbrk(int incr) 177 | { 178 | #ifndef NDEBUG 179 | _syscall_printf("\n Syscall sbrk(%x)", incr); 180 | #endif 181 | void *ret = (void *)_syscall_sbrk(incr); 182 | errno = syscall_errno; 183 | return ret; 184 | } 185 | 186 | int stat(const char *file, struct stat *st) 187 | { 188 | #ifndef NDEBUG 189 | _syscall_printf("\n Syscall stat(%s, %x)", file, st); 190 | #endif 191 | /* st->st_mode = S_IFCHR; */ 192 | /* return 0; */ 193 | int ret = _syscall_stat(file, st); 194 | errno = syscall_errno; 195 | return ret; 196 | } 197 | 198 | clock_t times(struct tms *buf) 199 | { 200 | #ifndef NDEBUG 201 | _syscall_printf("\n Syscall times(%x)", buf); 202 | #endif 203 | /* return -1; */ 204 | clock_t ret = (clock_t)_syscall_times(buf); 205 | errno = syscall_errno; 206 | return ret; 207 | } 208 | 209 | int unlink(char *name) 210 | { 211 | #ifndef NDEBUG 212 | _syscall_printf("\n Syscall unlink(%s)", name); 213 | #endif 214 | /* errno=ENOENT; */ 215 | /* return -1; */ 216 | int ret = _syscall_unlink(name); 217 | errno = syscall_errno; 218 | return ret; 219 | } 220 | 221 | int wait(int *status) 222 | { 223 | #ifndef NDEBUG 224 | _syscall_printf("\n Syscall wait(%x)", status); 225 | #endif 226 | /* errno = ECHILD; */ 227 | /* return -1; */ 228 | int ret = _syscall_wait(status); 229 | errno = syscall_errno; 230 | return ret; 231 | } 232 | 233 | int write(int file, char *ptr, int len) 234 | { 235 | ptr[len] = '\0'; 236 | #ifndef NDEBUG 237 | _syscall_printf("\n Syscall write()"); 238 | #endif 239 | int ret = _syscall_write(file, ptr, len); 240 | errno = syscall_errno; 241 | return ret; 242 | } 243 | 244 | sig_t signal(int signum, sig_t handler) 245 | { 246 | sig_t ret = (sig_t)_syscall_signal(signum, handler); 247 | errno = syscall_errno; 248 | return ret; 249 | } 250 | 251 | int dup(int fildes) 252 | { 253 | int ret = _syscall_dup(fildes); 254 | errno = syscall_errno; 255 | return ret; 256 | } 257 | 258 | int dup2(int fildes1, int fildes2) 259 | { 260 | int ret = _syscall_dup2(fildes1, fildes2); 261 | errno = syscall_errno; 262 | return ret; 263 | } 264 | 265 | int pipe(int fildes[2]) 266 | { 267 | int ret = _syscall_pipe(fildes); 268 | errno = syscall_errno; 269 | return ret; 270 | } 271 | 272 | #endif 273 | 274 | int execvp(const char *file, char *const argv[]) 275 | { 276 | int i = 0; 277 | int addpath = 1; 278 | while(file[i]) 279 | { 280 | if(file[i] == '/') 281 | { 282 | addpath = 0; 283 | break; 284 | } 285 | i++; 286 | } 287 | 288 | if(addpath) 289 | { 290 | char *path = strdup(getenv("PATH")); 291 | if(!path) path = "/usr/sbin:/bin"; 292 | char *brk; 293 | char *p = strtok_r(path, ":", &brk); 294 | while(p) 295 | { 296 | char *fullpath = malloc(strlen(p) + strlen(file) + 1); 297 | strcpy(fullpath, p); 298 | strcat(fullpath, "/"); 299 | strcat(fullpath, file); 300 | 301 | execve(fullpath, argv, environ); 302 | 303 | p = strtok_r(NULL, ":", &brk); 304 | } 305 | } else { 306 | execve(file, argv, environ); 307 | } 308 | 309 | return -1; 310 | } 311 | 312 | -------------------------------------------------------------------------------- /kernel/arch/idt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | idt_entry_t idt[NUM_INTERRUPTS]; 10 | int_handler_t int_handlers[NUM_INTERRUPTS]; 11 | struct idt_pointer idt_p; 12 | extern gdt_entry_t gdt[6]; 13 | 14 | // ASM isr stubs found in int.S 15 | extern isr_t isr0, isr1, isr2, isr3, isr4, isr5, isr6, isr7, isr8, \ 16 | isr9, isr10, isr11, isr12, isr13, isr14, isr15, isr16, isr17, \ 17 | isr18, isr19, isr20, isr21, isr22, isr23, isr24, isr25, isr26, \ 18 | isr27, isr28, isr29, isr30, isr31, isr32, isr33, isr34, isr35, \ 19 | isr36, isr37, isr38, isr39, isr40, isr41, isr42, isr43, isr44, \ 20 | isr45, isr46, isr47, isr128, isr130, isr255; 21 | 22 | // List of isrs 23 | isr_t *idt_raw[] = 24 | { 25 | &isr0, &isr1, &isr2, &isr3, &isr4, 26 | &isr5, &isr6, &isr7, &isr8, &isr9, //9 27 | &isr10, &isr11, &isr12, &isr13, &isr14, 28 | &isr15, &isr16, &isr17, &isr18, &isr19, //19 29 | &isr20, &isr21, &isr22, &isr23, &isr24, 30 | &isr25, &isr26, &isr27, &isr28, &isr29, //29 31 | &isr30, &isr31, &isr32, &isr33, &isr34, 32 | &isr35, &isr36, &isr37, &isr38, &isr39, //39 33 | &isr40, &isr41, &isr42, &isr43, &isr44, 34 | &isr45, &isr46, &isr47, 0, 0, //49 35 | 0, 0, 0, 0, 0, 36 | 0, 0, 0, 0, 0, //59 37 | 0, 0, 0, 0, 0, 38 | 0, 0, 0, 0, 0, //69 39 | 0, 0, 0, 0, 0, 40 | 0, 0, 0, 0, 0, //79 41 | 0, 0, 0, 0, 0, 42 | 0, 0, 0, 0, 0, //89 43 | 0, 0, 0, 0, 0, 44 | 0, 0, 0, 0, 0, //99 45 | 0, 0, 0, 0, 0, 46 | 0, 0, 0, 0, 0, //109 47 | 0, 0, 0, 0, 0, 48 | 0, 0, 0, 0, 0, //119 49 | 0, 0, 0, 0, 0, 50 | 0, 0, 0, &isr128, 0, //129 51 | &isr130, 0, 0, 0, 0, 52 | 0, 0, 0, 0, 0, //139 53 | 0, 0, 0, 0, 0, 54 | 0, 0, 0, 0, 0, //149 55 | 0, 0, 0, 0, 0, 56 | 0, 0, 0, 0, 0, //159 57 | 0, 0, 0, 0, 0, 58 | 0, 0, 0, 0, 0, //169 59 | 0, 0, 0, 0, 0, 60 | 0, 0, 0, 0, 0, //179 61 | 0, 0, 0, 0, 0, 62 | 0, 0, 0, 0, 0, //189 63 | 0, 0, 0, 0, 0, 64 | 0, 0, 0, 0, 0, //199 65 | 0, 0, 0, 0, 0, 66 | 0, 0, 0, 0, 0, //209 67 | 0, 0, 0, 0, 0, 68 | 0, 0, 0, 0, 0, //219 69 | 0, 0, 0, 0, 0, 70 | 0, 0, 0, 0, 0, //229 71 | 0, 0, 0, 0, 0, 72 | 0, 0, 0, 0, 0, //239 73 | 0, 0, 0, 0, 0, 74 | 0, 0, 0, 0, 0, //249 75 | 0, 0, 0, 0, 0, 76 | &isr255 77 | }; 78 | 79 | void idt_set(uint32_t num, uint32_t base, uint32_t segment, uint8_t flags) 80 | { 81 | if(!base) return; 82 | 83 | idt_set_base(idt[num], base); 84 | idt[num].segment = segment; 85 | idt[num].reserved = 0; 86 | idt[num].flags = flags; 87 | } 88 | 89 | void mask_int(unsigned char int_no) 90 | { 91 | // Disables interrupt int_no 92 | 93 | uint16_t port; 94 | uint8_t mask; 95 | 96 | if(int_no < 8) 97 | { 98 | port = MPIC_DATA_PORT; 99 | } 100 | else 101 | { 102 | port = SPIC_DATA_PORT; 103 | int_no -= 8; 104 | } 105 | 106 | mask = inb(port) | (1 << int_no); 107 | outb(port, mask); 108 | } 109 | 110 | void unmask_int(unsigned char int_no) 111 | { 112 | // Enable interrupt int_no 113 | 114 | uint16_t port; 115 | uint8_t mask; 116 | 117 | if(int_no < 8) 118 | { 119 | port = MPIC_DATA_PORT; 120 | } 121 | else 122 | { 123 | port = SPIC_DATA_PORT; 124 | int_no -= 8; 125 | } 126 | 127 | mask = inb(port) & ~(1 << int_no); 128 | outb(port, mask); 129 | } 130 | 131 | void idt_init() 132 | { 133 | // Setup interrupt handling 134 | 135 | // Set up the PIC 136 | outb(MPIC_CMD_PORT, 0x11); 137 | outb(SPIC_CMD_PORT, 0x11); 138 | outb(MPIC_DATA_PORT, 0x20); 139 | outb(SPIC_DATA_PORT, 0x28); 140 | outb(MPIC_DATA_PORT, 0x04); 141 | outb(SPIC_DATA_PORT, 0x02); 142 | outb(MPIC_DATA_PORT, 0x01); 143 | outb(SPIC_DATA_PORT, 0x01); 144 | 145 | // Enable all interrupts 146 | outb(MPIC_DATA_PORT, 0x0); 147 | outb(SPIC_DATA_PORT, 0x0); 148 | 149 | // Prepare pointer to new IDT 150 | idt_p.size = (sizeof(idt_entry_t)*NUM_INTERRUPTS) - 1; 151 | idt_p.offset = (uint32_t)&idt; 152 | 153 | memset(idt,0,sizeof(idt_entry_t)*NUM_INTERRUPTS); 154 | memset(int_handlers,0,sizeof(int_handler_t)*NUM_INTERRUPTS); 155 | 156 | // Setup IDT with pointers to the ASM stubs 157 | uint32_t i; 158 | for(i = 0; i < NUM_INTERRUPTS; i++) 159 | { 160 | if(idt_raw[i]) 161 | { 162 | idt_set(i, (uint32_t)idt_raw[i], SEG_KERNEL_CODE, IDT_PRESENT | IDT_INT_GATE); 163 | } 164 | } 165 | 166 | // Syscall interrupts should be callable from userspace 167 | idt[128].flags |= IDT_DPL_3; 168 | idt[255].flags |= IDT_DPL_3; 169 | 170 | // Enable new IDT 171 | idt_flush((uint32_t)&idt_p); 172 | } 173 | 174 | registers_t *idt_handler(registers_t *r) 175 | { 176 | // Common for all interrupt handlers 177 | // Should have another name... 178 | 179 | if(ISIRQ(r->int_no)) 180 | { 181 | // If the interrupt was issued by an IRQ, reset the IRQ handler. 182 | if(INT2IRQ(r->int_no) > 8) 183 | outb(SPIC_CMD_PORT, PIC_EOI); 184 | outb(MPIC_CMD_PORT, PIC_EOI); 185 | } 186 | 187 | if(int_handlers[r->int_no]) 188 | { 189 | // If there is an assigned handler for the interrupt 190 | 191 | // Enable all interrupts but the one we just got 192 | /* mask_int(INT2IRQ(r->int_no)); */ 193 | /* enable_interrupts(); */ 194 | 195 | // Run the assigned interrupts handler 196 | registers_t *ret = int_handlers[r->int_no](r); 197 | 198 | // If we return to a user mode thread, the TCB needs to be set up 199 | // appropriately and interrupts should be enabled. 200 | // Also handle signals here. 201 | if ((ret->cs & 0x3) == 0x3) 202 | { 203 | ret = (registers_t *)handle_signals((thread_t *)ret); 204 | set_kernel_stack(stack_from_tcb(((thread_t *)ret))); 205 | ret->eflags |= EFL_INT; 206 | } 207 | 208 | // Reenable the handled interrupt 209 | /* unmask_int(INT2IRQ(r->int_no)); */ 210 | 211 | return ret; 212 | } else { 213 | if(!ISIRQ(r->int_no)) 214 | { 215 | // If an unhandled interrupt (not IRQ) was issued, halt everything. 216 | 217 | disable_interrupts(); 218 | debug("[error]Unhanded interrupt received, %x\n", r->int_no); 219 | if(ISIRQ(r->int_no)) 220 | debug(", irq %x", INT2IRQ(r->int_no)); 221 | debug("\n Tid: %x", current->tid); 222 | print_registers(r); 223 | for(;;); 224 | } else { 225 | return r; 226 | } 227 | } 228 | 229 | } 230 | 231 | int_handler_t register_int_handler(uint32_t num, int_handler_t handler) 232 | { 233 | // Add interrupt handler to list of interrupt handlers :p 234 | 235 | int_handler_t old = int_handlers[num]; 236 | int_handlers[num] = handler; 237 | return old; 238 | } 239 | 240 | void tss_init() 241 | { 242 | // Set up the TSS. Very basis setup since the only thing that ever 243 | // changes is the stack pointer. 244 | uint32_t base = (uint32_t)&global_tss; 245 | uint32_t limit = sizeof(tss_t); 246 | 247 | set_gdt_base(gdt[GDT_TSS], base); 248 | set_gdt_limit(gdt[GDT_TSS], limit); 249 | gdt[GDT_TSS].flags = 0; 250 | gdt[GDT_TSS].access = 0x89; 251 | 252 | memset(&global_tss, 0, sizeof(tss_t)); 253 | global_tss.ss0 = SEG_KERNEL_DATA; 254 | global_tss.iomap = sizeof(tss_t); 255 | 256 | tss_flush(SEG_TSS); 257 | } 258 | 259 | -------------------------------------------------------------------------------- /toolchain/rebuild_newlib.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | if [ -z $BUILDROOT ]; then 5 | BUILDROOT=$DIR/.. 6 | fi 7 | 8 | . $BUILDROOT/util/common.sh 9 | 10 | newlibv=newlib-2.1.0 11 | 12 | function prepare_automake() { 13 | pushd $TEMPDIR >/dev/null 14 | 15 | ### Install correct version of automake 16 | # 17 | if [ ! -d /usr/local/Cellar/automake/1.12 ]; then 18 | echo -e "${CLR_NO} Downloading ${CLR_BLUE}automake${CLR_NO}" 19 | download "automake" "http://ftp.gnu.org/gnu/automake/" "automake-1.12.tar.gz" 2>${TEMPDIR}/error.log || dropout 20 | echo -e "extracting" 21 | unzip "automake-1.12.tar.gz" >/dev/null 2>${TEMPDIR}/error.log || dropout 22 | echo -en "${CLR_NO} Downloading ${CLR_BLUE}automake${CLR_NO} ... " 23 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 24 | 25 | mkdir -p build-automake 26 | pushd build-automake >/dev/null 27 | rm -rf * 28 | 29 | ### ./configure 30 | # 31 | echo -en "${CLR_NO} Configuring ${CLR_BLUE}automake${CLR_NO} ... " 32 | ../automake-1.12/configure --prefix=/usr/local/Cellar/automake/1.12 >/dev/null 2>${TEMPDIR}/error.log || dropout 33 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 34 | 35 | ### make 36 | # 37 | echo -en "${CLR_NO} Building ${CLR_BLUE}automake${CLR_NO} ... " 38 | make all -j >/dev/null 2>${TEMPDIR}/error.log || dropout 39 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 40 | 41 | ### make install 42 | # 43 | echo -en "${CLR_NO} Installing ${CLR_BLUE}automake${CLR_NO} ... " 44 | make install >/dev/null 2>${TEMPDIR}/error.log || dropout 45 | rm -r $PREFIX/share/locale 46 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 47 | popd 48 | fi 49 | 50 | popd 51 | 52 | brew switch automake 1.12 >/dev/null 53 | } 54 | 55 | function prepare_autoconf() { 56 | pushd $TEMPDIR >/dev/null 57 | 58 | ### Install correct version of autoconf 59 | # 60 | if [ ! -d /usr/local/Cellar/autoconf/2.64 ]; then 61 | echo -e "${CLR_NO} Downloading ${CLR_BLUE}autoconf${CLR_NO}" 62 | download "autoconf" "http://ftp.gnu.org/gnu/autoconf/" "autoconf-2.64.tar.gz" 2>${TEMPDIR}/error.log || dropout 63 | echo -e "extracting" 64 | unzip "autoconf-1.12.tar.gz" >/dev/null 2>${TEMPDIR}/error.log || dropout 65 | echo -en "${CLR_NO} Downloading ${CLR_BLUE}autoconf${CLR_NO} ... " 66 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 67 | 68 | mkdir -p build-autoconf 69 | pushd build-autoconf >/dev/null 70 | rm -rf * 71 | 72 | ### ./configure 73 | # 74 | echo -en "${CLR_NO} Configuring ${CLR_BLUE}autoconf${CLR_NO} ... " 75 | ../autoconf-2.64/configure --prefix=/usr/local/Cellar/autoconf/2.64 >/dev/null 2>${TEMPDIR}/error.log || dropout 76 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 77 | 78 | ### make 79 | # 80 | echo -en "${CLR_NO} Building ${CLR_BLUE}autoconf${CLR_NO} ... " 81 | make all -j >/dev/null 2>${TEMPDIR}/error.log || dropout 82 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 83 | 84 | ### make install 85 | # 86 | echo -en "${CLR_NO} Installing ${CLR_BLUE}autoconf${CLR_NO} ... " 87 | make install >/dev/null 2>${TEMPDIR}/error.log || dropout 88 | rm -r $PREFIX/share/locale 89 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 90 | popd 91 | fi 92 | popd 93 | 94 | brew switch autoconf 2.64 >/dev/null 95 | } 96 | 97 | function rebuild_newlib { 98 | pushd $TEMPDIR >/dev/null 99 | 100 | ### Download and extract newlib 101 | # 102 | echo -e "${CLR_NO} Downloading ${CLR_BLUE}${newlibv}${CLR_NO}" 103 | if [ ! -d $newlibv ]; then 104 | download "Newlib" "ftp://sourceware.org/pub/newlib/" "${newlibv}.tar.gz" 2>${TEMPDIR}/error.log || dropout 105 | echo -e "extracting" 106 | unzip "${newlibv}.tar.gz" >/dev/null 2>${TEMPDIR}/error.log || dropout 107 | fi 108 | echo -en "${CLR_NO} Downloading ${CLR_BLUE}${newlibv}${CLR_NO} ... " 109 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 110 | 111 | ### Patch newlib 112 | # 113 | echo -en "${CLR_NO} Patching ${CLR_BLUE}newlib${CLR_NO} ... " 114 | if [ ! -f $newlibv/.patched ] || [ "$1" = force ]; then 115 | dopatch "Newlib" $newlibv $BUILDROOT/toolchain/newlib.patch >/dev/null 2>${TEMPDIR}/error.log || dropout 116 | pushd $newlibv/newlib/libc/sys >/dev/null 117 | cp -r $BUILDROOT/toolchain/myos . 118 | autoconf >/dev/null 2>${TEMPDIR}/error.log || dropout 119 | pushd myos >/dev/null 120 | autoreconf >/dev/null 2>${TEMPDIR}/error.log || dropout 121 | popd >/dev/null 122 | popd >/dev/null 123 | touch $newlibv/.patched 124 | fi 125 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 126 | 127 | ### Create or empty build directory 128 | # 129 | mkdir -p build-newlib 130 | pushd build-newlib >/dev/null 131 | rm -rf * 132 | 133 | ### ./configure 134 | # 135 | echo -en "${CLR_NO} Configuring ${CLR_BLUE}newlib${CLR_NO} ... " 136 | ../${newlibv}/configure --target=$TARGET --prefix=$PREFIX >/dev/null 2>${TEMPDIR}/error.log || dropout 137 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 138 | 139 | ### make 140 | # 141 | echo -en "${CLR_NO} Building ${CLR_BLUE}kernel library${CLR_NO} ... " 142 | CPPFLAGS_FOR_TARGET=-DKERNEL_MODE make -j >/dev/null 2>${TEMPDIR}/error.log || dropout 143 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 144 | 145 | ### make install 146 | # 147 | echo -en "${CLR_NO} Installing ${CLR_BLUE}kernel library${CLR_NO} ... " 148 | make install >/dev/null 2>${TEMPDIR}/error.log || dropout 149 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 150 | mv $PREFIX/$TARGET/lib/libc.a $PREFIX/$TARGET/lib/libkernel.a 151 | 152 | rm -rf * 153 | 154 | ### ./configure 155 | # 156 | echo -en "${CLR_NO} Configuring ${CLR_BLUE}newlib${CLR_NO} again ... " 157 | ../${newlibv}/configure --target=$TARGET --prefix=$PREFIX >/dev/null 2>${TEMPDIR}/error.log || dropout 158 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 159 | 160 | ### make 161 | # 162 | echo -en "${CLR_NO} Building ${CLR_BLUE}user library${CLR_NO} ... " 163 | make -j >/dev/null 2>${TEMPDIR}/error.log || dropout 164 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 165 | 166 | ### make install 167 | # 168 | echo -en "${CLR_NO} Installing ${CLR_BLUE}user library${CLR_NO} ... " 169 | make install >/dev/null 2>${TEMPDIR}/error.log || dropout 170 | echo -e "${CLR_GREEN}[Done]${CLR_NO}" 171 | 172 | popd >/dev/null 173 | popd >/dev/null 174 | } 175 | 176 | echo -en "${CLR_NO} Checking for ${CLR_BLUE}automake 1.12${CLR_NO} ... " 177 | automake --version | grep 1.12 >/dev/null 178 | if [ $? != 0 ]; then 179 | echo -e "${CLR_YELLOW}[Missing]${CLR_NO}" 180 | echo -e "${CLR_BLUE} Building automake 1.12${CLR_NO}" 181 | prepare_automake 182 | else 183 | echo -e "${CLR_GREEN}[OK]${CLR_NO}" 184 | fi 185 | 186 | echo -en "${CLR_NO} Checking for ${CLR_BLUE}autoconf 2.64${CLR_NO} ... " 187 | autoconf --version | grep 2.64 >/dev/null 188 | if [ $? != 0 ]; then 189 | echo -e "${CLR_YELLOW}[Missing]${CLR_NO}" 190 | echo -e "${CLR_BLUE} Building autoconf 2.64${CLR_NO}" 191 | prepare_autoconf 192 | else 193 | echo -e "${CLR_GREEN}[OK]${CLR_NO}" 194 | fi 195 | 196 | echo -en "${CLR_NO} Checking for ${CLR_BLUE}newlib${CLR_NO} ... " 197 | if [ ! -f $PREFIX/$TARGET/lib/libc.a ]; then 198 | echo -e "${CLR_RED}[Missing]${CLR_NO}" 199 | echo -e "${CLR_BLUE} Building newlib${CLR_NO}" 200 | rebuild_newlib $@ 201 | else 202 | if [ "$1" = "force" ]; then 203 | echo -e "${CLR_YELLOW}[Forced]${CLR_NO}" 204 | rebuild_newlib force 205 | else 206 | echo -e "${CLR_GREEN}[OK]${CLR_NO}" 207 | fi 208 | fi 209 | -------------------------------------------------------------------------------- /tarfs/src/terminal_src/terminal.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "terminal.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void copybuffer(struct terminal *t) 11 | { 12 | if(!t) 13 | return; 14 | if(!t->buffer) 15 | return; 16 | memcpy(vidmem, t->buffer, sizeof(uint16_t)*t->rows*t->cols); 17 | 18 | unsigned short position = t->csr_row*80 + t->csr_col; 19 | 20 | outb(0x3D4, 0x0F); 21 | outb(0x3D5, (unsigned char)(position & 0xFF)); 22 | outb(0x3D4, 0x0E); 23 | outb(0x3D5, (unsigned char)(position >> 8) & 0xF); 24 | } 25 | 26 | int ansi_escape_char(char c) 27 | { 28 | // 0 - Not part of a command 29 | // 1 - Argument 30 | // 2 - Argument separator 31 | // 3 - Function 32 | // 33 | // h, l, p not supported 34 | 35 | if(( c >= '0' && c <= '9')) 36 | return 1; 37 | if( c == ';' ) 38 | return 2; 39 | if( c == 'H' || c == 'f' || c == 'A' || c == 'B' || c == 'C' || c == 'D' || c == 's' || c == 'u' || c == 'J' || c == 'K' || c == 'm' ) 40 | return 3; 41 | return 0; 42 | } 43 | 44 | int ansi_state = 0; 45 | char ansi_buffer[256]; 46 | char *ansi_bufp; 47 | uint32_t ansi_args[16]; 48 | uint32_t *ansi_argp; 49 | void terminal_putc(struct terminal *t, char c); 50 | 51 | int count_saved_args() 52 | { 53 | int i = 0; 54 | while(ansi_argp != &ansi_args[i] && i < 16)i++; 55 | return i; 56 | } 57 | 58 | int check_for_escape(struct terminal *t, char c) 59 | { 60 | int i; 61 | switch(ansi_state) 62 | { 63 | case 0: // Haven't started 64 | if(c == '\033') 65 | { 66 | ansi_state = 1; 67 | return 1; 68 | } 69 | return 0; 70 | case 1: // Got \033, waiting for [ 71 | if(c == '[') 72 | { 73 | ansi_state = 2; 74 | memset(ansi_buffer, 0, 256); 75 | ansi_bufp = ansi_buffer; 76 | *ansi_bufp++ = '['; 77 | 78 | memset(ansi_args, 0, 16*sizeof(uint32_t)); 79 | ansi_argp = ansi_args; 80 | return 1; 81 | } 82 | return 0; 83 | case 2: // In a possible ansi command sequence 84 | // Save the characters to buffer 85 | strncat(ansi_bufp, &c, 1); 86 | 87 | switch(ansi_escape_char(c)) 88 | { 89 | case 0: // Not part of an ansi command, give up 90 | ansi_state = 0; 91 | goto bail_print; 92 | case 1: // A digit. Wait for next 93 | return 1; 94 | case 2: // A semi colon. Save the previous data as an argument 95 | *ansi_argp++ = atoi(ansi_bufp); 96 | ansi_bufp += strlen(ansi_bufp); 97 | return 1; 98 | case 3: // End of an ansi command 99 | 100 | // Save data as argument if present 101 | if(strlen(ansi_bufp)>1) 102 | { 103 | *ansi_argp++ = atoi(ansi_bufp); 104 | ansi_bufp += strlen(ansi_bufp); 105 | } 106 | 107 | switch(c) 108 | { 109 | case 'H': 110 | case 'f': 111 | // Set position 112 | if(count_saved_args() != 2) 113 | goto bail_print; 114 | t->csr_row = ansi_args[0]; 115 | t->csr_col = ansi_args[1]; 116 | break; 117 | case 'A': 118 | // Up 119 | if(count_saved_args() > 1) 120 | goto bail_print; 121 | t->csr_row -= ansi_args[0]+1; 122 | if(t->csr_row < 0) 123 | t->csr_row = 0; 124 | break; 125 | case 'B': 126 | // Down 127 | if(count_saved_args() > 1) 128 | goto bail_print; 129 | t->csr_row += ansi_args[0]+1; 130 | if(t->csr_row >= t->rows) 131 | t->csr_row = t->rows; 132 | break; 133 | case 'C': 134 | // Forward 135 | if(count_saved_args() > 1) 136 | goto bail_print; 137 | t->csr_col += ansi_args[0]+1; 138 | if(t->csr_col >= t->cols) 139 | t->csr_col = t->cols; 140 | break; 141 | case 'D': 142 | // Backward 143 | if(count_saved_args() > 1) 144 | goto bail_print; 145 | t->csr_col -= ansi_args[0]+1; 146 | if(t->csr_col < 0) 147 | t->csr_col = 0; 148 | break; 149 | case 's': 150 | // Save position 151 | break; 152 | case 'u': 153 | // Restore position 154 | break; 155 | case 'J': 156 | // Erase display 157 | if(count_saved_args() != 1) 158 | goto bail_print; 159 | if(ansi_args[0] != 2) 160 | goto bail_print; 161 | memset(t->buffer, 0, 2*t->rows*t->cols); 162 | t->csr_row = 0; 163 | t->csr_col = 0; 164 | break; 165 | case 'K': 166 | // Erase line 167 | if(count_saved_args()) 168 | goto bail_print; 169 | memset(&t->buffer[t->csr_row*t->cols + t->csr_col], 0, \ 170 | t->cols - t->csr_col); 171 | break; 172 | case 'm': 173 | i = 0; 174 | while(i < count_saved_args()) 175 | { 176 | int arg = ansi_args[i]; 177 | if(arg == 0) 178 | { 179 | t->current_style = 0; 180 | t->fg_color = 7; 181 | t->bg_color = 0; 182 | } 183 | if(arg == 1) 184 | t->current_style |= 1; 185 | if(arg == 7) 186 | t->current_style |= 2; 187 | if(arg >= 30 && arg <= 37) 188 | { 189 | t->fg_color = arg-30; 190 | } 191 | if(arg >= 40 && arg <= 47) 192 | { 193 | t->bg_color = arg-40; 194 | } 195 | i++; 196 | } 197 | 198 | 199 | } 200 | ansi_state = 0; 201 | return 1; 202 | } 203 | } 204 | 205 | bail_print: 206 | // What we got wasn't an ansi escape sequence 207 | // Give up and print everything 208 | i = 0; 209 | while(ansi_buffer[i]) 210 | { 211 | if(isprint((int)ansi_buffer[i])) 212 | terminal_putc(t, ansi_buffer[i]); 213 | i++; 214 | } 215 | return 1; 216 | } 217 | 218 | void terminal_putc(struct terminal *t, char c) 219 | { 220 | char stl = 0; 221 | if(t->current_style & 0x2) // reverse 222 | stl = (t->fg_color<<4) + (t->bg_color & 0xF); 223 | else 224 | stl = (t->bg_color<<4) + (t->fg_color & 0xF); 225 | if(t->current_style & 0x1) // Bright 226 | stl |= 0x8; 227 | 228 | t->buffer[t->csr_row*t->cols + t->csr_col] = (stl << 8) | c; 229 | t->csr_col++; 230 | 231 | if(t->csr_col > t->cols) 232 | { 233 | t->csr_col = 0; 234 | if(++t->csr_row > t->rows) 235 | { 236 | // TODO Scroll buffer 237 | t->csr_row = 0; 238 | } 239 | } 240 | 241 | } 242 | 243 | void terminal_putch(struct terminal *t, char c) 244 | { 245 | if (!t) 246 | return; 247 | if(!t->buffer) 248 | return; 249 | if(check_for_escape(t, c)) 250 | return; 251 | switch(c) 252 | { 253 | case '\n': 254 | t->csr_row++; 255 | t->csr_col = 0; 256 | break; 257 | 258 | default: 259 | if(isprint((int)c)) 260 | terminal_putc(t, c); 261 | } 262 | } 263 | 264 | void terminal_output_handler(uint32_t a) 265 | { 266 | while(1) 267 | { 268 | char c = fgetc(vterm[a]->write_pipe[0]); 269 | terminal_putch(vterm[a], c); 270 | if(active_vterm == a) 271 | copybuffer(vterm[a]); 272 | } 273 | } 274 | 275 | void terminal_init(int num, uint32_t rows, uint32_t cols, char **argv) 276 | { 277 | struct terminal *t = vterm[num] = calloc(1, sizeof(struct terminal)); 278 | t->rows = rows; 279 | t->cols = cols; 280 | t->fg_color=7; 281 | t->buffer = calloc(rows*cols, sizeof(uint16_t)); 282 | 283 | // Setup reading side (keyboard) 284 | pipe(t->read_fd); 285 | t->read_pipe[0] = fdopen(t->read_fd[0], "r"); 286 | t->read_pipe[1] = fdopen(t->read_fd[1], "w"); 287 | 288 | // Setup writing side (screen) 289 | pipe(t->write_fd); 290 | t->write_pipe[0] = fdopen(t->write_fd[0], "r"); 291 | t->write_pipe[1] = fdopen(t->write_fd[1], "w"); 292 | // 293 | // Keep a thread to take care of new output 294 | void *stack = calloc(1,1280); 295 | _syscall_thread((void *)((uint32_t)stack + 1280), (void *)&terminal_output_handler, num); 296 | 297 | // Start running program 298 | t->pid = fork(); 299 | if(!t->pid) 300 | { 301 | dup2(t->read_fd[0], 0); 302 | dup2(t->write_fd[1], 1); 303 | dup2(t->write_fd[1], 2); 304 | execvp(argv[0], &argv[0]); 305 | exit(1); 306 | } 307 | } 308 | 309 | void screen_init() 310 | { 311 | vidmem = (uint16_t *)_syscall_vidmem(); 312 | } 313 | -------------------------------------------------------------------------------- /kernel/syscall/sys_process.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #undef errno 18 | extern int errno; 19 | 20 | 21 | void _exit(int rc) 22 | { 23 | if(current->proc->flags & PROC_FLAG_DEBUG) 24 | { 25 | debug("[info]EXIT(%x)\n", rc); 26 | print_areas(current->proc); 27 | } 28 | 29 | int i; 30 | process_t *p = current->proc; 31 | for(i = 0; i < NUM_FILEDES; i++) 32 | { 33 | if(p->fd[i]) 34 | { 35 | close(i); 36 | } 37 | } 38 | 39 | exit_process(current->proc, rc); 40 | 41 | current->state = THREAD_STATE_FINISHED; 42 | 43 | schedule(); 44 | 45 | debug("[error]ERROR! REACHED END OF EXIT SYSCALL!\n"); 46 | for(;;); 47 | } 48 | KDEF_SYSCALL(exit, r) 49 | { 50 | process_stack stack = init_pstack(); 51 | 52 | _exit(stack[0]); 53 | 54 | return r; 55 | } 56 | 57 | int execve(char *name, char **argv, char **env) 58 | { 59 | if(current->proc->flags & PROC_FLAG_DEBUG) 60 | { 61 | debug("[info]EXECVE(%s, %x, %x)\n", name, argv, env); 62 | } 63 | // Find the executable 64 | INODE executable = vfs_namei(name); 65 | if(!executable) 66 | { 67 | debug("[error] Executable %s not found.\n", name); 68 | errno = ENOENT; 69 | return -1; 70 | } 71 | if(is_elf(executable) != 2) 72 | { 73 | errno = ENOEXEC; 74 | debug("[error] Tried to load unexecutable file.\n"); 75 | return -1; 76 | } 77 | 78 | // Save environment in kernel space 79 | unsigned int envc = 0; 80 | char **temp_env; 81 | if(env) 82 | { 83 | while(env[envc++]); 84 | 85 | temp_env = calloc(envc, sizeof(char *)); 86 | 87 | unsigned int i = 0; 88 | while(env[i]) 89 | { 90 | temp_env[i] = strdup(env[i]); 91 | i++; 92 | } 93 | temp_env[envc-1] = 0; 94 | } 95 | 96 | // Save arguments in kernel space 97 | unsigned int argc = 0; 98 | char **temp_argv; 99 | if(argv) 100 | { 101 | while(argv[argc++]); 102 | 103 | temp_argv = calloc(argc, sizeof(char *)); 104 | 105 | unsigned int i = 0; 106 | while(argv[i]) 107 | { 108 | temp_argv[i] = strdup(argv[i]); 109 | i++; 110 | } 111 | temp_argv[argc-1] = 0; 112 | } 113 | 114 | if(current->proc->cmdline) 115 | free(current->proc->cmdline); 116 | current->proc->cmdline = strdup(name); 117 | 118 | // Clear all process memory areas 119 | procmm_removeall(current->proc); 120 | 121 | // Reset signal handlers 122 | memset(current->proc->signal_handler, 0, sizeof(sig_t)*NUM_SIGNALS); 123 | memset(current->proc->signal_blocked, 0, NUM_SIGNALS); 124 | init_list(current->proc->signal_queue); 125 | 126 | // Load executable 127 | load_elf(executable); 128 | 129 | // Reset thread registers and state 130 | current->r.eax = current->r.ebx = current->r.ecx = current->r.edx = 0; 131 | 132 | // Add an area for the process stack 133 | new_area(current->proc, USER_STACK_TOP, USER_STACK_TOP, MM_FLAG_WRITE | MM_FLAG_GROWSDOWN | MM_FLAG_ADDONUSE, MM_TYPE_STACK); 134 | current->kernel_thread = (registers_t *)current; 135 | uint32_t *pos = (uint32_t *)USER_STACK_TOP; // uint32_t since the stack should be word alligned 136 | 137 | // Restore environment 138 | if (env) 139 | { 140 | pos = pos - envc*sizeof(char *)/sizeof(uint32_t) - 1; 141 | env = (char **)pos; 142 | int i = 0; 143 | while(temp_env[i]) 144 | { 145 | pos = pos - strlen(temp_env[i])/sizeof(uint32_t) - 2; 146 | memcpy(pos, temp_env[i], strlen(temp_env[i])+1); 147 | env[i] = (char *)pos; 148 | i++; 149 | } 150 | env[envc-1] = 0; 151 | } 152 | 153 | // Restore arguments 154 | if(argv) 155 | { 156 | pos = pos - argc*sizeof(char *)/sizeof(uint32_t) - 1; 157 | argv = (char **)pos; 158 | int i = 0; 159 | while(temp_argv[i]) 160 | { 161 | pos = pos - strlen(temp_argv[i])/sizeof(uint32_t) - 2; 162 | memcpy(pos, temp_argv[i], strlen(temp_argv[i])+1); 163 | argv[i] = (char *)pos; 164 | i++; 165 | } 166 | argv[argc-1] = 0; 167 | } 168 | 169 | pos = pos - 3; 170 | pos[0] = (uint32_t)argc-1; 171 | pos[1] = (uint32_t)argv; 172 | pos[2] = (uint32_t)env; 173 | 174 | current->r.useresp = current->r.ebp = (uint32_t)pos; 175 | current->r.ecx = (uint32_t)pos; 176 | 177 | errno = 0; 178 | return 0; 179 | } 180 | KDEF_SYSCALL(execve, r) 181 | { 182 | process_stack stack = init_pstack(); 183 | r->eax = execve((char *)stack[0], (char **)stack[1], (char **)stack[2]); 184 | r->edx = errno; 185 | if(r->eax != (uint32_t)-1) 186 | { 187 | current->r.eip = current->proc->mm.code_entry; 188 | } 189 | return r; 190 | } 191 | 192 | int fork() 193 | { 194 | if(current->proc->flags & PROC_FLAG_DEBUG) 195 | { 196 | debug("[info]FORK()\n"); 197 | } 198 | process_t *child = fork_process(); 199 | thread_t *cth = list_entry(child->threads.next, thread_t, process_threads); 200 | cth->r.eax = 0; 201 | errno = 0; 202 | scheduler_insert(cth); 203 | return child->pid; 204 | } 205 | KDEF_SYSCALL(fork, r) 206 | { 207 | r->eax = fork(); 208 | r->edx = errno; 209 | return r; 210 | } 211 | 212 | int getpid() 213 | { 214 | if(current->proc->flags & PROC_FLAG_DEBUG) 215 | { 216 | debug("[info]GETPID()\n"); 217 | } 218 | errno = 0; 219 | return current->proc->pid; 220 | } 221 | KDEF_SYSCALL(getpid, r) 222 | { 223 | r->eax = getpid(); 224 | r->edx = errno; 225 | return r; 226 | } 227 | 228 | int kill(int pid, int sig) 229 | { 230 | if(current->proc->flags & PROC_FLAG_DEBUG) 231 | { 232 | debug("[info]KILL(%d, %d)\n", pid, sig); 233 | } 234 | /* debug("KILL(%d, %d)", pid, sig); */ 235 | if(pid <= 0) 236 | { 237 | errno = ESRCH; 238 | return -1; 239 | } 240 | if(sig > NUM_SIGNALS) 241 | { 242 | errno = EINVAL; 243 | return -1; 244 | } 245 | if(!get_process(pid)) 246 | { 247 | errno = ESRCH; 248 | return -1; 249 | } 250 | 251 | signal_process(pid, sig); 252 | 253 | return 0; 254 | } 255 | KDEF_SYSCALL(kill, r) 256 | { 257 | process_stack stack = init_pstack(); 258 | r->eax = kill(stack[0], stack[1]); 259 | r->edx = errno; 260 | return r; 261 | } 262 | 263 | int wait(int *status) 264 | { 265 | if(current->proc->flags & PROC_FLAG_DEBUG) 266 | { 267 | debug("[info]WAIT(%x)\n", status); 268 | } 269 | errno = ECHILD; 270 | return -1; 271 | } 272 | KDEF_SYSCALL(wait, r) 273 | { 274 | process_stack stack = init_pstack(); 275 | r->eax = wait((int *)stack[0]); 276 | r->edx = errno; 277 | return r; 278 | } 279 | 280 | int waitpid(int pid) 281 | { 282 | if(current->proc->flags & PROC_FLAG_DEBUG) 283 | { 284 | debug("[info]WAITPID(%d)\n", pid); 285 | } 286 | process_t *proc = get_process(pid); 287 | 288 | while(proc->state != PROC_STATE_FINISHED) 289 | { 290 | scheduler_sleep(current, &proc->waiting); 291 | 292 | schedule(); 293 | } 294 | 295 | int ret = proc->exit_code; 296 | free_process(proc); 297 | 298 | errno = 0; 299 | return ret; 300 | } 301 | KDEF_SYSCALL(waitpid, r) 302 | { 303 | process_stack stack = init_pstack(); 304 | r->eax = waitpid(stack[0]); 305 | r->edx = errno; 306 | return r; 307 | } 308 | 309 | void yield() 310 | { 311 | if(current->proc->flags & PROC_FLAG_DEBUG) 312 | { 313 | debug("[info]YIELD()\n"); 314 | } 315 | schedule(); 316 | errno = 0; 317 | } 318 | KDEF_SYSCALL(yield, r) 319 | { 320 | yield(); 321 | return r; 322 | } 323 | 324 | sig_t signal(int sig, sig_t handler) 325 | { 326 | if(current->proc->flags & PROC_FLAG_DEBUG) 327 | { 328 | debug("[info]SIGNAL(%d, %x)\n", sig, handler); 329 | } 330 | /* debug("SIGNAL(%d %x)", sig, handler); */ 331 | if(sig > NUM_SIGNALS) 332 | { 333 | errno = EINVAL; 334 | return (sig_t)-1; 335 | } 336 | if(sig == SIGKILL || sig == SIGSTOP) 337 | { 338 | if( handler != 0) 339 | { 340 | errno = EINVAL; 341 | return (sig_t)-1; 342 | } 343 | } 344 | process_t *p = current->proc; 345 | sig_t old = p->signal_handler[sig]; 346 | p->signal_handler[sig] = handler; 347 | return old; 348 | } 349 | KDEF_SYSCALL(signal, r) 350 | { 351 | process_stack stack = init_pstack(); 352 | r->eax = (uint32_t)signal(stack[0], (sig_t)stack[1]); 353 | r->edx = errno; 354 | return r; 355 | } 356 | 357 | KDEF_SYSCALL(process_debug, r) 358 | { 359 | if(current->proc->flags & PROC_FLAG_DEBUG) 360 | { 361 | debug("[info]PROCDB()\n"); 362 | } 363 | debug("[info]Starting debug\n"); 364 | current->proc->flags |= PROC_FLAG_DEBUG; 365 | debug("[info]Process: %x \n", current->proc->pid); 366 | return r; 367 | } 368 | 369 | KDEF_SYSCALL(thread_fork, r) 370 | { 371 | // example: thread_fork(stack, function, argument); 372 | process_stack stack = init_pstack(); 373 | if(current->proc->flags & PROC_FLAG_DEBUG) 374 | { 375 | debug("[info]thread_fork(%x, %x, %x)\n", stack[0], stack[1], stack[2]); 376 | } 377 | thread_t *th = new_thread((void (*)(void))stack[1], 1); 378 | append_to_list(current->proc->threads, th->process_threads); 379 | th->proc = current->proc; 380 | uint32_t *stk = (uint32_t *)stack[0]; 381 | *--stk = stack[2]; 382 | *--stk = SIGNAL_RETURN_ADDRESS; 383 | th->r.useresp = th->r.ebp = (uint32_t)stk; 384 | r->eax = th->tid; 385 | return r; 386 | } 387 | 388 | -------------------------------------------------------------------------------- /kernel/mem/vmm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | uint8_t vmm_running = 0; 11 | 12 | uintptr_t *page_directory = (uintptr_t *)VMM_PAGE_DIR; 13 | uintptr_t *page_tables = (uintptr_t *)VMM_PAGE_TABLES; 14 | 15 | uintptr_t *expage_directory = (uintptr_t *)VMM_EXPAGE_DIR; 16 | uintptr_t *expage_tables = (uintptr_t *)VMM_EXPAGE_TABLES; 17 | 18 | 19 | void vmm_pd_set(page_dir_t pd) 20 | { 21 | // Load a new page directory 22 | __asm__ volatile("mov %0, %%cr3" : : "r" (pd)); 23 | } 24 | 25 | uintptr_t vmm_page_get(uintptr_t page) 26 | { 27 | // Get the value of a page table entry in the current memory space 28 | page &= PAGE_MASK; 29 | 30 | if(page_directory[vmm_dir_idx(page)] & PAGE_PRESENT) 31 | if(page_tables[vmm_table_idx(page)] & PAGE_PRESENT) 32 | return page_tables[vmm_table_idx(page)]; 33 | return 0; 34 | } 35 | 36 | uintptr_t vmm_table_get(uintptr_t page) 37 | { 38 | // Get the value of a page dir entry in the current memory space 39 | 40 | page &= PAGE_MASK; 41 | 42 | if(page_directory[vmm_dir_idx(page)] & PAGE_PRESENT) 43 | return page_directory[vmm_dir_idx(page)]; 44 | return 0; 45 | } 46 | 47 | void vmm_table_set(uintptr_t page, uintptr_t value) 48 | { 49 | // Set the value of a page dir entry in the current memory space 50 | 51 | page &= PAGE_MASK; 52 | 53 | page_directory[vmm_dir_idx(page)] = value; 54 | } 55 | 56 | void vmm_page_touch(uintptr_t page, uint32_t flags) 57 | { 58 | // Make sure a page table for the address page exists in the current memory 59 | // space 60 | 61 | page &= PAGE_MASK; 62 | flags &= PAGE_FLAG_MASK; 63 | 64 | if(!(page_directory[vmm_dir_idx(page)] & PAGE_PRESENT)) 65 | { 66 | // There is no page table for the page 67 | 68 | if(page >= KERNEL_OFFSET && vmm_running) 69 | { 70 | // The page we want to add is in the kernel space 71 | spin_lock(&kernel_pd_sem); 72 | spin_lock(&exdir_sem); 73 | page_dir_t old_exdir = vmm_exdir_set(kernel_pd); 74 | if(expage_directory[vmm_dir_idx(page)] & PAGE_PRESENT) 75 | { 76 | // If the page table exists in the master page directory, just 77 | // copy it. 78 | page_directory[vmm_dir_idx(page)] = expage_directory[vmm_dir_idx(page)]; 79 | } else { 80 | // Otherwise allocate a new table 81 | page_directory[vmm_dir_idx(page)] = pmm_alloc_page() | flags; 82 | expage_directory[vmm_dir_idx(page)] = page_directory[vmm_dir_idx(page)]; 83 | } 84 | vmm_exdir_set(old_exdir); 85 | spin_unlock(&exdir_sem); 86 | spin_unlock(&kernel_pd_sem); 87 | } else { 88 | // If the page is in user space, just allocate a new table. 89 | page_directory[vmm_dir_idx(page)] = pmm_alloc_page() | flags; 90 | } 91 | 92 | // Clear the new page table 93 | vmm_flush_tlb((uintptr_t)&page_tables[vmm_table_idx(page)] & PAGE_MASK); 94 | memset((void *)((uintptr_t)&page_tables[vmm_table_idx(page)] & PAGE_MASK), 0, \ 95 | PAGE_SIZE); 96 | } 97 | } 98 | 99 | void vmm_page_set(uintptr_t page, uintptr_t value) 100 | { 101 | // Set the value of a page table entry in the current memory space 102 | page &= PAGE_MASK; 103 | 104 | vmm_page_touch(page, value & PAGE_FLAG_MASK); 105 | page_tables[vmm_table_idx(page)] = value; 106 | vmm_flush_tlb(page); 107 | } 108 | 109 | 110 | page_dir_t vmm_exdir_set(page_dir_t pd) 111 | { 112 | // Temporarily load or unload another page directory and its tables into the 113 | // current memory space 114 | 115 | page_dir_t old = \ 116 | page_directory[vmm_dir_idx(VMM_EXPAGE_DIR)] & PAGE_MASK; 117 | 118 | if(pd) 119 | page_directory[vmm_dir_idx(VMM_EXPAGE_DIR)] = \ 120 | pd | PAGE_PRESENT | PAGE_WRITE; 121 | else 122 | page_directory[vmm_dir_idx(VMM_EXPAGE_DIR)] = 0; 123 | 124 | vmm_flush_tlb(VMM_EXPAGE_DIR); 125 | 126 | return old; 127 | } 128 | 129 | uintptr_t vmm_expage_get(uintptr_t page) 130 | { 131 | // Get the value of a page table entry in the currently loaded external page 132 | // directory 133 | 134 | if(page_directory[vmm_dir_idx(VMM_EXPAGE_DIR)] == 0) 135 | return 0; 136 | 137 | page &= PAGE_MASK; 138 | if(expage_directory[vmm_dir_idx(page)] & PAGE_PRESENT) 139 | if(expage_tables[vmm_table_idx(page)] & PAGE_PRESENT) 140 | return expage_tables[vmm_table_idx(page)]; 141 | return 0; 142 | } 143 | 144 | uintptr_t vmm_extable_get(uintptr_t page) 145 | { 146 | // Get the value of a page dir entry in the current memory space 147 | 148 | page &= PAGE_MASK; 149 | 150 | if(expage_directory[vmm_dir_idx(page)] & PAGE_PRESENT) 151 | return expage_directory[vmm_dir_idx(page)]; 152 | return 0; 153 | } 154 | 155 | void vmm_extable_set(uintptr_t page, uintptr_t value) 156 | { 157 | // Set the value of a page dir entry in the current memory space 158 | 159 | page &= PAGE_MASK; 160 | 161 | expage_directory[vmm_dir_idx(page)] = value; 162 | } 163 | 164 | void vmm_expage_touch(uintptr_t page, uint32_t flags) 165 | { 166 | // Make sure a page table exists for address page in the currently loaded 167 | // external page directory 168 | 169 | page &= PAGE_MASK; 170 | flags &= PAGE_FLAG_MASK; 171 | 172 | if(page_directory[vmm_dir_idx(VMM_EXPAGE_DIR)] == 0) 173 | return; 174 | 175 | if(!(expage_directory[vmm_dir_idx(page)] & PAGE_PRESENT)) 176 | { 177 | expage_directory[vmm_dir_idx(page)] = pmm_alloc_page() | flags; 178 | vmm_flush_tlb((uintptr_t)&expage_tables[vmm_table_idx(page)] & PAGE_MASK); 179 | memset((void *)((uintptr_t)&expage_tables[vmm_table_idx(page)] & PAGE_MASK), 0, \ 180 | PAGE_SIZE); 181 | } 182 | } 183 | 184 | void vmm_expage_set(uintptr_t page, uintptr_t value) 185 | { 186 | // Set the value of a page table entry in the currently loaded external page 187 | // directory. 188 | page &= PAGE_MASK; 189 | 190 | vmm_expage_touch(page, value & PAGE_FLAG_MASK); 191 | expage_tables[vmm_table_idx(page)] = value; 192 | vmm_flush_tlb(page); 193 | } 194 | 195 | 196 | void vmm_clear_page(uintptr_t page) 197 | { 198 | // Clear a physical page 199 | 200 | spin_lock(&temp_sem); 201 | uintptr_t old = vmm_page_get(VMM_TEMP1); 202 | vmm_page_set(VMM_TEMP1, vmm_page_val(page, PAGE_PRESENT | PAGE_WRITE)); 203 | memset((void *)VMM_TEMP1, 0, PAGE_SIZE), 204 | vmm_page_set(VMM_TEMP1, old); 205 | spin_unlock(&temp_sem); 206 | } 207 | 208 | void vmm_copy_page(uintptr_t src, uintptr_t dst) 209 | { 210 | // Make a copy of a physical page 211 | 212 | spin_lock(&temp_sem); 213 | uintptr_t old_temp1 = vmm_page_get(VMM_TEMP1); 214 | uintptr_t old_temp2 = vmm_page_get(VMM_TEMP2); 215 | vmm_page_set(VMM_TEMP1, vmm_page_val(src, PAGE_PRESENT | PAGE_WRITE)); 216 | vmm_page_set(VMM_TEMP2, vmm_page_val(dst, PAGE_PRESENT | PAGE_WRITE)); 217 | 218 | // There's probably an x86 instruction to do this faster? 219 | memcpy((void *)VMM_TEMP2, (const void *)VMM_TEMP1, PAGE_SIZE); 220 | 221 | vmm_page_set(VMM_TEMP1, old_temp1); 222 | vmm_page_set(VMM_TEMP2, old_temp2); 223 | spin_unlock(&temp_sem); 224 | } 225 | 226 | page_dir_t vmm_new_pd() 227 | { 228 | // Returns the physical address of a page directory prepared for 229 | // recursive paging. 230 | 231 | page_dir_t pd = pmm_alloc_page(); 232 | 233 | spin_lock(&temp_sem); 234 | // Clear page directory. 235 | uintptr_t old = vmm_page_get(VMM_TEMP1); 236 | vmm_page_set(VMM_TEMP1, vmm_page_val(pd, PAGE_PRESENT | PAGE_WRITE)); 237 | memset((void *)VMM_TEMP1, 0, PAGE_SIZE); 238 | 239 | // Make page directory recursive. 240 | uint32_t *pdir = (uint32_t *)VMM_TEMP1; 241 | pdir[VMM_PAGES_PER_TABLE - 1] = vmm_page_val(pd, PAGE_PRESENT | PAGE_WRITE); 242 | 243 | vmm_page_set(VMM_TEMP1, old); 244 | spin_unlock(&temp_sem); 245 | 246 | return pd; 247 | } 248 | 249 | page_dir_t vmm_clone_pd() 250 | { 251 | // Make a copy of the current page directory 252 | 253 | page_dir_t pd = vmm_new_pd(); 254 | 255 | spin_lock(&exdir_sem); 256 | page_dir_t old_exdir = vmm_exdir_set(pd); 257 | 258 | uint32_t table; 259 | 260 | // Copy each page table except the kernel space 261 | for(table = 0; table < vmm_dir_idx(KERNEL_OFFSET); table++) 262 | { 263 | if(page_directory[table]) 264 | { 265 | expage_directory[table] = vmm_page_val(pmm_alloc_page(), \ 266 | page_directory[table] & PAGE_FLAG_MASK); 267 | vmm_copy_page(page_directory[table] & PAGE_MASK, \ 268 | expage_directory[table] & PAGE_MASK); 269 | } 270 | } 271 | 272 | // Point to the same page tables for the kernel space 273 | for(table = vmm_dir_idx(KERNEL_OFFSET); \ 274 | table < VMM_PAGES_PER_TABLE - 2; table++) 275 | { 276 | expage_directory[table] = page_directory[table]; 277 | } 278 | vmm_exdir_set(old_exdir); 279 | spin_unlock(&exdir_sem); 280 | 281 | return pd; 282 | } 283 | 284 | 285 | void vmm_init(uint32_t kernel_end) 286 | { 287 | // Setup the physical memory manager 288 | 289 | // Save the address of the kernel page directory (used as refference 290 | // for all others) 291 | __asm__ volatile("mov %%cr3, %0" : "=r" (kernel_pd)); 292 | 293 | // Set current page directory to a copy of the kernel page directory. 294 | vmm_pd_set(vmm_clone_pd()); 295 | uint32_t i = 0; 296 | uint32_t kspace = KERNEL_OFFSET; 297 | for(i=0; i < kernel_end; i += PAGE_SIZE) 298 | { 299 | vmm_page_set(kspace, vmm_page_val(i, PAGE_PRESENT | PAGE_WRITE)); 300 | kspace += PAGE_SIZE; 301 | } 302 | 303 | vmm_running = TRUE; 304 | } 305 | 306 | -------------------------------------------------------------------------------- /kernel/fs/vfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | vfs_node_t *vfs_root; 11 | 12 | 13 | void vfs_print_tree_rec(vfs_node_t *node, int level) 14 | { 15 | if(node) 16 | { 17 | int i; 18 | for(i=0; i < level; i++) 19 | debug("."); 20 | debug("%s\n", node->name); 21 | node = node->child; 22 | while(node) 23 | { 24 | vfs_print_tree_rec(node, level+1); 25 | node = node->older; 26 | } 27 | } 28 | } 29 | 30 | void vfs_print_tree() 31 | { 32 | debug("[info]VFS tree start\n"); 33 | vfs_print_tree_rec(vfs_root, 0); 34 | debug("[info]VFS tree end\n"); 35 | } 36 | 37 | 38 | void vfs_init() 39 | { 40 | vfs_root = calloc(1, sizeof(vfs_node_t)); 41 | vfs_root->parent = vfs_root; 42 | strcpy(vfs_root->name, "/"); 43 | } 44 | 45 | void vfs_free(INODE ino) 46 | { 47 | if(in_vfs_tree(ino)) 48 | return; 49 | if(ino->users > 0) 50 | return; 51 | if(ino->d && ino->d->flush) 52 | ino->d->flush(ino); 53 | else 54 | free(ino); 55 | } 56 | 57 | int32_t vfs_open(INODE ino, uint32_t mode) 58 | { 59 | ino->users++; 60 | if(ino->d->open) 61 | return ino->d->open(ino, mode); 62 | errno = EACCES; 63 | return -1; 64 | } 65 | int32_t vfs_close(INODE ino) 66 | { 67 | ino->users--; 68 | if(ino->d->close) 69 | return ino->d->close(ino); 70 | errno = EBADF; 71 | return -1; 72 | } 73 | uint32_t vfs_read(INODE ino, void *ptr, uint32_t length, uint32_t offset) 74 | { 75 | if(ino->d->read) 76 | return ino->d->read(ino, ptr, length, offset); 77 | return 0; 78 | } 79 | uint32_t vfs_write(INODE ino, void *ptr, uint32_t length, uint32_t offset) 80 | { 81 | if(ino->d->write) 82 | return ino->d->write(ino, ptr, length, offset); 83 | return 0; 84 | } 85 | int32_t vfs_link(INODE ino, INODE parent, const char *name) 86 | { 87 | if(ino->d->link) 88 | return ino->d->link(ino, parent, name); 89 | errno = EACCES; 90 | return -1; 91 | } 92 | int32_t vfs_unlink(INODE ino, const char *name) 93 | { 94 | if(ino->d->unlink) 95 | return ino->d->unlink(ino, name); 96 | errno = EACCES; 97 | return -1; 98 | } 99 | int32_t vfs_stat(INODE ino, struct stat *st) 100 | { 101 | if(ino->d->stat) 102 | return ino->d->stat(ino, st); 103 | errno = EBADF; 104 | return -1; 105 | } 106 | int32_t vfs_isatty(INODE ino) 107 | { 108 | if(ino->d->isatty) 109 | return ino->d->isatty(ino); 110 | return 0; 111 | } 112 | int32_t vfs_mkdir(INODE ino, const char *name) 113 | { 114 | if(ino->d->mkdir) 115 | return ino->d->mkdir(ino, name); 116 | errno = EACCES; 117 | return -1; 118 | } 119 | dirent_t *vfs_readdir(INODE ino, uint32_t num) 120 | { 121 | if(!((ino->type & FS_TYPE_MASK) == FS_DIRECTORY)) 122 | return 0; 123 | if(in_vfs_tree(ino)) 124 | { 125 | if(num == 0) 126 | { 127 | dirent_t *ret = calloc(1, sizeof(dirent_t)); 128 | ret->ino = ino; 129 | strcpy(ret->name, "."); 130 | return ret; 131 | } else if(num == 1) { 132 | dirent_t *ret = calloc(1, sizeof(dirent_t)); 133 | ret->ino = ino->parent; 134 | strcpy(ret->name, ".."); 135 | return ret; 136 | } 137 | } 138 | dirent_t *de = 0; 139 | if(ino->d->readdir) 140 | de = ino->d->readdir(ino, num); 141 | 142 | if(de && in_vfs_tree(ino)) 143 | { 144 | // Replace inode with the one from the vfs tree if it exists. 145 | INODE n = ino->child; 146 | while(n) 147 | { 148 | if(!strcmp(de->name, n->name)) 149 | { 150 | vfs_free(de->ino); 151 | de->ino = n; 152 | break; 153 | } 154 | n = n->older; 155 | } 156 | } 157 | return de; 158 | } 159 | INODE vfs_finddir(INODE ino, const char *name) 160 | { 161 | if(!((ino->type & FS_TYPE_MASK) == FS_DIRECTORY)) 162 | return 0; 163 | if(in_vfs_tree(ino)) 164 | { 165 | if(!strcmp(name, ".")) 166 | { 167 | return ino; 168 | } else if(!strcmp(name, "..")) { 169 | return ino->parent; 170 | } 171 | 172 | // Search through the mount tree first 173 | INODE n = ino->child; 174 | while(n) 175 | { 176 | if(!strcmp(name, n->name)) 177 | return n; 178 | n = n->older; 179 | } 180 | } 181 | 182 | if(ino->d->finddir) 183 | return ino->d->finddir(ino, name); 184 | 185 | if(ino->d->readdir) 186 | { 187 | // Backup solution 188 | int num = 0; 189 | dirent_t *de; 190 | while(1) 191 | { 192 | de = vfs_readdir(ino, num); 193 | if(!de) 194 | return 0; 195 | if(!strcmp(name, de->name)) 196 | break; 197 | free(de->name); 198 | free(de); 199 | num++; 200 | } 201 | INODE ret = de->ino; 202 | free(de->name); 203 | free(de); 204 | return ret; 205 | } 206 | return 0; 207 | } 208 | 209 | INODE vfs_find_root(char **path) 210 | { 211 | // Find closest point in mount tree 212 | INODE current = vfs_root; 213 | INODE mount = current; 214 | char *name; 215 | while((name = strsep(path, "/"))) 216 | { 217 | current = current->child; 218 | while(current) 219 | { 220 | if(!strcmp(current->name, name)) 221 | { 222 | mount = current; 223 | break; 224 | } 225 | current = current->older; 226 | } 227 | if(!current) 228 | { 229 | if(*path) 230 | { 231 | *path = *path - 1; 232 | *path[0] = '/'; 233 | } 234 | *path = name; 235 | break; 236 | } 237 | } 238 | 239 | return (INODE)mount; 240 | } 241 | 242 | INODE vfs_namei_mount(const char *path, INODE root) 243 | { 244 | if(root && in_vfs_tree(root)) 245 | { 246 | debug("[error] Tried to mount node already in mount tree: %s->%s\n", root->name, path); 247 | } 248 | char *npath = strdup(path); 249 | char *pth = &npath[1]; 250 | // Find closest point in mount tree 251 | INODE current = vfs_find_root(&pth); 252 | char *name; 253 | while(current && (name = strsep(&pth, "/"))) 254 | { 255 | // Go through the path 256 | INODE next = vfs_finddir(current, name); 257 | 258 | if(!next) 259 | { 260 | vfs_free(current); 261 | return 0; 262 | } 263 | 264 | if(root) 265 | { 266 | // Add node to mount tree if the goal is to mount something 267 | next->parent = current; 268 | next->older = current->child; 269 | current->child = next; 270 | } 271 | 272 | vfs_free(current); 273 | current = next; 274 | } 275 | free(npath); 276 | 277 | if(root) 278 | { 279 | // Replace node in mount tree 280 | root->parent = current->parent; 281 | current->parent = 0; 282 | if(root->parent->child == current) root->parent->child = root; 283 | root->older = current->older; 284 | if(root->older) root->older->younger = current; 285 | root->younger = current->younger; 286 | if(root->younger) root->younger->older = current; 287 | // Replace name 288 | strcpy(root->name, current->name); 289 | root->type |= FS_MOUNT; 290 | if(current == vfs_root) 291 | vfs_root = root; 292 | 293 | vfs_free(current); 294 | vfs_free(root); 295 | current = root; 296 | } 297 | return current; 298 | } 299 | 300 | INODE vfs_umount(const char *path) 301 | { 302 | char *npath = strdup(path); 303 | char *pth = &npath[1]; 304 | INODE ino = vfs_find_root(&pth); 305 | if(!ino || pth) 306 | { 307 | free(npath); 308 | return 0; 309 | } 310 | if(ino->child) 311 | { 312 | // TODO: Needs rewriting 313 | free(npath); 314 | return 0; 315 | } else { 316 | // Remove node from mount tree 317 | if(ino->parent->child == ino) ino->parent->child = ino->older; 318 | if(ino->younger) ino->younger->older = ino->older; 319 | if(ino->older) ino->older->younger = ino->younger; 320 | free(npath); 321 | return ino; 322 | } 323 | } 324 | 325 | INODE vfs_namei(const char *path) 326 | { 327 | return vfs_namei_mount(path, 0); 328 | } 329 | 330 | INODE vfs_mount(const char *path, INODE root) 331 | { 332 | debug("[info] VFS mounting %s to %s\n", root->name, path); 333 | return vfs_namei_mount(path, root); 334 | } 335 | 336 | char *canonicalize_path(const char *path, const char *prefix) 337 | { 338 | // Tokenize path and push every piece onto a stack 339 | // Push everything onto another stack, remove all . and pop one item 340 | // for .. 341 | // Pop second stack into new path 342 | 343 | typedef struct pth_stack{ 344 | char *name; 345 | struct pth_stack *prev; 346 | } stack_item; 347 | 348 | int length = strlen(path) + 1; 349 | if(prefix && path[0] != '/') 350 | length += strlen(prefix) + 1; 351 | char *pth = calloc(1, length); 352 | if(prefix && path[0] != '/') 353 | { 354 | strcat(pth, prefix); 355 | strcat(pth, "/"); 356 | } 357 | strcat(pth, path); 358 | 359 | stack_item *i = 0, *j = 0, *k = 0; 360 | char *p = pth; 361 | for(p = strtok(p, "/"); p; p = strtok(NULL, "/")) 362 | { 363 | if(!strcmp(p, ".")) 364 | continue; 365 | if(!strcmp(p, "..")) 366 | { 367 | // Pop 368 | i = j; 369 | j = j->prev; 370 | free(i->name); 371 | free(i); 372 | continue; 373 | } 374 | i = j; 375 | j = calloc(1, sizeof(stack_item)); 376 | j->name = strdup(p); 377 | j->prev = i; 378 | } 379 | free(pth); 380 | 381 | // Turn stack around 382 | while(j) 383 | { 384 | i = k; 385 | k = calloc(1, sizeof(stack_item)); 386 | k->name = j->name; 387 | k->prev = i; 388 | i = j; 389 | j = j->prev; 390 | free(i); 391 | } 392 | 393 | char *ret = calloc(1, strlen(path)+1); 394 | if(!k) 395 | strcat(ret, "/"); 396 | while(k) 397 | { 398 | strcat(ret, "/"); 399 | strcat(ret, k->name); 400 | i = k; 401 | k = k->prev; 402 | free(i->name); 403 | free(i); 404 | } 405 | return ret; 406 | } 407 | -------------------------------------------------------------------------------- /kernel/syscall/sys_fs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #undef errno 18 | extern int errno; 19 | 20 | int close(int file) 21 | { 22 | if(current->proc->flags & PROC_FLAG_DEBUG) 23 | { 24 | debug("[info]CLOSE(%x)\n", file); 25 | } 26 | process_t *p = current->proc; 27 | if(!p->fd[file]->ino) 28 | { 29 | errno = EBADF; 30 | return -1; 31 | } 32 | 33 | int retval = vfs_close(p->fd[file]->ino); 34 | vfs_free(p->fd[file]->ino); 35 | fd_put(p->fd[file]); 36 | p->fd[file] = 0; 37 | 38 | return retval; 39 | } 40 | KDEF_SYSCALL(close, r) 41 | { 42 | process_stack stack = init_pstack(); 43 | r->eax = close(stack[0]); 44 | r->edx = errno; 45 | return r; 46 | } 47 | 48 | int fstat(int file, struct stat *st) 49 | { 50 | if(current->proc->flags & PROC_FLAG_DEBUG) 51 | { 52 | debug("[info]FSTAT(%d, %x)\n", file, st); 53 | } 54 | process_t *p = current->proc; 55 | INODE node = p->fd[file]->ino; 56 | if(!node) 57 | { 58 | errno = EBADF; 59 | return -1; 60 | } 61 | if(kernel_booted && procmm_check_address((uintptr_t)st) <= 1) 62 | { 63 | errno = EFAULT; 64 | return -1; 65 | } 66 | return vfs_stat(node, st); 67 | } 68 | KDEF_SYSCALL(fstat, r) 69 | { 70 | process_stack stack = init_pstack(); 71 | r->eax = fstat(stack[0], (struct stat *) stack[1]); 72 | r->edx = errno; 73 | return r; 74 | } 75 | 76 | int isatty(int file) 77 | { 78 | if(current->proc->flags & PROC_FLAG_DEBUG) 79 | { 80 | debug("[info]ISATTY(%d)\n", file); 81 | } 82 | process_t *p = current->proc; 83 | INODE node = p->fd[file]->ino; 84 | if(!node) 85 | return 0; 86 | return vfs_isatty(node); 87 | } 88 | KDEF_SYSCALL(isatty, r) 89 | { 90 | process_stack stack = init_pstack(); 91 | r->eax = isatty(stack[0]); 92 | r->edx = errno; 93 | return r; 94 | } 95 | 96 | int link(char *old, char *new) 97 | { 98 | if(current->proc->flags & PROC_FLAG_DEBUG) 99 | { 100 | debug("[info]LINK(%s, %s)\n", old, new); 101 | } 102 | errno = EMLINK; 103 | return -1; 104 | } 105 | KDEF_SYSCALL(link, r) 106 | { 107 | process_stack stack = init_pstack(); 108 | r->eax = link((char *)stack[0], (char *)stack[1]); 109 | r->edx = errno; 110 | return r; 111 | } 112 | 113 | int lseek(int file, int ptr, int dir) 114 | { 115 | if(current->proc->flags & PROC_FLAG_DEBUG) 116 | { 117 | debug("[info]LSEEK(%d, %x, %x)\n", file, ptr, dir); 118 | } 119 | debug("[info]LSEEK(%d, %x, %x)\n", file, ptr, dir); 120 | process_t *p = current->proc; 121 | INODE node = p->fd[file]->ino; 122 | if(!node) 123 | { 124 | errno = EBADF; 125 | return -1; 126 | // ERROR! 127 | } 128 | if(dir != 0 && dir != 1 && dir != 2) 129 | { 130 | errno = EINVAL; 131 | return -1; 132 | } 133 | if((int)p->fd[file]->offset + ptr < 0) 134 | { 135 | errno = EINVAL; 136 | return -1; 137 | } 138 | if((node->type & FS_PIPE) == FS_PIPE) 139 | { 140 | errno = ESPIPE; 141 | return -1; 142 | } 143 | 144 | if(dir == SEEK_SET) // 0 145 | { 146 | p->fd[file]->offset = ptr; 147 | } 148 | if(dir == SEEK_CUR) // 1 149 | { 150 | p->fd[file]->offset += ptr; 151 | } 152 | if(dir == SEEK_END) // 2 153 | { 154 | p->fd[file]->offset = node->length + ptr; 155 | } 156 | return p->fd[file]->offset; 157 | } 158 | KDEF_SYSCALL(lseek, r) 159 | { 160 | process_stack stack = init_pstack(); 161 | r->eax = lseek(stack[0], stack[1], stack[2]); 162 | r->edx = errno; 163 | return r; 164 | } 165 | 166 | int open(const char *name, int flags, ...) 167 | { 168 | if(current->proc->flags & PROC_FLAG_DEBUG) 169 | { 170 | debug("[info]OPEN(%s, %x)\n", name, flags); 171 | } 172 | 173 | // Sanity check path address 174 | if(kernel_booted &&!procmm_check_address((uintptr_t)&name[0])) 175 | { 176 | errno = EFAULT; 177 | return -1; 178 | } 179 | 180 | // Find a free descriptor 181 | process_t *p = current->proc; 182 | int i; 183 | int fd = -1; 184 | for(i=0; i < NUM_FILEDES; i++) 185 | { 186 | if(p->fd[i]) 187 | continue; 188 | fd = i; 189 | p->fd[fd] = calloc(1, sizeof(file_desc_t)); 190 | fd_get(p->fd[fd]); 191 | break; 192 | } 193 | if(fd == -1) 194 | { 195 | // No free descriptors 196 | errno = EMFILE; 197 | return fd; 198 | } 199 | 200 | // Open the file 201 | char *n = canonicalize_path(name, 0); 202 | INODE node = vfs_namei(n); 203 | free(n); 204 | if(!node) 205 | { 206 | errno = ENOENT; 207 | fd_put(p->fd[fd]); 208 | p->fd[fd] = 0; 209 | return -1; 210 | } 211 | int retval = vfs_open(node, flags); 212 | if(retval < 0 ) 213 | { 214 | vfs_free(node); 215 | fd_put(p->fd[fd]); 216 | p->fd[fd] = 0; 217 | return -1; 218 | } 219 | p->fd[fd]->ino = node; 220 | p->fd[fd]->offset = 0; 221 | p->fd[fd]->flags = flags; 222 | 223 | return fd; 224 | } 225 | KDEF_SYSCALL(open, r) 226 | { 227 | process_stack stack = init_pstack(); 228 | r->eax = open((const char *)stack[0], stack[1], stack[2]); 229 | r->edx = errno; 230 | return r; 231 | } 232 | 233 | int read(int file, char *ptr, int len) 234 | { 235 | if(current->proc->flags & PROC_FLAG_DEBUG) 236 | { 237 | debug("[info]READ(%d, %x, %x)\n", file, ptr, len); 238 | } 239 | if(kernel_booted && (procmm_check_address((uintptr_t)ptr) <=1 )) 240 | { 241 | errno = EFAULT; 242 | return -1; 243 | } 244 | 245 | process_t *p = current->proc; 246 | INODE node = p->fd[file]->ino; 247 | if(!node) 248 | { 249 | errno = EBADF; 250 | return -1; 251 | } 252 | int ret = vfs_read(node, ptr, len, p->fd[file]->offset); 253 | p->fd[file]->offset += ret; 254 | return ret; 255 | } 256 | KDEF_SYSCALL(read, r) 257 | { 258 | process_stack stack = init_pstack(); 259 | r->eax = read(stack[0], (char *)stack[1], stack[2]); 260 | r->edx = errno; 261 | return r; 262 | } 263 | 264 | int stat(const char *file, struct stat *st) 265 | { 266 | if(current->proc->flags & PROC_FLAG_DEBUG) 267 | { 268 | debug("[info]STAT(%s, %x)\n", file, st); 269 | } 270 | if(kernel_booted && !procmm_check_address((uintptr_t)&file[0])) 271 | { 272 | errno = EFAULT; 273 | return -1; 274 | } 275 | if(kernel_booted && procmm_check_address((uintptr_t)st) <= 1) 276 | { 277 | errno = EFAULT; 278 | return -1; 279 | } 280 | INODE node = vfs_namei(file); 281 | int retval = vfs_stat(node, st); 282 | vfs_free(node); 283 | return retval; 284 | } 285 | KDEF_SYSCALL(stat, r) 286 | { 287 | process_stack stack = init_pstack(); 288 | r->eax = stat((const char *)stack[0], (struct stat *)stack[1]); 289 | r->edx = errno; 290 | return r; 291 | } 292 | 293 | int unlink(char *name) 294 | { 295 | if(current->proc->flags & PROC_FLAG_DEBUG) 296 | { 297 | debug("[info]UNLINK(%s)\n", name); 298 | } 299 | errno = ENOENT; 300 | return -1; 301 | } 302 | KDEF_SYSCALL(unlink, r) 303 | { 304 | process_stack stack = init_pstack(); 305 | r->eax = unlink((char *)stack[0]); 306 | r->edx = errno; 307 | return r; 308 | } 309 | 310 | int write(int file, char *ptr, int len) 311 | { 312 | if(current->proc->flags & PROC_FLAG_DEBUG) 313 | { 314 | debug("[info]WRITE(%d, %x, %x)\n", file, ptr, len); 315 | } 316 | if(kernel_booted && !procmm_check_address((uintptr_t)ptr)) 317 | { 318 | errno = EFAULT; 319 | return -1; 320 | } 321 | 322 | /* ptr[len] = '\0'; */ 323 | process_t *p = current->proc; 324 | INODE node = p->fd[file]->ino; 325 | if(!node) 326 | { 327 | errno = EBADF; 328 | return -1; 329 | } 330 | int ret = vfs_write(node, ptr, len, p->fd[file]->offset); 331 | p->fd[file]->offset += ret; 332 | return ret; 333 | } 334 | KDEF_SYSCALL(write, r) 335 | { 336 | process_stack stack = init_pstack(); 337 | r->eax = write(stack[0], (char *)stack[1], stack[2]); 338 | r->edx = errno; 339 | return r; 340 | } 341 | 342 | struct dirent *readdir(DIR *dirp) 343 | { 344 | if(current->proc->flags & PROC_FLAG_DEBUG) 345 | { 346 | debug("[info]READDIR(%x, %x)\n", dirp->fd, dirp->cur_entry+1); 347 | } 348 | dirp->cur_entry++; 349 | 350 | process_t *p = current->proc; 351 | INODE node = p->fd[dirp->fd]->ino; 352 | if(!node) 353 | { 354 | errno = EBADF; 355 | return 0; 356 | } 357 | 358 | dirent_t *de = 0; 359 | if(!(de = vfs_readdir(node, dirp->cur_entry))) 360 | return 0; 361 | struct dirent *d = calloc(1, sizeof(struct dirent)); 362 | strcpy(d->name, de->name); 363 | d->ino = 0; 364 | 365 | vfs_free(de->ino); 366 | free(de); 367 | 368 | return d; 369 | } 370 | KDEF_SYSCALL(readdir, r) 371 | { 372 | static DIR dirp; 373 | process_stack stack = init_pstack(); 374 | dirp.fd = stack[0]; 375 | dirp.cur_entry = stack[1]-1; 376 | struct dirent *de = readdir(&dirp); 377 | if(de) 378 | { 379 | memcpy((void *)stack[2], de, sizeof(struct dirent)); 380 | free(de); 381 | r->eax = 0; 382 | return r; 383 | } 384 | free(de); 385 | r->eax = -1; 386 | return r; 387 | } 388 | 389 | int dup(int fildes) 390 | { 391 | if(current->proc->flags & PROC_FLAG_DEBUG) 392 | { 393 | debug("[info]DUP(%x)\n", fildes); 394 | } 395 | process_t *p = current->proc; 396 | if(!p->fd[fildes] || fildes < 0) 397 | { 398 | errno = EBADF; 399 | return -1; 400 | } 401 | int i; 402 | int fd = -1; 403 | for(i=0; i < NUM_FILEDES; i++) 404 | { 405 | if(p->fd[i]) 406 | continue; 407 | fd = i; 408 | p->fd[fd] = p->fd[fildes]; 409 | fd_get(p->fd[fildes]); 410 | break; 411 | } 412 | if(fd == -1) 413 | errno = EMFILE; 414 | return fd; 415 | } 416 | KDEF_SYSCALL(dup, r) 417 | { 418 | process_stack stack = init_pstack(); 419 | r->eax = dup(stack[0]); 420 | r->edx = errno; 421 | return r; 422 | } 423 | 424 | int dup2(int fildes1, int fildes2) 425 | { 426 | if(current->proc->flags & PROC_FLAG_DEBUG) 427 | { 428 | debug("[info]DUP2(%x, %x)\n", fildes1, fildes2); 429 | } 430 | process_t *p = current->proc; 431 | if(!p->fd[fildes1] || fildes1 < 0 || fildes2 < 0) 432 | { 433 | errno = EBADF; 434 | return -1; 435 | } 436 | if(fildes1 >= NUM_FILEDES || fildes2 >= NUM_FILEDES) 437 | { 438 | errno = EMFILE; 439 | return -1; 440 | } 441 | 442 | if(fildes1 == fildes2) 443 | return fildes2; 444 | if(p->fd[fildes2]) 445 | { 446 | close(fildes2); 447 | } 448 | p->fd[fildes2] = p->fd[fildes1]; 449 | fd_get(p->fd[fildes1]); 450 | 451 | return fildes2; 452 | } 453 | KDEF_SYSCALL(dup2, r) 454 | { 455 | process_stack stack = init_pstack(); 456 | r->eax = dup2(stack[0], stack[1]); 457 | r->edx = errno; 458 | return r; 459 | } 460 | 461 | int pipe(int fildes[2]) 462 | { 463 | if(current->proc->flags & PROC_FLAG_DEBUG) 464 | { 465 | debug("[info]PIPE(%x)\n", fildes); 466 | } 467 | 468 | process_t *p = current->proc; 469 | 470 | // Find two free file descriptors 471 | int i; 472 | fildes[0] = -1; 473 | for(i = 0; i < NUM_FILEDES; i++) 474 | { 475 | if(p->fd[i]) 476 | continue; 477 | fildes[0] = i; 478 | p->fd[fildes[0]] = calloc(1, sizeof(file_desc_t)); 479 | fd_get(p->fd[fildes[0]]); 480 | break; 481 | } 482 | fildes[1] = -1; 483 | for(i = 0; i < NUM_FILEDES; i++) 484 | { 485 | if(p->fd[i]) 486 | continue; 487 | fildes[1] = i; 488 | p->fd[fildes[1]] = calloc(1, sizeof(file_desc_t)); 489 | fd_get(p->fd[fildes[1]]); 490 | break; 491 | } 492 | 493 | if(fildes[0] == -1 || fildes[1] == -1) 494 | { 495 | errno = EMFILE; 496 | return -1; 497 | } 498 | 499 | // Create pipe 500 | INODE tmp[2]; 501 | new_pipe(512, tmp); 502 | 503 | // Set up and open file descriptors 504 | p->fd[fildes[0]]->ino = tmp[0]; 505 | p->fd[fildes[0]]->flags = O_RDONLY; 506 | vfs_open(tmp[0], O_RDONLY); 507 | p->fd[fildes[1]]->ino = tmp[1]; 508 | p->fd[fildes[1]]->flags = O_WRONLY; 509 | vfs_open(tmp[1], O_WRONLY); 510 | 511 | return 0; 512 | } 513 | KDEF_SYSCALL(pipe, r) 514 | { 515 | process_stack stack = init_pstack(); 516 | r->eax = pipe((int *)stack[0]); 517 | r->edx = errno; 518 | return r; 519 | } 520 | --------------------------------------------------------------------------------