├── .gdbinit ├── .gdbinit.vmware ├── .gitignore ├── CHECKLIST ├── Makefile ├── README.md ├── TODO ├── contrib ├── lua-5.2.3-exscapeos.patch └── lua.sh ├── exscapeos.bochs ├── initrd ├── etc │ ├── mounts │ ├── shrc │ └── subsub │ │ └── subsub_file ├── fpu.lua ├── initrd_test.txt ├── popen.lua └── test.txt ├── isofiles └── boot │ └── grub │ ├── menu.lst │ └── stage2_eltorito ├── linker-kernel.ld ├── misc ├── Makefile └── create_initrd.py ├── net-scripts ├── ifdown.sh ├── ifup.sh └── prepare.sh ├── simics.sh ├── src ├── include │ ├── kernel │ │ ├── ata.h │ │ ├── backtrace.h │ │ ├── console.h │ │ ├── elf.h │ │ ├── ext2.h │ │ ├── fat.h │ │ ├── fpu.h │ │ ├── gdt.h │ │ ├── heap.h │ │ ├── initrd.h │ │ ├── interrupts.h │ │ ├── kernutil.h │ │ ├── keyboard.h │ │ ├── kshell.h │ │ ├── list.h │ │ ├── multiboot.h │ │ ├── mutex.h │ │ ├── net │ │ │ ├── arp.h │ │ │ ├── ipicmp.h │ │ │ ├── nethandler.h │ │ │ └── rtl8139.h │ │ ├── ordered_array.h │ │ ├── partition.h │ │ ├── pci.h │ │ ├── pipe.h │ │ ├── pmm.h │ │ ├── serial.h │ │ ├── stdio.h │ │ ├── syscall.h │ │ ├── task.h │ │ ├── time.h │ │ ├── timer.h │ │ ├── vfs.h │ │ └── vmm.h │ ├── path.h │ ├── stdarg.h │ ├── stdio.h │ ├── stdlib.h │ ├── string.h │ └── userspace │ │ └── exscapeos.h ├── kernel │ ├── ata.c │ ├── backtrace.c │ ├── console.c │ ├── copy_page.s │ ├── descriptor_tables.s │ ├── elf.c │ ├── ext2.c │ ├── fat │ │ ├── dir.c │ │ └── fat.c │ ├── fpu.c │ ├── gdt.c │ ├── heap.c │ ├── initrd.c │ ├── interrupts.c │ ├── isr.s │ ├── kernutil.c │ ├── keyboard.c │ ├── kmain.c │ ├── kshell.c │ ├── list.c │ ├── loader.s │ ├── mutex.c │ ├── net │ │ ├── arp.c │ │ ├── internet_checksum.s │ │ ├── ipicmp.c │ │ ├── nethandler.c │ │ └── rtl8139.c │ ├── ordered_array.c │ ├── partition.c │ ├── pci.c │ ├── pipe.c │ ├── pmm.c │ ├── serial.c │ ├── stdio.c │ ├── syscall.c │ ├── task.c │ ├── time.c │ ├── timer.c │ ├── vfs.c │ ├── vmm.c │ └── zero_page.s ├── lib │ ├── memcpy.s │ ├── memset.s │ ├── memsetw.s │ ├── path.c │ ├── stdlib.c │ ├── string.c │ └── vsprintf.c └── userspace │ ├── .user_Makefile │ ├── cat │ ├── Makefile │ └── cat.c │ ├── cpuid │ ├── Makefile │ └── cpuid.c │ ├── debug.sh │ ├── echo │ ├── Makefile │ └── echo.c │ ├── eshell │ ├── Makefile │ ├── main.c │ └── string.c │ ├── grep │ ├── Makefile │ └── grep.c │ ├── guess │ ├── Makefile │ └── guess.c │ ├── ls │ ├── Makefile │ └── ls.c │ ├── md5 │ ├── Makefile │ ├── main.c │ ├── md5.c │ └── md5.h │ └── tests │ ├── .test_Makefile │ ├── arg │ ├── Makefile │ └── arg.c │ ├── daemon │ ├── Makefile │ └── daemon.c │ ├── dirtest │ ├── Makefile │ └── dirtest.c │ ├── env_test │ ├── Makefile │ └── env_test.c │ ├── execve │ ├── Makefile │ └── execve.c │ ├── execve_child │ ├── Makefile │ └── execve_child.c │ ├── fenv │ ├── Makefile │ └── fenv.c │ ├── fork │ ├── Makefile │ └── fork.c │ ├── fork2 │ ├── Makefile │ └── fork2.c │ ├── getopt_test │ ├── Makefile │ └── getopt_test.c │ ├── growstack │ ├── Makefile │ └── growstack.c │ ├── lseek │ ├── Makefile │ └── lseek.c │ ├── misc_test │ ├── Makefile │ ├── misc_test.c │ └── test │ ├── pipe_test │ ├── Makefile │ └── pipe_test.c │ ├── pipe_test2 │ ├── Makefile │ └── pipe_test2.c │ ├── pipe_test3 │ ├── Makefile │ └── pipe_test3.c │ ├── symlink │ ├── Makefile │ └── symlink.c │ └── waitpid │ ├── Makefile │ └── waitpid.c └── toolchain ├── build.sh ├── build_newlib_only.sh ├── clean.sh └── patches ├── binutils-2.23.1-exscapeos.patch ├── exscapeos ├── Makefile.am ├── configure.in ├── crt0.S ├── getreent.c ├── sys │ ├── _types.h │ ├── dirent.h │ ├── stat.h │ └── types.h └── syscalls.c ├── gcc-4.9.2-exscapeos.patch ├── gdb-7.6.2-exscapeos.patch └── newlib-1.20.0-exscapeos.patch /.gdbinit: -------------------------------------------------------------------------------- 1 | file kernel.bin 2 | target remote localhost:1234 3 | -------------------------------------------------------------------------------- /.gdbinit.vmware: -------------------------------------------------------------------------------- 1 | file kernel.bin 2 | target remote localhost:8832 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.img 3 | *.d 4 | *.swp 5 | *.pyc 6 | kernel.bin 7 | initrd.img 8 | bootable.iso 9 | 10 | testing_area 11 | *.dSYM 12 | tags 13 | Session.vim 14 | 15 | serial-output 16 | 17 | initrd/bin/* 18 | initrd/ext2/ 19 | initrd/fat/ 20 | 21 | toolchain/distfiles 22 | toolchain/build-* 23 | toolchain/gcc-4.* 24 | toolchain/newlib-1.* 25 | toolchain/gdb-7.* 26 | toolchain/binutils-2.* 27 | -------------------------------------------------------------------------------- /CHECKLIST: -------------------------------------------------------------------------------- 1 | [x] Screen output (vsprintf) 2 | [x] GDTs set up 3 | [x] IDTs set up 4 | [x] ISRs/IRQ handling 5 | [x] PIT support 6 | [x] Paging 7 | [x] Keyboard input 8 | [x] Kernel heap 9 | [x] VFS layer + basic initrd 10 | [x] Proper console support (not sure how "proper" it is, but... it's decent!) 11 | [x] Multitasking 12 | [x] Basic kernel mode multitasking (shared page directory) 13 | [x] User mode support 14 | [x] Syscalls 15 | [-] ATA driver 16 | [x] Basic reading (PIO) 17 | [x] Basic writing (PIO) 18 | [ ] Decent error handling 19 | [-] File system 20 | [-] FAT 21 | [x] Read support 22 | [ ] Write support 23 | [-] ext2 24 | [-] Read support 25 | [ ] Write support 26 | [x] Executable loading (ELF parsing, etc.) 27 | [x] User-mode libc (wohoo!) 28 | [x] fork + execve 29 | [x] User-mode shell 30 | [x] Pipes 31 | [X] FPU/SSE/AVX state saving during context switches 32 | [ ] SSE/2/3/4.x/AVX support 33 | [ ] Signals 34 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET = build 2 | 3 | WARNINGS := -Wall -Wextra -Wshadow -Wpointer-arith -Wcast-align \ 4 | -Wwrite-strings -Wredundant-decls -Wnested-externs -Winline \ 5 | -Wuninitialized -Wstrict-prototypes \ 6 | -Wno-unused-parameter -Wno-cast-align -Werror -Wno-unused-function 7 | 8 | PREFIX = /usr/local/cross 9 | GCCINC = $(PREFIX)/lib/gcc/i586-pc-exscapeos/4.9.2/include 10 | TOOLCHAININC = $(PREFIX)/i586-pc-exscapeos/include 11 | 12 | CC = ccache i586-pc-exscapeos-gcc 13 | CFLAGS := -O0 -nostdlib -nostdinc -I./src/include -I$(GCCINC) -I$(TOOLCHAININC) -std=gnu99 -march=i586 $(WARNINGS) -ggdb3 -D__DYNAMIC_REENT__ -D_EXSCAPEOS_KERNEL -fdiagnostics-color=always 14 | LD = i586-pc-exscapeos-ld 15 | NATIVECC = gcc # Compiler for the HOST OS, e.g. Linux, Mac OS X 16 | 17 | PROJDIRS := src/kernel src/include src/lib 18 | SRCFILES := $(shell find $(PROJDIRS) -type f -name '*.c') 19 | HDRFILES := $(shell find $(PROJDIRS) -type f -name '*.h') 20 | ASMFILES := $(shell find $(PROJDIRS) -type f -name '*.s') 21 | OBJFILES := $(patsubst %.c,%.o,$(SRCFILES)) 22 | OBJFILES += $(patsubst %.s,%.o,$(ASMFILES)) 23 | 24 | USERSPACEPROG := $(shell find src/userspace/ -maxdepth 3 -name 'Makefile' -exec dirname {} \;) 25 | 26 | DEPFILES := $(patsubst %.c,%.d,$(SRCFILES)) 27 | 28 | # All files to end up in a distribution tarball 29 | ALLFILES := $(SRCFILES) $(HDRFILES) $(AUXFILES) $(ASMFILES) 30 | 31 | #QEMU := /usr/local/bin/qemu-system-i386 32 | QEMU := qemu-system-i386 33 | 34 | # Make sure this is blank if the host OS is not Linux / KVM is not supported 35 | #KVM := -machine accel=kvm 36 | KVM := 37 | 38 | all: $(OBJFILES) 39 | @set -e; if [ ! -d "initrd/bin" ]; then \ 40 | mkdir -p initrd/bin initrd/etc; \ 41 | fi 42 | @$(LD) -T linker-kernel.ld -o kernel.bin ${OBJFILES} 43 | @cp kernel.bin isofiles/boot 44 | @set -e; for prog in $(USERSPACEPROG); do \ 45 | make -C $$prog; \ 46 | done 47 | @set -e; if [ ! -f "initrd/bin/lua" ]; then \ 48 | cd contrib && bash lua.sh ; cd ..; \ 49 | fi 50 | # @/opt/local/bin/ctags -R * 51 | @if [ -f "initrd/bin/eshell" ]; then \ 52 | mv initrd/bin/eshell initrd/bin/sh; \ 53 | fi 54 | @python2 misc/create_initrd.py > /dev/null # let stderr through! 55 | @mkisofs -quiet -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -o bootable.iso isofiles 2>&1 | grep -vP 'GNU xorriso|^\s*$$' || true 56 | -@rm -f serial-output 57 | 58 | clean: 59 | -$(RM) $(wildcard $(OBJFILES) $(DEPFILES) kernel.bin bootable.iso misc/initrd.img) 60 | @for prog in $(USERSPACEPROG); do \ 61 | make -C $$prog clean; \ 62 | rm -f initrd/bin/`basename "$$prog"` initrd/bin/tests/`basename "$$prog"`; \ 63 | done 64 | @rm -f initrd/bin/sh 65 | -@rm -f serial-output 66 | 67 | -include $(DEPFILES) 68 | 69 | todolist: 70 | -@for file in $(ALLFILES); do fgrep -H -e TODO -e FIXME $$file; done; true 71 | @cat TODO 72 | 73 | %.o: %.c Makefile 74 | @$(CC) $(CFLAGS) -MMD -MP -c $< -o $@ -fno-builtin 75 | 76 | %.o: %.s Makefile 77 | @nasm -o $@ $< -f elf -F dwarf -g 78 | 79 | nofat: all 80 | $(QEMU) -cdrom bootable.iso -monitor stdio -s -serial file:serial-output -m 64 81 | 82 | #net: all 83 | #@bash net-scripts/prepare.sh 84 | #@sudo $(QEMU) -cdrom bootable.iso -hda hdd.img -hdb fat32.img -monitor stdio -s -serial file:serial-output -d cpu_reset -m 64 -net nic,vlan=0,macaddr=00:aa:00:18:6c:00,model=rtl8139 -net tap,ifname=tap2,script=net-scripts/ifup.sh,downscript=no $(KVM) 85 | 86 | #netdebug: all 87 | #@bash net-scripts/prepare.sh 88 | #@sudo $(QEMU) -cdrom bootable.iso -hda hdd.img -hdb fat32.img -monitor stdio -s -S -serial file:serial-output -d cpu_reset -m 64 -net nic,vlan=0,macaddr=00:aa:00:18:6c:00,model=rtl8139 -net tap,ifname=tap2,script=net-scripts/ifup.sh,downscript=no $(KVM) 89 | 90 | run: all 91 | @sudo $(QEMU) -cdrom bootable.iso -hda ext2-1kb.img -monitor stdio -s -serial file:serial-output -d cpu_reset -m 64 -boot d $(KVM) 92 | 93 | bochs: all 94 | -@bochs -f exscapeos.bochs -q 95 | 96 | debug: all 97 | @sudo $(QEMU) -cdrom bootable.iso -hda ext2-1kb.img -monitor stdio -s -S -serial file:serial-output -d cpu_reset -m 64 -boot d $(KVM) 98 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | * Console stuff: 2 | * "clear" command in the user mode shell 3 | * Color support (ANSI escapes?) 4 | Combined, this likely means adding some terminfo-ish terminal support; I have *NO* idea how that works, so it'll have to wait a bit. 5 | 6 | * Copy-on-write fork() 7 | 8 | * Rewrite the sleep/block system to handle: 9 | * sleep() 10 | * wait*() 11 | * mutexes 12 | * I/O (pipes, ATA) 13 | 14 | * Pipes: 15 | * Proper blocking, including notifying tasks waiting when the last reader/writer is closed 16 | 17 | * initrd: 18 | * Document the new initrd format (create_initrd.py, initrd.c) 19 | 20 | * Try to recreate and fix the OS not running under QEMU 1.0 (qemu-kvm-1.0/x86_64) 21 | 22 | * Improve the user-mode shell 23 | * Tab completion escaping (also add support for escaped spaces in argument parsing) 24 | * Pipe support 25 | * ; && and || 26 | * !! and !cmd (and perhaps !-n) to look through history 27 | * Better parsing, e.g. 2>&1 works the same as 2> &1 does now; echo a>b writes 'a' to the file 'b' even without the space in between, etc. 28 | 29 | * ext2: 30 | * ext2_read() 31 | 32 | * CHECK_ACCESS_* are very inadequate! It should be *trivial* to give an unmapped address and have the kernel page fault and panic! Not that this truly matters, since it's trivial to get the kernel to panic anyway -- I'm still doing that on purpose on every minor problem, so that bugs are not missed. 33 | 34 | * create basic "find" utility, with little more than -name and/or -iname to begin with...? 35 | * scandir on FAT returns < 0, but errno is not set! Why does it fail? 36 | 37 | * serial input as a supplement to the keyboard? interrupt-driven, of course. 38 | Could be nice to use the native keymap inside the OS easily! 39 | 40 | * VFS: 41 | * Improve /etc/mounts and fs_mount to specify disk+partition instead of the current system of autodetecting and only supporting 1 initrd, 1 FAT and 1 ext2 partition 42 | 43 | * if getdents() is called *again* after returning 0, it will likely start over again; test this behaviour (also under Linux) and fix if necessary 44 | 45 | * FAT: write support! 46 | * DMA for ATA transfers? 47 | * Signal support 48 | * Proper VFS 49 | * Implement queues for mutexes 50 | * Directory caching - searching and stat()ing a "large" (20+ entries) directory is slow! 100+ is *very* slow! 51 | -------------------------------------------------------------------------------- /contrib/lua-5.2.3-exscapeos.patch: -------------------------------------------------------------------------------- 1 | diff -Naur lua-5.2.3/Makefile lua-5.2.3-exscapeos/Makefile 2 | --- lua-5.2.3/Makefile 2012-05-17 16:05:54.000000000 +0200 3 | +++ lua-5.2.3-exscapeos/Makefile 2013-01-01 15:34:06.000000000 +0100 4 | @@ -4,7 +4,7 @@ 5 | # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= 6 | 7 | # Your platform. See PLATS for possible values. 8 | -PLAT= none 9 | +PLAT= posix 10 | 11 | # Where to install. The installation starts in the src and doc directories, 12 | # so take care if INSTALL_TOP is not an absolute path. See the local target. 13 | diff -Naur lua-5.2.3/src/Makefile lua-5.2.3-exscapeos/src/Makefile 14 | --- lua-5.2.3/src/Makefile 2012-03-09 17:32:16.000000000 +0100 15 | +++ lua-5.2.3-exscapeos/src/Makefile 2013-01-01 15:33:58.000000000 +0100 16 | @@ -4,15 +4,15 @@ 17 | # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= 18 | 19 | # Your platform. See PLATS for possible values. 20 | -PLAT= none 21 | +PLAT= posix 22 | 23 | -CC= gcc 24 | -CFLAGS= -O2 -Wall -DLUA_COMPAT_ALL $(SYSCFLAGS) $(MYCFLAGS) 25 | +CC= i586-pc-exscapeos-gcc 26 | +CFLAGS= -O0 -ggdb3 -Wall -DLUA_COMPAT_ALL $(SYSCFLAGS) $(MYCFLAGS) 27 | LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS) 28 | LIBS= -lm $(SYSLIBS) $(MYLIBS) 29 | 30 | -AR= ar rcu 31 | -RANLIB= ranlib 32 | +AR= i586-pc-exscapeos-ar rcu 33 | +RANLIB= i586-pc-exscapeos-ranlib 34 | RM= rm -f 35 | 36 | SYSCFLAGS= 37 | diff -Naur lua-5.2.3/src/luaconf.h lua-5.2.3-exscapeos/src/luaconf.h 38 | --- lua-5.2.3/src/luaconf.h 2012-05-11 16:14:42.000000000 +0200 39 | +++ lua-5.2.3-exscapeos/src/luaconf.h 2013-01-01 16:41:33.000000000 +0100 40 | @@ -66,10 +66,10 @@ 41 | ** CHANGE it (define it) if your system is XSI compatible. 42 | */ 43 | #if defined(LUA_USE_POSIX) 44 | -#define LUA_USE_MKSTEMP 45 | +/*#define LUA_USE_MKSTEMP*/ 46 | #define LUA_USE_ISATTY 47 | #define LUA_USE_POPEN 48 | -#define LUA_USE_ULONGJMP 49 | +/*#define LUA_USE_ULONGJMP*/ 50 | #define LUA_USE_GMTIME_R 51 | #endif 52 | 53 | -------------------------------------------------------------------------------- /contrib/lua.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ $(basename $PWD) != "contrib" ]]; then 4 | echo 'This script must be run from the contrib directory, for now. (Ugh!)' 5 | exit 1 6 | fi 7 | 8 | if [[ -f "../initrd/bin/lua" ]]; then 9 | if [[ $1 != "-f" ]]; then 10 | echo 'Lua already installed; skipping (use -f to force reinstall)' 11 | exit 0 12 | fi 13 | fi 14 | 15 | W=$PWD 16 | pushd /tmp && 17 | if [[ ! -f "lua-5.2.3.tar.gz" ]]; then 18 | wget http://www.lua.org/ftp/lua-5.2.3.tar.gz; fi && 19 | tar xf lua-5.2.3.tar.gz && 20 | cd lua-5.2.3 && 21 | patch -p1 < $W/lua-5.2.3-exscapeos.patch && 22 | make -j8 && 23 | cp -f src/lua $W/../initrd/bin/lua && 24 | echo 'Successfully built and installed Lua!' 25 | 26 | popd 27 | -------------------------------------------------------------------------------- /exscapeos.bochs: -------------------------------------------------------------------------------- 1 | # configuration file generated by Bochs 2 | plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, parallel=1, serial=1 3 | config_interface: textconfig 4 | display_library: x 5 | memory: host=32, guest=32 6 | romimage: file="/usr/share/bochs/BIOS-bochs-latest" 7 | vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest" 8 | boot: cdrom 9 | floppy_bootsig_check: disabled=0 10 | # no floppya 11 | # no floppyb 12 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 13 | ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 14 | #ata1-master: type=cdrom, path="/home/serenity/Programming/exscapeOS/bootable.iso", status=inserted, biosdetect=auto, model="Generic 1234" 15 | ata1-master: type=cdrom, path="./bootable.iso", status=inserted, biosdetect=auto, model="Generic 1234" 16 | ata2: enabled=0 17 | ata3: enabled=0 18 | pci: enabled=0 19 | vga: extension=vbe, update_freq=5 20 | cpu: count=1, ips=4000000, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0 21 | cpuid: family=6, model=0x03, stepping=3, mmx=1, apic=xapic, sse=sse2, sse4a=0, sep=1, aes=0, xsave=0, xsaveopt=0, movbe=0, adx=0, smep=0, mwait=1 22 | cpuid: vendor_string="GenuineIntel" 23 | cpuid: brand_string=" Intel(R) Pentium(R) 4 CPU " 24 | 25 | print_timestamps: enabled=0 26 | # no gdb stub 27 | port_e9_hack: enabled=0 28 | private_colormap: enabled=0 29 | clock: sync=none, time0=local, rtc_sync=0 30 | # no cmosimage 31 | # no loader 32 | log: - 33 | logprefix: %t%e%d 34 | panic: action=ask 35 | error: action=report 36 | info: action=report 37 | debug: action=ignore 38 | keyboard: type=mf, serial_delay=250, paste_delay=100000, keymap= 39 | user_shortcut: keys=none 40 | mouse: enabled=0, type=ps2, toggle=ctrl+mbutton 41 | parport1: enabled=1, file="" 42 | parport2: enabled=0 43 | com1: enabled=1, mode=null, dev="" 44 | com2: enabled=0 45 | com3: enabled=0 46 | com4: enabled=0 47 | -------------------------------------------------------------------------------- /initrd/etc/mounts: -------------------------------------------------------------------------------- 1 | initrd / 2 | ext2 /ext2 3 | -------------------------------------------------------------------------------- /initrd/etc/shrc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Auto-execute commands on /bin/sh startup 4 | 5 | # ls -R bin etc 6 | # scandir 7 | -------------------------------------------------------------------------------- /initrd/etc/subsub/subsub_file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exscape/exscapeOS/babd32d00b47cfbab1bd5b224e797cafd4189cf8/initrd/etc/subsub/subsub_file -------------------------------------------------------------------------------- /initrd/fpu.lua: -------------------------------------------------------------------------------- 1 | for i = 0, 1000000, 1 do 2 | a = math.random() 3 | b = math.random() 4 | ans = {} 5 | 6 | for j = 0, 100, 1 do 7 | ans[j] = a + b 8 | end 9 | 10 | for j = 1, 100, 1 do 11 | if ans[j] ~= ans[0] then 12 | print ("CALCULATION ERROR") 13 | os.exit(1) 14 | end 15 | end 16 | end 17 | 18 | print ("Done") 19 | -------------------------------------------------------------------------------- /initrd/initrd_test.txt: -------------------------------------------------------------------------------- 1 | Some text for testing initrd storage and stuff like that. 2 | -------------------------------------------------------------------------------- /initrd/popen.lua: -------------------------------------------------------------------------------- 1 | local file = assert(io.popen('/bin/ls -la', 'r')) 2 | local output = file:read('*all') 3 | file:close() 4 | print(output) --> Prints the output of the command. 5 | -------------------------------------------------------------------------------- /initrd/test.txt: -------------------------------------------------------------------------------- 1 | Hello, world! This test string is 44 bytes. 2 | -------------------------------------------------------------------------------- /isofiles/boot/grub/menu.lst: -------------------------------------------------------------------------------- 1 | default 0 2 | hiddenmenu 3 | timeout 0 4 | 5 | title exscapeOS 6 | kernel /boot/kernel.bin root=initrd quiet 7 | module /boot/initrd.img 8 | -------------------------------------------------------------------------------- /isofiles/boot/grub/stage2_eltorito: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exscape/exscapeOS/babd32d00b47cfbab1bd5b224e797cafd4189cf8/isofiles/boot/grub/stage2_eltorito -------------------------------------------------------------------------------- /linker-kernel.ld: -------------------------------------------------------------------------------- 1 | ENTRY (loader) 2 | 3 | SECTIONS{ 4 | . = 0x00100000; 5 | 6 | 7 | /* The following header is to be used instead of the uncommented one 8 | * whenever the higher half kernel is implemented! 9 | */ 10 | /* .__mbHeader : AT( ADDR(.__mbHeader) - KERNEL'S_VIRTUAL_OFFSET_HERE ) { 11 | *(.__mbHeader) 12 | } 13 | */ 14 | .__mbHeader : { 15 | *(.__mbHeader) 16 | } 17 | 18 | __start_text = .; 19 | .text :{ 20 | *(.text) 21 | } 22 | __end_text = .; 23 | 24 | .rodata ALIGN (0x1000) : { 25 | *(.rodata) 26 | } 27 | 28 | .data ALIGN (0x1000) : { 29 | *(.data) 30 | } 31 | 32 | .bss : { 33 | sbss = .; 34 | *(COMMON) 35 | *(.bss) 36 | ebss = .; 37 | } 38 | 39 | end = .; 40 | _end = .; 41 | __end = .; 42 | } 43 | -------------------------------------------------------------------------------- /misc/Makefile: -------------------------------------------------------------------------------- 1 | all: create_initrd 2 | 3 | clean: 4 | rm create_initrd && rm -rf *.dSYM 5 | 6 | create_initrd: 7 | gcc -Wall -Werror -std=gnu99 -O0 -ggdb3 -o create_initrd src/create_initrd.c 8 | -------------------------------------------------------------------------------- /misc/create_initrd.py: -------------------------------------------------------------------------------- 1 | import struct, time, sys, os, datetime 2 | from ctypes import c_uint32 3 | 4 | _IFDIR = 0040000 5 | 6 | #struct fileheader { 7 | # int parent; /* inode of the parent directory; 0 for the root dir */ 8 | # int inode; /* inode of this file/directory; also 0 for the root dir */ 9 | # int mtime; 10 | # char name[64]; 11 | # uint32 mode; /* orig. file perms & ~0222 - includes S_ISDIR() */ 12 | # uint32 offset; /* # of bytes into initrd file is located. DIRS: 0 (N/A) */ 13 | # uint32 length; /* file: # bytes. dir: # direct child entries...? */ 14 | #}; 15 | structstr = 'iii64sIII' 16 | 17 | # Describes one file or directory on the initrd 18 | class File(object): 19 | def __init__(self, parent, inode, name, mode, length, path, mtime): 20 | self.parent = parent 21 | self.inode = inode 22 | self.name = name[:63] 23 | if (self.name != name): 24 | sys.stderr.write("WARNING: truncated filename \"{0}\" to \"{1}\"".format(name, self.name)) 25 | self.mode = c_uint32(mode & ~0222).value # remove write bit; initrd files are always read only 26 | self.offset = 0 # set up later 27 | self.length = length 28 | self.path = path 29 | assert mtime >= 0 30 | assert mtime < 2**31 - 1 31 | self.mtime = mtime 32 | def __repr__(self): 33 | return struct.pack(structstr, self.parent, self.inode, self.mtime, self.name, self.mode, self.offset, self.length) 34 | def __str__(self): 35 | return __repr__(self) 36 | 37 | # Creates an initrd image from a set of Files (see above) 38 | def create_image(output_path, files): 39 | if len(files) < 1: 40 | sys.stderr.write('Error: attempted to write 0 files') 41 | sys.exit(1) 42 | 43 | f = open(output_path, "w") 44 | header_fmt = 'i' 45 | f.write(struct.pack(header_fmt, len(files))) # write the initrd header 46 | 47 | # total data bytes 48 | total = 0 49 | 50 | print 'initrd header length: {0} bytes'.format(struct.calcsize(header_fmt)) 51 | print 'file header length: {0} bytes per file'.format(struct.calcsize(structstr)) 52 | 53 | # Write all the headers 54 | for file in files: 55 | if (file.mode & _IFDIR) == 0: 56 | file.offset = 4 + struct.calcsize(structstr) * len(files) + total # first header + all file headers + all previously written file data 57 | else: 58 | # Dirs have no data and thus no offset 59 | file.offset = 0 60 | 61 | # Set file.length to the number of child entries 62 | children = 0 63 | for _f in files: 64 | if _f.parent == file.inode: 65 | children += 1 66 | file.length = children 67 | 68 | f.write(file.__repr__()) 69 | readable_date = datetime.datetime.fromtimestamp(file.mtime).strftime('%Y-%m-%d %H:%M:%S') 70 | print "Wrote file header: parent={0} inode={1} mtime={2} name={3} mode={4} offset={5} length={6} {7}".format(file.parent, file.inode, readable_date, file.name, oct(file.mode), file.offset, file.length, "(# direct children)" if (file.mode & _IFDIR) else "") 71 | if (file.mode & _IFDIR) == 0: 72 | # Only files change the offset, not dirs! 73 | total += file.length 74 | 75 | # Write the file data 76 | for file in files: 77 | if (file.mode & _IFDIR): 78 | continue 79 | if (file.length == 0): 80 | print 'Skipping write of 0-length file {0}'.format(file.path) 81 | continue 82 | 83 | inf = open(file.path, "r") 84 | 85 | assert f.tell() == file.offset 86 | f.write(inf.read()) 87 | assert f.tell() == file.offset + file.length 88 | 89 | inf.close() 90 | 91 | print 'Wrote {0} bytes of data for file {1} at offset {2}, real path {3}'.format(file.length, file.name, file.offset, file.path) 92 | 93 | print 'Done creating initrd! Wrote {0} bytes.'.format(f.tell()) 94 | 95 | f.close() 96 | 97 | def inode_gen(): 98 | i = 1 99 | while True: 100 | yield i 101 | i += 1 102 | 103 | def parent_inode(path, files): 104 | dir = os.path.dirname(path) 105 | if len(dir) == 1 or dir == 'initrd': 106 | # root directory, inode 1 107 | return 1 108 | 109 | for file in files: 110 | if file.path == dir: 111 | return file.inode 112 | 113 | raise Exception('parent_node: parent for {0} not found!'.format(path)) 114 | 115 | def add_entry(found, root, dir): 116 | st = os.stat(os.path.join(root, dir)) 117 | mode = st.st_mode 118 | size = st.st_size 119 | mtime= st.st_mtime 120 | if (mode & _IFDIR): 121 | size = 0 122 | parent_ino = parent_inode(os.path.join(root, dir), found) 123 | this_inode = inode.next() 124 | f = File(parent_ino, this_inode, dir, mode, size, os.path.join(root, dir), mtime) 125 | found.append(f) 126 | 127 | if __name__ == '__main__': 128 | found = [] 129 | inode = inode_gen() 130 | 131 | found.append(File(0, 0, "", _IFDIR, 0, "", 0)) # Add the null entry (inode 0 is invalid in many utils) 132 | # add the root dir 133 | add_entry(found, 'initrd', '/') 134 | 135 | # loop through stuff 136 | for root, subdirs, files in os.walk('initrd', topdown=True): 137 | for dir in subdirs: 138 | add_entry(found, root, dir) 139 | for file in files: 140 | add_entry(found, root, file) 141 | 142 | # Don't recurse into fat or ext2 in case stuff's mounted there 143 | # in the host OS; however, the empty directories are added above 144 | subdirs[:] = [d for d in subdirs if d not in ['ext2', 'fat']] 145 | 146 | create_image('isofiles/boot/initrd.img', found) 147 | 148 | 149 | #f1 = File(0, 0, '/', 0777 | _IFDIR, 1, None) 150 | #f2 = File(0, 1, 'bin', 0777 | _IFDIR, 1, None) 151 | #f3 = File(1, 2, 'grep', 0755, 0x10402, "/bin/grep") 152 | #f4 = File(1, 3, 'ls', 0755, 0x123, "/bin/ls") 153 | #create_image('out.img', [f1, f2, f3, f4]) 154 | -------------------------------------------------------------------------------- /net-scripts/ifdown.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 'ifdown done (empty script)' 3 | -------------------------------------------------------------------------------- /net-scripts/ifup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo ifconfig tap2 192.168.10.1 && 4 | sudo sysctl -w net.inet.ip.forwarding=1 5 | -------------------------------------------------------------------------------- /net-scripts/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [[ ! -e "/dev/tap" ]]; then 3 | sudo kextload /Library/Extensions/tap.kext 4 | sudo ln -s /dev/tap2 /dev/tap 5 | fi 6 | -------------------------------------------------------------------------------- /simics.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | make && ~/simics/simics -e '$create_network=no' -e '$memory_megs=64' -e '$num_cpus=1' -e '$text_console=no' ~/simics/exscapeOS.simics 4 | -------------------------------------------------------------------------------- /src/include/kernel/ata.h: -------------------------------------------------------------------------------- 1 | #ifndef _ATA_H 2 | #define _ATA_H 3 | 4 | #include 5 | 6 | struct ata_device; 7 | #include /* partition_t */ 8 | 9 | typedef struct ata_channel { 10 | uint16 base; /* IO base address */ 11 | uint16 ctrl; /* Control reg base */ 12 | uint16 bmide; /* Bus master IDE */ 13 | } ata_channel_t; 14 | 15 | typedef struct ata_device { 16 | bool exists; /* true if any device exists here, whether it's ATAPI ( = unused) or not. */ 17 | uint8 channel; /* 0 (Primary) or 1 (Secondary) */ 18 | uint8 drive; /* 0 (Master) or 1 (Slave) */ 19 | bool is_atapi; /* false: regular ATA. true: ATAPI (mostly optical drives, these days) */ 20 | uint32 capabilities; /* this drive's capabilities, as defined by the ATA_CAPABILITY_* flags defined below */ 21 | uint64 size; /* size in sectors */ 22 | char model[41]; /* model as a NULL-terminated string. May be padded to 40 characters. */ 23 | char serial[21]; /* serial number as a NULL-terminated string. May be padded to 20 characters. */ 24 | uint8 ata_ver; /* the ATA version this disk conforms to */ 25 | uint8 max_udma_mode; /* 0 through 5; other values are invalid */ 26 | uint8 max_pio_mode; /* should be at least 3 for all ATA drives */ 27 | partition_t partition[4]; /* the 4 primary MBR partitions on this disk */ 28 | uint8 max_sectors_multiple; /* how many sectors READ MULTIPLE can work with per block */ 29 | } ata_device_t; 30 | 31 | void ata_init(void); /* detects drives and creates the structures used */ 32 | bool ata_read(ata_device_t *dev, uint64 lba, void *buffer, int sectors); 33 | bool ata_write(ata_device_t *dev, uint64 lba, void *buffer, int sectors); 34 | 35 | bool disk_read(ata_device_t *dev, uint64 start_lba, uint32 bytes, void *buffer); /* reads a buffer */ 36 | bool disk_write(ata_device_t *dev, uint64 start_lba, uint32 bytes, void *buffer); 37 | 38 | extern ata_channel_t channels[2]; 39 | extern ata_device_t devices[4]; 40 | 41 | #define ATA_REG_BASE_PRI 0x1f0 42 | #define ATA_REG_BASE_SEC 0x170 43 | 44 | /* Offsets from the base addresses above */ 45 | #define ATA_REG_DATA 0 46 | #define ATA_REG_ERROR 1 47 | #define ATA_REG_FEATURES 1 /* features on write; is this used for non-ATAPI? */ 48 | #define ATA_REG_SECTOR_COUNT 2 49 | #define ATA_REG_LBA_LO 3 /* also sector number */ 50 | #define ATA_REG_LBA_MID 4 /* also cylinder low */ 51 | #define ATA_REG_LBA_HI 5 /* also cylinder high */ 52 | #define ATA_REG_DRIVE_SELECT 6 /* also head */ 53 | #define ATA_REG_COMMAND 7 /* acts as command on write... */ 54 | #define ATA_REG_STATUS 7 /* ... and status on read */ 55 | 56 | #define ATA_REG_DEV_CONTROL 0xffff /* Used internally */ 57 | #define ATA_REG_ALT_STATUS 0xffff /* Used internally */ 58 | #define ATA_REG_DEV_CONTROL_PRI 0x3f6 /* device control / alt. status reg */ 59 | #define ATA_REG_DEV_CONTROL_SEC 0x376 60 | 61 | /* The three bits that we're allowed to touch in the device control register */ 62 | #define ATA_REG_DEV_CONTROL_NIEN (1 << 1) /* interrupts disabled if 1 */ 63 | #define ATA_REG_DEV_CONTROL_SRST (1 << 2) /* Software reset bit */ 64 | #define ATA_REG_DEV_CONTROL_HOB (1 << 7) /* High Order Bit, used for LBA48 */ 65 | 66 | /* ATA commands we use */ 67 | #define ATA_CMD_IDENTIFY 0xec 68 | #define ATA_CMD_READ_SECTORS 0x20 69 | #define ATA_CMD_WRITE_SECTORS 0x30 70 | #define ATA_CMD_READ_MULTIPLE 0xc4 71 | #define ATA_CMD_WRITE_MULTIPLE 0xc5 72 | #define ATA_CMD_SET_MULTIPLE_MODE 0xc6 73 | #define ATA_CMD_SET_FEATURES 0xef 74 | 75 | /* SET FEATURES subcommands */ 76 | #define ATA_SF_SET_TRANSFER_MODE 0x03 77 | 78 | /* Drive IDs to be sent to the drive select IO port */ 79 | #define ATA_DRIVE 0xa0 /* base command */ 80 | #define ATA_MASTER 0 /* usage: ATA_DRIVE | (ATA_MASTER << 4) */ 81 | #define ATA_SLAVE 1 /* usage: ATA_DRIVE | (ATA_SLAVE << 4) */ 82 | 83 | /* Used internally (not defined in the ATA standard) */ 84 | #define ATA_PRIMARY 0 85 | #define ATA_SECONDARY 1 86 | 87 | /* ATA status register flags */ 88 | #define ATA_SR_BSY 0x80 89 | #define ATA_SR_DRDY 0x40 90 | #define ATA_SR_DF 0x20 91 | #define ATA_SR_DSC 0x10 92 | #define ATA_SR_DRQ 0x08 93 | /*#define ATA_SR_CORR 0x04*/ /* marked as obsolete in ATA-ATAPI 6 */ 94 | /*#define ATA_SR_IDX 0x02*/ /* same as above */ 95 | #define ATA_SR_ERR 0x01 96 | 97 | /* The flags in the error register */ 98 | #define ATA_ER_BBK 0x80 99 | #define ATA_ER_UNC 0x40 100 | #define ATA_ER_WP 0x40 101 | #define ATA_ER_MC 0x20 102 | #define ATA_ER_IDNF 0x10 103 | #define ATA_ER_MCR 0x08 104 | #define ATA_ER_ABRT 0x04 105 | #define ATA_ER_TK0NF 0x02 106 | #define ATA_ER_NM (1 << 1) 107 | #define ATA_ER_AMNF 0x01 108 | 109 | /* Flags used in the ata_device_t capabilities field - not defined in any standard */ 110 | #define ATA_CAPABILITY_LBA28 (1 << 0) 111 | #define ATA_CAPABILITY_LBA48 (1 << 1) 112 | #define ATA_CAPABILITY_WRITE_CACHE (1 << 2) 113 | #define ATA_CAPABILITY_FLUSH_CACHE (1 << 3) 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /src/include/kernel/backtrace.h: -------------------------------------------------------------------------------- 1 | #ifndef _BACKTRACE_H 2 | #define _BACKTRACE_H 3 | 4 | #include 5 | 6 | struct symbol { 7 | uint32 eip; 8 | const char *name; 9 | }; 10 | 11 | struct symbol *addr_to_func(uint32 eip); 12 | 13 | #define BACKTRACE_MAX 16 14 | // Lower indexes = deeper nesting 15 | struct backtrace { 16 | uint32 eip[BACKTRACE_MAX]; 17 | }; 18 | 19 | void get_backtrace(uint32 _ebp, struct backtrace *bt); 20 | void print_backtrace_struct(struct backtrace *bt); 21 | void print_backtrace(void); 22 | void print_backtrace_ebp(uint32 _ebp); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/include/kernel/console.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONSOLE_H 2 | #define _CONSOLE_H 3 | #include 4 | #include 5 | #include 6 | 7 | /* A ring buffer that stores keystrokes to a console */ 8 | typedef struct ringbuffer { 9 | volatile unsigned char data[KEYBUFFER_SIZE]; 10 | volatile unsigned char *read_ptr; 11 | volatile unsigned char *write_ptr; /* volatile is probably not needed */ 12 | volatile uint32 counter; /* how much unread data is stored? */ 13 | } ringbuffer_t; 14 | 15 | /* Defines a single virtual console */ 16 | typedef struct console { 17 | list_t *tasks; 18 | bool active; 19 | Point cursor; 20 | volatile struct ringbuffer keybuffer; 21 | uint16 *buffer; // ring buffer for scrollback + onscreen data 22 | uint16 *bufferptr; // pointer to the current "start" of the ring buffer 23 | uint16 current_position; // how many lines have we scrolled back? 24 | uint8 text_color; 25 | uint8 back_color; 26 | } console_t; 27 | 28 | #define NUM_SCROLLBACK 150 // how many screens worth of scrollback should each console have? 29 | #define MAX_SCROLLBACK ((24*NUM_SCROLLBACK) - 1) // how many LINES can we scroll back maximum? 30 | #define CONSOLE_BUFFER_SIZE (80*24*(NUM_SCROLLBACK+1)) // number of CHARACTERS (one character uses 16 bits) 31 | #define CONSOLE_BUFFER_SIZE_BYTES (CONSOLE_BUFFER_SIZE * 2) // number of BYTES, for kmalloc etc. 32 | 33 | #include /* must be done after defining console_t */ 34 | 35 | // 80x25 text mode color values 36 | #define BLACK 0 37 | #define BLUE 1 38 | #define GREEN 2 39 | #define CYAN 3 40 | #define RED 4 41 | #define MAGENTA 5 42 | #define BROWN 6 43 | #define LIGHT_GREY 7 44 | #define DARK_GREY 8 45 | #define LIGHT_BLUE 9 46 | #define LIGHT_GREEN 10 47 | #define LIGHT_CYAN 11 48 | #define LIGHT_RED 12 49 | #define LIGHT_MAGENTA 13 50 | #define LIGHT_BROWN 14 51 | #define WHITE 15 52 | // Bits to shift these values to get them in place 53 | #define BGCOLOR 12 54 | #define FGCOLOR 8 55 | 56 | void set_text_color(int color); 57 | void set_back_color(int color); 58 | 59 | /* If true, all output will be on the current console, no matter who's writing */ 60 | extern volatile bool force_current_console; 61 | 62 | int getchar(void); 63 | 64 | void scrollback_up(void); 65 | void scrollback_down(void); 66 | void scrollback_pgup(void); 67 | void scrollback_pgdown(void); 68 | void scrollback_reset(void); 69 | 70 | // Called by the timer; would be static otherwise 71 | void update_statusbar(void); 72 | 73 | extern volatile console_t *current_console; 74 | extern console_t kernel_console; 75 | 76 | #define NUM_VIRTUAL_CONSOLES 4 77 | extern console_t *virtual_consoles[NUM_VIRTUAL_CONSOLES]; 78 | 79 | void console_destroy(console_t *con); 80 | console_t *console_create(void); 81 | void console_init(console_t *new); 82 | void console_switch(console_t *new); 83 | 84 | int putchar(int c); 85 | void init_video(void); 86 | void clrscr(void); 87 | void update_cursor(void); 88 | void scroll(void); 89 | size_t printc(int back_color, int text_color, const char *fmt, ...); // printk with colors 90 | size_t printk(const char *fmt, ...); 91 | int puts(const char *s); 92 | int puts_xy(const char *s, int x, int y); 93 | 94 | Point get_cursor(void); 95 | bool set_cursor(int x, int y); 96 | void cursor_left(void); 97 | void cursor_right(void); 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /src/include/kernel/fat.h: -------------------------------------------------------------------------------- 1 | #ifndef _FAT_H 2 | #define _FAT_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | bool fat_detect(ata_device_t *dev, uint8 part); 9 | 10 | #define ATTRIB_READONLY 0x1 11 | #define ATTRIB_HIDDEN 0x2 12 | #define ATTRIB_SYSTEM 0x4 13 | #define ATTRIB_VOLUME_ID 0x8 14 | #define ATTRIB_DIR 0x10 15 | #define ATTRIB_ARCHIVE 0x20 16 | 17 | /* Used for Long File Name entries */ 18 | #define ATTRIB_LFN (ATTRIB_READONLY | ATTRIB_HIDDEN | ATTRIB_SYSTEM | ATTRIB_VOLUME_ID) 19 | 20 | /* Describes the FAT BPB (BIOS Parameter Block); shared between FAT12/FAT16/FAT32 */ 21 | struct fat32_bpb { 22 | uint8 jmp[3]; /* x86 code to jump past the following data */ 23 | char oem_ident[8]; 24 | uint16 bytes_per_sector; 25 | uint8 sectors_per_cluster; 26 | uint16 reserved_sectors; 27 | uint8 num_fats; 28 | uint16 num_direntries; 29 | uint16 small_total_sectors; /* 0 if >65535 sectors, i.e. for all FAT32 partitions? see below */ 30 | uint8 media_descr_type; /* 0xf8 == hard disk */ 31 | uint16 ignore; /* FAT12/FAT16 only */ 32 | uint16 sect_per_track; 33 | uint16 heads; 34 | uint32 hidden_sectors; /* relative LBA */ 35 | uint32 total_sectors; /* used if >65535 sectors, i.e. all FAT32 partitions? */ 36 | 37 | /* Describes the FAT32 EBPB, located just after the BPB (above). 38 | * Note that if this struct is mapped onto a partition that is actually 39 | * FAT12/FAT16, the values will be wildly incorrect! 40 | */ 41 | uint32 sectors_per_fat; /* FAT size, in sectors */ 42 | uint16 flags; 43 | uint8 fat_major_version; 44 | uint8 fat_minor_version; /* these two MAY be swapped */ 45 | uint32 root_cluster_num; 46 | uint16 fsinfo_cluster_num; 47 | uint16 backup_bs_cluster_num; 48 | uint8 reserved[12]; /* should be all 0 */ 49 | uint8 drive_number; 50 | uint8 reserved2; /* "Flags in Windows NT. Reserved otherwise. */ 51 | uint8 signature; /* 0x28 or 0x29 */ 52 | uint32 volumeid_serial; 53 | char volume_label[11]; /* space padded */ 54 | } __attribute__((packed)); 55 | typedef struct fat32_bpb fat32_bpb_t; 56 | 57 | #define FAT32_MAGIC 0x1234fedc 58 | typedef struct fat32_partition { 59 | uint32 magic; // used to verify this entry in the device table 60 | ata_device_t *dev; /* the device that holds this partition */ 61 | uint32 fat_start_lba; /* the LBA where the FAT begins */ 62 | uint32 end_lba; /* last valid LBA for this partition */ 63 | uint32 cluster_start_lba; 64 | uint32 sectors_per_cluster; 65 | uint32 root_dir_first_cluster; 66 | uint32 cluster_size; /* part->cluster_size is easier than part->bpb->sectors_per_cluster * 512 */ 67 | 68 | /* TODO: better naming. This is a pointer back to the dev->partition[x] structure. */ 69 | partition_t *part_info; 70 | 71 | /* The entire BPB and EBPB data structures for this partition */ 72 | fat32_bpb_t *bpb; 73 | 74 | mountpoint_t *mp; 75 | 76 | uint8 *cached_fat; 77 | } fat32_partition_t; 78 | 79 | /* Time format used in fat32_direntry_t */ 80 | typedef struct fat32_time { 81 | uint16 second : 5; 82 | uint16 minute : 6; 83 | uint16 hour : 5; 84 | } __attribute__((packed)) fat32_time_t; 85 | 86 | /* Date format used in fat32_direntry_t. Relative to 1980-01-01 */ 87 | typedef struct fat32_date { 88 | uint16 day : 5; 89 | uint16 month : 4; 90 | uint16 year : 7; 91 | } __attribute__((packed)) fat32_date_t; 92 | 93 | typedef struct fat32_direntry { 94 | char name[11]; /* 8.3 file name; the 8 part is space padded if shorter */ 95 | uint8 attrib; 96 | uint8 reserved; 97 | uint8 created_10ths; 98 | 99 | fat32_time_t create_time; 100 | fat32_date_t create_date; 101 | 102 | fat32_date_t access_date; 103 | 104 | uint16 high_cluster_num; 105 | 106 | fat32_time_t mod_time; 107 | fat32_date_t mod_date; 108 | 109 | uint16 low_cluster_num; 110 | uint32 file_size; 111 | } __attribute__((packed)) fat32_direntry_t; 112 | 113 | /* Maps on to a dir fat32_direntry_t if attrib == 0xF (ATTRIB_LFN) */ 114 | typedef uint16 UTF16_char; 115 | typedef struct fat32_lfn { 116 | uint8 entry; 117 | UTF16_char name_1[5]; 118 | uint8 attrib; /* Always 0xF for LFN entries */ 119 | uint8 long_entry_type; /* should be 0 for all LFN entries */ 120 | uint8 checksum; 121 | UTF16_char name_2[6]; 122 | char zero[2]; /* always zero */ 123 | UTF16_char name_3[2]; 124 | } __attribute__((packed)) fat32_lfn_t; 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /src/include/kernel/fpu.h: -------------------------------------------------------------------------------- 1 | #ifndef _FPU_H 2 | #define _FPU_H 3 | 4 | void fpu_init(void); 5 | 6 | // Note: this struct must always be 16-byte aligned, e.g. using __attribute__((aligned(16))), or 7 | // page-aligned kmalloc. 8 | typedef struct fpu_mmx_state { 9 | char data[512]; 10 | } fpu_mmx_state_t; 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/include/kernel/gdt.h: -------------------------------------------------------------------------------- 1 | #ifndef _GDT_H 2 | #define _GDT_H 3 | 4 | /* A single GDT entry. Needs to be packed! */ 5 | struct gdt_entry { 6 | uint16 limit_low; 7 | uint16 base_low; 8 | uint8 base_middle; 9 | uint8 access; 10 | uint8 granularity; 11 | uint8 base_high; 12 | } __attribute__((packed)); 13 | 14 | /* The 48-bit GDT pointer used by the LGDT instruction */ 15 | struct gdt_ptr { 16 | uint16 limit; 17 | uint32 base; 18 | } __attribute__((packed)); 19 | 20 | void gdt_set_gate(sint32 num, uint32 base, uint32 limit, uint8 access, uint8 gran); 21 | void gdt_install(void); 22 | void gdt_flush(void); 23 | 24 | struct tss_entry 25 | { 26 | uint32 prev_tss; // The previous TSS - if we used hardware task switching this would form a linked list. 27 | uint32 esp0; // The stack pointer to load when we change to kernel mode. 28 | uint32 ss0; // The stack segment to load when we change to kernel mode. 29 | uint32 esp1; // Unused... (This entry an all uncommented ones) 30 | uint32 ss1; 31 | uint32 esp2; 32 | uint32 ss2; 33 | uint32 cr3; 34 | uint32 eip; 35 | uint32 eflags; 36 | uint32 eax; 37 | uint32 ecx; 38 | uint32 edx; 39 | uint32 ebx; 40 | uint32 esp; 41 | uint32 ebp; 42 | uint32 esi; 43 | uint32 edi; 44 | uint32 es; // The value to load into ES when we change to kernel mode. 45 | uint32 cs; // The value to load into CS when we change to kernel mode. 46 | uint32 ss; // The value to load into SS when we change to kernel mode. 47 | uint32 ds; // The value to load into DS when we change to kernel mode. 48 | uint32 fs; // The value to load into FS when we change to kernel mode. 49 | uint32 gs; // The value to load into GS when we change to kernel mode. 50 | uint32 ldt; // Unused... 51 | uint16 trap; 52 | uint16 iomap_base; 53 | } __attribute__((packed)); 54 | 55 | typedef struct tss_entry tss_entry_t; 56 | 57 | void tss_switch(uint32 esp0, uint32 esp, uint32 ss); 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/include/kernel/heap.h: -------------------------------------------------------------------------------- 1 | #ifndef _KHEAP_H 2 | #define _KHEAP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /************************ 10 | **** HEAP FUNCTIONS **** 11 | ************************/ 12 | 13 | #define IS_PAGE_ALIGNED(x) (( ((uint32)(x)) & 0x00000fff) == 0) 14 | #define IS_DWORD_ALIGNED(x) (( ((uint32)(x)) & 3) == 0) 15 | 16 | #define HEAP_MAGIC 0xabcdef12 17 | 18 | #define AREA_USED 0 19 | #define AREA_FREE 1 20 | 21 | #define FOOTER_FROM_HEADER(__h) ((area_footer_t *)((uint32)__h + __h->size - sizeof(area_footer_t))) 22 | 23 | /* Describes an area header; placed before every block (free or used) */ 24 | typedef struct { 25 | uint32 size; /* includes the header and footer! */ 26 | uint8 type; /* == AREA_USED (0) || AREA_FREE (1) */ 27 | uint32 magic; 28 | } area_header_t; 29 | 30 | /* Describes an area footer; placed after every block (free or used) */ 31 | typedef struct { 32 | uint32 magic; 33 | area_header_t *header; 34 | } area_footer_t; 35 | 36 | /* Describes a heap structure - only one is used in the entire kernel */ 37 | typedef struct { 38 | uint32 start_address; 39 | uint32 end_address; 40 | uint32 _min_address; // start address is for the storage; _min_address for the entire heap w/ indexes etc. 41 | uint32 max_address; 42 | uint8 supervisor; 43 | uint8 readonly; 44 | 45 | ordered_array_t free_index; /* Stores an array of area_header_t pointers */ 46 | ordered_array_t used_index; /* Stores an array of area_header_t pointers */ 47 | 48 | area_header_t *rightmost_area; /* A pointer to the rightmost area, free or used. Used in both alloc() and free(). */ 49 | 50 | mutex_t *mutex; 51 | } heap_t; 52 | 53 | /* 65536 areas (per array; one for free areas, one for used areas) */ 54 | #define HEAP_INDEX_SIZE 0x10000 55 | 56 | #define KHEAP_START 0xc0000000 57 | #define KHEAP_MAX_ADDR 0xcffff000 /* one page less than 0xd000000 */ 58 | 59 | /* Set up the heap location, and start off with a 4 MiB heap */ 60 | //#define KHEAP_INITIAL_SIZE 0x400000 /* 4 MiB; KEEP IN MIND that this MUST be larger than 2 * sizeof(type_t) * HEAP_INDEX_SIZE! */ 61 | //#define HEAP_MIN_GROWTH 0x200000 /* 2 MiB; the smallest amount the heap is expanded by for each call to heap_expand() */ 62 | //#define HEAP_MAX_WASTE 0x400000 /* 4 MiB; the largest the rightmost area (if it's free) is allowed to be before the heap is contracted */ 63 | 64 | /* Values for heap debugging */ 65 | #define KHEAP_INITIAL_SIZE 0x90000 /* 64 kiB + 512k for the indexes */ 66 | #define KHEAP_MIN_GROWTH 0x8000 /* 32 kiB */ 67 | #define KHEAP_MAX_WASTE 0x120000 /* must be >1 MiB */ 68 | 69 | #define USER_HEAP_INITIAL_SIZE 0x90000 70 | #define USER_HEAP_MIN_GROWTH 0x8000 71 | #define USER_HEAP_MAX_WASTE 0x120000 72 | 73 | #define USER_HEAP_START 0x20000000 74 | #define USER_HEAP_MAX_ADDR 0xbff00000 75 | 76 | void stop_leak_trace(void); 77 | void start_leak_trace(void); 78 | 79 | heap_t *heap_create(uint32 start_address, uint32 initial_size, uint32 max_address, uint8 supervisor, uint8 readonly, struct task_mm *mm); 80 | void heap_destroy(heap_t *heap, page_directory_t *dir); 81 | void *heap_alloc(uint32 size, bool page_align, heap_t *heap); 82 | void heap_free(void *p, heap_t *heap); 83 | 84 | void validate_heap_index(bool print_headers); 85 | void print_heap_index(void); 86 | 87 | void kfree(void *p); 88 | 89 | uint32 kheap_used_bytes(void); 90 | 91 | // user space/syscalls (until a proper user space heap w/ brk() and sbrk() exists) 92 | void *malloc(size_t); 93 | void free(void *); 94 | 95 | /********************************* 96 | **** PRE-HEAP/HEAP FUNCTIONS **** 97 | *********************************/ 98 | 99 | /* Allocate /size/ bytes of memory. 100 | * If align == true, the return value will be page aligned. 101 | * If phys isn't NULL, it will be set to the physical address of the allocated area. 102 | */ 103 | void *kmalloc_int(uint32 size, bool align, uint32 *phys); 104 | 105 | /* 106 | * Tests whether a pointer belongs to the kernel heap or not. 107 | * Useful for checking use-after-free bugs. 108 | */ 109 | bool kheap_is_valid(void *p); 110 | 111 | /* Plain kmalloc; not page-aligned, doesn't return the physical address */ 112 | void *kmalloc(uint32 size); 113 | 114 | /* Page-aligned kmalloc */ 115 | void *kmalloc_a(uint32 size); 116 | 117 | /* Returns the physical address in phys, but doesn't page align. */ 118 | void *kmalloc_p(uint32 size, uint32 *phys); 119 | 120 | /* Returns the physical address in phys, and page aligns. */ 121 | void *kmalloc_ap(uint32 size, uint32 *phys); 122 | 123 | /* Expand the size of an existing allocation. */ 124 | void *krealloc(void *p, size_t new_size); 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /src/include/kernel/initrd.h: -------------------------------------------------------------------------------- 1 | #ifndef _INITRD_H 2 | #define _INITRD_H 3 | 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | uint32 nfiles; 9 | } initrd_header_t; 10 | 11 | /* Also defined in create_initrd.c */ 12 | typedef struct { 13 | int parent; /* inode of the parent directory; 1 for the root dir */ 14 | int inode; /* inode of this file/directory; also 1 for the root dir */ 15 | int mtime; /* unix timestamp */ 16 | char name[64]; 17 | uint32 mode; /* orig. file perms & ~0222 - includes S_ISDIR() etc. flags */ 18 | uint32 offset; /* # of bytes into initrd file is located. 0 for directories */ 19 | uint32 length; /* file: # bytes. dir: # direct child entries...? */ 20 | } initrd_file_header_t; 21 | 22 | /* Creates the initrd; the argument is the memory location of the multiboot module */ 23 | void init_initrd(uint32 location); 24 | bool fs_mount(void); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/include/kernel/interrupts.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTERRUPTS_H 2 | #define _INTERRUPTS_H 3 | 4 | #include 5 | 6 | #define EXCEPTION_DIVISION_BY_ZERO 0 7 | #define EXCEPTION_DEBUG 1 /* Reserved in modern CPUs */ 8 | #define EXCEPTION_NMI_INTERRUPT 2 9 | #define EXCEPTION_BREAKPOINT 3 10 | #define EXCEPTION_OVERFLOW 4 11 | #define EXCEPTION_OUT_OF_BOUNDS 5 12 | #define EXCEPTION_INVALID_OPCODE 6 13 | #define EXCEPTION_NO_COPROCESSOR 7 14 | #define EXCEPTION_DOUBLE_FAULT 8 15 | #define EXCEPTION_COPROCESSOR_SEGMENT_OVERRUN 9 /* not used by modern CPUs */ 16 | #define EXCEPTION_BAD_TSS 10 17 | #define EXCEPTION_SEGMENT_NOT_PRESENT 11 18 | #define EXCEPTION_STACK_FAULT 12 19 | #define EXCEPTION_GPF 13 20 | #define EXCEPTION_PAGE_FAULT 14 21 | #define EXCEPTION_UNKNOWN_INTERRUPT 15 22 | #define EXCEPTION_X86_FPU_ERROR 16 /* aka Math Fault */ 23 | #define EXCEPTION_ALIGNMENT_CHECK 17 24 | #define EXCEPTION_MACHINE_CHECK 18 25 | #define EXCEPTION_SIMD_FP_EXCEPTION 19 26 | 27 | #define INTERRUPT_LOCK bool reenable_interrupts = interrupts_enabled(); disable_interrupts() 28 | #define INTERRUPT_UNLOCK if (reenable_interrupts) enable_interrupts() 29 | #define YIELD asm volatile("int $0x7e") 30 | 31 | void idt_install(void); 32 | 33 | void disable_interrupts(void); 34 | void enable_interrupts(void); 35 | bool interrupts_enabled(void); 36 | 37 | void dump_regs_and_bt(uint32 esp); 38 | 39 | struct idt_entry { 40 | uint16 base_lo; 41 | uint16 sel; 42 | uint8 always0; 43 | uint8 flags; 44 | uint16 base_hi; 45 | } __attribute__((packed)); 46 | 47 | struct idt_ptr { 48 | uint16 limit; 49 | uint32 base; 50 | } __attribute__((packed)); 51 | 52 | typedef struct 53 | { 54 | uint32 gs, fs, es, ds; 55 | uint32 edi, esi, ebp, ebx, edx, ecx, eax; 56 | uint32 int_no, err_code; 57 | uint32 eip, cs, eflags, useresp, ss; 58 | } __attribute__((packed)) registers_t; 59 | 60 | /* Used to register callbacks for interrupts. */ 61 | typedef uint32 (*isr_t)(uint32); 62 | void register_interrupt_handler(uint8 n, isr_t handler); 63 | 64 | /* The mapping of IRQs to ISR handlers. */ 65 | #define IRQ0 32 66 | #define IRQ1 33 67 | #define IRQ2 34 68 | #define IRQ3 35 69 | #define IRQ4 36 70 | #define IRQ5 37 71 | #define IRQ6 38 72 | #define IRQ7 39 73 | #define IRQ8 40 74 | #define IRQ9 41 75 | #define IRQ10 42 76 | #define IRQ11 43 77 | #define IRQ12 44 78 | #define IRQ13 45 79 | #define IRQ14 46 80 | #define IRQ15 47 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/include/kernel/kernutil.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNUTIL_H 2 | #define _KERNUTIL_H 3 | 4 | #include 5 | 6 | uint8 inb(uint16 port); 7 | uint16 inw(uint16 port); 8 | uint32 inl(uint16 port); 9 | 10 | void outb(uint16 port, uint8 value); 11 | void outw(uint16 port, uint16 value); 12 | void outl(uint16 port, uint32 value); 13 | 14 | void panic(const char *fmt, ...) __attribute__((noreturn)); 15 | void reset(void) __attribute__((noreturn)); 16 | void reboot(void) __attribute__((noreturn)); 17 | 18 | #define assert(b) ((b) ? (void)0 : panic_assert(__FILE__, __LINE__, #b)) 19 | extern void panic_assert(const char *file, uint32 line, const char *desc); 20 | 21 | /* timer.c */ 22 | void timer_install(void); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/include/kernel/keyboard.h: -------------------------------------------------------------------------------- 1 | #ifndef _KEYBOARD_H 2 | #define _KEYBOARD_H 3 | 4 | #include /* registers_t */ 5 | 6 | #define KEYBUFFER_SIZE 256 7 | 8 | uint32 keyboard_callback(uint32 esp); 9 | void init_keyboard(void); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/include/kernel/kshell.h: -------------------------------------------------------------------------------- 1 | #ifndef _KSHELL_H 2 | #define _KSHELL_H 3 | 4 | void kshell(void *data, uint32 length); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/include/kernel/list.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIST_H 2 | #define _LIST_H 3 | 4 | #include 5 | 6 | struct list; /* forward declaration due to its use in the node struct */ 7 | 8 | /* A single node in the list */ 9 | typedef struct node { 10 | void *data; 11 | struct node *prev; 12 | struct node *next; 13 | struct list *list; /* the list that this node belongs to */ 14 | } node_t; 15 | 16 | struct _mutex; 17 | 18 | typedef struct list { 19 | node_t *head; 20 | node_t *tail; 21 | uint32 count; /* number of items in the list */ 22 | struct _mutex *mutex; 23 | } list_t; 24 | 25 | #define list_foreach(list, iterator) for (node_t *iterator = list->head; iterator != NULL; iterator = iterator->next) 26 | #define list_foreach_dot(list, iterator) for (node_t *iterator = list.head; iterator != NULL; iterator = iterator->next) 27 | 28 | uint32 list_size(list_t *list); 29 | list_t *list_create(void); 30 | list_t *list_copy(list_t *orig, void *(*_copy_data)(void *) ); 31 | node_t *list_prepend(list_t *list, void *data); 32 | node_t *list_append(list_t *list, void *data); 33 | node_t *list_node_insert_before(node_t *node, void *data); 34 | node_t *list_node_insert_after(node_t *node, void *data); 35 | void list_remove_node(list_t *list, node_t *elem); 36 | void list_destroy(list_t *list); 37 | node_t *list_find_first(list_t *list, void *data); 38 | node_t *list_find_last(list_t *list, void *data); 39 | 40 | bool list_remove_first(list_t *list, void *data); 41 | bool list_remove_last(list_t *list, void *data); 42 | 43 | /* I'm not overly proud about this one. It finds the next node that the predicate function returns true for. 44 | * The name, despite its length, doesn't point out that it "loops back" to the beginning of the list 45 | * if the end is reached without a hit, though. Essentially this is a "ring" function, not a "list" one. */ 46 | node_t *list_node_find_next_predicate(node_t *node, bool (*predicate_func)(node_t *) ); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/include/kernel/multiboot.h: -------------------------------------------------------------------------------- 1 | /* multiboot.h - the header for Multiboot */ 2 | /* Copyright (C) 1999, 2001 Free Software Foundation, Inc. 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ 17 | 18 | /* Macros. */ 19 | 20 | /* The magic number for the Multiboot header. */ 21 | #define MULTIBOOT_HEADER_MAGIC 0x1BADB002 22 | 23 | /* The flags for the Multiboot header. */ 24 | #ifdef __ELF__ 25 | # define MULTIBOOT_HEADER_FLAGS 0x00000003 26 | #else 27 | # define MULTIBOOT_HEADER_FLAGS 0x00010003 28 | #endif 29 | 30 | /* The magic number passed by a Multiboot-compliant boot loader. */ 31 | #define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 32 | 33 | /* The size of our stack (16KB). */ 34 | #define STACK_SIZE 0x4000 35 | 36 | /* C symbol format. HAVE_ASM_USCORE is defined by configure. */ 37 | #ifdef HAVE_ASM_USCORE 38 | # define EXT_C(sym) _ ## sym 39 | #else 40 | # define EXT_C(sym) sym 41 | #endif 42 | 43 | #ifndef ASM 44 | /* Do not include here in boot.S. */ 45 | 46 | /* Types. */ 47 | 48 | /* The Multiboot header. */ 49 | typedef struct multiboot_header 50 | { 51 | unsigned long magic; 52 | unsigned long flags; 53 | unsigned long checksum; 54 | unsigned long header_addr; 55 | unsigned long load_addr; 56 | unsigned long load_end_addr; 57 | unsigned long bss_end_addr; 58 | unsigned long entry_addr; 59 | } multiboot_header_t; 60 | 61 | /* The symbol table for a.out. */ 62 | typedef struct aout_symbol_table 63 | { 64 | unsigned long tabsize; 65 | unsigned long strsize; 66 | unsigned long addr; 67 | unsigned long reserved; 68 | } aout_symbol_table_t; 69 | 70 | /* The section header table for ELF. */ 71 | typedef struct elf_section_header_table 72 | { 73 | unsigned long num; 74 | unsigned long size; 75 | unsigned long addr; 76 | unsigned long shndx; 77 | } elf_section_header_table_t; 78 | 79 | /* The Multiboot information. */ 80 | typedef struct multiboot_info 81 | { 82 | unsigned long flags; 83 | unsigned long mem_lower; 84 | unsigned long mem_upper; 85 | unsigned long boot_device; 86 | unsigned long cmdline; 87 | unsigned long mods_count; 88 | unsigned long mods_addr; 89 | union 90 | { 91 | aout_symbol_table_t aout_sym; 92 | elf_section_header_table_t elf_sec; 93 | } u; 94 | unsigned long mmap_length; 95 | unsigned long mmap_addr; 96 | } multiboot_info_t; 97 | 98 | /* The module structure. */ 99 | typedef struct module 100 | { 101 | unsigned long mod_start; 102 | unsigned long mod_end; 103 | unsigned long string; 104 | unsigned long reserved; 105 | } module_t; 106 | 107 | /* The memory map. Be careful that the offset 0 is base_addr_low 108 | but no size. */ 109 | typedef struct memory_map 110 | { 111 | unsigned long size; 112 | unsigned long base_addr_low; 113 | unsigned long base_addr_high; 114 | unsigned long length_low; 115 | unsigned long length_high; 116 | unsigned long type; 117 | } memory_map_t; 118 | 119 | #endif /* ! ASM */ 120 | -------------------------------------------------------------------------------- /src/include/kernel/mutex.h: -------------------------------------------------------------------------------- 1 | #ifndef _MUTEX_H 2 | #define _MUTEX_H 3 | 4 | struct task; // Forward declare instead of including task.h 5 | // since that causes problems 6 | 7 | typedef struct _mutex { 8 | /*task_t *owner;*/ 9 | struct task *owner; 10 | uint32 mutex; 11 | } mutex_t; 12 | 13 | mutex_t *mutex_create(void); 14 | void mutex_destroy(mutex_t *mutex); 15 | 16 | void mutex_lock(mutex_t *mutex); 17 | void mutex_unlock(mutex_t *mutex); 18 | bool mutex_is_locked(mutex_t *mutex); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/include/kernel/net/arp.h: -------------------------------------------------------------------------------- 1 | #ifndef _ARP_H 2 | #define _ARP_H 3 | 4 | #define ARP_REQUEST 1 5 | #define ARP_REPLY 2 6 | 7 | #define ARP_CACHE_TIME (5*60*1000) // 5 minutes 8 | 9 | typedef struct { 10 | uint16 htype; // 1 for Ethernet 11 | uint16 ptype; // 0x0800 for IPv4 12 | uint8 hlen; // 6 for Ethernet addresses 13 | uint8 plen; // 4 for IPv4 addresses 14 | uint16 operation; // ARP_REQUEST or ARP_REPLY 15 | uint8 src_mac[6]; // Sender MAC 16 | uint8 src_ip[4]; // Sender IP 17 | uint8 dst_mac[6]; // Target MAC; ignored for requests 18 | uint8 dst_ip[4]; // Target IP 19 | } __attribute((packed)) arpheader_t; 20 | 21 | // An entry in the ARP cache 22 | typedef struct { 23 | uint8 ip[4]; 24 | uint8 mac[6]; 25 | uint32 timestamp; 26 | } arpentry_t; 27 | 28 | void arp_init(void); // Sets up the ARP cache 29 | void send_arp_reply(const uint8 *packet); 30 | void arp_handle_packet(void *data, uint32 length); 31 | bool arp_lookup(uint8 *ip, uint8 *mac_buffer); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/include/kernel/net/ipicmp.h: -------------------------------------------------------------------------------- 1 | #ifndef _IPICMP_H 2 | #define _IPICMP_H 3 | 4 | #define IPV4_PROTO_ICMP 1 5 | #define IPV4_PROTO_TCP 6 6 | #define IPV4_PROTO_UDP 17 7 | 8 | #define ICMP_ECHO_REQUEST 8 9 | #define ICMP_ECHO_REPLY 0 10 | 11 | typedef struct { 12 | uint8 IHL : 4, version : 4; 13 | uint8 DSCP : 6, ECN : 2; 14 | uint16 total_length; 15 | uint16 id; 16 | uint16 flags : 3, fragment_offset : 13; 17 | uint8 ttl; 18 | uint8 protocol; 19 | uint16 header_checksum; 20 | uint8 src_ip[4]; 21 | uint8 dst_ip[4]; 22 | } __attribute__((packed)) ipv4header_t; 23 | 24 | // internet_checksum.s - used for things besides IP and ICMP, though 25 | uint16 internet_checksum(void *ptr, uint32 length); 26 | 27 | void send_ipv4_packet(uint8 *dst_ip, uint8 protocol, void *payload, uint16 payload_size); 28 | void handle_icmp(void *data, uint32 length); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/include/kernel/net/nethandler.h: -------------------------------------------------------------------------------- 1 | #ifndef _NETHANDLER_H 2 | #define _NETHANDLER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define NETHANDLER_NAME_SIZE 20 10 | #define NETHANDLER_NUM_BUFFERS 8 11 | #define NETHANDLER_BUFFER_SIZE 1536 /* Exactly 1500 ought to be enough */ 12 | 13 | typedef enum { 14 | EMPTY, 15 | NEEDS_PROCESSING, 16 | CURRENTLY_PROCESSING 17 | /* PROCESSED would be the same as EMPTY */ 18 | } nethandler_buffer_state; 19 | 20 | typedef struct { 21 | uint8 buffer[NETHANDLER_BUFFER_SIZE]; 22 | uint32 length; 23 | nethandler_buffer_state state; 24 | } nethandler_buffer_t; 25 | 26 | typedef struct { 27 | task_t *task; 28 | char name[NETHANDLER_NAME_SIZE]; 29 | nethandler_buffer_t *buffers[NETHANDLER_NUM_BUFFERS]; 30 | void (*function)(void *, uint32); 31 | } nethandler_t; 32 | 33 | nethandler_t *nethandler_create(const char *name, void (*func)(void *, uint32)); 34 | void nethandler_add_packet(nethandler_t *worker, void *data, uint32 length); 35 | void nethandler_task(void *data, uint32 length); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/include/kernel/net/rtl8139.h: -------------------------------------------------------------------------------- 1 | #ifndef _RTL8139_H 2 | #define _RTL8139_H 3 | 4 | #define RTL8139_RXBUFFER_SIZE 8192 /* + 16 is allocated */ 5 | 6 | // RTL8139C registers 7 | #define RTL_RBSTART 0x30 /* Receive Buffer Start Address (DWORD aligned) */ 8 | #define RTL_CR 0x37 /* command register */ 9 | #define RTL_CAPR 0x38 /* Current Address of Packet Read */ 10 | #define RTL_CBR 0x3a /* Current Buffer Address (Rx buffer) */ 11 | #define RTL_IMR 0x3c /* Interrupt Mask Register */ 12 | #define RTL_ISR 0x3e /* Interrupt Status Register */ 13 | #define RTL_TCR 0x40 /* Transmit Configuration Register */ 14 | #define RTL_RCR 0x44 /* Receive Configuration Register */ 15 | #define RTL_MPC 0x4c /* Missed Packet Counter */ 16 | #define RTL_CONFIG0 0x51 /* Configuration Register 0 */ 17 | #define RTL_CONFIG1 0x52 /* Configuration Register 1 */ 18 | #define RTL_CONFIG3 0x59 /* Configuration Register 3 */ 19 | #define RTL_CONFIG4 0x5a /* Configuration Register 4 */ 20 | #define RTL_BMCR 0x62 /* Basic Mode Control Register */ 21 | #define RTL_BMSR 0x64 /* Basic Mode Status Register */ 22 | #define RTL_CONFIG5 0xd8 /* Configuration Register 5 */ 23 | 24 | #define RTL_TSD0 0x10 /* Transmit Status of Descriptor 0 */ 25 | #define RTL_TSD1 0x14 /* Transmit Status of Descriptor 1 */ 26 | #define RTL_TSD2 0x18 /* Transmit Status of Descriptor 2 */ 27 | #define RTL_TSD3 0x1c /* Transmit Status of Descriptor 3 */ 28 | #define RTS_TSAD0 0x20 /* Transmit Start Address of Descriptor 0 (DWORD aligned) */ 29 | #define RTS_TSAD1 0x24 /* Transmit Start Address of Descriptor 1 (DWORD aligned) */ 30 | #define RTS_TSAD2 0x28 /* Transmit Start Address of Descriptor 2 (DWORD aligned) */ 31 | #define RTS_TSAD3 0x2c /* Transmit Start Address of Descriptor 3 (DWORD aligned) */ 32 | #define RTL_TSD_BASE 0x10 /* Used to calculate the register offset automatically */ 33 | #define RTL_TSAD_BASE 0x20 /* As above */ 34 | 35 | // Command register bits 36 | #define RTL_RESET (1 << 4) /* Software Reset */ 37 | #define RTL_RE (1 << 3) /* Receiver Enable */ 38 | #define RTL_TE (1 << 2) /* Transmitter Enable */ 39 | #define RTL_BUFE (1 << 0) /* Receive Buffer Empty */ 40 | 41 | // IMR register bits 42 | #define RTL_ROK (1 << 0) 43 | #define RTL_RER (1 << 1) 44 | #define RTL_TOK (1 << 2) 45 | #define RTL_TER (1 << 3) 46 | 47 | // RCR register bits 48 | #define RTL_AAP (1 << 0) /* Accept Physical Address Packets */ 49 | #define RTL_APM (1 << 1) /* Accept Physical Match Packets */ 50 | #define RTL_AM (1 << 2) /* Accept Multicast Packets */ 51 | #define RTL_AB (1 << 3) /* Accept Broadcast Packets */ 52 | 53 | // TSDx (0 - 3) register bits 54 | #define RTL_TSD_TOK (1 << 15) 55 | #define RTL_TSD_OWN (1 << 13) 56 | #define RTL_TSD_BOTH ((1 << 15) | (1 << 13)) 57 | #define RTL_TSD_NONE 0 58 | 59 | // Ethertypes we might encounter 60 | #define ETHERTYPE_IPV4 0x0800 61 | #define ETHERTYPE_ARP 0x0806 62 | #define ETHERTYPE_IPV6 0x86dd 63 | 64 | // Ethernet II header (w/o VLAN 802.11Q tag) 65 | typedef struct { 66 | uint8 mac_dst[6]; 67 | uint8 mac_src[6]; 68 | /* uint32 vlan_tag; */ 69 | uint16 ethertype; 70 | /* payload 42-1500 octets */ 71 | /* uint32 crc; */ 72 | } __attribute((packed)) ethheader_t; 73 | 74 | // One of the four transmit descriptors, used to store info about the packet 75 | // we're sending and its location 76 | typedef struct { 77 | uint8 *buffer; 78 | uint32 buffer_phys; 79 | uint16 packet_length; 80 | } txdesc_t; 81 | 82 | bool init_rtl8139(void); 83 | void rtl8139_send_frame(uint8 *dst_mac, uint16 ethertype, void *payload, uint16 payload_size); 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /src/include/kernel/ordered_array.h: -------------------------------------------------------------------------------- 1 | #ifndef _ORDERED_ARRAY_H 2 | #define _ORDERED_ARRAY_H 3 | 4 | #include 5 | 6 | /* This array is sorted on insertion and thus is always sorted. It stores anything that can be cast to a void*. */ 7 | typedef void* type_t; 8 | 9 | /* A predicate that should return nonzero if the first argument is less than the second. */ 10 | typedef sint8 (*lessthan_predicate_t)(type_t, type_t); 11 | 12 | typedef struct { 13 | type_t *array; 14 | uint32 size; 15 | uint32 max_size; 16 | lessthan_predicate_t less_than; 17 | } ordered_array_t; 18 | 19 | sint8 standard_lessthan_predicate(type_t a, type_t b); 20 | 21 | /* Functions to create an ordered array */ 22 | ordered_array_t create_ordered_array(uint32 max_size, lessthan_predicate_t less_than); 23 | ordered_array_t place_ordered_array(void *addr, uint32 max_size, lessthan_predicate_t less_than); 24 | 25 | void destroy_ordered_array(ordered_array_t *array); 26 | void insert_ordered_array(type_t item, ordered_array_t *array); 27 | 28 | /* Replace an element */ 29 | void update_ordered_array(uint32 i, type_t item, ordered_array_t *array); 30 | 31 | /* Returns the index of the element specified, or -1 if not found. If multiple exists, returns the first item. */ 32 | sint32 indexof_ordered_array(type_t item, ordered_array_t *array); 33 | 34 | /* Equivalent to array[i] */ 35 | type_t lookup_ordered_array(uint32 i, ordered_array_t *array); 36 | 37 | /* Remove an item by index */ 38 | void remove_ordered_array(uint32 i, ordered_array_t *array); 39 | 40 | /* Remove an item by the item itself */ 41 | void remove_ordered_array_item(type_t item, ordered_array_t *array); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/include/kernel/partition.h: -------------------------------------------------------------------------------- 1 | #ifndef _PARTITION_H 2 | #define _PARTITION_H 3 | 4 | #include 5 | 6 | typedef struct partition { 7 | bool exists; 8 | bool bootable; 9 | uint8 type; /* system id byte */ 10 | uint32 start_lba; 11 | uint32 total_sectors; 12 | uint8 filesystem; /* not necessarily the same as type above */ 13 | /* The /filesystem/ member is only slightly related to the /type/ member. 14 | * More specifically, /type/ is the System ID byte from the MBR, which 15 | * gives a maximum of 255 (1 through 0xff) types. All regular Linux 16 | * partitions uses 0x83, for example, no matter the filesystem. 17 | * 18 | * /filesystem/, on the other hand, is set depending on the exact 19 | * filesystem used, e.g. ext2, ext3, FAT32, ReiserFS, XFS, ... 20 | * The filesystem member should be one of the FS_* values. 21 | * As of right now only FAT32 is supported, and far from completely.o 22 | */ 23 | } partition_t; 24 | 25 | #include 26 | 27 | void parse_mbr(struct ata_device *dev); 28 | 29 | /* System ID byte values */ 30 | #define PART_EXTENDED_8GB 0x05 31 | #define PART_EXTENDED 0x0f 32 | #define PART_FAT12 0x01 33 | #define PART_FAT16 0x06 34 | #define PART_FAT16_LBA 0x0e 35 | #define PART_FAT32 0x0b 36 | #define PART_FAT32_LBA 0x0c 37 | #define PART_LINUX 0x83 38 | #define PART_LINUX_SWAP 0x82 39 | 40 | /* Filesystems we know about */ 41 | #define FS_NOT_YET_TESTED 0 /* the default value, before the FAT driver is called */ 42 | #define FS_FAT32 0x01 43 | #define FS_UNKNOWN 0xff 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/include/kernel/pci.h: -------------------------------------------------------------------------------- 1 | #ifndef _PCI_H 2 | #define _PCI_H 3 | 4 | typedef struct { 5 | uint32 address; 6 | uint8 type; /* BAR_MEM or BAR_IO */ 7 | } bar_t; 8 | 9 | typedef struct { 10 | uint16 vendor_id; 11 | uint16 device_id; 12 | bar_t bar[6]; 13 | uint8 irq; 14 | uint8 classcode; 15 | uint8 subclasscode; 16 | } pci_device_t; 17 | 18 | // Looks through the PCI database to find the details (BARs, IRQ etc.) 19 | // for a PCI device 20 | pci_device_t *find_pci_device(uint32 vendor_id, uint32 device_id); 21 | 22 | /* The IO registers used to access PCI registers */ 23 | #define PCI_CONFIG_ADDRESS 0xcf8 24 | #define PCI_CONFIG_DATA 0xcfc 25 | 26 | /* PCI configuration space offsets 27 | * comments after the value state what to AND the 32-bit register with 28 | * to get the final value 29 | */ 30 | #define PCI_CONF_DEVICE 0x00 /* 0xffff0000 */ 31 | #define PCI_CONF_VENDOR 0x00 /* 0x0000ffff */ 32 | #define PCI_CONF_STATUS 0x04 /* 0xffff0000 */ 33 | #define PCI_CONF_COMMAND 0x04 /* 0x0000ffff */ 34 | #define PCI_CONF_CLASS 0x08 /* 0xffffff00 */ 35 | #define PCI_CONF_REVISION 0x08 /* 0x000000ff */ 36 | #define PCI_CONF_BIST 0x0c /* 0xff000000 */ 37 | #define PCI_CONF_HEADER_TYPE 0x0c /* 0x00ff0000 */ 38 | #define PCI_CONF_LATENCY 0x0c /* 0x0000ff00 */ 39 | #define PCI_CONF_CACHELINE_SIZE 0x0c /* 0x000000ff */ 40 | #define PCI_CONF_BAR0 0x10 41 | #define PCI_CONF_BAR1 0x14 42 | #define PCI_CONF_BAR2 0x18 43 | #define PCI_CONF_BAR3 0x1c 44 | #define PCI_CONF_BAR4 0x20 45 | #define PCI_CONF_BAR5 0x24 46 | #define PCI_CONF_IRQ 0x3C /* 0x000000ff */ 47 | 48 | /* bit 0 has these values for the two BAR types */ 49 | #define BAR_MEM 0 50 | #define BAR_IO 1 51 | 52 | #define PCI_ENABLE (1UL << 31) 53 | 54 | void init_pci(void); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/include/kernel/pipe.h: -------------------------------------------------------------------------------- 1 | #ifndef _PIPE_H 2 | #define _PIPE_H 3 | 4 | #include 5 | #include 6 | 7 | #define PIPE_BUFFER_SIZE 65536 8 | 9 | int pipe(int fildes[2]); 10 | int sys_pipe(int fildes[2]); 11 | 12 | struct pipe { 13 | char *buffer; // PIPE_BUFFER_SIZE bytes 14 | struct open_file *reader; // may have >1 count 15 | struct open_file *writer; // may have >1 count 16 | char *read_pos; 17 | char *write_pos; 18 | char *max_pos; // buffer + PIPE_BUFFER_SIZE TODO: OBOE 19 | uint32 bytes_avail; 20 | mutex_t *lock; 21 | 22 | time_t mtime; 23 | time_t atime; 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/include/kernel/pmm.h: -------------------------------------------------------------------------------- 1 | #ifndef _PMM_H 2 | #define _PMM_H 3 | 4 | #include 5 | 6 | void pmm_init(uint32 mbd_mmap_addr, uint32 mbd_mmap_length, uint32 upper_mem); 7 | uint32 pmm_alloc(void); 8 | uint32 pmm_alloc_continuous(uint32 num_frames); 9 | void pmm_free(uint32 phys_addr); 10 | uint32 pmm_bytes_free(void); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/include/kernel/serial.h: -------------------------------------------------------------------------------- 1 | #ifndef _SERIAL_H 2 | #define _SERIAL_H 3 | 4 | #define SERIAL_PORT 0x3F8 /* COM; TODO: detect in BIOS data area prior to unmapping that page (0x0) */ 5 | 6 | // Port offsets 7 | #define SERIAL_DATA 0 8 | #define SERIAL_INT_ENABLE 1 9 | #define SERIAL_BAUD_LOW 0 /* with DLAB set */ 10 | #define SERIAL_BAUD_HIGH 1 /* with DLAB set */ 11 | #define SERIAL_DLAB 0x80 12 | #define SERIAL_INT_ID_FIFO 2 13 | #define SERIAL_LCR 3 /* Line Control Register */ 14 | #define SERIAL_MCR 4 /* Modem Control Register */ 15 | #define SERIAL_LINE_STATUS 5 16 | #define SERIAL_MODEM_STATUS 6 17 | #define SERIAL_SCRATCH 7 18 | 19 | void init_serial(void); 20 | 21 | void serial_send_byte(char c); 22 | void serial_send(const char *str); 23 | size_t prints(const char *fmt, ...); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/include/kernel/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_STDIO_H 2 | #define _KERNEL_STDIO_H 3 | 4 | #include 5 | #include 6 | 7 | /* Implements I/O for the standard streams */ 8 | 9 | int stdio_read(int fd, void *buf, size_t length); 10 | int stdio_write(int fd, const void *buf, size_t length); 11 | int stdio_close(int fd, struct open_file *file); 12 | int stdio_fstat(int fd, struct stat *st); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/include/kernel/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYSCALL_H 2 | #define _SYSCALL_H 3 | 4 | #include 5 | 6 | void init_syscalls(void); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/include/kernel/task.h: -------------------------------------------------------------------------------- 1 | #ifndef _TASK_H 2 | #define _TASK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include /* struct open_file */ 9 | #include 10 | #include 11 | #include 12 | 13 | #define TASK_NAME_LEN 64 14 | 15 | typedef struct task { 16 | int id; // Process ID. 17 | char name[TASK_NAME_LEN]; 18 | uint32 esp; 19 | uint32 ss; 20 | void *stack; // This task's kernel stack 21 | uint32 state; /* e.g. running, sleeping */ 22 | uint32 wakeup_time; /* for sleeping tasks only: at which tick this task should be woken */ 23 | uint8 privilege; /* this task's privilege level (i.e. 0 or 3) */ 24 | console_t *console; 25 | struct task_mm *mm; /* memory info, including the page directory pointer */ 26 | struct task_mm *old_mm; // used by execve, to ensure that we can return on failure 27 | struct open_file **fdtable; 28 | char *pwd; 29 | struct _reent *reent; // Used by Newlib 30 | 31 | fpu_mmx_state_t *fpu_state; 32 | bool has_used_fpu; 33 | 34 | // used by execve 35 | bool did_execve; 36 | uint32 new_entry; 37 | 38 | struct task *parent; 39 | list_t *children; 40 | 41 | struct symbol *symbols; 42 | char *symbol_string_table; 43 | size_t symbol_string_table_size; 44 | 45 | // XXX: when adding entries, remember to copy them in fork(), if necessary! 46 | 47 | int exit_code; 48 | int link_count; // used to detect symlink loops 49 | } task_t; 50 | 51 | extern volatile task_t *current_task; 52 | extern volatile task_t *console_task; 53 | extern task_t kernel_task; 54 | 55 | #define TASK_RUNNING (1 << 0) 56 | #define TASK_SLEEPING (1 << 1) 57 | #define TASK_WAKING_UP (TASK_RUNNING | TASK_SLEEPING) // was sleeping, has not yet been scheduled since then 58 | #define TASK_IOWAIT (1 << 2) 59 | #define TASK_EXITING (1 << 3) 60 | #define TASK_IDLE (1 << 4) // used for the idle_task process 61 | #define TASK_DEAD (1 << 5) // task has _exit()'ed, but has not been wait()ed on 62 | #define TASK_WAITING (1 << 6) // wait()ing for a child 63 | 64 | void user_exit(void); // called from user mode 65 | 66 | /* Size of the kernel stack for each task (except the main kernel task; that stack is set up in loader.s) */ 67 | #define KERNEL_STACK_SIZE 16384 68 | 69 | #define USER_STACK_START 0xbffff000 70 | #define USER_STACK_SIZE (64*1024) 71 | #define USER_STACK_SIZE_MAX (8*1024*1024) 72 | #define USER_STACK_GROW_SIZE (128*1024) // How much to grow the stack by on a guard page PF. Note that if cur_size + this >= max size, the stack will not grow, even through there may still be SOME room to grow. 73 | 74 | char **parse_command_line(const char *cmdline, uint32 *argc, task_t *task); 75 | void set_entry_point(task_t *task, uint32 addr); 76 | void set_next_task(task_t *task); 77 | bool does_task_exist(task_t *task); 78 | void init_tasking(uint32 kerntask_esp0); 79 | int getpid(void); 80 | int getppid(void); 81 | task_t *create_task_elf(const char *path, console_t *con, void *data, uint32 length); 82 | task_t *create_task( void (*entry_point)(void *, uint32), const char *name, console_t *con, void *data, uint32 length); 83 | uint32 scheduler_taskSwitch(uint32 esp); 84 | uint32 switch_task(task_t *new_task, uint32 esp); 85 | bool kill_pid(int pid); /* calls kill on the correct task */ 86 | void kill(task_t *task); /* sets a task to TASK_EXITING so that it never runs */ 87 | void destroy_task(task_t *task); /* actually kills the task for good */ 88 | void sleep(uint32 milliseconds); 89 | int fork(void); 90 | uint32 *set_task_stack(task_t *task, void *data, uint32 data_len, uint32 entry_point); 91 | 92 | /* Used in the ATA driver, to make tasks sleep while waiting for the disk to read data */ 93 | void scheduler_set_iowait(void); 94 | uint32 scheduler_wake_iowait(uint32 esp); 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /src/include/kernel/time.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_TIME_H 2 | #define _KERNEL_TIME_H 3 | 4 | #include 5 | #include 6 | 7 | void get_time(Time *); 8 | time_t kern_mktime(Time *); // Note that the same rules as mktime() uses apply, e.g. month is 0 to 11, year is "years since 1900" etc. 9 | time_t kern_time(void); 10 | 11 | // mktime stuff, originally from Newlib 12 | 13 | #define SECSPERMIN 60L 14 | #define MINSPERHOUR 60L 15 | #define HOURSPERDAY 24L 16 | #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) 17 | #define SECSPERDAY (SECSPERHOUR * HOURSPERDAY) 18 | #define DAYSPERWEEK 7 19 | #define MONSPERYEAR 12 20 | 21 | #define YEAR_BASE 1900 22 | #define EPOCH_YEAR 1970 23 | #define EPOCH_WDAY 4 24 | #define EPOCH_YEARS_SINCE_LEAP 2 25 | #define EPOCH_YEARS_SINCE_CENTURY 70 26 | #define EPOCH_YEARS_SINCE_LEAP_CENTURY 370 27 | 28 | #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/include/kernel/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef _TIMER_H 2 | #define _TIMER_H 3 | 4 | #include 5 | 6 | /* This is enough to not wrap for 497 days at 100 Hz. */ 7 | #define TIMER_DIVISOR ((uint16)11932) 8 | #define TIMER_HZ 100 9 | #define TIMER_MS 10 // reciprocal of 100 Hz 10 | /*const uint16 TIMER_DIVISOR = 11932;*/ 11 | /*const uint16 TIMER_HZ = 100;*/ 12 | /*const uint16 TIMER_MS = 10; // reciprocal of 100 Hz*/ 13 | 14 | uint32 uptime(void); 15 | uint32 gettickcount(void); 16 | void delay(uint32 ms); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/include/kernel/vfs.h: -------------------------------------------------------------------------------- 1 | #ifndef _FILEIO_H 2 | #define _FILEIO_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define SEEK_SET 0 9 | #define SEEK_CUR 1 10 | #define SEEK_END 2 11 | 12 | /* forward declarations */ 13 | struct fat32_partition; 14 | struct mountpoint; 15 | struct dir_ops; 16 | struct dir; 17 | struct task; 18 | 19 | typedef struct dir_ops { 20 | struct dirent *(*readdir)(struct dir *); 21 | int (*closedir)(struct dir *); 22 | } dir_ops_t; 23 | 24 | typedef struct dir { 25 | uint32 dev; // the partition associated with this DIR 26 | uint32 ino; 27 | 28 | // These four are used by FAT... 29 | uint8 *buf; 30 | int _buflen; /* buffer's malloc'ed size */ 31 | int pos; 32 | int len; /* number of valid data bytes in the buffer */ 33 | 34 | // ... while this is used by ext2, which uses getdents to implements readdir. 35 | // Some of the above are still used, as getdents can return more that one entry at a time. 36 | int fd; 37 | 38 | struct mountpoint *mp; 39 | struct dir_ops dops; 40 | } DIR; 41 | 42 | typedef struct mp_ops { 43 | int (*open)(uint32 /* dev */, const char * /* absolute path */, int /* mode */); 44 | DIR *(*opendir)(struct mountpoint *, const char * /* absolute path */); 45 | int (*stat)(struct mountpoint *, const char * /* path */, struct stat *); 46 | int (*lstat)(struct mountpoint *, const char * /* path */, struct stat *); 47 | ssize_t (*readlink)(struct mountpoint *, const char *, char *, size_t); 48 | } mp_ops_t; 49 | 50 | struct open_file; 51 | typedef struct open_file_ops { 52 | int (*read)(int /* fd */, void * /* buf */, size_t /* length */); 53 | int (*write)(int /* fd */, const void * /* buf */, size_t /* length */); 54 | int (*close)(int /* fd */, struct open_file * /* file */); 55 | off_t (*lseek)(int /* fd */, off_t /* offset */, int /* whence */); 56 | int (*fstat)(int /* fd */, struct stat *); 57 | int (*getdents)(int /* fd */, void * /* buffer */, int /* count */); 58 | } open_file_ops_t; 59 | 60 | typedef struct mountpoint { 61 | char path[1024]; 62 | 63 | uint32 dev; 64 | struct mp_ops mpops; 65 | int depth; // 0 for a path of /, 1 for /mnt, 2 for /mnt/ext2 and so on. 66 | } mountpoint_t; 67 | 68 | /* A list of the mountpoints currently used */ 69 | extern list_t *mountpoints; 70 | 71 | mountpoint_t *find_mountpoint_for_path(const char *path); 72 | 73 | #include 74 | 75 | #define MAX_OPEN_FILES 128 76 | 77 | #define O_RDONLY 0 78 | #define O_DIRECTORY 0x10000 79 | 80 | #define MAX_DEVS 8 81 | extern void *devtable[MAX_DEVS]; 82 | extern uint32 next_dev; 83 | 84 | #define DEV_PIPE 0x7fff 85 | 86 | typedef struct open_file { 87 | int count; // number of fds that link to this file 88 | dev_t dev; 89 | ino_t ino; 90 | ino_t cur_block; // current cluster number for FAT 91 | off_t offset; 92 | off_t size; 93 | int mode; 94 | mountpoint_t *mp; 95 | char *path; 96 | struct open_file_ops fops; 97 | void *data; // implementation specific data 98 | } open_file_t; 99 | 100 | struct open_file *get_filp(int fd); 101 | struct open_file *new_filp(int *fd); 102 | void destroy_filp(int fd); 103 | 104 | struct open_file *do_get_filp(int fd, struct task *task); 105 | int do_close(int fd, struct task *task); 106 | 107 | // Resolves all symlinks in a given path. 108 | int resolve_actual_path(char *out_path, size_t bufsize); 109 | 110 | int open(const char *path, int mode); 111 | int read(int fd, void *buf, int length); 112 | int write(int fd, const void *buf, int length); 113 | int close(int fd); 114 | DIR *opendir(const char *path); 115 | struct dirent *readdir(DIR *dir); 116 | int closedir(DIR *dir); 117 | //int stat(const char *in_path, struct stat *buf); 118 | //int fstat(int fd, struct stat *buf); 119 | int chdir(const char *path); 120 | off_t lseek(int fd, off_t offset, int whence); 121 | int getdents (int fd, void *dp, int count); 122 | //int lstat(const char *path, struct stat *buf); 123 | ssize_t readlink(const char *pathname, char *buf, size_t bufsiz); 124 | 125 | int dup(int); 126 | int dup2(int, int); 127 | 128 | bool find_relpath(const char *in_path, char *relpath, mountpoint_t **mp_out); 129 | 130 | #endif 131 | -------------------------------------------------------------------------------- /src/include/path.h: -------------------------------------------------------------------------------- 1 | #ifndef _PATH_H 2 | #define _PATH_H 3 | 4 | #define PATH_MAX 1023 /* buffers are 1024, so 1023 chars max */ 5 | 6 | bool path_join(char *path, const char *right); 7 | bool path_collapse_dots(char *path); 8 | void path_dirname(char *path); 9 | void path_basename(char *path); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/include/stdarg.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 1989, 1997, 1998, 1999, 2000, 2009 Free Software Foundation, Inc. 2 | 3 | This file is part of GCC. 4 | 5 | GCC is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 3, or (at your option) 8 | any later version. 9 | 10 | GCC is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | Under Section 7 of GPL version 3, you are granted additional 16 | permissions described in the GCC Runtime Library Exception, version 17 | 3.1, as published by the Free Software Foundation. 18 | 19 | You should have received a copy of the GNU General Public License and 20 | a copy of the GCC Runtime Library Exception along with this program; 21 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 22 | . */ 23 | 24 | /* 25 | * ISO C Standard: 7.15 Variable arguments 26 | */ 27 | 28 | #ifndef _STDARG_H 29 | #ifndef _ANSI_STDARG_H_ 30 | #ifndef __need___va_list 31 | #define _STDARG_H 32 | #define _ANSI_STDARG_H_ 33 | #endif /* not __need___va_list */ 34 | #undef __need___va_list 35 | 36 | /* Define __gnuc_va_list. */ 37 | 38 | #ifndef __GNUC_VA_LIST 39 | #define __GNUC_VA_LIST 40 | typedef __builtin_va_list __gnuc_va_list; 41 | #endif 42 | 43 | /* Define the standard macros for the user, 44 | if this invocation was from the user program. */ 45 | #ifdef _STDARG_H 46 | 47 | #define va_start(v,l) __builtin_va_start(v,l) 48 | #define va_end(v) __builtin_va_end(v) 49 | #define va_arg(v,l) __builtin_va_arg(v,l) 50 | #if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L || defined(__GXX_EXPERIMENTAL_CXX0X__) 51 | #define va_copy(d,s) __builtin_va_copy(d,s) 52 | #endif 53 | #define __va_copy(d,s) __builtin_va_copy(d,s) 54 | 55 | /* Define va_list, if desired, from __gnuc_va_list. */ 56 | /* We deliberately do not define va_list when called from 57 | stdio.h, because ANSI C says that stdio.h is not supposed to define 58 | va_list. stdio.h needs to have access to that data type, 59 | but must not use that name. It should use the name __gnuc_va_list, 60 | which is safe because it is reserved for the implementation. */ 61 | 62 | #ifdef _HIDDEN_VA_LIST /* On OSF1, this means varargs.h is "half-loaded". */ 63 | #undef _VA_LIST 64 | #endif 65 | 66 | #ifdef _BSD_VA_LIST 67 | #undef _BSD_VA_LIST 68 | #endif 69 | 70 | #if defined(__svr4__) || (defined(_SCO_DS) && !defined(__VA_LIST)) 71 | /* SVR4.2 uses _VA_LIST for an internal alias for va_list, 72 | so we must avoid testing it and setting it here. 73 | SVR4 uses _VA_LIST as a flag in stdarg.h, but we should 74 | have no conflict with that. */ 75 | #ifndef _VA_LIST_ 76 | #define _VA_LIST_ 77 | #ifdef __i860__ 78 | #ifndef _VA_LIST 79 | #define _VA_LIST va_list 80 | #endif 81 | #endif /* __i860__ */ 82 | typedef __gnuc_va_list va_list; 83 | #ifdef _SCO_DS 84 | #define __VA_LIST 85 | #endif 86 | #endif /* _VA_LIST_ */ 87 | #else /* not __svr4__ || _SCO_DS */ 88 | 89 | /* The macro _VA_LIST_ is the same thing used by this file in Ultrix. 90 | But on BSD NET2 we must not test or define or undef it. 91 | (Note that the comments in NET 2's ansi.h 92 | are incorrect for _VA_LIST_--see stdio.h!) */ 93 | #if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__) || defined(WINNT) 94 | /* The macro _VA_LIST_DEFINED is used in Windows NT 3.5 */ 95 | #ifndef _VA_LIST_DEFINED 96 | /* The macro _VA_LIST is used in SCO Unix 3.2. */ 97 | #ifndef _VA_LIST 98 | /* The macro _VA_LIST_T_H is used in the Bull dpx2 */ 99 | #ifndef _VA_LIST_T_H 100 | /* The macro __va_list__ is used by BeOS. */ 101 | #ifndef __va_list__ 102 | typedef __gnuc_va_list va_list; 103 | #endif /* not __va_list__ */ 104 | #endif /* not _VA_LIST_T_H */ 105 | #endif /* not _VA_LIST */ 106 | #endif /* not _VA_LIST_DEFINED */ 107 | #if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__)) 108 | #define _VA_LIST_ 109 | #endif 110 | #ifndef _VA_LIST 111 | #define _VA_LIST 112 | #endif 113 | #ifndef _VA_LIST_DEFINED 114 | #define _VA_LIST_DEFINED 115 | #endif 116 | #ifndef _VA_LIST_T_H 117 | #define _VA_LIST_T_H 118 | #endif 119 | #ifndef __va_list__ 120 | #define __va_list__ 121 | #endif 122 | 123 | #endif /* not _VA_LIST_, except on certain systems */ 124 | 125 | #endif /* not __svr4__ */ 126 | 127 | #endif /* _STDARG_H */ 128 | 129 | #endif /* not _ANSI_STDARG_H_ */ 130 | #endif /* not _STDARG_H */ 131 | -------------------------------------------------------------------------------- /src/include/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDIO_H 2 | #define _STDIO_H 3 | 4 | #include 5 | 6 | int sprintf(char *buf, const char *fmt, ...); 7 | int vsprintf(char *buf, const char *fmt, __gnuc_va_list args); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/include/stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDLIB_H 2 | #define _STDLIB_H 3 | 4 | #include 5 | 6 | void itoa(signed long, char *); 7 | void reverse(char *s); 8 | 9 | int rand(void); 10 | void srand(uint32 seed); 11 | #define RAND_RANGE(x,y) ( rand() % (y - x + 1) + x ) 12 | int isdigit(int c); 13 | int ipow(int base, int exp); /* used for atoi */ 14 | int atoi(const char *str); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRING_H 2 | #define _STRING_H 3 | 4 | #include 5 | 6 | void *memset(void *addr, int c, size_t n); 7 | void *memsetw(void *dst, uint16 val, size_t count); 8 | size_t strlen(const char *str); 9 | void *memcpy(void *restrict s1, const void *restrict s2, size_t n); 10 | 11 | char *strcpy(char *restrict s1, const char *restrict s2); 12 | int strcmp(const char *s1, const char *s2); 13 | int strncmp(const char *s1, const char *s2, size_t n); 14 | 15 | int memcmp(const void *lhs, const void *rhs, size_t count); 16 | 17 | char *strchr(const char *s, int c); 18 | char *strrchr(const char *s, int c); 19 | 20 | size_t strlcpy(char *dst, const char *src, size_t size); 21 | size_t strlcat(char *dst, const char *src, size_t size); 22 | char *strstr(const char *haystack, const char *needle); 23 | 24 | int stricmp(const char *s1, const char *s2); 25 | int strnicmp(const char *s1, const char *s2, size_t n); 26 | 27 | char *strdup(const char *s); 28 | 29 | /* These three are public domain implementations, i.e. not written by me */ 30 | size_t strcspn(const char *s1, const char *s2); 31 | size_t strspn(const char *s1, const char *s2); 32 | char *strtok_r(char *s, const char *delimiters, char **lasts); 33 | 34 | /* This doesn't really belong in string.h. */ 35 | int isspace(int c); 36 | 37 | /* Remove leading and trailing whitespace. Modifies the original string. The returned pointer 38 | * may be different from the one passed in - if there was leading whitespace. */ 39 | /* This is NOT a standard function! */ 40 | char *trim(char *str); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/include/userspace/exscapeos.h: -------------------------------------------------------------------------------- 1 | #if _EXSCAPEOS_USERSPACE 2 | 3 | #include "types.h" 4 | 5 | struct stat; 6 | 7 | #define DECL_SYSCALL0(fn, ret) ret fn(void); 8 | #define DECL_SYSCALL1(fn, ret, p1) ret fn(p1); 9 | #define DECL_SYSCALL2(fn, ret, p1,p2) ret fn(p1,p2); 10 | #define DECL_SYSCALL3(fn, ret, p1,p2,p3) ret fn(p1,p2,p3); 11 | #define DECL_SYSCALL4(fn, ret, p1,p2,p3,p4) ret fn(p1,p2,p3,p4); 12 | #define DECL_SYSCALL5(fn, ret, p1,p2,p3,p4,p5) ret fn(p1,p2,p3,p4,p5); 13 | 14 | #define DEFN_SYSCALL0(fn, ret, num) \ 15 | ret fn(void) \ 16 | { \ 17 | ret a; \ 18 | asm volatile("int $0x80" : "=a" (a) : "0" (num)); \ 19 | return a; \ 20 | } 21 | 22 | #define DEFN_SYSCALL1(fn, ret, num, P1) \ 23 | ret fn(P1 p1) \ 24 | { \ 25 | ret a; \ 26 | asm volatile("int $0x80" : "=a" (a) : "0" (num), "b" ((ret)p1)); \ 27 | return a; \ 28 | } 29 | 30 | #define DEFN_SYSCALL2(fn, ret, num, P1, P2) \ 31 | ret fn(P1 p1, P2 p2) \ 32 | { \ 33 | ret a; \ 34 | asm volatile("int $0x80" : "=a" (a) : "0" (num), "b" ((ret)p1), "c" ((ret)p2)); \ 35 | return a; \ 36 | } 37 | 38 | #define DEFN_SYSCALL3(fn, ret, num, P1, P2, P3) \ 39 | ret fn(P1 p1, P2 p2, P3 p3) \ 40 | { \ 41 | ret a; \ 42 | asm volatile("int $0x80" : "=a" (a) : "0" (num), "b" ((ret)p1), "c" ((ret)p2), "d"((ret)p3)); \ 43 | return a; \ 44 | } 45 | 46 | #define DEFN_SYSCALL4(fn, ret, num, P1, P2, P3, P4) \ 47 | ret fn(P1 p1, P2 p2, P3 p3, P4 p4) \ 48 | { \ 49 | ret a; \ 50 | asm volatile("int $0x80" : "=a" (a) : "0" (num), "b" ((ret)p1), "c" ((ret)p2), "d" ((ret)p3), "S" ((ret)p4)); \ 51 | return a; \ 52 | } 53 | 54 | #define DEFN_SYSCALL5(fn, ret, num) \ 55 | ret fn(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) \ 56 | { \ 57 | ret a; \ 58 | asm volatile("int $0x80" : "=a" (a) : "0" (num), "b" ((ret)p1), "c" ((ret)p2), "d" ((ret)p3), "S" ((ret)p4), "D" ((ret)p5)); \ 59 | return a; \ 60 | } 61 | 62 | DECL_SYSCALL0(_exit, int); 63 | DECL_SYSCALL1(puts, int, const char *); 64 | DECL_SYSCALL1(sleep, int, uint32); 65 | DECL_SYSCALL0(getchar, int); 66 | DECL_SYSCALL1(putchar, int, int); 67 | DECL_SYSCALL2(open, int, const char *, int); 68 | DECL_SYSCALL3(read, int, int, void *, int); 69 | DECL_SYSCALL1(close, int, int); 70 | DECL_SYSCALL1(malloc, void *, size_t); 71 | DECL_SYSCALL1(free, int, void *); 72 | DECL_SYSCALL2(stat, int, const char *, struct stat *); 73 | DECL_SYSCALL1(chdir, int, const char *); 74 | DECL_SYSCALL3(write, int, int, const void *, int); 75 | typedef sint64 off_t; 76 | DECL_SYSCALL3(lseek, off_t, int, off_t, int); 77 | DECL_SYSCALL2(fstat, int, int, struct stat *); 78 | DECL_SYSCALL0(getpid, int); 79 | DECL_SYSCALL1(sbrk, void *, sint32); 80 | 81 | // TODO: move these defines 82 | #define SEEK_SET 0 83 | #define SEEK_CUR 1 84 | #define SEEK_END 2 85 | 86 | #endif // _EXSCAPEOS_USERSPACE, the below is done in user AND kernel space 87 | 88 | DEFN_SYSCALL0(_exit, int, 0); 89 | DEFN_SYSCALL1(puts, int, 1, const char *); 90 | DEFN_SYSCALL1(sleep, int, 2,uint32); 91 | DEFN_SYSCALL0(getchar, int, 3); 92 | DEFN_SYSCALL1(putchar, int, 4, int); 93 | DEFN_SYSCALL2(open, int, 5, const char *, int); 94 | DEFN_SYSCALL3(read, int, 6, int, void *, int); 95 | DEFN_SYSCALL1(close, int, 7, int); 96 | DEFN_SYSCALL1(malloc, void *, 8, size_t); 97 | DEFN_SYSCALL1(free, int, 9, void *); 98 | DEFN_SYSCALL2(stat, int, 10, const char *, struct stat *); 99 | DEFN_SYSCALL1(chdir, int, 11, const char *); 100 | DEFN_SYSCALL3(write, int, 12, int, const void *, int); 101 | /* lseek is syscall 13! */ 102 | DEFN_SYSCALL2(fstat, int, 14, int, struct stat *); 103 | DEFN_SYSCALL0(getpid, int, 15); 104 | DEFN_SYSCALL1(sbrk, void *, 16, sint32); 105 | 106 | #if _EXSCAPEOS_USERSPACE 107 | 108 | // We can't use DEFN_SYSCALL3 because of the 64-bit parameter and return 109 | off_t lseek(int fd, off_t offset, int whence) { 110 | union { 111 | off_t o64; 112 | uint32 u32[2]; 113 | } arg, ret; 114 | arg.o64 = offset; 115 | asm volatile("int $0x80" : "=a" (ret.u32[0]), "=d" (ret.u32[1]) : "0" (13), "b" (fd), "c" (arg.u32[0]), "d"(arg.u32[1]), "S"(whence)); 116 | return ret.o64; 117 | } 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /src/kernel/backtrace.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | extern struct symbol *kernel_syms; 7 | 8 | // Translate an EIP value (e.g. 0x104e3c) to a function name 9 | struct symbol *addr_to_func(uint32 addr) { 10 | if (!( 11 | (addr >= 0x100000 && addr <= 0x200000) || // possibly valid kernel EIP 12 | (addr >= 0x10000000 && addr <= 0x20000000) // possibly valid userspace EIP 13 | )) 14 | return NULL; 15 | 16 | struct symbol tmp = { .eip = 0xffffffff, .name = NULL }; 17 | struct symbol *best_match = &tmp; 18 | uint32 min_diff = 0xffffffff; 19 | 20 | struct symbol *all_syms[] = { kernel_syms, current_task->symbols, NULL }; 21 | 22 | // So this is a bit messy, but here's the idea behind each symbol pointer, whether * or ** 23 | // kernel_syms: pointer to an array of struct symbol entries 24 | // current_task->symbols: as above, for the current userspace task 25 | // all_syms: contains pointers to both of the above, to make looping easier. might be extended in the future. 26 | // symp (defined below): the current symbol we're testing 27 | // Note that we loop until eip == 0; the array is "null terminated", so to speak, with 28 | // a null strect entry (eip == 0, name == NULL). 29 | for (int symlist = 0; all_syms[symlist] != NULL; symlist++) { 30 | struct symbol *symp = all_syms[symlist]; 31 | while (symp->eip && symp->name) { 32 | // Compare all symbols to the address, and see if there's a better match. 33 | // "Better match" is defined as the symbol starting BEFORE the address, such 34 | // that the address may be INSIDE the symbol function, *and* closer to it than 35 | // previously. We don't know the function length, so this will have to do. 36 | // So far, it's worked 100%. 37 | if (symp->eip <= addr && (addr - symp->eip) < min_diff) { 38 | best_match = symp; 39 | min_diff = addr - symp->eip; 40 | } 41 | symp++; 42 | } 43 | } 44 | 45 | // We didn't find anything if the best match hasn't been updated properly. 46 | // Either that, or we DID find something, but it has no name. 47 | //printk("best_match = 0x%p, name ADDRESS = 0x%p\n", best_match, &best_match->name); 48 | if (best_match->eip == 0xffffffff || best_match->name == NULL || *(best_match->name) == 0) 49 | return NULL; 50 | 51 | // This "best" match is so bad that it's certain to be incorrect 52 | if (addr - best_match->eip > 0x200000) 53 | return NULL; 54 | 55 | return best_match; 56 | } 57 | 58 | // Find a backtrace from the passed EBP value, and store it in bt. 59 | // Depths higher than BACKTRACE_MAX are cut off. 60 | // If eip[i] == 0, that signals the end of the backtrace. 61 | void get_backtrace(uint32 _ebp, struct backtrace *bt) { 62 | memset(bt, 0, sizeof(struct backtrace)); 63 | uint32 *ebp = (uint32 *)_ebp; 64 | int i = 0; 65 | while (ebp != NULL) { 66 | if (i >= BACKTRACE_MAX) 67 | break; 68 | if (ebp > (uint32 *)0xcfff0000 || ebp < (uint32 *)0x100000) { 69 | break; 70 | } 71 | 72 | bt->eip[i] = *(ebp + 1); 73 | ebp = (uint32 *)*ebp; 74 | i++; 75 | } 76 | } 77 | 78 | // Print a backtrace as obtained by the function above 79 | void print_backtrace_struct(struct backtrace *bt) { 80 | assert(bt != NULL); 81 | for (int i = 0; i < BACKTRACE_MAX; i++) { 82 | if (bt->eip[i] == 0) 83 | break; 84 | 85 | struct symbol *sym = addr_to_func(bt->eip[i]); 86 | if (bt->eip[i] == 0xffffffff || sym == NULL) 87 | printk("0x%08x in ???%s\n", bt->eip[i], IS_USER_SPACE(bt->eip[i]) ? " (userspace)" : ""); 88 | else if (sym != NULL) { 89 | printk("0x%08x in %s+0x%x%s\n", bt->eip[i], sym->name, bt->eip[i] - sym->eip, IS_USER_SPACE(bt->eip[i]) ? " (userspace)" : ""); 90 | } 91 | } 92 | } 93 | 94 | // Combine the two above functions to make printing really simple 95 | void print_backtrace_ebp(uint32 _ebp) { 96 | struct backtrace bt; 97 | get_backtrace(_ebp, &bt); 98 | print_backtrace_struct(&bt); 99 | } 100 | 101 | // ... and combine the THREE functions above to make printing "right here, right now" even simpler yet. 102 | void print_backtrace(void) { 103 | uint32 ebp; 104 | asm volatile("mov %%ebp, %[ebp]" : [ebp]"=m"(ebp) : : "memory", "cc"); 105 | print_backtrace_ebp(ebp); 106 | } 107 | -------------------------------------------------------------------------------- /src/kernel/copy_page.s: -------------------------------------------------------------------------------- 1 | section .text 2 | align 4 3 | global copy_page_physical:function 4 | 5 | copy_page_physical: 6 | pushf ; push EFLAGS 7 | cli 8 | push esi ; we can only trample eax, ecx and edx 9 | push edi 10 | 11 | ; NOTE: if the number of pushes above changes, these offsets change as well! 12 | mov esi, [esp+16] ; source address 13 | mov edi, [esp+20] ; dest address 14 | 15 | ; Disable paging 16 | mov edx, cr0 17 | and edx, 0x7fffffff 18 | mov cr0, edx 19 | 20 | ; Copy the data 21 | mov ecx, 1024 ; 1024*4 bytes to copy 22 | rep movsd 23 | 24 | ; Re-enable paging 25 | mov edx, cr0 26 | or edx, 0x80000000 27 | mov cr0, edx 28 | 29 | pop edi 30 | pop esi 31 | popf ; return EFLAGS, which will also re-enable interrupts 32 | ret 33 | -------------------------------------------------------------------------------- /src/kernel/descriptor_tables.s: -------------------------------------------------------------------------------- 1 | global gdt_flush:function 2 | global idt_load:function 3 | global tss_flush:function 4 | extern gdt ; pointer to the GDT null descriptor, where the GDT pointer is 5 | extern idtp ; the IDT pointer, defined in kernel/idt.c 6 | 7 | section .text 8 | align 4 9 | 10 | gdt_flush: 11 | lgdt [gdt] ; load the GDT 12 | mov ax, 0x10 ; 0x10 is the offset to the data segment in the GDT, i.e gdt[2] in C 13 | mov ds, ax 14 | mov es, ax 15 | mov fs, ax 16 | mov gs, ax 17 | mov ss, ax 18 | jmp 0x08:flush2 ; 0x08 is the offset to the code segment (gdt[1]), so this is a far jump there 19 | 20 | flush2: 21 | ret ; jump back to the C kernel 22 | 23 | ; ---------- 24 | 25 | idt_load: 26 | lidt [idtp] 27 | ret ; Yup, that's it! 28 | 29 | tss_flush: 30 | mov ax, 0x2b ; load the index of our TSS structure - 0x28 | 3 (for user mode) 31 | ltr ax 32 | ret 33 | -------------------------------------------------------------------------------- /src/kernel/fpu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // x87_MMX_SSE_SSE2_SSE3_StateOwner from the Intel docs 7 | task_t *last_fpu_task = NULL; 8 | 9 | static uint32 no_fpu_interrupt_handler(uint32 esp); 10 | 11 | void fpu_init(void) { 12 | register_interrupt_handler(EXCEPTION_NO_COPROCESSOR, no_fpu_interrupt_handler); 13 | asm volatile("fninit"); 14 | 15 | // Enable FPU native exceptions (NE) and set the Task Switched (TS) bits. 16 | // TS is used to only save FPU state after it has been used in a given process. 17 | asm volatile("mov %%cr0, %%eax;" 18 | "or $0x00000010, %%eax;" /* NE = 1 */ 19 | "or $0x00000008, %%eax;" /* TS = 1 */ 20 | "mov %%eax, %%cr0;" 21 | : /* no outputs */ 22 | : /* no inputs */ 23 | : "%eax", "cc"); 24 | 25 | // Set the CR4 OSFXSR flag, which enables FXSAVE/FXRSTOR to save SSE* state. 26 | asm volatile("mov %%cr4, %%eax;" 27 | "or $0x00000200, %%eax;" /* OSFXSR = 1 */ 28 | "mov %%eax, %%cr4;" 29 | : /* no outputs */ 30 | : /* no inputs */ 31 | : "%eax", "cc"); 32 | } 33 | 34 | static uint32 no_fpu_interrupt_handler(uint32 esp) { 35 | // First of all, we must clear TS, or we we'll get stuck in a loop: 36 | // FPU instuction -> #NM -> this code -> FPU instruction -> ... 37 | asm volatile("clts"); 38 | 39 | // Next, save the state for the previous FPU task, if any 40 | if (last_fpu_task != NULL) { 41 | assert(last_fpu_task->fpu_state != NULL); 42 | asm volatile("fxsave %0" : "=m"(*last_fpu_task->fpu_state) : : "memory"); 43 | } 44 | 45 | if (!current_task->has_used_fpu) { 46 | // Initialize the FPU registers and set the state to something sane. 47 | asm volatile("fninit"); 48 | asm volatile("fxsave %0" 49 | :"=m"(*current_task->fpu_state) : : "memory"); 50 | 51 | current_task->has_used_fpu = true; 52 | } 53 | else { 54 | // Restore the state for the current task, as it's currently trying to use it 55 | asm volatile("fxrstor %0" : : "m"(*current_task->fpu_state)); 56 | } 57 | 58 | last_fpu_task = (task_t *)current_task; 59 | 60 | return esp; 61 | } 62 | -------------------------------------------------------------------------------- /src/kernel/gdt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include /* memset */ 4 | #include /* assert */ 5 | #include 6 | #include 7 | 8 | /* Create three kernel-global instances of GDT entries, and a pointer */ 9 | #define NUM_GDT_ENTRIES 7 10 | struct gdt_entry gdt[NUM_GDT_ENTRIES]; 11 | struct gdt_ptr *gp = (struct gdt_ptr *)&gdt[0]; /* store the GDT pointer in the null descriptor */ 12 | 13 | /* assembly helper function */ 14 | extern void tss_flush(void); 15 | 16 | /* only used in this file */ 17 | static void write_tss(sint32, uint16, uint32); 18 | 19 | tss_entry_t tss_entry; 20 | tss_entry_t tss_double_fault; 21 | 22 | /* Set up a GDT descriptor */ 23 | void gdt_set_gate(sint32 num, uint32 base, uint32 limit, uint8 access, uint8 gran) { 24 | assert(num <= NUM_GDT_ENTRIES - 1); 25 | 26 | /* Set up the descriptor base address */ 27 | gdt[num].base_low = (base & 0xFFFF); 28 | gdt[num].base_middle = (base >> 16) & 0xff; 29 | gdt[num].base_high = (base >> 24) & 0xff; 30 | 31 | /* Set up the descriptor limits */ 32 | gdt[num].limit_low = (limit & 0xffff); 33 | gdt[num].granularity = ((limit >> 16) & 0x0f); 34 | 35 | /* Set up the granularity and access flags */ 36 | gdt[num].granularity |= (gran & 0xf0); 37 | gdt[num].access = access; 38 | } 39 | 40 | #include 41 | void double_fault_handler(void) { 42 | printk("EAX =%08x EBX=%08x ECX=%08x EDX=%08x\n", tss_entry.eax, tss_entry.ebx, tss_entry.ecx, tss_entry.edx); 43 | printk("ESI =%08x EDI=%08x ESP=%08x EBP=%08x\n", tss_entry.esi, tss_entry.edi, tss_entry.esp, tss_entry.ebp); 44 | printk("CS =%08x DS =%08x EIP=%08x EFLAGS=%08x\n", tss_entry.cs, tss_entry.ds, tss_entry.eip, tss_entry.eflags); 45 | printk("ESP0=%08x\n", tss_entry.esp0); 46 | 47 | panic("Double fault! Kernel stack overflow?"); 48 | } 49 | 50 | uint8 *stack = NULL; 51 | 52 | /* 53 | * This is the "main" GDT setup function, i.e. the one kmain() should call. 54 | * It sets up the GDT pointer, the first three entries, and then calls 55 | * gdt_flush() to load the new GDT and update the segment registers. 56 | */ 57 | void gdt_install(void) { 58 | 59 | /* Create the NULL descriptor. 60 | Most of this will be overwritten by the GDT pointer, though. */ 61 | gdt_set_gate(0, 0, 0, 0, 0); 62 | 63 | /* Set up the GDT pointer - which is now stored in the NULL descriptor */ 64 | gp->limit = (sizeof(struct gdt_entry) * NUM_GDT_ENTRIES) - 1; 65 | gp->base = (uint32)&gdt; 66 | 67 | /* 68 | * Create the code segment descriptor. 69 | * The base address is 0, limit is 4 GiB, 4 kiB granularity, 70 | * uses 32-bit opcodes and is a CS descriptor. 71 | */ 72 | gdt_set_gate(1, 0, 0xffffffff, 0x9a, 0xcf); 73 | 74 | /* 75 | * Create the data segment descriptor. 76 | * The descriptor type is the only difference from 77 | * the code segment descriptor above! 78 | */ 79 | gdt_set_gate(2, 0, 0xffffffff, 0x92, 0xcf); 80 | 81 | /* Set up equivalent descriptors (first code, then data) for user mode */ 82 | gdt_set_gate(3, 0, 0xffffffff, 0xfa, 0xcf); 83 | gdt_set_gate(4, 0, 0xffffffff, 0xf2, 0xcf); 84 | 85 | /* Set up our one TSS */ 86 | write_tss(5, 0x10, 0); 87 | 88 | // Clear out the space we'll set up soon (AFTER paging), for 89 | // the double fault handler. 90 | memset(&gdt[6], 0, 8); 91 | 92 | /* Install the new GDT! */ 93 | gdt_flush(); 94 | tss_flush(); 95 | } 96 | 97 | void init_double_fault_handler(page_directory_t *pagedir) { 98 | /* Set up a double fault handler */ 99 | gdt_set_gate(6, (uint32)&tss_double_fault, sizeof(tss_entry_t), 0xe9, 0xcf); 100 | memset(&tss_double_fault, 0, sizeof(tss_entry_t)); 101 | 102 | tss_double_fault.eip = (uint32)double_fault_handler; 103 | tss_double_fault.cr3 = (uint32)(pagedir->physical_address); 104 | tss_double_fault.cs = 0x08; 105 | tss_double_fault.ds = 0x10; 106 | tss_double_fault.es = 0x10; 107 | tss_double_fault.fs = 0x10; 108 | tss_double_fault.gs = 0x10; 109 | tss_double_fault.ss = 0x10; 110 | tss_double_fault.ss0 = 0x10; 111 | 112 | stack = kmalloc_a(PAGE_SIZE); 113 | tss_double_fault.esp = (uint32)stack + PAGE_SIZE; 114 | tss_double_fault.esp0 = (uint32)stack + PAGE_SIZE; 115 | tss_double_fault.eflags = 0x2; 116 | 117 | tss_double_fault.iomap_base = sizeof(tss_entry_t); 118 | } 119 | 120 | static void write_tss(sint32 num, uint16 ss0, uint32 esp0) { 121 | /* Calculate what we need for the GDT entry */ 122 | uint32 base = (uint32)&tss_entry; 123 | uint32 limit = sizeof(tss_entry_t); 124 | 125 | gdt_set_gate(num, base, limit, 0xe9, 0x00); 126 | 127 | memset(&tss_entry, 0, sizeof(tss_entry_t)); 128 | 129 | tss_entry.ss0 = ss0; 130 | tss_entry.esp0 = esp0; 131 | tss_entry.iomap_base = sizeof(tss_entry_t); 132 | 133 | // Here we set the cs, ss, ds, es, fs and gs entries in the TSS. These specify what 134 | // segments should be loaded when the processor switches to kernel mode. Therefore 135 | // they are just our normal kernel code/data segments - 0x08 and 0x10 respectively, 136 | // but with the last two bits set, making 0x0b and 0x13. The setting of these bits 137 | // sets the RPL (requested privilege level) to 3, meaning that this TSS can be used 138 | // to switch to kernel mode from ring 3. 139 | tss_entry.cs = 0x0b; 140 | tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = 0x13; 141 | } 142 | 143 | void tss_switch(uint32 esp0, uint32 esp, uint32 ss) { 144 | tss_entry.esp0 = esp0; 145 | tss_entry.esp = esp; 146 | tss_entry.ss = ss; 147 | } 148 | -------------------------------------------------------------------------------- /src/kernel/isr.s: -------------------------------------------------------------------------------- 1 | extern isr_handler ; defined in kernel/interrupts.c 2 | extern irq_handler ; defined in kernel/interrupts.c 3 | extern in_isr ; kernel/interrupts.c (bool) 4 | 5 | section .text 6 | align 4 7 | 8 | ; ----------- 9 | ; ISR routines 10 | 11 | %macro ISR_NOERRCODE 1 12 | global isr%1:function 13 | isr%1: 14 | cli 15 | push 0 16 | push %1 17 | jmp isr_common_stub 18 | %endmacro 19 | 20 | %macro ISR_ERRCODE 1 21 | global isr%1:function 22 | isr%1: 23 | cli 24 | push %1 25 | jmp isr_common_stub 26 | %endmacro 27 | 28 | ISR_NOERRCODE 0 29 | ISR_NOERRCODE 1 30 | ISR_NOERRCODE 2 31 | ISR_NOERRCODE 3 32 | ISR_NOERRCODE 4 33 | ISR_NOERRCODE 5 34 | ISR_NOERRCODE 6 35 | ISR_NOERRCODE 7 36 | ISR_ERRCODE 8 37 | ISR_NOERRCODE 9 38 | ISR_ERRCODE 10 39 | ISR_ERRCODE 11 40 | ISR_ERRCODE 12 41 | ISR_ERRCODE 13 42 | ISR_ERRCODE 14 43 | ISR_NOERRCODE 15 44 | ISR_NOERRCODE 16 45 | ISR_ERRCODE 17 ; Is this correct? The Intel manual states that a 0 error code is pushed. 46 | ISR_NOERRCODE 18 47 | ISR_NOERRCODE 19 48 | ISR_NOERRCODE 20 49 | ISR_NOERRCODE 21 50 | ISR_NOERRCODE 22 51 | ISR_NOERRCODE 23 52 | ISR_NOERRCODE 24 53 | ISR_NOERRCODE 25 54 | ISR_NOERRCODE 26 55 | ISR_NOERRCODE 27 56 | ISR_NOERRCODE 28 57 | ISR_NOERRCODE 29 58 | ISR_NOERRCODE 30 59 | ISR_NOERRCODE 31 60 | 61 | ; the syscall handler 62 | ISR_NOERRCODE 128 63 | 64 | ; Our ISR stub. It saves the processor state, sets up for kernel mode segments, 65 | ; calls the C-level fault handler, and restores the stack frame. 66 | global isr_common_stub:function 67 | isr_common_stub: 68 | mov byte [in_isr], 1 69 | push eax 70 | push ecx 71 | push edx 72 | push ebx 73 | push ebp 74 | push esi 75 | push edi 76 | 77 | push ds 78 | push es 79 | push fs 80 | push gs 81 | 82 | mov ax, 0x10 83 | mov ds, ax 84 | mov es, ax 85 | mov fs, ax 86 | mov gs, ax 87 | 88 | push esp 89 | call isr_handler 90 | mov esp, eax 91 | 92 | pop gs 93 | pop fs 94 | pop es 95 | pop ds 96 | 97 | pop edi 98 | pop esi 99 | pop ebp 100 | pop ebx 101 | pop edx 102 | pop ecx 103 | pop eax 104 | 105 | add esp, 8 106 | mov byte [in_isr], 0 107 | sti 108 | iret 109 | 110 | 111 | ; --------- 112 | ; IRQ handling 113 | 114 | ; Create a stub handler, since each IRQ needs its own function 115 | %macro IRQ 2 ; 2 arguments, IRQ number and the ISR number we map it to 116 | global irq%1:function 117 | irq%1: 118 | cli 119 | push byte 0 ; IRQ handlers (like ISR handlers) use the registers_t struct, so we need this dummy "error code" 120 | push byte %2 121 | jmp irq_common_stub 122 | %endmacro 123 | 124 | ; Create the IRQ handlers and map them to better ISR numbers 125 | IRQ 0, 32 126 | IRQ 1, 33 127 | IRQ 2, 34 128 | IRQ 3, 35 129 | IRQ 4, 36 130 | IRQ 5, 37 131 | IRQ 6, 38 132 | IRQ 7, 39 133 | IRQ 8, 40 134 | IRQ 9, 41 135 | IRQ 10, 42 136 | IRQ 11, 43 137 | IRQ 12, 44 138 | IRQ 13, 45 139 | IRQ 14, 46 140 | IRQ 15, 47 141 | IRQ 126, 126 ; the task switch vector 142 | 143 | ; This is called/jumped to by the handlers created by the macros above. 144 | global irq_common_stub:function 145 | irq_common_stub: 146 | ; interrupts are already off 147 | mov byte [in_isr], 1 148 | push eax 149 | push ecx 150 | push edx 151 | push ebx 152 | push ebp 153 | push esi 154 | push edi 155 | 156 | push ds 157 | push es 158 | push fs 159 | push gs 160 | 161 | mov ax, 0x10 162 | mov ds, ax 163 | mov es, ax 164 | mov fs, ax 165 | mov gs, ax 166 | 167 | push esp 168 | call irq_handler 169 | mov esp, eax 170 | 171 | pop gs 172 | pop fs 173 | pop es 174 | pop ds 175 | 176 | pop edi 177 | pop esi 178 | pop ebp 179 | pop ebx 180 | pop edx 181 | pop ecx 182 | pop eax 183 | 184 | add esp, 8 185 | mov byte [in_isr], 0 186 | sti 187 | iret 188 | -------------------------------------------------------------------------------- /src/kernel/kernutil.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // Write a byte to the specified port 10 | void outb(uint16 port, uint8 value) 11 | { 12 | asm volatile ("outb %1, %0" : : "dN" (port), "a" (value)); 13 | } 14 | 15 | void outw(uint16 port, uint16 value) 16 | { 17 | asm volatile ("outw %1, %0" : : "dN" (port), "a" (value)); 18 | } 19 | 20 | void outl(uint16 port, uint32 value) 21 | { 22 | asm volatile ("outl %1, %0" : : "dN" (port), "a" (value)); 23 | } 24 | 25 | uint8 inb(uint16 port) 26 | { 27 | uint8 ret; 28 | asm volatile("inb %1, %0" : "=a" (ret) : "dN" (port)); 29 | return ret; 30 | } 31 | 32 | uint16 inw(uint16 port) 33 | { 34 | uint16 ret; 35 | asm volatile ("inw %1, %0" : "=a" (ret) : "dN" (port)); 36 | return ret; 37 | } 38 | 39 | uint32 inl(uint16 port) 40 | { 41 | uint32 ret; 42 | asm volatile ("inl %1, %0" : "=a" (ret) : "dN" (port)); 43 | return ret; 44 | } 45 | 46 | extern bool kernel_paniced; 47 | extern char _printk_buf[1024]; 48 | 49 | void panic(const char *fmt, ...) { 50 | asm volatile("cli"); 51 | console_switch(&kernel_console); 52 | console_task = &kernel_task; // always has a console; this way, putchar() won't panic and cause a triple fault 53 | scrollback_reset(); 54 | 55 | va_list args; 56 | int i; 57 | 58 | printk("\nPANIC: "); 59 | 60 | va_start(args, fmt); 61 | i = vsprintf(_printk_buf, fmt, args); 62 | va_end(args); 63 | 64 | if (i > 0) { 65 | size_t len = strlen(_printk_buf); 66 | for (size_t j = 0; j < len; j++) { 67 | putchar(_printk_buf[j]); 68 | } 69 | } 70 | 71 | printk("\nCurrent task: %u (%s)", current_task->id, current_task->name); 72 | 73 | kernel_paniced = true; 74 | update_statusbar(); 75 | 76 | // Uncommenting cli+hlt makes scrollback after a panic impossible, but 77 | // on the other hand, it gives useful backtraces and debugging possibilities 78 | // in gdb post-panic. 79 | // HOWEVER, it also makes it a not-really-true panic, since interrupts are still working, 80 | // and tasks don't stop...! 81 | 82 | asm volatile("cli; 0: hlt ; jmp 0b"); 83 | 84 | for(;;) { sleep(10000000); } 85 | } 86 | 87 | extern void panic_assert(const char *file, uint32 line, const char *desc) { 88 | /* Call panic() instead of doing this ourselves, so that breakpoints 89 | * on panic() catches assertions as well */ 90 | printk("\nAssertion failure! Backtrace:\n"); 91 | print_backtrace(); 92 | panic("Assertion failed: %s (%s:%d)\n", desc, file, line); 93 | } 94 | 95 | void reset(void) { 96 | /* Resets the CPU by causing a triple fault. 97 | * More specifically, it creates a NULL IDT pointer, loads the "IDT", and causes an interrupt. 98 | * There is, of course, no handler available to handle that interrupt, which eventually causes a triple fault. */ 99 | struct idt_ptr p; 100 | memset(&p, 0, sizeof(struct idt_ptr)); 101 | asm volatile("lidt (%0);" 102 | "int $3;" 103 | : : "r"(&p)); 104 | for(;;); // To keep GCC quiet; the above WILL not return, but GCC doesn't believe that 105 | } 106 | 107 | void reboot(void) { 108 | /* Restarts the computer. Initially, this simply calls reset(); in the future, 109 | * it will call the necessary cleanup functions, flush disk caches etc. */ 110 | reset(); 111 | } 112 | -------------------------------------------------------------------------------- /src/kernel/loader.s: -------------------------------------------------------------------------------- 1 | global loader:function ; making entry point visible to linker 2 | extern kmain ; kmain is defined elsewhere 3 | 4 | ; setting up the Multiboot header - see GRUB docs for details 5 | MODULEALIGN equ 1<<0 ; align loaded modules on page boundaries 6 | MEMINFO equ 1<<1 ; provide memory map 7 | FLAGS equ MODULEALIGN | MEMINFO ; this is the Multiboot 'flag' field 8 | MAGIC equ 0x1BADB002 ; 'magic number' lets bootloader find the header 9 | CHECKSUM equ -(MAGIC + FLAGS) ; checksum required 10 | 11 | section .__mbHeader ; to keep GRUB happy, this needs to be first; see linker.ld 12 | align 4 13 | 14 | MultiBootHeader: 15 | dd MAGIC 16 | dd FLAGS 17 | dd CHECKSUM 18 | 19 | section .text 20 | align 4 21 | 22 | ; reserve initial kernel stack space 23 | STACKSIZE equ 0x4000 24 | 25 | loader: 26 | mov esp, stack+STACKSIZE ; set up the stack 27 | push stack ; pass the initial stack ESP0 28 | push eax ; pass Multiboot magic number 29 | push ebx ; pass Multiboot info structure 30 | 31 | call kmain ; call the kernel 32 | 33 | cli 34 | .hang: 35 | hlt ; halt machine should kernel return 36 | jmp .hang 37 | 38 | section .bss 39 | align 4 40 | stack: 41 | resb STACKSIZE ; reserve 16k stack on a doubleword boundary 42 | -------------------------------------------------------------------------------- /src/kernel/mutex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | mutex_t *mutex_create(void) { 7 | mutex_t *mutex = kmalloc(sizeof(mutex_t)); 8 | mutex->owner = NULL; 9 | mutex->mutex = 0; 10 | 11 | return mutex; 12 | } 13 | 14 | extern volatile bool in_isr; 15 | extern volatile bool task_switching; 16 | 17 | void mutex_destroy(mutex_t *mutex) { 18 | assert(mutex->mutex == 0); // Must not be locked 19 | assert(mutex->owner == NULL); // Set during unlock 20 | kfree(mutex); 21 | } 22 | 23 | #define DISABLE_MUTEXES 0 24 | 25 | void mutex_lock(mutex_t *mutex) { 26 | assert(mutex != NULL); 27 | #if (!DISABLE_MUTEXES) 28 | uint8 success = 0; 29 | 30 | if (in_isr) 31 | panic("mutex_lock() while in ISR!"); 32 | 33 | while (success == 0) { 34 | asm volatile("LOCK BTSL $0, %[mutex];" 35 | "SETNCB %[success];" 36 | : 37 | [mutex]"=m"(mutex->mutex), 38 | [success]"=m"(success) 39 | : : "cc", "memory"); 40 | 41 | if (success) { 42 | mutex->owner = (task_t *)current_task; 43 | } 44 | else { 45 | //sleep(10); 46 | assert(task_switching == true); 47 | // if (task_switching) 48 | YIELD; 49 | } 50 | } 51 | #endif 52 | } 53 | 54 | void mutex_unlock(mutex_t *mutex) { 55 | assert(mutex != NULL); 56 | #if (!DISABLE_MUTEXES) 57 | if (in_isr) 58 | panic("mutex_unlock() while in ISR!"); 59 | assert(mutex->mutex != 0); // mutex is locked 60 | assert(mutex->owner == current_task); 61 | mutex->mutex = 0; 62 | mutex->owner = NULL; 63 | #endif 64 | } 65 | 66 | bool mutex_is_locked(mutex_t *mutex) { 67 | #if DISABLE_MUTEXES 68 | return false; 69 | #else 70 | return mutex->mutex != 0; 71 | #endif 72 | } 73 | -------------------------------------------------------------------------------- /src/kernel/net/internet_checksum.s: -------------------------------------------------------------------------------- 1 | section .text 2 | align 4 3 | global internet_checksum 4 | 5 | internet_checksum: 6 | ; set up the stack frame 7 | push ebp 8 | mov ebp, esp 9 | 10 | push ebx ; eax, ecx and edx can be trampled 11 | 12 | mov ebx, [ebp + 8] ; param 1 (data pointer) 13 | mov ecx, [ebp + 12] ; param 2 (length) 14 | 15 | xor ax, ax ; we store the sum here 16 | 17 | .loop: 18 | sub ecx, 2 ; if len = 20, data[20] is an invalid access! start off at length-2 19 | add ax, word [ebx + ecx] 20 | jc .addone 21 | .back: 22 | cmp ecx, 1 23 | je .lastbyte 24 | cmp ecx, 0 25 | jnz .loop 26 | jmp .end 27 | 28 | .addone: 29 | inc ax 30 | jmp .back 31 | 32 | .lastbyte: 33 | movzx dx, byte [ebx] 34 | add ax, dx 35 | jnc .end 36 | inc ax 37 | 38 | .end: 39 | pop ebx ; restore ebx 40 | not ax 41 | movzx eax, ax 42 | 43 | leave 44 | ret 45 | -------------------------------------------------------------------------------- /src/kernel/net/ipicmp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | uint8 ip_address[] = {192, 168, 10, 10}; // My IP address 13 | uint8 gateway[] = {192, 168, 10, 1}; // My default gw 14 | uint8 netmask[] = {255, 255, 255, 0}; // My netmask 15 | 16 | // A friend from ata.h 17 | #define BSWAP16(x) ( (((x) & 0xff) << 8) | (((x) & 0xff00) >> 8) ) 18 | 19 | // Are these two IPs on the same subnet? 20 | // Uses the netmask global. 21 | static bool same_subnet(uint8 *ip1, uint8 *ip2) { 22 | assert(ip1 != NULL); 23 | assert(ip2 != NULL); 24 | 25 | char buf1[4], buf2[4]; 26 | memcpy(buf1, ip1, 4); 27 | memcpy(buf2, ip2, 4); 28 | 29 | for (int i=0; i<4; i++) { 30 | buf1[i] &= netmask[i]; 31 | buf2[i] &= netmask[i]; 32 | } 33 | 34 | return memcmp(buf1, buf2, 4) == 0; 35 | } 36 | 37 | //void handle_icmp(uint8 *packet, uint16 length, uint8 *src_ip) { 38 | void handle_icmp(void *data, uint32 length) { 39 | uint8 *packet = (uint8 *)data + sizeof(ipv4header_t) + (((ipv4header_t *)data)->IHL - 5) * 4; 40 | uint8 type = *packet; 41 | uint8 code = *(packet + 1); 42 | uint16 checksum = *((uint16 *)(packet + 2)); 43 | checksum=checksum; // sigh 44 | code=code; 45 | 46 | // We don't want to transmit 20 (usually) bytes too much! 47 | length -= sizeof(ipv4header_t); 48 | 49 | switch (type) { 50 | case ICMP_ECHO_REQUEST: { // type 8 51 | //uint16 identifier = *((uint16 *)(packet + 4)); 52 | //uint16 seq = *((uint16 *)(packet + 6)); 53 | //printk("ICMP echo request: id=%u seq=%u\n", BSWAP16(identifier), BSWAP16(seq)); 54 | 55 | // Data length is the packet length, minus the 8 byte header 56 | //printk("Data length: %u\n", length - 8); 57 | 58 | uint8 buf[1500]; 59 | memcpy(buf, packet, length); 60 | 61 | // Set the type field 62 | *buf = ICMP_ECHO_REPLY; 63 | 64 | // Calculate and set checksum 65 | *((uint16 *)(buf + 2)) = 0; // only zero to compute checksum 66 | *((uint16 *)(buf + 2)) = internet_checksum(buf, length); 67 | 68 | uint8 *src_ip = (uint8 *) (((ipv4header_t *)data)->src_ip); 69 | send_ipv4_packet(src_ip, IPV4_PROTO_ICMP, buf, length); 70 | 71 | //kfree(buf); 72 | 73 | break; 74 | } 75 | 76 | default: 77 | break; 78 | } 79 | } 80 | 81 | void send_ipv4_packet(uint8 *dst_ip, uint8 protocol, void *payload, uint16 payload_size) { 82 | assert(dst_ip != NULL); 83 | assert(payload != NULL); 84 | assert(payload_size <= (1500 - sizeof(ipv4header_t))); 85 | 86 | uint8 buffer[1500]; 87 | ipv4header_t *ip_hdr = (ipv4header_t *)buffer; 88 | ip_hdr->IHL = 5; // no options field 89 | ip_hdr->version = 4; // always 4 for IPv4 90 | ip_hdr->DSCP = 0; // not used 91 | ip_hdr->ECN = 0; // not used 92 | ip_hdr->total_length = BSWAP16(sizeof(ipv4header_t) + payload_size); 93 | ip_hdr->id = 0; // TODO: is this OK? 94 | ip_hdr->ttl = 64; 95 | ip_hdr->protocol = protocol; 96 | memcpy(ip_hdr->src_ip, ip_address, 4); 97 | memcpy(ip_hdr->dst_ip, dst_ip, 4); 98 | ip_hdr->header_checksum = 0; // Zero only to calculate the actual checksum 99 | ip_hdr->header_checksum = internet_checksum(ip_hdr, sizeof(ipv4header_t)); 100 | 101 | memcpy(buffer + sizeof(ipv4header_t), payload, payload_size); 102 | 103 | uint8 dst_mac[6] = {0}; 104 | 105 | // Is the target IP on the same subnet as we are? 106 | if (same_subnet(dst_ip, ip_address)) { 107 | // Yep - go ahead as usual 108 | int ret = arp_lookup(dst_ip, dst_mac); 109 | assert(ret != 0); 110 | } 111 | else { 112 | // No - send this packet to the gateway's MAC address instead 113 | int ret = arp_lookup(gateway, dst_mac); 114 | assert(ret != 0); 115 | } 116 | 117 | // TODO: arp_lookup() needs writing! 118 | //dst_mac[0] = 0x10; 119 | //dst_mac[1] = 0x10; 120 | //dst_mac[2] = 0x10; 121 | //dst_mac[3] = 0x20; 122 | //dst_mac[4] = 0x20; 123 | //dst_mac[5] = 0x20; 124 | 125 | //printk("dst mac = %02x:%02x:%02x:%02x:%02x:%02x, dst ip = %d.%d.%d.%d\n", 126 | //dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5], 127 | //dst_ip[0], dst_ip[1], dst_ip[2], dst_ip[3]); 128 | //panic("Is that correct?"); 129 | 130 | rtl8139_send_frame(dst_mac, ETHERTYPE_IPV4, buffer, sizeof(ipv4header_t) + payload_size); 131 | } 132 | -------------------------------------------------------------------------------- /src/kernel/net/nethandler.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* 9 | * This "class" (collection functions and structs, rather) handles incoming network packets. 10 | * Previously, this was done in the ISR itself, which is a bad idea for several reasons. 11 | * After that, I used a similar approach to this one, except that it copied the data to a 12 | * malloc'ed buffer, and added a task to a linked list to be processed - list_append ALSO uses 13 | * malloc. 14 | * This appears only uses malloc on startup, which is 100% OK, and never at runtime. 15 | * 16 | * Each "nethandler" (currently one for ARP, one for ICMP - which will likely be expanded to IP) 17 | * holds a number of buffers, of which only one is used at a time. 18 | */ 19 | 20 | nethandler_t *nethandler_arp = NULL; 21 | nethandler_t *nethandler_icmp = NULL; 22 | 23 | // Create a new nethandler, and start a task. 24 | nethandler_t *nethandler_create(const char *name, void (*func)(void *, uint32)) { 25 | nethandler_t *worker = kmalloc(sizeof(nethandler_t)); 26 | 27 | assert(strlen(name) + 1 <= NETHANDLER_NAME_SIZE); 28 | strlcpy(worker->name, name, NETHANDLER_NAME_SIZE); 29 | 30 | worker->function = func; 31 | 32 | // Allocate memory for the buffers, and set them to a known state 33 | for (int i=0; i < NETHANDLER_NUM_BUFFERS; i++) { 34 | worker->buffers[i] = kmalloc(sizeof(nethandler_buffer_t)); 35 | memset(worker->buffers[i], 0, sizeof(nethandler_buffer_t)); // Also sets length and state 36 | } 37 | 38 | // Create a process to do all this 39 | worker->task = create_task(nethandler_task, name, &kernel_console, worker, sizeof(nethandler_t)); 40 | 41 | return worker; 42 | } 43 | 44 | // Called by the network card ISR to process a packet 45 | void nethandler_add_packet(nethandler_t *worker, void *data, uint32 length) { 46 | assert(worker != NULL); 47 | assert(data != NULL); 48 | assert(length > 0); 49 | 50 | // Find the first free buffer 51 | nethandler_buffer_t *buffer = NULL; 52 | for (int i = 0; i < NETHANDLER_NUM_BUFFERS; i++) { 53 | if (worker->buffers[i]->state == EMPTY) { 54 | buffer = worker->buffers[i]; 55 | break; 56 | } 57 | } 58 | if (buffer == NULL) { 59 | // No free buffers: drop this packet 60 | return; 61 | } 62 | 63 | memcpy(buffer->buffer, data, length); 64 | buffer->length = length; 65 | 66 | // This MUST be last, since the task may start work at any time after this is set 67 | buffer->state = NEEDS_PROCESSING; 68 | } 69 | 70 | // The *process* that does all the work. I'll try to come up with better naming 71 | // than to have "task" mean two different things... 72 | void nethandler_task(void *data, uint32 length) { 73 | nethandler_t *worker = (nethandler_t *)data; 74 | 75 | while (true) { 76 | nethandler_buffer_t *buffer = NULL; 77 | while (buffer == NULL) { 78 | buffer = NULL; 79 | for (int i=0; i < NETHANDLER_NUM_BUFFERS; i++) { 80 | if (worker->buffers[i]->state == NEEDS_PROCESSING) { 81 | buffer = worker->buffers[i]; 82 | buffer->state = CURRENTLY_PROCESSING; 83 | break; 84 | } 85 | } 86 | 87 | if (buffer == NULL) { 88 | // Nothing to do; switch to some other task, that can actually do something 89 | sleep(10); 90 | //YIELD; 91 | } 92 | } 93 | 94 | worker->function(buffer->buffer, buffer->length); 95 | memset(buffer->buffer, 0, NETHANDLER_BUFFER_SIZE); 96 | 97 | // Must be the very LAST thing we do, since the ISR may start filling this up any time when this is set 98 | buffer->state = EMPTY; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/kernel/ordered_array.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include /* sprintf, for a debugging change only! */ 7 | #include /* printk, same as above */ 8 | 9 | sint8 standard_lessthan_predicate(type_t a, type_t b) { 10 | return (a < b) ? 1 : 0; 11 | } 12 | 13 | /* Create an ordered array */ 14 | ordered_array_t create_ordered_array(uint32 max_size, lessthan_predicate_t less_than) { 15 | ordered_array_t arr; 16 | 17 | /* allocate one element extra; remove_ordered_array accesses one element past the end. 18 | * ugly, but easier (and prettier code, even if the idea is dirty) than changing the algorithm. */ 19 | arr.array = (void *)kmalloc( (max_size + 1) * sizeof(type_t)); 20 | memset(arr.array, 0, max_size * sizeof(type_t)); 21 | arr.size = 0; 22 | arr.max_size = max_size; 23 | arr.less_than = less_than; 24 | 25 | return arr; 26 | } 27 | 28 | /* Create an ordered array at /addr/ (doesn't allocate space!) */ 29 | ordered_array_t place_ordered_array(void *addr, uint32 max_size, lessthan_predicate_t less_than) { 30 | ordered_array_t arr; 31 | arr.array = (type_t *)addr; 32 | memset(arr.array, 0, max_size * sizeof(type_t)); 33 | arr.size = 0; 34 | arr.max_size = max_size; 35 | arr.less_than = less_than; 36 | 37 | return arr; 38 | } 39 | 40 | /* Destroy an ordered array */ 41 | void destroy_ordered_array(ordered_array_t *array) { 42 | kfree(array->array); 43 | } 44 | 45 | /* Insert an item into an ordered array */ 46 | void insert_ordered_array(type_t item, ordered_array_t *array) { 47 | assert(array->less_than != NULL); 48 | assert(array->size + 1 <= array->max_size); 49 | 50 | uint32 i = 0; 51 | 52 | /* Figure out where the item should be placed */ 53 | while (i < array->size && array->less_than(array->array[i], item)) 54 | i++; 55 | 56 | if (i == array->size) { 57 | /* Just add this item at the end of the array */ 58 | array->array[array->size] = item; 59 | } 60 | else { 61 | /* Save the current item */ 62 | type_t tmp = array->array[i]; 63 | 64 | array->array[i] = item; 65 | 66 | /* Move the rest of the array one step forwards */ 67 | while (i < array->size) { 68 | i++; 69 | type_t tmp2 = array->array[i]; 70 | array->array[i] = tmp; 71 | tmp = tmp2; 72 | } 73 | } 74 | 75 | array->size++; 76 | } 77 | 78 | sint32 indexof_ordered_array(type_t item, ordered_array_t *array) { 79 | /* Returns the index where this item is stored (or the first, if it exists multiple times), or -1 if nothing is found. */ 80 | sint32 i = 0; 81 | for (i = 0; i < (sint32)array->size; i++) { 82 | if (lookup_ordered_array(i, array) == item) 83 | return i; 84 | } 85 | 86 | return -1; 87 | } 88 | 89 | 90 | void update_ordered_array(uint32 i, type_t item, ordered_array_t *array) { 91 | assert(i < array->size); 92 | array->array[i] = item; 93 | } 94 | 95 | type_t lookup_ordered_array(uint32 i, ordered_array_t *array) { 96 | assert(i < array->size); 97 | return array->array[i]; 98 | } 99 | 100 | /* Remove the object at i from the array */ 101 | void remove_ordered_array(uint32 i, ordered_array_t *array) { 102 | /* Shrink the array, overrwriting the element to remove */ 103 | while (i < array->size) { 104 | array->array[i] = array->array[i+1]; 105 | i++; 106 | } 107 | 108 | array->size--; 109 | } 110 | 111 | /* Remove the item /item/; if multiple exist, the first is deleted */ 112 | void remove_ordered_array_item(type_t item, ordered_array_t *array) { 113 | for (uint32 i = 0; i < array->size; i++) { 114 | if (lookup_ordered_array(i, array) == item) { 115 | /* We found it! Now remove it: */ 116 | remove_ordered_array(i, array); 117 | return; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/kernel/partition.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include /* memset */ 7 | #include 8 | 9 | /* Used in this file only. */ 10 | struct mbr_ptable { 11 | uint8 bootable : 8; /* bit 7 (0x80) is set if bootable */ 12 | uint8 start_head : 8; 13 | uint8 start_sector : 6; 14 | uint16 start_cyl : 10; 15 | uint8 system_id : 8; 16 | uint8 ending_head : 8; 17 | uint8 ending_sector : 6; 18 | uint16 ending_cyl : 10; 19 | uint32 rel_sector : 32; /* also: starting LBA adress */ 20 | uint32 total_sectors : 32; 21 | } __attribute__((packed)); 22 | 23 | /* Reads LBA0, and sets up the partition entries for the disk. */ 24 | void parse_mbr(ata_device_t *dev) { 25 | assert(dev != NULL); 26 | assert(sizeof(struct mbr_ptable) == 16); 27 | 28 | memset(dev->partition, 0, sizeof(partition_t) * 4); 29 | 30 | /* If this device is nonexistant or an ATAPI device, set all partitions to 31 | * not present. */ 32 | if (!dev->exists || dev->is_atapi) { 33 | for (int i=0; i < 3; i++) { 34 | dev->partition[i].exists = false; 35 | } 36 | 37 | return; 38 | } 39 | 40 | /* Read the MBR from disk */ 41 | unsigned char *buf = kmalloc(512); 42 | int ret = ata_read(dev, /* LBA = */ 0, buf, 1); 43 | assert(ret != 0); 44 | 45 | /* Last 2 bytes of the MBR should be 0xAA55. 46 | * If they're not, set all partitions to not present and return. */ 47 | if (*( (uint16 *)(buf + 510) ) != 0xAA55) { 48 | for (int i=0; i < 3; i++) { 49 | dev->partition[i].exists = false; 50 | } 51 | 52 | return; 53 | } 54 | 55 | /* Loop through the partition table. */ 56 | for (int i = 0; i < 3; i++) { 57 | /* A bit ugly, but... eh. Partition entry 1 (1-indexed) is at offset 446, #2 at offset 446+16, etc. */ 58 | struct mbr_ptable *part = ((struct mbr_ptable *)(buf + 446)) + i; 59 | 60 | /* Check whether this partition exists or not */ 61 | if (part->system_id == 0 || part->total_sectors == 0) { 62 | dev->partition[i].exists = false; 63 | continue; 64 | } 65 | else 66 | dev->partition[i].exists = true; 67 | 68 | /* Set the bootable flag */ 69 | if (part->system_id & 0x80) 70 | dev->partition[i].bootable = true; 71 | 72 | /* Copy the system ID byte and the partition location/size */ 73 | dev->partition[i].type = part->system_id; 74 | dev->partition[i].start_lba = part->rel_sector; 75 | dev->partition[i].total_sectors = part->total_sectors; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/kernel/pci.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include /* memset */ 6 | 7 | /* Is this used? */ 8 | #include 9 | 10 | /* For debugging */ 11 | #include 12 | 13 | list_t *pci_devices = NULL; 14 | 15 | #define PCI_DEBUG 0 16 | 17 | pci_device_t *find_pci_device(uint32 vendor_id, uint32 device_id) { 18 | // list_node_find_next_predicate can't accept additional parameters (d'oh!), 19 | // so we'll have to do this ourselves. 20 | list_foreach(pci_devices, it) { 21 | pci_device_t *cur = (pci_device_t *)it->data; 22 | if (cur->vendor_id == vendor_id && cur->device_id == device_id) 23 | return cur; 24 | 25 | } 26 | 27 | return NULL; 28 | } 29 | 30 | // Reads the PCI configuration space, one dword at a time. 31 | // To read 8 or 16 bits, you currently need to AND the rest out yourself. 32 | uint32 pci_read_config(uint8 bus, uint8 slot, uint8 func, uint8 reg) { 33 | outl(PCI_CONFIG_ADDRESS, PCI_ENABLE | (bus << 16) | (slot << 11) | (func << 8) | (reg & ~0x3)); 34 | return inl(PCI_CONFIG_DATA); 35 | } 36 | 37 | void init_pci(void) { 38 | uint32 bus, slot, func; 39 | 40 | pci_devices = list_create(); 41 | 42 | for (bus = 0; bus < 256; bus++) { 43 | for (slot = 0; slot < 32; slot++) { 44 | for (func = 0; func < 8; func++) { 45 | uint32 vendor_id, device_id; 46 | 47 | vendor_id = (pci_read_config(bus, slot, func, PCI_CONF_VENDOR) & 0xffff); 48 | if (vendor_id == 0xffff) 49 | continue; 50 | 51 | device_id = (pci_read_config(bus, slot, func, PCI_CONF_DEVICE) & 0xffff0000) >> 16; 52 | uint32 class_tmp = pci_read_config(bus, slot, func, PCI_CONF_CLASS); 53 | 54 | uint32 classcode = (class_tmp >> 24); 55 | uint32 subclasscode = (class_tmp >> 16) & 0xff; 56 | 57 | //printk("device found at bus %u, slot %u, func %u: vendor 0x%04x, device 0x%04x\n", bus, slot, func, vendor_id, device_id); 58 | uint8 type = (pci_read_config(bus, slot, func, PCI_CONF_HEADER_TYPE) & 0x00ff0000) >> 24; 59 | 60 | /* 61 | if (type == 0) 62 | printk("Type: regular PCI device\n"); 63 | else if (type == 1) 64 | printk("Type: PCI-to-PCI bridge\n"); 65 | else if (type == 2) 66 | printk("Type: CardBus bridge\n"); 67 | */ 68 | 69 | uint8 interrupt = pci_read_config(bus, slot, func, PCI_CONF_IRQ) & 0xff; // lower 8 bits is the interrupt 70 | //printk("IRQ: %u\n", interrupt); 71 | 72 | // Store this device in the PCI device database 73 | pci_device_t *dev = kmalloc(sizeof(pci_device_t)); 74 | memset(dev, 0, sizeof(pci_device_t)); 75 | dev->vendor_id = vendor_id; 76 | dev->device_id = device_id; 77 | dev->irq = interrupt; 78 | dev->classcode = classcode; 79 | dev->subclasscode = subclasscode; 80 | 81 | list_append(pci_devices, dev); 82 | // BARs are filled in below 83 | 84 | uint32 bar[6] = {0}; 85 | if (type == 0) { 86 | for (int i=0; i<6; i++) { 87 | bar[i] = pci_read_config(bus, slot, func, 0x10 + i*4); 88 | if ((bar[i] & 1) == BAR_IO) { 89 | // This is an I/O space address; the 2 LSBs aren't part of the address 90 | dev->bar[i].type = BAR_IO; 91 | dev->bar[i].address = bar[i] & ~0x3; 92 | //printk("BAR%d is an IO address\n", i); 93 | } 94 | else { 95 | // Memory space address; 4 LSBs aren't part of the address (bit 3 is prefetch, 2-1 type, and bit 0 always 0) 96 | dev->bar[i].type = BAR_MEM; 97 | dev->bar[i].address = bar[i] & ~0xf; 98 | //if (bar[i] != 0) /* used for empty BARs */ 99 | //printk("BAR%d is a memory address\n", i); 100 | } 101 | } 102 | 103 | //printk("PCI revision: 0x%02x\n", pci_read_config(bus, slot, func, PCI_CONF_REVISION) & 0xff); 104 | 105 | //printk(" bar0 0x%08x bar1 0x%08x bar2 0x%08x bar3 0x%08x bar4 0x%08x bar5 0x%08x\n", dev->bar[0].address, dev->bar[1].address, dev->bar[2].address, dev->bar[3].address, dev->bar[4].address, dev->bar[5].address); 106 | //printk("\n"); 107 | //printk("database size is now %u items\n", pci_devices->count); 108 | } 109 | } 110 | } 111 | } 112 | 113 | #if PCI_DEBUG > 0 114 | for (node_t *n = pci_devices->head; n != NULL; n = n->next) { 115 | pci_device_t *cur = (pci_device_t *)n->data; 116 | printk("%04x:%04x", cur->vendor_id, cur->device_id); 117 | if (cur->irq != 0) 118 | printk(", IRQ %u", cur->irq); 119 | for (int i=0; i<6; i++) { 120 | if (cur->bar[i].address != 0) { 121 | printk(" BAR%u (%s): 0x%08x", i, cur->bar[i].type == BAR_IO ? "IO" : "MEM", cur->bar[i].address); 122 | } 123 | } 124 | printk("\n"); 125 | } 126 | #endif 127 | } 128 | -------------------------------------------------------------------------------- /src/kernel/serial.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // Port offsets 10 | #define SERIAL_DATA 0 11 | #define SERIAL_INT_ENABLE 1 12 | #define SERIAL_BAUD_LOW 0 /* with DLAB set */ 13 | #define SERIAL_BAUD_HIGH 1 /* with DLAB set */ 14 | #define SERIAL_DLAB 0x80 15 | #define SERIAL_INT_ID_FIFO 2 16 | #define SERIAL_LCR 3 /* Line Control Register */ 17 | #define SERIAL_MCR 4 /* Modem Control Register */ 18 | #define SERIAL_LINE_STATUS 5 19 | #define SERIAL_MODEM_STATUS 6 20 | #define SERIAL_SCRATCH 7 21 | 22 | static uint8 serial_reg_r(uint8 reg) { 23 | assert(reg <= 7); 24 | return inb(SERIAL_PORT + reg); 25 | } 26 | 27 | static bool serial_set_up = false; 28 | 29 | static void serial_reg_w(uint8 reg, uint8 value) { 30 | assert(reg <= 7); 31 | outb(SERIAL_PORT + reg, value); 32 | } 33 | 34 | void init_serial(void) { 35 | uint16 baud_divisor = 1; // 115200 baud 36 | 37 | serial_reg_w(SERIAL_INT_ENABLE, 0); // Disable interrutps 38 | serial_reg_w(SERIAL_LCR, SERIAL_DLAB); // Set DLAB, to send address 39 | serial_reg_w(SERIAL_BAUD_LOW, (baud_divisor & 0xff)); 40 | serial_reg_w(SERIAL_BAUD_HIGH, (baud_divisor & 0xff00) >> 8); 41 | serial_reg_w(SERIAL_LCR, 0x03); // 8N1 42 | serial_reg_w(SERIAL_INT_ID_FIFO, 0xC7); // Enable FIFO, clear them, with 14-byte threshold (TODO: look this up) 43 | serial_reg_w(SERIAL_MCR, 0x0b); // Hmm 44 | 45 | serial_set_up = true; 46 | } 47 | 48 | void serial_send_byte(char c) { 49 | if (!serial_set_up) 50 | return; 51 | 52 | while ((serial_reg_r(SERIAL_LINE_STATUS) & 0x20) == 0) { } 53 | serial_reg_w(SERIAL_DATA, c); 54 | } 55 | 56 | void serial_send(const char *str) { 57 | assert(str != NULL); 58 | if (!serial_set_up) 59 | return; 60 | const char *p = str; 61 | INTERRUPT_LOCK; 62 | while (*p != 0) { 63 | serial_send_byte(*p++); 64 | } 65 | INTERRUPT_UNLOCK; 66 | } 67 | 68 | static char _prints_buf[1024]; 69 | 70 | // Like printk, but prints to the serial console 71 | size_t prints(const char *fmt, ...) { 72 | va_list args; 73 | int i; 74 | 75 | //mutex_lock(printk_mutex); 76 | 77 | va_start(args, fmt); 78 | i = vsprintf(_prints_buf, fmt, args); 79 | va_end(args); 80 | 81 | if (i > 0) { 82 | INTERRUPT_LOCK; 83 | size_t len = strlen(_prints_buf); 84 | for (size_t j = 0; j < len; j++) { 85 | serial_send_byte(_prints_buf[j]); 86 | } 87 | INTERRUPT_UNLOCK; 88 | } 89 | 90 | //mutex_unlock(printk_mutex); 91 | 92 | return i; 93 | } 94 | -------------------------------------------------------------------------------- /src/kernel/stdio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* Implements I/O for the standard streams */ 9 | 10 | int stdio_read(int fd, void *buf, size_t length) { 11 | struct open_file *filp = get_filp(fd); 12 | if (!filp) 13 | return -EBADF; 14 | if (filp->ino != 0) { 15 | assert(filp->ino <= 2); 16 | // Read on stdout or stderr 17 | return 0; 18 | } 19 | 20 | char *p = (char *)buf; 21 | 22 | if (fd != 0) { 23 | return 0; // Don't allow reading from stdout/stderr 24 | } 25 | 26 | int ret = 0; 27 | while (p < (char *)buf + length - 1 /* NULL termination */) { 28 | char c = getchar(); 29 | 30 | if (c >= ' ' || c == '\n') { 31 | putchar(c); // echo to screen 32 | update_cursor(); 33 | } 34 | else if (c == '\b') { 35 | if (p > (char *)buf) { 36 | p--; 37 | putchar(c); 38 | putchar(' '); 39 | putchar(c); 40 | update_cursor(); 41 | ret--; 42 | } 43 | } 44 | else if (c == -1) { 45 | // EOF sent by Ctrl-D 46 | if (ret > 0) 47 | continue; 48 | else { 49 | putchar('^'); 50 | putchar('D'); 51 | return 0; 52 | } 53 | } 54 | 55 | if (c == '\r' || c == '\n') { 56 | ret++; 57 | *p++ = c; 58 | *p = 0; 59 | return ret; 60 | } 61 | else if (c != '\b') { 62 | *p++ = c; 63 | ret++; 64 | } 65 | } 66 | 67 | assert(p < (char *)buf + length); 68 | *p = 0; 69 | 70 | return ret; 71 | } 72 | 73 | int stdio_write(int fd, const void *buf, size_t length) { 74 | struct open_file *filp = get_filp(fd); 75 | if (!filp) 76 | return -EBADF; 77 | if (filp->ino == 0) { 78 | // Write on stdin 79 | return 0; 80 | } 81 | 82 | // stdout and stderr are treated identically; neither is buffered 83 | 84 | const char *p = (const char *)buf; 85 | size_t ret = 0; 86 | 87 | for (size_t i = 0; i < length && *p; i++) { 88 | assert(p < (const char *)buf + length); 89 | putchar(*p++); 90 | ret++; 91 | } 92 | update_cursor(); 93 | 94 | return ret; 95 | } 96 | 97 | int stdio_close(int fd, struct open_file *file) { 98 | // We really don't need to do anything at all, 99 | // except for the stuff that close() does for us after we return! 100 | 101 | return 0; 102 | } 103 | 104 | int stdio_fstat(int fd, struct stat *st) { 105 | struct open_file *filp = get_filp(fd); 106 | if (!filp) 107 | return -EBADF; 108 | memset(st, 0, sizeof(struct stat)); 109 | st->st_dev = 0xffff; // TODO 110 | st->st_ino = filp->ino; 111 | st->st_mode = 0666 | S_IFCHR; 112 | st->st_blksize = 128; 113 | 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /src/kernel/timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* Enough to not wrap in 497 days */ 8 | volatile uint32 timer_ticks = 0; 9 | 10 | uint32 gettickcount(void) { 11 | /* Returns the number of ticks that have passed since reboot. */ 12 | return timer_ticks; 13 | } 14 | 15 | uint32 uptime(void) { 16 | /* Returns the system uptime, in seconds. */ 17 | return timer_ticks / TIMER_HZ; 18 | } 19 | 20 | uint32 timer_handler(uint32 esp) { 21 | /* Increase the tick count */ 22 | timer_ticks++; 23 | 24 | /* make sure the tick is visible somehow */ 25 | //uint16 *vram = (uint16 *)(0xb8000 + 79*2); 26 | //*vram = (*vram) + 1; 27 | 28 | if ((timer_ticks & 15) == 0) 29 | update_statusbar(); 30 | 31 | return esp; 32 | } 33 | 34 | // Like sleep, but works on any process/thread. Wastes CPU cycles, of course, but it can still be handy at times. 35 | void delay(uint32 ms) { 36 | if (timer_ticks == 0) 37 | return; // ugly safeguard: return if the timer isn't installed yet 38 | uint32 ticks = ms / 10; 39 | if (ticks == 0) 40 | ticks = 1; 41 | uint32 start = gettickcount(); 42 | while (gettickcount() < start + ticks) { } 43 | } 44 | 45 | /* 46 | * I *think* the error from timer drift comes to ~1.3 seconds per 24 hours, but 47 | * I don't feel too certain about the calculations... 48 | * Those 1.3 seconds (if correct) come from the fact that we assume the timer frequency to be 100.00 Hz, but 49 | * it in reality is sliightly less at something about 99.9985 Hz. 50 | * Additional error will of course be added due to PIT inaccurary - or, if we're lucky, they cancel out 51 | * so that the accuracy in in fact improved! Needless to say, we can't know or rely on either of these, though. 52 | */ 53 | void timer_install(void) { 54 | /* 55 | * Set the timer frequency 56 | * If the oscillator works at 1 193 182 Hz, dividing by 11932 gives 57 | * 99.9985 Hz, the closest possible to 100 (with an integer divisor, of course). 58 | */ 59 | outb(0x43, 0x36); 60 | outb(0x40, TIMER_DIVISOR & 0xff); /* set low byte */ 61 | outb(0x40, (TIMER_DIVISOR >> 8) & 0xff); /* set high byte */ 62 | 63 | /* Install the timer handler */ 64 | register_interrupt_handler(IRQ0, timer_handler); 65 | } 66 | -------------------------------------------------------------------------------- /src/kernel/zero_page.s: -------------------------------------------------------------------------------- 1 | section .text 2 | align 4 3 | global zero_page_physical:function 4 | 5 | zero_page_physical: 6 | push esi ; we can only trample eax, ecx and edx 7 | push edi 8 | 9 | ; NOTE: if the number of pushes above changes, this offset changes as well! 10 | mov edi, [esp+12] ; dest address 11 | 12 | ; Disable paging 13 | mov edx, cr0 14 | and edx, 0x7fffffff 15 | mov cr0, edx 16 | 17 | ; Zero the framae 18 | xor eax, eax 19 | mov ecx, 1024 20 | rep stosd 21 | 22 | ; Re-enable paging 23 | mov edx, cr0 24 | or edx, 0x80000000 25 | mov cr0, edx 26 | 27 | pop edi 28 | pop esi 29 | ret 30 | -------------------------------------------------------------------------------- /src/lib/memcpy.s: -------------------------------------------------------------------------------- 1 | section .text 2 | align 4 3 | global memcpy 4 | 5 | memcpy: 6 | ; set up the stack frame 7 | push ebp 8 | mov ebp, esp 9 | 10 | ; save registers (we can only destroy EAX, ECX and EDX) 11 | push ebx 12 | push edi 13 | push esi 14 | 15 | mov edi, [ebp + 8] ; param #1 (dst) 16 | mov esi, [ebp + 12] ; param #2 (src) 17 | mov eax, [ebp + 16] ; param #3 (len) 18 | 19 | push edi ; save the first argument, since we need to return it 20 | 21 | ; Set ecx to the number of dwords to copy 22 | xor edx, edx ; clear edx before division 23 | mov ebx, 4 ; div doesn't accept immediate operands 24 | div ebx 25 | mov ecx, eax ; len/4 dwords to copy (since each is 4 bytes!) 26 | mov ebx, edx ; len%4 bytes left; store this in ebx for the moment 27 | 28 | rep movsd ; copy the dwords 29 | mov ecx, ebx ; ebx = number of bytes remaining 30 | rep movsb ; copy the bytes, if any 31 | 32 | ; pop the return value 33 | pop eax 34 | 35 | ; restore the registers we pushed 36 | pop esi 37 | pop edi 38 | pop ebx 39 | 40 | leave ; clean up the stack frame 41 | ret 42 | -------------------------------------------------------------------------------- /src/lib/memset.s: -------------------------------------------------------------------------------- 1 | section .text 2 | align 4 3 | global memset 4 | 5 | ; void *memset(void *addr, int c, size_t n); 6 | ; returns the input addr 7 | 8 | memset: 9 | ; set up the stack frame 10 | push ebp 11 | mov ebp, esp 12 | 13 | ; save registers (we can only destroy EAX, ECX and EDX) 14 | push ebx 15 | push edi 16 | 17 | ; slosl: Fill (E)CX dwords at ES:[(E)DI] with EAX 18 | ; stosb: Fill (E)CX bytes at ES:[(E)DI] with AL 19 | 20 | mov edi, [ebp + 8] ; param #1 (addr) 21 | mov ebx, [ebp + 12] ; param #2 (character) 22 | mov ecx, [ebp + 16] ; param #3 (length) 23 | 24 | ; push the first argument; it's our return value 25 | push edi 26 | 27 | ; set up the value to write; since we should only use the lower 8 bits of it, we need to repeat it. 28 | ; i.e. the input may be 0x000000ab (meaning the user specified 0xab; the rest is padding for the int type used), 29 | ; meaning we want to write the dword 0xabababab. 30 | ; bl contains the bits to use and repeat. 31 | and ebx, 0xff ; clear any other bits 32 | xor eax, eax ; clear the target register 33 | or eax, ebx ; add the lowest two bits, 0x000000YY 34 | shl ebx, 8 35 | or eax, ebx ; add 0x0000YY00 bits 36 | shl ebx, 8 37 | or eax, ebx ; add 0x00YY0000 bits 38 | shl ebx, 8 39 | or eax, ebx ; add 0xYY000000 bits 40 | 41 | ; eax should now contain the pattern we want (for stosd), e.g. 0xabababab for the input 0xab 42 | ; likewise, al should contain the pattern we want (for stosb) 43 | 44 | push eax ; store the value (temporarily, while we calculate the number of dwords and bytes) 45 | 46 | ; Set ecx to the number of dwords to set 47 | mov eax, ecx ; ecx = number of bytes to set 48 | xor edx, edx ; clear edx before division 49 | mov ebx, 4 ; div doesn't accept immediate operands 50 | div ebx 51 | mov ecx, eax ; len/4 dwords to copy (since each is 4 bytes!) 52 | mov ebx, edx ; len%4 bytes left; store this in ebx for the moment 53 | 54 | pop eax ; fetch the value to set into eax 55 | 56 | rep stosd ; set the dwords 57 | mov ecx, ebx ; ebx = number of bytes remaining (i.e. len % 4) 58 | rep stosb ; set the bytes, if any 59 | 60 | ; pop the return value 61 | pop eax 62 | 63 | ; restore the registers we pushed 64 | pop edi 65 | pop ebx 66 | 67 | leave ; clean up the stack frame 68 | ret 69 | -------------------------------------------------------------------------------- /src/lib/memsetw.s: -------------------------------------------------------------------------------- 1 | section .text 2 | align 4 3 | global memsetw 4 | 5 | ; void *memsetw(void *addr, uint16 word, size_t n); 6 | ; returns the input addr 7 | 8 | memsetw: 9 | ; set up the stack frame 10 | push ebp 11 | mov ebp, esp 12 | 13 | ; save registers (we can only destroy EAX, ECX and EDX) 14 | push ebx 15 | push edi 16 | 17 | mov edi, [ebp + 8] ; param #1 (addr) 18 | mov ebx, [ebp + 12] ; param #2 (word to fill with) 19 | mov ecx, [ebp + 16] ; param #3 (length (number of words)) 20 | 21 | ; push the first argument; it's our return value 22 | push edi 23 | 24 | ; set up the value to write 25 | and ebx, 0xffff ; clear any other bits (this should be a noop?) 26 | xor eax, eax ; clear the target register 27 | or eax, ebx ; add the low 16 bits (0x0000YYYY) 28 | shl ebx, 16 29 | or eax, ebx ; add the high 16 bits (0xYYYY0000) 30 | 31 | ; eax should now contain the pattern we want (for stosd) 32 | ; likewise, ax should contain the pattern we want (for stosw) 33 | 34 | push eax ; store the value (temporarily, while we calculate the number of dwords and words) 35 | 36 | ; Set ecx to the number of dwords to set 37 | mov eax, ecx ; ecx = number of words to set 38 | xor edx, edx ; clear edx before division 39 | mov ebx, 2 ; div doesn't accept immediate operands 40 | div ebx 41 | mov ecx, eax ; len/2 dwords to copy 42 | mov ebx, edx ; len%2 words left; store this in ebx for the moment 43 | 44 | pop eax ; fetch the value to set into eax 45 | 46 | rep stosd ; set the dwords 47 | mov ecx, ebx ; ebx = number of words remaining (i.e. len % 2 - 0 or 1) 48 | rep stosw ; set the word, if any 49 | 50 | ; pop the return value 51 | pop eax 52 | 53 | ; restore the registers we pushed 54 | pop edi 55 | pop ebx 56 | 57 | leave ; clean up the stack frame 58 | ret 59 | -------------------------------------------------------------------------------- /src/lib/path.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static bool __path_join(char *path, const char *right) { 6 | if (path == NULL || right == NULL) 7 | return false; 8 | if (strlen(right) > 255) 9 | return false; 10 | 11 | if (strchr(right, '/') != NULL) 12 | return false; // TODO: shouldn't happen 13 | 14 | if (strcmp(right, ".") == 0) 15 | return true; // We didn't do anything, but didn't fail either 16 | if (strcmp(right, "..") == 0) { 17 | // Move back one directory 18 | path_dirname(path); 19 | return true; 20 | } 21 | 22 | size_t path_len = strlen(path); 23 | if (path[path_len - 1] != '/' && right[0] != '/') { 24 | // Add a slash between the two 25 | path[path_len] = '/'; 26 | path[path_len + 1] = 0; 27 | } 28 | 29 | bool trunc = (strlen(path) + strlen(right) > PATH_MAX); 30 | 31 | strlcat(path, right, PATH_MAX); 32 | 33 | return !trunc; 34 | } 35 | 36 | bool path_join(char *path, const char *right) { 37 | char *tmp; 38 | char *token = NULL; 39 | char buf[PATH_MAX+1] = {0}; 40 | strlcpy(buf, right, PATH_MAX+1); 41 | for (token = strtok_r(buf, "/", &tmp); token != NULL; token = strtok_r(NULL, "/", &tmp)) { 42 | if (!__path_join(path, token)) 43 | return false; 44 | } 45 | 46 | return true; 47 | } 48 | 49 | // Removes . and .. from the path, converting it as necessary. 50 | // For example, the input "/a/b/../c/./d" should become "/a/c/d". 51 | bool path_collapse_dots(char *path) { 52 | if (*path != '/') 53 | return false; 54 | 55 | char buf[PATH_MAX+1] = {0}; 56 | strcpy(buf, "/"); 57 | 58 | char *tmp; 59 | char *token = NULL; 60 | for (token = strtok_r(path, "/", &tmp); token != NULL; (token = strtok_r(NULL, "/", &tmp))) { 61 | path_join(buf, token); 62 | } 63 | 64 | // The output string should never be longer than the input, so this should be OK. 65 | strcpy(path, buf); 66 | 67 | return true; 68 | } 69 | 70 | void path_dirname(char *path) { 71 | size_t path_len = strlen(path); 72 | if (path[path_len - 1] == '/') 73 | path[path_len - 1] = 0; 74 | 75 | char *p = strrchr(path, '/'); 76 | if (p != NULL) 77 | *p = 0; 78 | 79 | if(path[0] == 0) { 80 | // If this happens, the parent is the root directory 81 | strcpy(path, "/"); 82 | } 83 | } 84 | 85 | void path_basename(char *path) { 86 | size_t path_len = strlen(path); 87 | if (path[path_len - 1] == '/' && path_len != 1) 88 | path[path_len - 1] = 0; 89 | else if (path[path_len - 1] == '/' && path_len == 1) { 90 | // Path is / 91 | return; 92 | } 93 | 94 | char *p = strrchr(path, '/'); 95 | 96 | char tmp[256] = {0}; // we don't have memmove(), so use a temporary buffer 97 | 98 | strlcpy(tmp, p + 1, 256); 99 | strlcpy(path, tmp, 256); 100 | } 101 | -------------------------------------------------------------------------------- /src/lib/stdlib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void reverse(char *s) { 5 | /* Reverses the bytes of a string. The string must be NULL-terminated. */ 6 | char tmp; 7 | size_t j = strlen(s) - 1; 8 | for (size_t i=0; i < j; i++, j--) { 9 | tmp = s[j]; 10 | s[j] = s[i]; 11 | s[i] = tmp; 12 | } 13 | } 14 | 15 | void itoa(signed long n, char *out) { 16 | /* Converts a signed long to a char[] representation. */ 17 | /* Make sure the 'out' parameter is large enough! */ 18 | /* 21 bytes should be enough even for 64-bit signed longs. */ 19 | 20 | signed long sign = n; 21 | 22 | if (n < 0) 23 | n = -n; 24 | else if (n == 0) { 25 | out[0] = 0x30; 26 | out[1] = 0; 27 | return; 28 | } 29 | 30 | signed long i; 31 | for (i = 0; n > 0 /* [sic] */; i++) { 32 | out[i] = (n % 10) + 0x30; /* dec -> ASCII */ 33 | n /= 10; 34 | } 35 | if (sign < 0) 36 | out[i++] = '-'; 37 | 38 | out[i++] = 0; 39 | 40 | reverse(out); 41 | } 42 | 43 | /* A nice, simple, and probably not-too-great PRNG */ 44 | 45 | static unsigned long int next = 1; 46 | 47 | int rand(void) // RAND_MAX assumed to be 32767 48 | { 49 | next = next * 1103515245 + 12345; 50 | return (unsigned int)(next/65536) % 32768; 51 | } 52 | 53 | void srand(unsigned int seed) 54 | { 55 | next = seed; 56 | } 57 | 58 | int isdigit(int c) { 59 | if (c >= '0' && c <= '9') 60 | return 1; 61 | else 62 | return 0; 63 | } 64 | 65 | /* Calculates base^exp - integers only. No negative exponents. */ 66 | int ipow(int base, int exp) { 67 | if (base == 0) 68 | return 0; // 0^anything is 0 69 | if (exp < 0) 70 | return 0; // we don't support negative exponents 71 | if (exp == 0) 72 | return 1; // anything^0 is 1 (except 0^0, handled above) 73 | 74 | int result = 1; 75 | while (exp--) 76 | result *= base; 77 | 78 | return result; 79 | } 80 | 81 | /* Converts a char array to an integer. */ 82 | int atoi(const char *str) { 83 | if (*str == 0) 84 | return 0; 85 | 86 | int num = 0; 87 | 88 | /* skip non-number data */ 89 | while (*str && !isdigit(*str) && *str != '-') str++; 90 | 91 | /* support negative numbers */ 92 | int sign = 1; 93 | if (*str == '-') { 94 | sign = -1; 95 | str++; 96 | } 97 | 98 | /* calculate the end of the actual number data (other data is allowed and ignored) */ 99 | const char *end = str; 100 | while (isdigit(*end)) end++; 101 | 102 | /* calculate the length */ 103 | size_t len = (end - str); 104 | 105 | /* Calculate the actual number */ 106 | const char *p = str; 107 | for (size_t i = 0; i < len; i++) { 108 | num += (*p++ - 0x30) * ipow(10, (len - i - 1)); 109 | } 110 | 111 | /* Flip the sign (multiply by -1) if needed */ 112 | num *= sign; 113 | 114 | return num; 115 | } 116 | -------------------------------------------------------------------------------- /src/lib/vsprintf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * linux/kernel/vsprintf.c 3 | * 4 | * (C) 1991 Linus Torvalds 5 | */ 6 | 7 | /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ 8 | /* 9 | * Wirzenius wrote this portably, Torvalds fucked it up :-) 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | /* we use this so that we can do without the ctype library */ 16 | #define is_digit(c) ((c) >= '0' && (c) <= '9') 17 | 18 | static int skip_atoi(const char **s) 19 | { 20 | int i=0; 21 | 22 | while (is_digit(**s)) 23 | i = i*10 + *((*s)++) - '0'; 24 | return i; 25 | } 26 | 27 | #define ZEROPAD 1 /* pad with zero */ 28 | #define SIGN 2 /* unsigned/signed long */ 29 | #define PLUS 4 /* show plus */ 30 | #define SPACE 8 /* space if plus */ 31 | #define LEFT 16 /* left justified */ 32 | #define SPECIAL 32 /* 0x */ 33 | #define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ 34 | 35 | #define do_div(n,base) ({ \ 36 | int __res; \ 37 | __asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ 38 | __res; }) 39 | 40 | static char * number(char * str, int num, int base, int size, int precision 41 | ,int type) 42 | { 43 | char c,sign,tmp[36]; 44 | const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 45 | int i; 46 | 47 | if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; 48 | if (type&LEFT) type &= ~ZEROPAD; 49 | if (base<2 || base>36) 50 | return 0; 51 | c = (type & ZEROPAD) ? '0' : ' ' ; 52 | if (type&SIGN && num<0) { 53 | sign='-'; 54 | num = -num; 55 | } else 56 | sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0); 57 | if (sign) size--; 58 | if (type&SPECIAL) { 59 | if (base==16) size -= 2; 60 | else if (base==8) size--; 61 | } 62 | i=0; 63 | if (num==0) 64 | tmp[i++]='0'; 65 | else while (num!=0) { 66 | tmp[i++] = digits[do_div(num,base)]; 67 | } 68 | if (i>precision) precision=i; 69 | size -= precision; 70 | if (!(type&(ZEROPAD+LEFT))) 71 | while(size-->0) 72 | *str++ = ' '; 73 | if (sign) 74 | *str++ = sign; 75 | if (type&SPECIAL) { 76 | if (base==8) 77 | *str++ = '0'; 78 | else if (base==16) { 79 | *str++ = '0'; 80 | *str++ = digits[33]; 81 | } 82 | } 83 | if (!(type&LEFT)) 84 | while(size-->0) 85 | *str++ = c; 86 | while(i0) 89 | *str++ = tmp[i]; 90 | while(size-->0) 91 | *str++ = ' '; 92 | return str; 93 | } 94 | 95 | int vsprintf(char *buf, const char *fmt, __gnuc_va_list args) 96 | { 97 | int len; 98 | int i; 99 | char * str; 100 | char *s; 101 | int *ip; 102 | 103 | int flags; /* flags to number() */ 104 | 105 | int field_width; /* width of output field */ 106 | int precision; /* min. # of digits for integers; max 107 | number of chars for from string */ 108 | // int qualifier; /* 'h', 'l', or 'L' for integer fields */ 109 | 110 | for (str=buf ; *fmt ; ++fmt) { 111 | if (*fmt != '%') { 112 | *str++ = *fmt; 113 | continue; 114 | } 115 | 116 | /* process flags */ 117 | flags = 0; 118 | repeat: 119 | ++fmt; /* this also skips first '%' */ 120 | switch (*fmt) { 121 | case '-': flags |= LEFT; goto repeat; 122 | case '+': flags |= PLUS; goto repeat; 123 | case ' ': flags |= SPACE; goto repeat; 124 | case '#': flags |= SPECIAL; goto repeat; 125 | case '0': flags |= ZEROPAD; goto repeat; 126 | } 127 | 128 | /* get field width */ 129 | field_width = -1; 130 | if (is_digit(*fmt)) 131 | field_width = skip_atoi(&fmt); 132 | else if (*fmt == '*') { 133 | /* it's the next argument */ 134 | field_width = va_arg(args, int); 135 | if (field_width < 0) { 136 | field_width = -field_width; 137 | flags |= LEFT; 138 | } 139 | } 140 | 141 | /* get the precision */ 142 | precision = -1; 143 | if (*fmt == '.') { 144 | ++fmt; 145 | if (is_digit(*fmt)) 146 | precision = skip_atoi(&fmt); 147 | else if (*fmt == '*') { 148 | /* it's the next argument */ 149 | precision = va_arg(args, int); 150 | } 151 | if (precision < 0) 152 | precision = 0; 153 | } 154 | 155 | /* get the conversion qualifier */ 156 | /* 157 | qualifier = -1; 158 | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { 159 | qualifier = *fmt; 160 | ++fmt; 161 | } 162 | */ 163 | switch (*fmt) { 164 | case 'c': 165 | if (!(flags & LEFT)) 166 | while (--field_width > 0) 167 | *str++ = ' '; 168 | *str++ = (unsigned char) va_arg(args, int); 169 | while (--field_width > 0) 170 | *str++ = ' '; 171 | break; 172 | 173 | case 's': 174 | s = va_arg(args, char *); 175 | len = strlen(s); 176 | if (precision < 0) 177 | precision = len; 178 | else if (len > precision) 179 | len = precision; 180 | 181 | if (!(flags & LEFT)) 182 | while (len < field_width--) 183 | *str++ = ' '; 184 | for (i = 0; i < len; ++i) 185 | *str++ = *s++; 186 | while (len < field_width--) 187 | *str++ = ' '; 188 | break; 189 | 190 | case 'o': 191 | str = number(str, va_arg(args, unsigned long), 8, 192 | field_width, precision, flags); 193 | break; 194 | 195 | case 'p': 196 | if (field_width == -1) { 197 | field_width = 8; 198 | flags |= ZEROPAD; 199 | } 200 | str = number(str, 201 | (unsigned long) va_arg(args, void *), 16, 202 | field_width, precision, flags); 203 | break; 204 | 205 | case 'x': 206 | flags |= SMALL; 207 | case 'X': 208 | str = number(str, va_arg(args, unsigned long), 16, 209 | field_width, precision, flags); 210 | break; 211 | 212 | case 'd': 213 | case 'i': 214 | flags |= SIGN; 215 | case 'u': 216 | str = number(str, va_arg(args, unsigned long), 10, 217 | field_width, precision, flags); 218 | break; 219 | 220 | case 'n': 221 | ip = va_arg(args, int *); 222 | *ip = (str - buf); 223 | break; 224 | 225 | default: 226 | if (*fmt != '%') 227 | *str++ = '%'; 228 | if (*fmt) 229 | *str++ = *fmt; 230 | else 231 | --fmt; 232 | break; 233 | } 234 | } 235 | *str = '\0'; 236 | return str-buf; 237 | } 238 | -------------------------------------------------------------------------------- /src/userspace/.user_Makefile: -------------------------------------------------------------------------------- 1 | WARNINGS := -Wall -Wextra -Wshadow -Wpointer-arith -Wcast-align \ 2 | -Wwrite-strings -Wredundant-decls -Wnested-externs -Winline \ 3 | -Wuninitialized -Wstrict-prototypes \ 4 | -Wno-unused-parameter -Wno-cast-align -Werror 5 | 6 | CC = i586-pc-exscapeos-gcc 7 | CFLAGS := -O0 -std=gnu99 -march=i586 $(WARNINGS) -ggdb3 -static -D_EXSCAPEOS 8 | LD = i586-pc-exscapeos-gcc 9 | LDFLAGS := -lc 10 | 11 | SRCFILES := $(shell find . -type f -name '*.c') 12 | OBJFILES := $(patsubst %.c,%.o,$(SRCFILES)) 13 | DEPFILES := $(patsubst %.c,%.d,$(SRCFILES)) 14 | 15 | OUTNAME := $(shell basename "`pwd`") 16 | 17 | all: $(OBJFILES) 18 | @$(LD) $(LDFLAGS) -o $(OUTNAME) $(OBJFILES) 19 | @mv -f $(OUTNAME) ../../../initrd/bin 20 | 21 | clean: 22 | -$(RM) $(wildcard $(OBJFILES) $(DEPFILES) ../../../initrd/bin/$(OUTNAME)) 23 | 24 | -include $(DEPFILES) 25 | 26 | %.o: %.c Makefile 27 | @$(CC) $(CFLAGS) -MMD -MP -c $< -o $@ 28 | -------------------------------------------------------------------------------- /src/userspace/cat/Makefile: -------------------------------------------------------------------------------- 1 | ../.user_Makefile -------------------------------------------------------------------------------- /src/userspace/cat/cat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifndef O_RDONLY 11 | #define O_RDONLY 0 12 | #endif 13 | 14 | int main(int argc, char **argv) { 15 | #define BUFSIZE (16*1024) 16 | char *buf = malloc(BUFSIZE); 17 | 18 | bool error = false; 19 | 20 | for (int i=1; i < argc || i == 1; i++) { 21 | const char *filename; 22 | int fd; 23 | 24 | if (argc == 1 || (argc > 1 && !strcmp(argv[i], "-"))) { 25 | filename = "(stdin)"; 26 | fd = fileno(stdin); 27 | } 28 | else { 29 | filename = argv[i]; 30 | fd = open(filename, O_RDONLY); 31 | if (fd < 0) { 32 | fprintf(stderr, "%s: %s: %s\n", argv[0], filename, strerror(errno)); 33 | error = true; 34 | continue; 35 | } 36 | struct stat st; 37 | if (fstat(fd, &st) != 0) { 38 | fprintf(stderr, "cat: %s: %s\n", filename, strerror(errno)); 39 | error = true; 40 | continue; 41 | } 42 | if (S_ISDIR(st.st_mode)) { 43 | fprintf(stderr, "cat: %s: %s\n", filename, strerror(EISDIR)); 44 | error = true; 45 | continue; 46 | } 47 | } 48 | 49 | int r = 0; 50 | uint32 tot = 0; 51 | do { 52 | memset(buf, 0, BUFSIZE); 53 | r = read(fd, buf, BUFSIZE); 54 | if (r == -1) { 55 | fprintf(stderr, "%s: %s: %s\n", argv[0], filename, strerror(errno)); 56 | break; 57 | } 58 | tot += r; 59 | if (r > 0) 60 | write(fileno(stdout), buf, r); 61 | } while (r > 0); 62 | 63 | if (!strcmp(filename, "stdin") != 0 && fd != fileno(stdin)) 64 | close(fd); 65 | } 66 | 67 | if (!error) 68 | return 0; 69 | else 70 | return 1; 71 | } 72 | -------------------------------------------------------------------------------- /src/userspace/cpuid/Makefile: -------------------------------------------------------------------------------- 1 | ../.user_Makefile -------------------------------------------------------------------------------- /src/userspace/cpuid/cpuid.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) { 4 | int eax, ebx, ecx, edx; 5 | asm volatile("movl $1, %%eax;" 6 | "cpuid;" 7 | " mov %%eax, %[eaxout];" 8 | " mov %%ebx, %[ebxout];" 9 | " mov %%ecx, %[ecxout];" 10 | " mov %%edx, %[edxout];" 11 | : [eaxout] "=m"(eax), 12 | [ebxout] "=m"(ebx), 13 | [ecxout] "=m"(ecx), 14 | [edxout] "=m"(edx) 15 | : 16 | : "eax", "ebx", "ecx", "edx"); 17 | 18 | #define EAX(n) ((eax & (1 << n)) ? "yes" : "no") 19 | #define EBX(n) ((ebx & (1 << n)) ? "yes" : "no") 20 | #define ECX(n) ((ecx & (1 << n)) ? "yes" : "no") 21 | #define EDX(n) ((edx & (1 << n)) ? "yes" : "no") 22 | printf("FPU: %s\n", EDX(0)); 23 | printf("MMX: %s\n", EDX(23)); 24 | printf("FXSR: %s\n", EDX(24)); 25 | printf("SSE: %s\n", EDX(25)); 26 | printf("SSE2: %s\n", EDX(26)); 27 | printf("SSE3: %s\n", ECX(0)); 28 | printf("SSSE3: %s\n", ECX(9)); 29 | printf("SSSE4.1: %s\n", ECX(19)); 30 | printf("SSSE4.2: %s\n", ECX(20)); 31 | printf("AVX: %s\n", ECX(28)); 32 | printf("POPCNT: %s\n", ECX(23)); 33 | printf("AES-NI: %s\n", ECX(25)); 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /src/userspace/debug.sh: -------------------------------------------------------------------------------- 1 | # Source this file in e.g. your shell startup (~/.bash_profile or similar) 2 | 3 | # Userspace debugging helpers 4 | # Examples: "gu userspace/helloworld", then start qemu, and run, to have debug symbols 5 | # "gub userspace/helloworld main", to set a breakpoint in main and boot normally after qemu is started 6 | 7 | gu() { 8 | if [[ "$#" -ne 1 ]]; then 9 | echo "Usage: gu " 10 | return 11 | fi 12 | 13 | i586-pc-exscapeos-gdb -tui --eval-command "set confirm off" \ 14 | --eval-command "add-symbol-file $1 $(/usr/local/cross/bin/i586-pc-exscapeos-objdump -x $1| perl -ne '/start address (0x\d{8})/ && print $1')" \ 15 | --eval-command "set confirm on" \ 16 | --eval-command "continue" 17 | } 18 | 19 | gub() { 20 | if [[ "$#" -ne 2 ]]; then 21 | echo "Usage: gub " 22 | return 23 | fi 24 | 25 | i586-pc-exscapeos-gdb -tui --eval-command "set confirm off" \ 26 | --eval-command "add-symbol-file $1 $(/usr/local/cross/bin/i586-pc-exscapeos-objdump -x $1 | perl -ne '/start address (0x\d{8})/ && print $1')" \ 27 | --eval-command "set confirm on" \ 28 | --eval-command "break $2" \ 29 | --eval-command "continue" 30 | } 31 | -------------------------------------------------------------------------------- /src/userspace/echo/Makefile: -------------------------------------------------------------------------------- 1 | ../.user_Makefile -------------------------------------------------------------------------------- /src/userspace/echo/echo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char **argv) { 8 | bool newline = true; 9 | 10 | argc--; 11 | argv++; 12 | 13 | if (argc >= 1 && strcmp(argv[0], "-n") == 0) { 14 | newline = false; 15 | argc--; 16 | argv++; 17 | } 18 | 19 | for (int i = 0; i < argc; i++) { 20 | printf("%s", argv[i]); 21 | if (i < argc - 1) 22 | printf(" "); 23 | } 24 | 25 | if (newline) 26 | printf("\n"); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /src/userspace/eshell/Makefile: -------------------------------------------------------------------------------- 1 | ../.user_Makefile -------------------------------------------------------------------------------- /src/userspace/eshell/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // Replaces the first occurance of old with new in buf. 6 | // size is the size of the buffer, in bytes. 7 | void str_replace(char *buf, const char *old, const char *new, int size) { 8 | char *start = strstr(buf, old); 9 | if (start == NULL) 10 | return; 11 | 12 | ssize_t buf_len = (ssize_t)strlen(buf); 13 | ssize_t old_len = (ssize_t)strlen(old); 14 | ssize_t new_len = (ssize_t)strlen(new); 15 | 16 | if (buf_len + (new_len - old_len) > size - 1) { 17 | // This won't fit! 18 | return; 19 | } 20 | 21 | char *end = start + old_len; 22 | char *ending = malloc((buf + buf_len) - end + 1); 23 | strlcpy(ending, end, (buf + buf_len) - end + 1); 24 | 25 | // OK, we have the stuff after the variable stored away; now we're free 26 | // to destroy the buffer contents after /end/ with no ill consequences. 27 | 28 | // Do the replace 29 | int t = (size - (start - buf)); 30 | strlcpy(start, new, t); 31 | // Copy back the ending 32 | strlcat(start + new_len, ending, (size - new_len)); 33 | 34 | free(ending); 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/userspace/grep/Makefile: -------------------------------------------------------------------------------- 1 | ../.user_Makefile -------------------------------------------------------------------------------- /src/userspace/grep/grep.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | void print_usage(char **argv) { 14 | fprintf(stderr, "Usage: %s [options] [filename(s)]\n", argv[0]); 15 | fprintf(stderr, "Options:\n"); 16 | fprintf(stderr, " -i for case insensitive search\n"); 17 | fprintf(stderr, " -c to print number of matches only\n"); 18 | fprintf(stderr, " -v to invert matching (print/count non-matching lines)\n"); 19 | fprintf(stderr, "Leave filename empty to search stdin, or do grep -- -.\n"); 20 | fprintf(stderr, "Examples:\n"); 21 | fprintf(stderr, "%s string file1 file2\n", argv[0]); 22 | fprintf(stderr, "cat file | %s string\n", argv[0]); 23 | fprintf(stderr, "cat file1 | %s string - file2\n", argv[0]); 24 | } 25 | 26 | int opt_case = 0, opt_count = 0, opt_invert = 0; 27 | 28 | int main(int argc, char **argv) { 29 | bool error = false; 30 | bool match = false; 31 | int c; 32 | while ((c = getopt(argc, argv, "cihv")) != -1) { 33 | switch (c) { 34 | case 'h': 35 | print_usage(argv); 36 | exit(0); 37 | break; 38 | case 'i': 39 | opt_case = 1; 40 | break; 41 | case 'c': 42 | opt_count = 1; 43 | break; 44 | case 'v': 45 | opt_invert = 1; 46 | break; 47 | case 0: 48 | fprintf(stderr, "getopt returned 0; if you used - for stdin, try -- - instead\n"); 49 | exit(1); 50 | break; 51 | default: 52 | printf("grep: unknown option %c\n", c); 53 | exit(1); 54 | break; 55 | } 56 | } 57 | argc -= optind; 58 | argv += optind; 59 | 60 | if (argc < 1) { 61 | print_usage(argv - optind); 62 | exit(1); 63 | } 64 | 65 | char *needle = argv[0]; 66 | argv++; 67 | argc--; 68 | 69 | for (int i = 0; i < argc || i == 0; i++) { 70 | const char *filename = NULL; 71 | int fd; 72 | 73 | if ((argc == 0 && i == 0) || (argc > i && !strcmp(argv[i], "-"))) { 74 | // Use stdin 75 | filename = "(stdin)"; 76 | fd = fileno(stdin); 77 | } 78 | else { 79 | filename = argv[i]; 80 | fd = open(filename, O_RDONLY); 81 | if (fd < 0) { 82 | fprintf(stderr, "grep: %s: %s\n", filename, strerror(errno)); 83 | error = true; 84 | continue; 85 | } 86 | struct stat st; 87 | if (fstat(fd, &st) != 0) { 88 | fprintf(stderr, "grep: %s: %s\n", filename, strerror(errno)); 89 | error = true; 90 | continue; 91 | } 92 | if (S_ISDIR(st.st_mode)) { 93 | fprintf(stderr, "grep: %s: %s\n", filename, strerror(EISDIR)); 94 | error = true; 95 | continue; 96 | } 97 | } 98 | 99 | char *p; 100 | char line[4096] = {0}; 101 | int matches = 0; // matches for this file only 102 | FILE *f = fdopen(fd, "r"); 103 | if (!f) { 104 | fprintf(stderr, "grep: fdopen: %s\n", strerror(errno)); 105 | error = true; 106 | continue; 107 | } 108 | 109 | while ((p = fgets(line, 4096, f)) != NULL) { 110 | bool result = opt_case ? strcasestr(line, needle) : strstr(line, needle); 111 | if (opt_invert) 112 | result = !result; 113 | 114 | if (result) { 115 | match = true; 116 | matches++; 117 | if (!opt_count) { 118 | if (argc > 1) 119 | printf("%s:", filename); 120 | printf("%s", line); 121 | fflush(stdout); 122 | } 123 | } 124 | } 125 | if (opt_count) { 126 | if (argc > 1) 127 | printf("%s:", filename); 128 | printf("%d\n", matches); 129 | } 130 | } 131 | 132 | if (error) 133 | return 2; 134 | else 135 | return (match) ? 0 : 1; 136 | } 137 | -------------------------------------------------------------------------------- /src/userspace/guess/Makefile: -------------------------------------------------------------------------------- 1 | ../.user_Makefile -------------------------------------------------------------------------------- /src/userspace/guess/guess.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MAX_GUESSES 10 6 | #define MAX_NUM 10000 7 | 8 | int main(int argc, char **argv) { 9 | srand(time(NULL)); 10 | int num = 1 + (rand() % MAX_NUM); 11 | int guess = -1; 12 | int num_guesses = 0; 13 | 14 | char buf[16] = {0}; 15 | 16 | while (guess != num) { 17 | printf("%d guesses remaining\n", MAX_GUESSES - num_guesses); 18 | printf("Guess the number, from user mode (1-%d): ", MAX_NUM); 19 | fflush(stdout); 20 | 21 | char *end; 22 | fgets(buf, 16, stdin); 23 | guess = strtol(buf, &end, 10); 24 | if (*end != 0 && *end != '\n') { 25 | printf("That's not a number! Try again.\n"); 26 | continue; 27 | } 28 | 29 | num_guesses++; 30 | 31 | if (guess == num) { 32 | printf("You got it on guess %d!\n", num_guesses); 33 | break; 34 | } 35 | else if (num_guesses >= MAX_GUESSES) { 36 | printf("Sorry, you lost! The number was %d.\n", num); 37 | return 0; 38 | } 39 | else if (guess > num) { 40 | puts("Nope. Try lower."); 41 | } 42 | else if (guess < num) { 43 | puts("Nope. Try higher."); 44 | } 45 | } 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /src/userspace/ls/Makefile: -------------------------------------------------------------------------------- 1 | ../.user_Makefile -------------------------------------------------------------------------------- /src/userspace/md5/Makefile: -------------------------------------------------------------------------------- 1 | ../.user_Makefile -------------------------------------------------------------------------------- /src/userspace/md5/md5.h: -------------------------------------------------------------------------------- 1 | #ifndef MD5_H 2 | #define MD5_H 3 | 4 | #include 5 | #include 6 | #undef HIGHFIRST 7 | 8 | struct MD5Context { 9 | uint32 buf[4]; 10 | uint32 bits[2]; 11 | unsigned char in[64]; 12 | }; 13 | 14 | void MD5Init(struct MD5Context *ctx); 15 | void MD5Update(struct MD5Context *ctx, unsigned char *buf, unsigned len); 16 | void MD5Final(unsigned char digest[16], struct MD5Context *ctx); 17 | void MD5Transform(uint32 buf[4], uint32 in[16]); 18 | 19 | /* 20 | * This is needed to make RSAREF happy on some MS-DOS compilers. 21 | */ 22 | typedef struct MD5Context MD5_CTX; 23 | 24 | /* Define CHECK_HARDWARE_PROPERTIES to have main.c verify 25 | byte order and uint32 settings. */ 26 | #define CHECK_HARDWARE_PROPERTIES 27 | 28 | #endif /* !MD5_H */ 29 | -------------------------------------------------------------------------------- /src/userspace/tests/.test_Makefile: -------------------------------------------------------------------------------- 1 | WARNINGS := -Wall -Wextra -Wshadow -Wpointer-arith -Wcast-align \ 2 | -Wwrite-strings -Wredundant-decls -Wnested-externs -Winline \ 3 | -Wuninitialized -Wstrict-prototypes \ 4 | -Wno-unused-parameter -Wno-cast-align -Werror 5 | 6 | CC = i586-pc-exscapeos-gcc 7 | CFLAGS := -O0 -std=gnu99 -march=i586 $(WARNINGS) -ggdb3 -static -D_EXSCAPEOS 8 | LD = i586-pc-exscapeos-gcc 9 | LDFLAGS := -lc 10 | 11 | SRCFILES := $(shell find . -type f -name '*.c') 12 | OBJFILES := $(patsubst %.c,%.o,$(SRCFILES)) 13 | DEPFILES := $(patsubst %.c,%.d,$(SRCFILES)) 14 | 15 | OUTNAME := $(shell basename "`pwd`") 16 | 17 | all: $(OBJFILES) 18 | @$(LD) $(LDFLAGS) -o $(OUTNAME) $(OBJFILES) 19 | @mv -f $(OUTNAME) ../../../../initrd/bin/tests 20 | 21 | clean: 22 | -$(RM) $(wildcard $(OBJFILES) $(DEPFILES) ../../../../initrd/bin/tests/$(OUTNAME)) 23 | 24 | -include $(DEPFILES) 25 | 26 | %.o: %.c Makefile 27 | @$(CC) $(CFLAGS) -MMD -MP -c $< -o $@ 28 | -------------------------------------------------------------------------------- /src/userspace/tests/arg/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/arg/arg.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) { 4 | for (int i=0; i < argc; i++) { 5 | printf("argv[%d] = %s\n", i, argv[i]); 6 | } 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /src/userspace/tests/daemon/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/daemon/daemon.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) { 6 | pid_t pid; 7 | pid = fork(); 8 | if (pid < 0) { 9 | printf("fork error!\n"); 10 | exit(1); 11 | } 12 | else if (pid > 0) { 13 | printf("fork successful; parent exiting\n"); 14 | exit(0); 15 | } 16 | 17 | printf("in child: parent is long gone. child pid = %d\n", getpid()); 18 | printf("child: sleeping 5 seconds...\n"); 19 | sleep(5); 20 | printf("child: returning 0\n"); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /src/userspace/tests/dirtest/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/dirtest/dirtest.c: -------------------------------------------------------------------------------- 1 | #include /* Defines DT_* constants */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | extern int getdents(int, void *, int); 9 | 10 | #define handle_error(msg) \ 11 | do { perror(msg); exit(EXIT_FAILURE); } while (0) 12 | 13 | #define BUF_SIZE 1024 14 | 15 | int 16 | main(int argc, char *argv[]) 17 | { 18 | int fd, nread; 19 | char buf[BUF_SIZE]; 20 | struct dirent *d; 21 | int bpos; 22 | char d_type; 23 | 24 | fd = open(argc > 1 ? argv[1] : ".", O_RDONLY); 25 | if (fd == -1) 26 | handle_error("open"); 27 | 28 | for ( ; ; ) { 29 | nread = getdents(fd, buf, BUF_SIZE); 30 | if (nread == -1) 31 | handle_error("getdents"); 32 | 33 | if (nread == 0) 34 | break; 35 | printf("--------------- nread=%d ---------------\n", nread); 36 | printf("i-node# file type d_reclen d_namlen d_name\n"); 37 | for (bpos = 0; bpos < nread;) { 38 | d = (struct dirent *) (buf + bpos); 39 | printf("%8d ", (int)d->d_ino); 40 | d_type = d->d_type; 41 | printf("%-10s ", (d_type == DT_REG) ? "regular" : 42 | (d_type == DT_DIR) ? "directory" : 43 | (d_type == DT_FIFO) ? "FIFO" : 44 | (d_type == DT_SOCK) ? "socket" : 45 | (d_type == DT_LNK) ? "symlink" : 46 | (d_type == DT_BLK) ? "block dev" : 47 | (d_type == DT_CHR) ? "char dev" : "???"); 48 | printf("%4d %10d %s\n", d->d_reclen, 49 | (int) d->d_namlen, d->d_name); 50 | bpos += d->d_reclen; 51 | } 52 | } 53 | 54 | exit(EXIT_SUCCESS); 55 | } 56 | -------------------------------------------------------------------------------- /src/userspace/tests/env_test/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/env_test/env_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) { 6 | const char *a = "Hello, world!"; 7 | setenv("VAR", a, 1); 8 | 9 | printf("getenv(\"VAR\") = %s\n", getenv("VAR")); 10 | setenv("VAR", "Yoooooooooooo", 1); 11 | printf("getenv(\"VAR\") = %s\n", getenv("VAR")); 12 | setenv("VAR", "Nice", 1); 13 | printf("getenv(\"VAR\") = %s\n", getenv("VAR")); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /src/userspace/tests/execve/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/execve/execve.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char **argv) { 9 | 10 | int pid = fork(); 11 | if (pid == 0) { 12 | printf("In child; will execve now\n"); 13 | setenv("ENVTEST", "Hello, world!", 1); 14 | int r = execve("/initrd/execve_child", argv, NULL); 15 | printf("execve returned!! return value: %d, errno = %d (%s)\n", r, errno, strerror(errno)); 16 | _exit(0); 17 | } 18 | else if (pid > 0) { 19 | printf("In parent: waiting for child %d...\n", pid); 20 | int status; 21 | int r = wait(&status); 22 | printf("Parent: wait returned %d; status = %04x\n", r, status); 23 | printf("Exiting from parent.\n"); 24 | exit(0); 25 | } 26 | 27 | fprintf(stderr, "fork failed!\n"); 28 | 29 | return 1; 30 | } 31 | -------------------------------------------------------------------------------- /src/userspace/tests/execve_child/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/execve_child/execve_child.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) { 6 | printf("in execve \"child\", attempting getenv...\n"); 7 | const char *e = getenv("ENVTEST"); 8 | if (e == NULL) { 9 | printf("getenv(\"ENVTEST\") == NULL!\n"); 10 | } 11 | else if (*e == 0) { 12 | printf("getenv returned empty string\n"); 13 | } 14 | else 15 | printf("getenv returned: %s\n", e); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /src/userspace/tests/fenv/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/fenv/fenv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) { 6 | setenv("ENVTEST", "It works!", 1); 7 | int r = fork(); 8 | 9 | printf("%s: getenv: %s\n", r == 0 ? "child" : "parent", getenv("ENVTEST")); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /src/userspace/tests/fork/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/fork/fork.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char **argv) { 9 | 10 | int val = 1; 11 | int ret = 0; 12 | 13 | ret = fork(); 14 | if (ret == -1) { 15 | printf("fork failed with error %d: %s\n", errno, strerror(errno)); 16 | return 1; 17 | } 18 | else if (ret == 0) { 19 | printf("fork(): in child! pid = %d, val = %d\n", getpid(), val); 20 | val += 10; 21 | printf("child: val = %d after increment by 10\n", val); 22 | printf("child: getppid = %d\n", getppid()); 23 | sleep(3); 24 | printf("child: getppid = %d\n", getppid()); 25 | } 26 | else { 27 | printf("fork(): in parent; child has pid %d, val = %d\n", ret, val); 28 | val += 20; 29 | printf("parent: val = %d after increment by 20\n", val); 30 | //int st; 31 | sleep(1); 32 | printf("parent: exiting without waiting!\n"); 33 | exit(0); 34 | //printf("parent: waiting...\n"); 35 | //int p = wait(&st); 36 | //printf("parent: wait returned (child %d exited): status = %d (%04x)\n", p, st, st); 37 | } 38 | 39 | printf("Exiting from %s\n", ret == 0 ? "child" : "parent"); 40 | 41 | return (ret == 0 ? 8 : 0); // child returns nonzero for testing 42 | } 43 | -------------------------------------------------------------------------------- /src/userspace/tests/fork2/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/fork2/fork2.c: -------------------------------------------------------------------------------- 1 | #include /* printf, stderr, fprintf */ 2 | #include /* pid_t */ 3 | #include /* _exit, fork */ 4 | #include /* exit */ 5 | #include /* errno */ 6 | 7 | int main(void) 8 | { 9 | pid_t pid; 10 | 11 | /* Output from both the child and the parent process 12 | * will be written to the standard output, 13 | * as they both run at the same time. 14 | */ 15 | pid = fork(); 16 | if (pid == -1) 17 | { 18 | /* Error: 19 | * When fork() returns -1, an error happened 20 | * (for example, number of processes reached the limit). 21 | */ 22 | fprintf(stderr, "can't fork, error %d\n", errno); 23 | exit(EXIT_FAILURE); 24 | } 25 | 26 | if (pid == 0) 27 | { 28 | /* Child process: 29 | * When fork() returns 0, we are in 30 | * the child process. 31 | */ 32 | int j; 33 | for (j = 0; j < 10; j++) 34 | { 35 | printf("child: %d\n", j); 36 | usleep(200000); 37 | } 38 | sleep(2); 39 | printf("child: exiting\n"); 40 | _exit(0); /* Note that we do not use exit() */ 41 | } 42 | else 43 | { 44 | 45 | /* When fork() returns a positive number, we are in the parent process 46 | * (the fork return value is the PID of the newly created child process) 47 | * Again we count up to ten. 48 | */ 49 | int i; 50 | for (i = 0; i < 10; i++) 51 | { 52 | printf("parent: %d\n", i); 53 | usleep(120000); 54 | } 55 | printf("parent: exiting\n"); 56 | exit(0); 57 | } 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /src/userspace/tests/getopt_test/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/getopt_test/getopt_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) { 6 | for (int i=0; i < argc; i++) { 7 | printf("argv[%d] = %s\n", i, argv[i]); 8 | } 9 | int c; 10 | while ((c = getopt(argc, argv, "abc")) != -1) { 11 | switch (c) { 12 | case 'a': 13 | printf("option a\n"); 14 | break; 15 | case 'b': 16 | printf("option b\n"); 17 | break; 18 | case 'c': 19 | printf("option c\n"); 20 | break; 21 | default: 22 | printf("valid options are: -a, -b and -c\n"); 23 | exit(1); 24 | break; 25 | } 26 | } 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /src/userspace/tests/growstack/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/growstack/growstack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Simple program to test on-demand (on #PF) stack growing 5 | 6 | int main(int argc, char **argv) { 7 | unsigned int max; 8 | if (argc != 2 || (max = 1024*atoi(argv[1])) == 0) { 9 | fprintf(stderr, "Usage: %s \n", argv[0]); 10 | return 1; 11 | } 12 | 13 | char stack; 14 | char *p = &stack - 4096; /* move away from the part of the stack that's populated */ 15 | 16 | unsigned int sum = 0; /* should remain 0, or memory wasn't zeroed properly */ 17 | while (p >= &stack - max) { sum += *p--; } 18 | printf("Done, %d kbytes allocated/read\n", max/1024); 19 | printf("Sum = %u\n", sum); 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /src/userspace/tests/lseek/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/lseek/lseek.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | //#define PATH "/Volumes/EXSCAPEOS 1/test.txt" 7 | #define PATH "/test.txt" 8 | 9 | int main(int argc, char **argv) { 10 | int fd = open(PATH, O_RDONLY); 11 | if (fd < 0) { 12 | fprintf(stderr, "Unable to open file!\n"); 13 | return -1; 14 | } 15 | 16 | // Ugly, but it works. Tested by verifying 17 | // that the same stuff is read into buf under 18 | // exscapeOS and OS X/Linux. 19 | 20 | char buf[128] = {0}; 21 | read(fd, buf, 10); 22 | lseek(fd, 20, SEEK_SET); 23 | read(fd, buf + 10, 6); 24 | lseek(fd, -6, SEEK_CUR); 25 | read(fd, buf + 16, 4); 26 | lseek(fd, -7, SEEK_END); 27 | read(fd, buf + 20, 3); 28 | 29 | lseek(fd, -30, SEEK_CUR); 30 | read(fd, buf + 23, 7); 31 | lseek(fd, 12000, SEEK_SET); 32 | read(fd, buf + 30, 5); 33 | lseek(fd, -18, SEEK_END); 34 | read(fd, buf + 35, 6); 35 | lseek(fd, -4500, SEEK_CUR); 36 | read(fd, buf + 41, 5); 37 | 38 | // Make the whitespace more readable 39 | for (size_t i=0; i < strlen(buf); i++) { 40 | if (buf[i] == ' ') 41 | buf[i] = '_'; 42 | else if(buf[i] == '\n') 43 | buf[i] = '\\'; 44 | else if(buf[i] < ' ') 45 | buf[i] = '?'; 46 | } 47 | 48 | write(1, buf, strlen(buf)); 49 | 50 | write(1, "\nOne: ", 6); 51 | memset(buf, 0, 128); 52 | read(0, buf, 128); 53 | 54 | char buf2[128] = {0}; 55 | write(1, "Two: ", 5); 56 | memset(buf2, 0, 128); 57 | read(0, buf2, 128); 58 | 59 | write(1, "You entered: ", 13); 60 | write(1, buf, strlen(buf) - 1); // strip \n 61 | write(1, " ", 1); 62 | write(1, buf2, strlen(buf2)); // don't strip 63 | 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /src/userspace/tests/misc_test/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/misc_test/misc_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char **argv) { 10 | 11 | FILE *f = fopen("/initrd/initrd_test.txt", "r"); 12 | if (!f) { 13 | perror("fopen"); 14 | exit(1); 15 | } 16 | 17 | printf("opened file, forking...\n"); 18 | 19 | pid_t pid = fork(); 20 | if (pid == 0) { 21 | // Child 22 | printf("Child: reading part of the file...\n"); 23 | } 24 | else if (pid > 0) { 25 | // Parent 26 | printf("Parent: doing my part\n"); 27 | } 28 | char buf[9] = {0}; 29 | fread(buf, 1, 8, f); 30 | printf("%s", buf); 31 | fflush(stdout); 32 | 33 | exit(0); 34 | 35 | return 0; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/userspace/tests/misc_test/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exscape/exscapeOS/babd32d00b47cfbab1bd5b224e797cafd4189cf8/src/userspace/tests/misc_test/test -------------------------------------------------------------------------------- /src/userspace/tests/pipe_test/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/pipe_test/pipe_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char **argv) { 9 | #define BSIZE 100 10 | 11 | char buf[BSIZE] = {0}; 12 | int fildes[2]; 13 | ssize_t nbytes; 14 | int status; 15 | 16 | status = pipe(fildes); 17 | if (status == -1 ) { 18 | /* an error occurred */ 19 | fprintf(stderr, "pipe: error %d (%s)\n", errno, strerror(errno)); 20 | exit(1); 21 | } 22 | 23 | switch (fork()) { 24 | case -1: /* Handle error */ 25 | break; 26 | 27 | case 0: /* Child - reads from pipe */ 28 | close(fildes[1]); /* Write end is unused */ 29 | nbytes = read(fildes[0], buf, BSIZE); /* Get data from pipe */ 30 | if (nbytes == -1) { 31 | perror("read"); 32 | exit(EXIT_FAILURE); 33 | } 34 | close(fildes[0]); /* Finished with pipe */ 35 | printf("read from pipe: %s", buf); 36 | assert(read(fildes[0], buf, BSIZE) <= 0); 37 | exit(EXIT_SUCCESS); 38 | break; 39 | 40 | default: /* Parent - writes to pipe */ 41 | close(fildes[0]); /* Read end is unused */ 42 | nbytes = write(fildes[1], "Hello world\n", 12); /* Write data on pipe */ 43 | if (nbytes == -1) { 44 | perror("parent: write"); 45 | exit(EXIT_FAILURE); 46 | } 47 | close(fildes[1]); /* Child will see EOF */ 48 | exit(EXIT_SUCCESS); 49 | break; 50 | } 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /src/userspace/tests/pipe_test2/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/pipe_test2/pipe_test2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | struct pipe { 10 | int read; 11 | int write; 12 | }; 13 | 14 | struct command { 15 | const char **cmd; 16 | struct pipe *in; 17 | struct pipe *out; 18 | }; 19 | 20 | int main(int argc, char **argv) { 21 | 22 | #define MAX_PIPES 64 23 | struct pipe pipes[MAX_PIPES]; 24 | memset(&pipes, 0, MAX_PIPES * sizeof(struct pipe)); 25 | 26 | /* 27 | const char *arg1[] = { "/bin/cat", "/fat/numbers", NULL }; 28 | const char *arg2[] = { "/bin/grep", "5", NULL }; 29 | const char *arg3[] = { "/bin/grep", "0", NULL }; 30 | struct command cmd1 = { arg1, NULL, NULL }; 31 | struct command cmd2 = { arg2, NULL, NULL }; 32 | struct command cmd3 = { arg3, NULL, NULL }; 33 | 34 | struct command *cmds[] = { &cmd1, &cmd2, &cmd3, NULL }; 35 | 36 | int num_cmds = 3; 37 | */ 38 | 39 | const char *arg1[] = { "/bin/cat", "/fat/mm.mp3", NULL }; 40 | const char *arg2[] = { "/bin/md5", NULL }; 41 | struct command cmd1 = { arg1, NULL, NULL }; 42 | struct command cmd2 = { arg2, NULL, NULL }; 43 | 44 | struct command *cmds[] = { &cmd1, &cmd2, NULL }; 45 | 46 | int num_cmds = 2; 47 | 48 | for (int i = 0; i < num_cmds - 1; i++) { 49 | pipe((int *)&pipes[i]); // TODO: error handling 50 | printf("pipe() created FDs %d (read) and %d (write)\n", pipes[i].read, pipes[i].write); 51 | assert(cmds[i]->cmd != NULL); 52 | assert(cmds[i+1]->cmd != NULL); 53 | 54 | printf("assigning pipe %d (r)/%d (w) as output for %s\n", pipes[i].read, pipes[i].write, cmds[i]->cmd[0]); 55 | cmds[i ]->out = &pipes[i]; 56 | printf("assigning pipe %d (r)/%d (w) as input for %s\n", pipes[i].read, pipes[i].write, cmds[i+1]->cmd[0]); 57 | cmds[i+1]->in = &pipes[i]; 58 | } 59 | fflush(stdout); 60 | 61 | for (int i = 0; i < num_cmds; i++) { 62 | fprintf(stderr, "forking, i = %d\n", i); 63 | int pid = fork(); 64 | if (pid > 0) { 65 | // Parent 66 | 67 | if (num_cmds > 1) { 68 | // Close pipe FDs in the parent 69 | 70 | if (i == 0) { 71 | assert(!close(pipes[i].write)); 72 | } 73 | else if (i > 0 && i < num_cmds - 1) { 74 | assert(!close(pipes[i-1].read)); 75 | assert(!close(pipes[i].write)); 76 | } 77 | else if (i == num_cmds - 1) { 78 | assert(!close(pipes[i].read)); 79 | } 80 | } 81 | } 82 | else { 83 | // Child 84 | fprintf(stderr, "child cmds[%d], pid %d (%s) starting up...\n", i, getpid(), cmds[i]->cmd[0]); 85 | if (cmds[i]->in != NULL) { 86 | // Change stdin 87 | fprintf(stderr, "child cmds[%d], pid %d: redirecting %d to stdin and closing both pipe fds\n", i, getpid(), cmds[i]->in->read); 88 | int in_fd = cmds[i]->in->read; 89 | close(cmds[i]->in->write); 90 | int r; 91 | if ((r = dup2(in_fd, fileno(stdin))) != fileno(stdin)) { 92 | fprintf(stderr, "cmds[%d], pid %d: dup2(%d, stdin) failed! errno = %d (%s)\n", i, getpid(), in_fd, errno, strerror(errno)); 93 | } 94 | close(in_fd); 95 | } 96 | if (cmds[i]->out != NULL) { 97 | // Change stdout 98 | fprintf(stderr, "child cmds[%d], pid %d: redirecting %d to stdout and closing both pipe fds\n", i, getpid(), cmds[i]->out->write); 99 | int out_fd = cmds[i]->out->write; 100 | close(cmds[i]->out->read); 101 | int r; 102 | if ((r = dup2(out_fd, fileno(stdout))) != fileno(stdout)) { 103 | fprintf(stderr, "cmds[%d], pid %d: dup2 to stdout failed! errno = %d (%s)\n", i, getpid(), errno, strerror(errno)); 104 | } 105 | close(out_fd); 106 | } 107 | 108 | fprintf(stderr, "child cmds[%d]: executing %s\n", i, cmds[i]->cmd[0]); 109 | 110 | execve(cmds[i]->cmd[0], (char **)cmds[i]->cmd, NULL); 111 | fprintf(stderr, "EXECVE FAILED for cmd %d; errno = %d (%s)\n", i, errno, strerror(errno)); 112 | abort(); 113 | } 114 | } 115 | 116 | int status; 117 | int r; 118 | printf("parent: waiting for next child to exit...\n"); 119 | while ((r = waitpid(-1, &status, 0)) != -1) { 120 | printf("waitpid returned %d; exit status = 0x%04x\n", r, status); 121 | } 122 | 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /src/userspace/tests/pipe_test3/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/pipe_test3/pipe_test3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // 10 | // Unfinished stuff for adding pipe support to the shell 11 | // 12 | 13 | struct pipe { 14 | int read; 15 | int write; 16 | }; 17 | 18 | struct command { 19 | const char **cmd; 20 | struct pipe *in; 21 | struct pipe *out; 22 | }; 23 | 24 | int main(int argc, char **argv) { 25 | 26 | #define MAX_PIPES 64 27 | struct pipe pipes[MAX_PIPES]; 28 | memset(&pipes, 0, MAX_PIPES * sizeof(struct pipe)); 29 | 30 | const char *arg1[] = { "/bin/cat", "fpu.lua", NULL }; 31 | const char *arg2[] = { "/bin/grep", "pri", NULL }; 32 | const char *arg3[] = { "/bin/grep", "nt (", NULL }; 33 | struct command cmd1 = { arg1, NULL, NULL }; 34 | struct command cmd2 = { arg2, NULL, NULL }; 35 | struct command cmd3 = { arg3, NULL, NULL }; 36 | 37 | struct command *cmds[] = { &cmd1, &cmd2, &cmd3, NULL }; 38 | 39 | int num_cmds = 3; 40 | 41 | for (int i = 0; i < num_cmds - 1; i++) { 42 | pipe((int *)&pipes[i]); // TODO: error handling 43 | printf("pipe() created FDs %d (read) and %d (write)\n", pipes[i].read, pipes[i].write); 44 | assert(cmds[i]->cmd != NULL); 45 | assert(cmds[i+1]->cmd != NULL); 46 | 47 | printf("assigning pipe %d (r)/%d (w) as output for %s\n", pipes[i].read, pipes[i].write, cmds[i]->cmd[0]); 48 | cmds[i ]->out = &pipes[i]; 49 | printf("assigning pipe %d (r)/%d (w) as input for %s\n", pipes[i].read, pipes[i].write, cmds[i+1]->cmd[0]); 50 | cmds[i+1]->in = &pipes[i]; 51 | } 52 | fflush(stdout); 53 | 54 | for (int i = 0; i < num_cmds; i++) { 55 | fprintf(stderr, "forking, i = %d\n", i); 56 | int pid = fork(); 57 | if (pid > 0) { 58 | // Parent 59 | 60 | if (num_cmds > 1) { 61 | // Close pipe FDs in the parent 62 | 63 | if (i == 0) { 64 | assert(!close(pipes[i].write)); 65 | } 66 | else if (i > 0 && i < num_cmds - 1) { 67 | assert(!close(pipes[i-1].read)); 68 | assert(!close(pipes[i].write)); 69 | } 70 | else if (i == num_cmds - 1) { 71 | assert(!close(pipes[i].read)); 72 | } 73 | } 74 | } 75 | else { 76 | // Child 77 | fprintf(stderr, "child cmds[%d], pid %d (%s) starting up...\n", i, getpid(), cmds[i]->cmd[0]); 78 | if (cmds[i]->in != NULL) { 79 | // Change stdin 80 | fprintf(stderr, "child cmds[%d], pid %d: redirecting %d to stdin and closing both pipe fds\n", i, getpid(), cmds[i]->in->read); 81 | int in_fd = cmds[i]->in->read; 82 | close(cmds[i]->in->write); 83 | int r; 84 | if ((r = dup2(in_fd, fileno(stdin))) != fileno(stdin)) { 85 | fprintf(stderr, "cmds[%d], pid %d: dup2(%d, stdin) failed! errno = %d (%s)\n", i, getpid(), in_fd, errno, strerror(errno)); 86 | } 87 | close(in_fd); 88 | } 89 | if (cmds[i]->out != NULL) { 90 | // Change stdout 91 | fprintf(stderr, "child cmds[%d], pid %d: redirecting %d to stdout and closing both pipe fds\n", i, getpid(), cmds[i]->out->write); 92 | int out_fd = cmds[i]->out->write; 93 | close(cmds[i]->out->read); 94 | int r; 95 | if ((r = dup2(out_fd, fileno(stdout))) != fileno(stdout)) { 96 | fprintf(stderr, "cmds[%d], pid %d: dup2 to stdout failed! errno = %d (%s)\n", i, getpid(), errno, strerror(errno)); 97 | } 98 | close(out_fd); 99 | } 100 | 101 | fprintf(stderr, "child cmds[%d]: executing %s\n", i, cmds[i]->cmd[0]); 102 | 103 | execve(cmds[i]->cmd[0], (char **)cmds[i]->cmd, NULL); 104 | fprintf(stderr, "EXECVE FAILED for cmd %d; errno = %d (%s)\n", i, errno, strerror(errno)); 105 | abort(); 106 | } 107 | } 108 | 109 | int status; 110 | int r; 111 | printf("parent: waiting for next child to exit...\n"); 112 | // while ((r = waitpid(-1, &status, 0)) != -1) { 113 | while ((r = wait(&status)) != -1) { 114 | printf("waitpid returned %d; exit status = 0x%04x\n", r, status); 115 | } 116 | 117 | return 0; 118 | } 119 | -------------------------------------------------------------------------------- /src/userspace/tests/symlink/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/waitpid/Makefile: -------------------------------------------------------------------------------- 1 | ../.test_Makefile -------------------------------------------------------------------------------- /src/userspace/tests/waitpid/waitpid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char **argv) { 9 | int pid = fork(); 10 | if (pid == 0) { 11 | // Child 12 | printf("in child, pid = %d, ppid = %d\n", getpid(), getppid()); 13 | sleep(2); 14 | } 15 | else if (pid > 0) { 16 | // Parent 17 | printf("in parent, pid = %d, child pid = %d\n", getpid(), pid); 18 | int status; 19 | int ret; 20 | do { ret = waitpid(pid, &status, WNOHANG); printf("."); fflush(stdout);} while (ret == 0); 21 | if (ret == -1) { 22 | printf("waitpid failed: errno = %d (%s)\n", errno, strerror(errno)); 23 | } 24 | printf("waitpid returned %d, status = %04x\n", ret, status); 25 | } 26 | else { 27 | fprintf(stderr, "fork() failed!\n"); 28 | exit(1); 29 | } 30 | 31 | printf("exiting from %s\n", pid == 0 ? "child" : "parent"); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /toolchain/build_newlib_only.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | pushd $(dirname $0) > /dev/null 4 | P=$(pwd) 5 | popd >/dev/null 6 | 7 | export NEWLIB_ONLY=1 8 | bash -x $P/build.sh 9 | unset NEWLIB_ONLY 10 | -------------------------------------------------------------------------------- /toolchain/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo 4 | echo Removing old sources and build files... 5 | echo 6 | rm -rf binutils-2.*.* gcc-4.*.* gdb-7.*.* newlib-*.*.* build-{binutils,gcc,newlib,gdb} 7 | -------------------------------------------------------------------------------- /toolchain/patches/binutils-2.23.1-exscapeos.patch: -------------------------------------------------------------------------------- 1 | From 078db9a69a7ebea5185f6b559cf78dc3846636c2 Mon Sep 17 00:00:00 2001 2 | From: Thomas Backman 3 | Date: Thu, 13 Dec 2012 11:11:36 +0100 4 | Subject: [PATCH] First take at exscapeOS binutils mods 5 | 6 | --- 7 | bfd/config.bfd | 4 ++++ 8 | config.sub | 2 +- 9 | gas/configure.tgt | 1 + 10 | ld/Makefile.in | 3 +++ 11 | ld/configure.tgt | 1 + 12 | ld/emulparams/exscapeos_i386.sh | 15 +++++++++++++++ 13 | 6 files changed, 25 insertions(+), 1 deletions(-) 14 | create mode 100644 ld/emulparams/exscapeos_i386.sh 15 | 16 | diff --git a/bfd/config.bfd b/bfd/config.bfd 17 | index 6025f26..ab71129 100644 18 | --- a/bfd/config.bfd 19 | +++ b/bfd/config.bfd 20 | @@ -495,6 +495,10 @@ case "${targ}" in 21 | targ_defvec=bfd_elf32_i386_vec 22 | targ_selvecs=i386coff_vec 23 | ;; 24 | + i[3-7]86-*-exscapeos*) 25 | + targ_defvec=bfd_elf32_i386_vec 26 | + targ_selvecs=i386coff_vec 27 | + ;; 28 | i[3-7]86-*-solaris2*) 29 | targ_defvec=bfd_elf32_i386_sol2_vec 30 | targ_selvecs="i386coff_vec" 31 | diff --git a/config.sub b/config.sub 32 | index 59bb593..31af25b 100755 33 | --- a/config.sub 34 | +++ b/config.sub 35 | @@ -1348,7 +1348,7 @@ case $os in 36 | | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ 37 | | -sym* | -kopensolaris* \ 38 | | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ 39 | - | -aos* | -aros* \ 40 | + | -aos* | -aros* | -exscapeos* \ 41 | | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ 42 | | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ 43 | | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ 44 | diff --git a/gas/configure.tgt b/gas/configure.tgt 45 | index 9e44de0..80111df 100644 46 | --- a/gas/configure.tgt 47 | +++ b/gas/configure.tgt 48 | @@ -188,6 +188,7 @@ case ${generic_target} in 49 | i386-*-beos*) fmt=elf ;; 50 | i386-*-coff) fmt=coff ;; 51 | i386-*-elf) fmt=elf ;; 52 | + i386-*-exscapeos*) fmt=elf ;; 53 | i386-*-kaos*) fmt=elf ;; 54 | i386-*-bsd*) fmt=aout em=386bsd ;; 55 | i386-*-nacl*) fmt=elf em=nacl 56 | diff --git a/ld/Makefile.in b/ld/Makefile.in 57 | index a675d01..673cb96 100644 58 | --- a/ld/Makefile.in 59 | +++ b/ld/Makefile.in 60 | @@ -2683,6 +2683,9 @@ eelf32xtensa.c: $(srcdir)/emulparams/elf32xtensa.sh $(ELF_DEPS) \ 61 | eelf_i386.c: $(srcdir)/emulparams/elf_i386.sh \ 62 | $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} 63 | ${GENSCRIPTS} elf_i386 "$(tdir_elf_i386)" 64 | +eexscapeos_i386.c: $(srcdir)/emulparams/exscapeos_i386.sh \ 65 | + $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} 66 | + ${GENSCRIPTS} exscapeos_i386 "$(tdir_exscapeos_i386)" 67 | eelf_i386_be.c: $(srcdir)/emulparams/elf_i386_be.sh \ 68 | $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} 69 | ${GENSCRIPTS} elf_i386_be "$(tdir_elf_i386_be)" 70 | diff --git a/ld/configure.tgt b/ld/configure.tgt 71 | index 72bc5bc..a572bb8 100644 72 | --- a/ld/configure.tgt 73 | +++ b/ld/configure.tgt 74 | @@ -199,6 +199,7 @@ i[3-7]86-*-rtems*) targ_emul=elf_i386 ;; 75 | i[3-7]86-*-aros*) targ_emul=elf_i386 ;; 76 | i[3-7]86-*-rdos*) targ_emul=elf_i386 ;; 77 | i[3-7]86-*-bsd) targ_emul=i386bsd ;; 78 | +i[3-7]86-*-exscapeos*) targ_emul=exscapeos_i386 ;; 79 | i[3-7]86-*-bsd386) targ_emul=i386bsd ;; 80 | i[3-7]86-*-bsdi*) targ_emul=i386bsd ;; 81 | i[3-7]86-*-aout) targ_emul=i386aout ;; 82 | diff --git a/ld/emulparams/exscapeos_i386.sh b/ld/emulparams/exscapeos_i386.sh 83 | new file mode 100644 84 | index 0000000..76893a9 85 | --- /dev/null 86 | +++ b/ld/emulparams/exscapeos_i386.sh 87 | @@ -0,0 +1,15 @@ 88 | +. ${srcdir}/emulparams/plt_unwind.sh 89 | +SCRIPT_NAME=elf 90 | +OUTPUT_FORMAT="elf32-i386" 91 | +NO_RELA_RELOCS=yes 92 | +TEXT_START_ADDR=0x10000000 93 | +MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" 94 | +COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)" 95 | +ARCH=i386 96 | +MACHINE= 97 | +TEMPLATE_NAME=elf32 98 | +GENERATE_SHLIB_SCRIPT=yes 99 | +GENERATE_PIE_SCRIPT=yes 100 | +NO_SMALL_DATA=yes 101 | +SEPARATE_GOTPLT="SIZEOF (.got.plt) >= 12 ? 12 : 0" 102 | +IREL_IN_PLT= 103 | -- 104 | 1.7.7.4 105 | 106 | -------------------------------------------------------------------------------- /toolchain/patches/exscapeos/Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = cygnus 2 | INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS) 3 | AM_CCASFLAGS = $(INCLUDES) 4 | 5 | noinst_LIBRARIES = lib.a 6 | 7 | if MAY_SUPPLY_SYSCALLS 8 | extra_objs = $(lpfx)syscalls.o 9 | else 10 | extra_objs = 11 | endif 12 | 13 | lib_a_SOURCES = 14 | lib_a_LIBADD = $(extra_objs) 15 | EXTRA_lib_a_SOURCES = syscalls.c crt0.S 16 | lib_a_DEPENDENCIES = $(extra_objs) 17 | lib_a_CCASFLAGS = $(AM_CCASFLAGS) 18 | lib_a_CFLAGS = $(AM_CFLAGS) 19 | 20 | if MAY_SUPPLY_SYSCALLS 21 | all: crt0.o 22 | endif 23 | 24 | ACLOCAL_AMFLAGS = -I ../../.. 25 | CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host 26 | -------------------------------------------------------------------------------- /toolchain/patches/exscapeos/configure.in: -------------------------------------------------------------------------------- 1 | AC_PREREQ(2.59) 2 | AC_INIT([newlib], [NEWLIB_VERSION]) 3 | AC_CONFIG_SRCDIR([crt0.S]) 4 | AC_CONFIG_AUX_DIR(../../../..) 5 | NEWLIB_CONFIGURE(../../..) 6 | AC_CONFIG_FILES([Makefile]) 7 | AC_OUTPUT 8 | -------------------------------------------------------------------------------- /toolchain/patches/exscapeos/crt0.S: -------------------------------------------------------------------------------- 1 | .global _start 2 | .type _start STT_FUNC 3 | .extern main 4 | .extern exit 5 | .extern environ 6 | .extern _init_signal 7 | 8 | _start: 9 | 10 | # set up Newlib signals (intra-process only), until 11 | # exscapeOS supports real signals 12 | call _init_signal 13 | 14 | # push argc and argv, and set up environ 15 | movl 4(%esp), %eax # argc 16 | movl 8(%esp), %ebx # argv 17 | movl 12(%esp), %ecx # envp 18 | pushl %ecx # envp 19 | pushl %ebx # argv 20 | pushl %eax # argc 21 | mov %ecx, environ 22 | # run the program 23 | call main 24 | # clean the parameters off the stack 25 | addl $12, %esp 26 | 27 | # call exit() with the main() return value as a parameter 28 | pushl %eax 29 | call exit 30 | 31 | # this should not be reached, 32 | # but in case it is, wait forever 33 | .wait: 34 | hlt 35 | jmp .wait 36 | -------------------------------------------------------------------------------- /toolchain/patches/exscapeos/getreent.c: -------------------------------------------------------------------------------- 1 | #include <_ansi.h> 2 | #include 3 | 4 | #ifdef __getreent 5 | #undef __getreent 6 | #endif 7 | 8 | struct _reent * 9 | _DEFUN_VOID(__getreent) 10 | { 11 | // NULL is undeclared here 12 | static struct _reent *ptr = (struct _reent *)0; 13 | if (ptr == (struct _reent *)0) 14 | ptr = sys___getreent(); 15 | 16 | return ptr; 17 | } 18 | -------------------------------------------------------------------------------- /toolchain/patches/exscapeos/sys/_types.h: -------------------------------------------------------------------------------- 1 | /* ANSI C namespace clean utility typedefs */ 2 | 3 | /* This file defines various typedefs needed by the system calls that support 4 | the C library. Basically, they're just the POSIX versions with an '_' 5 | prepended. This file lives in the `sys' directory so targets can provide 6 | their own if desired (or they can put target dependant conditionals here). 7 | */ 8 | 9 | #ifndef _SYS__TYPES_H 10 | #define _SYS__TYPES_H 11 | 12 | #include 13 | #include 14 | 15 | typedef signed long long _off_t; 16 | 17 | #ifndef __dev_t_defined 18 | typedef short __dev_t; 19 | #endif 20 | 21 | #ifndef __uid_t_defined 22 | typedef unsigned short __uid_t; 23 | #endif 24 | #ifndef __gid_t_defined 25 | typedef unsigned short __gid_t; 26 | #endif 27 | 28 | #ifndef __off64_t_defined 29 | __extension__ typedef long long _off64_t; 30 | #endif 31 | 32 | /* 33 | * We need fpos_t for the following, but it doesn't have a leading "_", 34 | * so we use _fpos_t instead. 35 | */ 36 | #ifndef __fpos_t_defined 37 | typedef long _fpos_t; /* XXX must match off_t in */ 38 | /* (and must be `long' for now) */ 39 | #endif 40 | 41 | #ifdef __LARGE64_FILES 42 | #ifndef __fpos64_t_defined 43 | typedef _off64_t _fpos64_t; 44 | #endif 45 | #endif 46 | 47 | #ifndef __ssize_t_defined 48 | #if defined(__INT_MAX__) && __INT_MAX__ == 2147483647 49 | typedef int _ssize_t; 50 | #else 51 | typedef long _ssize_t; 52 | #endif 53 | #endif 54 | 55 | #define __need_wint_t 56 | #include 57 | 58 | #ifndef __mbstate_t_defined 59 | /* Conversion state information. */ 60 | typedef struct 61 | { 62 | int __count; 63 | union 64 | { 65 | wint_t __wch; 66 | unsigned char __wchb[4]; 67 | } __value; /* Value so far. */ 68 | } _mbstate_t; 69 | #endif 70 | 71 | #ifndef __flock_t_defined 72 | typedef _LOCK_RECURSIVE_T _flock_t; 73 | #endif 74 | 75 | #ifndef __iconv_t_defined 76 | /* Iconv descriptor type */ 77 | typedef void *_iconv_t; 78 | #endif 79 | 80 | #endif /* _SYS__TYPES_H */ 81 | -------------------------------------------------------------------------------- /toolchain/patches/exscapeos/sys/dirent.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_DIRENT_H 2 | #define _SYS_DIRENT_H 3 | 4 | #include 5 | 6 | #define MAXNAMLEN 256 7 | 8 | /* POSIX struct dirent */ 9 | struct dirent { 10 | uint32 d_ino; 11 | uint16 d_dev; // custom field, to allow a dirent to uniquely specify a file 12 | uint16 __pad; 13 | uint16 d_reclen; 14 | uint8 d_type; 15 | uint8 d_namlen; 16 | char d_name[MAXNAMLEN]; 17 | }; 18 | 19 | #define _DIRENT_HAVE_D_NAMLEN 20 | #define _DIRENT_HAVE_D_RECLEN 21 | #define _DIRENT_HAVE_D_TYPE 22 | 23 | // struct dirent.d_type flags 24 | enum { 25 | DT_UNKNOWN = 0, 26 | DT_FIFO = 1, 27 | DT_CHR = 2, 28 | DT_DIR = 4, 29 | DT_BLK = 6, 30 | DT_REG = 8, 31 | DT_LNK = 10, 32 | DT_SOCK = 12, 33 | DT_WHT = 14 34 | }; 35 | 36 | #ifndef _EXSCAPEOS_KERNEL 37 | typedef struct { 38 | int dd_fd; /* directory file */ 39 | int dd_loc; /* position in buffer */ 40 | int dd_seek; 41 | char *dd_buf; /* buffer */ 42 | int dd_len; /* buffer length */ 43 | int dd_size; /* amount of data in buffer */ 44 | // _LOCK_RECURSIVE_T dd_lock; 45 | } DIR; 46 | 47 | struct dirent *readdir(DIR *dirp); 48 | DIR *opendir(const char *name); 49 | int closedir(DIR *dirp); 50 | 51 | int scandir(const char *dirname, struct dirent ***namelist, int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **, const struct dirent **)); 52 | void rewinddir(DIR *dirp); 53 | void seekdir(DIR *dirp, long loc); 54 | long telldir(DIR *dirp); 55 | #endif 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /toolchain/patches/exscapeos/sys/stat.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_STAT_H 2 | #define _SYS_STAT_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include <_ansi.h> 9 | #include 10 | #include 11 | 12 | /* dj's stat defines _STAT_H_ */ 13 | #ifndef _STAT_H_ 14 | 15 | /* It is intended that the layout of this structure not change when the 16 | sizes of any of the basic types change (short, int, long) [via a compile 17 | time option]. */ 18 | 19 | struct stat 20 | { 21 | dev_t st_dev; 22 | ino_t st_ino; 23 | mode_t st_mode; 24 | nlink_t st_nlink; 25 | uid_t st_uid; 26 | gid_t st_gid; 27 | dev_t st_rdev; 28 | off_t st_size; 29 | /* SysV/sco doesn't have the rest... But Solaris, eabi does. */ 30 | time_t st_atime; 31 | long st_spare1; 32 | time_t st_mtime; 33 | long st_spare2; 34 | time_t st_ctime; 35 | long st_spare3; 36 | #define HAVE_BLKSIZE 37 | long st_blksize; 38 | long st_blocks; 39 | long st_spare4[2]; 40 | }; 41 | 42 | #define _IFMT 0170000 /* type of file */ 43 | #define _IFDIR 0040000 /* directory */ 44 | #define _IFCHR 0020000 /* character special */ 45 | #define _IFBLK 0060000 /* block special */ 46 | #define _IFREG 0100000 /* regular */ 47 | #define _IFLNK 0120000 /* symbolic link */ 48 | #define _IFSOCK 0140000 /* socket */ 49 | #define _IFIFO 0010000 /* fifo */ 50 | 51 | #define S_BLKSIZE 1024 /* size of a block */ 52 | 53 | #define S_ISUID 0004000 /* set user id on execution */ 54 | #define S_ISGID 0002000 /* set group id on execution */ 55 | #define S_ISVTX 0001000 /* save swapped text even after use */ 56 | #ifndef _POSIX_SOURCE 57 | #define S_IREAD 0000400 /* read permission, owner */ 58 | #define S_IWRITE 0000200 /* write permission, owner */ 59 | #define S_IEXEC 0000100 /* execute/search permission, owner */ 60 | #define S_ENFMT 0002000 /* enforcement-mode locking */ 61 | #endif /* !_POSIX_SOURCE */ 62 | 63 | #define S_IFMT _IFMT 64 | #define S_IFDIR _IFDIR 65 | #define S_IFCHR _IFCHR 66 | #define S_IFBLK _IFBLK 67 | #define S_IFREG _IFREG 68 | #define S_IFLNK _IFLNK 69 | #define S_IFSOCK _IFSOCK 70 | #define S_IFIFO _IFIFO 71 | 72 | #ifdef _WIN32 73 | /* The Windows header files define _S_ forms of these, so we do too 74 | for easier portability. */ 75 | #define _S_IFMT _IFMT 76 | #define _S_IFDIR _IFDIR 77 | #define _S_IFCHR _IFCHR 78 | #define _S_IFIFO _IFIFO 79 | #define _S_IFREG _IFREG 80 | #define _S_IREAD 0000400 81 | #define _S_IWRITE 0000200 82 | #define _S_IEXEC 0000100 83 | #endif 84 | 85 | #define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) 86 | #define S_IRUSR 0000400 /* read permission, owner */ 87 | #define S_IWUSR 0000200 /* write permission, owner */ 88 | #define S_IXUSR 0000100/* execute/search permission, owner */ 89 | #define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) 90 | #define S_IRGRP 0000040 /* read permission, group */ 91 | #define S_IWGRP 0000020 /* write permission, grougroup */ 92 | #define S_IXGRP 0000010/* execute/search permission, group */ 93 | #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) 94 | #define S_IROTH 0000004 /* read permission, other */ 95 | #define S_IWOTH 0000002 /* write permission, other */ 96 | #define S_IXOTH 0000001/* execute/search permission, other */ 97 | 98 | #ifndef _POSIX_SOURCE 99 | #define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO) /* 0777 */ 100 | #define ALLPERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) /* 07777 */ 101 | #define DEFFILEMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) /* 0666 */ 102 | #endif 103 | 104 | #define S_ISBLK(m) (((m)&_IFMT) == _IFBLK) 105 | #define S_ISCHR(m) (((m)&_IFMT) == _IFCHR) 106 | #define S_ISDIR(m) (((m)&_IFMT) == _IFDIR) 107 | #define S_ISFIFO(m) (((m)&_IFMT) == _IFIFO) 108 | #define S_ISREG(m) (((m)&_IFMT) == _IFREG) 109 | #define S_ISLNK(m) (((m)&_IFMT) == _IFLNK) 110 | #define S_ISSOCK(m) (((m)&_IFMT) == _IFSOCK) 111 | 112 | #if defined(__CYGWIN__) 113 | /* Special tv_nsec values for futimens(2) and utimensat(2). */ 114 | #define UTIME_NOW -2L 115 | #define UTIME_OMIT -1L 116 | #endif 117 | 118 | int _EXFUN(chmod,( const char *__path, mode_t __mode )); 119 | int _EXFUN(fchmod,(int __fd, mode_t __mode)); 120 | int _EXFUN(fstat,( int __fd, struct stat *__sbuf )); 121 | int _EXFUN(mkdir,( const char *_path, mode_t __mode )); 122 | int _EXFUN(mkfifo,( const char *__path, mode_t __mode )); 123 | int _EXFUN(stat,( const char *__path, struct stat *__sbuf )); 124 | int _EXFUN(lstat,( const char *__path, struct stat *__buf )); 125 | mode_t _EXFUN(umask,( mode_t __mask )); 126 | 127 | #if defined (__SPU__) || defined(__rtems__) || defined(__CYGWIN__) && !defined(__INSIDE_CYGWIN__) 128 | int _EXFUN(mknod,( const char *__path, mode_t __mode, dev_t __dev )); 129 | #endif 130 | 131 | #if defined (__CYGWIN__) && !defined(__INSIDE_CYGWIN__) 132 | int _EXFUN(fchmodat, (int, const char *, mode_t, int)); 133 | int _EXFUN(fstatat, (int, const char *, struct stat *, int)); 134 | int _EXFUN(mkdirat, (int, const char *, mode_t)); 135 | int _EXFUN(mkfifoat, (int, const char *, mode_t)); 136 | int _EXFUN(mknodat, (int, const char *, mode_t, dev_t)); 137 | int _EXFUN(utimensat, (int, const char *, const struct timespec *, int)); 138 | int _EXFUN(futimens, (int, const struct timespec *)); 139 | #endif 140 | 141 | /* Provide prototypes for most of the _ names that are 142 | provided in newlib for some compilers. */ 143 | #ifdef _COMPILING_NEWLIB 144 | int _EXFUN(_fstat,( int __fd, struct stat *__sbuf )); 145 | int _EXFUN(_stat,( const char *__path, struct stat *__sbuf )); 146 | #ifdef __LARGE64_FILES 147 | struct stat64; 148 | int _EXFUN(_fstat64,( int __fd, struct stat64 *__sbuf )); 149 | #endif 150 | #endif 151 | 152 | #endif /* !_STAT_H_ */ 153 | #ifdef __cplusplus 154 | } 155 | #endif 156 | #endif /* _SYS_STAT_H */ 157 | -------------------------------------------------------------------------------- /toolchain/patches/gcc-4.9.2-exscapeos.patch: -------------------------------------------------------------------------------- 1 | diff -Naur gcc-4.7.2/config.sub gcc-4.7.2-MOD/config.sub 2 | --- gcc-4.7.2/config.sub 2012-08-06 16:34:27.000000000 +0200 3 | +++ gcc-4.7.2-MOD/config.sub 2012-12-13 13:38:30.000000000 +0100 4 | @@ -1333,7 +1333,7 @@ 5 | | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ 6 | | -sym* | -kopensolaris* \ 7 | | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ 8 | - | -aos* | -aros* \ 9 | + | -aos* | -aros* | -exscapeos* \ 10 | | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ 11 | | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ 12 | | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ 13 | diff -Naur gcc-4.7.2/gcc/config/exscapeos.h gcc-4.7.2-MOD/gcc/config/exscapeos.h 14 | --- gcc-4.7.2/gcc/config/exscapeos.h 1970-01-01 01:00:00.000000000 +0100 15 | +++ gcc-4.7.2-MOD/gcc/config/exscapeos.h 2012-12-13 13:38:30.000000000 +0100 16 | @@ -0,0 +1,8 @@ 17 | +#undef TARGET_OS_CPP_BUILTINS 18 | +#define TARGET_OS_CPP_BUILTINS() \ 19 | + do { \ 20 | + builtin_define_std ("exscapeos"); \ 21 | + builtin_define_std ("unix"); \ 22 | + builtin_assert ("system=exscapeos"); \ 23 | + builtin_assert ("system=unix"); \ 24 | + } while(0); 25 | diff -Naur gcc-4.7.2/gcc/config.gcc gcc-4.7.2-MOD/gcc/config.gcc 26 | --- gcc-4.7.2/gcc/config.gcc 2012-09-12 11:03:54.000000000 +0200 27 | +++ gcc-4.7.2-MOD/gcc/config.gcc 2012-12-13 14:31:13.000000000 +0100 28 | @@ -553,6 +553,12 @@ 29 | "" | yes | posix) thread_file='posix' ;; 30 | esac 31 | ;; 32 | +*-*-exscapeos*) 33 | + extra_parts="crtbegin.o crtend.o" 34 | + gas=yes 35 | + gnu_ld=yes 36 | + default_use_cxa_atexit=yes 37 | + ;; 38 | *-*-freebsd*) 39 | # This is the generic ELF configuration of FreeBSD. Later 40 | # machine-specific sections may refine and add to this 41 | @@ -1197,6 +1203,11 @@ 42 | with_cpu=${with_cpu:-core2} 43 | tmake_file="${tmake_file} t-slibgcc" 44 | ;; 45 | +i[34567]86-*-exscapeos*) 46 | + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h i386/i386elf.h exscapeos.h" 47 | + tmake_file="i386/t-i386elf t-svr4 i386/t-crtstuff" 48 | + use_fixproto=yes 49 | + ;; 50 | x86_64-*-darwin*) 51 | with_cpu=${with_cpu:-core2} 52 | tmake_file="${tmake_file} ${cpu_type}/t-darwin64 t-slibgcc" 53 | diff -Naur gcc-4.7.2/libgcc/config.host gcc-4.7.2-MOD/libgcc/config.host 54 | --- gcc-4.7.2/libgcc/config.host 2012-09-05 14:19:47.000000000 +0200 55 | +++ gcc-4.7.2-MOD/libgcc/config.host 2012-12-13 14:37:28.000000000 +0100 56 | @@ -1138,6 +1138,10 @@ 57 | tmake_file="mep/t-mep t-fdpbit" 58 | extra_parts="crtbegin.o crtend.o" 59 | ;; 60 | +i[3-7]86-*-exscapeos*) 61 | + extra_parts="crtbegin.o crtend.o" 62 | + tmake_file="$tmake_file i386/t-crtstuff" 63 | + ;; 64 | *) 65 | echo "*** Configuration ${host} not supported" 1>&2 66 | exit 1 67 | -------------------------------------------------------------------------------- /toolchain/patches/gdb-7.6.2-exscapeos.patch: -------------------------------------------------------------------------------- 1 | diff -Naur gdb-7.6.2/bfd/config.bfd gdb-7.6.2-patched/bfd/config.bfd 2 | --- gdb-7.6.2/bfd/config.bfd 2013-12-08 05:33:13.000000000 +0100 3 | +++ gdb-7.6.2-patched/bfd/config.bfd 2014-01-25 21:47:36.000000000 +0100 4 | @@ -538,6 +538,9 @@ 5 | i[3-7]86-*-aros*) 6 | targ_defvec=bfd_elf32_i386_vec 7 | ;; 8 | + i[3-7]86-*-exscapeos*) 9 | + targ_defvec=bfd_elf32_i386_vec 10 | + ;; 11 | i[3-7]86-*-chorus*) 12 | targ_defvec=bfd_elf32_i386_vec 13 | ;; 14 | diff -Naur gdb-7.6.2/config.sub gdb-7.6.2-patched/config.sub 15 | --- gdb-7.6.2/config.sub 2013-12-08 05:33:13.000000000 +0100 16 | +++ gdb-7.6.2-patched/config.sub 2014-01-25 21:47:14.000000000 +0100 17 | @@ -510,6 +510,10 @@ 18 | basic_machine=i386-pc 19 | os=-aros 20 | ;; 21 | + exscapeos) 22 | + basic_machine=i386-pc 23 | + os=-exscapeos 24 | + ;; 25 | aux) 26 | basic_machine=m68k-apple 27 | os=-aux 28 | @@ -1358,7 +1362,7 @@ 29 | | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ 30 | | -sym* | -kopensolaris* | -plan9* \ 31 | | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ 32 | - | -aos* | -aros* \ 33 | + | -aos* | -aros* | -exscapeos* \ 34 | | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ 35 | | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ 36 | | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ 37 | @@ -1502,6 +1506,9 @@ 38 | -aros*) 39 | os=-aros 40 | ;; 41 | + -exscapeos*) 42 | + os=-exscapeos 43 | + ;; 44 | -zvmoe) 45 | os=-zvmoe 46 | ;; 47 | diff -Naur gdb-7.6.2/readline/support/config.sub gdb-7.6.2-patched/readline/support/config.sub 48 | --- gdb-7.6.2/readline/support/config.sub 2013-12-08 05:11:52.000000000 +0100 49 | +++ gdb-7.6.2-patched/readline/support/config.sub 2014-01-25 21:47:53.000000000 +0100 50 | @@ -1389,6 +1389,9 @@ 51 | -aros*) 52 | os=-aros 53 | ;; 54 | + -exscapeos*) 55 | + os=-exscapeos 56 | + ;; 57 | -kaos*) 58 | os=-kaos 59 | ;; 60 | --------------------------------------------------------------------------------