cynix

x86 UNIX-like OS
git clone git://git.2f30.org/cynix.git
Log | Files | Refs | README

commit 0ec9b130edf156928778ba80a87602540e905d0f
parent 1f41c3e4e4890bc1bde09256f32b83eaebe24d7a
Author: sin <sin@2f30.org>
Date:   Mon May 28 13:57:31 +0100

cynix: Initial commit


Diffstat:
.astylerc | 10++++++++++
AUTHORS | 2++
COPYING | 14++++++++++++++
INSTALL | 3+++
Makefile | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
README.md | 3+--
TODO | 25+++++++++++++++++++++++++
build/add.sh | 14++++++++++++++
build/bochsrc | 9+++++++++
build/initrd | 0
build/installimg.sh | 17+++++++++++++++++
build/link.ld | 24++++++++++++++++++++++++
build/logo | 23+++++++++++++++++++++++
build/makeiso.sh | 13+++++++++++++
build/mkcreateimg.sh | 36++++++++++++++++++++++++++++++++++++
build/mkfloppyimg.sh | 7+++++++
build/run.sh | 17+++++++++++++++++
build/stage1 | 0
build/stage2 | 0
build/stage2_eltorito | 0
compile.sh | 11+++++++++++
format.sh | 13+++++++++++++
src/boot/Makefile-part | 1+
src/boot/boot.S | 34++++++++++++++++++++++++++++++++++
src/boot/init.c | 24++++++++++++++++++++++++
src/cmd/ls.c | 48++++++++++++++++++++++++++++++++++++++++++++++++
src/core/Makefile-part | 23+++++++++++++++++++++++
src/core/common.c | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/cpuid.c | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/elf.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/errno.c | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/ext2.c | 837+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/gdt.c | 28++++++++++++++++++++++++++++
src/core/heap.c | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/idt.c | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/kdb.c | 542+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/keyboard.c | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/main.c | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/mm.c | 885+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/pci.c | 267+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/pic.c | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/pipe.c | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/rtc.c | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/rtl8139.c | 249+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/serial.c | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/syscall.c | 299+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/tss.c | 464+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/tty.c | 267+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/core/x86_asm.S | 467+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/include/common.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/include/elf.h | 183+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/include/errno.h | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/include/ext2.h | 301+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/include/gdt.h | 30++++++++++++++++++++++++++++++
src/include/heap.h | 16++++++++++++++++
src/include/idt.h | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/include/kdb.h | 10++++++++++
src/include/keyboard.h | 10++++++++++
src/include/list.h | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/include/mm.h | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/include/multiboot.h | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/include/pci.h | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/include/pic.h | 12++++++++++++
src/include/pipe.h | 15+++++++++++++++
src/include/rtc.h | 13+++++++++++++
src/include/rtl8139.h | 10++++++++++
src/include/serial.h | 12++++++++++++
src/include/syscall.h | 258+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/include/tss.h | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/include/tty.h | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/include/version.h | 7+++++++
src/include/x86.h | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/libc/Makefile-part | 1+
src/libc/ctype.h | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/libc/stdarg.h | 11+++++++++++
src/libc/stdint.h | 16++++++++++++++++
src/libc/stdio.c | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/libc/stdio.h | 15+++++++++++++++
src/libc/stdlib.c | 143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/libc/stdlib.h | 8++++++++
src/libc/string.c | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/libc/string.h | 19+++++++++++++++++++
src/libc/sys/types.h | 19+++++++++++++++++++
src/libc/unistd.h | 9+++++++++
src/libc/vsprintf.c | 242+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/newlib-port/closedir.c | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/newlib-port/crt0.S | 11+++++++++++
src/newlib-port/crt0.c | 22++++++++++++++++++++++
src/newlib-port/cynix_binutils-2.20.patch | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/newlib-port/cynix_gcc-4.4.2.patch | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/newlib-port/opendir.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/newlib-port/readdir.c | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/newlib-port/sys/dirent.h | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/newlib-port/syscalls.c | 522+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/tools/hash.c | 45+++++++++++++++++++++++++++++++++++++++++++++
src/vim.sh | 4++++
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 @@ + +  +     +  +   + + + + + + + + + + + +   + +  + Cynix v0.01  +  by sin  +   +    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(&reg->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(&regs); + } 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)