commit 0ec9b130edf156928778ba80a87602540e905d0f
parent 1f41c3e4e4890bc1bde09256f32b83eaebe24d7a
Author: sin <sin@2f30.org>
Date: Mon, 28 May 2012 13:57:31 +0100
cynix: Initial commit
Diffstat:
96 files changed, 9606 insertions(+), 2 deletions(-)
diff --git a/.astylerc b/.astylerc
@@ -0,0 +1,10 @@
+indent=force-tab=8
+indent-classes
+indent-namespaces
+indent-preprocessor
+max-instatement-indent=80
+suffix=none
+brackets=linux
+keep-one-line-statements
+keep-one-line-blocks
+convert-tabs
diff --git a/AUTHORS b/AUTHORS
@@ -0,0 +1,2 @@
+Author and maintainer of cynix:
+ stateless
diff --git a/COPYING b/COPYING
@@ -0,0 +1,14 @@
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ Version 2, December 2004
+
+ Copyright (C) 2004 Sam Hocevar
+ 14 rue de Plaisance, 75014 Paris, France
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
+
diff --git a/INSTALL b/INSTALL
@@ -0,0 +1,3 @@
+Make sure you've got QEMU or bochs installed. If your CPU does not
+support KVM disable it from build/run.sh. Run compile.sh to compile,
+install and execute the image using QEMU as root.
diff --git a/Makefile b/Makefile
@@ -0,0 +1,54 @@
+# root Makefile for cynix
+
+MAKEFLAGS += -rR --no-print-directory
+bin = build/kernel
+inc = -Isrc/include -Isrc/libc
+CC = gcc
+CFLAGS = -std=gnu99 -m32 -Wall -Wextra -Wformat-security -Wshadow \
+ -Wunreachable-code -Wpointer-arith -g -nostdlib -nostdinc \
+ -nodefaultlibs -nostartfiles -fno-builtin $(inc)
+ASFLAGS = -m32 -g -nostdlib -nostdinc -nodefaultlibs -nostartfiles \
+ -fno-builtin $(inc)
+LDFLAGS = -m elf_i386 -Tbuild/link.ld
+logo = "build/logo"
+
+include src/boot/Makefile-part
+include src/core/Makefile-part
+include src/libc/Makefile-part
+
+$(bin): $(obj)
+ @echo -e " LD\t"$@
+ @ld $(LDFLAGS) -o $@ $(obj)
+ @echo " Generating kernel.sym"
+ @nm build/kernel | sort > build/kernel.sym
+ @echo -e "\nHere comes the dopefish!"
+ @cat $(logo)
+ @tput sgr0
+
+%.o: %.c
+ @echo -e " CC\t"$<
+ @$(CC) $(CFLAGS) -c -o $@ $<
+
+%.o: %.S
+ @echo -e " CC\t"$<
+ @$(CC) $(ASFLAGS) -c -o $@ $<
+
+.PHONY: install
+install:
+ @pushd build && ./mkcreateimg.sh && ./installimg.sh && popd
+
+.PHONY: clean
+clean:
+ @rm -rf $(obj) build/kernel* build/image.img build/iso build/cynix.iso
+
+.PHONY: boot
+boot:
+ @pushd build && ./run.sh && popd
+
+.PHONY: pack
+dist:
+ @tar cfz ../cynix.tar.gz .
+
+.PHONY: all
+all:
+ @make clean && make && make boot
diff --git a/README.md b/README.md
@@ -1,4 +1,4 @@
cynix
=====
-An x86 based UNIX-like operating system
-\ No newline at end of file
+An x86 based UNIX-like operating system.
diff --git a/TODO b/TODO
@@ -0,0 +1,25 @@
+* Decouple the keyboard driver from the tty handling.
+* Implement a VT100 compliant tty.
+* Make the kernel live at 0xc0000000.
+* Do all the necessary things to support user-mode.
+* Make sure the functions in the kernel return sensible values.
+* Make sure I've got proper types in the kernel, (use addr_t for uint32_t).
+* Implement a bitmap interface.
+* Provide a means of protecting the stack from growing into the heap.
+* Check permissions in open(2) etc.
+* Track down memory leaks in the ext2 driver.
+* Consider having a separate list for zombie processes.
+* Have the proc struct contain a list of children.
+* Fix structs whose names don't have _t at the end.
+* The allocated file descriptors start at index 3. Remember to fix that.
+* Use APIC instead of PIC.
+* Add support for FPU stuff (bochs complains).
+* Add missing functions to newlib.
+* The ext2 driver only works with a 1024-byte blocksize.
+* Dump PCI functions as well.
+* Implement gdb stubs properly.
+* Make sure that arguments are correctly pushed on the stack.
+* Open file descriptors (0, 1, 2) in crt0.c.
+* Implement cd etc.
+* Add more syscalls.
+* Fix execve bug (rewrite path-lookup code, try to remove all kfrees).
diff --git a/build/add.sh b/build/add.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+E_BADARGS=65
+if [ ! "$UID" == "0" ]; then
+ echo "[+] you need to be root!" 1>&2
+ exit
+fi
+if [ ! -n "$1" ]; then
+ echo "Usage: `basename $0` file" 1>&2
+ exit $E_BADARGS
+fi
+mount -o loop initrd mnt
+cp $1 mnt/
+umount mnt
diff --git a/build/bochsrc b/build/bochsrc
@@ -0,0 +1,9 @@
+config_interface: textconfig
+romimage: file=/usr/share/bochs/BIOS-bochs-latest
+megs: 32
+floppya: 1_44=image.img, status=inserted
+boot: floppy
+log: /dev/stdout
+panic: action=ask
+error: action=report
+info: action=report
diff --git a/build/initrd b/build/initrd
Binary files differ.
diff --git a/build/installimg.sh b/build/installimg.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+MNT_PATH=mnt
+if [ ! "$UID" == "0" ]; then
+ echo "[+] you need to be root!" 1>&2
+ exit
+fi
+if [ ! -f "kernel" ]; then
+ echo "[+] the kernel has to be compiled first!" 1>&2
+ exit
+fi
+losetup /dev/loop0 image.img
+mount -t ext2 /dev/loop0 $MNT_PATH
+cp kernel $MNT_PATH
+cp initrd $MNT_PATH
+umount /dev/loop0
+losetup -d /dev/loop0
diff --git a/build/link.ld b/build/link.ld
@@ -0,0 +1,24 @@
+ENTRY(start)
+SECTIONS
+{
+ .text 0x100000:
+ {
+ code = .; _code = .; __code = .;
+ *(.text)
+ . = ALIGN(4096);
+ }
+ .data :
+ {
+ data = .; _data = .; __data = .;
+ *(.data)
+ *(.rodata)
+ . = ALIGN(4096);
+ }
+ .bss :
+ {
+ bss = .; _bss = .; __bss = .;
+ *(.bss)
+ . = ALIGN(4096);
+ }
+ end = .; _end = .; __end = .;
+}
diff --git a/build/logo b/build/logo
@@ -0,0 +1,23 @@
+[0;34;44mмлллллллл[1mммм[0;34;44mлллллл[40mпп[35mммлллллппппппппппппллллллллллллллллллл[30mлл[34;44mллллллллллллллллллл[40m
+[44mллллл[1;40mллллл[44mллл[0;34;44mлллл[30;40mл[35mлллллл[30mллл[37;47mл[1mлллллллллл[0;47mл[30;40mлл[1mл[0;35mллллллллллллллллл[30mлл[34;44mлллл лллллл[40m
+[44mл [1mлллллл [1C[0;35mлллллл[30mллл[1;37mллллллллллллллл[0;30mллл[35mллпппппплллллллллл [44m [34mл[40m
+[44mллл[1mлллллллллл [0;30mл[35mлллллл[30mлл[1;37mлллллллллллллллллл[0;30mлллл[1mлл[37;47mллл[0;47mл[30;40mл[35mлллллллллм[30mлл[34;44mлллллллл[30;40mллл[34;44mлллл[40m
+[44mллл [1mллллллл [1C[0;35mлллллл[30mлл[1;37mллллллллл[0;47mл[30;40mллллл[1mл[37mллл[0;47mл[1;30mл[37mллллллллллл[0;30mл[35mллллллллл[30mл[34;44mлллл[30;40mллл[35mллл[30mлл[34;44mлл[40m
+[44mллл[1mллллллллл[0;30mлл[35mллллл[30mлл[37;47mл[1mллллллл[30mл[0;30mллллл[37;47mл[1mл[40mл[0;30mлл[1;37mллллллллллллллл[0;30mлл[35mлллллллл[30mл[34;44mллл[30;40mл[35mлл[30mл[35mллл[1;30;42mл[0;30mл[34;44mл[40m
+[44mллл[1mлл[0;34;44mлл[1mлллл[0;34;44mл[30;40mл[35mллллл[1;30;42mл[0;30mлл[1;37mллллллл[0;30mллллллл[37;47mл[1mл[40mл[0;30mллл[1;47mл[0;47mл[30;40mллллл[1;37mлллллллл[0;30mл[35mл[30mл[35mллллллл[30mлллл[35mлл[30mл[35mллллл[34;44mл[40m
+[44mллл[40mп[44mл[1mл[0;34;44mллл[1;40mл[44mлл[0;30mл[35mллллл[30mллл[1;37mллллллл[0;30mллллллллллллл[1;47mл[0;30mллллллл[1;37mллллллл[0;30mл[35mл[30mл[35mллллллл[30mл[35mллллл[30mл[35mллллл[30;44mн[40m
+[34;44mлл[30;40mл[35mл[30mл[34mппп[44mлллл[30;40mл[35mллллл[30mллл[37;47mл[1mлллллл[0;30mллллллллллллл[1;47mл[0;47mл[30;40mллллл[1mл[37mлллллл[0;30mл[35mллл[30mллл[35mлллл[30mл[35mлллл[30mл[35mлллллл[30;44mн[40m
+[34;44mлл[30;40mл[35mлллл[30mл[34mппп[30mл[35mлллллл[1;30;42mл[0;30mллл[1;37mллллллл[0;30mллллллллллллл[1;47mлллл[40mл[0;47mл[1mлллл[40mл[0;30mл[35mллллллл[30mлллл[35mл[30mл[35mлллллллллл[1;30;42mл[0;34;44mл[40m
+[44mлл[30;40mл[35mлллллллл[30mлл[35mлллллл[30mлллл[1;37mлллллллл[0;47mл[30;40mлллл[1;37mллл[0;30mл[35mлл[30mллллллллл[35mллллл[1;30;42mл[0;30mлллл[35mлллл[30mл[35mлпппппппппп[30mл[34;44mл[40m
+[44mл[30;40mл[35mлллллллллл[30mл[35mллллллл[30mллллл[37;47mл[1mллллллллл[40mлл[0;30mл[35mллллллллллллллл[1;30;42mл[0;30mлл[31;41mллл[30;40mллл[1mл[0;35mлллл[30mллл[34;44mллллллллл[40m
+[44mл[30;40mл[35mлллллллллл[30mл[35mллллллллл[1;30;42mл[0;30mлллллллллллл[1mл[0;35mлллллллллллллл[30mлллллл[31;41mллл[30;40mлллл[1mл[0;35mлллл[30mллллллллл[34;44mлл[40m
+[44mл[30;40mл[1mл[0;35mлллллллл[30mллл[35mлллллллллллллллллллллллл[30mлллллллл[1;37mлллллл[0;47mл[30;40mллл[31;41mллллл[30;40mллл[35mллллл[30mл[35mллллл[30mлл[34;44mлл[40m
+[44mлл[30;40mл[1mл[0;35mллллл[30mллллл[35mллллллллллллллл[30mл[37;47mл[1mллллллллл[0;47mл[30;40mл[37;47mл[1mллллллллл[0;47mл[30;40mллл[31;41mллллл[30;40mллл[35mллллл[30mл[35mлллл[30mллл[34;44mлл[40m
+[44mллл[30;40mл[1mл[0;35mллл[30mл[34;44mллл[30;40mллл[35mлллллллллллллл[30mл[37;47mл[1mллллллллл[0;47mл[30;40mл[37;47mл[1mллллллллл[0;47mл[30;40mллл[31;41mллллл[30;40mллл[35mллллл[30mл[35mллл[30mлл[34;44mлллл[40m
+[44mлл [1C[35;40mл[30mл[44m [6C[40mл[1mл[0;35mлллллл[30mл[35mлллллл[30mл[37;47mл[1mллллллллл[0;47mл[30;40mл[37;47mл[1mллллллллл[0;47mл[30;40mллл[31;41mллл[30;40mлллл[35mлллллл[30mл[35mлл[30mллл[34;44mлллл[40m
+[44mллллл[30;40mл[34;44mл[30;40mл[35mлллллл[30mлл[35mллллллллллллл[30mл[37;47mл[1mллллллллл[0;47mл[30;40mл[37;47mл[1mллллллллл[0;47mл[30;40mллл[31;41mллл[30;40mллл[35mлллллл[30mл[35mлл[30mлл[34;44mлллллл[40m
+[44mлл [30;40mллл[35mллл[30mллл[35mллллл[30mл[35mлллллл[30mл[37;47mл[1mллллллллл[0;47mл[30;40mл[37;47mл[1mллллллллл[0;47mл[30;40mллллллл[1mл[0;35mллллллл[30mлллл[34;44mллллллл[40m
+[44mлл [3C[35;40mл[30mлллл[35mлллл[1;30;42mл[0;30mл[35mллллл[30mл[37;47mл[1mллллллллл[0;47mл[30;40mл[37;47mл[1mллллллллл[0;47mл[30;40mллл[1mл[0;35mлллллл[1;37;40mCyn[40mix v0[44m.01 [0;34;44mлл[40m
+[44mл лл[30;40mллл[34;44mллл[30;40mл[35mлллл лллл[30mлллллллллллллллллллллллл[35mлллллллллл[30mлллл[34;44mл[1;37mby sin [0;34;44mлл[40m
+[44mлл лллл[30;40mл[35mллллл [30mлл[35mллллллллл[30mлллл[35mллллллллллллллллллллл[30mллл[34;44mллллллллллллллл[40m
+[44mл[1m [0;34;44mллллллллллллл[35;40mлллллл[30mлллл[35mллллллллллмммммм ллллллллллллл[30mллл[34;44mллллллллл лл[40m[0m[255D
diff --git a/build/makeiso.sh b/build/makeiso.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+if [ ! -f "kernel" ]; then
+ echo "[+] the kernel has to be compiled first!" 1>&2
+ exit
+fi
+mkdir -p iso/boot/grub
+cp stage2_eltorito iso/boot/grub
+cp kernel initrd iso/boot
+echo "default 0;title cynix;kernel /boot/kernel;module /boot/initrd" | \
+ sed 's/;/\n/g' > iso/boot/grub/menu.lst
+genisoimage -R -b boot/grub/stage2_eltorito -no-emul-boot \
+ -input-charset utf-8 -boot-load-size 4 -boot-info-table -o cynix.iso iso
diff --git a/build/mkcreateimg.sh b/build/mkcreateimg.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+MNT_PATH=./mnt
+
+function notfound() {
+ echo "[+] $1 can't be located!" 1>&2
+ umount /dev/loop0
+ exit
+}
+
+if [ ! "$UID" == "0" ]; then
+ echo "[+] you need to be root!" 1>&2
+ exit
+fi
+[ -d $MNT_PATH ] || mkdir $MNT_PATH
+lsmod | grep loop
+[ $? -eq 0 ] || modprobe loop &>/dev/null
+[ $? -eq 0 ] || echo "[+] loop can't be loaded!"
+dd if=/dev/zero of=image.img bs=512 count=2880
+losetup /dev/loop0 image.img
+mkfs -t ext2 /dev/loop0
+mount -t ext2 /dev/loop0 $MNT_PATH/
+mkdir -p $MNT_PATH/grub
+[ -f stage1 ] || notfound "stage1"
+[ -f stage2 ] || notfound "stage2"
+cp stage[12] $MNT_PATH/grub
+echo "timeout 1;default 0;title cynix;root (fd0);kernel /kernel;module (fd0)/initrd" | \
+ sed 's/;/\n/g' > $MNT_PATH/grub/menu.lst
+grub --batch --device-map=/dev/null << EOF
+device (fd0) /dev/loop0
+root (fd0)
+setup (fd0)
+quit
+EOF
+umount /dev/loop0
+losetup -d /dev/loop0
diff --git a/build/mkfloppyimg.sh b/build/mkfloppyimg.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+if [ ! "$UID" == "0" ]; then
+ echo "[+] you need to be root!" 1>&2
+ exit
+fi
+dd if=./image.img of=/dev/fd0
diff --git a/build/run.sh b/build/run.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+if [ ! "$UID" == "0" ]; then
+ echo "[+] you need to be root!" 1>&2
+ exit
+fi
+# use -s -S for remote debugging with gdb.
+# use -enable-kvm for kvm support.
+./mkcreateimg.sh \
+ && ./installimg.sh \
+ && tunctl -b -u `whoami` &>/dev/null \
+ && ifconfig tap0 up \
+ && qemu -net nic,model=rtl8139 \
+ -net tap,ifname=tap0,script=no,downscript=no \
+ -serial stdio -fda image.img -boot a -m 32 \
+ -localtime -no-acpi -vga std \
+ && tunctl -d tap0 &>/dev/null
diff --git a/build/stage1 b/build/stage1
Binary files differ.
diff --git a/build/stage2 b/build/stage2
Binary files differ.
diff --git a/build/stage2_eltorito b/build/stage2_eltorito
Binary files differ.
diff --git a/compile.sh b/compile.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+echo "#ifndef __VERSION_H__" > src/include/version.h
+echo "#define __VERSION_H__" >> src/include/version.h
+echo "#define USER \"`whoami`\"" >> src/include/version.h
+echo "#define DATE \"`date`\"" >> src/include/version.h
+echo "#define HOST \"`hostname`\"" >> src/include/version.h
+echo "#define REVISION \"`hg summary 2>/dev/null | awk '{print $2}' \
+ | sed 's/:/\n/g' | head -1`\"" >> src/include/version.h
+echo "#endif" >> src/include/version.h
+sudo make all
diff --git a/format.sh b/format.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+i=0
+for file in $(find . -type f -iname "*.[ch]"); do
+ astyle --options=.astylerc $file | grep -i "formatted"
+ if [ $? -eq 0 ]; then
+ let i=i+1
+ fi
+done
+
+if [ $i -gt 0 ]; then
+ echo "Beautified" $i "files."
+fi
diff --git a/src/boot/Makefile-part b/src/boot/Makefile-part
@@ -0,0 +1 @@
+obj += src/boot/boot.o src/boot/init.o
diff --git a/src/boot/boot.S b/src/boot/boot.S
@@ -0,0 +1,34 @@
+#define ASM 1
+#include <multiboot.h>
+.text
+.globl start, _start
+start:
+_start:
+ jmp multiboot_entry
+ .align 4
+ .globl multiboot_header
+multiboot_header:
+ .long MULTIBOOT_HEADER_MAGIC
+ .long MULTIBOOT_HEADER_FLAGS
+ .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
+#ifndef __ELF__
+ .long multiboot_header
+ .long _start
+ .long _edata
+ .long _end
+ .load multiboot_entry
+#endif
+multiboot_entry:
+ cli
+ movl $(stack + STACK_SIZE), %esp
+ pushl $0
+ popf
+ pushl %esp
+ pushl %ebx
+ pushl %eax
+ call EXT_C(init)
+loop:
+ hlt
+ jmp loop
+.comm stack, STACK_SIZE
+
diff --git a/src/boot/init.c b/src/boot/init.c
@@ -0,0 +1,24 @@
+/*
+ * core/init.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <multiboot.h>
+#include <common.h>
+
+extern int main(void);
+extern int puts(const char *s);
+
+unsigned long int addr_info = 0, initial_esp = 0;
+
+void
+init(unsigned long int magic, unsigned long int addr, unsigned long int initial_esp_arg)
+{
+ if (magic != MULTIBOOT_BOOTLOADER_MAGIC)
+ panic("0x%lx invalid magic number", magic);
+ addr_info = addr;
+ initial_esp = initial_esp_arg;
+ main();
+}
+
diff --git a/src/cmd/ls.c b/src/cmd/ls.c
@@ -0,0 +1,48 @@
+#include <dirent.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+int
+main(void)
+{
+ char buf[256];
+ DIR *dirp;
+ struct dirent *dirent;
+ struct stat stbuf;
+ int ret;
+
+ dirp = opendir("/");
+ if (!dirp)
+ return -errno;
+ dirent = readdir(dirp);
+ printf("%-12s%-12s%-12s%-12s\n", "FILENAME", "TYPE", "UID", "GID");
+ while (dirent) {
+ if (!strcmp(dirent->d_name, ".")
+ || !strcmp(dirent->d_name, ".."))
+ goto out;
+ bzero(buf, 256);
+ buf[0] = '/';
+ strncpy(buf + 1, dirent->d_name, 255);
+ buf[255] = '\0';
+ ret = stat(buf, &stbuf);
+ if (ret < 0) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ break;
+ }
+ printf("%-12s%-12s%-12d%-12d\n",
+ dirent->d_name,
+ S_ISREG(stbuf.st_mode) ? "FILE" : "DIR",
+ stbuf.st_uid,
+ stbuf.st_gid);
+out:
+ dirent = readdir(dirp);
+ }
+ ret = closedir(dirp);
+ if (ret < 0)
+ return -errno;
+ return 0;
+}
+
diff --git a/src/core/Makefile-part b/src/core/Makefile-part
@@ -0,0 +1,23 @@
+obj += \
+ src/core/main.o \
+ src/core/tty.o \
+ src/core/x86_asm.o \
+ src/core/rtc.o \
+ src/core/keyboard.o \
+ src/core/idt.o \
+ src/core/gdt.o \
+ src/core/pic.o \
+ src/core/mm.o \
+ src/core/heap.o \
+ src/core/errno.o \
+ src/core/syscall.o \
+ src/core/tss.o \
+ src/core/ext2.o \
+ src/core/serial.o \
+ src/core/common.o \
+ src/core/elf.o \
+ src/core/pci.o \
+ src/core/cpuid.o \
+ src/core/kdb.o \
+ src/core/rtl8139.o \
+ src/core/pipe.o
diff --git a/src/core/common.c b/src/core/common.c
@@ -0,0 +1,133 @@
+/*
+ * core/common.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <common.h>
+#include <tty.h>
+#include <ctype.h>
+#include <elf.h>
+#include <serial.h>
+#include <x86.h>
+#include <tss.h>
+
+extern uint8_t __code[0];
+extern uint8_t __end[0];
+extern unsigned long int initial_esp;
+
+void
+dump_regs(void)
+{
+ uint32_t eax, ebx, ecx, edx, esp, ebp;
+ uint32_t edi, esi;
+
+ asm volatile ("movl %%eax, %0" : "=r"(eax));
+ asm volatile ("movl %%ebx, %0" : "=r"(ebx));
+ asm volatile ("movl %%ecx, %0" : "=r"(ecx));
+ asm volatile ("movl %%edx, %0" : "=r"(edx));
+ asm volatile ("movl %%esp, %0" : "=r"(esp));
+ asm volatile ("movl %%ebp, %0" : "=r"(ebp));
+ asm volatile ("movl %%esi, %0" : "=r"(esi));
+ asm volatile ("movl %%edi, %0" : "=r"(edi));
+
+ printf("eax = 0x%08lx\nebx = 0x%08lx\necx = 0x%08lx\n",
+ eax, ebx, ecx);
+ printf("edx = 0x%08lx\nesp = 0x%08lx\nebp = 0x%08lx\n",
+ edx, esp, ebp);
+ printf("esi = 0x%08lx\nedi = 0x%08lx\n",
+ esi, edi);
+ serial_dump("eax = 0x%08lx\nebx = 0x%08lx\necx = 0x%08lx\n",
+ eax, ebx, ecx);
+ serial_dump("edx = 0x%08lx\nesp = 0x%08lx\nebp = 0x%08lx\n",
+ edx, esp, ebp);
+ serial_dump("esi = 0x%08lx\nedi = 0x%08lx\n",
+ esi, edi);
+}
+
+void
+panic_internal(const char *file, const char *fn, uint32_t line, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[512], line_s[32];
+
+ asm volatile ("cli");
+ printf("~~~ kernel panic ~~~\n");
+ stacktrace(8);
+ itoa(line, line_s, 10);
+ printf("%s:%s:%s ", file, fn, line_s);
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+ printf("%s\n", buf);
+ update_cursor(cursor_y, cursor_x);
+ serial_dump("~~~ kernel panic ~~~\n");
+ serial_dump("%s:%s:%s ", file, fn, line_s);
+ serial_dump("%s\n", buf);
+ dump_regs();
+ asm volatile ("hlt");
+}
+
+void
+hexdump(const void *ptr, size_t len)
+{
+ const char *addr = (const char *)ptr;
+ size_t i;
+ int j;
+
+ for (i = 0; i < len; i += 16) {
+ serial_dump("0x%08lx: ", (uint32_t)addr);
+ serial_dump("0x%08lx 0x%08lx 0x%08lx 0x%08lx |",
+ *(uint32_t *)addr,
+ *(uint32_t *)(addr + 4),
+ *(uint32_t *)(addr + 8),
+ *(uint32_t *)(addr + 12)
+ );
+ printf("0x%08lx: ", (uint32_t)addr);
+ printf("0x%08lx 0x%08lx 0x%08lx 0x%08lx |",
+ *(uint32_t *)addr,
+ *(uint32_t *)(addr + 4),
+ *(uint32_t *)(addr + 8),
+ *(uint32_t *)(addr + 12)
+ );
+
+ for (j = 0; j < 16; ++j) {
+ serial_dump("%c", (isalpha(addr[j])) ? addr[j] : '.');
+ printf("%c", (isalpha(addr[j])) ? addr[j] : '.');
+ }
+ serial_dump("|\n");
+ printf("|\n");
+ addr += 16;
+ }
+}
+
+void
+stacktrace(int depth)
+{
+ uint32_t *addr, ebp, stack_top;
+ const char *p;
+
+ stack_top = (!curr_proc) ? initial_esp :
+ (uint32_t)curr_proc->stack + TASK_STACK_SIZE - sizeof(struct cswitch_frame_t);
+ GET_EBP(ebp);
+ addr = (uint32_t *)(ebp + 4);
+ if (curr_proc)
+ printf("Stack trace for thread [%d:%s]\n", curr_proc->pid, curr_proc->name);
+ printf("\t\t%-12s %-12s\n", "Address", "Function");
+ while (depth--) {
+ p = find_symbol(*addr);
+ if (!p)
+ ++depth;
+ else
+ printf("\t\t0x%-12.8lx%-12s\n", *addr, p);
+ for (;;) {
+ if ((uint32_t)addr + 4 >= stack_top)
+ return;
+ addr += 4;
+ /* this is just a heuristic */
+ if (*addr > (uint32_t)__code && *addr < (uint32_t)__end)
+ break;
+ }
+ }
+}
+
diff --git a/src/core/cpuid.c b/src/core/cpuid.c
@@ -0,0 +1,82 @@
+/*
+ * core/cpuid.c
+ *
+ * Copyright (C) 2010 stateless
+ */
+
+#include <x86.h>
+#include <stdint.h>
+
+#define cpuid(code, eax, ebx, ecx, edx) \
+ ({ \
+ uint32_t __code = code; \
+ asm volatile ("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "0"(__code)); \
+ })
+
+static const char *intel_brands[] = {
+ "Brand not supported",
+ "Intel(R) Celeron(R) processor",
+ "Intel(R) Pentium(R) III processor",
+ "Intel(R) Pentium(R) III Xeon(R) processor",
+ "Intel(R) Pentium(R) III processor",
+ "Reserved",
+ "Mobile Intel(R) Pentium(R) III processor-M",
+ "Mobile Intel(R) Celeron(R) processor",
+ "Intel(R) Pentium(R) 4 processor",
+ "Intel(R) Pentium(R) 4 processor",
+ "Intel(R) Celeron(R) processor",
+ "Intel(R) Xeon(R) Processor",
+ "Intel(R) Xeon(R) processor MP",
+ "Reserved",
+ "Mobile Intel(R) Pentium(R) 4 processor-M",
+ "Mobile Intel(R) Pentium(R) Celeron(R) processor",
+ "Reserved",
+ "Mobile Genuine Intel(R) processor",
+ "Intel(R) Celeron(R) M processor",
+ "Mobile Intel(R) Celeron(R) processor",
+ "Intel(R) Celeron(R) processor",
+ "Mobile Geniune Intel(R) processor",
+ "Intel(R) Pentium(R) M processor",
+ "Mobile Intel(R) Celeron(R) processor"
+};
+
+static void
+print_vendor(uint32_t str[4])
+{
+ printf("vendor_id: ");
+ printf("%c%c%c%c", (str[1] & 0xff), (str[1] >> 8) & 0xff,
+ (str[1] >> 16) & 0xff, (str[1] >> 24) & 0xff);
+ printf("%c%c%c%c", (str[3] & 0xff), (str[3] >> 8) & 0xff,
+ (str[3] >> 16) & 0xff, (str[3] >> 24) & 0xff);
+ printf("%c%c%c%c", (str[2] & 0xff), (str[2] >> 8) & 0xff,
+ (str[2] >> 16) & 0xff, (str[2] >> 24) & 0xff);
+ putchar('\n');
+}
+
+void
+do_cpuid(void)
+{
+ uint32_t output[4], family, brand, a, b, d;
+ uint32_t unused;
+
+ cpuid(0, output[0], output[1], output[2], output[3]);
+ printf("processor: 0\n");
+ print_vendor(output);
+ if (output[1] != 0x756e6547) { /* not an Intel cpu */
+ info("can't get any more info out of this cpu!\n");
+ return;
+ }
+
+ cpuid(1, a, b, unused, d);
+ family = (a >> 8) & 0xf;
+ printf("cpu_family: %s\n",
+ (family == 4) ? "i486" :
+ (family == 5) ? "Pentium" :
+ (family == 6) ? "Pentium Pro" : "Unknown");
+ brand = (b & 0xff);
+ if (brand < sizeof(intel_brands) / sizeof(intel_brands[0]))
+ printf("model_name: %s\n", intel_brands[brand]);
+ else
+ printf("model_name: Unknown\n");
+}
+
diff --git a/src/core/elf.c b/src/core/elf.c
@@ -0,0 +1,55 @@
+/*
+ * core/elf.c
+ *
+ * Copyright (C) 2010 stateless
+ */
+
+#include <elf.h>
+#include <multiboot.h>
+#include <common.h>
+#include <string.h>
+#include <serial.h>
+
+extern multiboot_info_t *info_boot;
+
+Elf32_Shdr *symtab = NULL, *strtab = NULL;
+
+int
+prepare_elf(void)
+{
+ elf_section_header_table_t *header;
+ Elf32_Shdr *sh, *tmp;
+ unsigned long i;
+
+ header = &info_boot->u.elf_sec;
+ sh = (Elf32_Shdr *)(header->addr + header->shndx * header->size);
+ for (i = 0; i < header->num; ++i) {
+ tmp = (Elf32_Shdr *)(header->addr + i * header->size);
+ if (tmp->sh_type == SHT_SYMTAB)
+ symtab = tmp;
+ else if (tmp->sh_type == SHT_STRTAB)
+ if (!strcmp((const char *)sh->sh_addr + tmp->sh_name, ".strtab"))
+ strtab = tmp;
+ }
+ return (!symtab || !strtab) ? -1 : 0;
+}
+
+const char *
+find_symbol(uint32_t addr)
+{
+ Elf32_Sym *sym;
+ size_t i;
+
+ if (!symtab || !strtab)
+ return NULL;
+
+ sym = (Elf32_Sym *)symtab->sh_addr;
+ for (i = 0; i < symtab->sh_size / sizeof(*sym); ++i) {
+ if (addr >= sym->st_value && addr < sym->st_value + sym->st_size)
+ return (const char *)(strtab->sh_addr + sym->st_name);
+ ++sym;
+ }
+
+ return NULL;
+}
+
diff --git a/src/core/errno.c b/src/core/errno.c
@@ -0,0 +1,57 @@
+/*
+ * core/errno.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <errno.h>
+
+int errno;
+
+const char *sys_errlist [] = {
+ "argument list too long", /* E2BIG */
+ "permission denied", /* EACCES */
+ "resource temporarily unavailable", /* EAGAIN */
+ "bad file descriptor", /* EBADF */
+ "bad message", /* EBADMSG */
+ "device or resource busy", /* EBUSY */
+ "operation canceled", /* ECANCELED */
+ "no child processes", /* ECHILD */
+ "resource deadlock avoided", /* EDEADLK */
+ "mathematics argument out of domain of function", /* EDOM */
+ "file exists", /* EEXIST */
+ "bad address", /* EFAULT */
+ "file too large", /* EFBIG */
+ "illegal byte sequence ", /* EILSEQ */
+ "operation in progress", /* EINPROGRESS */
+ "interrupted function call", /* EINTR */
+ "invalid argument", /* EINVAL */
+ "input/output error", /* EIO */
+ "is a directory", /* EISDIR */
+ "too many open files", /* EMFILE */
+ "too many links", /* EMLINK */
+ "message too long", /* EMSGSIZE */
+ "filename too long", /* ENAMETOOLONG */
+ "too many open files in system", /* ENFILE */
+ "no such device", /* ENODEV */
+ "no such file or directory", /* ENOENT */
+ "exec format error", /* ENOEXEC */
+ "no locks available", /* ENOLCK */
+ "not enough space", /* ENOMEM */
+ "no space left on device", /* ENOSPC */
+ "function not implemented", /* ENOSYS */
+ "not a directory", /* ENOTDIR */
+ "directory not empty", /* ENOTEMPTY */
+ "operation not supported", /* ENOTSUP */
+ "inappropriate I/O control", /* ENOTTY */
+ "no such device or address", /* ENXIO */
+ "operation not permitted", /* EPERM */
+ "broken pipe", /* EPIPE */
+ "result too large", /* ERANGE */
+ "read-only file system", /* EROFS */
+ "invalid seek", /* ESPIPE */
+ "no such process", /* ESRCH */
+ "connection timed out", /* ETIMEDOUT */
+ "improper link" /* EXDEV */
+};
+
diff --git a/src/core/ext2.c b/src/core/ext2.c
@@ -0,0 +1,837 @@
+/*
+ * core/ext2.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <ext2.h>
+#include <common.h>
+#include <errno.h>
+#include <string.h>
+#include <heap.h>
+#include <x86.h>
+#include <mm.h>
+#include <syscall.h>
+#include <elf.h>
+#include <tty.h>
+#include <unistd.h>
+#include <pipe.h>
+
+#define EXT2_SETERRNO_AND_RET(err, ret) SETERRNO_AND_RET(err, ret)
+
+spinlock_t flist_lock;
+struct list_head flist;
+
+static struct ext2_superblock_t *sblock = NULL;
+static struct ext2_inode_t *root_inode = NULL;
+static char *fs_base_addr = NULL;
+
+static void *readblock(uint32_t block_no);
+static struct ext2_inode_t *geti(ino_t ino);
+static struct ext2_gdt_t *readgdt(uint32_t gdt);
+static int read_inode_blocks(struct ext2_inode_t *inode, off_t offs, char *buffer, size_t nbytes);
+static int check_inode_status(ino_t inode);
+static struct ext2_dir_t *resolve_path_internal(struct ext2_inode_t *inode, const char *path);
+static struct ext2_dir_t *resolve_path(const char *path);
+static struct ext2_dir_t *find_dentry(struct ext2_inode_t *inode, const char *name, uint32_t is_root);
+static int filealloc(ino_t inode_nr);
+static blksize_t get_block_size(void);
+
+static blksize_t
+get_block_size(void)
+{
+ assert(sblock);
+ return 1024 << sblock->block_size;
+}
+
+static inline void *
+readblock(uint32_t block_no)
+{
+ assert(sblock);
+ return fs_base_addr + get_block_size() * block_no;
+}
+
+static inline struct ext2_gdt_t *
+readgdt(uint32_t gdt) {
+ char *block;
+
+ block = readblock(2);
+ return (struct ext2_gdt_t *)(block + (gdt * sizeof(struct ext2_gdt_t)));
+}
+
+static inline struct ext2_inode_t *
+geti(ino_t ino) {
+ struct ext2_gdt_t *gdt;
+
+ gdt = readgdt((ino - 1) / sblock->nr_inodes_per_group);
+ return (struct ext2_inode_t *)((char *)readblock(gdt->addr_inode_table) + (ino - 1) * sblock->inode_size);
+}
+
+/* should be called with flist_lock held */
+__attribute__ ((unused)) static void
+dump_flist(void)
+{
+ struct list_head *iter;
+ struct file_t *f;
+
+ list_for_each(iter, &flist) {
+ f = list_entry(iter, struct file_t, f_listopen);
+ printf("inode = 0x%08lx, off = %lu, state = %s, ref_count = %d\n",
+ (void *)f->f_inode,
+ f->f_off,
+ (f->f_state == FILE_ALLOC) ? "FILE_ALLOC" : "FILE_NONE",
+ f->f_refcount
+ );
+ }
+}
+
+int
+ext2_mount(char *addr)
+{
+ int i;
+
+ if (!addr) return -EINVAL;
+ fs_base_addr = addr;
+ sblock = (struct ext2_superblock_t *)(fs_base_addr + 1024);
+ if (sblock->magic != 0xef53) {
+ info("invalid ext2 volume!\n");
+ sblock = NULL;
+ return -EILSEQ;
+ }
+ root_inode = geti(2);
+ if (!(root_inode->file_mode & DIRECTORY_T)) {
+ info("can't locate the root directory of the filesystem!\n");
+ return -ENOTDIR;
+ }
+ for (i = 1; i <= 10; ++i)
+ if (check_inode_status(i) < 0) {
+ info("inode validation failed!\n");
+ return -EIO;
+ }
+ INIT_LIST_HEAD(&flist);
+ initspinlock(&flist_lock);
+ return 0;
+}
+
+struct ext2_inode_t *
+get_root_inode(void) {
+ assert(root_inode);
+ return root_inode;
+}
+
+static int
+read_inode_blocks(struct ext2_inode_t *inode, off_t offs /* in blocks */, char *buffer, size_t nbytes)
+{
+ int ret = -EINVAL, off = 0;
+ uint32_t *block, i;
+ blkcnt_t nr_blocks;
+ blksize_t blksize;
+ char *tmp;
+
+ if (!inode || !buffer)
+ return ret;
+ if (!nbytes)
+ return 0;
+
+ /* TODO: make sure this code is bug-proof */
+ blksize = get_block_size();
+ nr_blocks = inode->size_low32 / blksize;
+ if (nr_blocks >= 12 + (blksize / 4)
+ || (nbytes / blksize) + offs >= 12 + (blksize / 4)) {
+ info("can't handle double indirect blocks yet!\n");
+ return -EIO;
+ }
+ if (offs >= 12) {
+ offs -= 12;
+ goto read_indirect;
+ }
+ block = (uint32_t *)inode->direct_blocks;
+ block += offs;
+ for (i = offs / blksize; nbytes && i <= nr_blocks; ++i, ++block) {
+ if (!*block)
+ continue;
+ tmp = readblock(*block);
+ memcpy((char *)buffer + off, tmp, blksize);
+ nbytes -= blksize;
+ off += blksize;
+ if (off / blksize >= 12 && nbytes)
+ goto read_indirect;
+ }
+ if (!nbytes) return off;
+read_indirect:
+ block = (uint32_t *)readblock(inode->single_indir_block);
+ block += offs;
+ for (i = offs / blksize; nbytes && i <= nr_blocks; ++i, ++block) {
+ if (!*block)
+ continue;
+ tmp = readblock(*block);
+ memcpy((char *)buffer + off, tmp, blksize);
+ nbytes -= blksize;
+ off += blksize;
+ }
+ return off;
+}
+
+static struct ext2_dir_t *
+find_dentry(struct ext2_inode_t *inode, const char *name, uint32_t is_root) {
+ char *buffer;
+ struct ext2_dir_t *dir, *retdir;
+ int ret;
+ blkcnt_t nr_blocks;
+ blksize_t blksize;
+
+ if (!name)
+ return ERR_PTR(-EINVAL);
+
+ blksize = get_block_size();
+ buffer = kmalloc(blksize);
+ if (IS_ERR(buffer))
+ return (void *)buffer;
+ nr_blocks = inode->size_low32 / blksize;
+ for (uint32_t j = 0; j <= nr_blocks; ++j) {
+ if ((ret = read_inode_blocks(inode, j, buffer, blksize)) < 0)
+ kerror(-ret);
+ if (!ret) continue;
+ dir = (struct ext2_dir_t *)buffer;
+ if (is_root) goto found;
+ for (; dir->rec_length;
+ dir = (struct ext2_dir_t *)((char *)dir + dir->rec_length)) {
+ if (strlen(name) == dir->name_length) {
+ if (!strncmp(name, dir->filename, dir->name_length)) {
+found:
+ if (is_root)
+ assert(!strcmp(name, "/"));
+ retdir = kmalloc(sizeof(*retdir));
+ if (IS_ERR(retdir)) {
+ kfree(buffer);
+ return retdir;
+ }
+ memcpy(retdir, dir, sizeof(*retdir));
+ kfree(buffer);
+ return retdir;
+ }
+ }
+ }
+ }
+ kfree(buffer);
+ return ERR_PTR(-ENOENT);
+}
+
+static int
+filealloc(ino_t inode_nr)
+{
+ struct ext2_inode_t *inode;
+ struct file_t *f;
+ int i;
+
+ inode = geti(inode_nr);
+ acquire(&flist_lock);
+ for (i = 3; i < NR_MAX_OPEN_FILES; ++i) {
+ if (curr_proc->fdtable[i]
+ && curr_proc->fdtable[i]->f_state != FILE_NONE)
+ continue;
+ if (!curr_proc->fdtable[i]) {
+ f = kmalloc(sizeof(struct file_t));
+ if (IS_ERR(f)) {
+ release(&flist_lock);
+ return PTR_ERR(f);
+ }
+ f->f_state = FILE_NONE;
+ list_add_tail(&f->f_listopen, &flist);
+ curr_proc->fdtable[i] = f;
+ }
+ f = curr_proc->fdtable[i];
+ assert(f->f_state == FILE_NONE);
+ f->f_refcount = 1;
+ f->f_off = 0;
+ f->f_state = FILE_ALLOC;
+ f->f_type = FILE_REG;
+ f->f_inode = inode;
+ f->f_inode_nr = inode_nr;
+ release(&flist_lock);
+ return i;
+ }
+ release(&flist_lock);
+ return -EMFILE;
+}
+
+int
+fileclose(int fd)
+{
+ struct file_t *f;
+ int j;
+
+ if (fd < 0 || fd >= NR_MAX_OPEN_FILES)
+ return -EINVAL;
+
+ acquire(&flist_lock);
+ f = curr_proc->fdtable[fd];
+ if (!f || f->f_state != FILE_ALLOC) {
+ release(&flist_lock);
+ return -EBADF;
+ }
+ if (!--f->f_refcount) {
+ curr_proc->fdtable[fd]->f_state = FILE_NONE;
+ if (f->f_type == FILE_PIPE) {
+ for (j = 3; j < NR_MAX_OPEN_FILES; ++j) {
+ if (fd == j || curr_proc->pipebufs[j] != curr_proc->pipebufs[fd])
+ continue;
+ if (curr_proc->fdtable[j]->f_state == FILE_ALLOC)
+ break;
+ /* no one is referencing this buffer */
+ kfree(curr_proc->pipebufs[fd]);
+ curr_proc->pipebufs[fd] = curr_proc->pipebufs[j] = NULL;
+ break;
+ }
+ }
+ }
+ release(&flist_lock);
+ return 0;
+}
+
+/* TODO: free pipebufs */
+void
+closefds(void)
+{
+ struct file_t *f;
+ int i;
+
+ acquire(&flist_lock);
+ for (i = 3; i < NR_MAX_OPEN_FILES; ++i) {
+ if (!curr_proc->fdtable[i])
+ continue;
+ f = curr_proc->fdtable[i];
+ if (f->f_state == FILE_NONE || f->f_state == FILE_ALLOC) {
+ if (f->f_state == FILE_NONE) {
+ assert(!f->f_refcount);
+ list_del(&f->f_listopen);
+ /* invalidate dup(2)ed close fds */
+ bzero(f, sizeof(*f));
+ kfree(f);
+ } else {
+ if (!--f->f_refcount) {
+ list_del(&f->f_listopen);
+ bzero(f, sizeof(*f));
+ kfree(f);
+ }
+ }
+ }
+ }
+ release(&flist_lock);
+}
+
+static struct ext2_dir_t *
+resolve_path_internal(struct ext2_inode_t *inode, const char *path) {
+ struct ext2_dir_t *dirent;
+ char *buf, *bufptr;
+ const char *ptr;
+ uint32_t ino;
+ uint32_t is_root_flag = 1;
+ int ret;
+
+ buf = kmalloc(EXT2_NAME_LEN + 1);
+ if (IS_ERR(buf)) {
+ ret = PTR_ERR(buf);
+ return ERR_PTR(ret);
+ }
+ memset(buf, 0, EXT2_NAME_LEN + 1);
+ ptr = path;
+ *buf = *ptr;
+ if (*ptr == '/') ++ptr;
+ if (*ptr) {
+ bufptr = buf;
+ while (*ptr && *ptr != '/') {
+ if (bufptr - buf >= EXT2_NAME_LEN) {
+ kfree(buf);
+ return ERR_PTR(-ENAMETOOLONG);
+ }
+ *bufptr++ = *ptr++;
+ }
+ if (*ptr == '/') ++ptr;
+ is_root_flag = 0;
+ }
+ if (IS_ERR(dirent = find_dentry(inode, buf, is_root_flag))) {
+ ret = PTR_ERR(dirent);
+ goto err;
+ }
+ kfree(buf);
+ if (!*ptr)
+ return dirent;
+ ino = dirent->inode;
+ kfree(dirent);
+ return resolve_path_internal(geti(ino), ptr);
+err:
+ kfree(buf);
+ return ERR_PTR(ret);
+}
+
+static struct ext2_dir_t *
+resolve_path(const char *path) {
+ if (!path)
+ return NULL;
+ if (*path == '/')
+ return resolve_path_internal(root_inode, path);
+ return resolve_path_internal(curr_proc->cdir, path);
+}
+
+static int
+check_inode_status(ino_t inode)
+{
+ struct ext2_gdt_t *gdt;
+ char *inode_bitmap;
+ blksize_t i;
+
+ gdt = readgdt((inode - 1) / sblock->nr_inodes_per_group);
+ inode_bitmap = readblock(gdt->addr_block_bitmap);
+ for (i = 0; i < get_block_size(); ++i)
+ if (inode_bitmap[i / 8] & (1 << (1 % 8)))
+ return 0;
+ return -ENOENT;
+}
+
+int
+dup(int oldfd)
+{
+ int i;
+ struct file_t *f, *tmp;
+
+ if (oldfd < 0 || oldfd >= NR_MAX_OPEN_FILES)
+ return -EINVAL;
+ acquire(&flist_lock);
+ f = curr_proc->fdtable[oldfd];
+ if (!f || f->f_state != FILE_ALLOC) {
+ release(&flist_lock);
+ return -EBADF;
+ }
+ for (i = 3; i < NR_MAX_OPEN_FILES; ++i) {
+ tmp = curr_proc->fdtable[i];
+ if (!tmp || tmp->f_state == FILE_NONE) {
+ if (tmp->f_state == FILE_NONE) {
+ assert(!tmp->f_refcount);
+ list_del(&tmp->f_listopen);
+ kfree(tmp);
+ tmp = NULL;
+ }
+ curr_proc->fdtable[i] = f;
+ ++f->f_refcount;
+ release(&flist_lock);
+ return i;
+ }
+ }
+ release(&flist_lock);
+ return -EMFILE;
+}
+
+int
+dup2(int oldfd, int newfd)
+{
+ struct file_t *f, *tmp;
+
+ if (oldfd < 0 || oldfd >= NR_MAX_OPEN_FILES)
+ return -EINVAL;
+ acquire(&flist_lock);
+ f = curr_proc->fdtable[oldfd];
+ if (!f || f->f_state != FILE_ALLOC
+ || newfd < 0 || newfd >= NR_MAX_OPEN_FILES) {
+ release(&flist_lock);
+ return -EBADF;
+ }
+ if (oldfd == newfd) {
+ release(&flist_lock);
+ return newfd;
+ }
+ tmp = curr_proc->fdtable[newfd];
+ if (tmp && tmp->f_state == FILE_ALLOC)
+ if (!--tmp->f_refcount)
+ tmp->f_state = FILE_NONE;
+ if (tmp)
+ assert(!tmp->f_refcount);
+ if (!tmp || !tmp->f_refcount) {
+ curr_proc->fdtable[newfd] = f;
+ ++f->f_refcount;
+ release(&flist_lock);
+ return newfd;
+ }
+ release(&flist_lock);
+ return -EMFILE;
+}
+
+int
+open(const char *pathname,
+ __attribute__ ((unused)) int flags,
+ __attribute__ ((unused)) mode_t mode)
+{
+ struct ext2_dir_t *dirent;
+ int fd;
+
+ if (!pathname)
+ return -EINVAL;
+ dirent = resolve_path(pathname);
+ if (IS_ERR(dirent))
+ return PTR_ERR(dirent);
+ fd = filealloc(dirent->inode);
+ return fd;
+}
+
+int
+creat(__attribute__ ((unused)) const char *pathname,
+ __attribute__ ((unused)) mode_t mode)
+{
+ return -ENOSYS;
+}
+
+int
+close(int fd)
+{
+ return fileclose(fd);
+}
+
+DIR *
+opendir(const char *name)
+{
+ int fd;
+ DIR *newdir = NULL;
+
+ fd = sys_open(name, 0, 0);
+ if (fd < 0)
+ EXT2_SETERRNO_AND_RET(-fd, NULL);
+ if (!(curr_proc->fdtable[fd]->f_inode->file_mode & DIRECTORY_T)) {
+ errno = ENOTDIR;
+ goto err;
+ }
+ newdir = kmalloc(sizeof(*newdir));
+ if (IS_ERR(newdir)) {
+ errno = -PTR_ERR(newdir);
+ goto err;
+ }
+ newdir->off = 0;
+ newdir->fd = fd;
+ return newdir;
+err:
+ sys_close(fd);
+ EXT2_SETERRNO_AND_RET(errno, NULL);
+}
+
+struct dirent_t *
+readdir(DIR *dirp) {
+ struct file_t *file;
+ static struct dirent_t dirent;
+ struct ext2_dir_t *dir;
+ struct ext2_inode_t *inode;
+ char *buffer;
+ blksize_t blksize;
+ int ret;
+
+ if (!dirp)
+ return ERR_PTR(-EINVAL);
+ file = curr_proc->fdtable[dirp->fd];
+ if (!file || !(file->f_inode->file_mode & DIRECTORY_T))
+ return ERR_PTR(-EINVAL);
+ inode = geti(file->f_inode_nr);
+ blksize = get_block_size();
+ buffer = kmalloc(blksize);
+ if (IS_ERR(buffer))
+ return (void *)buffer;
+ /* TODO: make it possible to have directory entries spanning many blocks */
+ ret = read_inode_blocks(inode, 0, buffer, blksize);
+ if (ret <= 0) {
+ kfree(buffer);
+ return ERR_PTR(ret);
+ }
+ dir = (struct ext2_dir_t *)(buffer + dirp->off);
+ if (dirp->off >= blksize) {
+ kfree(buffer);
+ return NULL;
+ }
+ dirp->off += dir->rec_length;
+ dirent.d_inode = dir->inode;
+ dirent.d_off = (uint32_t)((char *)dir - buffer);
+ dirent.d_namelen = dir->name_length;
+ memset(dirent.d_name, 0, EXT2_NAME_LEN + 1);
+ memcpy(dirent.d_name, dir->filename, dir->name_length);
+ kfree(buffer);
+ return &dirent;
+}
+
+int
+closedir(DIR *dirp)
+{
+ int ret;
+
+ if (!dirp)
+ return -EINVAL;
+ if ((ret = sys_close(dirp->fd)) < 0)
+ return ret;
+ kfree(dirp);
+ return 0;
+}
+
+ssize_t
+read(int fd, void *buf, size_t count)
+{
+ struct file_t *f;
+ int ret;
+ char *newbuf;
+ size_t newcnt;
+ blksize_t blksize;
+ off_t soff;
+ ssize_t r;
+
+
+ if (fd < 0 || fd >= NR_MAX_OPEN_FILES || !buf)
+ return -EINVAL;
+
+ if (fd == STDIN_FILENO)
+ return tty_read(buf, count);
+
+ acquire(&flist_lock);
+ f = curr_proc->fdtable[fd];
+ if (!f || f->f_state != FILE_ALLOC) {
+ release(&flist_lock);
+ return -EBADF;
+ }
+ if (f->f_type == FILE_PIPE) {
+ r = piperead(fd, buf, count);
+ release(&flist_lock);
+ return r;
+ }
+ assert(f->f_inode);
+ if (f->f_inode->file_mode & DIRECTORY_T) {
+ release(&flist_lock);
+ return -EISDIR;
+ }
+ blksize = get_block_size();
+ if (f->f_inode->size_low32 - f->f_off < count)
+ count = f->f_inode->size_low32 - f->f_off;
+ if (!count) goto out;
+ newcnt = count;
+ if (newcnt % blksize) newcnt = (newcnt + blksize) & ~(blksize - 1);
+ newbuf = kmalloc(newcnt);
+ if (IS_ERR(newbuf)) {
+ release(&flist_lock);
+ return PTR_ERR(newbuf);
+ }
+ soff = (f->f_off % blksize) ? (f->f_off & ~((off_t)blksize - 1)) : (off_t)f->f_off;
+ soff /= blksize;
+ if ((ret = read_inode_blocks(f->f_inode, soff, newbuf, newcnt)) <= 0) {
+ kfree(newbuf);
+ release(&flist_lock);
+ return ret;
+ }
+ soff = f->f_off % newcnt;
+ if (newcnt - soff < count) count = newcnt - soff;
+ memcpy(buf, newbuf + soff, count);
+ f->f_off += count;
+ kfree(newbuf);
+out:
+ release(&flist_lock);
+ return count;
+}
+
+ssize_t
+write(int fd, const void *buf, size_t count)
+{
+ const char *ptr;
+ size_t len = 0;
+ struct file_t *f;
+ ssize_t r;
+
+ if (fd < 0 || fd >= NR_MAX_OPEN_FILES || !buf)
+ return -EINVAL;
+
+ /* ignore STDIN, STDOUT and STDERR for now */
+ if (fd > 2) {
+ acquire(&flist_lock);
+ f = curr_proc->fdtable[fd];
+ if (!f || f->f_state != FILE_ALLOC) {
+ release(&flist_lock);
+ return -EBADF;
+ }
+ if (f->f_type == FILE_PIPE) {
+ r = pipewrite(fd, buf, count);
+ release(&flist_lock);
+ return r;
+ }
+ release(&flist_lock);
+ }
+ ptr = buf;
+ while (count--) {
+ if (putchar(*ptr++) < 0)
+ break;
+ ++len;
+ }
+ return len;
+}
+
+int
+stat(const char *path, struct stat *buf)
+{
+ struct ext2_dir_t *dir;
+ struct ext2_inode_t *inode;
+
+ if (!path || !buf)
+ return -EINVAL;
+
+ dir = resolve_path(path);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+ inode = geti(dir->inode);
+ buf->st_dev = 0;
+ buf->st_ino = dir->inode;
+ buf->st_mode = inode->file_mode;
+ buf->st_nlink = inode->link_count;
+ buf->st_uid = inode->uid_low16 | (inode->uid_upper16 << 16);
+ buf->st_gid = inode->gid_low16 | (inode->gid_upper16 << 16);
+ buf->st_rdev = 0;
+ buf->st_size = inode->size_low32;
+ buf->st_blksize = get_block_size();
+ buf->st_blocks = (inode->size_low32 / buf->st_blksize) * (buf->st_blksize / 512);
+ buf->st_atime = inode->atime;
+ buf->st_mtime = inode->mtime;
+ buf->st_ctime = inode->ctime;
+ return 0;
+}
+
+int
+fstat(int fd, struct stat *buf)
+{
+ struct file_t *f;
+ struct ext2_inode_t *inode;
+
+ if (fd < 0 || fd >= NR_MAX_OPEN_FILES)
+ return -EBADF;
+ if (!buf)
+ return -EINVAL;
+ acquire(&flist_lock);
+ f = curr_proc->fdtable[fd];
+ if (!f || f->f_state != FILE_ALLOC) {
+ release(&flist_lock);
+ return -EBADF;
+ }
+ inode = geti(f->f_inode_nr);
+ buf->st_dev = 0;
+ buf->st_ino = f->f_inode_nr;
+ buf->st_mode = inode->file_mode;
+ buf->st_nlink = inode->link_count;
+ buf->st_uid = inode->uid_low16 | (inode->uid_upper16 << 16);
+ buf->st_gid = inode->gid_low16 | (inode->gid_upper16 << 16);
+ buf->st_rdev = 0;
+ buf->st_size = inode->size_low32;
+ buf->st_blksize = get_block_size();
+ buf->st_blocks = (inode->size_low32 / buf->st_blksize) * (buf->st_blksize / 512);
+ buf->st_atime = inode->atime;
+ buf->st_mtime = inode->mtime;
+ buf->st_ctime = inode->ctime;
+ release(&flist_lock);
+ return 0;
+}
+
+int
+execve(const char *filename,
+ __attribute__ ((unused)) char *const argv[],
+ __attribute__ ((unused)) char *const envp[])
+{
+ struct stat buf;
+ int fd, ret = 0, i;
+ char *elfimage;
+ ssize_t bytesleft;
+ ssize_t bytesread = 0;
+ Elf32_Ehdr *elfheader;
+ Elf32_Phdr *elfprog;
+ uint32_t sz;
+ struct mmap_region *reg;
+ struct list_head *iter, *tmpreg;
+ size_t len;
+ blksize_t blksize;
+
+ if ((fd = open(filename, O_RDONLY, 0)) < 0)
+ return fd;
+ if ((ret = fstat(fd, &buf)) < 0)
+ goto err;
+ if (IS_ERR(elfimage = kmalloc(buf.st_size))) {
+ ret = PTR_ERR(elfimage);
+ goto err;
+ }
+
+ bytesleft = buf.st_size;
+ blksize = get_block_size();
+ do {
+ ret = read(fd, elfimage + bytesread, bytesleft);
+ if (!ret) break;
+ if (ret < 0) goto err1;
+ bytesread += ret;
+ bytesleft -= ret;
+ } while (bytesleft > 0);
+ assert(!bytesleft && bytesread == buf.st_size);
+ elfheader = (Elf32_Ehdr *)elfimage;
+
+ if (elfheader->e_ident[EI_MAG0] != 0x7f
+ || elfheader->e_ident[EI_MAG1] != 'E'
+ || elfheader->e_ident[EI_MAG2] != 'L'
+ || elfheader->e_ident[EI_MAG3] != 'F'
+ || elfheader->e_type != ET_EXEC
+ || elfheader->e_machine != EM_386
+ || !elfheader->e_entry
+ || elfheader->e_version != EV_CURRENT
+ || elfheader->e_ident[EI_VERSION] != EV_CURRENT
+ || !elfheader->e_phnum
+ || elfheader->e_ident[EI_CLASS] != ELFCLASS32
+ || elfheader->e_ident[EI_DATA] != ELFDATA2LSB) {
+ ret = -ENOEXEC;
+ goto err1;
+ }
+
+ elfprog = (Elf32_Phdr *)(elfimage + elfheader->e_phoff);
+ for (i = 0; i < elfheader->e_phnum; ++i, ++elfprog) {
+ if (elfprog->p_type != 0x1) continue;
+ if (elfprog->p_vaddr + elfprog->p_memsz < elfprog->p_vaddr)
+ goto err1;
+ sz = elfprog->p_filesz;
+ reg = kmalloc(sizeof(*reg));
+ if (IS_ERR(reg)) {
+ ret = PTR_ERR(reg);
+ goto err1;
+ }
+ if ((ret = mmap_range(elfprog->p_vaddr, elfprog->p_vaddr + sz)) < 0) {
+ for (--elfprog; i > 0; --i) {
+ ret = unmap_range(elfprog->p_vaddr, elfprog->p_vaddr + sz);
+ if (ret < 0)
+ panic("can't unmap mapped pages!");
+ }
+ kfree(reg);
+ goto err2;
+ }
+ bzero((void *)elfprog->p_vaddr, 0);
+ memcpy((void *)elfprog->p_vaddr,
+ (const void *)(elfimage + elfprog->p_offset), sz);
+ reg->base_addr = elfprog->p_vaddr; reg->size = sz;
+ list_add_tail(®->l_region, &curr_proc->l_regions);
+ }
+
+ kfree(curr_proc->name);
+ len = strlen(filename) + 1;
+ assert(len);
+ curr_proc->name = kmalloc(len);
+ if (IS_ERR(curr_proc->name)) {
+ ret = PTR_ERR(curr_proc->name);
+ goto err2;
+ }
+ strncpy(curr_proc->name, filename, len);
+ curr_proc->name[len - 1] = '\0';
+ curr_proc->cf->eip = elfheader->e_entry;
+ goto err1;
+err2:
+ list_for_each_safe(iter, tmpreg, &curr_proc->l_regions) {
+ reg = list_entry(iter, struct mmap_region, l_region);
+ if (unmap_range(reg->base_addr, reg->base_addr + reg->size) < 0)
+ panic("failed to unmap pages!");
+ list_del(iter);
+ kfree(reg);
+ }
+err1:
+ kfree(elfimage);
+err:
+ close(fd);
+ return ret;
+}
+
diff --git a/src/core/gdt.c b/src/core/gdt.c
@@ -0,0 +1,28 @@
+/*
+ * core/gdt.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <gdt.h>
+#include <common.h>
+
+extern void gdt_flush(addr_t);
+
+static uint64_t gdt[] = {
+ 0x0000000000000000llu,
+ 0x00cf9a000000ffffllu,
+ 0x00cf92000000ffffllu,
+ 0x00cffa000000ffffllu,
+ 0x00cff2000000ffffllu
+};
+static struct gdt_selector_t gdt_sel;
+
+void
+initialize_gdt(void)
+{
+ gdt_sel.limit = (sizeof(struct gdt_selector_t) * len(gdt)) - 1;
+ gdt_sel.base = (addr_t)gdt;
+ gdt_flush((addr_t)&gdt_sel);
+}
+
diff --git a/src/core/heap.c b/src/core/heap.c
@@ -0,0 +1,155 @@
+/*
+ * core/heap.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <heap.h>
+#include <mm.h>
+#include <common.h>
+#include <x86.h>
+#include <errno.h>
+#include <list.h>
+#include <tty.h>
+
+/* for debugging purposes */
+#define DUMP_CHUNK(chunk) \
+ ({ \
+ printf("\tbase_addr = 0x%lx, end_addr = 0x%lx, size = 0x%x\n", \
+ chunk->base_addr, \
+ chunk->end_addr, chunk->size); \
+ serial_dump("\tbase_addr = 0x%lx, end_addr = 0x%lx, size = 0x%x\n", \
+ chunk->base_addr, \
+ chunk->end_addr, chunk->size); \
+ })
+
+struct chunk_t {
+ uint32_t base_addr;
+ uint32_t end_addr;
+ size_t size;
+ struct list_head list;
+};
+
+static int is_init = 0;
+static struct list_head freelist;
+static struct list_head allolist;
+
+void
+walk_heap_lists(void)
+{
+ uint32_t state;
+ struct list_head *iter;
+ struct chunk_t *tmp;
+
+ save_flags(&state);
+ cli();
+ printf("Summary of free chunks\n");
+ serial_dump("Summary of free chunks\n");
+ list_for_each(iter, &freelist) {
+ tmp = list_entry(iter, struct chunk_t, list);
+ DUMP_CHUNK(tmp);
+ }
+ printf("Summary of allocated chunks\n");
+ serial_dump("Summary of allocated chunks\n");
+ list_for_each(iter, &allolist) {
+ tmp = list_entry(iter, struct chunk_t, list);
+ DUMP_CHUNK(tmp);
+ }
+ load_flags(state);
+}
+
+void
+kfree(void *ptr)
+{
+ struct chunk_t *tmp;
+ struct list_head *iter, *q;
+ uint32_t state;
+
+ if (!ptr) return; /* free-ing NULL pointers is good */
+ if (!is_init)
+ panic("allocator is not initialized!");
+ save_flags(&state);
+ cli();
+ list_for_each_safe(iter, q, &allolist) {
+ tmp = list_entry(iter, struct chunk_t, list);
+ if (tmp->base_addr == (uint32_t)ptr) {
+ list_del(&tmp->list);
+ list_add_tail(&tmp->list, &freelist);
+ goto out;
+ }
+ }
+ panic("trying to free non-existent chunk at 0x%08lx!", ptr);
+out:
+ load_flags(state);
+}
+
+void *
+kmalloc_ext(size_t size, enum heap_cntl flag)
+{
+ struct list_head *iter, *q;
+ struct chunk_t *tmp, *new;
+ uint32_t addr, state;
+ int ret;
+
+ if (!is_init)
+ panic("allocator is not initialized!");
+
+ if (flag != DEFAULT)
+ return ERR_PTR(-ENOTSUP);
+
+ if (!size)
+ return ERR_PTR(-EINVAL);
+ save_flags(&state);
+ cli();
+ size += sizeof(struct chunk_t);
+ do {
+ list_for_each_safe(iter, q, &freelist) {
+ tmp = list_entry(iter, struct chunk_t, list);
+ if (size > tmp->size)
+ continue;
+ new = (struct chunk_t *)(tmp->end_addr - size);
+ new->base_addr = tmp->end_addr - size + sizeof(*tmp);
+ new->size = size - sizeof(*tmp);
+ new->end_addr = tmp->end_addr;
+ tmp->size -= size;
+ tmp->end_addr -= size;
+ list_add_tail(&new->list, &allolist);
+ load_flags(state);
+ return (void *)new->base_addr;
+ }
+ addr = (uint32_t)sbrk(size);
+ if (IS_ERR((void *)addr)) {
+ ret = PTR_ERR((void *)addr);
+ break;
+ }
+ tmp = (struct chunk_t *)addr;
+ tmp->base_addr = addr + sizeof(*tmp);
+ tmp->size = size;
+ tmp->size = roundup_pagesize(tmp->size);
+ tmp->size -= sizeof(*tmp);
+ tmp->end_addr = tmp->base_addr + tmp->size;
+ list_add_tail(&tmp->list, &freelist);
+ } while (1);
+ load_flags(state);
+ return ERR_PTR(ret);
+}
+
+void *
+kmalloc(size_t size)
+{
+ return kmalloc_ext(size, DEFAULT);
+}
+
+void
+init_heap(void)
+{
+ uint32_t state;
+
+ save_flags(&state);
+ cli();
+ INIT_LIST_HEAD(&freelist);
+ INIT_LIST_HEAD(&allolist);
+ is_init = 1;
+ load_flags(state);
+}
+
diff --git a/src/core/idt.c b/src/core/idt.c
@@ -0,0 +1,160 @@
+/*
+ * core/idt.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <idt.h>
+#include <common.h>
+#include <x86.h>
+#include <string.h>
+#include <syscall.h>
+#include <tss.h>
+#include <errno.h>
+#include <tty.h>
+#include <pic.h>
+
+#define INIT_IDT_INTR_GATE(index, offset, sel, gsize, pl, sp) \
+ ({ \
+ idt_intr_gates[index].offset_lo = (uint16_t)offset; \
+ idt_intr_gates[index].selector = sel; \
+ idt_intr_gates[index].all0 = 0; \
+ idt_intr_gates[index].gate_size = gsize; \
+ idt_intr_gates[index].privilege_level = pl; \
+ idt_intr_gates[index].segment_present = sp; \
+ idt_intr_gates[index].offset_hi = (uint16_t)(offset >> 16) & 0xffff; \
+ })
+
+extern void idt_flush(uint32_t);
+extern void syscall_handler(void);
+
+static const char *interrupt_names[] = {
+ "Division by zero exception",
+ "Debug exception",
+ "Non maskable interrupt",
+ "Breakpoint exception",
+ "Into detected overflow",
+ "Out of bounds exception",
+ "Invalid opcode exception",
+ "No coprocessor exception",
+ "Double fault",
+ "Coprocessor segment overrun",
+ "Bad TSS",
+ "Segment not present",
+ "Stack fault",
+ "General protection fault",
+ "Page fault",
+ "Unknown interrupt exception",
+ "Coprocessor fault",
+ "Alignment check exception",
+ "Machine check exception"
+};
+
+static isr_handler isr_handlers[256];
+static struct idt_intr_gate idt_intr_gates[256];
+static struct idt_selector idt_intr_sel;
+
+static void
+spurious_irq7(__attribute__ ((unused)) struct trapframe_t *regs)
+{
+}
+
+void
+initialize_idt(void)
+{
+ idt_intr_sel.limit = sizeof(struct idt_intr_gate) * 256 - 1;
+ idt_intr_sel.base = (uint32_t)idt_intr_gates;
+
+ memset(idt_intr_gates, 0, sizeof(struct idt_intr_gate) * 256);
+
+ INIT_IDT_INTR_GATE(0, (uint32_t)isr0, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(1, (uint32_t)isr1, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(2, (uint32_t)isr2, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(3, (uint32_t)isr3, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(4, (uint32_t)isr4, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(5, (uint32_t)isr5, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(6, (uint32_t)isr6, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(7, (uint32_t)isr7, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(8, (uint32_t)isr8, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(9, (uint32_t)isr9, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(10, (uint32_t)isr10, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(11, (uint32_t)isr11, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(12, (uint32_t)isr12, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(13, (uint32_t)isr13, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(14, (uint32_t)isr14, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(15, (uint32_t)isr15, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(16, (uint32_t)isr16, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(17, (uint32_t)isr17, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(18, (uint32_t)isr18, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(19, (uint32_t)isr19, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(20, (uint32_t)isr20, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(21, (uint32_t)isr21, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(22, (uint32_t)isr22, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(23, (uint32_t)isr23, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(24, (uint32_t)isr24, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(25, (uint32_t)isr25, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(26, (uint32_t)isr26, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(27, (uint32_t)isr27, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(28, (uint32_t)isr28, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(29, (uint32_t)isr29, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(30, (uint32_t)isr30, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(31, (uint32_t)isr31, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(32, (uint32_t)isr32, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(33, (uint32_t)isr33, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(34, (uint32_t)isr34, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(35, (uint32_t)isr35, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(36, (uint32_t)isr36, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(37, (uint32_t)isr37, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(38, (uint32_t)isr38, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(39, (uint32_t)isr39, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(40, (uint32_t)isr40, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(41, (uint32_t)isr41, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(42, (uint32_t)isr42, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(43, (uint32_t)isr43, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(44, (uint32_t)isr44, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(45, (uint32_t)isr45, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(46, (uint32_t)isr46, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(47, (uint32_t)isr47, 0x08, 0xe, 0x0, 0x1);
+ INIT_IDT_INTR_GATE(0x80, (uint32_t)isr128, 0x08, 0xe, 0x0, 0x1);
+
+ register_isr_handler(0x80, syscall_dispatcher);
+ register_isr_handler(39, spurious_irq7);
+ idt_flush((uint32_t)&idt_intr_sel);
+}
+
+int
+register_isr_handler(uint8_t index, isr_handler handler)
+{
+ if (!handler)
+ return -EINVAL;
+ isr_handlers[index] = handler;
+ return 0;
+}
+
+uint32_t
+handle_interrupt(struct trapframe_t regs)
+{
+ if (isr_handlers[regs.int_no]) {
+ if (curr_proc) {
+ curr_proc->esp = regs.unroll_esp;
+ if (regs.int_no == 0x80 && regs.eax != __NR_suspend_task)
+ curr_proc->old_esp = curr_proc->esp;
+ curr_proc->cf = (struct cswitch_frame_t *)((uint32_t *) & regs + 1);
+ }
+ isr_handler handler = isr_handlers[regs.int_no];
+ handler(®s);
+ } else {
+ clear_scr();
+ ccurr_col(BLACK, RED);
+ DEBUG_CODE(printf("Unhandled interrupt[%lu]: %s\n", regs.int_no,
+ (regs.int_no < (sizeof(interrupt_names) / sizeof(interrupt_names[0])))
+ ? interrupt_names[regs.int_no] : "Unknown");)
+ DUMP_STACK_REGS(regs);
+ panic("halted");
+ }
+ pic_eoi(regs.int_no);
+ if (!curr_proc)
+ return regs.unroll_esp;
+ return curr_proc->esp;
+}
+
diff --git a/src/core/kdb.c b/src/core/kdb.c
@@ -0,0 +1,542 @@
+/*
+ * core/kdb.c
+ *
+ * Copyright (C) 2010 stateless
+ */
+
+#include <common.h>
+#include <kdb.h>
+#include <tty.h>
+#include <heap.h>
+#include <string.h>
+#include <errno.h>
+#include <syscall.h>
+#include <x86.h>
+#include <pci.h>
+#include <tss.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <elf.h>
+#include <rtl8139.h>
+#include <pipe.h>
+#include <rtc.h>
+
+#define ENV_REPORT
+
+enum {
+ CMD_SIZE = 512
+};
+
+static void kdb_loop(void);
+
+static int kdb_cmd_help(int argc, char **argv);
+static int kdb_cmd_exit(int argc, char **argv);
+static int kdb_cmd_reboot(int argc, char **argv);
+static int kdb_cmd_lspci(int argc, char **argv);
+static int kdb_cmd_ps(int argc, char **argv);
+static int kdb_cmd_cpuid(int argc, char **argv);
+static int kdb_cmd_heapdump(int argc, char **argv);
+static int kdb_cmd_hexdump(int argc, char **argv);
+static int kdb_cmd_write(int argc, char **argv);
+static int kdb_cmd_symlookup(int argc, char **argv);
+static int kdb_cmd_dumpregs(int argc, char **argv);
+static int kdb_cmd_exec(int argc, char **argv);
+static int kdb_cmd_ls(int argc, char **argv);
+static int kdb_cmd_dumpframe(int argc, char **argv);
+static int kdb_cmd_macaddr(int argc, char **argv);
+static int kdb_cmd_test(int argc, char **argv);
+static int kdb_cmd_dumpmap(int argc, char **argv);
+
+static struct trapframe_t cframe;
+static char *cmd;
+
+static struct {
+ const char *name;
+ const char *desc;
+ int (*fnp)(int argc, char **argv);
+} kdb_cmds[] = {
+ { "help", "Show this help menu.", kdb_cmd_help },
+ { "exit", "Quit the debugger.", kdb_cmd_exit },
+ { "reboot", "Reboot the machine.", kdb_cmd_reboot },
+ { "lspci", "Perform a PCI enumeration.", kdb_cmd_lspci },
+ { "ps", "Dump the scheduler's runqueue.", kdb_cmd_ps },
+ { "cpuid", "Dump CPU info.", kdb_cmd_cpuid },
+ { "heapdump", "Dump the kernel's heap allocation/deallocation lists.", kdb_cmd_heapdump },
+ { "hexdump", "Do a hexdump of a specific memory range.", kdb_cmd_hexdump },
+ { "write", "Write a specific value in a range of addresses.", kdb_cmd_write },
+ { "symlookup", "Match an address to a symbol name.", kdb_cmd_symlookup },
+ { "dumpregs", "Dump the system's registers.", kdb_cmd_dumpregs },
+ { "exec", "Execute an ELF file.", kdb_cmd_exec },
+ { "ls", "List directory contents.", kdb_cmd_ls },
+ { "dumpframe", "Dump the last saved trapframe.", kdb_cmd_dumpframe },
+ { "mac-addr", "Dump the mac-address.", kdb_cmd_macaddr },
+ { "dumpmap", "Dump memory mappings.", kdb_cmd_dumpmap },
+ { "test", "Testing routine.", kdb_cmd_test }
+};
+
+void
+set_trapframe(struct trapframe_t *tframe)
+{
+ cframe = *tframe;
+}
+
+void
+kdb_enter(void)
+{
+ cmd = kmalloc(CMD_SIZE);
+ if (IS_ERR(cmd))
+ return;
+ memset(cmd, 0, CMD_SIZE);
+ ccurr_col(BLACK, WHITE);
+ clear_scr();
+ printf("type help for a list of commands.\n");
+ kdb_loop();
+}
+
+static char **
+parse_cmd(int *argc)
+{
+ int f, i;
+ char *p, **argv, *tmp, *arg;
+ *argc = 0;
+
+ for (f = 1, p = cmd; *p; ++p) {
+ if (!f && *p == ' ') {
+ ++*argc;
+ f = 1;
+ continue;
+ }
+ if (f && *p != ' ')
+ f = 0;
+ }
+ if (!f)
+ ++*argc;
+ argv = kmalloc((*argc + 1) * sizeof(char *));
+ if (IS_ERR(argv))
+ panic("oom");
+ for (p = cmd; *p; ++p, tmp = p)
+ ; /* nothing */
+ for (p = cmd; *p; ++p)
+ if (*p == ' ')
+ *p = '\0';
+ for (i = 0, f = 1, p = cmd; p < tmp; ++p) {
+ if (!f && *p == '\0') {
+ f = 1;
+ argv[i++] = arg;
+ continue;
+ }
+ if (f && *p) {
+ f = 0;
+ arg = p;
+ }
+ }
+ if (!f)
+ argv[i] = arg;
+ argv[*argc] = NULL;
+ return argv;
+}
+
+static char *
+prepare_cmd(void)
+{
+ char *p;
+
+ p = &cmd[CMD_SIZE - 1];
+ while (p != cmd) {
+ if (*p == '\n') {
+ *p-- = '\0';
+ continue;
+ }
+ --p;
+ }
+ while (*p != ' ') ++p;
+ *p = '\0';
+ return p;
+}
+
+static void
+trimstr(char *s)
+{
+ char *ptr = s;
+
+ while (*ptr == ' ') ++ptr;
+ memmove(s, ptr, strlen(s) - (ptr - s));
+ memset(s + strlen(s) - (ptr - s), 0, ptr - s);
+ ptr = s + strlen(s) - 1;
+ while (*ptr == ' ') --ptr;
+ if (*ptr) {
+ ++ptr;
+ *ptr = '\0';
+ }
+}
+
+static void
+kdb_loop(void)
+{
+ size_t i;
+ char *p;
+ ssize_t r;
+ int argc, ret;
+ char **argv;
+
+ do {
+again:
+ update_cursor(cursor_y, 2);
+ printf("> ");
+ r = sys_read(0, cmd, CMD_SIZE - 1);
+ cmd[r] = '\0';
+ p = cmd;
+ trimstr(p);
+ for (; *p; ++p)
+ if (!isspace(*p))
+ break;
+ if (*p == '\0')
+ goto again;
+ p = prepare_cmd();
+ for (i = 0; i <
+ sizeof(kdb_cmds) / sizeof(kdb_cmds[0]); ++i) {
+ if (!strcmp(cmd, kdb_cmds[i].name)) {
+ *p = ' ';
+ argv = parse_cmd(&argc);
+ if (!kdb_cmds[i].fnp)
+ panic("%s: is not initialized properly!",
+ kdb_cmds[i].name);
+ ret = kdb_cmds[i].fnp(argc, argv);
+#ifdef ENV_REPORT
+ if (ret < 0) {
+ printf("FAIL: %d", ret);
+ if (ret <= -1 && ret >= -44)
+ printf(":%s", sys_errlist[-ret - 1]);
+ putchar('\n');
+ }
+#endif
+ kfree(argv);
+ goto again;
+ }
+ }
+ p = cmd;
+ while (isspace(*p)) ++p;
+ printf("%s: command not found\n", p);
+ } while (1);
+}
+
+static int
+kdb_cmd_help(int argc, char **argv)
+{
+ size_t i;
+
+ if (argc != 1) {
+ printf("usage: %s\n", argv[0]);
+ return -EINVAL;
+ }
+
+ printf("Command list\n");
+ for (i = 0; i < sizeof(kdb_cmds) / sizeof(kdb_cmds[0]); ++i)
+ printf(" %s -- %s\n", kdb_cmds[i].name, kdb_cmds[i].desc);
+ return 0;
+}
+
+static int
+kdb_cmd_exit(int argc, char **argv)
+{
+ if (argc != 1) {
+ printf("usage: %s\n", argv[0]);
+ return -EINVAL;
+ }
+ sys_exit(0);
+ return 0;
+}
+
+static int
+kdb_cmd_reboot(int argc, char **argv)
+{
+ if (argc != 1) {
+ printf("usage: %s\n", argv[0]);
+ return -EINVAL;
+ }
+ outb(0x64, 0xfe);
+ cli();
+ hlt();
+ return 0;
+}
+
+static int
+kdb_cmd_lspci(int argc, char **argv)
+{
+ if (argc != 1) {
+ printf("usage: %s\n", argv[0]);
+ return -EINVAL;
+ }
+ lspci();
+ return 0;
+}
+
+static int
+kdb_cmd_ps(int argc, char **argv)
+{
+ if (argc != 1) {
+ printf("usage: %s\n", argv[0]);
+ return -EINVAL;
+ }
+ ps();
+ return 0;
+}
+
+static int
+kdb_cmd_cpuid(int argc, char **argv)
+{
+ if (argc != 1) {
+ printf("usage: %s\n", argv[0]);
+ return -EINVAL;
+ }
+ do_cpuid();
+ return 0;
+}
+
+static int
+kdb_cmd_heapdump(int argc, char **argv)
+{
+ if (argc != 1) {
+ printf("usage: %s\n", argv[0]);
+ return -EINVAL;
+ }
+ walk_heap_lists();
+ return 0;
+}
+
+static int
+kdb_cmd_hexdump(int argc, char **argv)
+{
+ uint32_t addr, len;
+
+ if (argc != 3) {
+ printf("usage: %s memory-address len\n", argv[0]);
+ printf("NOTE: all arguments are specified in hex\n");
+ return -EINVAL;
+ }
+ addr = strtoul(argv[1], NULL, 16);
+ len = strtoul(argv[2], NULL, 16);
+ hexdump((const void *)addr, len);
+ return 0;
+}
+
+static int
+kdb_cmd_write(int argc, char **argv)
+{
+ uint32_t val, low, high, *p;
+
+ if (argc != 4) {
+ printf("usage: %s value low-addr high-addr\n", argv[0]);
+ printf("NOTE: the range is [low-addr, high-addr), all arguments are specified in hex\n");
+ return -EINVAL;
+ }
+ val = strtoul(argv[1], NULL, 16);
+ low = strtoul(argv[2], NULL, 16);
+ high = strtoul(argv[3], NULL, 16);
+ if (high <= low) {
+ printf("high-addr can't be lower or equal to low-addr\n");
+ return -EINVAL;
+ }
+ p = (uint32_t *)low;
+ while (p < (uint32_t *)high)
+ *p++ = val;
+ return 0;
+}
+
+static int
+kdb_cmd_symlookup(int argc, char **argv)
+{
+ uint32_t addr;
+ const char *sym;
+
+ if (argc != 2) {
+ printf("usage: %s symbol-address\n", argv[0]);
+ printf("NOTE: the address must be specified in hex\n");
+ return -EINVAL;
+ }
+ addr = strtoul(argv[1], NULL, 16);
+ sym = find_symbol(addr);
+ printf("%s => %s\n", argv[1], (!sym) ? "unknown" : sym);
+ return 0;
+}
+
+/* TODO: add more regs */
+static int
+kdb_cmd_dumpregs(int argc, char **argv)
+{
+ uint32_t eax, ebx, ecx, edx, esp, ebp;
+ uint32_t edi, esi;
+
+ if (argc != 1) {
+ printf("usage: %s\n", argv[0]);
+ return -EINVAL;
+ }
+
+ asm volatile ("movl %%eax, %0" : "=r"(eax));
+ asm volatile ("movl %%ebx, %0" : "=r"(ebx));
+ asm volatile ("movl %%ecx, %0" : "=r"(ecx));
+ asm volatile ("movl %%edx, %0" : "=r"(edx));
+ asm volatile ("movl %%esp, %0" : "=r"(esp));
+ asm volatile ("movl %%ebp, %0" : "=r"(ebp));
+ asm volatile ("movl %%esi, %0" : "=r"(esi));
+ asm volatile ("movl %%edi, %0" : "=r"(edi));
+
+ printf("eax = 0x%08lx\nebx = 0x%08lx\necx = 0x%08lx\n",
+ eax, ebx, ecx);
+ printf("edx = 0x%08lx\nesp = 0x%08lx\nebp = 0x%08lx\n",
+ edx, esp, ebp);
+ printf("esi = 0x%08lx\nedi = 0x%08lx\n",
+ esi, edi);
+ return 0;
+}
+
+static int
+kdb_cmd_exec(int argc, char **argv)
+{
+ pid_t pid;
+ int ret, status;
+
+ if (argc != 2) {
+ printf("usage: %s filename\n", argv[0]);
+ return -EINVAL;
+ }
+
+ pid = sys_fork();
+ if (pid < 0)
+ return pid;
+ if (!pid) {
+ ret = sys_execve(argv[1], NULL, NULL);
+ sys_exit(ret);
+ } else {
+ while (1) {
+ if ((ret = sys_waitpid(-1, &status, WNOHANG)) < 0)
+ break;
+ }
+ }
+ printf("child exited with error code %d\n", status);
+ return 0;
+}
+
+static int
+kdb_cmd_ls(int argc, char **argv)
+{
+ char buf[256];
+ DIR *dirp;
+ struct dirent_t *dirent;
+ struct stat stbuf;
+ int ret;
+
+ if (argc != 1) {
+ printf("usage: %s\n", argv[0]);
+ return -EINVAL;
+ }
+
+ dirp = opendir("/");
+ if (!dirp)
+ return -errno;
+ dirent = sys_readdir(dirp);
+ printf("%-12s%-12s%-12s%-12s\n", "FILENAME", "TYPE", "UID", "GID");
+ while (dirent) {
+ if (!strcmp(dirent->d_name, ".")
+ || !strcmp(dirent->d_name, ".."))
+ goto out;
+ bzero(buf, 256);
+ buf[0] = '/';
+ strncpy(buf + 1, dirent->d_name, 255);
+ buf[255] = '\0';
+ if (!stat(buf, &stbuf)) {
+ printf("%-12s%-12s%-12d%-12d\n",
+ dirent->d_name,
+ S_ISREG(stbuf.st_mode) ? "FILE" : "DIR",
+ stbuf.st_uid,
+ stbuf.st_gid);
+ }
+out:
+ dirent = readdir(dirp);
+ }
+ ret = closedir(dirp);
+ if (ret < 0)
+ return -errno;
+ return 0;
+}
+
+static int
+kdb_cmd_dumpframe(int argc, char **argv)
+{
+ if (argc != 1) {
+ printf("usage: %s\n", argv[0]);
+ return -EINVAL;
+ }
+ DUMP_STACK_REGS(cframe);
+ return 0;
+}
+
+static int
+kdb_cmd_macaddr(int argc, char **argv)
+{
+ const uint8_t *mac_addr;
+
+ if (argc != 1) {
+ printf("usage: %s\n", argv[0]);
+ return -EINVAL;
+ }
+ mac_addr = get_mac_addr();
+ if (!mac_addr) {
+ info("no mac-addr?\n");
+ return -ENODEV;
+ }
+ printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac_addr[0],
+ mac_addr[1],
+ mac_addr[2],
+ mac_addr[3],
+ mac_addr[4],
+ mac_addr[5]
+ );
+ return 0;
+}
+
+static int
+kdb_cmd_dumpmap(int argc, char **argv)
+{
+ if (argc != 1) {
+ printf("usage: %s\n", argv[0]);
+ return -EINVAL;
+ }
+ dump_mappings();
+ return 0;
+}
+
+static int
+kdb_cmd_test(int argc, char **argv)
+{
+ ssize_t r;
+ int pipefd[2];
+ char buf[32];
+ pid_t pid;
+
+ if (argc != 1) {
+ printf("usage: %s\n", argv[0]);
+ return -EINVAL;
+ }
+
+ bzero(buf, sizeof buf);
+ if (sys_pipe(pipefd) < 0)
+ panic("sys_pipe failed");
+ pid = sys_fork();
+ if (!pid) {
+ assert(!sys_close(pipefd[1]));
+ sleep(1);
+ r = sys_read(pipefd[0], buf, 13);
+ if (r < 0)
+ kerror(-r);
+ if (r)
+ printf("%s", buf);
+ sys_exit(0);
+ }
+ assert(!sys_close(pipefd[0]));
+ assert(sys_write(pipefd[1], "hello", 5) == 5);
+ assert(sys_write(pipefd[1], ", world\n", 8) == 8);
+ return 0;
+}
+
diff --git a/src/core/keyboard.c b/src/core/keyboard.c
@@ -0,0 +1,187 @@
+/*
+ * core/keyboard.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <keyboard.h>
+#include <x86.h>
+#include <idt.h>
+#include <common.h>
+#include <kdb.h>
+#include <tty.h>
+
+enum { KBD_BUF_SIZE = 4096 };
+enum { CMD_PORT = 0x64, DATA_PORT = 0x60 /* to/from the kbd */, STATUS_PORT = 0x64 };
+
+/* special keys */
+enum {
+ LALT, RALT,
+ LCTRL, RCTRL,
+ LSHIFT, RSHIFT,
+ F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
+ CAPSLK, NUMLK, SCRLK, SYSRQ,
+ ESC = 27,
+ INSERT, DEL, HOME, END, PGUP, PGDN, LEFT, RIGHT, UP, DOWN,
+ NUM_DOT, NUM_ENTER, NUM_PLUS, NUM_MINUS, NUM_MUL, NUM_DIV,
+ NUM_0, NUM_1, NUM_2, NUM_3, NUM_4, NUM_5, NUM_6, NUM_7, NUM_8, NUM_9,
+ BACKSP = 127
+};
+
+int f_kdb = 0;
+
+static uint8_t kbd_buffer[KBD_BUF_SIZE]; /* plain ascii 0 - 127 */
+static uint32_t head = 0, tail = 0;
+static bool shift_st = 0;
+
+static int keycodes_lower[] = {
+ 0, ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', BACKSP, /* 0 - e */
+ '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\r', /* f - 1c */
+ LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', /* 1d - 29 */
+ LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', RSHIFT, /* 2a - 36 */
+ NUM_MUL, LALT, ' ', CAPSLK, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, /* 37 - 44 */
+ NUMLK, SCRLK, NUM_7, NUM_8, NUM_9, NUM_MINUS, NUM_4, NUM_5, NUM_6, NUM_PLUS, /* 45 - 4e */
+ NUM_1, NUM_2, NUM_3, NUM_0, NUM_DOT, SYSRQ, 0, 0, F11, F12, /* 4d - 58 */
+ 0, 0, 0, 0, 0, 0, 0, /* 59 - 5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 70 - 7f */
+};
+
+static int keycodes_upper[] = {
+ 0, ESC, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', BACKSP, /* 0 - e */
+ '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\r', /* f - 1c */
+ LCTRL, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', /* 1d - 29 */
+ LSHIFT, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', RSHIFT, /* 2a - 36 */
+ NUM_MUL, LALT, ' ', CAPSLK, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, /* 37 - 44 */
+ NUMLK, SCRLK, NUM_7, NUM_8, NUM_9, NUM_MINUS, NUM_4, NUM_5, NUM_6, NUM_PLUS, /* 45 - 4e */
+ NUM_1, NUM_2, NUM_3, NUM_0, NUM_DOT, SYSRQ, 0, 0, F11, F12, /* 4d - 58 */
+ 0, 0, 0, 0, 0, 0, 0, /* 59 - 5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 70 - 7f */
+};
+
+static inline void
+wait_cmd_buffer(void)
+{
+ while (inb(STATUS_PORT) & 0x2)
+ ;
+}
+
+static inline void
+wait_result_buffer(void)
+{
+ while (!(inb(STATUS_PORT) & 0x1))
+ ;
+}
+
+static inline void
+send_kbd_cmd(uint8_t byte)
+{
+ wait_cmd_buffer();
+ outb(CMD_PORT, byte);
+ wait_cmd_buffer();
+}
+
+static inline uint8_t
+recv_kbd_res(void)
+{
+ uint8_t byte;
+ wait_result_buffer();
+ byte = inb(DATA_PORT);
+ return byte;
+}
+
+void
+keyboard_callback(__attribute__ ((unused)) struct trapframe_t *regs)
+{
+ wait_result_buffer();
+ uint8_t scancode = inb(DATA_PORT);
+
+ if (!(scancode & 0x80)) {
+ if (tail != KBD_BUF_SIZE) {
+ if (scancode == 0x2a)
+ shift_st = 1;
+ if (scancode == 0x58) {
+ if (!f_kdb) {
+ f_kdb = 1;
+ set_trapframe(regs);
+ assert(!IS_ERR(create_kthread("kdb", kdb_enter)));
+ freeze_tasks();
+ }
+ return;
+ }
+ if (!is_tty_attached()) return;
+ kbd_buffer[tail++] = (shift_st) ? keycodes_upper[scancode]
+ : keycodes_lower[scancode];
+ if (scancode == 0x1c) kbd_buffer[tail - 1] = '\n';
+ resume_task(tty_get_sleep_chan());
+ }
+ } else if (scancode == 0xaa)
+ shift_st = 0;
+}
+
+int
+kbd_getchar(void)
+{
+ int ch;
+ uint32_t state;
+
+ save_flags(&state);
+ cli();
+ if (head == tail) {
+ if (tail == KBD_BUF_SIZE)
+ head = tail = 0;
+ load_flags(state);
+ return -1;
+ }
+ ch = kbd_buffer[head];
+ ++head;
+ load_flags(state);
+ return ch;
+}
+
+void
+initialize_keyboard(void)
+{
+ uint8_t byte;
+
+ /* disable keyboard */
+ send_kbd_cmd(0xad);
+
+ /* perform a self-test */
+ send_kbd_cmd(0xaa);
+ if (recv_kbd_res() != 0x55)
+ panic("keyboard self-test failed!");
+
+ /* read the CCB */
+ send_kbd_cmd(0x20);
+ byte = recv_kbd_res();
+
+ /* if keyboard translation is not enabled, try to enable it */
+ if (!(byte & (1 << 6))) {
+ info("translation is not enabled, attempting to enable it ...\n");
+ byte |= (1 << 6);
+ send_kbd_cmd(0x60);
+ outb(DATA_PORT, byte);
+ wait_cmd_buffer();
+ send_kbd_cmd(0x20);
+ if (!(recv_kbd_res() & (1 << 6))) {
+ printf("failed!\n");
+ hlt();
+ }
+ printf("OK!\n");
+ }
+
+ /* check if we are in polling mode and if so enable interrupts on IRQ1 */
+ if (!(byte & 0x1)) {
+ byte |= 0x1;
+ send_kbd_cmd(0x60);
+ outb(DATA_PORT, byte);
+ wait_cmd_buffer();
+ }
+
+ /* enable keyboard */
+ send_kbd_cmd(0xae);
+ register_isr_handler(33, keyboard_callback);
+}
+
diff --git a/src/core/main.c b/src/core/main.c
@@ -0,0 +1,168 @@
+/*
+ * core/main.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <tty.h>
+#include <rtc.h>
+#include <keyboard.h>
+#include <common.h>
+#include <x86.h>
+#include <idt.h>
+#include <gdt.h>
+#include <pic.h>
+#include <string.h>
+#include <multiboot.h>
+#include <elf.h>
+#include <mm.h>
+#include <heap.h>
+#include <tss.h>
+#include <syscall.h>
+#include <errno.h>
+#include <ext2.h>
+#include <serial.h>
+#include <pci.h>
+#include <rtl8139.h>
+#include <version.h>
+
+extern struct fs_node_t *vfs_root;
+extern struct task_t *current_task;
+extern unsigned long int initial_esp;
+extern unsigned long int addr_info;
+extern uint8_t multiboot_header[0];
+extern uint8_t __code[0];
+extern uint8_t __data[0];
+extern uint8_t __bss[0];
+extern uint8_t __end[0];
+
+multiboot_info_t *info_boot = NULL;
+multiboot_header_t *mb_header = NULL;
+uint32_t initrd_base;
+uint32_t initrd_end;
+
+static void syscall(void);
+static void move_kernel_stack(uint32_t new_stack_addr);
+
+int
+main(void)
+{
+ int ret;
+
+ serial_init();
+
+ ccurr_col(BLACK, WHITE);
+ clear_scr();
+
+ info_boot = (multiboot_info_t *) addr_info;
+ mb_header = (multiboot_header_t *)multiboot_header;
+ if (mb_header->magic != MULTIBOOT_HEADER_MAGIC)
+ panic("invalid multiboot header number");
+ if (!(info_boot->flags & (1 << 3)))
+ panic("modules can't be located!");
+ if (!info_boot->mods_count)
+ panic("can't locate initrd, modules count is 0!");
+
+ initrd_base = *(uint32_t *)info_boot->mods_addr;
+ initrd_end = *(uint32_t *)(info_boot->mods_addr + 4);
+
+ if (prepare_elf() < 0)
+ info("could not locate either the symbol table or the string table!\n");
+
+ initialize_gdt();
+ remap_pic();
+ initialize_idt();
+ init_rtc(100);
+ initialize_keyboard();
+ sti();
+
+ if ((ret = init_mm()) < 0)
+ kerror(-ret);
+ if ((ret = init_vm()) < 0)
+ kerror(-ret);
+
+ move_kernel_stack(0xe0000000);
+
+ if (!pci_init()) {
+ pci_enumerate();
+ if (rtl8139_init() < 0)
+ info("failed to initialize the rtl8139\n");
+ } else {
+ info("pci failed to init\n");
+ }
+
+ ext2_mount((char *)initrd_base);
+
+ if (strlen(REVISION) > 0)
+ printf("Revision: %s\n", REVISION);
+ printf("Built on %s by %s on host %s\n\n", DATE, USER, HOST);
+ printf("Press F12 to drop into the kernel debugger.");
+ update_cursor(cursor_y, cursor_x);
+ if ((ret = init_tss()) < 0)
+ kerror(-ret);
+ kick_tss();
+ panic("WTF?");
+ return 0xdeadc0de;
+}
+
+static void
+move_kernel_stack(uint32_t new_stack_addr)
+{
+ uint32_t curr_esp, i, *ptr, offset;
+
+ GET_ESP(curr_esp);
+ offset = (initial_esp - curr_esp);
+ memcpy((void *)(new_stack_addr - offset), (const void *)curr_esp, offset);
+ ptr = (uint32_t *)new_stack_addr;
+ for (i = 0; i < offset; i += 4) {
+ --ptr;
+ if (*ptr < initial_esp && *ptr > curr_esp)
+ *ptr = *ptr + (new_stack_addr - initial_esp);
+ }
+ initial_esp = new_stack_addr;
+ new_stack_addr -= offset;
+ PUT_ESP(new_stack_addr);
+}
+
+uint32_t
+get_fnv_hash(const char *buf, size_t count, uint32_t hash)
+{
+ static uint32_t fnv_offset_basis = 2166136261;
+ static uint32_t fnv_prime = 16777619;
+
+ hash = (!hash) ? fnv_offset_basis : hash;
+ while (count--) {
+ hash ^= *buf++;
+ hash *= fnv_prime;
+ }
+
+ return hash;
+}
+
+__attribute__ ((unused)) static void
+syscall(void)
+{
+ char buf[256];
+ uint32_t hash = 0;
+ int fd, oldfd;
+ ssize_t ret;
+
+ oldfd = sys_open("/a.out", O_RDONLY, 0);
+ if (oldfd < 0)
+ kerror(-oldfd);
+ if ((fd = sys_dup(oldfd)) < 0)
+ kerror(-fd);
+ sys_close(oldfd);
+ do {
+ ret = sys_read(fd, buf, 255);
+ if (ret < 0) kerror(-ret);
+ if (!ret) break;
+ buf[ret] = '\0';
+ hash = get_fnv_hash(buf, ret, hash);
+ ret = sys_write(fd, buf, ret);
+ if (ret < 0) kerror(-ret);
+ } while (1);
+ serial_dump("hash = 0x%08lx\n", hash);
+ sys_close(fd);
+}
+
diff --git a/src/core/mm.c b/src/core/mm.c
@@ -0,0 +1,885 @@
+/*
+ * core/mm.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <mm.h>
+#include <multiboot.h>
+#include <common.h>
+#include <string.h>
+#include <idt.h>
+#include <x86.h>
+#include <heap.h>
+#include <errno.h>
+#include <tss.h>
+#include <serial.h>
+
+#define SET_PTE(pte, p, rw_mode, priv, frame_addr) \
+ ({ \
+ pte.present = p; \
+ pte.rw = rw_mode; \
+ pte.privilege = priv; \
+ pte.frame = frame_addr; \
+ })
+
+#define SET_PDE(pde, p, rw_mode, priv, pt) \
+ ({ \
+ pde.present = p; \
+ pde.rw = rw_mode; \
+ pde.privilege = priv; \
+ pde.pt_addr = pt; \
+ })
+
+#define PTABLE_BASE_ADDR 0xffc00000
+#define PDIR_BASE_ADDR 0xfffff000
+
+enum page_fl { P_FL = 1 << 0, RW_FL = 1 << 1, US_FL = 1 << 2 };
+
+extern multiboot_info_t *info_boot;
+extern uint32_t initrd_end;
+
+struct page_directory_t *new_kernel_pdir = NULL;
+
+static uint32_t mm_phys_addr = 0, mm_phys_addr_end = 0;
+static uint8_t *framemap = NULL, *pagemap_pa = NULL;
+static struct page_directory_t *kernel_page_dir = NULL;
+static struct page_table_t *kernel_page_table = NULL;
+static uint32_t curr_kernel_heap_addr = KERNEL_HEAP, total_frames = 0;
+
+static inline uint32_t
+get_frame_block(uint32_t frame)
+{
+ return frame / 8;
+}
+
+static inline uint32_t
+get_frame_offset(uint32_t frame)
+{
+ return frame % 8;
+}
+
+static inline bool
+is_frame_free(uint32_t frame)
+{
+ return !(framemap[get_frame_block(frame)] & (1 << get_frame_offset(frame)));
+}
+
+static inline uint32_t
+get_page_block(uint32_t page)
+{
+ return page / 8;
+}
+
+static inline uint32_t
+get_page_offset(uint32_t page)
+{
+ return page % 8;
+}
+
+static inline bool
+is_page_free(uint32_t page)
+{
+ return !(pagemap_pa[get_page_block(page)] & (1 << get_page_offset(page)));
+}
+
+static inline void
+enable_paging(void)
+{
+ uint32_t cr0;
+
+ asm volatile ("movl %%cr0, %0": "=r"(cr0));
+ cr0 |= 0x80000000;
+ asm volatile ("movl %0, %%cr0":: "r"(cr0));
+}
+
+static inline void
+disable_paging(void)
+{
+ uint32_t cr0;
+
+ asm volatile ("movl %%cr0, %0": "=r"(cr0));
+ cr0 &= 0x7fffffff;
+ asm volatile ("movl %0, %%cr0":: "r"(cr0));
+}
+
+static inline uint32_t
+get_fault_addr(void)
+{
+ uint32_t cr2;
+
+ asm volatile ("movl %%cr2, %0" : "=r"(cr2));
+ return cr2;
+}
+
+static uint32_t
+get_free_frame(void)
+{
+ void *page;
+
+ page = palloc(PAGE_SIZE);
+ if (IS_ERR(page)) {
+ errno = -PTR_ERR(page);
+ return 0;
+ }
+ return (uint32_t)page;
+}
+
+static inline uint32_t
+get_pte_index(uint32_t virt_addr)
+{
+ return (virt_addr & 0x3ff000) >> 12;
+}
+
+static inline uint32_t
+get_pde_index(uint32_t virt_addr)
+{
+ return (virt_addr & PTABLE_BASE_ADDR) >> 22;
+}
+
+static inline struct page_directory_t *
+curr_pdir(void) {
+ return (struct page_directory_t *)PDIR_BASE_ADDR;
+}
+
+static inline struct page_table_t *
+get_ptable(uint32_t index) {
+ return (struct page_table_t *)(PTABLE_BASE_ADDR + index);
+}
+
+void
+switch_page_dir(struct page_directory_t *pagedir)
+{
+ uint32_t phys;
+ bool val = false;
+
+ if (!pagedir)
+ panic("invalid pagedir!");
+ phys = virt_to_phys((uint32_t)pagedir, &val);
+ if (!val)
+ panic("virt_to_phys failed!");
+ if (phys % PAGE_SIZE)
+ panic("address of pagedir [0x%08lx] is not page aligned!",
+ (void *)pagedir);
+ asm volatile ("movl %0, %%cr3":: "r"(phys));
+ flush_tlb();
+}
+
+void
+pagefault_callback(struct trapframe_t *regs)
+{
+ uint32_t errcode = regs->err_code, addr, page;
+ int ret = -ENOMEM;
+
+ addr = get_fault_addr();
+ serial_dump("mm: faulting address is [0x%08lx]", addr);
+ if (curr_proc) serial_dump(", task-id is [%lu]", curr_proc->pid);
+ switch (errcode & 0x7) {
+ case P_FL:
+ panic("supervisory process tried to read a page and caused a protection fault");
+ break;
+ case RW_FL:
+ page = get_free_frame();
+ if (!page) kerror(errno);
+ if ((ret = mmap(addr, page)) < 0)
+ kerror(-ret);
+ serial_dump(", found free frame at [0x%08lx]\n", page);
+ break;
+ case RW_FL | P_FL:
+ panic("supervisory process tried to write a page and caused a protection fault");
+ break;
+ case US_FL:
+ panic("user process tried to read a non-present page entry");
+ break;
+ case US_FL | P_FL:
+ panic("user process tried to read a page and caused a protection fault");
+ break;
+ case US_FL | RW_FL:
+ panic("user process tried to write to a non-present page entry");
+ break;
+ case US_FL | RW_FL | P_FL:
+ panic("user process tried to write a page and caused a protection fault");
+ break;
+ default:
+ panic("supervisory process tried to read a non-present page entry");
+ break;
+ }
+}
+
+/* retrieve the memory map from GRUB and initialize the physical memory allocator */
+int
+init_mm(void)
+{
+ int mm_phys_addr_valid = 0, ret = -EFAULT;
+ unsigned long base_addr, i, framemap_size; /* in frames */
+ memory_map_t *memmap;
+ uint32_t state;
+
+ save_flags(&state);
+ cli();
+ if (!info_boot) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (!(info_boot->flags & (1 << 6))) {
+ ret = -ENOTSUP;
+ goto err;
+ }
+
+ mm_phys_addr = (initrd_end + PAGE_SIZE) & ~(PAGE_SIZE - 1);
+ base_addr = info_boot->mmap_addr;
+ do {
+ memmap = (memory_map_t *)base_addr;
+ if (memmap->type == 1) {
+ if (memmap->base_addr_low >= 0x100000) {
+ if (!mm_phys_addr_valid && mm_phys_addr < memmap->base_addr_low
+ + memmap->length_low) {
+ mm_phys_addr_valid = 1;
+ total_frames = (memmap->base_addr_low + memmap->length_low
+ - mm_phys_addr) >> PAGE_SHIFT;
+ framemap_size = (total_frames >> 3);
+ framemap_size = roundup_pagesize(framemap_size);
+ framemap_size >>= PAGE_SHIFT;
+ total_frames -= framemap_size;
+ if ((total_frames >> 3) > memmap->length_low) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ break;
+ }
+ }
+ }
+ base_addr += memmap->size + sizeof(uint32_t);
+ } while (base_addr < info_boot->mmap_addr + info_boot->mmap_length);
+
+ if (!mm_phys_addr_valid) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ framemap = (uint8_t *)mm_phys_addr;
+ for (i = 0; i < total_frames >> 3; ++i)
+ framemap[i] = 0;
+
+ /* first bit in bitmap refers to this frame */
+ mm_phys_addr = ((uint32_t)framemap + (total_frames >> 3) + PAGE_SIZE)
+ & ~(PAGE_SIZE - 1);
+ serial_dump("mm: # of available frames = %lu, total free mem = %luK\n",
+ total_frames,
+ (total_frames * PAGE_SIZE) >> 10);
+ /* nullify all available memory, just in case */
+ for (i = 0; i < (total_frames - 1) >> 3; ++i)
+ memset((void *)(mm_phys_addr + (i << PAGE_SHIFT)), 0, PAGE_SIZE);
+ load_flags(state);
+ return 0;
+err:
+ load_flags(state);
+ return ret;
+}
+
+/* initialize the virtual memory manager */
+int
+init_vm(void)
+{
+ int ret = -ENOMEM;
+ uint32_t i, state, addr, virt_addr;
+ struct page_directory_t *tmp;
+ struct page_table_t *ptable;
+
+ save_flags(&state);
+ cli();
+ kernel_page_dir = palloc(sizeof(*kernel_page_dir));
+ if (IS_ERR(kernel_page_dir)) {
+ ret = PTR_ERR(kernel_page_dir);
+ goto error;
+ }
+ memset(kernel_page_dir, 0, sizeof(*kernel_page_dir));
+
+ kernel_page_table = palloc(sizeof(*kernel_page_table));
+ if (IS_ERR(kernel_page_table)) {
+ ret = PTR_ERR(kernel_page_table);
+ goto error;
+ }
+ memset(kernel_page_table, 0, sizeof(*kernel_page_table));
+
+ addr = ((uint32_t)kernel_page_table > (uint32_t)kernel_page_dir) ?
+ (uint32_t)kernel_page_table : (uint32_t)kernel_page_dir;
+ mm_phys_addr_end = roundup_pagesize(addr + PAGE_SIZE);
+
+ for (i = 0; i < 1024; ++i) {
+ SET_PTE(kernel_page_table->pages[i],
+ (i < (mm_phys_addr_end >> PAGE_SHIFT)) ? 1 : 0, 1, 0, i);
+ }
+
+ SET_PDE(kernel_page_dir->ptables[0], 1, 1, 0,
+ (uint32_t)kernel_page_table >> PAGE_SHIFT);
+ SET_PDE(kernel_page_dir->ptables[1023], 1, 1, 0,
+ (uint32_t)kernel_page_dir->ptables >> PAGE_SHIFT);
+ register_isr_handler(14, pagefault_callback);
+ asm volatile ("movl %0, %%cr3":: "r"(kernel_page_dir->ptables));
+ enable_paging();
+
+ /* preallocate the page tables for the kernel heap */
+ tmp = curr_pdir();
+ for (i = 0; i < (KERNEL_HEAP_END - KERNEL_HEAP) >> PAGE_SHIFT; ++i) {
+ virt_addr = get_pde_index(KERNEL_HEAP + (i << PAGE_SHIFT));
+ ptable = get_ptable(virt_addr << PAGE_SHIFT);
+ if (!tmp->ptables[virt_addr].present) {
+ addr = (uint32_t)palloc(sizeof(struct page_table_t));
+ if (IS_ERR((void *)addr)) {
+ ret = PTR_ERR((void *)addr);
+ goto error;
+ }
+ SET_PDE(tmp->ptables[virt_addr], 1, 1, 0, addr >> PAGE_SHIFT);
+ memset(ptable, 0, sizeof(*ptable));
+ }
+ }
+
+ init_heap();
+ if ((ret = init_page_pa_allocator()) < 0)
+ goto error;
+ new_kernel_pdir = clone_page_dir();
+ if (IS_ERR(new_kernel_pdir)) {
+ ret = PTR_ERR(new_kernel_pdir);
+ goto error;
+ }
+ switch_page_dir(new_kernel_pdir);
+ load_flags(state);
+ return 0;
+error:
+ load_flags(state);
+ return ret;
+}
+
+void *
+sbrk(intptr_t incr)
+{
+ uint32_t page_num;
+ uint32_t kernel_heap_addr_old = curr_kernel_heap_addr, state;
+ int ret = -ENOMEM;
+
+ if (incr < 0)
+ panic("%ld negative offset given!", incr);
+
+ incr = roundup_pagesize(incr);
+ page_num = incr / PAGE_SIZE;
+ save_flags(&state);
+ cli();
+ if ((curr_kernel_heap_addr + incr >= KERNEL_HEAP_END)
+ || (ret = mmap_range(curr_kernel_heap_addr,
+ curr_kernel_heap_addr + incr)) < 0)
+ goto err;
+ curr_kernel_heap_addr += incr;
+ load_flags(state);
+ return (void *)kernel_heap_addr_old;
+err:
+ load_flags(state);
+ return ERR_PTR(ret);
+}
+
+static struct page_directory_t *
+create_pdir(uint32_t *addr_phys) {
+ struct page_directory_t *new_pdir;
+
+ if (addr_phys) {
+ new_pdir = alloc_page_pa(addr_phys, ALLOC_PHYS);
+ if (IS_ERR(new_pdir))
+ return new_pdir;
+ memset(new_pdir, 0, PAGE_SIZE);
+ SET_PDE(new_pdir->ptables[1023], 1, 1, 0, *addr_phys >> PAGE_SHIFT);
+ return new_pdir;
+ }
+ return ERR_PTR(-EINVAL);
+}
+
+static int
+destroy_pdir(struct page_directory_t *pdir, uint32_t *phys, enum page_pa_fl flags)
+{
+ if (!pdir || !phys)
+ return -EINVAL;
+ free_page_pa(pdir, phys, flags);
+ return 0;
+}
+
+static int
+clone_page_table(struct page_table_t *ptable, uint32_t *phys)
+{
+ uint32_t src_frame_addr_phys, dst_frame_addr_phys, frame, i;
+ uint32_t state;
+ void *src_frame_addr_virt, *dst_frame_addr_virt;
+ struct page_table_t *new_ptable;
+ int ret;
+
+ if (!ptable || !phys)
+ return -EINVAL;
+
+ save_flags(&state);
+ cli();
+ new_ptable = alloc_page_pa(phys, ALLOC_PHYS);
+ if (IS_ERR(new_ptable)) {
+ ret = PTR_ERR(new_ptable);
+ goto out;
+ }
+ memset(new_ptable, 0, PAGE_SIZE);
+ for (i = 0; i < 1024; ++i) {
+ if (!ptable->pages[i].present)
+ continue;
+ frame = (uint32_t)palloc(PAGE_SIZE);
+ if (!IS_ERR((void *)frame)) {
+ *(uint32_t *)&new_ptable->pages[i] = *(uint32_t *) & ptable->pages[i];
+ new_ptable->pages[i].frame = frame >> PAGE_SHIFT;
+ src_frame_addr_phys = ptable->pages[i].frame << PAGE_SHIFT;
+ dst_frame_addr_phys = new_ptable->pages[i].frame << PAGE_SHIFT;
+ src_frame_addr_virt = alloc_page_pa(&src_frame_addr_phys, DONT_ALLOC_PHYS);
+ if (!IS_ERR(src_frame_addr_virt)) {
+ dst_frame_addr_virt = alloc_page_pa(&dst_frame_addr_phys, DONT_ALLOC_PHYS);
+ if (!IS_ERR(dst_frame_addr_virt)) {
+ memcpy(dst_frame_addr_virt, src_frame_addr_virt, PAGE_SIZE);
+ free_page_pa(
+ src_frame_addr_virt,
+ &src_frame_addr_phys,
+ DONT_FREE_PHYS
+ );
+ free_page_pa(
+ dst_frame_addr_virt,
+ &dst_frame_addr_phys,
+ DONT_FREE_PHYS
+ );
+ } else { ret = PTR_ERR(dst_frame_addr_virt); goto out3; }
+ } else { ret = PTR_ERR( src_frame_addr_virt); goto out2; }
+ } else { ret = PTR_ERR((void *)frame); goto out1; }
+ }
+ free_page_pa(new_ptable, phys, DONT_FREE_PHYS);
+ load_flags(state);
+ return 0;
+out3:
+ free_page_pa(src_frame_addr_virt, &src_frame_addr_phys, FREE_PHYS);
+out2:
+ pfree((void *)frame, PAGE_SIZE);
+out1:
+ free_page_pa(new_ptable, phys, FREE_PHYS);
+out:
+ load_flags(state);
+ return ret;
+}
+
+struct page_directory_t *
+clone_page_dir(void) {
+ uint32_t new_pdir_addr_phys, state, i;
+ uint32_t new_ptable_addr_phys;
+ struct page_directory_t *new_pdir, *pdir;
+ int ret;
+
+ save_flags(&state);
+ cli();
+ new_pdir = create_pdir(&new_pdir_addr_phys);
+ if (IS_ERR(new_pdir)) {
+ ret = PTR_ERR(new_pdir);
+ goto out;
+ }
+ pdir = curr_pdir();
+ for (i = 0; i < 1023; ++i) { /* exclude recursive mapping */
+ if (!pdir->ptables[i].present) continue;
+ if (*(uint32_t *)&kernel_page_dir->ptables[i]
+ == *(uint32_t *)&pdir->ptables[i]) {
+ *(uint32_t *)&new_pdir->ptables[i] = *(uint32_t *) & pdir->ptables[i];
+ continue;
+ }
+ if ((ret = clone_page_table(get_ptable(i << PAGE_SHIFT),
+ &new_ptable_addr_phys)) < 0)
+ goto out1;
+ SET_PDE(new_pdir->ptables[i], 1, 1, 0,
+ new_ptable_addr_phys >> PAGE_SHIFT);
+ }
+ load_flags(state);
+ return new_pdir;
+out1:
+ destroy_pdir(new_pdir, &new_pdir_addr_phys, FREE_PHYS);
+out:
+ load_flags(state);
+ return ERR_PTR(ret);
+}
+
+void
+flush_tlb(void)
+{
+ uint32_t val, state;
+
+ save_flags(&state);
+ cli();
+ asm volatile ("movl %%cr3, %0" : "=r" (val));
+ asm volatile ("movl %0, %%cr3" :: "r" (val));
+ load_flags(state);
+}
+
+uint32_t
+virt_to_phys(uint32_t virt_addr, bool *val)
+{
+ struct page_directory_t *curr_page_dir;
+ struct page_table_t *ptable;
+ uint32_t state, ret;
+
+ if (!val)
+ panic("arg 'val' appears to be NULL!");
+
+ save_flags(&state);
+ cli();
+ *val = true;
+ curr_page_dir = curr_pdir();
+ ptable = get_ptable(get_pde_index(virt_addr) << PAGE_SHIFT);
+ if (!curr_page_dir->ptables[get_pde_index(virt_addr)].present)
+ *val = false;
+ if (!ptable->pages[get_pte_index(virt_addr)].present)
+ *val = false;
+ ret = (ptable->pages[get_pte_index(virt_addr)].frame << PAGE_SHIFT)
+ + (virt_addr & 0xfff);
+ load_flags(state);
+ return ret;
+}
+
+int
+mmap(uint32_t virt_addr, uint32_t phys_addr)
+{
+ struct page_directory_t *curr_page_dir;
+ struct page_table_t *ptable;
+ uint32_t pt_addr, state;
+ int ret = -ENOMEM;
+
+ save_flags(&state);
+ cli();
+ curr_page_dir = curr_pdir();
+ ptable = get_ptable(get_pde_index(virt_addr) << PAGE_SHIFT);
+ if (!curr_page_dir->ptables[get_pde_index(virt_addr)].present) {
+ pt_addr = get_free_frame();
+ if (!pt_addr) goto err;
+ SET_PDE(curr_page_dir->ptables[get_pde_index(virt_addr)],
+ 1,
+ 1,
+ 0,
+ pt_addr >> PAGE_SHIFT);
+ }
+ if (ptable->pages[get_pte_index(virt_addr)].present)
+ panic("duplicate mapping: 0x%08lx -> 0x%08lx", virt_addr, phys_addr);
+ SET_PTE(ptable->pages[get_pte_index(virt_addr)],
+ 1,
+ 1,
+ 0,
+ phys_addr >> PAGE_SHIFT);
+ flush_tlb();
+ load_flags(state);
+ return 0;
+err:
+ load_flags(state);
+ return ret;
+}
+
+int
+unmap(uint32_t virt_addr)
+{
+ int ret = -EFAULT;
+ struct page_directory_t *curr_page_dir;
+ struct page_table_t *ptable;
+ uint32_t state;
+ uint32_t i;
+
+ save_flags(&state);
+ cli();
+ curr_page_dir = curr_pdir();
+ if (!curr_page_dir->ptables[get_pde_index(virt_addr)].present)
+ goto err;
+ ptable = get_ptable(get_pde_index(virt_addr) << PAGE_SHIFT);
+ if (!ptable->pages[get_pte_index(virt_addr)].present)
+ goto err;
+ ptable->pages[get_pte_index(virt_addr)].present = 0;
+ for (i = 0; i < 1024 && !ptable->pages[i].present; ++i)
+ ;
+ if (i == 1024) {
+ curr_page_dir->ptables[get_pde_index(virt_addr)].present = 0;
+ pfree((void *)(curr_page_dir->ptables[get_pde_index(virt_addr)].pt_addr
+ << PAGE_SHIFT),
+ PAGE_SIZE);
+ }
+ flush_tlb();
+ load_flags(state);
+ return 0;
+err:
+ load_flags(state);
+ return ret;
+}
+
+int
+mmap_range(uint32_t virt_addr_start, uint32_t virt_addr_end)
+{
+ uint32_t state, free_page;
+ uint32_t s;
+ int ret;
+
+ save_flags(&state);
+ cli();
+ s = virt_addr_start;
+ virt_addr_start &= ~(PAGE_SIZE - 1);
+ virt_addr_end = roundup_pagesize(virt_addr_end);
+ for (; virt_addr_start < virt_addr_end; virt_addr_start += PAGE_SIZE) {
+ free_page = get_free_frame();
+ if (free_page) {
+ if ((ret = mmap(virt_addr_start, free_page)) < 0) {
+ load_flags(state);
+ return ret;
+ }
+ continue;
+ }
+ if (s < virt_addr_start) {
+ ret = unmap_range(s, virt_addr_start);
+ if (ret < 0)
+ panic("can't unmap range!");
+ }
+ load_flags(state);
+ return -ENOMEM;
+ }
+ load_flags(state);
+ return 0;
+}
+
+int
+unmap_range(uint32_t virt_addr_start, uint32_t virt_addr_end)
+{
+ uint32_t state;
+ int ret;
+
+ save_flags(&state);
+ cli();
+ virt_addr_start &= ~(PAGE_SIZE - 1);
+ virt_addr_end = roundup_pagesize(virt_addr_end);
+ for (; virt_addr_start < virt_addr_end; virt_addr_start += PAGE_SIZE) {
+ if ((ret = unmap(virt_addr_start)) < 0) {
+ load_flags(state);
+ return ret;
+ }
+ }
+ load_flags(state);
+ return 0;
+}
+
+void
+dump_mappings(void)
+{
+ uint32_t i, j, nr = 0, state;
+ uint32_t addr, paddr;
+ struct page_directory_t *pdir;
+ struct page_table_t *ptable;
+ bool valid_map;
+
+ save_flags(&state);
+ cli();
+ serial_dump("Mmap dump for [%s:%d]\n", curr_proc->name, curr_proc->pid);
+ printf("Mmap dump for [%s:%d]\n", curr_proc->name, curr_proc->pid);
+ pdir = curr_pdir();
+ for (i = 1; i < 1023; ++i) {
+ if (!pdir->ptables[i].present)
+ continue;
+ ptable = get_ptable(i << PAGE_SHIFT);
+ for (j = 0; j < 1024; ++j) {
+ if (!ptable->pages[j].present)
+ continue;
+ addr = (i << 22) | (j << 12);
+ paddr = virt_to_phys(addr, &valid_map);
+ if (!valid_map)
+ continue;
+ serial_dump("[%lu] 0x%08lx -> 0x%08lx\n", nr++, addr, paddr);
+ printf("[%lu] 0x%08lx -> 0x%08lx\n", nr++, addr, paddr);
+ }
+ }
+ load_flags(state);
+}
+
+void
+remove_proc_mappings(void)
+{
+ uint32_t state, i, j;
+ uint32_t addr, paddr, tmp;
+ struct page_directory_t *pdir;
+ struct page_table_t *ptable;
+ bool valid_map;
+ struct list_head *iter, *tmpreg;
+ struct mmap_region *reg;
+
+ save_flags(&state);
+ cli();
+ list_for_each_safe(iter, tmpreg, &curr_proc->l_regions) {
+ reg = list_entry(iter, struct mmap_region, l_region);
+ if (unmap_range(reg->base_addr, reg->base_addr + reg->size) < 0)
+ panic("failed to unmap pages!");
+ list_del(iter);
+ kfree(reg);
+ }
+ pdir = curr_pdir();
+ for (i = 2; i < 1023; ++i) {
+ if (pdir->ptables[i].present) {
+ if (*(uint32_t *)&curr_proc->parent->page_dir->ptables[i]
+ != *(uint32_t *)&pdir->ptables[i]) {
+ ptable = get_ptable(i << PAGE_SHIFT);
+ for (j = 0; j < 1024; ++j)
+ if (ptable->pages[j].present)
+ pfree((void *)(ptable->pages[j].frame << PAGE_SHIFT),
+ PAGE_SIZE);
+ paddr = pdir->ptables[i].pt_addr << PAGE_SHIFT;
+ pfree((void *)paddr, PAGE_SIZE);
+ }
+ }
+ }
+ paddr = read_cr3();
+ for (i = 0; i < PAGE_HEAP_SIZE >> PAGE_SHIFT; i++) {
+ if (!is_page_free(i)) {
+ addr = PAGE_HEAP + (i << PAGE_SHIFT);
+ tmp = virt_to_phys(addr, &valid_map);
+ if (valid_map && paddr == tmp) {
+ free_page_pa((void *)addr, &paddr, FREE_PHYS);
+ break;
+ }
+ }
+ }
+ load_flags(state);
+}
+
+/* a bitmap based physical memory allocator */
+uint32_t
+get_num_free_frames(void)
+{
+ uint32_t i, nfree = 0;
+
+ for (i = 0; i < total_frames; ++i)
+ if (is_frame_free(i))
+ ++nfree;
+ return nfree;
+}
+
+void *
+palloc(size_t size)
+{
+ uint32_t i, j, frames_alloc, state;
+
+ assert(framemap);
+ if (!size)
+ return ERR_PTR(-EINVAL);
+
+ size = roundup_pagesize(size);
+ frames_alloc = size >> PAGE_SHIFT;
+ if (frames_alloc > total_frames - 1)
+ return ERR_PTR(-ENOMEM);
+
+ save_flags(&state);
+ cli();
+ for (i = 0; i < total_frames; ++i) {
+ if (is_frame_free(i)) {
+ for (j = 0; j < frames_alloc; ++j)
+ if (!is_frame_free(i + j))
+ break;
+ if (j == frames_alloc) {
+ for (j = 0; j < frames_alloc; ++j)
+ framemap[get_frame_block(i + j)] |=
+ (1 << get_frame_offset(i + j));
+ load_flags(state);
+ return (void *)(mm_phys_addr + (i << PAGE_SHIFT));
+ }
+ }
+ }
+ load_flags(state);
+ return ERR_PTR(-ENOMEM);
+}
+
+void
+pfree(void *addr, size_t size)
+{
+ uint32_t framestofree, base_addr, i, state;
+
+ if (!addr || !size)
+ return;
+
+ size = roundup_pagesize(size);
+ framestofree = size >> PAGE_SHIFT;
+ base_addr = (uint32_t)addr;
+ base_addr -= mm_phys_addr;
+ base_addr >>= PAGE_SHIFT;
+
+ save_flags(&state);
+ cli();
+ for (i = 0; i < framestofree; ++i)
+ framemap[get_frame_block(base_addr + i)] &=
+ ~(1 << get_frame_offset(base_addr + i));
+ load_flags(state);
+}
+
+int
+init_page_pa_allocator(void)
+{
+ size_t len = PAGE_HEAP_SIZE >> PAGE_SHIFT;
+
+ pagemap_pa = kmalloc(len);
+ if (IS_ERR(pagemap_pa))
+ return PTR_ERR(pagemap_pa);
+ memset(pagemap_pa, 0, len);
+ return 0;
+}
+
+void *
+alloc_page_pa(uint32_t *frame, enum page_pa_fl flags)
+{
+ uint32_t i, addr, state;
+ int ret;
+
+ if (!frame)
+ return ERR_PTR(-EINVAL);
+
+ save_flags(&state);
+ cli();
+ for (i = 0; i < PAGE_HEAP_SIZE >> PAGE_SHIFT; ++i) {
+ if (is_page_free(i)) {
+ addr = (flags == ALLOC_PHYS) ? get_free_frame() : *frame;
+ if (addr) {
+ if ((ret = mmap(PAGE_HEAP
+ + (i << PAGE_SHIFT), addr)) < 0) {
+ load_flags(state);
+ return ERR_PTR(ret);
+ }
+ pagemap_pa[get_page_block(i)] |= (1 << get_page_offset(i));
+ *frame = addr;
+ if (flags == ALLOC_PHYS)
+ memset((void *)(PAGE_HEAP + (i << PAGE_SHIFT)), 0,
+ PAGE_SIZE);
+ load_flags(state);
+ return (void *)(PAGE_HEAP + (i << PAGE_SHIFT));
+ }
+ break;
+ }
+ }
+ load_flags(state);
+ return ERR_PTR((flags == ALLOC_PHYS) ? -ENOMEM : -EINVAL);
+}
+
+int
+free_page_pa(void *page, uint32_t *frame, enum page_pa_fl flags)
+{
+ uint32_t base_addr, state;
+ int ret;
+
+ if (!page || !frame)
+ return -EINVAL;
+
+ save_flags(&state);
+ cli();
+ base_addr = (uint32_t)page;
+ if ((ret = unmap(base_addr)) < 0) {
+ load_flags(state);
+ return ret;
+ }
+ base_addr -= PAGE_HEAP;
+ base_addr >>= PAGE_SHIFT;
+ pagemap_pa[get_page_block(base_addr)] &=
+ ~(1 << get_page_offset(base_addr));
+ if (flags == FREE_PHYS)
+ pfree((void *)*frame, PAGE_SIZE);
+ load_flags(state);
+ return 0;
+}
+
diff --git a/src/core/pci.c b/src/core/pci.c
@@ -0,0 +1,267 @@
+/*
+ * core/pci.c
+ *
+ * Copyright (C) 2010 stateless
+ */
+
+#include <pci.h>
+#include <x86.h>
+#include <string.h>
+#include <heap.h>
+#include <errno.h>
+#include <serial.h>
+
+static int has_pci_init = 0;
+static struct list_head rootbus;
+static spinlock_t pci_lock;
+
+uint32_t
+pci_read32(struct pci_config_addr_t *addr)
+{
+ uint32_t r;
+
+ acquire(&pci_lock);
+ if (addr->reg_num & 0x3)
+ panic("offset is not 0-padded!");
+ outl(CONFIG_ADDRESS, *(uint32_t *)addr);
+ r = inl(CONFIG_DATA);
+ release(&pci_lock);
+ return r;
+}
+
+uint32_t
+pci_init(void)
+{
+ uint32_t ret, tmp;
+
+ initspinlock(&pci_lock);
+ outl(CONFIG_ADDRESS, 0);
+ outl(0xcfa, 0);
+ if (inl(CONFIG_ADDRESS) == 0 && inl(0xcfa) == 0) {
+ info("PCI type-2 is not supported!\n");
+ return 1;
+ }
+ tmp = inl(CONFIG_ADDRESS);
+ outl(CONFIG_ADDRESS, 0x80000000);
+ ret = inl(CONFIG_ADDRESS);
+ outl(CONFIG_ADDRESS, tmp);
+ if (ret == 0x80000000)
+ has_pci_init = 1;
+ return ret != 0x80000000;
+}
+
+static void
+dump_dev(struct pci_dev_t *dev)
+{
+ struct pci_config_addr_t addr;
+ union pci_config_space_t *cspace;
+ uint32_t reg = 0x10, r;
+
+ printf("Bus = %d, Device = %d\n", dev->busn, dev->devn);
+ cspace = dev->cspace;
+ if (cspace->type0.header_type == 0x1)
+ printf("\tPCI-to-PCI bridge\n");
+ printf("\tvendor_id = 0x%04lx, device_id = 0x%04lx\n",
+ cspace->type0.vendor_id, cspace->type0.device_id);
+ printf("\tstatus = 0x%04lx, command = 0x%04lx\n",
+ cspace->type0.status, cspace->type0.command);
+ printf("\tclass = 0x%02lx, subclass = 0x%02lx\n",
+ cspace->type0.class, cspace->type0.subclass);
+ printf("\tIRQ = %u\n", cspace->type0.irq);
+
+ serial_dump("Bus = %d, Device = %d\n", dev->busn, dev->devn);
+ cspace = dev->cspace;
+ if (cspace->type0.header_type == 0x1)
+ serial_dump("\tPCI-to-PCI bridge\n");
+ serial_dump("\tvendor_id = 0x%04lx, device_id = 0x%04lx\n",
+ cspace->type0.vendor_id, cspace->type0.device_id);
+ serial_dump("\tstatus = 0x%04lx, command = 0x%04lx\n",
+ cspace->type0.status, cspace->type0.command);
+ serial_dump("\tclass = 0x%02lx, subclass = 0x%02lx\n",
+ cspace->type0.class, cspace->type0.subclass);
+ serial_dump("\tIRQ = %u\n", cspace->type0.irq);
+
+ addr.enable_bit = 1;
+ addr.bus_num = dev->busn;
+ addr.dev_num = dev->devn;
+ if (cspace->type0.header_type) {
+ if (cspace->type0.header_type & 0x80)
+ printf("\tmultiple functions are available\n");
+ addr.reg_num = 0x18;
+ r = pci_read32(&addr);
+ printf("\tprimary bus = %u, secondary bus = %u\n",
+ r & 0xff, (r >> 8) & 0xff);
+ }
+ for (; reg <= (cspace->type0.header_type == 0x1 ? 0x14 : 0x24);
+ reg += 4) {
+ addr.reg_num = reg;
+ r = pci_read32(&addr);
+ if (r != 0 && r != 0xffffffff)
+ printf("\tbar%d = 0x%08lx\n",
+ (reg - 0x10) / 4, r);
+ }
+}
+
+void
+lspci(void)
+{
+ struct list_head *iter_bus, *iter_dev;
+ struct pci_dev_t *dev;
+ struct pci_bus_t *bus;
+
+ if (!has_pci_init) {
+ info("there is no PCI bus!\n");
+ return;
+ }
+
+ list_for_each(iter_bus, &rootbus) {
+ bus = list_entry(iter_bus, struct pci_bus_t, pci_bus_list);
+ list_for_each(iter_dev, &bus->pci_dev_list) {
+ dev = list_entry(iter_dev, struct pci_dev_t, list);
+ dump_dev(dev);
+ }
+ }
+}
+
+static int
+load_config_space(struct pci_dev_t *dev, struct pci_config_addr_t addr)
+{
+ uint32_t r, reg, *p;
+ union pci_config_space_t *cspace;
+
+ cspace = kmalloc(sizeof(*cspace));
+ if (IS_ERR(cspace))
+ return PTR_ERR(cspace);
+ memset(cspace, 0, sizeof(cspace));
+ p = (uint32_t *)cspace;
+ addr.enable_bit = 1;
+ for (reg = 0; reg <= 0x3c; reg += 4) {
+ addr.reg_num = reg;
+ r = pci_read32(&addr);
+ if (r != 0)
+ *p = r;
+ ++p;
+ }
+ dev->cspace = cspace;
+ return 0;
+}
+
+static void
+cleanup(void)
+{
+ struct list_head *iter_bus, *iter_dev, *tmp1, *tmp2;
+ struct pci_dev_t *dev;
+ struct pci_bus_t *bus;
+
+ list_for_each_safe(iter_bus, tmp1, &rootbus) {
+ bus = list_entry(iter_bus, struct pci_bus_t, pci_bus_list);
+ list_for_each_safe(iter_dev, tmp2, &bus->pci_dev_list) {
+ dev = list_entry(iter_dev, struct pci_dev_t, list);
+ list_del(iter_dev);
+ kfree(dev->cspace);
+ kfree(dev);
+ }
+ list_del(iter_bus);
+ kfree(bus);
+ }
+}
+
+static struct pci_bus_t *
+create_bus(void) {
+ struct pci_bus_t *bus;
+
+ bus = kmalloc(sizeof(*bus));
+ if (IS_ERR(bus)) {
+ cleanup();
+ return bus;
+ }
+ INIT_LIST_HEAD(&bus->pci_dev_list);
+ return bus;
+}
+
+static int
+attach_dev(struct pci_bus_t *bus, struct pci_config_addr_t addr,
+ int busn, int devn)
+{
+ int ret;
+ struct pci_dev_t *dev;
+
+ dev = kmalloc(sizeof(*dev));
+ if (IS_ERR(dev)) {
+ cleanup();
+ return PTR_ERR(dev);
+ }
+ memset(dev, 0, sizeof(*dev));
+ dev->cspace = NULL;
+ dev->bus = bus;
+ dev->busn = busn;
+ dev->devn = devn;
+ ret = load_config_space(dev, addr);
+ if (ret < 0) {
+ assert(IS_ERR(dev->cspace));
+ kfree(dev);
+ cleanup();
+ return -1;
+ }
+ list_add_tail(&dev->list, &bus->pci_dev_list);
+ return 0;
+}
+
+int
+pci_enumerate(void)
+{
+ struct pci_bus_t *busp;
+ struct pci_config_addr_t addr;
+ int dev, bus, ret, f;
+ uint32_t r;
+
+ INIT_LIST_HEAD(&rootbus);
+ memset(&addr, 0, sizeof(addr));
+ addr.enable_bit = 1;
+ for (bus = 0; bus < 256; ++bus) {
+ addr.bus_num = bus;
+ for (dev = 0, f = 0; dev < 32; ++dev) {
+ addr.dev_num = dev;
+ if ((r = pci_read32(&addr)) == PCI_NO_DEV)
+ continue;
+ if (!f) {
+ busp = create_bus();
+ if (IS_ERR(busp))
+ return PTR_ERR(busp);
+ list_add(&busp->pci_bus_list, &rootbus);
+ f = 1;
+ }
+ ret = attach_dev(busp, addr, bus, dev);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
+
+struct pci_dev_t *
+get_pci_dev(uint16_t vendor_id, uint16_t device_id) {
+ struct list_head *iter_bus, *iter_dev;
+ struct pci_dev_t *dev;
+ struct pci_bus_t *bus;
+
+ if (!has_pci_init) {
+ info("there is no PCI bus!\n");
+ return NULL;
+ }
+
+ list_for_each(iter_bus, &rootbus) {
+ bus = list_entry(iter_bus, struct pci_bus_t, pci_bus_list);
+ list_for_each(iter_dev, &bus->pci_dev_list) {
+ dev = list_entry(iter_dev, struct pci_dev_t, list);
+ if (!dev->cspace)
+ continue;
+ if (dev->cspace->type0.vendor_id == vendor_id
+ && dev->cspace->type0.device_id == device_id)
+ return dev;
+ }
+ }
+ return NULL;
+}
+
diff --git a/src/core/pic.c b/src/core/pic.c
@@ -0,0 +1,79 @@
+/*
+ * core/pic.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <pic.h>
+#include <x86.h>
+#include <common.h>
+
+enum {
+ BASE_IRQ_PIC1 = 0x20,
+ BASE_IRQ_PIC2 = BASE_IRQ_PIC1 + 8
+};
+
+void
+remap_pic(void)
+{
+ /* ICW 1 */
+ outb(0x20, 0x11);
+ outb(0xa0, 0x11);
+
+ /* ICW 2 */
+ outb(0x21, BASE_IRQ_PIC1);
+ outb(0xa1, BASE_IRQ_PIC2);
+
+ /* ICW 3 */
+ outb(0x21, 0x4);
+ outb(0xa1, 0x2);
+
+ /* ICW 4 */
+ outb(0x21, 0x1);
+ outb(0xa1, 0x1);
+
+ /* nullify the data registers */
+ outb(0x21, 0x0);
+ outb(0xa1, 0x0);
+}
+
+void
+enable_irq(uint32_t irq)
+{
+ uint8_t imr;
+
+ imr = (irq <= 7) ? inb(0x21) : inb(0xa1);
+ irq %= 8;
+ imr &= ~(1 << irq);
+ if (irq <= 7) {
+ outb(0x21, imr);
+ return;
+ }
+ outb(0xa1, imr);
+}
+
+void
+disable_irq(uint32_t irq)
+{
+ uint8_t imr;
+
+ imr = (irq <= 7) ? inb(0x21) : inb(0xa1);
+ irq %= 8;
+ imr |= (1 << irq);
+ if (irq <= 7) {
+ outb(0x21, imr);
+ return;
+ }
+ outb(0xa1, imr);
+}
+
+void
+pic_eoi(uint32_t int_no)
+{
+ if (int_no > 31) {
+ if (int_no >= 40)
+ outb(0xa0, 0x20);
+ outb(0x20, 0x20);
+ }
+}
+
diff --git a/src/core/pipe.c b/src/core/pipe.c
@@ -0,0 +1,133 @@
+/*
+ * core/pipe.c
+ *
+ * Copyright (C) 2010 stateless
+ */
+
+#include <pipe.h>
+#include <ext2.h>
+#include <common.h>
+#include <errno.h>
+#include <string.h>
+#include <heap.h>
+#include <x86.h>
+#include <tss.h>
+
+extern spinlock_t flist_lock;
+extern struct list_head flist;
+
+static int
+pipealloc(void)
+{
+ struct file_t *f;
+ int i;
+
+ acquire(&flist_lock);
+ for (i = 3; i < NR_MAX_OPEN_FILES; ++i) {
+ if (curr_proc->fdtable[i]
+ && curr_proc->fdtable[i]->f_state != FILE_NONE)
+ continue;
+ if (!curr_proc->fdtable[i]) {
+ f = kmalloc(sizeof(struct file_t));
+ if (IS_ERR(f)) {
+ release(&flist_lock);
+ return PTR_ERR(f);
+ }
+ f->f_state = FILE_NONE;
+ list_add_tail(&f->f_listopen, &flist);
+ curr_proc->fdtable[i] = f;
+ }
+ f = curr_proc->fdtable[i];
+ assert(f->f_state == FILE_NONE);
+ f->f_refcount = 1;
+ f->f_off = 0;
+ f->f_state = FILE_ALLOC;
+ f->f_type = FILE_PIPE;
+ f->f_inode = NULL;
+ f->f_inode_nr = 0;
+ curr_proc->pipebufs[i] = NULL;
+ release(&flist_lock);
+ return i;
+ }
+ release(&flist_lock);
+ return -EMFILE;
+}
+
+int
+pipe(int pipefd[2])
+{
+ int ret;
+ char *buf;
+
+ pipefd[0] = pipealloc();
+ if (pipefd[0] < 0)
+ return pipefd[0];
+ pipefd[1] = pipealloc();
+ if (pipefd[1] < 0) {
+ ret = pipefd[1];
+ goto err;
+ }
+ buf = kmalloc(PIPE_SIZ);
+ if (IS_ERR(buf)) {
+ ret = PTR_ERR(buf);
+ goto err1;
+ }
+ curr_proc->pipebufs[pipefd[0]] = buf;
+ curr_proc->pipebufs[pipefd[1]] = buf;
+ return 0;
+err1:
+ fileclose(pipefd[1]);
+err:
+ fileclose(pipefd[0]);
+ return ret;
+}
+
+/* must be called with flist_lock acquired */
+ssize_t
+piperead(int fd, void *buf, size_t count)
+{
+ size_t i;
+ struct file_t *f = NULL;
+ char *pbuf;
+
+ pbuf = curr_proc->pipebufs[fd];
+ for (i = 0; i < NR_MAX_OPEN_FILES; ++i)
+ if (curr_proc->pipebufs[i] == pbuf && i != (size_t)fd) {
+ f = curr_proc->fdtable[i];
+ break;
+ }
+ if (!f) f = curr_proc->fdtable[i];
+ for (i = 0; i < count && i < (size_t)f->f_off; ++i) {
+ ((char *)buf)[i] = *pbuf;
+ memcpy(pbuf, pbuf + 1, PIPE_SIZ - 1);
+ }
+ f->f_off -= i;
+ return i;
+}
+
+/* must be called with flist_lock acquired */
+ssize_t
+pipewrite(int fd, const void *buf, size_t count)
+{
+ size_t i;
+ char *pbuf;
+ ssize_t r;
+
+ pbuf = curr_proc->pipebufs[fd];
+ for (i = 0; i < NR_MAX_OPEN_FILES; ++i)
+ if (curr_proc->pipebufs[i] == pbuf && i != (size_t)fd)
+ break;
+ /* read end has been closed */
+ if (i != NR_MAX_OPEN_FILES
+ && curr_proc->fdtable[i]->f_state == FILE_NONE)
+ return -EPIPE;
+ for (i = 0; i < count && curr_proc->fdtable[fd]->f_off + i < PIPE_SIZ; ++i)
+ pbuf[curr_proc->fdtable[fd]->f_off + i] = ((char *)buf)[i];
+ curr_proc->fdtable[fd]->f_off += i;
+ r = i;
+ for (i = 0; i < NR_MAX_OPEN_FILES; ++i)
+ if (curr_proc->pipebufs[i] == pbuf && i != (size_t)fd)
+ curr_proc->fdtable[i]->f_off = curr_proc->fdtable[fd]->f_off;
+ return r;
+}
+
diff --git a/src/core/rtc.c b/src/core/rtc.c
@@ -0,0 +1,58 @@
+/*
+ * core/rtc.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <rtc.h>
+#include <common.h>
+#include <x86.h>
+#include <idt.h>
+#include <tss.h>
+#include <tty.h>
+
+volatile uint32_t systimer = 0;
+
+static uint32_t curr_freq = 100;
+
+void
+rtc_callback(__attribute__ ((unused)) struct trapframe_t *regs)
+{
+ ++systimer;
+ if (systimer % 500)
+ blink();
+ schedule();
+}
+
+void
+init_rtc(uint32_t freq)
+{
+ register_isr_handler(32, rtc_callback);
+
+ curr_freq = freq;
+ uint32_t divisor = 1193182 / freq;
+ /* channel: 0, access mode: lo/hi byte, operating mode: square wave, binary mode */
+ outb(0x43, 0x36);
+ outb(0x40, (divisor & 0xff));
+ outb(0x40, ((divisor >> 8) & 0xff));
+}
+
+void
+sleep(uint32_t seconds)
+{
+ while (seconds--) {
+ uint32_t now = systimer;
+ while (systimer < now + curr_freq)
+ ;
+ }
+}
+
+void
+msleep(uint32_t msec)
+{
+ uint32_t s = systimer;
+ while (systimer < s + msec)
+ ;
+ return;
+}
+
diff --git a/src/core/rtl8139.c b/src/core/rtl8139.c
@@ -0,0 +1,249 @@
+/*
+ * core/rtl8139.c
+ *
+ * Copyright (C) 2010 stateless
+ */
+
+#include <rtl8139.h>
+#include <pci.h>
+#include <x86.h>
+#include <idt.h>
+#include <heap.h>
+#include <rtc.h>
+#include <string.h>
+#include <errno.h>
+
+#define INTMASK (RTL_INT_PCIERR | RTL_INT_RX_ERR \
+ | RTL_INT_RX_OK | RTL_INT_TX_ERR \
+ | RTL_INT_TX_OK | RTL_INT_RXBUF_OVERFLOW)
+
+enum {
+ RTL_VENDOR_ID = 0x10ec,
+ RTL_DEVICE_ID = 0x8139,
+ RTL_RESET_TIMEOUT = 20 /* 200 ms */
+};
+
+/* NOTE: register naming comes from NetBSD-DC sources. */
+enum rtl_registers {
+ RTL_IDR0 = 0x00, /* Mac address */
+ RTL_MAR0 = 0x08, /* Multicast filter */
+ RTL_TXSTATUS0 = 0x10, /* Transmit status (4 32bit regs) */
+ RTL_TXSTATUS1 = 0x14, /* Transmit status (4 32bit regs) */
+ RTL_TXSTATUS2 = 0x18, /* Transmit status (4 32bit regs) */
+ RTL_TXSTATUS3 = 0x1c, /* Transmit status (4 32bit regs) */
+ RTL_TXADDR0 = 0x20, /* Tx descriptors (also 4 32bit) */
+ RTL_TXADDR1 = 0x24, /* Tx descriptors (also 4 32bit) */
+ RTL_TXADDR2 = 0x28, /* Tx descriptors (also 4 32bit) */
+ RTL_TXADDR3 = 0x2c, /* Tx descriptors (also 4 32bit) */
+ RTL_RXBUF = 0x30, /* Receive buffer start address */
+ RTL_RXEARLYCNT = 0x34, /* Early Rx byte count */
+ RTL_RXEARLYSTATUS = 0x36, /* Early Rx status */
+ RTL_CHIPCMD = 0x37, /* Command register */
+ RTL_RXBUFTAIL = 0x38, /* Current address of packet read (queue tail) */
+ RTL_RXBUFHEAD = 0x3A, /* Current buffer address (queue head) */
+ RTL_INTRMASK = 0x3C, /* Interrupt mask */
+ RTL_INTRSTATUS = 0x3E, /* Interrupt status */
+ RTL_TXCONFIG = 0x40, /* Tx config */
+ RTL_RXCONFIG = 0x44, /* Rx config */
+ RTL_TIMER = 0x48, /* A general purpose counter */
+ RTL_RXMISSED = 0x4C, /* 24 bits valid, write clears */
+ RTL_CFG9346 = 0x50, /* 93C46 command register */
+ RTL_CONFIG0 = 0x51, /* Configuration reg 0 */
+ RTL_CONFIG1 = 0x52, /* Configuration reg 1 */
+ RTL_TIMERINT = 0x54, /* Timer interrupt register (32 bits) */
+ RTL_MEDIASTATUS = 0x58, /* Media status register */
+ RTL_CONFIG3 = 0x59, /* Config register 3 */
+ RTL_CONFIG4 = 0x5A, /* Config register 4 */
+ RTL_MULTIINTR = 0x5C, /* Multiple interrupt select */
+ RTL_MII_TSAD = 0x60, /* Transmit status of all descriptors (16 bits) */
+ RTL_MII_BMCR = 0x62, /* Basic Mode Control Register (16 bits) */
+ RTL_MII_BMSR = 0x64, /* Basic Mode Status Register (16 bits) */
+ RTL_AS_ADVERT = 0x66, /* Auto-negotiation advertisement reg (16 bits) */
+ RTL_AS_LPAR = 0x68, /* Auto-negotiation link partner reg (16 bits) */
+ RTL_AS_EXPANSION = 0x6A /* Auto-negotiation expansion reg (16 bits) */
+};
+
+enum rtl_command_bits {
+ RTL_CMD_RESET = 0x10,
+ RTL_CMD_RX_ENABLE = 0x08,
+ RTL_CMD_TX_ENABLE = 0x04,
+ RTL_CMD_RX_BUF_EMPTY = 0x01
+};
+
+enum rtl_int_status {
+ RTL_INT_PCIERR = 0x8000, /* PCI Bus error */
+ RTL_INT_TIMEOUT = 0x4000, /* Set when TCTR reaches TimerInt value */
+ RTL_INT_RXFIFO_OVERFLOW = 0x0040, /* Rx FIFO overflow */
+ RTL_INT_RXFIFO_UNDERRUN = 0x0020, /* Packet underrun / link change */
+ RTL_INT_RXBUF_OVERFLOW = 0x0010, /* Rx BUFFER overflow */
+ RTL_INT_TX_ERR = 0x0008,
+ RTL_INT_TX_OK = 0x0004,
+ RTL_INT_RX_ERR = 0x0002,
+ RTL_INT_RX_OK = 0x0001
+};
+
+enum rtl_tx_status {
+ RTL_TX_CARRIER_LOST = 0x80000000, /* Carrier sense lost */
+ RTL_TX_ABORTED = 0x40000000, /* Transmission aborted */
+ RTL_TX_OUT_OF_WINDOW = 0x20000000, /* Out of window collision */
+ RTL_TX_STATUS_OK = 0x00008000, /* Status ok: a good packet was transmitted */
+ RTL_TX_UNDERRUN = 0x00004000, /* Transmit FIFO underrun */
+ RTL_TX_HOST_OWNS = 0x00002000, /* Set to 1 when DMA operation is completed */
+ RTL_TX_SIZE_MASK = 0x00001fff /* Descriptor size mask */
+};
+
+enum rtl_rx_status {
+ RTL_RX_MULTICAST = 0x00008000, /* Multicast packet */
+ RTL_RX_PAM = 0x00004000, /* Physical address matched */
+ RTL_RX_BROADCAST = 0x00002000, /* Broadcast address matched */
+ RTL_RX_BAD_SYMBOL = 0x00000020, /* Invalid symbol in 100TX packet */
+ RTL_RX_RUNT = 0x00000010, /* Packet size is <64 bytes */
+ RTL_RX_TOO_LONG = 0x00000008, /* Packet size is >4K bytes */
+ RTL_RX_CRC_ERR = 0x00000004, /* CRC error */
+ RTL_RX_FRAME_ALIGN = 0x00000002, /* Frame alignment error */
+ RTL_RX_STATUS_OK = 0x00000001 /* Status ok: a good packet was received */
+};
+
+struct rtl8139_t {
+ char rx_buffer[8192 + 16];
+ uint8_t mac_addr[6];
+ spinlock_t iolock;
+ uint32_t io_base;
+} *rtl = NULL;
+
+void
+rtl8139_int(__attribute__ ((unused)) struct trapframe_t *regs)
+{
+ panic("yoohoo!");
+}
+
+static void
+rtl_write8(uint16_t offset, uint8_t val)
+{
+ acquire(&rtl->iolock);
+ outb(rtl->io_base + offset, val);
+ release(&rtl->iolock);
+}
+
+static void
+rtl_write32(uint16_t offset, uint32_t val)
+{
+ acquire(&rtl->iolock);
+ outl(rtl->io_base + offset, val);
+ release(&rtl->iolock);
+}
+
+static void
+rtl_write16(uint16_t offset, uint16_t val)
+{
+ acquire(&rtl->iolock);
+ outw(rtl->io_base + offset, val);
+ release(&rtl->iolock);
+}
+
+static uint8_t
+rtl_read8(uint16_t offset)
+{
+ uint8_t r;
+
+ acquire(&rtl->iolock);
+ r = inb(rtl->io_base + offset);
+ release(&rtl->iolock);
+ return r;
+}
+
+static uint32_t
+rtl_read32(uint16_t offset)
+{
+ uint32_t r;
+
+ acquire(&rtl->iolock);
+ r = inl(rtl->io_base + offset);
+ release(&rtl->iolock);
+ return r;
+}
+
+int
+rtl8139_init(void)
+{
+ struct pci_dev_t *dev;
+ uint32_t i, timeout = 0;
+
+ /* enumerate the PCI bus looking for an rtl8139 */
+ dev = get_pci_dev(RTL_VENDOR_ID, RTL_DEVICE_ID);
+ if (!dev)
+ return -ENODEV;
+
+ rtl = kmalloc(sizeof(*rtl));
+ if (IS_ERR(rtl))
+ return PTR_ERR(rtl);
+
+ memset(rtl, 0, sizeof(*rtl));
+ initspinlock(&rtl->iolock);
+
+ /* grab the io port base for all subsequence i/o operations */
+ rtl->io_base = dev->cspace->type0.bar0 & 0xfffffffc;
+
+ /* reset the device */
+ rtl_write8(RTL_CHIPCMD, RTL_CMD_RESET);
+ do {
+ if (timeout++ == RTL_RESET_TIMEOUT)
+ goto err;
+ msleep(1); /* sleep for ~10ms */
+ } while (rtl_read8(RTL_CHIPCMD) & RTL_CMD_RESET);
+
+ register_isr_handler(0x20 + dev->cspace->type0.irq, rtl8139_int);
+
+ /* grab the mac-address */
+ for (i = 0; i < 6; ++i)
+ rtl->mac_addr[i] = rtl_read8(i);
+
+ /* put the device in config mode to enable writing to the config registers */
+ rtl_write8(RTL_CFG9346, 0xc0);
+ /* reset config 1 */
+ rtl_write8(RTL_CONFIG1, 0);
+ /* go back to normal mode */
+ rtl_write8(RTL_CFG9346, 0);
+
+ /* set the receive buffer address */
+ rtl_write32(RTL_RXBUF, (uint32_t)rtl->rx_buffer);
+ /* TODO: setup the tx descriptors */
+
+#if 0
+ /* accept
+ * physical address packets,
+ * physical match packets,
+ * multicast packets,
+ * and broadcast packets
+ * enable wrap mode
+ */
+ rtl_write32(RTL_RXCONFIG, 0xf | (1 << 7));
+ /* make sure IRQs will fire */
+ rtl_write32(RTL_INTRMASK, RTL_INT_TX_OK | RTL_INT_RX_OK);
+#else
+ rtl_write32(RTL_RXMISSED, 0);
+ rtl_write32(RTL_RXCONFIG, rtl_read32(RTL_RXCONFIG) | 0x0000000f);
+ rtl_write32(RTL_MAR0, 0);
+ rtl_write32(RTL_MAR0 + 4, 0);
+ rtl_write16(RTL_MULTIINTR, 0);
+ rtl_write16(RTL_INTRMASK, INTMASK);
+#endif
+
+ /* enable the receiver and the transmitter */
+ rtl_write32(RTL_CHIPCMD, RTL_CMD_RX_ENABLE | RTL_CMD_TX_ENABLE);
+ /* just to be on the safe side */
+ rtl_write8(RTL_CFG9346, 0);
+ return 0;
+err:
+ kfree(rtl);
+ return -EBUSY;
+}
+
+const uint8_t *
+get_mac_addr(void)
+{
+ if (!rtl)
+ return NULL;
+ return rtl->mac_addr;
+}
+
diff --git a/src/core/serial.c b/src/core/serial.c
@@ -0,0 +1,78 @@
+/*
+ * core/serial.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <serial.h>
+#include <x86.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+
+static int serial_has_init = 0;
+
+void
+serial_init(void)
+{
+ uint32_t state;
+
+ save_flags(&state);
+ cli();
+ outb(COM_PORT + 1, 0x0);
+ outb(COM_PORT + 3, 1 << 7);
+ outb(COM_PORT + 0, 0x3);
+ outb(COM_PORT + 1, 0x0);
+ outb(COM_PORT + 3, 0 << 7);
+ outb(COM_PORT + 3, 0x3);
+ outb(COM_PORT + 2, 0xc7);
+ outb(COM_PORT + 4, 0x0b);
+ serial_has_init = 1;
+ load_flags(state);
+}
+
+int
+serial_dump(const char *s, ...)
+{
+ char buf[512], *ptr;
+ va_list ap;
+ int c;
+ uint32_t state;
+
+ if (!serial_has_init)
+ return -EIO;
+ save_flags(&state);
+ cli();
+ va_start(ap, s);
+ c = vsprintf(buf, s, ap);
+ va_end(ap);
+ ptr = buf;
+ while (*ptr)
+ if (inb(COM_PORT + 5) & 0x20)
+ outb(COM_PORT, *ptr++);
+ load_flags(state);
+ return c;
+}
+
+int
+serial_putchar(int c)
+{
+ uint32_t state;
+
+ if (!serial_has_init)
+ return -EIO;
+ save_flags(&state);
+ cli();
+ if (inb(COM_PORT + 5) & 0x20)
+ outb(COM_PORT, (uint8_t)c);
+ load_flags(state);
+ return 0;
+}
+
+int
+serial_avail(void)
+{
+ return serial_has_init;
+}
+
diff --git a/src/core/syscall.c b/src/core/syscall.c
@@ -0,0 +1,299 @@
+/*
+ * core/syscall.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <syscall.h>
+#include <string.h>
+#include <x86.h>
+#include <common.h>
+#include <tss.h>
+#include <serial.h>
+#include <rtc.h>
+#include <mm.h>
+#include <tty.h>
+#include <errno.h>
+#include <pipe.h>
+
+extern int f_kdb;
+
+static void __sys_write(struct trapframe_t *regs);
+static void __sys_read(struct trapframe_t *regs);
+static void __sys_exit(struct trapframe_t *regs);
+static void __sys_fork(struct trapframe_t *regs);
+static void __sys_waitpid(struct trapframe_t *regs);
+static void __sys_reschedule(struct trapframe_t *regs);
+static void __sys_open(struct trapframe_t *regs);
+static void __sys_close(struct trapframe_t *regs);
+static void __sys_creat(struct trapframe_t *regs);
+static void __sys_execve(struct trapframe_t *regs);
+static void __sys_isatty(struct trapframe_t *regs);
+static void __sys_getpid(struct trapframe_t *regs);
+static void __sys_getppid(struct trapframe_t *regs);
+static void __sys_readdir(struct trapframe_t *regs);
+static void __sys_dup(struct trapframe_t *regs);
+static void __sys_dup2(struct trapframe_t *regs);
+static void __sys_stat(struct trapframe_t *regs);
+static void __sys_fstat(struct trapframe_t *regs);
+static void __sys_seeder(struct trapframe_t *regs);
+static void __sys_sbrk(struct trapframe_t *regs);
+static void __sys_getuid(struct trapframe_t *regs);
+static void __sys_setuid(struct trapframe_t *regs);
+static void __sys_getgid(struct trapframe_t *regs);
+static void __sys_setgid(struct trapframe_t *regs);
+static void __sys_suspend_task(struct trapframe_t *regs);
+static void __sys_resume_task(struct trapframe_t *regs);
+static void __sys_pipe(struct trapframe_t *regs);
+
+static void *syscall_table[SYSCALL_NR] = {
+ [__NR_exit] = &__sys_exit,
+ [__NR_fork] = &__sys_fork,
+ [__NR_read] = &__sys_read,
+ [__NR_write] = &__sys_write,
+ [__NR_waitpid] = &__sys_waitpid,
+ [__NR_reschedule] = &__sys_reschedule,
+ [__NR_open] = &__sys_open,
+ [__NR_close] = &__sys_close,
+ [__NR_creat] = &__sys_creat,
+ [__NR_execve] = &__sys_execve,
+ [__NR_isatty] = &__sys_isatty,
+ [__NR_getpid] = &__sys_getpid,
+ [__NR_getppid] = &__sys_getppid,
+ [__NR_readdir] = &__sys_readdir,
+ [__NR_dup] = &__sys_dup,
+ [__NR_dup2] = &__sys_dup2,
+ [__NR_stat] = &__sys_stat,
+ [__NR_fstat] = &__sys_fstat,
+ [__NR_seeder] = &__sys_seeder,
+ [__NR_sbrk] = &__sys_sbrk,
+ [__NR_getuid] = &__sys_getuid,
+ [__NR_setuid] = &__sys_setuid,
+ [__NR_getgid] = &__sys_getgid,
+ [__NR_setgid] = &__sys_setgid,
+ [__NR_suspend_task] = &__sys_suspend_task,
+ [__NR_resume_task] = &__sys_resume_task,
+ [__NR_pipe] = &__sys_pipe
+};
+
+#ifdef BSYSCALL_TRACE
+static const char *syscall_names[SYSCALL_NR] = {
+ [__NR_exit] = "sys_exit",
+ [__NR_fork] = "sys_fork",
+ [__NR_read] = "sys_read",
+ [__NR_write] = "sys_write",
+ [__NR_waitpid] = "sys_waitpid",
+ [__NR_reschedule] = "sys_reschedule",
+ [__NR_open] = "sys_open",
+ [__NR_close] = "sys_close",
+ [__NR_creat] = "sys_creat",
+ [__NR_execve] = "sys_execve",
+ [__NR_isatty] = "sys_isatty",
+ [__NR_getpid] = "sys_getpid",
+ [__NR_getppid] = "sys_getppid",
+ [__NR_readdir] = "sys_readdir",
+ [__NR_dup] = "sys_dup",
+ [__NR_dup2] = "sys_dup2",
+ [__NR_stat] = "sys_stat",
+ [__NR_fstat] = "sys_fstat",
+ [__NR_seeder] = "sys_seeder",
+ [__NR_sbrk] = "sys_sbrk",
+ [__NR_getuid] = "sys_getuid",
+ [__NR_setuid] = "sys_setuid",
+ [__NR_getgid] = "sys_getgid",
+ [__NR_setgid] = "sys_setgid",
+ [__NR_suspend_task] = "sys_suspend_task",
+ [__NR_resume_task] = "sys_resume_task",
+ [__NR_pipe] = "sys_pipe"
+};
+#endif
+
+static void
+__sys_write(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)write((int)regs->ebx, (const void *)regs->ecx, (size_t)regs->edx);
+}
+
+static void
+__sys_read(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)read((int)regs->ebx, (void *)regs->ecx, (size_t)regs->edx);
+}
+
+static void
+__sys_exit(struct trapframe_t *regs)
+{
+ if (!strcmp(curr_proc->name, "kdb")) {
+ unfreeze_tasks();
+ f_kdb = 0;
+ }
+ curr_proc->state = TASK_ZOMBIE;
+ curr_proc->status = (int)regs->ebx;
+ attach_tty(curr_proc->parent);
+ tty_resume();
+ closefds();
+ remove_proc_mappings();
+ schedule();
+}
+
+static void
+__sys_fork(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)fork();
+}
+
+static void
+__sys_waitpid(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)waitpid((pid_t)regs->ebx, (int *)regs->ecx, (int)regs->edx);
+}
+
+static void
+__sys_reschedule(__attribute__ ((unused)) struct trapframe_t *regs)
+{
+ schedule();
+}
+
+static void
+__sys_open(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)open((const char *)regs->ebx, (int)regs->ecx, (mode_t)regs->edx);
+}
+
+static void
+__sys_close(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)close((int)regs->ebx);
+}
+
+static void
+__sys_creat(struct trapframe_t *regs)
+{
+ regs->eax = (int)creat((const char *)regs->ebx, (mode_t)regs->ecx);
+}
+
+static void
+__sys_execve(__attribute__ ((unused)) struct trapframe_t *regs)
+{
+ regs->eax = execve((const char *)regs->ebx, 0, 0); /* FIXME */
+}
+
+static void
+__sys_isatty(struct trapframe_t *regs)
+{
+ regs->eax = 1;
+}
+
+static void
+__sys_getpid(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)curr_proc->pid;
+}
+
+static void
+__sys_getppid(struct trapframe_t *regs)
+{
+ regs->eax = (!curr_proc->parent) ? 0 : (uint32_t)curr_proc->parent->pid;
+}
+
+static void
+__sys_readdir(struct trapframe_t *regs)
+{
+ /* I will probably need to change the prototype of readdir to not depend on DIR */
+ regs->eax = (uint32_t)readdir((DIR *)regs->ebx);
+}
+
+static void
+__sys_dup(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)dup((int)regs->ebx);
+}
+
+static void
+__sys_dup2(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)dup2((int)regs->ebx, (int)regs->ecx);
+}
+
+static void
+__sys_stat(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)stat((const char *)regs->ebx, (struct stat *)regs->ecx);
+}
+
+static void
+__sys_fstat(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)fstat((int)regs->ebx, (struct stat *)regs->ecx);
+}
+
+static void
+__sys_seeder(struct trapframe_t *regs)
+{
+ regs->eax = systimer ^ (uint32_t)curr_proc;
+}
+
+static void
+__sys_sbrk(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)sbrk((intptr_t)regs->ebx);
+}
+
+static void
+__sys_getuid(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)getuid();
+}
+
+static void
+__sys_setuid(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)setuid((uid_t)regs->ebx);
+}
+
+static void
+__sys_getgid(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)getgid();
+}
+
+static void
+__sys_setgid(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)setgid((uid_t)regs->ebx);
+}
+
+static void
+__sys_suspend_task(struct trapframe_t *regs)
+{
+ suspend_task((void *)regs->ebx);
+}
+
+static void
+__sys_resume_task(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)resume_task((void *)regs->ebx);
+}
+
+static void
+__sys_pipe(struct trapframe_t *regs)
+{
+ regs->eax = (uint32_t)pipe((int *)regs->ebx);
+}
+
+void
+syscall_dispatcher(struct trapframe_t *regs)
+{
+ if (regs->eax > 0 && regs->eax < SYSCALL_NR && syscall_table[regs->eax]) {
+ if (curr_proc) {
+ TRACE_SYSCALL(serial_dump("tracing[%s with pid %d]: %s [eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx]\n",
+ curr_proc->name, curr_proc->pid, syscall_names[regs->eax],
+ regs->eax, regs->ebx, regs->ecx, regs->edx);)
+ }
+ void (*fp)(struct trapframe_t * regs) = (void (*)(struct trapframe_t *))syscall_table[regs->eax];
+ fp(regs);
+ } else {
+ regs->eax = -ENOSYS;
+ }
+}
+
diff --git a/src/core/tss.c b/src/core/tss.c
@@ -0,0 +1,464 @@
+/*
+ * core/tss.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <tss.h>
+#include <string.h>
+#include <common.h>
+#include <heap.h>
+#include <errno.h>
+#include <syscall.h>
+#include <tty.h>
+
+#define NR_HASH_ENT 64
+
+extern struct page_directory_t *new_kernel_pdir;
+
+struct task_t *curr_proc = NULL;
+
+static struct list_head htsleep[NR_HASH_ENT];
+static struct list_head runqueue;
+static struct task_t *idle = NULL;
+static int tss_init = 0;
+static pid_t currpid = 0;
+
+static uint32_t hash_chan(void *chan);
+
+static inline pid_t
+get_new_pid(void)
+{
+ int pid;
+ uint32_t state;
+
+ save_flags(&state);
+ cli();
+ /* I hope this never wraps */
+ pid = currpid++;
+ load_flags(state);
+ return pid;
+}
+
+void
+ps(void)
+{
+ uint32_t state, i;
+ struct list_head *iter;
+ struct task_t *task;
+
+ printf("%-12s%-12s%-12s%-12s%-12s\n",
+ "PID",
+ "TYPE",
+ "STATE",
+ "PROC",
+ "PARENT");
+ save_flags(&state);
+ cli();
+ list_for_each(iter, &runqueue) {
+ task = list_entry(iter, struct task_t, q_task);
+ printf("%-12d%-12s%-12s%-12s%-12s\n",
+ task->pid,
+ (task->flags & KERNEL_PROCESS) ? "KTHREAD" : "USER PROC",
+ (task->state == TASK_ZOMBIE) ? "ZOMBIE" :
+ (task->state == TASK_SLEEPING) ? "SLEEPING" :
+ (task->state == TASK_RUNNABLE) ? "RUNNABLE" : "RUNNING",
+ task->name,
+ (!task->parent) ? "(null)" : task->parent->name);
+ }
+ for (i = 0; i < NR_HASH_ENT; ++i) {
+ list_for_each(iter, &htsleep[i]) {
+ task = list_entry(iter, struct task_t, q_task);
+ assert(task->state == TASK_SLEEPING);
+ printf("%-12d%-12s%-12s%-12s%-12s\n",
+ task->pid,
+ (task->flags & KERNEL_PROCESS) ? "KTRHEAD" : "USER PROC",
+ "SLEEPING",
+ task->name,
+ (!task->parent) ? "(null)" : task->parent->name);
+ }
+ }
+ load_flags(state);
+}
+
+void
+idle_fn(void)
+{
+ tss_init = 1;
+ curr_proc->state = TASK_RUNNING;
+ sti();
+ while (1) {
+ }
+}
+
+void
+freeze_tasks(void)
+{
+ struct list_head *iter;
+ struct task_t *task;
+
+ list_for_each(iter, &runqueue) {
+ task = list_entry(iter, struct task_t, q_task);
+ if (!strcmp(task->name, "kdb")
+ || !strcmp(task->name, "idle")) {
+ task->state = TASK_RUNNABLE;
+ continue;
+ }
+ task->old_state = task->state;
+ task->state = TASK_SLEEPING;
+ }
+}
+
+void
+unfreeze_tasks(void)
+{
+ struct list_head *iter;
+ struct task_t *task;
+
+ list_for_each(iter, &runqueue) {
+ task = list_entry(iter, struct task_t, q_task);
+ if (strcmp(task->name, "kdb")
+ && strcmp(task->name, "idle"))
+ task->state = task->old_state;
+ }
+}
+
+void
+schedule(void)
+{
+ struct list_head *iter, *q;
+ struct task_t *task;
+
+ if (!tss_init)
+ return;
+
+ list_for_each_safe(iter, q, &runqueue) {
+ task = list_entry(iter, struct task_t, q_task);
+ if (task->state == TASK_RUNNABLE) {
+ task->state = TASK_RUNNING;
+ curr_proc = task;
+ switch_page_dir(curr_proc->page_dir);
+ break;
+ } else if (task->state == TASK_RUNNING)
+ task->state = TASK_RUNNABLE;
+ list_del(iter);
+ add_task(task);
+ }
+}
+
+int
+init_tss(void)
+{
+ int i;
+
+ cli();
+ INIT_LIST_HEAD(&runqueue);
+ for (i = 0; i < NR_HASH_ENT; ++i)
+ INIT_LIST_HEAD(&htsleep[i]);
+ idle = create_kthread("idle", idle_fn);
+ if (IS_ERR(idle))
+ return PTR_ERR(idle);
+ curr_proc = idle;
+ return 0;
+}
+
+void
+kick_tss(void)
+{
+ PUT_ESP(curr_proc->esp);
+ jmp(((struct cswitch_frame_t *)curr_proc->esp)->eip);
+}
+
+struct task_t *
+create_kthread(const char *name, void *routine) {
+ struct task_t *task;
+ int ret = -ENOMEM, i;
+ size_t len;
+
+ task = kmalloc(sizeof(*task));
+ if (IS_ERR(task)) {
+ ret = PTR_ERR(task);
+ goto err;
+ }
+ memset(task, 0, sizeof(*task));
+ len = strlen(name) + 1;
+ assert(len);
+ task->name = kmalloc(len);
+ if (IS_ERR(task->name)) {
+ ret = PTR_ERR(task->name);
+ goto err1;
+ }
+ strncpy(task->name, name, len);
+ task->name[len - 1] = '\0';
+ INIT_LIST_HEAD(&task->l_regions);
+ task->parent = curr_proc;
+ task->pid = get_new_pid();
+ task->state = task->old_state = TASK_RUNNABLE;
+ task->flags = KERNEL_PROCESS;
+ task->cdir = get_root_inode();
+ if (!task->cdir) {
+ ret = -EIO;
+ goto err2;
+ }
+ for (i = 0; i < NR_MAX_OPEN_FILES; ++i)
+ task->fdtable[i] = NULL;
+ task->stack = kmalloc(TASK_STACK_SIZE);
+ if (IS_ERR(task->stack)) {
+ ret = PTR_ERR(task->stack);
+ goto err2;
+ }
+ memset(task->stack, 0x0, TASK_STACK_SIZE);
+ task->page_dir = clone_page_dir();
+ if (IS_ERR(task->page_dir)) {
+ ret = PTR_ERR(task->page_dir);
+ goto err3;
+ }
+ task->cf = (struct cswitch_frame_t *)((uint8_t *)task->stack
+ + TASK_STACK_SIZE
+ - sizeof(struct cswitch_frame_t));
+ task->cf->eflags = 0x202;
+ task->cf->cs = 0x8;
+ task->cf->eip = (uint32_t)routine;
+ task->cf->ds = 0x10;
+ task->esp = (uint32_t)task->cf;
+ attach_tty(task);
+ add_task(task);
+ return task;
+err3:
+ kfree(task->stack);
+err2:
+ kfree(task->name);
+err1:
+ kfree(task);
+err:
+ return ERR_PTR(ret);
+}
+
+void
+add_task(struct task_t *task)
+{
+ uint32_t state;
+
+ save_flags(&state);
+ cli();
+ list_add_tail(&task->q_task, &runqueue);
+ load_flags(state);
+}
+
+void
+remove_task(struct task_t *task)
+{
+ uint32_t state;
+
+ save_flags(&state);
+ cli();
+ list_del(&task->q_task);
+ kfree(task->name);
+ kfree(task->stack);
+ kfree(task);
+ load_flags(state);
+}
+
+int
+fork(void)
+{
+ int ret = -ENOMEM, i;
+ uint32_t offset;
+ struct task_t *task, *parent;
+ size_t len;
+
+ parent = curr_proc;
+ task = kmalloc(sizeof(*task));
+ if (IS_ERR(task)) {
+ ret = PTR_ERR(task);
+ goto err;
+ }
+ memset(task, 0, sizeof(*task));
+ len = strlen(parent->name) + 1;
+ assert(len);
+ task->name = kmalloc(len);
+ if (IS_ERR(task->name)) {
+ ret = PTR_ERR(task->name);
+ goto err1;
+ }
+ strncpy(task->name, parent->name, len);
+ task->name[len - 1] = '\0';
+ INIT_LIST_HEAD(&task->l_regions);
+ task->parent = parent;
+ task->pid = get_new_pid();
+ task->state = task->old_state = TASK_RUNNABLE;
+ task->flags = parent->flags;
+ task->uid = parent->uid;
+ task->gid = parent->gid;
+ task->fuid = parent->fuid;
+ task->fgid = parent->fgid;
+ task->cdir = parent->cdir;
+ for (i = 0; i < NR_MAX_OPEN_FILES; ++i) {
+ task->fdtable[i] = parent->fdtable[i];
+ if (task->fdtable[i]->f_state == FILE_ALLOC)
+ ++task->fdtable[i]->f_refcount;
+ }
+ for (i = 0; i < NR_MAX_OPEN_FILES; ++i)
+ task->pipebufs[i] = parent->pipebufs[i];
+ task->stack = kmalloc(TASK_STACK_SIZE);
+ if (IS_ERR(task->stack)) {
+ ret = PTR_ERR(task->stack);
+ goto err2;
+ }
+ memset(task->stack, 0, TASK_STACK_SIZE);
+ task->page_dir = clone_page_dir();
+ if (IS_ERR(task->page_dir)) {
+ ret = PTR_ERR(task->page_dir);
+ goto err3;
+ }
+ memcpy(task->stack, parent->stack, TASK_STACK_SIZE);
+ /*
+ * perhaps by patching all ebps in the parent stack, the child will be able to
+ * return properly even if SYS_FORK is not inlined
+ */
+ offset = (uint32_t)((uint8_t *)parent->stack
+ + TASK_STACK_SIZE
+ - parent->esp);
+ task->cf = (struct cswitch_frame_t *)((uint8_t *)task->stack
+ + TASK_STACK_SIZE
+ - offset
+ - sizeof(struct cswitch_frame_t));
+ *task->cf = *parent->cf;
+ offset = (uint32_t)((uint8_t *)parent->stack
+ + TASK_STACK_SIZE
+ - parent->cf->ebp);
+ task->cf->ebp = (uint32_t)((uint8_t *)task->stack
+ + TASK_STACK_SIZE
+ - offset);
+ task->cf->eax = 0;
+ task->esp = (uint32_t)task->cf;
+ /* TODO: create userspace stuff */
+ attach_tty(task);
+ add_task(task);
+ return task->pid;
+err3:
+ kfree(task->stack);
+err2:
+ kfree(task->name);
+err1:
+ kfree(task);
+err:
+ return ret;
+}
+
+/* TODO: test this one */
+pid_t
+waitpid(pid_t pid, int *status, int options)
+{
+ struct list_head *iter, *q;
+ struct task_t *task;
+ pid_t retpid;
+ int haschld, pidexists;
+
+ assert(options == WNOHANG);
+ if (options != WNOHANG)
+ return -EINVAL;
+
+ haschld = 0;
+ pidexists = (pid == -1) ? 1 : 0;
+ for (;;) {
+ list_for_each_safe(iter, q, &runqueue) {
+ task = list_entry(iter, struct task_t, q_task);
+ if (pid != -1 && task->pid == pid)
+ pidexists = 1;
+ if (task->parent != curr_proc)
+ continue;
+ haschld = 1;
+ if (task->state != TASK_ZOMBIE)
+ continue;
+ if (status) *status = (int)task->status;
+ retpid = task->pid;
+ remove_task(task);
+ goto out;
+ }
+ if (!pidexists)
+ return -ECHILD;
+ if (options == WNOHANG) {
+ if (haschld)
+ return 0;
+ return -ECHILD;
+ }
+ }
+out:
+ return retpid;
+}
+
+static uint32_t
+hash_chan(void *chan)
+{
+ uint32_t *c = chan, hash = 0, i;
+
+ for (i = 0; i < 32; ++i)
+ hash = (*c & (1lu << i)) + (hash << 6) + (hash << 16) - hash;
+ return hash;
+}
+
+/* can be called as follows:
+ * syscall -> suspend_task (from a syscall)
+ * suspend_task (normally)
+ * NOTE: suspend_task will fail if it is called
+ * from nested syscalls (syscall depth > 1)
+ */
+void
+suspend_task(void *channel)
+{
+ uint32_t i;
+
+ curr_proc->state = TASK_SLEEPING;
+ list_del(&curr_proc->q_task);
+ i = hash_chan(channel) % NR_HASH_ENT;
+ list_add_tail(&curr_proc->q_task, &htsleep[i]);
+ schedule();
+}
+
+int
+resume_task(void *channel)
+{
+ uint32_t i;
+ struct list_head *iter, *q;
+ struct task_t *task;
+
+ i = hash_chan(channel) % NR_HASH_ENT;
+ list_for_each_safe(iter, q, &htsleep[i]) {
+ task = list_entry(iter, struct task_t, q_task);
+ assert(task->state == TASK_SLEEPING);
+ task->state = TASK_RUNNABLE;
+ list_del(&task->q_task);
+ list_add(&task->q_task, &runqueue);
+ }
+ return 0;
+}
+
+uid_t
+getuid(void)
+{
+ return curr_proc->uid;
+}
+
+int
+setuid(__attribute__ ((unused)) uid_t uid)
+{
+ /* TODO: perform additional checks */
+ curr_proc->uid = uid; /* w00t w00t */
+ return 0;
+}
+
+gid_t
+getgid(void)
+{
+ return curr_proc->gid;
+}
+
+int
+setgid(__attribute__ ((unused)) gid_t gid)
+{
+ /* TODO: perform additional checks */
+ curr_proc->gid = gid;
+ return 0;
+}
+
diff --git a/src/core/tty.c b/src/core/tty.c
@@ -0,0 +1,267 @@
+/*
+ * core/tty.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <tty.h>
+#include <x86.h>
+#include <keyboard.h>
+#include <ctype.h>
+#include <tss.h>
+#include <string.h>
+#include <syscall.h>
+
+unsigned short int cursor_x = 0;
+unsigned short int cursor_y = 0;
+volatile unsigned char *framebuffer = (unsigned char *)FRAMEBUFFER_ADDR;
+enum vga_colours curr_col = 0;
+
+static void *tty_sleep_chan = (void *) & tty_sleep_chan;
+static void *tty_suspend_chan = (void *) & tty_suspend_chan;
+static struct task_t *ctrl_tty_task = NULL;
+
+void
+ccurr_col(enum vga_colours bg, enum vga_colours fg)
+{
+ uint32_t state;
+
+ save_flags(&state);
+ cli();
+ curr_col = 0;
+ curr_col |= fg;
+ curr_col = curr_col | (bg << 4);
+ load_flags(state);
+}
+
+void
+clear_scr(void)
+{
+ uint32_t state;
+ int y, x;
+
+ save_flags(&state);
+ cli();
+ for (y = 0; y < BUF_HEIGHT; ++y) {
+ for (x = 0; x < BUF_WIDTH; ++x) {
+ framebuffer[((y * BUF_WIDTH + x) << 1)] = 0;
+ framebuffer[((y * BUF_WIDTH + x) << 1) + 1] = curr_col;
+ }
+ }
+ gotoxy(0, 0);
+ load_flags(state);
+}
+
+void
+gotoxy(unsigned short newy, unsigned short newx)
+{
+ uint32_t state;
+
+ save_flags(&state);
+ cli();
+ cursor_x = newx;
+ cursor_y = newy;
+ load_flags(state);
+}
+
+void
+erase_line(int y)
+{
+ int x;
+ uint32_t state;
+
+ save_flags(&state);
+ cli();
+ for (x = 0; x < BUF_WIDTH; ++x) {
+ framebuffer[((y * BUF_WIDTH + x) << 1)] = 0;
+ framebuffer[((y * BUF_WIDTH + x) << 1) + 1] = curr_col;
+ }
+ load_flags(state);
+}
+
+void
+scroll(void)
+{
+ int y, x;
+ volatile unsigned char *dst, *src;
+ uint32_t state;
+
+ save_flags(&state);
+ cli();
+ if (cursor_y >= BUF_HEIGHT) {
+ for (y = 0; y < BUF_HEIGHT - 1; ++y) {
+ erase_line(y);
+ dst = framebuffer + ((y * BUF_WIDTH) << 1);
+ src = framebuffer + (((y + 1) * BUF_WIDTH) << 1);
+ for (x = 0; x < BUF_WIDTH * 2; ++x)
+ *(dst + x) = *(src + x);
+ }
+ erase_line(BUF_HEIGHT - 1);
+ gotoxy(BUF_HEIGHT - 1, 0);
+ }
+ load_flags(state);
+}
+
+void
+blink(void)
+{
+ uint32_t state;
+ uint8_t temp;
+
+ save_flags(&state);
+ cli();
+ outb(0x3d4, 0xa);
+ temp = inb(0x3d5);
+ temp ^= 0x20;
+ outb(0x3d5, temp);
+ load_flags(state);
+}
+
+int
+tty_putchar(int c)
+{
+ uint32_t state;
+ volatile unsigned char *ptr;
+
+ save_flags(&state);
+ cli();
+ if (c == '\b' && cursor_x) {
+ gotoxy(cursor_y, cursor_x - 1);
+ } else if (c == '\n') {
+ gotoxy(cursor_y + 1, 0);
+ } else if (c == '\r') {
+ gotoxy(cursor_y, 0);
+ } else if (c == '\t') {
+ gotoxy(cursor_y, cursor_x + 4);
+ } else {
+ ptr = framebuffer + ((cursor_y * BUF_WIDTH + cursor_x) << 1);
+ *ptr = c & 0xff;
+ *(ptr + 1) = curr_col & 0xff;
+ gotoxy(cursor_y, cursor_x + 1);
+ }
+ if (cursor_x >= BUF_WIDTH)
+ gotoxy(cursor_y + 1, 0);
+ scroll();
+ load_flags(state);
+ return c;
+}
+
+void
+update_cursor(uint16_t row, uint16_t col)
+{
+ uint32_t state;
+ uint16_t position = (row * 80) + col;
+
+ save_flags(&state);
+ cli();
+ outb(0x3d4, 0xf);
+ outb(0x3d5, (position & 0xff));
+ outb(0x3d4, 0xe);
+ outb(0x3d5, ((position >> 8) & 0xff));
+ load_flags(state);
+}
+
+void *
+tty_get_sleep_chan(void)
+{
+ return tty_sleep_chan;
+}
+
+void
+attach_tty(struct task_t *ctask)
+{
+ if (strcmp(ctask->name, "idle"))
+ ctrl_tty_task = ctask;
+}
+
+int
+is_tty_attached(void)
+{
+ return !ctrl_tty_task ? 0 : 1;
+}
+
+int
+is_ctrl_task(struct task_t *ctask)
+{
+ return ctrl_tty_task == ctask;
+}
+
+void
+tty_suspend(void)
+{
+ sys_suspend_task(tty_suspend_chan);
+}
+
+void
+tty_resume(void)
+{
+ sys_resume_task(tty_suspend_chan);
+}
+
+struct task_t *
+tty_get_ctrl_task(void) {
+ return ctrl_tty_task;
+}
+
+ssize_t
+tty_read(void *buf, size_t count)
+{
+ int c;
+ size_t i = 0;
+ char *p;
+ volatile unsigned char *ptr;
+
+ p = buf;
+ while (i < count) {
+ do {
+ if (!is_ctrl_task(curr_proc))
+ tty_suspend();
+again:
+ sys_suspend_task(tty_sleep_chan);
+ c = kbd_getchar();
+ if (c != -1 && (isprint(c) || c == 127)) {
+ if (c == 127) {
+ if (p == buf)
+ goto again;
+ gotoxy(cursor_y, cursor_x - 1);
+ update_cursor(cursor_y, cursor_x);
+ *--p = '\0';
+ c = ' ';
+ ptr = framebuffer +
+ ((cursor_y * BUF_WIDTH + cursor_x) << 1);
+ *ptr = c & 0xff;
+ *(ptr + 1) = curr_col & 0xff;
+ goto again;
+ }
+ if (*p != '\n')
+ update_cursor(cursor_y, cursor_x + 1);
+ tty_putchar(c);
+ *p = c;
+ if (*p == '\n') {
+ /* HACK */
+ curr_proc->esp = curr_proc->old_esp;
+ return i + 1;
+ }
+ ++p;
+ break;
+ }
+ } while (1);
+ ++i;
+ }
+ /* HACK */
+ curr_proc->esp = curr_proc->old_esp;
+ return count;
+}
+
+int
+raw_tty_getchar(void)
+{
+ int c;
+
+ do {
+ c = kbd_getchar();
+ if (c != -1)
+ return c;
+ } while (1);
+}
+
diff --git a/src/core/x86_asm.S b/src/core/x86_asm.S
@@ -0,0 +1,467 @@
+.text
+.globl gdt_flush
+.type gdt_flush, @function
+gdt_flush:
+ movl 4(%esp), %eax
+ lgdt (%eax)
+
+ movw $0x10, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+
+ ljmp $(0x08), $flush
+flush:
+ ret
+
+.text
+.globl tss_flush
+.type tss_flush, @function
+tss_flush:
+ movw $0x28, %ax
+ ltrw %ax
+ ret
+
+.globl idt_flush
+.type idt_flush, @function
+idt_flush:
+ movl 4(%esp), %eax
+ lidt (%eax)
+ ret
+
+.globl isr0
+.type isr0, @function
+isr0:
+ cli
+ pushl $0x0
+ pushl $0x0
+ jmp isr_handler
+
+.globl isr1
+.type isr1, @function
+isr1:
+ cli
+ pushl $0x0
+ pushl $0x1
+ jmp isr_handler
+
+.globl isr2
+.type isr2, @function
+isr2:
+ cli
+ pushl $0x0
+ pushl $0x2
+ jmp isr_handler
+
+.globl isr3
+.type isr3, @function
+isr3:
+ cli
+ pushl $0x0
+ pushl $0x3
+ jmp isr_handler
+
+.globl isr4
+.type isr4, @function
+isr4:
+ cli
+ pushl $0x0
+ pushl $0x4
+ jmp isr_handler
+
+.globl isr5
+.type isr5, @function
+isr5:
+ cli
+ pushl $0x0
+ pushl $0x5
+ jmp isr_handler
+
+.globl isr6
+.type isr6, @function
+isr6:
+ cli
+ pushl $0x0
+ pushl $0x6
+ jmp isr_handler
+
+.globl isr7
+.type isr7, @function
+isr7:
+ cli
+ pushl $0x0
+ pushl $0x7
+ jmp isr_handler
+
+.globl isr8
+.type isr8, @function
+isr8:
+ cli
+ pushl $0x8
+ jmp isr_handler
+
+.globl isr9
+.type isr9, @function
+isr9:
+ cli
+ pushl $0x0
+ pushl $0x9
+ jmp isr_handler
+
+.globl isr10
+.type isr10, @function
+isr10:
+ cli
+ pushl $0xa
+ jmp isr_handler
+
+.globl isr11
+.type isr11, @function
+isr11:
+ cli
+ pushl $0xb
+ jmp isr_handler
+
+.globl isr12
+.type isr12, @function
+isr12:
+ cli
+ pushl $0xc
+ jmp isr_handler
+
+.globl isr13
+.type isr13, @function
+isr13:
+ cli
+ pushl $0xd
+ jmp isr_handler
+
+.globl isr14
+.type isr14, @function
+isr14:
+ cli
+ pushl $0xe
+ jmp isr_handler
+
+.globl isr15
+.type isr15, @function
+isr15:
+ cli
+ pushl $0x0
+ pushl $0xf
+ jmp isr_handler
+
+.globl isr16
+.type isr16, @function
+isr16:
+ cli
+ pushl $0x0
+ pushl $0x10
+ jmp isr_handler
+
+.globl isr17
+.type isr17, @function
+isr17:
+ cli
+ pushl $0x0
+ pushl $0x11
+ jmp isr_handler
+
+.globl isr18
+.type isr18, @function
+isr18:
+ cli
+ pushl $0x0
+ pushl $0x12
+ jmp isr_handler
+
+.globl isr19
+.type isr19, @function
+isr19:
+ cli
+ pushl $0x0
+ pushl $0x13
+ jmp isr_handler
+
+.globl isr20
+.type isr20, @function
+isr20:
+ cli
+ pushl $0x0
+ pushl $0x14
+ jmp isr_handler
+
+.globl isr21
+.type isr21, @function
+isr21:
+ cli
+ pushl $0x0
+ pushl $0x15
+ jmp isr_handler
+
+.globl isr22
+.type isr22, @function
+isr22:
+ cli
+ pushl $0x0
+ pushl $0x16
+ jmp isr_handler
+
+.globl isr23
+.type isr23, @function
+isr23:
+ cli
+ pushl $0x0
+ pushl $0x17
+ jmp isr_handler
+
+.globl isr24
+.type isr24, @function
+isr24:
+ cli
+ pushl $0x0
+ pushl $0x18
+ jmp isr_handler
+
+.globl isr25
+.type isr25, @function
+isr25:
+ cli
+ pushl $0x0
+ pushl $0x19
+ jmp isr_handler
+
+.globl isr26
+.type isr26, @function
+isr26:
+ cli
+ pushl $0x0
+ pushl $0x1a
+ jmp isr_handler
+
+.globl isr27
+.type isr27, @function
+isr27:
+ cli
+ pushl $0x0
+ pushl $0x1b
+ jmp isr_handler
+
+.globl isr28
+.type isr28, @function
+isr28:
+ cli
+ pushl $0x0
+ pushl $0x1c
+ jmp isr_handler
+
+.globl isr29
+.type isr29, @function
+isr29:
+ cli
+ pushl $0x0
+ pushl $0x1d
+ jmp isr_handler
+
+.globl isr30
+.type isr30, @function
+isr30:
+ cli
+ pushl $0x0
+ pushl $0x1e
+ jmp isr_handler
+
+.globl isr31
+.type isr31, @function
+isr31:
+ cli
+ pushl $0x0
+ pushl $0x1f
+ jmp isr_handler
+
+.globl isr32
+.type isr32, @function
+isr32:
+ ;cli
+ pushl $0x0
+ pushl $0x20
+ jmp isr_handler
+
+.globl isr33
+.type isr33, @function
+isr33:
+ ;cli
+ pushl $0x0
+ pushl $0x21
+ jmp isr_handler
+
+.globl isr34
+.type isr34, @function
+isr34:
+ ;cli
+ pushl $0x0
+ pushl $0x22
+ jmp isr_handler
+
+.globl isr35
+.type isr35, @function
+isr35:
+ ;cli
+ pushl $0x0
+ pushl $0x23
+ jmp isr_handler
+
+.globl isr36
+.type isr36, @function
+isr36:
+ ;cli
+ pushl $0x0
+ pushl $0x24
+ jmp isr_handler
+
+.globl isr37
+.type isr37, @function
+isr37:
+ ;cli
+ pushl $0x0
+ pushl $0x25
+ jmp isr_handler
+
+.globl isr38
+.type isr38, @function
+isr38:
+ ;cli
+ pushl $0x0
+ pushl $0x26
+ jmp isr_handler
+
+.globl isr39
+.type isr39, @function
+isr39:
+ ;cli
+ pushl $0x0
+ pushl $0x27
+ jmp isr_handler
+
+.globl isr40
+.type isr40, @function
+isr40:
+ ;cli
+ pushl $0x0
+ pushl $0x28
+ jmp isr_handler
+
+.globl isr41
+.type isr41, @function
+isr41:
+ ;cli
+ pushl $0x0
+ pushl $0x29
+ jmp isr_handler
+
+.globl isr42
+.type isr42, @function
+isr42:
+ ;cli
+ pushl $0x0
+ pushl $0x2a
+ jmp isr_handler
+
+.globl isr43
+.type isr43, @function
+isr43:
+ ;cli
+ pushl $0x0
+ pushl $0x2b
+ jmp isr_handler
+
+.globl isr44
+.type isr44, @function
+isr44:
+ ;cli
+ pushl $0x0
+ pushl $0x2c
+ jmp isr_handler
+
+.globl isr45
+.type isr45, @function
+isr45:
+ ;cli
+ pushl $0x0
+ pushl $0x2d
+ jmp isr_handler
+
+.globl isr46
+.type isr46, @function
+isr46:
+ ;cli
+ pushl $0x0
+ pushl $0x2e
+ jmp isr_handler
+
+.globl isr47
+.type isr47, @function
+isr47:
+ ;cli
+ pushl $0x0
+ pushl $0x2f
+ jmp isr_handler
+
+.globl isr128
+.type isr128, @function
+isr128:
+ cli
+ pushl $0x0
+ pushl $0x80
+ jmp isr_handler
+
+.globl isr_handler
+.type isr_handler, @function
+isr_handler:
+ pushal
+ pushl %ds
+ xorl %eax, %eax
+ movw $0x10, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ cld
+ movl %esp, %eax
+ pushl %eax
+ call handle_interrupt
+ movl %eax, %esp
+ popl %ebx
+ movw %bx, %ds
+ movw %bx, %es
+ movw %bx, %fs
+ movw %bx, %gs
+ popal
+ add $0x8, %esp
+ iret
+
+.globl save_flags
+.type save_flags, @function
+save_flags:
+ pushf
+ popl %eax
+ movl 4(%esp), %ecx
+ movl %eax, (%ecx)
+ ret
+
+.globl load_flags
+.type load_flags, @function
+load_flags:
+ movl 4(%esp), %eax
+ pushl %eax
+ popf
+ ret
+
+.globl fetch_eip
+.type fetch_eip, @function
+fetch_eip:
+ popl %eax
+ jmp *%eax
+
diff --git a/src/include/common.h b/src/include/common.h
@@ -0,0 +1,72 @@
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#if __STDC_VERSION__ < 199901L
+#if __GNUC__ >= 2
+#define __func__ __FUNCTION__
+#else
+#define __func__ "<unknown>"
+#endif
+#endif
+
+#define BINCLUDE_DEBUG_CODE
+#if defined(BINCLUDE_DEBUG_CODE)
+#define DEBUG_CODE(statement) statement
+#else
+#define DEBUG_CODE(statement)
+#endif
+
+#define BSYSCALL_TRACE
+#if 1
+#undef BSYSCALL_TRACE
+#endif
+#if defined(BSYSCALL_TRACE)
+#define TRACE_SYSCALL(statement) statement
+#else
+#define TRACE_SYSCALL(statement)
+#endif
+
+#define MIN_ERRNO 1
+#define MAX_ERRNO 44
+#define SETERRNO_AND_RET(err, ret) ({ errno = (err); return (ret); })
+#define stringify(s) #s
+#define info(format, ...) printf(format, ##__VA_ARGS__)
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#define assert(cond) ({ if (unlikely(!(cond))) panic("Assertion '%s' failed!", #cond); })
+#define len(array) (sizeof(array) / sizeof(array[0]))
+#define offsetof(TYPE, MEMBER) ((size_t)__builtin_offsetof(TYPE, MEMBER))
+#define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) ); })
+#define panic(format, ...) panic_internal(__FILE__, __func__, __LINE__, format, ##__VA_ARGS__)
+
+typedef enum { false, true } bool;
+typedef uint32_t addr_t;
+
+extern void panic_internal(const char *file, const char *fn, uint32_t line, const char *fmt, ...);
+extern void hexdump(const void *ptr, size_t len);
+extern void stacktrace(int depth);
+
+static inline int
+IS_ERR(const void *ptr)
+{
+ return (int)ptr >= -MAX_ERRNO && (int)ptr <= -MIN_ERRNO;
+}
+
+static inline void *
+ERR_PTR(int error)
+{
+ return (void *)error;
+}
+
+static inline int
+PTR_ERR(const void *ptr)
+{
+ return (int)ptr;
+}
+
+#endif
+
diff --git a/src/include/elf.h b/src/include/elf.h
@@ -0,0 +1,183 @@
+#ifndef __ELF_H__
+#define __ELF_H__
+
+#include <stdint.h>
+
+enum {
+ ET_NONE,
+ ET_REL,
+ ET_EXEC,
+ ET_DYN,
+ ET_CORE,
+ ET_LOPROC = 0xff00,
+ ET_HIPROC = 0xffff
+};
+
+enum {
+ EV_NONE,
+ EV_CURRENT
+};
+
+enum {
+ EM_NONE,
+ EM_M32,
+ EM_SPARC,
+ EM_386,
+ EM_68K,
+ EM_88K,
+ EM_860,
+ EM_MIPS
+};
+
+enum {
+ EI_MAG0,
+ EI_MAG1,
+ EI_MAG2,
+ EI_MAG3,
+ EI_CLASS,
+ EI_DATA,
+ EI_VERSION,
+ EI_PAD,
+ EI_NIDENT = 16
+};
+
+enum {
+ ELFCLASSNONE,
+ ELFCLASS32,
+ ELFCLASS64
+};
+
+enum {
+ ELFDATANONE,
+ ELFDATA2LSB,
+ ELFDATA2MSB
+};
+
+enum {
+ SHT_NULL,
+ SHT_PROGBITS,
+ SHT_SYMTAB,
+ SHT_STRTAB,
+ SHT_RELA,
+ SHT_HASH,
+ SHT_DYNAMIC,
+ SHT_NOTE,
+ SHT_NOBITS,
+ SHT_REL,
+ SHT_SHLIB,
+ SHT_DYNSYM,
+ SHT_LOPROC = 0x70000000,
+ SHT_HIPROC = 0x7fffffff,
+ SHT_LOUSER = 0x80000000,
+ SHT_HIUSER = 0xffffffff
+};
+
+enum {
+ SHF_WRITE = 0x1,
+ SHF_ALLOC = 0x2,
+ SHF_EXECINSTR = 0x4,
+ SHF_MASKPROC = 0xf0000000
+};
+
+enum {
+ SHN_UNDEF,
+ SHN_LORESERVE = 0xff00,
+ SHN_LOPROC = 0xff00,
+ SHN_HIPROC = 0xff1f,
+ SHN_ABS = 0xfff1,
+ SHN_COMMON = 0xfff2,
+ SHN_HIRESERVE = 0xffff
+};
+
+enum {
+ STB_LOCAL,
+ STB_GLOBAL,
+ STB_WEAK,
+ STB_LOPROC = 13,
+ STB_HIPROC = 15
+};
+
+enum {
+ STT_NOTYPE,
+ STT_OBJECT,
+ STT_FUNC,
+ STT_SECTION,
+ STT_FILE,
+ STT_LOPROC = 13,
+ STT_HIPROC = 15
+};
+
+typedef uint32_t Elf32_Addr;
+typedef uint16_t Elf32_Half;
+typedef uint32_t Elf32_Off;
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+
+typedef struct {
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry;
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shtrndx;
+} Elf32_Ehdr;
+
+typedef struct {
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+typedef struct {
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} Elf32_Phdr;
+
+typedef struct {
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf32_Half st_shndx;
+} Elf32_Sym;
+
+typedef struct {
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+} Elf32_Rel;
+
+typedef struct {
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+ Elf32_Sword r_addend;
+} Elf32_Rela;
+
+extern int execve(const char *filename, char *const argv[], char *const envp[]);
+extern int prepare_elf(void);
+extern const char *find_symbol(uint32_t addr);
+extern void elfdump(uint32_t base_addr);
+
+#endif
+
diff --git a/src/include/errno.h b/src/include/errno.h
@@ -0,0 +1,111 @@
+/* POSIX error codes for system calls
+ *
+ * E2BIG : argument list too long
+ * EACCES : permission denied
+ * EAGAIN : resource temporarily unavailable
+ * EBADF : bad file descriptor
+ * EBADMSG : bad message
+ * EBUSY : device or resource busy
+ * ECANCELED : operation canceled
+ * ECHILD : no child processes
+ * EDEADLK : resource deadlock avoided
+ * EDOM : mathematics argument out of domain of function
+ * EEXIST : file exists
+ * EFAULT : bad address
+ * EFBIG : file too large
+ * EILSEQ : illegal byte sequence
+ * EINPROGRESS : operation in progress
+ * EINTR : interrupted function call
+ * EINVAL : invalid argument
+ * EIO : input/output error
+ * EISDIR : is a directory
+ * EMFILE : too many open files
+ * EMLINK : too many links
+ * EMSGSIZE : message too long
+ * ENAMETOOLONG: filename too long
+ * ENFILE : too many open files in system
+ * ENODEV : no such device
+ * ENOENT : no such file or directory
+ * ENOEXEC : exec format error
+ * ENOLCK : no locks available
+ * ENOMEM : not enough space
+ * ENOSPC : no space left on device
+ * ENOSYS : function not implemented
+ * ENOTDIR : not a directory
+ * ENOTEMPTY : directory not empty
+ * ENOTSUP : operation not supported
+ * ENOTTY : inappropriate I/O control
+ * ENXIO : no such device or address
+ * EPERM : operation not permitted
+ * EPIPE : broken pipe
+ * ERANGE : result too large
+ * EROFS : read-only file system
+ * ESPIPE : invalid seek
+ * ESRCH : no such process
+ * ETIMEDOUT : connection timed out
+ * EXDEV : improper link
+ */
+
+#ifndef __ERRNO_H__
+#define __ERRNO_H__
+
+#include <common.h>
+
+#define E2BIG 1
+#define EACCES 2
+#define EAGAIN 3
+#define EBADF 4
+#define EBADMSG 5
+#define EBUSY 6
+#define ECANCELED 7
+#define ECHILD 8
+#define EDEADLK 9
+#define EDOM 10
+#define EEXIST 11
+#define EFAULT 12
+#define EFBIG 13
+#define EILSEQ 14
+#define EINPROGRESS 15
+#define EINTR 16
+#define EINVAL 17
+#define EIO 18
+#define EISDIR 19
+#define EMFILE 20
+#define EMLINK 21
+#define EMSGSIZE 22
+#define ENAMETOOLONG 23
+#define ENFILE 24
+#define ENODEV 25
+#define ENOENT 26
+#define ENOEXEC 27
+#define ENOLCK 28
+#define ENOMEM 29
+#define ENOSPC 30
+#define ENOSYS 31
+#define ENOTDIR 32
+#define ENOTEMPTY 33
+#define ENOTSUP 34
+#define ENOTTY 35
+#define ENXIO 36
+#define EPERM 37
+#define EPIPE 38
+#define ERANGE 39
+#define EROFS 40
+#define ESPIPE 41
+#define ESRCH 42
+#define ETIMEDOUT 43
+#define EXDEV 44
+
+extern int errno;
+extern const char *sys_errlist [];
+
+static inline
+void kerror(int err)
+{
+ if (err < 1 || err > 44)
+ panic("Out of range!");
+ panic(sys_errlist[err - 1]);
+}
+
+#endif
+
diff --git a/src/include/ext2.h b/src/include/ext2.h
@@ -0,0 +1,301 @@
+#ifndef __EXT2_H__
+#define __EXT2_H__
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <list.h>
+
+#define O_RDONLY 0
+#define NR_MAX_OPEN_FILES 32
+#define EXT2_NAME_LEN 255
+
+#define S_IFMT 0170000 /* type of file */
+#define S_IFREG 0100000 /* regular */
+#define S_IFDIR 0040000 /* directory */
+#define S_IFBLK 0060000 /* block special */
+#define S_IFCHR 0020000 /* character special */
+#define S_IFIFO 0010000 /* fifo */
+
+#define S_ISUID 0004000 /* set user id on execution */
+#define S_ISGID 0002000 /* set group id on execution */
+
+#define S_IRWXU 0000700 /* read,write,execute perm: owner */
+#define S_IRUSR 0000400 /* read permission: owner */
+#define S_IWUSR 0000200 /* write permission: owner */
+#define S_IXUSR 0000100 /* execute/search permission: owner */
+#define S_IRWXG 0000070 /* read,write,execute perm: group */
+#define S_IRGRP 0000040 /* read permission: group */
+#define S_IWGRP 0000020 /* write permission: group */
+#define S_IXGRP 0000010 /* execute/search permission: group */
+#define S_IRWXO 0000007 /* read,write,execute perm: other */
+#define S_IROTH 0000004 /* read permission: other */
+#define S_IWOTH 0000002 /* write permission: other */
+#define S_IXOTH 0000001 /* execute/search permission: other */
+
+#define S_ISFIFO(m) (((m)&(S_IFMT)) == (S_IFIFO))
+#define S_ISDIR(m) (((m)&(S_IFMT)) == (S_IFDIR))
+#define S_ISCHR(m) (((m)&(S_IFMT)) == (S_IFCHR))
+#define S_ISBLK(m) (((m)&(S_IFMT)) == (S_IFBLK))
+#define S_ISREG(m) (((m)&(S_IFMT)) == (S_IFREG))
+
+enum file_state {
+ FILE_ALLOC,
+ FILE_NONE
+};
+
+enum file_type {
+ FILE_REG,
+ FILE_PIPE
+};
+
+enum fs_state {
+ EXT2_CLEAN = 1 << 0,
+ EXT2_FAULTY = 1 << 1,
+ EXT2_ORPHAN_REC = 1 << 2
+};
+
+enum fs_err_handling {
+ EXT2_CONT,
+ EXT2_REMNT_RO,
+ EXT2_PANIC
+};
+
+enum fs_creator {
+ EXT2_LINUX,
+ EXT2_HURD,
+ EXT2_MASIX,
+ EXT2_FREEBSD,
+ EXT2_LITES
+};
+
+enum fs_feat_compat {
+ EXT2_PREALLOCATE_DIR_BLOCKS = 1 << 0,
+ EXT2_AFS_EXIST = 1 << 1,
+ EXT2_HAS_JOURNAL = 1 << 2,
+ EXT2_INODES_EXTENDED = 1 << 3,
+ EXT2_CAN_RESIZE = 1 << 4,
+ EXT2_USE_HASH = 1 << 5
+};
+
+enum fs_feat_incompat {
+ EXT2_COMPRESSION = 1 << 0,
+ EXT2_DIR_HAS_TYPE = 1 << 1,
+ EXT2_NEEDS_RECOVERY = 1 << 2,
+ EXT2_USES_JOURNAL_DEVICE = 1 << 3
+};
+
+enum fs_feat_ro_compat {
+ EXT2_SPARSE_SUPER_AND_GDT = 1 << 0,
+ EXT2_LARGE_FILES = 1 << 1,
+ EXT2_DIR_B_TREES = 1 << 2
+};
+
+enum fs_file_mode_flags {
+ /* bits [0, 8] */
+ OX = 01,
+ OW = 02,
+ OR = 03,
+ GX = 010,
+ GW = 020,
+ GR = 040,
+ UX = 0100,
+ UW = 0200,
+ UR = 0400,
+ /* bits [9, 11] */
+ STICKY = 0x200,
+ SGID = 0x400,
+ SUID = 0x800,
+ /* bits [12, 15] */
+ FIFO_T = 0x1000,
+ CHDEV_T = 0x2000,
+ DIRECTORY_T = 0x4000,
+ BLOCK_T = 0x6000,
+ REGULAR_T = 0x8000,
+ SYM_T = 0xa000,
+ UNIX_SOCKET_T = 0xc000
+};
+
+enum fs_inode_flags {
+ EXT2_SEC_DEL = 1 << 0,
+ EXT2_KEEP_COPY_ON_DEL = 1 << 1,
+ EXT2_FILE_COMPRESSION = 1 << 2,
+ EXT2_SYNC = 1 << 3,
+ EXT2_IMMUTABLE = 1 << 4,
+ EXT2_APPEND_ONLY = 1 << 5,
+ EXT2_DUMP_EXCLUDE = 1 << 6,
+ EXT2_IGNORE_ATIME = 1 << 7,
+ EXT2_HASH_DIR = 1 << 8,
+ EXT2_DATA_JOURNALED_EXT3 = 1 << 9
+};
+
+enum fs_file_t {
+ EXT2_FT_UNKNOWN,
+ EXT2_FT_REG_FILE,
+ EXT2_FT_DIR,
+ EXT2_FT_CHRDEV,
+ EXT2_FT_BLKDEV,
+ EXT2_FT_FIFO,
+ EXT2_FT_SOCK,
+ EXT2_FT_SYMLINK,
+ EXT2_FT_MAX
+};
+
+struct ext2_superblock_t {
+ uint32_t nr_inodes;
+ uint32_t nr_blocks;
+ uint32_t nr_reserved_inodes;
+ uint32_t nr_free_blocks;
+ uint32_t nr_free_inodes;
+ uint32_t first_data_block;
+ uint32_t block_size; /* saved as the number of places to shift 1024 to the left */
+ uint32_t fragment_size; /* same as above */
+ uint32_t nr_blocks_per_group;
+ uint32_t nr_fragments_per_group;
+ uint32_t nr_inodes_per_group;
+ uint32_t last_mtime;
+ uint32_t last_wtime;
+ uint16_t mnt_count;
+ uint16_t max_mnt_count;
+ uint16_t magic;
+ uint16_t state;
+ uint16_t err_handling_method;
+ uint16_t minor_version;
+ uint32_t lastcheck;
+ uint32_t check_interval;
+ uint32_t creator_os;
+ uint32_t major_version;
+ uint16_t uid_for_reserved_blocks;
+ uint16_t gid_for_reserved_blocks;
+ uint32_t first_ino;
+ uint16_t inode_size;
+ uint16_t super_block_group;
+ uint32_t feat_compat;
+ uint32_t feat_incompat;
+ uint32_t feat_ro_compat;
+ char fs_id[16];
+ char volume_name[16];
+ char path_last_mount[64];
+ uint32_t algo_usage_bitmap;
+ uint8_t nr_blocks_preallocate_file;
+ uint8_t nr_blocks_preallocate_dir;
+ uint16_t unused1;
+ char journal_id[16];
+ uint32_t journal_inode;
+ uint32_t journal_dev;
+ uint32_t head_orphan_inode_list;
+ uint32_t hash_seed[4];
+ uint8_t default_hash_version;
+ uint8_t unused2;
+ uint16_t unused3;
+ uint32_t mount_options;
+ uint32_t first_metablock;
+ uint32_t reserved[190];
+} __attribute__ ((packed));
+
+struct ext2_gdt_t {
+ uint32_t addr_block_bitmap;
+ uint32_t addr_inode_bitmap;
+ uint32_t addr_inode_table;
+ uint16_t nr_free_blocks;
+ uint16_t nr_free_inodes;
+ uint16_t nr_dir_entries;
+ uint16_t unused;
+ uint32_t reserved[3];
+} __attribute__ ((packed));
+
+struct ext2_inode_t {
+ uint16_t file_mode;
+ uint16_t uid_low16;
+ uint32_t size_low32;
+ uint32_t atime;
+ uint32_t ctime;
+ uint32_t mtime;
+ uint32_t dtime;
+ uint16_t gid_low16;
+ uint16_t link_count;
+ uint32_t sector_count;
+ uint32_t flags;
+ uint32_t unused1;
+ char direct_blocks[48];
+ uint32_t single_indir_block;
+ uint32_t double_indir_block;
+ uint32_t triple_indir_block;
+ uint32_t gen_number;
+ uint32_t ext_attribute_block;
+ uint32_t size_upper32;
+ uint32_t addr_fragment;
+ uint8_t fragment_index;
+ uint8_t fragment_size;
+ uint16_t unused2;
+ uint16_t uid_upper16;
+ uint16_t gid_upper16;
+ uint32_t reserved;
+} __attribute__ ((packed));
+
+struct ext2_dir_t {
+ uint32_t inode;
+ uint16_t rec_length;
+ uint8_t name_length;
+ uint8_t file_t;
+ char filename[EXT2_NAME_LEN];
+} __attribute__ ((packed));
+
+struct file_t {
+ struct ext2_inode_t *f_inode;
+ ino_t f_inode_nr;
+ off_t f_off;
+ enum file_state f_state;
+ enum file_type f_type;
+ int f_refcount;
+ struct list_head f_listopen;
+};
+
+typedef struct DIR {
+ int fd;
+ uint32_t off;
+} DIR;
+
+struct dirent_t {
+ ino_t d_inode;
+ off_t d_off;
+ uint16_t d_namelen;
+ char d_name[EXT2_NAME_LEN + 1];
+};
+
+struct stat {
+ dev_t st_dev; /* ID of device containing file */
+ ino_t st_ino; /* inode number */
+ mode_t st_mode; /* protection */
+ nlink_t st_nlink; /* number of hard links */
+ uid_t st_uid; /* user ID of owner */
+ gid_t st_gid; /* group ID of owner */
+ dev_t st_rdev; /* device ID (if special file) */
+ off_t st_size; /* total size, in bytes */
+ blksize_t st_blksize; /* blocksize for file system I/O */
+ blkcnt_t st_blocks; /* number of 512B blocks allocated */
+ time_t st_atime; /* time of last access */
+ time_t st_mtime; /* time of last modification */
+ time_t st_ctime; /* time of last status change */
+};
+
+extern struct ext2_inode_t *get_root_inode(void);
+extern int ext2_mount(char *addr);
+extern void ext2_dump(void);
+extern int open(const char *pathname, int flags, mode_t mode);
+extern int creat(const char *pathname, mode_t mode);
+extern int close(int fd);
+extern ssize_t write(int fd, const void *buf, size_t count);
+extern ssize_t read(int fd, void *buf, size_t count);
+extern void closefds(void);
+extern DIR *opendir(const char *name);
+extern int closedir(DIR *dirp);
+extern struct dirent_t *readdir(DIR *dirp);
+extern int dup(int oldfd);
+extern int dup2(int oldfd, int newfd);
+extern int stat(const char *path, struct stat *buf);
+extern int fstat(int fd, struct stat *buf);
+extern int execve(const char *filename, char *const argv[], char *const envp[]);
+extern int fileclose(int fd);
+
+#endif
+
diff --git a/src/include/gdt.h b/src/include/gdt.h
@@ -0,0 +1,30 @@
+#ifndef __GDT_H__
+#define __GDT_H__
+
+#include <stdint.h>
+
+struct gdt_descriptor_t {
+ uint16_t limit_lo : 16;
+ uint16_t base_lo : 16;
+ uint8_t base_middle : 8;
+ uint8_t type : 4;
+ uint8_t s : 1;
+ uint8_t privilege_level : 2;
+ uint8_t segment_present : 1;
+ uint8_t limit_hi : 4;
+ uint8_t available : 1;
+ uint8_t l : 1;
+ uint8_t db : 1;
+ uint8_t granularity : 1;
+ uint8_t base_hi : 8;
+} __attribute__((packed));
+
+struct gdt_selector_t {
+ uint16_t limit;
+ uint32_t base;
+} __attribute__((packed));
+
+extern void initialize_gdt(void);
+
+#endif
+
diff --git a/src/include/heap.h b/src/include/heap.h
@@ -0,0 +1,16 @@
+#ifndef __HEAP_H__
+#define __HEAP_H__
+
+#include <sys/types.h>
+
+enum { KERNEL_HEAP = 0xd0000000, KERNEL_HEAP_END = 0xd8000000 };
+enum heap_cntl { DEFAULT };
+
+extern void *kmalloc(size_t size);
+extern void *kmalloc_ext(size_t size, enum heap_cntl flag);
+extern void kfree(void *ptr);
+extern void walk_heap_lists(void);
+extern void init_heap(void);
+
+#endif
+
diff --git a/src/include/idt.h b/src/include/idt.h
@@ -0,0 +1,96 @@
+#ifndef __IDT_H__
+#define __IDT_H__
+
+#include <stdint.h>
+
+#define DUMP_STACK_REGS(regs) \
+ ({ \
+ DEBUG_CODE(printf("unroll_esp = 0x%lx\n", regs.unroll_esp);) \
+ DEBUG_CODE(printf("ds = 0x%lx\n", regs.ds);) \
+ DEBUG_CODE(printf("edi = 0x%lx, esi = 0x%lx, ebp = 0x%lx, esp = 0x%lx, ebx = 0x%lx, edx = 0x%lx, ecx = 0x%lx, eax = 0x%lx\n", \
+ regs.edi, regs.esi, regs.ebp, regs.esp, regs.ebx, regs.edx, regs.ecx, regs.eax);) \
+ DEBUG_CODE(printf("int_no = 0x%lx, err_code = 0x%lx\n", regs.int_no, regs.err_code);) \
+ DEBUG_CODE(printf("eip = 0x%lx, cs = 0x%lx, eflags = 0x%lx\n", \
+ regs.eip, regs.cs, regs.eflags);) \
+ })
+
+struct trapframe_t {
+ uint32_t unroll_esp;
+ uint32_t ds; /* Data segment selector */
+ uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; /* Pushed by pusha. */
+ uint32_t int_no, err_code; /* Interrupt number and error code (if applicable) */
+ uint32_t eip, cs, eflags; /* Pushed by the processor automatically. I might need to add useresp and ss.*/
+} __attribute__ ((packed));
+
+struct idt_intr_gate {
+ uint16_t offset_lo : 16;
+ uint16_t selector : 16;
+ uint8_t all0 : 8;
+ uint8_t gate_size : 5; /* 0b0D110 */
+ uint8_t privilege_level : 2;
+ uint8_t segment_present : 1;
+ uint16_t offset_hi : 16;
+} __attribute__((packed));
+
+struct idt_selector {
+ uint16_t limit;
+ uint32_t base;
+} __attribute__ ((packed));
+
+typedef void (*isr_handler)(struct trapframe_t *regs);
+
+extern void isr0(void);
+extern void isr1(void);
+extern void isr2(void);
+extern void isr3(void);
+extern void isr4(void);
+extern void isr5(void);
+extern void isr6(void);
+extern void isr7(void);
+extern void isr8(void);
+extern void isr9(void);
+extern void isr10(void);
+extern void isr11(void);
+extern void isr12(void);
+extern void isr13(void);
+extern void isr14(void);
+extern void isr15(void);
+extern void isr16(void);
+extern void isr17(void);
+extern void isr18(void);
+extern void isr19(void);
+extern void isr20(void);
+extern void isr21(void);
+extern void isr22(void);
+extern void isr23(void);
+extern void isr24(void);
+extern void isr25(void);
+extern void isr26(void);
+extern void isr27(void);
+extern void isr28(void);
+extern void isr29(void);
+extern void isr30(void);
+extern void isr31(void);
+extern void isr32(void);
+extern void isr33(void);
+extern void isr34(void);
+extern void isr35(void);
+extern void isr36(void);
+extern void isr37(void);
+extern void isr38(void);
+extern void isr39(void);
+extern void isr40(void);
+extern void isr41(void);
+extern void isr42(void);
+extern void isr43(void);
+extern void isr44(void);
+extern void isr45(void);
+extern void isr46(void);
+extern void isr47(void);
+extern void isr128(void);
+extern void initialize_idt(void);
+extern uint32_t handle_interrupt(struct trapframe_t regs);
+extern int register_isr_handler(uint8_t index, isr_handler handler);
+
+#endif
+
diff --git a/src/include/kdb.h b/src/include/kdb.h
@@ -0,0 +1,10 @@
+#ifndef __KDB_H__
+#define __KDB_H__
+
+#include <idt.h>
+
+extern void set_trapframe(struct trapframe_t *tframe);
+extern void kdb_enter(void);
+
+#endif
+
diff --git a/src/include/keyboard.h b/src/include/keyboard.h
@@ -0,0 +1,10 @@
+#ifndef __KEYBOARD_H__
+#define __KEYBOARD_H__
+
+#include <stdint.h>
+
+extern void initialize_keyboard(void);
+extern int kbd_getchar(void);
+
+#endif
+
diff --git a/src/include/list.h b/src/include/list.h
@@ -0,0 +1,78 @@
+#ifndef __LIST_H__
+#define __LIST_H__
+
+#include <common.h>
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = pos->next)
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) } /* assign both next and prev to point to &name */
+
+struct list_head {
+ struct list_head *next;
+ struct list_head *prev;
+};
+
+static inline void
+INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+static inline void
+list_add(struct list_head *new, struct list_head *head)
+{
+ head->next->prev = new;
+ new->next = head->next;
+ new->prev = head;
+ head->next = new;
+}
+
+static inline void
+list_add_tail(struct list_head *new, struct list_head *head)
+{
+ head->prev->next = new;
+ new->next = head;
+ new->prev = head->prev;
+ head->prev = new;
+}
+
+static inline void
+list_del(struct list_head *entry)
+{
+ entry->prev->next = entry->next;
+ entry->next->prev = entry->prev;
+ entry->next = NULL;
+ entry->prev = NULL;
+}
+
+#endif
+
diff --git a/src/include/mm.h b/src/include/mm.h
@@ -0,0 +1,77 @@
+#ifndef __MM_H__
+#define __MM_H__
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <common.h>
+
+enum { PAGE_SIZE = 0x1000, PAGE_SHIFT = 12, PAGE_HEAP = 0xf0000000, PAGE_HEAP_SIZE = 0x4000000 };
+enum page_pa_fl { DONT_ALLOC_PHYS, ALLOC_PHYS, DONT_FREE_PHYS, FREE_PHYS };
+
+struct pte_t {
+ uint8_t present : 1;
+ uint8_t rw : 1;
+ uint8_t privilege : 1; /* user/supervisor */
+ uint8_t pwt : 1; /* if the bit is set write-through is enabled, otherwise write-back */
+ uint8_t pcd : 1; /* if the bit is set the page will not be cached */
+ uint8_t accessed : 1;
+ uint8_t dirty : 1;
+ uint8_t pat : 1; /* must be zero if pat is not supported */
+ uint8_t global : 1;
+ uint8_t ignore : 3;
+ uint32_t frame : 20;
+} __attribute__ ((packed));
+
+struct page_table_t {
+ struct pte_t pages[1024];
+} __attribute__ ((packed));
+
+struct pde_t {
+ uint8_t present : 1;
+ uint8_t rw : 1;
+ uint8_t privilege : 1; /* user/supervisor */
+ uint8_t pwt : 1; /* if the bit is set write-through is enabled, otherwise write-back */
+ uint8_t pcd : 1; /* if the bit is set the page will not be cached */
+ uint8_t accessed : 1;
+ uint8_t dirty : 1; /* ignored */
+ uint8_t page_size : 1; /* if the bit is set, the pages are 4mb in size (pse must be enabled), otherwise 4kb */
+ uint8_t ignore : 4;
+ uint32_t pt_addr : 20;
+} __attribute__ ((packed));
+
+struct page_directory_t {
+ struct pde_t ptables[1024];
+} __attribute__ ((packed));
+
+extern void switch_page_dir(struct page_directory_t *pagedir);
+extern int init_mm(void);
+extern int init_vm(void);
+extern void *palloc(size_t size);
+extern void pfree(void *addr, size_t size);
+extern uint32_t virt_to_phys(uint32_t virt_addr, bool *val);
+extern int mmap(uint32_t virt_addr, uint32_t phys_addr);
+extern int mmap_range(uint32_t virt_addr_start, uint32_t virt_addr_end);
+extern int unmap_range(uint32_t virt_addr_start, uint32_t virt_addr_end);
+extern int unmap(uint32_t virt_addr);
+extern void *sbrk(intptr_t incr);
+extern void flush_tlb(void);
+extern struct page_directory_t *clone_page_dir(void);
+extern void set_curr_page_dir(struct page_directory_t *page_dir);
+extern int init_page_pa_allocator(void);
+extern void *alloc_page_pa(uint32_t *frame, enum page_pa_fl flags);
+extern int free_page_pa(void *page, uint32_t *frame, enum page_pa_fl flags);
+extern void remove_proc_mappings(void);
+extern uint32_t get_num_free_frames(void);
+extern void dump_mappings(void);
+
+static inline uint32_t
+roundup_pagesize(uint32_t n)
+{
+ if (n % PAGE_SIZE)
+ n = (n + PAGE_SIZE) & ~(PAGE_SIZE - 1);
+ return n;
+}
+
+#endif
+
diff --git a/src/include/multiboot.h b/src/include/multiboot.h
@@ -0,0 +1,95 @@
+/* The magic number for the Multiboot header. */
+#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
+
+/* The flags for the Multiboot header. */
+#ifdef __ELF__
+#define MULTIBOOT_HEADER_FLAGS 0x00000003
+#else
+#define MULTIBOOT_HEADER_FLAGS 0x00010003
+#endif
+
+/* The magic number passed by a Multiboot-compliant boot loader. */
+#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
+
+/* The size of our stack (16KB). */
+#define STACK_SIZE 0x4000
+
+/* C symbol format. HAVE_ASM_USCORE is defined by configure. */
+#ifdef HAVE_ASM_USCORE
+#define EXT_C(sym) _ ## sym
+#else
+#define EXT_C(sym) sym
+#endif
+
+#ifndef ASM
+/* Do not include here in boot.S. */
+
+/* Types. */
+
+/* The Multiboot header. */
+typedef struct multiboot_header {
+ unsigned long magic;
+ unsigned long flags;
+ unsigned long checksum;
+ unsigned long header_addr;
+ unsigned long load_addr;
+ unsigned long load_end_addr;
+ unsigned long bss_end_addr;
+ unsigned long entry_addr;
+} multiboot_header_t;
+
+/* The symbol table for a.out. */
+typedef struct aout_symbol_table {
+ unsigned long tabsize;
+ unsigned long strsize;
+ unsigned long addr;
+ unsigned long reserved;
+} aout_symbol_table_t;
+
+/* The section header table for ELF. */
+typedef struct elf_section_header_table {
+ unsigned long num;
+ unsigned long size;
+ unsigned long addr;
+ unsigned long shndx;
+} elf_section_header_table_t;
+
+/* The Multiboot information. */
+typedef struct multiboot_info {
+ unsigned long flags;
+ unsigned long mem_lower;
+ unsigned long mem_upper;
+ unsigned long boot_device;
+ unsigned long cmdline;
+ unsigned long mods_count;
+ unsigned long mods_addr;
+ union {
+ aout_symbol_table_t aout_sym;
+ elf_section_header_table_t elf_sec;
+ } u;
+
+ unsigned long mmap_length;
+ unsigned long mmap_addr;
+} multiboot_info_t;
+
+/* The module structure. */
+typedef struct module {
+ unsigned long mod_start;
+ unsigned long mod_end;
+ unsigned long string;
+ unsigned long reserved;
+} module_t;
+
+/* The memory map. Be careful that the offset 0 is base_addr_low
+ but no size. */
+typedef struct memory_map {
+ unsigned long size;
+ unsigned long base_addr_low;
+ unsigned long base_addr_high;
+ unsigned long length_low;
+ unsigned long length_high;
+ unsigned long type;
+} memory_map_t;
+
+#endif
+
diff --git a/src/include/pci.h b/src/include/pci.h
@@ -0,0 +1,73 @@
+#ifndef __PCI_H__
+#define __PCI_H__
+
+#include <stdint.h>
+#include <list.h>
+
+enum {
+ CONFIG_ADDRESS = 0xcf8,
+ CONFIG_DATA = 0xcfc,
+ PCI_NO_DEV = 0xffffffff
+};
+
+struct pci_config_addr_t {
+ uint8_t reg_num : 8;
+ uint8_t func_num : 3;
+ uint8_t dev_num : 5;
+ uint8_t bus_num : 8;
+ uint8_t reserved : 7;
+ uint8_t enable_bit : 1;
+} __attribute__ ((packed));
+
+union pci_config_space_t {
+ struct {
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint16_t command;
+ uint16_t status;
+ uint8_t rev_id;
+ uint8_t prog_if;
+ uint8_t subclass;
+ uint8_t class;
+ uint8_t cachelsz;
+ uint8_t latency_timer;
+ uint8_t header_type;
+ uint8_t bist;
+ uint32_t bar0, bar1, bar2, bar3, bar4, bar5;
+ uint32_t cardbus_cis_reg;
+ uint16_t sub_vendor_id;
+ uint16_t sub_id;
+ uint32_t exp_rom_addr;
+ uint16_t caps;
+ uint16_t reserved0;
+ uint32_t reserved1;
+ uint8_t irq;
+ uint8_t int_pin;
+ uint8_t min_grant;
+ uint8_t max_latency;
+ } __attribute__((packed)) type0;
+};
+
+struct pci_dev_t;
+
+struct pci_bus_t {
+ struct list_head pci_dev_list;
+ struct list_head pci_bus_list;
+};
+
+struct pci_dev_t {
+ union pci_config_space_t *cspace;
+ struct pci_bus_t *bus;
+ struct list_head list;
+ int busn;
+ int devn;
+};
+
+extern uint32_t pci_read32(struct pci_config_addr_t *addr);
+extern uint32_t pci_init(void);
+extern int pci_enumerate(void);
+extern void lspci(void);
+extern struct pci_dev_t * get_pci_dev(uint16_t vendor_id, uint16_t device_id);
+
+#endif
+
diff --git a/src/include/pic.h b/src/include/pic.h
@@ -0,0 +1,12 @@
+#ifndef __PIC_H__
+#define __PIC_H__
+
+#include <stdint.h>
+
+extern void remap_pic(void);
+extern void enable_irq(uint32_t irq);
+extern void disable_irq(uint32_t irq);
+extern void pic_eoi(uint32_t int_no);
+
+#endif
+
diff --git a/src/include/pipe.h b/src/include/pipe.h
@@ -0,0 +1,15 @@
+#ifndef __PIPE_H__
+#define __PIPE_H__
+
+#include <sys/types.h>
+
+enum {
+ PIPE_SIZ = 8192
+};
+
+extern int pipe(int pipefd[2]);
+extern ssize_t piperead(int fd, void *buf, size_t count);
+extern ssize_t pipewrite(int fd, const void *buf, size_t count);
+
+#endif
+
diff --git a/src/include/rtc.h b/src/include/rtc.h
@@ -0,0 +1,13 @@
+#ifndef __RTC_H__
+#define __RTC_H__
+
+#include <stdint.h>
+
+extern volatile uint32_t systimer;
+
+extern void init_rtc(uint32_t freq);
+extern void sleep(uint32_t seconds);
+extern void msleep(uint32_t msec);
+
+#endif
+
diff --git a/src/include/rtl8139.h b/src/include/rtl8139.h
@@ -0,0 +1,10 @@
+#ifndef __RTL8139_H__
+#define __RTL8139_H__
+
+#include <stdint.h>
+
+extern int rtl8139_init(void);
+extern const uint8_t *get_mac_addr(void);
+
+#endif
+
diff --git a/src/include/serial.h b/src/include/serial.h
@@ -0,0 +1,12 @@
+#ifndef __SERIAL_H__
+#define __SERIAL_H__
+
+#define COM_PORT 0x3f8
+
+extern void serial_init(void);
+extern int serial_dump(const char *s, ...);
+extern int serial_avail(void);
+extern int serial_putchar(int c);
+
+#endif
+
diff --git a/src/include/syscall.h b/src/include/syscall.h
@@ -0,0 +1,258 @@
+#ifndef __SYSCALL_H__
+#define __SYSCALL_H__
+
+#include <idt.h>
+#include <common.h>
+
+#define sys_exit(status) \
+ ({ \
+ int __num = __NR_exit, err_code = status; \
+ asm volatile ("int $0x80" :: "a"(__num), "b"(err_code)); \
+ })
+
+#define sys_fork() \
+ ({ \
+ int __num = __NR_fork; \
+ pid_t __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num)); \
+ __ret; \
+ })
+
+#define sys_waitpid(pid, status, options) \
+ ({ \
+ int __num = __NR_waitpid, *__status = status, __options = options; \
+ pid_t __pid = pid, __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__pid), "c"(__status), "d"(__options)); \
+ __ret; \
+ })
+
+#define sys_read(fd, buf, count) \
+ ({ \
+ int __num = __NR_read, __fd = fd; \
+ ssize_t __ret; \
+ void *__buf = buf; \
+ size_t __count = count; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__fd), "c"(__buf), "d"(__count)); \
+ __ret; \
+ })
+
+#define sys_write(fd, buf, count) \
+ ({ \
+ int __num = __NR_write, __fd = fd; \
+ ssize_t __ret; \
+ void *__buf = buf; \
+ size_t __count = count; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__fd), "c"(__buf), "d"(__count)); \
+ __ret; \
+ })
+
+#define sys_reschedule() \
+ ({ \
+ int __num = __NR_reschedule; \
+ asm volatile ("int $0x80" :: "a"(__num)); \
+ })
+
+#define sys_open(pathname, flags, mode) \
+ ({ \
+ int __num = __NR_open, __flags = flags, __ret; \
+ const char *__pathname = pathname; \
+ mode_t __mode = mode; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__pathname), "c"(__flags), "d"(__mode)); \
+ __ret; \
+ })
+
+#define sys_creat(pathname, mode) \
+ ({ \
+ int __num = __NR_creat, __ret; \
+ mode_t __mode = mode; \
+ const char *__pathname = pathname; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__pathname), "c"(__mode)); \
+ __ret; \
+ })
+
+#define sys_close(fd) \
+ ({ \
+ int __num = __NR_close, __ret; \
+ int __fd = fd; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__fd)); \
+ __ret; \
+ })
+
+#define sys_isatty(fd) \
+ ({ \
+ int __num = __NR_isatty, __ret, __fd = fd; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__fd)); \
+ __ret; \
+ })
+
+#define sys_getpid() \
+ ({ \
+ int __num = __NR_getpid; \
+ pid_t __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num)); \
+ __ret; \
+ })
+
+#define sys_getppid() \
+ ({ \
+ int __num = __NR_getppid; \
+ pid_t __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num)); \
+ __ret; \
+ })
+
+#define sys_readdir(dir) \
+ ({ \
+ int __num = __NR_readdir; \
+ DIR *__dir = dir; \
+ struct dirent_t *__ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__dir)); \
+ __ret; \
+ })
+
+#define sys_dup(oldfd) \
+ ({ \
+ int __num = __NR_dup, __oldfd = oldfd, __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__oldfd)); \
+ __ret; \
+ })
+
+#define sys_dup2(oldfd, newfd) \
+ ({ \
+ int __num = __NR_dup, __oldfd = oldfd, __newfd = newfd, __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__oldfd), "c"(__newfd)); \
+ __ret; \
+ })
+
+#define sys_stat(path, stbuf) \
+ ({ \
+ int __num = __NR_stat, __ret; \
+ const char *__path = path; \
+ struct stat *__buf = stbuf; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__path), "c"(__buf)); \
+ __ret; \
+ })
+
+#define sys_fstat(fd, stbuf) \
+ ({ \
+ int __num = __NR_fstat, __ret, __fd = fd; \
+ struct stat *__buf = stbuf; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__fd), "c"(__buf)); \
+ __ret; \
+ })
+
+#define sys_execve(filename, argv, envp) \
+ ({ \
+ int __num = __NR_execve, __ret; \
+ const char *__filename = filename; \
+ char **const __argv = argv; \
+ char **const __envp = envp; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__filename), "c"(__argv), "d"(__envp)); \
+ __ret; \
+ })
+
+#define sys_seeder() \
+ ({ \
+ int __num = __NR_seeder, __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num)); \
+ __ret; \
+ })
+
+#define sys_sbrk(incr) \
+ ({ \
+ int __num = __NR_sbrk, __ret; \
+ intptr_t __incr = incr; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__incr)); \
+ __ret; \
+ })
+
+#define sys_getuid() \
+ ({ \
+ int __num = __NR_getuid; \
+ uid_t __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num)); \
+ __ret; \
+ })
+
+#define sys_setuid(uid) \
+ ({ \
+ int __num = __NR_setuid, __ret; \
+ uid_t __uid = uid; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__uid)); \
+ __ret; \
+ })
+
+#define sys_getgid() \
+ ({ \
+ int __num = __NR_getgid; \
+ uid_t __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num)); \
+ __ret; \
+ })
+
+#define sys_setgid(gid) \
+ ({ \
+ int __num = __NR_setgid, __ret; \
+ uid_t __gid = gid; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__gid)); \
+ __ret; \
+ })
+
+#define sys_suspend_task(channel) \
+ ({ \
+ int __num = __NR_suspend_task, __ret; \
+ void * __channel = channel; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__channel)); \
+ __ret; \
+ })
+
+#define sys_resume_task(channel) \
+ ({ \
+ int __num = __NR_resume_task; \
+ void * __channel = channel; \
+ asm volatile ("int $0x80" :: "a"(__num), "b"(__channel)); \
+ })
+
+#define sys_pipe(pipefds) \
+ ({ \
+ int __num = __NR_pipe, __ret; \
+ int *__pipefds = pipefds; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__pipefds)); \
+ __ret; \
+ })
+
+#define SYSCALL_NR 30
+#define __NR_exit 1
+#define __NR_fork 2
+#define __NR_read 3
+#define __NR_write 4
+#define __NR_open 5
+#define __NR_close 6
+#define __NR_waitpid 7
+#define __NR_creat 8
+#define __NR_link 9
+#define __NR_unlink 10
+#define __NR_execve 11
+#define __NR_reschedule 12
+#define __NR_isatty 13
+#define __NR_getpid 14
+#define __NR_getppid 15
+#define __NR_readdir 16
+#define __NR_dup 17
+#define __NR_dup2 18
+#define __NR_stat 19
+#define __NR_fstat 20
+#define __NR_seeder 21
+#define __NR_sbrk 22
+#define __NR_getuid 23
+#define __NR_setuid 24
+#define __NR_getgid 25
+#define __NR_setgid 26
+#define __NR_suspend_task 27
+#define __NR_resume_task 28
+#define __NR_pipe 29
+
+extern void syscall_dispatcher(struct trapframe_t *regs);
+
+#endif
+
diff --git a/src/include/tss.h b/src/include/tss.h
@@ -0,0 +1,141 @@
+#ifndef __TSS_H__
+#define __TSS_H__
+
+#include <stdint.h>
+#include <idt.h>
+#include <mm.h>
+#include <list.h>
+#include <ext2.h>
+#include <x86.h>
+#include <sys/types.h>
+#include <serial.h>
+
+#define DUMP_CSWITCH_FRAME(frame) \
+ ({ \
+ DEBUG_CODE(serial_dump("ds = 0x%lx\n", frame->ds);) \
+ DEBUG_CODE(serial_dump("edi = 0x%lx, esi = 0x%lx, ebp = 0x%lx, esp = 0x%lx, ebx = 0x%lx, edx = 0x%lx, ecx = 0x%lx, eax = 0x%lx\n", \
+ frame->edi, frame->esi, frame->ebp, frame->esp, frame->ebx, frame->edx, frame->ecx, frame->eax);) \
+ DEBUG_CODE(serial_dump("int_no = 0x%lx, err_code = 0x%lx\n", frame->int_no, frame->err_code);) \
+ DEBUG_CODE(serial_dump("eip = 0x%lx, cs = 0x%lx, eflags = 0x%lx\n", \
+ frame->eip, frame->cs, frame->eflags);) \
+ })
+
+#define TASK_STACK_SIZE (2048 * sizeof(uint32_t))
+#define WNOHANG 1
+
+enum task_state_t {
+ TASK_ZOMBIE,
+ TASK_SLEEPING,
+ TASK_RUNNABLE,
+ TASK_RUNNING
+};
+
+enum task_fl {
+ KERNEL_PROCESS = 1,
+ USER_PROCESS
+};
+
+struct tss_t {
+ uint32_t link;
+ uint32_t esp0;
+ uint32_t ss0;
+ uint32_t esp1;
+ uint32_t ss1;
+ uint32_t esp2;
+ uint32_t ss2;
+ uint32_t cr3;
+ uint32_t eip;
+ uint32_t eflags;
+ uint32_t eax;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t ebx;
+ uint32_t esp;
+ uint32_t ebp;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t es;
+ uint32_t cs;
+ uint32_t ss;
+ uint32_t ds;
+ uint32_t fs;
+ uint32_t gs;
+ uint32_t ldt;
+ uint16_t trace_bitmap;
+ uint16_t iomap;
+} __attribute__ ((packed));
+
+struct cswitch_frame_t {
+ uint32_t ds; /* Data segment selector */
+ uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; /* Pushed by pusha. */
+ uint32_t int_no, err_code; /* Interrupt number and error code (if applicable) */
+ uint32_t eip, cs, eflags; /* Pushed by the processor automatically. I might need to add useresp and ss.*/
+} __attribute__ ((packed));
+
+struct tss_descriptor_t {
+ uint16_t limit_lo : 16;
+ uint16_t base_lo : 16;
+ uint8_t base_middle : 8;
+ uint8_t type : 4; /* 1001b inactive, 1011b busy */
+ uint8_t s : 1; /* zero */
+ uint8_t privilege_level : 2;
+ uint8_t segment_present : 1;
+ uint8_t limit_hi : 4;
+ uint8_t available : 1;
+ uint8_t l : 1; /* zero */
+ uint8_t db : 1; /* zero */
+ uint8_t granularity : 1; /* must be zero */
+ uint8_t base_hi : 8;
+} __attribute__ ((packed));
+
+struct mmap_region {
+ uint32_t base_addr;
+ uint32_t size;
+ struct list_head l_region;
+};
+
+struct task_t {
+ uint32_t esp, old_esp;
+ enum task_state_t state, old_state;
+ struct page_directory_t *page_dir;
+ uint32_t *stack;
+ char *name;
+ enum task_fl flags;
+ struct list_head q_task;
+ pid_t pid;
+ int status;
+ struct task_t *parent;
+ struct cswitch_frame_t *cf;
+ struct ext2_inode_t *cdir;
+ struct file_t *fdtable[NR_MAX_OPEN_FILES];
+ char *pipebufs[NR_MAX_OPEN_FILES];
+ uid_t uid;
+ gid_t gid;
+ uid_t fuid;
+ gid_t fgid;
+ struct list_head l_regions;
+};
+
+extern void ps(void);
+extern void kick_tss(void);
+extern void remove_task(struct task_t *task);
+extern void add_task(struct task_t *task);
+extern struct task_t *create_kthread(const char *name, void *routine);
+extern struct task_t *current;
+extern int init_tss(void);
+extern void schedule(void);
+extern int fork(void);
+extern pid_t waitpid(pid_t pid, int *status, int options);
+extern void suspend_task(void *channel);
+extern int resume_task(void *channel);
+extern void freeze_tasks(void);
+extern void unfreeze_tasks(void);
+extern uid_t getuid(void);
+extern int setuid(uid_t uid);
+extern gid_t getgid(void);
+extern int setgid(gid_t gid);
+
+extern struct task_t *curr_proc;
+
+#endif
+
diff --git a/src/include/tty.h b/src/include/tty.h
@@ -0,0 +1,57 @@
+#ifndef __TTY_H__
+#define __TTY_H__
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <tss.h>
+
+enum vga_defs {
+ FRAMEBUFFER_ADDR = 0xb8000,
+ BUF_HEIGHT = 25,
+ BUF_WIDTH = 80
+};
+
+enum vga_colours {
+ BLACK,
+ BLUE,
+ GREEN,
+ CYAN,
+ RED,
+ MAGENTA,
+ BROWN,
+ LIGHT_GREY,
+ DARK_GREY,
+ LIGHT_BLUE,
+ LIGHT_GREEN,
+ LIGHT_CYAN,
+ LIGHT_RED,
+ LIGHT_MAGENTA,
+ LIGHT_BROWN,
+ WHITE
+};
+
+extern unsigned short cursor_x;
+extern unsigned short cursor_y;
+extern volatile unsigned char *framebuffer;
+extern enum vga_colours curr_col;
+
+extern void ccurr_col(enum vga_colours bg, enum vga_colours fg);
+extern void clear_scr(void);
+extern void gotoxy(unsigned short newy, unsigned short newx);
+extern void scroll(void);
+extern void erase_line(int y);
+extern void blink(void);
+extern void update_cursor(uint16_t row, uint16_t col);
+extern int tty_putchar(int c);
+extern ssize_t tty_read(void *buf, size_t count);
+extern int raw_tty_read(void);
+extern void *tty_get_sleep_chan(void);
+extern void attach_tty(struct task_t *ctask);
+extern void tty_suspend(void);
+extern void tty_resume(void);
+extern int is_ctrl_task(struct task_t *ctask);
+extern struct task_t *tty_get_ctrl_task(void);
+extern int is_tty_attached(void);
+
+#endif
+
diff --git a/src/include/version.h b/src/include/version.h
@@ -0,0 +1,7 @@
+#ifndef __VERSION_H__
+#define __VERSION_H__
+#define USER "rip"
+#define DATE "Sat May 29 23:54:31 BST 2010"
+#define HOST "ripbox"
+#define REVISION "573"
+#endif
diff --git a/src/include/x86.h b/src/include/x86.h
@@ -0,0 +1,137 @@
+#ifndef __X86_H__
+#define __X86_H__
+
+#include <stdint.h>
+#include <common.h>
+
+/* useful macros */
+#define GET_ESP(esp) asm volatile ("movl %%esp, %0" : "=r"(esp));
+#define PUT_ESP(esp) asm volatile ("movl %0, %%esp" :: "r"(esp));
+#define GET_EBP(ebp) asm volatile ("movl %%ebp, %0" : "=r"(ebp));
+#define PUT_EBP(ebp) asm volatile ("movl %0, %%ebp" :: "r"(ebp));
+
+extern void save_flags(uint32_t *state);
+extern void load_flags(uint32_t state);
+extern uint32_t fetch_eip(void);
+extern void do_cpuid(void);
+
+typedef int spinlock_t;
+
+static inline void
+cli(void)
+{
+ asm volatile ("cli");
+}
+
+static inline void
+sti(void)
+{
+ asm volatile ("sti");
+}
+
+static inline bool
+ints_on(void)
+{
+ uint32_t state;
+
+ save_flags(&state);
+ return state & (1 << 9);
+}
+
+static inline void
+hlt(void)
+{
+ asm volatile ("hlt");
+}
+
+static inline void
+jmp(uint32_t addr)
+{
+ asm volatile ("call *%0" :: "a"(addr));
+}
+
+static inline void
+outb(uint16_t port, uint8_t val)
+{
+ asm volatile ("outb %0, %1" :: "a"(val), "Nd"(port));
+}
+
+static inline void
+outw(uint16_t port, uint16_t val)
+{
+ asm volatile ("outw %0, %1" :: "a"(val), "Nd"(port));
+}
+
+static inline void
+outl(uint16_t port, uint32_t val)
+{
+ asm volatile ("outl %0, %1" :: "a"(val), "Nd"(port));
+}
+
+static inline uint8_t
+inb(uint16_t port)
+{
+ uint8_t ret;
+
+ asm volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
+ return ret;
+}
+
+static inline uint16_t
+inw(uint16_t port)
+{
+ uint16_t ret;
+
+ asm volatile ("inw %1, %0" : "=a"(ret) : "Nd"(port));
+ return ret;
+}
+
+static inline uint32_t
+inl(uint16_t port)
+{
+ uint32_t ret;
+
+ asm volatile ("inl %1, %0" : "=a"(ret) : "Nd"(port));
+ return ret;
+}
+
+static inline uint32_t
+read_cr3(void)
+{
+ uint32_t cr3;
+
+ asm volatile ("movl %%cr3, %0" : "=r"(cr3));
+ return cr3;
+}
+
+static inline void
+initspinlock(spinlock_t *spinlock)
+{
+ assert(spinlock != NULL);
+ __sync_lock_release(spinlock);
+}
+
+static inline void
+acquire(spinlock_t *spinlock)
+{
+ assert(spinlock != NULL);
+ while (__sync_lock_test_and_set(spinlock, 1) == 1)
+ ;
+}
+
+static inline int
+try_acquire(spinlock_t *spinlock)
+{
+ assert(spinlock != NULL);
+ return __sync_lock_test_and_set(spinlock, 1);
+}
+
+static inline void
+release(spinlock_t *spinlock)
+{
+ assert(spinlock != NULL);
+ __sync_lock_release(spinlock);
+}
+
+#endif
+
diff --git a/src/libc/Makefile-part b/src/libc/Makefile-part
@@ -0,0 +1 @@
+obj += src/libc/stdio.o src/libc/stdlib.o src/libc/string.o src/libc/vsprintf.o
diff --git a/src/libc/ctype.h b/src/libc/ctype.h
@@ -0,0 +1,59 @@
+#ifndef __CTYPE_H__
+#define __CTYPE_H__
+
+static inline int
+isupper(int c)
+{
+ return (c >= 'A' && c <= 'Z');
+}
+
+static inline int
+islower(int c)
+{
+ return (c >= 'a' && c <= 'z');
+}
+
+static inline int
+isalpha(int c)
+{
+ return (isupper(c) || islower(c));
+}
+
+static inline int
+isdigit(int c)
+{
+ return (c >= '0' && c <= '9');
+}
+
+static inline int
+isxdigit(int c)
+{
+ return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
+}
+
+static inline int
+isspace(int c)
+{
+ return (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v');
+}
+
+static inline int
+isblank(int c)
+{
+ return (c == ' ' || c == '\t');
+}
+
+static inline int
+isalnum(int c)
+{
+ return (isalpha(c) || isdigit(c));
+}
+
+static inline int
+isprint(int c)
+{
+ return ((c > 32 && c < 127) || isspace(c));
+}
+
+#endif
+
diff --git a/src/libc/stdarg.h b/src/libc/stdarg.h
@@ -0,0 +1,11 @@
+#ifndef __STDARG_H__
+#define __STDARG_H__
+
+#define va_start(v, l) __builtin_va_start(v, l)
+#define va_arg(v, l) __builtin_va_arg(v, l)
+#define va_end(v) __builtin_va_end(v)
+#define va_copy(d, s) __builtin_va_copy(d, s)
+typedef __builtin_va_list va_list;
+
+#endif
+
diff --git a/src/libc/stdint.h b/src/libc/stdint.h
@@ -0,0 +1,16 @@
+#ifndef __STDINT_H__
+#define __STDINT_H__
+
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int int16_t;
+typedef unsigned short int uint16_t;
+typedef signed long int int32_t;
+typedef unsigned long int uint32_t;
+typedef signed long long int int64_t;
+typedef unsigned long long int uint64_t;
+typedef int32_t intptr_t;
+typedef uint32_t uintptr_t;
+
+#endif
+
diff --git a/src/libc/stdio.c b/src/libc/stdio.c
@@ -0,0 +1,60 @@
+/*
+ * libc/stdio.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <tty.h>
+#include <stdio.h>
+#include <string.h>
+#include <x86.h>
+
+int
+putchar(int c)
+{
+ uint32_t state;
+
+ save_flags(&state);
+ cli();
+ c = tty_putchar(c);
+ load_flags(state);
+ return c;
+}
+
+int
+printf(const char *fmt, ...)
+{
+ char buffer[512], *ptr;
+ va_list ap;
+ int c;
+ uint32_t state;
+
+ save_flags(&state);
+ cli();
+ va_start(ap, fmt);
+ vsprintf(buffer, fmt, ap);
+ va_end(ap);
+ ptr = buffer;
+ while (*ptr) {
+ putchar(*ptr++);
+ ++c;
+ }
+ load_flags(state);
+ return c;
+}
+
+int
+puts(const char *s)
+{
+ uint32_t state;
+
+ save_flags(&state);
+ cli();
+ const char *ptr = s;
+ while (*ptr)
+ putchar(*ptr++);
+ putchar('\n');
+ load_flags(state);
+ return (int)(ptr - s);
+}
+
diff --git a/src/libc/stdio.h b/src/libc/stdio.h
@@ -0,0 +1,15 @@
+#ifndef __STDIO_H__
+#define __STDIO_H__
+
+#include <stdarg.h>
+
+#define NULL ((void *)0)
+#define BUFSIZ 8192
+
+extern int putchar(int c);
+extern int printf(const char *fmt, ...);
+extern int puts(const char *s);
+extern int vsprintf(char *buf, const char *fmt, va_list args);
+
+#endif
+
diff --git a/src/libc/stdlib.c b/src/libc/stdlib.c
@@ -0,0 +1,143 @@
+/*
+ * libc/stdlib.c
+ *
+ * Copyright (C) 2009 stateless
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+void
+itoa(long int num, char *buffer, int base)
+{
+ static char hex[] = "0123456789abcdef";
+ char *ptr = buffer, tmp, *beg = buffer;
+ int rem;
+ unsigned int uns;
+
+ if (base == 'x') {
+ unsigned long n = num;
+ do {
+ rem = n % 16;
+ *ptr++ = hex[rem];
+ n /= 16;
+ } while (n); *ptr = '\0'; --ptr;
+ } else {
+ if (base == 'd' && num < 0) {
+ *ptr++ = '-'; num = -num;
+ ++beg;
+ }
+ uns = (unsigned int)num;
+ do {
+ rem = uns % 10;
+ *ptr++ = rem + '0';
+ uns /= 10;
+ } while (uns); *ptr = '\0'; --ptr;
+ }
+ while (ptr >= beg) {
+ tmp = *beg;
+ *beg = *ptr;
+ *ptr = tmp;
+ --ptr;
+ ++beg;
+ }
+}
+
+/*
+ * Copyright (c) 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long
+strtoul(const char *nptr, char **endptr, int base)
+{
+ const char *s;
+ unsigned long acc, cutoff;
+ int c;
+ int neg, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = (unsigned char) * s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+
+ cutoff = 0xffffffff / (unsigned long)base;
+ cutlim = 0xffffffff % (unsigned long)base;
+ for (acc = 0, any = 0;; c = (unsigned char) * s++) {
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0)
+ continue;
+ if (acc > cutoff || (acc == cutoff && c > cutlim)) {
+ any = -1;
+ acc = 0xffffffff;
+ errno = ERANGE;
+ } else {
+ any = 1;
+ acc *= (unsigned long)base;
+ acc += c;
+ }
+ }
+ if (neg && any > 0)
+ acc = -acc;
+ if (endptr != 0)
+ *endptr = (char *) (any ? s - 1 : nptr);
+ return (acc);
+}
+
diff --git a/src/libc/stdlib.h b/src/libc/stdlib.h
@@ -0,0 +1,8 @@
+#ifndef __STDLIB_H__
+#define __STDLIB_H__
+
+extern void itoa(long int num, char *buffer, int base /* should be 'd', 'u' or 'x' */);
+extern unsigned long strtoul(const char *nptr, char **endptr, int base);
+
+#endif
+
diff --git a/src/libc/string.c b/src/libc/string.c
@@ -0,0 +1,135 @@
+/* This file is released under the GPL v2 public license */
+
+#include <string.h>
+
+void *
+memcpy(void *dest, const void *src, size_t n)
+{
+ char *tmp = dest;
+ const char *s = src;
+
+ while (n--)
+ *tmp++ = *s++;
+ return dest;
+}
+
+void *
+memmove(void *dest, const void *src, size_t count)
+{
+ char *tmp;
+ const char *s;
+
+ if (dest <= src) {
+ tmp = dest;
+ s = src;
+ while (count--)
+ *tmp++ = *s++;
+ } else {
+ tmp = dest;
+ tmp += count;
+ s = src;
+ s += count;
+ while (count--)
+ *--tmp = *--s;
+ }
+ return dest;
+}
+
+void *
+memset(void *s, int c, size_t n)
+{
+ char *ptr = s;
+ while (n--)
+ *ptr++ = c;
+ return s;
+}
+
+int
+memcmp(const void *cs, const void *ct, size_t count)
+{
+ const unsigned char *su1, *su2;
+ int res = 0;
+
+ for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+ if ((res = *su1 - *su2) != 0)
+ break;
+ return res;
+}
+
+size_t
+strlen(const char *s)
+{
+ size_t len = 0;
+
+ while (*s++) ++len;
+ return len;
+}
+
+size_t
+strnlen(const char *s, size_t count)
+{
+ const char *sc;
+
+ for (sc = s; count-- && *sc != '\0'; ++sc)
+ ;
+ return sc - s;
+}
+
+int
+strcmp(const char *cs, const char *ct)
+{
+ signed char res;
+
+ while (1) {
+ if ((res = *cs - *ct++) != 0 || !*cs++)
+ break;
+ }
+ return res;
+}
+
+char *
+strcpy(char *dest, const char *src)
+{
+ char *tmp = dest;
+
+ while ((*dest++ = *src++) != '\0')
+ /* nothing */;
+ return tmp;
+}
+
+char *
+strncpy(char *dest, const char *src, size_t count)
+{
+ char *tmp = dest;
+
+ while (count) {
+ if ((*tmp = *src) != 0)
+ src++;
+ tmp++;
+ count--;
+ }
+ return dest;
+}
+
+int
+strncmp(const char *cs, const char *ct, size_t count)
+{
+ signed char res = 0;
+
+ while (count) {
+ if ((res = *cs - *ct++) != 0 || !*cs++)
+ break;
+ count--;
+ }
+ return res;
+}
+
+void
+bzero(void *s, size_t n)
+{
+ unsigned char *ptr = s;
+
+ while (n--)
+ *ptr++ = 0;
+}
+
diff --git a/src/libc/string.h b/src/libc/string.h
@@ -0,0 +1,19 @@
+#ifndef __STRING_H__
+#define __STRING_H__
+
+#include <sys/types.h>
+
+extern void *memcpy(void *dest, const void *src, size_t n);
+extern void *memmove(void *dest, const void *src, size_t count);
+extern void *memset(void *s, int c, size_t n);
+extern int memcmp(const void *cs, const void *ct, size_t count);
+extern size_t strlen(const char *s);
+extern size_t strnlen(const char *s, size_t count);
+extern int strcmp(const char *cs, const char *ct);
+extern char *strcpy(char *dest, const char *src);
+extern char *strncpy(char *dest, const char *src, size_t count);
+extern int strncmp(const char *cs, const char *ct, size_t count);
+extern void bzero(void *s, size_t n);
+
+#endif
+
diff --git a/src/libc/sys/types.h b/src/libc/sys/types.h
@@ -0,0 +1,19 @@
+#ifndef __TYPES_H__
+#define __TYPES_H__
+
+typedef int ssize_t;
+typedef unsigned int size_t;
+typedef int pid_t;
+typedef long int time_t;
+typedef unsigned short uid_t;
+typedef unsigned short gid_t;
+typedef unsigned short dev_t;
+typedef unsigned short ino_t;
+typedef unsigned long int mode_t;
+typedef long int off_t;
+typedef short int nlink_t;
+typedef unsigned long int blksize_t;
+typedef unsigned long int blkcnt_t;
+
+#endif
+
diff --git a/src/libc/unistd.h b/src/libc/unistd.h
@@ -0,0 +1,9 @@
+#ifndef __UNISTD_H__
+#define __UNISTD_H__
+
+enum {
+ STDIN_FILENO
+};
+
+#endif
+
diff --git a/src/libc/vsprintf.c b/src/libc/vsprintf.c
@@ -0,0 +1,242 @@
+/* This file is released under the GPL v2 public license */
+
+/*
+ * linux/kernel/vsprintf.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+static int skip_atoi(const char **s)
+{
+ int i = 0;
+
+ while (isdigit(**s))
+ i = i * 10 + *((*s)++) - '0';
+ return i;
+}
+
+#define ZEROPAD 1 /* pad with zero */
+#define SIGN 2 /* unsigned/signed long */
+#define PLUS 4 /* show plus */
+#define SPACE 8 /* space if plus */
+#define LEFT 16 /* left justified */
+#define SPECIAL 32 /* 0x */
+#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */
+
+#define do_div(n,base) \
+ ({ \
+ int __res; \
+ __asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \
+ __res; \
+ })
+
+static char * number(char * str, int num, int base, int size, int precision
+ , int type)
+{
+ char c, sign, tmp[36];
+ const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ int i;
+
+ if (type & SMALL) digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+ if (type & LEFT) type &= ~ZEROPAD;
+ if (base < 2 || base > 36)
+ return 0;
+ c = (type & ZEROPAD) ? '0' : ' ' ;
+ if (type & SIGN && num < 0) {
+ sign = '-';
+ num = -num;
+ } else
+ sign = (type & PLUS) ? '+' : ((type & SPACE) ? ' ' : 0);
+ if (sign) size--;
+ if (type & SPECIAL) {
+ if (base == 16)
+ size -= 2;
+ else if (base == 8)
+ size--;
+ }
+ i = 0;
+ if (num == 0)
+ tmp[i++] = '0';
+ else while (num != 0)
+ tmp[i++] = digits[do_div(num, base)];
+ if (i > precision) precision = i;
+ size -= precision;
+ if (!(type&(ZEROPAD + LEFT)))
+ while (size-- > 0)
+ *str++ = ' ';
+ if (sign)
+ *str++ = sign;
+ if (type & SPECIAL) {
+ if (base == 8) {
+ *str++ = '0';
+ } else if (base == 16) {
+ *str++ = '0';
+ *str++ = digits[33];
+ }
+ }
+ if (!(type & LEFT))
+ while (size-- > 0)
+ *str++ = c;
+ while (i < precision--)
+ *str++ = '0';
+ while (i-- > 0)
+ *str++ = tmp[i];
+ while (size-- > 0)
+ *str++ = ' ';
+ return str;
+}
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+ int len;
+ int i;
+ char * str;
+ char *s;
+ int *ip;
+
+ int flags; /* flags to number() */
+
+ int field_width; /* width of output field */
+ int precision; /* min. # of digits for integers; max
+ number of chars for from string */
+ int qualifier; /* 'h', 'l', or 'L' for integer fields */
+
+ for (str = buf ; *fmt ; ++fmt) {
+ if (*fmt != '%') {
+ *str++ = *fmt;
+ continue;
+ }
+
+ /* process flags */
+ flags = 0;
+repeat:
+ ++fmt; /* this also skips first '%' */
+ switch (*fmt) {
+ case '-': flags |= LEFT; goto repeat;
+ case '+': flags |= PLUS; goto repeat;
+ case ' ': flags |= SPACE; goto repeat;
+ case '#': flags |= SPECIAL; goto repeat;
+ case '0': flags |= ZEROPAD; goto repeat;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (isdigit(*fmt))
+ field_width = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ /* it's the next argument */
+ field_width = va_arg(args, int);
+ if (field_width < 0) {
+ field_width = -field_width;
+ flags |= LEFT;
+ }
+ }
+
+ /* get the precision */
+ precision = -1;
+ if (*fmt == '.') {
+ ++fmt;
+ if (isdigit(*fmt))
+ precision = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ /* it's the next argument */
+ precision = va_arg(args, int);
+ }
+ if (precision < 0)
+ precision = 0;
+ }
+
+ /* get the conversion qualifier */
+ qualifier = -1;
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+ qualifier = *fmt;
+ ++fmt;
+ }
+
+ switch (*fmt) {
+ case 'c':
+ if (!(flags & LEFT))
+ while (--field_width > 0)
+ *str++ = ' ';
+ *str++ = (unsigned char) va_arg(args, int);
+ while (--field_width > 0)
+ *str++ = ' ';
+ break;
+
+ case 's':
+ s = va_arg(args, char *);
+ if (!s)
+ s = "<NULL>";
+ len = strlen(s);
+ if (precision < 0)
+ precision = len;
+ else if (len > precision)
+ len = precision;
+
+ if (!(flags & LEFT))
+ while (len < field_width--)
+ *str++ = ' ';
+ for (i = 0; i < len; ++i)
+ *str++ = *s++;
+ while (len < field_width--)
+ *str++ = ' ';
+ break;
+
+ case 'o':
+ str = number(str, va_arg(args, unsigned long), 8,
+ field_width, precision, flags);
+ break;
+
+ case 'p':
+ if (field_width == -1) {
+ field_width = 8;
+ flags |= ZEROPAD;
+ }
+ str = number(str,
+ (unsigned long) va_arg(args, void *), 16,
+ field_width, precision, flags);
+ break;
+
+ case 'x':
+ flags |= SMALL;
+ case 'X':
+ str = number(str, va_arg(args, unsigned long), 16,
+ field_width, precision, flags);
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= SIGN;
+ case 'u':
+ str = number(str, va_arg(args, unsigned long), 10,
+ field_width, precision, flags);
+ break;
+
+ case 'n':
+ ip = va_arg(args, int *);
+ *ip = (str - buf);
+ break;
+
+ default:
+ if (*fmt != '%')
+ *str++ = '%';
+ if (*fmt)
+ *str++ = *fmt;
+ else
+ --fmt;
+ break;
+ }
+ }
+ *str = '\0';
+ return str - buf;
+}
+
diff --git a/src/newlib-port/closedir.c b/src/newlib-port/closedir.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)closedir.c 5.9 (Berkeley) 2/23/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * close a directory.
+ */
+int
+closedir(dirp)
+register DIR *dirp;
+{
+ int fd;
+
+ fd = dirp->fd;
+ dirp->fd = -1;
+ dirp->off = 0;
+ return(close(fd));
+}
+
diff --git a/src/newlib-port/crt0.S b/src/newlib-port/crt0.S
@@ -0,0 +1,11 @@
+.global _start
+.extern main
+_start:
+ call _init_signal
+ call main
+ movl %eax, %ebx
+ movl $0x1, %eax
+ int $0x80
+lp:
+ hlt
+ jmp lp
diff --git a/src/newlib-port/crt0.c b/src/newlib-port/crt0.c
@@ -0,0 +1,22 @@
+extern int main(int argc, char **argv);
+extern void _init_signal(void);
+
+#define sys_exit(status) \
+ ({ \
+ int __num = 1, err_code = status; \
+ asm volatile ("int $0x80" :: "a"(__num), "b"(err_code)); \
+ })
+
+static char *argv[] = { "arg0", (char *)0 };
+
+void
+_start(void)
+{
+ int ret;
+
+ _init_signal();
+ ret = main(1, argv);
+ sys_exit(ret);
+ for (;;);
+}
+
diff --git a/src/newlib-port/cynix_binutils-2.20.patch b/src/newlib-port/cynix_binutils-2.20.patch
@@ -0,0 +1,79 @@
+diff -rupN binutils-2.20-orig/bfd/config.bfd binutils-2.20/bfd/config.bfd
+--- binutils-2.20-orig/bfd/config.bfd 2009-08-06 18:38:00.000000000 +0100
++++ binutils-2.20/bfd/config.bfd 2010-02-09 16:06:12.000000000 +0000
+@@ -207,7 +207,10 @@ case "${targ}" in
+ want64=true
+ ;;
+ #endif /* BFD64 */
+-
++ i[3-7]86-*-cynix*)
++ targ_defvec=bfd_elf32_i386_vec
++ targ_selvecs=i386coff_vec
++ ;;
+ am34-*-linux* | am33_2.0-*-linux*)
+ targ_defvec=bfd_elf32_am33lin_vec
+ ;;
+diff -rupN binutils-2.20-orig/config.sub binutils-2.20/config.sub
+--- binutils-2.20-orig/config.sub 2009-08-17 05:10:29.000000000 +0100
++++ binutils-2.20/config.sub 2010-02-09 16:06:18.000000000 +0000
+@@ -1274,7 +1274,7 @@ case $os in
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -kopensolaris* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+- | -aos* | -aros* \
++ | -aos* | -cynix* | -aros* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+diff -rupN binutils-2.20-orig/gas/configure.tgt binutils-2.20/gas/configure.tgt
+--- binutils-2.20-orig/gas/configure.tgt 2009-09-09 09:13:28.000000000 +0100
++++ binutils-2.20/gas/configure.tgt 2010-02-09 16:06:13.000000000 +0000
+@@ -96,6 +96,7 @@ esac
+ generic_target=${cpu_type}-$vendor-$os
+ # Note: This table is alpha-sorted, please try to keep it that way.
+ case ${generic_target} in
++ i386-*-cynix*) fmt=elf ;;
+ alpha-*-*vms*) fmt=evax ;;
+ alpha-*-osf*) fmt=ecoff ;;
+ alpha-*-linuxecoff*) fmt=ecoff ;;
+diff -rupN binutils-2.20-orig/ld/Makefile.in binutils-2.20/ld/Makefile.in
+--- binutils-2.20-orig/ld/Makefile.in 2009-09-07 13:10:24.000000000 +0100
++++ binutils-2.20/ld/Makefile.in 2010-02-09 16:06:09.000000000 +0000
+@@ -2451,6 +2451,9 @@ eelf64ltsmip.c: $(srcdir)/emulparams/elf
+ eelf_i386.c: $(srcdir)/emulparams/elf_i386.sh \
+ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} elf_i386 "$(tdir_elf_i386)"
++ecynix_i386.c: $(srcdir)/emulparams/cynix_i386.sh \
++ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
++ ${GENSCRIPTS} cynix_i386 "$(tdir_cynix_i386)"
+ eelf_x86_64.c: $(srcdir)/emulparams/elf_x86_64.sh \
+ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} elf_x86_64 "$(tdir_elf_x86_64)"
+diff -rupN binutils-2.20-orig/ld/configure.tgt binutils-2.20/ld/configure.tgt
+--- binutils-2.20-orig/ld/configure.tgt 2009-08-06 18:38:03.000000000 +0100
++++ binutils-2.20/ld/configure.tgt 2010-02-09 16:06:09.000000000 +0000
+@@ -36,6 +36,7 @@ alpha*-*-linuxecoff*) targ_emul=alpha ta
+ alpha*-*-linux-*) targ_emul=elf64alpha targ_extra_emuls=alpha
+ tdir_alpha=`echo ${targ_alias} | sed -e 's/linux/linuxecoff/'` ;;
+ alpha*-*-osf*) targ_emul=alpha ;;
++i[3-7]86-*-cynix*) targ_emul=cynix_i386 ;;
+ alpha*-*-gnu*) targ_emul=elf64alpha ;;
+ alpha*-*-netware*) targ_emul=alpha ;;
+ alpha*-*-netbsd*) targ_emul=elf64alpha_nbsd ;;
+diff -rupN binutils-2.20-orig/ld/emulparams/cynix_i386.sh binutils-2.20/ld/emulparams/cynix_i386.sh
+--- binutils-2.20-orig/ld/emulparams/cynix_i386.sh 1970-01-01 01:00:00.000000000 +0100
++++ binutils-2.20/ld/emulparams/cynix_i386.sh 2010-02-09 16:06:09.000000000 +0000
+@@ -0,0 +1,13 @@
++SCRIPT_NAME=elf
++OUTPUT_FORMAT=elf32-i386
++TEXT_START_ADDR=0x40000000
++MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
++COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
++ARCH=i386
++MACHINE=
++NOP=0x90909090
++TEMPLATE_NAME=elf32
++GENERATE_SHLIB_SCRIPT=yes
++GENERATE_PIE_SCRIPT=yes
++NO_SMALL_DATA=yes
++SEPARATE_GOTPLT=12
diff --git a/src/newlib-port/cynix_gcc-4.4.2.patch b/src/newlib-port/cynix_gcc-4.4.2.patch
@@ -0,0 +1,66 @@
+diff -rupN gcc-4.4.2-orig/config.sub gcc-4.4.2/config.sub
+--- gcc-4.4.2-orig/config.sub 2008-12-18 03:27:27.000000000 +0000
++++ gcc-4.4.2/config.sub 2010-02-09 16:06:40.000000000 +0000
+@@ -1257,7 +1257,7 @@ case $os in
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+- | -aos* \
++ | -aos* | -cynix* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+diff -rupN gcc-4.4.2-orig/gcc/config/cynix.h gcc-4.4.2/gcc/config/cynix.h
+--- gcc-4.4.2-orig/gcc/config/cynix.h 1970-01-01 01:00:00.000000000 +0100
++++ gcc-4.4.2/gcc/config/cynix.h 2010-02-09 16:06:36.000000000 +0000
+@@ -0,0 +1,10 @@
++#undef TARGET_OS_CPP_BUILTINS
++#define TARGET_OS_CPP_BUILTINS() \
++ do { \
++ builtin_define_std ("cynix"); \
++ builtin_define_std ("unix"); \
++ builtin_assert ("system=cynix"); \
++ builtin_assert ("system=unix"); \
++ } while(0);
++#undef TARGET_VERSION
++#define TARGET_VERSION fprintf(stderr, " (i386 cynix)");
+diff -rupN gcc-4.4.2-orig/gcc/config.gcc gcc-4.4.2/gcc/config.gcc
+--- gcc-4.4.2-orig/gcc/config.gcc 2009-09-13 14:01:13.000000000 +0100
++++ gcc-4.4.2/gcc/config.gcc 2010-02-09 16:06:34.000000000 +0000
+@@ -407,6 +407,12 @@ esac
+
+ # Common parts for widely ported systems.
+ case ${target} in
++ *-*-cynix*)
++ extra_parts="crtbegin.o crtend.o"
++ gas=yes
++ gnu_ld=yes
++ default_use_cxa_atexit=yes
++ ;;
+ *-*-darwin*)
+ tm_file="${tm_file} darwin.h"
+ case ${target} in
+@@ -602,6 +608,11 @@ case ${target} in
+ then tmake_file=${cpu_type}/t-$rest
+ fi
+ ;;
++i[3-7]86-*-cynix*)
++ tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h i386/i386elf.h cynix.h"
++ tmake_file="i386/t-i386elf t-svr4"
++ use_fixproto=yes
++ ;;
+ alpha*-*-linux*)
+ tm_file="${tm_file} alpha/elf.h alpha/linux.h alpha/linux-elf.h"
+ target_cpu_default="MASK_GAS"
+diff -rupN gcc-4.4.2-orig/libgcc/config.host gcc-4.4.2/libgcc/config.host
+--- gcc-4.4.2-orig/libgcc/config.host 2009-04-17 12:58:41.000000000 +0100
++++ gcc-4.4.2/libgcc/config.host 2010-02-09 16:06:41.000000000 +0000
+@@ -172,6 +172,8 @@ case ${host} in
+ then tmake_file=${cpu_type}/t-$rest
+ fi
+ ;;
++i[3-7]86-*-cynix*)
++ ;;
+ alpha*-*-linux* | alpha*-*-gnu*)
+ tmake_file="${tmake_file} alpha/t-crtfm"
+ extra_parts="$extra_parts crtfastmath.o"
diff --git a/src/newlib-port/opendir.c b/src/newlib-port/opendir.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)opendir.c 5.11 (Berkeley) 2/23/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * open a directory.
+ */
+DIR *
+opendir(name)
+const char *name;
+{
+ register DIR *dirp;
+ register int fd;
+
+ if ((fd = open(name, 0)) == -1)
+ return NULL;
+ dirp = malloc(sizeof(DIR));
+ if (!dirp) {
+ close(fd);
+ return NULL;
+ }
+ dirp->fd = fd;
+ dirp->off = 0;
+ return dirp;
+}
+
diff --git a/src/newlib-port/readdir.c b/src/newlib-port/readdir.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)readdir.c 5.7 (Berkeley) 6/1/90";
+#endif /* LIBC_SCCS and not lint */
+
+#include <dirent.h>
+
+#define sys_readdir(dir) \
+ ({ \
+ int __num = 16; \
+ DIR *__dir = dir; \
+ struct dirent *__ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__dir)); \
+ __ret; \
+ })
+
+/*
+ * get next entry in a directory.
+ */
+struct dirent *
+readdir(dirp)
+register DIR *dirp;
+{
+ return sys_readdir(dirp);
+}
+
diff --git a/src/newlib-port/sys/dirent.h b/src/newlib-port/sys/dirent.h
@@ -0,0 +1,54 @@
+#ifndef _SYS_DIRENT_H
+# define _SYS_DIRENT_H
+
+#define MAX_NAME_LEN 255
+
+#if 0
+typedef struct _dirdesc {
+ int dd_fd;
+ long dd_loc;
+ long dd_size;
+ char *dd_buf;
+ int dd_len;
+ long dd_seek;
+} DIR;
+
+# define __dirfd(dp) ((dp)->dd_fd)
+
+DIR *opendir (const char *);
+struct dirent *readdir (DIR *);
+void rewinddir (DIR *);
+int closedir (DIR *);
+
+#include <sys/types.h>
+
+struct dirent {
+ long d_ino;
+ off_t d_off;
+ unsigned short d_reclen;
+ /* we need better syntax for variable-sized arrays */
+ char d_name[1];
+};
+#endif
+
+#include <sys/types.h>
+
+typedef struct DIR {
+ int fd;
+ unsigned long off;
+} DIR;
+
+struct dirent {
+ ino_t d_inode;
+ off_t d_off;
+ unsigned short d_namelen;
+ char d_name[MAX_NAME_LEN + 1];
+};
+
+DIR *opendir (const char *);
+struct dirent *readdir (DIR *);
+void rewinddir (DIR *);
+int closedir (DIR *);
+
+#endif
+
diff --git a/src/newlib-port/syscalls.c b/src/newlib-port/syscalls.c
@@ -0,0 +1,522 @@
+/* syscalls glue for newlib */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/times.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+#define sys_exit(status) \
+ ({ \
+ int __num = __NR_exit, err_code = status; \
+ asm volatile ("int $0x80" :: "a"(__num), "b"(err_code)); \
+ })
+
+#define sys_fork() \
+ ({ \
+ int __num = __NR_fork; \
+ pid_t __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num)); \
+ __ret; \
+ })
+
+#define sys_waitpid(pid, status, options) \
+ ({ \
+ int __num = __NR_waitpid, *__status = status, __options = options; \
+ pid_t __pid = pid, __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__pid), "c"(__status), "d"(__options)); \
+ __ret; \
+ })
+
+#define sys_read(fd, buf, count) \
+ ({ \
+ int __num = __NR_read, __fd = fd; \
+ ssize_t __ret; \
+ void *__buf = buf; \
+ size_t __count = count; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__fd), "c"(__buf), "d"(__count)); \
+ __ret; \
+ })
+
+#define sys_write(fd, buf, count) \
+ ({ \
+ int __num = __NR_write, __fd = fd; \
+ ssize_t __ret; \
+ void *__buf = buf; \
+ size_t __count = count; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__fd), "c"(__buf), "d"(__count)); \
+ __ret; \
+ })
+
+#define sys_reschedule() \
+ ({ \
+ int __num = __NR_reschedule; \
+ asm volatile ("int $0x80" :: "a"(__num)); \
+ })
+
+#define sys_open(pathname, flags, mode) \
+ ({ \
+ int __num = __NR_open, __flags = flags, __ret; \
+ const char *__pathname = pathname; \
+ mode_t __mode = mode; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__pathname), "c"(__flags), "d"(__mode)); \
+ __ret; \
+ })
+
+#define sys_creat(pathname, mode) \
+ ({ \
+ int __num = __NR_creat, __ret; \
+ mode_t __mode = mode; \
+ const char *__pathname = pathname; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__pathname), "c"(__mode)); \
+ __ret; \
+ })
+
+#define sys_close(fd) \
+ ({ \
+ int __num = __NR_close, __ret; \
+ int __fd = fd; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__fd)); \
+ __ret; \
+ })
+
+#define sys_isatty(fd) \
+ ({ \
+ int __num = __NR_isatty, __ret, __fd = fd; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__fd)); \
+ __ret; \
+ })
+
+#define sys_getpid() \
+ ({ \
+ int __num = __NR_getpid; \
+ pid_t __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num)); \
+ __ret; \
+ })
+
+#define sys_getppid() \
+ ({ \
+ int __num = __NR_getppid; \
+ pid_t __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num)); \
+ __ret; \
+ })
+
+#define sys_readdir() \
+ ({ \
+ int __num = __NR_readdir; \
+ struct dirent_t *__ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num)); \
+ __ret; \
+ })
+
+#define sys_dup(oldfd) \
+ ({ \
+ int __num = __NR_dup, __oldfd = oldfd, __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__oldfd)); \
+ __ret; \
+ })
+
+#define sys_dup2(oldfd, newfd) \
+ ({ \
+ int __num = __NR_dup, __oldfd = oldfd, __newfd = newfd, __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__oldfd), "c"(__newfd)); \
+ __ret; \
+ })
+
+#define sys_stat(path, stbuf) \
+ ({ \
+ int __num = __NR_stat, __ret; \
+ const char *__path = path; \
+ struct stat *__buf = stbuf; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__path), "c"(__buf)); \
+ __ret; \
+ })
+
+#define sys_fstat(fd, stbuf) \
+ ({ \
+ int __num = __NR_fstat, __ret, __fd = fd; \
+ struct stat *__buf = stbuf; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__fd), "c"(__buf)); \
+ __ret; \
+ })
+
+#define sys_execve(filename, argv, envp) \
+ ({ \
+ int __num = __NR_execve, __ret; \
+ const char *__filename = filename; \
+ char **const __argv = argv; \
+ char **const __envp = envp; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__filename), "c"(__argv), "d"(__envp)); \
+ __ret; \
+ })
+
+#define sys_seeder() \
+ ({ \
+ int __num = __NR_seeder, __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num)); \
+ __ret; \
+ })
+
+#define sys_sbrk(incr) \
+ ({ \
+ int __num = __NR_sbrk, __ret; \
+ long __incr = incr; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__incr)); \
+ __ret; \
+ })
+
+#define sys_getuid() \
+ ({ \
+ int __num = __NR_getuid; \
+ uid_t __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num)); \
+ __ret; \
+ })
+
+#define sys_setuid(uid) \
+ ({ \
+ int __num = __NR_setuid, __ret; \
+ uid_t __uid = uid; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__uid)); \
+ __ret; \
+ })
+
+#define sys_getgid() \
+ ({ \
+ int __num = __NR_getgid; \
+ uid_t __ret; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num)); \
+ __ret; \
+ })
+
+#define sys_setgid(gid) \
+ ({ \
+ int __num = __NR_setgid, __ret; \
+ uid_t __gid = gid; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__gid)); \
+ __ret; \
+ })
+
+#define sys_suspend_task(channel) \
+ ({ \
+ int __num = __NR_suspend_task, __ret; \
+ void * __channel = channel; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__channel)); \
+ __ret; \
+ })
+
+#define sys_resume_task(channel) \
+ ({ \
+ int __num = __NR_resume_task; \
+ void * __channel = channel; \
+ asm volatile ("int $0x80" :: "a"(__num), "b"(__channel)); \
+ })
+
+#define sys_pipe(pipefds) \
+ ({ \
+ int __num = __NR_pipe, __ret; \
+ int *__pipefds = pipefds; \
+ asm volatile ("int $0x80" : "=a"(__ret) : "0"(__num), "b"(__pipefds)); \
+ __ret; \
+ })
+
+#define SYSCALL_NR 30
+#define __NR_exit 1
+#define __NR_fork 2
+#define __NR_read 3
+#define __NR_write 4
+#define __NR_open 5
+#define __NR_close 6
+#define __NR_waitpid 7
+#define __NR_creat 8
+#define __NR_link 9
+#define __NR_unlink 10
+#define __NR_execve 11
+#define __NR_reschedule 12
+#define __NR_isatty 13
+#define __NR_getpid 14
+#define __NR_getppid 15
+#define __NR_readdir 16
+#define __NR_dup 17
+#define __NR_dup2 18
+#define __NR_stat 19
+#define __NR_fstat 20
+#define __NR_seeder 21
+#define __NR_sbrk 22
+#define __NR_getuid 23
+#define __NR_setuid 24
+#define __NR_getgid 25
+#define __NR_setgid 26
+#define __NR_suspend_task 27
+#define __NR_resume_task 28
+#define __NR_pipe 29
+
+char **environ;
+
+int
+pipe(int pipefd[2])
+{
+ int ret;
+
+ ret = sys_pipe(pipefd);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+uid_t
+getuid(void)
+{
+ return sys_getuid();
+}
+
+int
+setuid(uid_t uid)
+{
+ int ret;
+
+ ret = sys_setuid(uid);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+gid_t
+getgid(void)
+{
+ return sys_getgid();
+}
+
+int
+setgid(gid_t gid)
+{
+ int ret;
+
+ ret = sys_setgid(gid);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+void
+_exit(void)
+{
+ sys_exit(0);
+}
+
+int
+close(int file)
+{
+ int ret;
+
+ ret = sys_close(file);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+int
+execve(char *name, char **argv, char **env)
+{
+ int ret;
+
+ ret = sys_execve(name, argv, env);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+int
+fork(void)
+{
+ int ret;
+
+ ret = sys_fork();
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+int
+fstat(int file, struct stat *st)
+{
+ int ret;
+
+ ret = sys_fstat(file, st);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+int
+dup(int fildes)
+{
+ int ret;
+
+ ret = sys_dup(fildes);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+int
+dup2(int fildes, int fildes2)
+{
+ int ret;
+
+ ret = sys_dup2(fildes, fildes2);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+int
+getpid(void)
+{
+ return sys_getpid();
+}
+
+int
+isatty(int file)
+{
+ return sys_isatty(file);
+}
+
+int
+kill(int pid, int sig)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int
+link(char *old, char *new)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int
+lseek(int file, int ptr, int dir)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int
+open(const char *name, int flags, ...)
+{
+ int ret;
+
+ ret = sys_open(name, flags, 0);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+int
+read(int file, char *ptr, int len)
+{
+ int ret;
+
+ ret = sys_read(file, ptr, len);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+caddr_t
+sbrk(int incr)
+{
+ caddr_t ret;
+
+ ret = (caddr_t)sys_sbrk(incr);
+ return ret;
+}
+
+int
+stat(const char *file, struct stat *st)
+{
+ int ret;
+
+ ret = sys_stat(file, st);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+clock_t
+times(struct tms *buf)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int
+unlink(char *name)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int
+wait(int *status)
+{
+ int ret;
+
+ ret = sys_waitpid(-1, status, 0);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+int
+write(int file, char *ptr, int len)
+{
+ int ret;
+
+ ret = sys_write(file, ptr, len);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+int
+gettimeofday(struct timeval *p, void *z)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
diff --git a/src/tools/hash.c b/src/tools/hash.c
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <string.h>
+
+uint32_t
+get_fnv_hash(const char *buf, size_t count, uint32_t hash)
+{
+ static uint32_t fnv_offset_basis = 2166136261;
+ static uint32_t fnv_prime = 16777619;
+
+ hash = (!hash) ? fnv_offset_basis : hash;
+ while (count--) {
+ hash ^= *buf++;
+ hash *= fnv_prime;
+ }
+
+ return hash;
+}
+
+int
+main(void)
+{
+ int fd;
+ char buf[256];
+ ssize_t ret;
+ uint32_t hash = 0;
+
+ fd = open("big", O_RDONLY);
+ if (fd < 0)
+ return EXIT_FAILURE;
+ do {
+ ret = read(fd, buf, 255);
+ if (ret <= 0) break;
+ buf[ret] = '\0';
+ hash = get_fnv_hash(buf, ret, hash);
+ } while (1);
+ printf("hash = 0x%08lx\n", hash);
+ close(fd);
+ return EXIT_SUCCESS;
+}
+
diff --git a/src/vim.sh b/src/vim.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+gvim -p $(find . -type f -iname "*.[chS]" | grep -v tools \
+ | grep -v newlib-port | grep -v version.h)