├── .bochsrc ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── Rakefile ├── build ├── boot.mk ├── kern.mk ├── rootfs.mk └── user.mk ├── root └── home │ ├── about.txt │ ├── about2.txt │ └── about3.txt ├── src ├── blk │ ├── buf.c │ ├── conf.c │ └── hd.c ├── boot │ └── boot.S ├── chr │ ├── keybd.c │ ├── tty.c │ └── vga.c ├── fs │ ├── alloc.c │ ├── bmap.c │ ├── fcntl.c │ ├── inode.c │ ├── link.c │ ├── mount.c │ ├── namei.c │ ├── open.c │ ├── rdwr.c │ ├── rdwri.c │ └── super.c ├── inc │ ├── a.out.h │ ├── asm.h │ ├── buf.h │ ├── cmos.h │ ├── conf.h │ ├── dirent.h │ ├── file.h │ ├── gdt.h │ ├── hd.h │ ├── idt.h │ ├── inode.h │ ├── keybd.h │ ├── lib.h │ ├── malloc.h │ ├── mmu.h │ ├── page.h │ ├── param.h │ ├── proc.h │ ├── proto.h │ ├── signal.h │ ├── stat.h │ ├── stdarg.h │ ├── super.h │ ├── tss.h │ ├── tty.h │ ├── unistd.h │ ├── usr │ │ ├── setjmp.h │ │ ├── stdio.h │ │ └── stdlib.h │ ├── vm.h │ └── x86.h ├── kern │ ├── entry.S │ ├── exec.c │ ├── exit.c │ ├── fork.c │ ├── main.c │ ├── sched.c │ ├── seg.c │ ├── signal.c │ ├── sys1.c │ ├── sys2.c │ ├── sys3.c │ ├── sys4.c │ ├── sysent.c │ ├── timer.c │ ├── trap.c │ └── wait.c ├── lib │ └── string.c └── mm │ ├── malloc.c │ ├── pgfault.c │ ├── pm.c │ ├── pte.c │ └── vm.c ├── tool ├── boot.ld ├── main.ld └── user.ld └── usr ├── cat.c ├── hello.c ├── init.c ├── libsys ├── entry.S ├── libsys.c ├── printf.c └── string.c ├── ls.c ├── sh.c └── test ├── test_chdir.c ├── test_exec.c ├── test_exit.c ├── test_fork.c ├── test_pause.c └── test_signal.c /.bochsrc: -------------------------------------------------------------------------------- 1 | # You many now use double quotes around pathnames, in case 2 | # your pathname includes spaces. 3 | 4 | romimage: file=/usr/share/bochs/BIOS-bochs-latest 5 | vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest 6 | 7 | # size of memory 8 | megs: 128 9 | 10 | # floppy image 11 | floppya: 1_44=bin/kernel.img, status=inserted 12 | # just a partition image, formatted by mkfs.minix, 1mb 13 | ata0-master: type=disk, path="bin/rootfs.img", mode=flat, cylinders=2, heads=16, spt=63 14 | 15 | boot: a 16 | 17 | log: .bochsout 18 | panic: action=ask 19 | error: action=report 20 | info: action=report 21 | debug: action=ignore 22 | 23 | # gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0 24 | 25 | vga_update_interval: 300000 26 | keyboard_serial_delay: 250 27 | keyboard_paste_delay: 100000 28 | mouse: enabled=0 29 | private_colormap: enabled=0 30 | fullscreen: enabled=0 31 | screenmode: name="sample" 32 | keyboard_mapping: enabled=0, map= 33 | keyboard_type: at 34 | 35 | debug_symbols: file=main.sym 36 | 37 | #keyboard_type: at 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | *.img 3 | *.o 4 | bin/* 5 | root/bin/* 6 | .bochsout 7 | main.sym 8 | tags 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Fleurer 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of the organization nor the 13 | names of its contributors may be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CINC := -Isrc/inc -Isrc/inc/usr 2 | CFLAG := -Wall -Werror -nostdinc -fno-builtin -fno-stack-protector \ 3 | -finline-functions -finline-small-functions -findirect-inlining \ 4 | -finline-functions-called-once 5 | 6 | include build/boot.mk 7 | include build/kern.mk 8 | include build/rootfs.mk 9 | include build/user.mk 10 | 11 | all: bochs 12 | 13 | bochs: build 14 | bochs -q -f .bochsrc 15 | 16 | debug: build 17 | bochs-dbg -q -f .bochsrc 18 | 19 | build: 20 | echo 21 | 22 | clean: 23 | -rm -rf bin/* root/bin/* src/kern/entry.S .bochsout 24 | 25 | .PHONY: all bochs build debug clean 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Fleurix 2 | ======= 3 | 4 | About 5 | ----- 6 | 7 | A prototype Unix-like kernel. 8 | 9 | It contains 37 system calls, 7000 lines of C, over 200 lines of assembly, developed in a bochs environment. Admittedly, it can't yet shed the label of being a "toy", but it has accomplished its design goal, which is to *get it running* :) 10 | 11 | It has: 12 | ------- 13 | 14 | - A basic process management with `fork()`, `exec()`, `exit()`, `wait()`, signal handlings, and so on. Support a.out executable format. 15 | - A pure paging memory management with copy-on-write and demand paging. Support 4GB of address space for each process, sharing 128MB of kernel address space. 16 | - A simple minixv1 fs implementation. It's simple, and it can takes advantage of tools under Linux such as mkfs.minix, fsck.minix, etc. 17 | - A simple `kmalloc()`. 18 | - A simple terminal. 19 | 20 | Syscalls 21 | -------- 22 | 23 | ```c 24 | static inline _SYS0(int, debug); 25 | static inline _SYS2(int, access, char*, int); 26 | static inline _SYS3(int, open, char*, int, int); 27 | static inline _SYS2(int, creat, char*, int); 28 | static inline _SYS1(int, close, int); 29 | static inline _SYS3(int, fcntl, int, int, int); 30 | static inline _SYS3(int, mknod, char*, int, int); 31 | static inline _SYS3(int, write, int, char*, int); 32 | static inline _SYS3(int, read, int, char*, int); 33 | static inline _SYS3(int, lseek, int, int, int); 34 | static inline _SYS1(int, chdir, char*); 35 | static inline _SYS1(int, chroot, char*); 36 | static inline _SYS1(int, dup, int); 37 | static inline _SYS2(int, dup2, int, int); 38 | static inline _SYS2(int, link, char*, char*); 39 | static inline _SYS1(int, unlink, char*); 40 | static inline _SYS2(int, stat, char*, struct stat*); 41 | static inline _SYS2(int, fstat, int, struct stat*); 42 | static inline _SYS0(int, fork); 43 | static inline _SYS2(int, exec, char*, char**); 44 | static inline _SYS1(int, _exit, int); 45 | static inline _SYS1(int, nice, int); 46 | static inline _SYS0(int, getpid); 47 | static inline _SYS0(int, getppid); 48 | static inline _SYS0(int, getuid); 49 | static inline _SYS0(int, getgid); 50 | static inline _SYS0(int, geteuid); 51 | static inline _SYS0(int, getegid); 52 | static inline _SYS0(int, getpgrp); 53 | static inline _SYS0(int, setpgrp); 54 | static inline _SYS2(int, setreuid, int, int); 55 | static inline _SYS2(int, setregid, int, int); 56 | static inline _SYS2(int, kill, int, int); 57 | static inline _SYS2(int, signal, int, uint); 58 | static inline _SYS3(int, sigaction, int, struct sigaction*, struct sigaction*); 59 | static inline _SYS0(int, sigreturn); 60 | static inline _SYS3(int, waitpid, int, int*, int); 61 | static inline _SYS1(int, wait, int*); 62 | static inline _SYS0(int, pause); 63 | ``` 64 | 65 | Delayed yet :( 66 | -------------- 67 | 68 | - not have pipes. 69 | - not support swap. 70 | - not POSIX yet. 71 | - not support hard disk partitioning. 72 | - only supports up to 128MB of physical memory. 73 | 74 | Compiling & Testing 75 | ------------------- 76 | 77 | tools: rake, binutils(gcc, ld, as), nasm, bochs, mkfs.minix 78 | 79 | ``` 80 | git clone git@github.com:Fleurer/fleurix.git 81 | cd fleurix 82 | rake 83 | ``` 84 | 85 | Write your own programs under Fleurix 86 | ------------------------------------- 87 | 88 | Create a new .c file in the usr/ directory, then execute: 89 | 90 | ``` 91 | rake 92 | ``` 93 | 94 | Contributing 95 | ------------ 96 | 97 | 1. Fork it. 98 | 2. Create a branch (`git checkout -b my_markup`) 99 | 3. Commit your changes (`git commit -am "Added Snarkdown"`) 100 | 4. Push to the branch (`git push origin my_markup`) 101 | 5. Create an Issue with a link to your branch 102 | 6. Enjoy a refreshing Diet Coke and wait 103 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | cinc = '-Isrc/inc -Isrc/inc/usr' 2 | cflag = %{ 3 | -Wall 4 | -nostdinc -fno-builtin -fno-stack-protector 5 | -finline-functions -finline-small-functions -findirect-inlining -finline-functions -finline-functions-called-once 6 | }.split(/\s/).join(' ') 7 | 8 | mkdir_p 'bin' 9 | mkdir_p 'bin/usr' 10 | mkdir_p 'bin/libsys' 11 | mkdir_p 'root/bin' 12 | mkdir_p 'root/dev' 13 | 14 | # ---------------------------------------------------------- 15 | 16 | task :default => [:bochs] 17 | 18 | task :bochs => :build do 19 | sh "bochs -q -f .bochsrc" 20 | end 21 | 22 | task :nm => :build do 23 | sh 'cat main.nmtab' 24 | end 25 | 26 | task :debug => :build do 27 | sh "bochs-dbg -q -f .bochsrc" 28 | end 29 | 30 | task :build => ['bin/kernel.img', :rootfs, :ctags] 31 | 32 | task :clean do 33 | sh "rm -rf bin/* root/bin/* .bochsout" 34 | end 35 | 36 | task :werr do 37 | cflag += ' -Werror' 38 | Rake::Task['clean'].invoke 39 | Rake::Task['build'].invoke 40 | end 41 | 42 | ## helpers ## 43 | task :todo do 44 | sh "grep -r -n '\\(TODO\\|\\\\)' ./src --color" 45 | end 46 | 47 | task :ctags do 48 | sh "(cd src; ctags -R .)" 49 | end 50 | 51 | task :fsck do 52 | sh "fsck.minix -fl ./bin/rootfs.img" 53 | end 54 | 55 | # -------------------------------------------------------------------- 56 | # kernel.img = boot.bin + main.bin 57 | 58 | # the kernel image, a concat of boot image and the main binary. 59 | file 'bin/kernel.img' => ['bin/boot.bin', 'bin/main.bin'] do 60 | sh "cat bin/boot.bin bin/main.bin > bin/kernel.img" 61 | end 62 | 63 | # -------------------------------------------------------------------- 64 | # the bootloader part 65 | # => boot.bin 66 | 67 | file 'bin/boot.o' => ['src/boot/boot.S'] do 68 | sh "nasm -f elf -o bin/boot.o src/boot/boot.S" 69 | end 70 | 71 | file 'bin/boot.bin' => ['bin/boot.o', 'tool/boot.ld'] do 72 | sh "ld bin/boot.o -o bin/boot.bin -e c -T tool/boot.ld" 73 | end 74 | 75 | # --------------------------------------------------------------------- 76 | # kernel's C part 77 | # => main.bin 78 | 79 | hfiles = Dir['src/inc/*.h'] 80 | cfiles = Dir['src/**/*.c'] 81 | sfiles = [ 82 | 'src/kern/entry.S' 83 | ] 84 | ofiles = (sfiles + cfiles).map{|fn| 'bin/'+File.basename(fn).ext('o') } 85 | 86 | cfiles.each do |fn_c| 87 | fn_o = 'bin/'+File.basename(fn_c).ext('o') 88 | file fn_o => [fn_c, *hfiles] do 89 | sh "gcc #{cflag} #{cinc} -o #{fn_o} -c #{fn_c} 2>&1" 90 | end 91 | end 92 | 93 | sfiles.each do |fn_s| 94 | fn_o = 'bin/'+File.basename(fn_s).ext('o') 95 | file fn_o => [fn_s, *hfiles] do 96 | sh "nasm -f elf -o #{fn_o} #{fn_s}" 97 | end 98 | end 99 | 100 | # ---------------------------------------------------------------------3 101 | 102 | file 'bin/main.bin' => 'bin/main.elf' do 103 | sh "objcopy -R .pdr -R .comment -R .note -S -O binary bin/main.elf bin/main.bin" 104 | end 105 | 106 | file 'bin/main.elf' => ofiles + ['tool/main.ld'] do 107 | sh "ld #{ofiles * ' '} -o bin/main.elf -e c -T tool/main.ld" 108 | sh "(nm bin/main.elf | sort) > main.sym" 109 | end 110 | 111 | # ---------------------------------------------------------------------- 112 | # the rootfs part. 113 | # => rootfs.img 114 | 115 | # the root file system aka the hard disk image, 1mb yet and ignored 116 | # partition 117 | # note: on mounting, a root privilege is required. 118 | task :rootfs => ['bin/rootfs.img'] 119 | 120 | # init and copy some thing into the hard disk image. 121 | file 'bin/rootfs.img' => [:usr] do 122 | `rm -f bin/rootfs.img` 123 | sh "bximage bin/rootfs.img -hd -mode=flat -size=1 -q" 124 | sh "mkfs.minix bin/rootfs.img" 125 | mkdir_p '/tmp/fx_mnt_root' 126 | `sudo umount /tmp/fx_mnt_root` 127 | sh "sudo mount -o loop -t minix bin/rootfs.img /tmp/fx_mnt_root" 128 | sh "sudo cp -r ./root/* /tmp/fx_mnt_root" 129 | `sudo mknod /tmp/fx_mnt_root/dev/tty0 c 1 0` 130 | sh "sudo umount /tmp/fx_mnt_root" 131 | sh "rm -rf /tmp/fx_mnt_root" 132 | end 133 | 134 | # ---------------------------------------------------------------------- 135 | 136 | usr_cfiles = Dir['usr/test/*.c'] + Dir['usr/*.c'] 137 | usr_ofiles = usr_cfiles.map{|fn| 'bin/usr/'+File.basename(fn).ext('o') } 138 | usr_efiles = usr_cfiles.map{|fn| 'bin/usr/'+File.basename(fn).ext('') } 139 | 140 | libsys_cfiles = Dir['usr/libsys/*.c'] 141 | libsys_sfiles = %w{ 142 | usr/libsys/entry.S 143 | } 144 | libsys_ofiles = (libsys_sfiles+libsys_cfiles).map{|fn| 'bin/libsys/'+File.basename(fn).ext('o') } 145 | 146 | task :libsys => libsys_ofiles 147 | 148 | task :usr => usr_efiles 149 | 150 | # => libsys.a 151 | libsys_sfiles.each do |fn_s| 152 | fn_o = 'bin/libsys/'+File.basename(fn_s).ext('o') 153 | file fn_o => fn_s do 154 | sh "nasm -f elf -o #{fn_o} #{fn_s}" 155 | end 156 | end 157 | 158 | libsys_cfiles.each do |fn_c| 159 | fn = File.basename(fn_c).ext('') 160 | fn_o = 'bin/libsys/'+fn.ext('o') 161 | file fn_o => fn_c do 162 | sh "gcc -c #{cinc} -nostdinc -fno-builtin -fno-stack-protector #{fn_c} -o #{fn_o}" 163 | end 164 | end 165 | 166 | usr_cfiles.each do |fn_c| 167 | fn = File.basename(fn_c).ext('') 168 | fn_o = 'bin/usr/'+fn.ext('o') 169 | fn_e = 'bin/usr/'+fn 170 | file fn_e => [fn_c, :libsys, 'tool/user.ld'] do 171 | sh "gcc -c #{cinc} -nostdinc -fno-builtin -fno-stack-protector #{fn_c} -o #{fn_o}" 172 | sh "ld #{libsys_ofiles*' '} #{fn_o} -o #{fn_e} -e c -T tool/user.ld" 173 | sh "nm #{fn_e} > #{fn_o.ext('sym')}" 174 | sh "objdump -S #{fn_e} > #{fn_e.ext('S')}" 175 | sh "cp #{fn_e} root/bin/#{fn}" 176 | end 177 | end 178 | -------------------------------------------------------------------------------- /build/boot.mk: -------------------------------------------------------------------------------- 1 | # output: bin/boot.bin 2 | 3 | bin/boot.bin: bin/boot.o tool/boot.ld 4 | @mkdir -p bin 5 | ld bin/boot.o -o bin/boot.bin -e c -T tool/boot.ld 6 | 7 | bin/boot.o: src/boot/boot.S 8 | @mkdir -p bin 9 | nasm -f elf -o bin/boot.o src/boot/boot.S 10 | -------------------------------------------------------------------------------- /build/kern.mk: -------------------------------------------------------------------------------- 1 | # output: kern.bin 2 | 3 | H_FILES = $(wildcard src/**/*.h) 4 | C_FILES = $(wildcard src/**/*.c) 5 | S_FILES = src/kern/entry.S 6 | O_FILES = $(addprefix bin/, $(basename $(C_FILES:.c=.o) $(S_FILES:.S=.o))) 7 | 8 | bin/%.o: $(wildcard src/**/%.c) $(H_FILES) 9 | gcc $(CFLAG) $(CINC) -o $@ -c $< 10 | 11 | bin/entry.o: src/kern/entry.S 12 | nasm -f elf -o $@ $< 13 | 14 | bin/kern.bin: bin/kern.elf 15 | objcopy -R .pdr -R .comment -R .note -S -O binary $< $@ 16 | 17 | bin/kern.elf: $(O_FILES) tool/main.ld 18 | ld $< -o $@ -e -c -T tool/main.ld 19 | -------------------------------------------------------------------------------- /build/rootfs.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flaneur2020/fleurix/5ee04c556e293654bdf2148b62a1683f980d5ebc/build/rootfs.mk -------------------------------------------------------------------------------- /build/user.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flaneur2020/fleurix/5ee04c556e293654bdf2148b62a1683f980d5ebc/build/user.mk -------------------------------------------------------------------------------- /root/home/about.txt: -------------------------------------------------------------------------------- 1 | == the Messager 2 | 3 | When you feel you're alone 4 | Cut off from this cruel world 5 | Your instincts telling you to run 6 | Listen to your heart 7 | Those angel voices 8 | They'll sing to you there'll be a guide back home 9 | 10 | When life leaves us blind 11 | Love keeps us kind 12 | It keeps us kind 13 | 14 | When you've suffered enough 15 | And your spirit is breaking 16 | Your growing desperate from the fight 17 | 18 | Remember you're loved 19 | And you always will be 20 | This melody will bring you right back home 21 | 22 | When life leaves us blind 23 | Love keeps us kind 24 | When Life leaves us blind 25 | Love keeps us kind 26 | 27 | -------------------------------------------------------------------------------- /root/home/about2.txt: -------------------------------------------------------------------------------- 1 | When life leaves us blind 2 | Love keeps us kind 3 | When Life leaves us blind 4 | Love keeps us kind 5 | 6 | -------------------------------------------------------------------------------- /root/home/about3.txt: -------------------------------------------------------------------------------- 1 | god saves us everyone when we are burning in the fire of a thousand suns. 2 | -------------------------------------------------------------------------------- /src/blk/conf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | ushort rootdev = DEVNO(1, 0); 12 | 13 | struct bdevsw bdevsw[NBLKDEV] = { 14 | { 0, }, /* NODEV */ 15 | { &nulldev, &nulldev, &hd_request, &hdtab } 16 | }; 17 | 18 | struct cdevsw cdevsw[NCHRDEV] = { 19 | { 0, }, /* NODEV */ 20 | { &tty_open, (void*)&nulldev, &tty_read, &tty_write, (void*)&nulldev } 21 | }; 22 | 23 | -------------------------------------------------------------------------------- /src/blk/hd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | /* 11 | * hd.c - driver for the hard disk. 12 | * Ingore the second ide drive right now. 13 | * 14 | * Many constants, refered from http://wiki.osdev.org/IDE. 15 | * Thanks buddy. 16 | * */ 17 | 18 | struct devtab hdtab = { 0 , }; 19 | 20 | /* 21 | * Drive number can only be 0 or 1. 22 | * lba is 28-bit. 23 | * Number of sectors must <= 255. 24 | * 25 | * note: 0x1F6 is the register HD_DEVSEL, which (might) stands for HD DEV SELECTOR. 26 | * if bit 6 of this register is set, we are going to use LBA as addressing mode. 27 | * In LBA mode, the (8 bits) register 0x1F3,0x1f4,0x1F5 and the lower 4 bits of 0x1F6, 28 | * forms a 28-bit LBA address, so called LBA-28. 29 | * */ 30 | int hd_cmd(uint drive, uint cmd, uint lba, uchar ns) { 31 | hd_wait_ready(); 32 | outb(0x3F6, 0); // generate interrupt 33 | outb(0x1F2, ns); // number of sectors 34 | outb(0x1F3, lba & 0xFF); 35 | outb(0x1F4, (lba >> 8) & 0xFF); 36 | outb(0x1F5, (lba >> 16) & 0xFF); 37 | outb(0x1F6, 0xE0 | ((drive&1)<<4) | ((lba>>24)&0x0F)); 38 | outb(HD_CMD, cmd); 39 | return 0; 40 | } 41 | 42 | /* 43 | * After we've send a command, we should wait for 400 nanosecond, then read the Status 44 | * port. If the Busy bit is on, we should read the status port again until the Busy bit is 0; 45 | * then we can read the results of the command. This operation is called "Polling". We can also 46 | * use IRQs instead of polling. 47 | * */ 48 | int hd_wait_ready(){ 49 | int i = 10000, r; 50 | while(--i || ((r=inb(HD_STAT)) & HD_BSY)){ 51 | /* do nothing */; 52 | } 53 | return i; 54 | } 55 | 56 | /* prepend it into devtab's waiting list(via av_prev, av_next), 57 | * if it's not active, send a request for the hard disk drive right 58 | * now. 59 | * */ 60 | int hd_request(struct buf *bp){ 61 | // prepend into the waiting list 62 | bp->av_prev = (struct buf*)&hdtab; 63 | bp->av_next = hdtab.av_next; 64 | hdtab.av_next->av_prev = bp; 65 | hdtab.av_next = bp; 66 | // if the device's not busy 67 | if (hdtab.d_active == 0) { 68 | hd_start(); 69 | } 70 | return 0; 71 | } 72 | 73 | /* if waiting list is not empty, then take the tail, send a request 74 | * for the hard disk drive and mark it active. 75 | * note: BLK = (sizeof logical block) / (sizeof disk block), so 76 | * physical address = lba * BLK 77 | * TODO: don't support two hd disk yet. 78 | * */ 79 | void hd_start(){ 80 | struct buf *bp; 81 | // if waiting list is empty 82 | if ((struct devtab*)hdtab.av_next == &hdtab) { 83 | return; 84 | } 85 | // take the tail 86 | bp = hdtab.av_prev; 87 | hdtab.d_active = 1; 88 | // read or write. 89 | if (bp->b_flag & B_READ) { 90 | hd_cmd(0, HD_CMD_READ, bp->b_blkno*BLK/PBLK, BLK/PBLK); 91 | } 92 | else { 93 | hd_cmd(0, HD_CMD_WRITE, bp->b_blkno*BLK/PBLK, BLK/PBLK); 94 | outsl(0x1F0, bp->b_data, BLK/4); 95 | } 96 | } 97 | 98 | /* interrupt handler of the hard disk drive, triggered on got 99 | * data from the hard disk. get and remove the tail from the 100 | * waiting list, if there's still something inside it, hd_start() 101 | * again. 102 | * */ 103 | int do_hd_intr(struct trap *tf){ 104 | struct buf *bp; 105 | 106 | if (hdtab.d_active == 0) { 107 | return 0; 108 | } 109 | hdtab.d_active = 0; 110 | bp = hdtab.av_prev; 111 | bp->av_prev->av_next = bp->av_next; 112 | bp->av_next->av_prev = bp->av_prev; 113 | // read data if needed 114 | if (bp->b_flag & B_READ) { 115 | insl(0x1F0, bp->b_data, BLK/4); 116 | } 117 | iodone(bp); 118 | hd_start(); 119 | return 0; 120 | } 121 | 122 | /* 123 | * Allow the hard disk controller invoking interrupts 124 | * and set the interrupt handler. 125 | * */ 126 | void hd_init(){ 127 | irq_enable(14); 128 | set_hwint(IRQ0+14, &do_hd_intr); 129 | } 130 | 131 | /******************************************************/ 132 | 133 | /* empty routine */ 134 | int nulldev(){ 135 | return 0; 136 | } 137 | 138 | /* it should raise an ENODEV error when being called.*/ 139 | int nodev(){ 140 | syserr(ENODEV); 141 | return 0; 142 | } 143 | 144 | -------------------------------------------------------------------------------- /src/boot/boot.S: -------------------------------------------------------------------------------- 1 | align 4 2 | 3 | [bits 16] 4 | jmp _start 5 | 6 | ;; read_sect(sn, *buf), load a sector to memory. 7 | ;; input : si - logical sector number(starts at 0) 8 | ;; di - *buf 9 | ;; 10 | _read_sect: 11 | push cx 12 | push bx 13 | mov ax, si ; disk sector number 14 | mov bx, di ; buffer address. 15 | ; ch = cylinder = sn / 36 16 | mov cl, 36 17 | div cl 18 | mov ch, al 19 | ; dh = head = (sn%36)/18 20 | mov al, ah 21 | mov ah, 0 22 | mov cl, 18 23 | div cl 24 | mov dh, al 25 | ; cl = sector = (ln%36)%18+1 26 | mov cl, ah 27 | inc cl 28 | ; dl = drive = 0; 29 | mov dl, 0 30 | ; raise int 13h 31 | mov ax, 201h 32 | int 13h 33 | pop bx 34 | pop cx 35 | ret 36 | 37 | ;; ----------------------------------------------------------------------- 38 | ;; 39 | ;; bootloader starts here 40 | ;; 41 | 42 | [global _start] 43 | _start: 44 | xor ax, ax 45 | mov ds, ax 46 | mov ss, ax 47 | mov sp, 0x2000 48 | 49 | _reset_drive: 50 | mov ah, 0 ; RESET-command 51 | int 0x13 ; Call interrupt 13h 52 | or ah, ah ; Check for error code 53 | jnz _reset_drive ; Try again if ah != 0 54 | 55 | ; 56 | ; load kernel to 0x10000 (es:bx = 0x1000: 0000) 57 | ; 58 | mov ax, 0x1000 59 | mov es, ax ; es = 1000h 60 | mov di, 0 ; 61 | mov si, 1 ; 62 | mov cx, 128 ; read 128 sectors, 64kb 63 | _read_sect_loop: 64 | call _read_sect 65 | inc si 66 | add di, 0x200 67 | dec cx 68 | jnz _read_sect_loop 69 | 70 | 71 | ; 72 | ; prepare to enter protect mode 73 | ; 74 | 75 | ; Enable the A20 76 | seta20.1: 77 | in al, 0x64 78 | test al, 0x2 79 | jnz seta20.1 80 | mov al, 0xd1 81 | out byte 0x64, al 82 | seta20.2: 83 | in al, 0x64 84 | test al, 0x2 85 | jnz seta20.2 86 | mov al, 0xdf 87 | out byte 0x60, al 88 | 89 | ; clear registers 90 | xor ax, ax 91 | mov ds, ax 92 | mov ss, ax 93 | mov es, ax 94 | 95 | ; clear the intrrupt 96 | cli 97 | ; load gdt 98 | lgdt [gdt_desc] 99 | ; switch on PE in cr0 100 | mov eax, cr0 101 | or eax, 1 102 | mov cr0, eax 103 | ; jump, set seg registers as selector 104 | jmp 08h:_start_pm 105 | 106 | ;; ------------------------------------------------------------- 107 | 108 | [bits 32] 109 | 110 | _start_pm: 111 | mov ax, 10h 112 | mov ds, ax 113 | mov ss, ax 114 | mov es, ax 115 | mov gs, ax 116 | ; move stack to 0x1000 117 | mov esp, 1000h 118 | 119 | ; copy 0x10000 to 0x100000 120 | cld 121 | mov esi, 10000h 122 | mov edi, 100000h 123 | mov ecx, 10000h ; copy 64kb 124 | rep movsb 125 | 126 | ; jump to C! 127 | ; never return it should be 128 | jmp 08h:100000h 129 | 130 | _hang: 131 | jmp _hang 132 | 133 | gdt: 134 | gdt_null: 135 | dd 0, 0 136 | gdt_code: 137 | ; dword 1 138 | dw 0xffff 139 | dw 0 140 | ; dword 2 141 | db 0 142 | db 10011010b 143 | db 11001111b 144 | db 0 145 | gdt_data: 146 | ; dword 1 147 | dw 0xffff 148 | dw 0 149 | ; dword 2 150 | db 0 151 | db 10010010b 152 | db 11001111b 153 | db 0 154 | gdt_end: 155 | 156 | gdt_desc: 157 | dw gdt_end - gdt - 1 158 | dd gdt 159 | 160 | ; Magic number for sector 161 | times 510-($-$$) db 0 162 | dw 0xAA55 163 | -------------------------------------------------------------------------------- /src/chr/keybd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | /* 10 | * keybd.c 11 | * 12 | * ps: this article is marvulous. 13 | * http://www.osdever.net/papers/view/ibm-pc-keyboard-information-for-software-developers 14 | * 15 | * */ 16 | 17 | static uint mode = 0; 18 | 19 | /* translate into flags which indicated the satus of shift, ctrl & alt. */ 20 | char shift(char sc){ 21 | char ch = sc & 0x7f; 22 | 23 | if (mode & E0ESC) { 24 | switch (ch) { 25 | case 0x1D: return CTRL; 26 | case 0x38: return ALT; 27 | } 28 | } 29 | else { 30 | switch(ch) { 31 | case 0x2A: 32 | case 0x36: return SHIFT; 33 | case 0x1D: return CTRL; 34 | case 0x38: return ALT; 35 | } 36 | } 37 | return 0; 38 | } 39 | 40 | /* 41 | * Each keyboard interrupt came along with a 8bit scan code (via inb(KB_DATA)), if bit 8 is 42 | * set, it's releasing a key, else pressing. 43 | * */ 44 | int do_keybd_intr(struct trap *tf){ 45 | uchar sc, ch, m; 46 | uchar *map = keybd_map; 47 | 48 | // got no data 49 | if ((inb(KB_STAT) & KB_STAT_DIB)==0){ 50 | return -1; 51 | } 52 | sc = inb(KB_DATA); 53 | 54 | // ignore capslock yet. 55 | if ((sc & 0x7f) == 0x3A) 56 | return 0; 57 | 58 | // check E0ESC 59 | if (sc == 0xE0) 60 | mode |= E0ESC; 61 | 62 | // check shift, ctrl and alt 63 | if ((m = shift(sc))) { 64 | if (sc & 0x80) 65 | mode &= ~m; 66 | else 67 | mode |= m; 68 | return 0; 69 | } 70 | map = (mode & SHIFT)? shift_map: keybd_map; 71 | ch = map[sc & 0x7f]; 72 | 73 | if (mode & CTRL) { 74 | switch(ch){ 75 | case 'c': ch = CINTR; 76 | case 'd': ch = CEOF; 77 | case 'x': ch = CKILL; 78 | case 'q': ch = CSTART; 79 | case 's': ch = CSTOP; 80 | case 'z': ch = CSUSP; 81 | case '\\': ch = CQUIT; 82 | } 83 | } 84 | 85 | // on pressed 86 | if ((sc & 0x80)==0 && ch!='\0') { 87 | tty_input(&tty[0], ch); 88 | } 89 | // on released 90 | else { 91 | mode &= ~E0ESC; 92 | } 93 | 94 | return 0; 95 | } 96 | 97 | void keybd_init(){ 98 | irq_enable(1); 99 | set_hwint(IRQ0+1, &do_keybd_intr); 100 | } 101 | -------------------------------------------------------------------------------- /src/chr/tty.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // 6 | #include 7 | #include 8 | 9 | struct tty tty[NTTY]; 10 | 11 | /* ---------------------------------------------- */ 12 | int tty_start(struct tty *tp); 13 | 14 | 15 | /* 16 | * Append a character into a tty buf. 17 | * */ 18 | int putq(struct qbuf *qb, char ch){ 19 | // this buffer has been full now. 20 | if (qb->q_count == QBUFSIZ) { 21 | return -1; 22 | } 23 | qb->q_char[qb->q_end] = ch; 24 | qb->q_end = (qb->q_end + 1) % QBUFSIZ; 25 | qb->q_count++; 26 | return 0; 27 | } 28 | 29 | /* Get the first character from a tty buf. 30 | * */ 31 | char getq(struct qbuf *qb){ 32 | char ch; 33 | // if this buffer is empty 34 | if (qb->q_count == 0) { 35 | return -1; 36 | } 37 | ch = qb->q_char[qb->q_start]; 38 | qb->q_start = (qb->q_start + 1) % QBUFSIZ; 39 | qb->q_count--; 40 | return ch; 41 | } 42 | 43 | /* Erase the last character of a tty buf */ 44 | char eraseq(struct qbuf *qb){ 45 | // if this buffer is empty 46 | if (qb->q_count == 0) { 47 | return -1; 48 | } 49 | qb->q_end = (qb->q_end-1 + QBUFSIZ) % QBUFSIZ; 50 | qb->q_count--; 51 | return 0; 52 | } 53 | 54 | /* ---------------------------------------------- */ 55 | 56 | /* take characterers from raw list, make some parse & erase and place 57 | * it into canon list. */ 58 | int tty_canon(struct tty *tp){ 59 | char ch; 60 | int i; 61 | 62 | // if raw mode 63 | if (tp->t_flag & TTY_RAW) { 64 | while ((ch=getq(&tp->t_rawq)) >= 0) { 65 | putq(&tp->t_canq, ch); 66 | } 67 | return 0; 68 | } 69 | // canon mode 70 | while ((ch=getq(&tp->t_rawq)) >= 0) { 71 | switch(ch){ 72 | case '\t': 73 | // expand tab into spaces 74 | for(i=0; i<4-(tp->t_col%4); i++) 75 | putq(&tp->t_canq, ' '); 76 | return 0; 77 | break; 78 | case CERASE: 79 | eraseq(&tp->t_canq); 80 | break; 81 | default: 82 | putq(&tp->t_canq, ch); 83 | break; 84 | } 85 | } 86 | return 0; 87 | } 88 | 89 | /* output characters with buffering */ 90 | int tty_output(struct tty *tp, char ch){ 91 | int i; 92 | // 93 | switch(ch){ 94 | case '\t': 95 | // expand tab into spaces 96 | for(i=0; i<4-(tp->t_col%4); i++) 97 | putq(&tp->t_outq, ' '); 98 | break; 99 | default: 100 | putq(&tp->t_outq, ch); 101 | break; 102 | } 103 | return 0; 104 | } 105 | 106 | /* 107 | * Place a character on raw TTY input queue, if a carriage character 108 | * arrives, wake up the awaitors. 109 | * */ 110 | int tty_input(struct tty *tp, char ch){ 111 | uint cnt; 112 | 113 | putq(&tp->t_rawq, ch); 114 | cnt = tp->t_canq.q_count; 115 | tty_canon(tp); 116 | 117 | if (tp->t_flag & TTY_ECHO) { 118 | if (ch == CERASE) { 119 | if (cnt <= 0) { 120 | return 0; 121 | } 122 | } 123 | tty_output(tp, ch); 124 | tty_start(tp); 125 | } 126 | 127 | if ((tp->t_flag & TTY_RAW)==0){ 128 | if (CINTR==ch) { 129 | sigsend_g(tp->t_pgrp, SIGINT, 0); 130 | } 131 | } 132 | if (ch==CEOF || ch=='\n') { 133 | eraseq(&tp->t_canq); 134 | wakeup((uint)tp); 135 | return 0; 136 | } 137 | return 0; 138 | } 139 | 140 | /* ---------------------------------------- */ 141 | 142 | /* output actually starts here. */ 143 | int tty_start(struct tty *tp){ 144 | void (*putc)(char); 145 | char ch; 146 | 147 | putc = tp->t_putc; 148 | while((ch=getq(&tp->t_outq)) >= 0){ 149 | putc(ch); 150 | } 151 | return 0; 152 | } 153 | 154 | /* ---------------------------------------------- */ 155 | 156 | int tty_open(ushort dev){ 157 | struct tty *tp; 158 | 159 | if (MINOR(dev) >= NTTY){ 160 | syserr(ENODEV); 161 | return -1; 162 | } 163 | tp = &tty[MINOR(dev)]; 164 | tp->t_flag = TTY_ECHO; 165 | tp->t_putc = &putch; 166 | tp->t_rawq.q_count = 0; 167 | tp->t_canq.q_count = 0; 168 | tp->t_outq.q_count = 0; 169 | tp->t_pgrp = cu->p_pgrp; 170 | return 0; 171 | } 172 | 173 | /* called in iput() */ 174 | int tty_close(ushort dev){ 175 | return 0; 176 | } 177 | 178 | /* ---------------------------------------------- */ 179 | 180 | /* 181 | * If the list is not full, wait until 182 | * */ 183 | int tty_read(ushort dev, char *buf, uint cnt){ 184 | struct tty *tp; 185 | char ch; 186 | int i; 187 | 188 | if (MINOR(dev) >= NTTY){ 189 | syserr(ENODEV); 190 | return -1; 191 | } 192 | tp = &tty[MINOR(dev)]; 193 | // if no data on canonical list 194 | if (tp->t_canq.q_count < cnt) { 195 | sleep((uint)tp, PRITTY); 196 | } 197 | // 198 | for (i=0; it_canq)) < 0) 200 | break; 201 | buf[i] = ch; 202 | } 203 | return i+1; 204 | } 205 | 206 | int tty_write(ushort dev, char *buf, uint cnt){ 207 | struct tty *tp; 208 | int i; 209 | 210 | if (MINOR(dev) >= NTTY){ 211 | syserr(ENODEV); 212 | return -1; 213 | } 214 | tp = &tty[MINOR(dev)]; 215 | for (i=0; i 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | /* 8 | * vga.c 9 | * 10 | * This file indicated how to display text on the terminal, no 11 | * xxx_init() needed. And you can take printk() almost every 12 | * where among this kernel. 13 | * */ 14 | 15 | struct vchar { 16 | char vc_char:8; 17 | char vc_color:4; 18 | char vc_bgcolor:4; 19 | }; 20 | 21 | #define VGA_WHITE 0x07 22 | #define VGA_BLACK 0x00 23 | 24 | #define VC_BLANK (' '|VGA_WHITE<<8) 25 | 26 | /* VGA is a memory mapping interface, you may view it as an 80x25 array 27 | * which located at 0x8b000 (defined in main.ld). 28 | * */ 29 | extern struct vchar vgamem[25][80]; 30 | 31 | #define px (tty[0].t_col) 32 | #define py (tty[0].t_row) 33 | 34 | /* adjust the position of cursor */ 35 | void flush_csr(){ 36 | uint pos = py * 80 + px; 37 | outb(0x3D4, 14); 38 | outb(0x3D5, pos >> 8); 39 | outb(0x3D4, 15); 40 | outb(0x3D5, pos); 41 | } 42 | 43 | /* clear screen */ 44 | void cls(){ 45 | memsetw((short*)vgamem, VC_BLANK, 80*25); 46 | px = 0; 47 | py = 0; 48 | flush_csr(); 49 | } 50 | 51 | /* scroll up one line. */ 52 | void scroll(void) { 53 | if(py >= 25) { 54 | uint pos = py-25+1; 55 | memcpy(vgamem, &vgamem[pos][0], (25-pos)*80*sizeof(struct vchar)); 56 | memsetw((short*)&vgamem[25-pos][0], VC_BLANK, 80); 57 | py = 25-1; 58 | } 59 | } 60 | 61 | /* ----------------------------------------------------- */ 62 | 63 | void putch(char c) { 64 | if(c == '\b') { 65 | if(px > 0) { 66 | px--; 67 | vgamem[py][px].vc_char = ' '; 68 | } 69 | else { 70 | if (py>0) 71 | py--; 72 | px = 79; 73 | vgamem[py][px].vc_char = ' '; 74 | } 75 | } 76 | else if(c == '\t') { 77 | px = (px + 4) & ~3; 78 | } 79 | else if(c == '\r') { 80 | px = 0; 81 | } 82 | else if(c == '\n') { 83 | px = 0; 84 | py++; 85 | } 86 | else if(c >= ' ') { 87 | vgamem[py][px].vc_char = c; 88 | px++; 89 | } 90 | 91 | if(px >= 80) { 92 | px = 0; 93 | py++; 94 | } 95 | scroll(); 96 | flush_csr(); 97 | } 98 | 99 | void puts(char *str){ 100 | int i; 101 | for(i=0; i 2 | #include 3 | #include 4 | #include 5 | // 6 | #include 7 | #include 8 | // 9 | #include 10 | #include 11 | #include 12 | 13 | /* alloc one disk block in order to extend one file. returns 14 | * its LBA. 15 | * note: only called in bmap(, , 1). 16 | * note2: here assumes each zone equals one block. 17 | * */ 18 | int balloc(ushort dev){ 19 | struct super *sp; 20 | struct buf *bp; 21 | int nr, r, bn; 22 | 23 | sp = getsp(dev); 24 | for(nr=0; nr < sp->s_max_zone; nr++){ 25 | bp = bread(dev, BMAPBLK(sp, nr)); 26 | r = find_bit(bp->b_data, BLK); 27 | if (r < 0) { 28 | continue; 29 | } 30 | bn = nr*BPB + r; 31 | bp->b_data[bn/8] |= 1<<(bn%8); 32 | bwrite(bp); 33 | brelse(bp); 34 | unlk_sp(sp); 35 | // bzero(dev, sp->s_data_zone0 + bn); 36 | return sp->s_data_zone0 + bn; 37 | } 38 | unlk_sp(sp); 39 | panic("no free block"); 40 | return -1; 41 | } 42 | 43 | /* free a block. 44 | * */ 45 | int bfree(ushort dev, uint nr){ 46 | struct buf *bp; 47 | struct super *sp; 48 | uint bn; 49 | 50 | sp = getsp(dev); 51 | if ((nr < sp->s_data_zone0) || (nr >= sp->s_max_zone)) { 52 | panic("freeing a block not in data zone"); 53 | } 54 | bn = nr + 1 - sp->s_data_zone0; 55 | bp = bread(dev, BMAPBLK(sp, bn)); 56 | if ((bp->b_data[bn/8] & (1<<(bn%8))) == 0){ 57 | panic("freeing free block"); 58 | } 59 | bp->b_data[bn/8] &= ~(1<<(bn%8)); 60 | bwrite(bp); 61 | brelse(bp); 62 | unlk_sp(sp); 63 | return 0; 64 | } 65 | 66 | /* zero one disk block. 67 | * */ 68 | int bzero(ushort dev, uint bn){ 69 | struct buf *bp; 70 | 71 | bp = getblk(dev, bn); 72 | memset(bp->b_data, 0, BLK); 73 | bwrite(bp); 74 | brelse(bp); 75 | return 0; 76 | } 77 | 78 | /* --------------------------------------------------- */ 79 | 80 | /* allocate one inode. returns the inode number which can be 81 | * fetched with via an iget. 82 | * */ 83 | int ialloc(ushort dev){ 84 | uint nr, ino; 85 | int r; 86 | struct super *sp; 87 | struct buf *bp; 88 | 89 | sp = getsp(dev); 90 | for (nr=0; nr < sp->s_max_inode; nr++){ 91 | bp = bread(dev, IMAPBLK(sp, nr)); 92 | r = find_bit(bp->b_data, BLK); 93 | if (r < 0) { 94 | continue; 95 | } 96 | ino = nr*BPB + r; 97 | bp->b_data[ino/8] |= 1<<(ino%8); 98 | bwrite(bp); 99 | brelse(bp); 100 | unlk_sp(sp); 101 | return ino; 102 | } 103 | unlk_sp(sp); 104 | panic("no free inode"); 105 | return -1; 106 | } 107 | 108 | void ifree(ushort dev, uint ino){ 109 | struct buf *bp; 110 | struct super *sp; 111 | 112 | sp = getsp(dev); 113 | if ((ino <= 0) || (ino >= sp->s_max_inode)) { 114 | panic("freeing an non-existing inode"); 115 | } 116 | bp = bread(dev, IMAPBLK(sp, ino)); 117 | if ((bp->b_data[ino/8] & (1<<(ino%8))) == 0){ 118 | panic("freeing free inode"); 119 | } 120 | bp->b_data[ino/8] &= ~(1<<(ino%8)); 121 | bwrite(bp); 122 | brelse(bp); 123 | unlk_sp(sp); 124 | } 125 | 126 | /* find the first zero bit in one bitmap */ 127 | int find_bit(char *bm, int size){ 128 | uint byte, i, j; 129 | for (i=0; i 2 | #include 3 | #include 4 | // 5 | #include 6 | #include 7 | // 8 | #include 9 | #include 10 | #include 11 | // 12 | #include 13 | 14 | /* 15 | * Given an inode and a position within the corresponding file, locate the 16 | * block (not zone) number in which that position is to be found and return it. 17 | * returns 0 on error. 18 | * note: 19 | * the first 7 entry of ip->zones[] are direct pointers, ip->zone[7] is an indirect 20 | * pointer to a zone map, while ip->zone[8] is an double indirect pointer to a zone map. 21 | * note2: file extends only here. 22 | * 23 | * ip->i_size is adjusted in writei(); 24 | * 25 | * TODO: maybe we can remove all the updatei and bwrite stuff, but sync() is to be implemented 26 | * first. 27 | */ 28 | int bmap(struct inode *ip, ushort nr, uchar creat) { 29 | struct buf *bp, *bp2; 30 | short *zmap, *zmap2; 31 | ushort dev; 32 | 33 | if ((nr > MAX_FILESIZ/BLK) || ((nr > (ip->i_size/BLK) && (creat==0)))) { 34 | panic("blk nr too big."); 35 | } 36 | 37 | dev = ip->i_dev; 38 | if (nr<7){ 39 | // if the create flag is set 40 | if (ip->i_zone[nr]==0 && creat){ 41 | ip->i_zone[nr] = balloc(dev); 42 | ip->i_flag |= I_DIRTY; 43 | iupdate(ip); 44 | } 45 | return ip->i_zone[nr]; 46 | } 47 | nr -= 7; 48 | /*----------------------------*/ 49 | // read the indirect zone map 50 | if (nri_zone[7]==0) { 52 | if (creat==0) { 53 | return 0; 54 | } 55 | // if the indirect block is null and creat is set 56 | ip->i_zone[7] = balloc(dev); 57 | bzero(dev, ip->i_zone[7]); 58 | ip->i_flag |= I_DIRTY; 59 | iupdate(ip); 60 | } 61 | bp = bread(dev, ip->i_zone[7]); 62 | zmap = (short *)bp->b_data; 63 | if (zmap[nr]==0 && creat) { 64 | zmap[nr] = balloc(dev); 65 | bwrite(bp); 66 | } 67 | brelse(bp); 68 | return zmap[nr]; 69 | } 70 | /*----------------------------*/ 71 | nr -= NINDBLK; 72 | // the double indirect zone map. 73 | // read the middle indirect zone map. 74 | if (ip->i_zone[8]==0) { 75 | // if the first indirect block is null and creat is set 76 | if (creat == 0) { 77 | return 0; 78 | } 79 | ip->i_zone[8] = balloc(dev); 80 | bzero(dev, ip->i_zone[8]); 81 | ip->i_flag |= I_DIRTY; 82 | iupdate(ip); 83 | } 84 | bp = bread(dev, ip->i_zone[8]); 85 | zmap = (short *)bp->b_data; 86 | if (zmap[nr/NINDBLK]==0) { 87 | if (creat==0) { 88 | brelse(bp); 89 | return 0; 90 | } 91 | // if the second indirect block is null and creat is set 92 | zmap[nr/NINDBLK] = balloc(dev); 93 | bzero(dev, zmap[nr/NINDBLK]); 94 | bwrite(bp); 95 | } 96 | // read the secondary indirect zone map. 97 | bp2 = bread(dev, zmap[nr/NINDBLK]); 98 | zmap2 = (short*)bp2->b_data; 99 | if ((zmap2[nr%NINDBLK]==0) & creat) { 100 | zmap2[nr%NINDBLK] = balloc(dev); 101 | bwrite(bp2); 102 | } 103 | brelse(bp); 104 | brelse(bp2); 105 | return zmap2[nr%NINDBLK]; 106 | } 107 | 108 | /* 109 | * Discard inode's content. 110 | * Called from routines like open(), iput(). 111 | * */ 112 | int itrunc(struct inode *ip){ 113 | int i,j; 114 | ushort dev; 115 | struct buf *bp, *bp2; 116 | char *zmap, *zmap2; 117 | 118 | // only regular file but not directory can be truncated 119 | if (!(ip->i_mode & S_IFREG) || (ip->i_mode & S_IFDIR)) { 120 | return -1; 121 | } 122 | 123 | dev = ip->i_dev; 124 | for (i=0; i<7; i++){ 125 | if (ip->i_zone[i]!=0){ 126 | bfree(dev, ip->i_zone[i]); 127 | ip->i_flag |= I_DIRTY; 128 | ip->i_zone[i] = 0; 129 | } 130 | } 131 | /* -------------------------- */ 132 | if (ip->i_zone[7] != 0){ 133 | bp = bread(dev, ip->i_zone[7]); 134 | zmap = bp->b_data; 135 | for (i=0; ii_zone[7]); 141 | ip->i_zone[7] = 0; 142 | brelse(bp); 143 | } 144 | /* -------------------------- */ 145 | if (ip->i_zone[8] != 0){ 146 | bp = bread(dev, ip->i_zone[8]); 147 | zmap = bp->b_data; 148 | for (i=0; ib_data; 152 | for (j=0; ji_zone[8]); 163 | ip->i_zone[8] = 0; 164 | } 165 | ip->i_size = 0; 166 | iupdate(ip); 167 | return 0; 168 | } 169 | -------------------------------------------------------------------------------- /src/fs/fcntl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // 6 | #include 7 | #include 8 | // 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | struct file file[NFILE]; 15 | 16 | /* -------------------------------------------------------------- */ 17 | 18 | /* 19 | * fcntl() performs one of the operations described below on the 20 | * open file descriptor fd. The operation is determined by cmd. 21 | * Also there is an optional thrid argument, which associated with 22 | * the second argument cmd. 23 | * */ 24 | /* TODO: add other commands */ 25 | int do_fcntl(int fd, uint cmd, uint arg){ 26 | struct file *fp; 27 | 28 | fp = cu->p_ofile[fd]; 29 | if (fd>=NOFILE || fd<0 || fp==NULL){ 30 | syserr(EBADF); 31 | return -1; 32 | } 33 | 34 | switch(cmd) { 35 | // duplicate a fd, just as dup 36 | case F_DUPFD: 37 | return do_dup(fd); 38 | case F_GETFL: 39 | return fp->f_oflag; 40 | case F_SETFL: 41 | fp->f_oflag = arg; 42 | return 0; 43 | case F_GETFD: 44 | return cu->p_fdflag[fd]; 45 | case F_SETFD: 46 | cu->p_fdflag[fd] = arg; 47 | return 0; 48 | case F_GETLK: 49 | case F_SETLK: 50 | case F_SETLKW: 51 | default: 52 | return -1; 53 | } 54 | } 55 | 56 | /* get a struct stat of an inode. a memory check is nessary. */ 57 | int do_stat(struct inode *ip, struct stat *sbuf){ 58 | struct stat tmp; 59 | 60 | tmp.st_dev = ip->i_dev; 61 | tmp.st_ino = ip->i_num; 62 | tmp.st_mode = ip->i_mode; 63 | tmp.st_nlink = ip->i_nlink; 64 | tmp.st_uid = ip->i_uid; 65 | tmp.st_gid = ip->i_gid; 66 | tmp.st_rdev = ip->i_zone[0]; 67 | tmp.st_mtime = ip->i_mtime; 68 | tmp.st_ctime = ip->i_ctime; 69 | tmp.st_atime = ip->i_atime; 70 | tmp.st_size = ip->i_size; 71 | 72 | *sbuf = tmp; 73 | return 0; 74 | } 75 | 76 | /* -------------------------------------------------------------- */ 77 | 78 | /* check file access and permssion. mode is R_OK, W_OK and X_OK. 79 | * In the case of write, the read-only status of the file system is 80 | * checked. 81 | * The super user is granted all permissions except for EXEC where 82 | * at least one of the EXEC bits must be on. 83 | * 84 | * returns 0 on OK and -1 on fail. 85 | * */ 86 | int do_access(struct inode *ip, uint mode){ 87 | struct super *sp; 88 | uint m; 89 | 90 | if (ip==NULL) { 91 | syserr(EACCES); 92 | return -1; 93 | } 94 | 95 | if (mode & W_OK) { 96 | // fs is readonly 97 | sp = getsp(ip->i_dev); 98 | unlk_sp(sp); 99 | if (sp->s_flag & S_RDONLY) { 100 | syserr(EROFS); 101 | return -1; 102 | } 103 | // this inode is running. 104 | if (ip->i_flag & I_TEXT) { 105 | return -1; 106 | } 107 | } 108 | // super user is granted all permissions. but X_OK needs at least one bit on. 109 | if (suser()){ 110 | if (mode & X_OK) { 111 | if ((ip->i_mode & (X_OK|X_OK<<3|X_OK<<6))){ 112 | syserr(EACCES); 113 | return -1; 114 | } 115 | return 0; 116 | } 117 | } 118 | // 119 | m = ip->i_mode & 0777; 120 | if (cu->p_euid == ip->i_uid) 121 | m >>= 6; 122 | else if (cu->p_egid == ip->i_gid) 123 | m >>= 3; 124 | // 125 | if ((m & 07 & mode)==mode) { 126 | return 0; 127 | } 128 | syserr(EACCES); 129 | return -1; 130 | } 131 | 132 | /* -------------------------------------------------------------- */ 133 | 134 | /* 135 | * creat a new file if not existing yet. if existed, truncate it. 136 | * this routine also returns a file descriptor just like do_open(). 137 | * */ 138 | int do_creat(char *path, int mode){ 139 | return do_open(path, O_CREAT | O_TRUNC, mode); 140 | } 141 | 142 | /* 143 | * */ 144 | int do_mknod(char *path, int mode, ushort dev){ 145 | struct inode *ip; 146 | 147 | ip = namei(path, 1); 148 | // if existing 149 | if (ip==NULL) { 150 | syserr(ENOENT); 151 | iput(ip); 152 | return -1; 153 | } 154 | if (ip->i_nlink != 0){ 155 | syserr(EEXIST); 156 | iput(ip); 157 | return -1; 158 | } 159 | if (mode==S_IFBLK || mode==S_IFCHR) { 160 | ip->i_zone[0] = dev; 161 | } 162 | ip->i_mode = mode; 163 | ip->i_nlink = 1; 164 | ip->i_mtime = time(); 165 | ip->i_uid = cu->p_euid; 166 | ip->i_gid = cu->p_egid; 167 | iupdate(ip); 168 | iput(ip); 169 | return 0; 170 | } 171 | 172 | /* -------------------------------------------------------------- */ 173 | 174 | -------------------------------------------------------------------------------- /src/fs/inode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | // 5 | #include 6 | #include 7 | // 8 | #include 9 | #include 10 | #include 11 | // 12 | #include 13 | 14 | struct inode inode[NINODE]; 15 | 16 | /* 17 | * this file indicated some operation on inode. such as 18 | * iget -> get an locked inode. 19 | * iput -> release an locked inode. 20 | * iload -> load an inode from disk. 21 | * iupdate -> write changes back to disk. 22 | * */ 23 | 24 | /* get an (locked) inode via an number 25 | * if the inode is in cache, return it right now. 26 | * return NULL on error. 27 | * note1: you may compare this code with getblk, the idea here 28 | * is common used among everywhere on resource allocation. 29 | * it returns ONLY locked inode just as B_BUSY in getblk, just 30 | * to prevent other processes' accessing within one syscall. 31 | * 32 | * note2: though there is still some differences between getblk, 33 | * put an eye on *reference count*, lock won't stays long(within 34 | * one syscall, like the open routine, which unlock the inode at 35 | * last), though *reference count* ramains set between syscalls 36 | * to prevent the kernel from reallocating active in-core inode. 37 | * 38 | * */ 39 | struct inode* iget(ushort dev, uint num){ 40 | struct inode *ip; 41 | struct super *sp; 42 | 43 | _loop: 44 | for(ip=&inode[0]; ip<&inode[NINODE]; ip++){ 45 | if (ip->i_dev==dev && ip->i_num==num) { 46 | // if found but locked. 47 | if (ip->i_flag & I_LOCK) { 48 | ip->i_flag |= I_WANTED; 49 | sleep((uint)ip, PINOD); 50 | goto _loop; 51 | } 52 | // if this is an mount point, redirect to the mount 53 | // target's root inode. 54 | if (ip->i_flag & I_MOUNT) { 55 | for (sp=&mnt[0]; sp<&mnt[NMOUNT]; sp++){ 56 | if (ip == sp->s_imnt){ 57 | // iget(sp->s_dev, ROOTINO); 58 | dev = sp->s_dev; 59 | num = ROOTINO; 60 | goto _loop; 61 | } 62 | } 63 | } 64 | // if found straightly 65 | ip->i_count++; 66 | ip->i_flag |= I_LOCK; 67 | return ip; 68 | } 69 | } 70 | // not cached, so seek one free slot 71 | for(ip=&inode[0]; ip<&inode[NINODE]; ip++){ 72 | // time to read disk 73 | if (ip->i_count==0) { 74 | ip->i_dev = dev; 75 | ip->i_num = num; 76 | ip->i_flag = I_LOCK; 77 | ip->i_count++; 78 | iload(ip); 79 | return ip; 80 | } 81 | } 82 | // if not found (no free slot) 83 | printk("inode table overflow.\n"); 84 | return NULL; 85 | } 86 | 87 | /* 88 | * release an inode. 89 | * decrease the reference count, write updates to disk if nessary. 90 | * also check the link count, if zero, trucate it. 91 | * */ 92 | void iput(struct inode *ip){ 93 | ushort dev; 94 | 95 | if(ip==NULL) 96 | panic("bad struct inode*"); 97 | ip->i_flag |= I_LOCK; 98 | if (ip->i_count > 0) { 99 | ip->i_count--; 100 | } 101 | if (ip->i_count==0){ 102 | if (ip->i_nlink==0) { 103 | itrunc(ip); 104 | ifree(ip->i_dev, ip->i_num); 105 | } 106 | // if it's a device file, the dev number is stored in zone[0]. 107 | dev = ip->i_zone[0]; 108 | switch (ip->i_mode & S_IFMT) { 109 | case S_IFBLK: 110 | (*bdevsw[MAJOR(dev)].d_close)(dev); 111 | break; 112 | case S_IFCHR: 113 | (*cdevsw[MAJOR(dev)].d_close)(dev); 114 | break; 115 | } 116 | iupdate(ip); 117 | ip->i_flag = 0; 118 | ip->i_num = 0; 119 | } 120 | unlk_ino(ip); 121 | } 122 | 123 | /***************************************************/ 124 | 125 | /* load a inode from disk 126 | * */ 127 | int iload(struct inode *ip){ 128 | struct super *sp; 129 | struct d_inode *itab; /* note this is an d_inode, 32 bytes. */ 130 | struct buf *bp; 131 | 132 | sp = getsp(ip->i_dev); 133 | if (sp==NULL){ 134 | panic("error on reading a super"); 135 | } 136 | // get the blk number where this inode lies in. 137 | bp = bread(ip->i_dev, IBLK(sp, ip->i_num)); 138 | if (bp->b_flag & B_ERROR) { 139 | panic("error on reading an inode"); 140 | } 141 | itab = (struct d_inode*)bp->b_data; 142 | memcpy(ip, &itab[(ip->i_num-1)%IPB], sizeof(struct d_inode)); 143 | brelse(bp); 144 | return 0; 145 | } 146 | 147 | /* write changes back to disk if nessary. */ 148 | void iupdate(struct inode *ip){ 149 | struct super *sp; 150 | struct d_inode *itab; 151 | struct buf *bp; 152 | 153 | /* 154 | if ((ip->i_flag & I_DIRTY)==0){ 155 | return; 156 | } 157 | */ 158 | 159 | sp = getsp(ip->i_dev); 160 | if (sp==NULL){ 161 | panic("bad super"); 162 | } 163 | // get the blk number where this inode lies in. 164 | bp = bread(ip->i_dev, IBLK(sp, ip->i_num)); 165 | if (bp->b_flag & B_ERROR) { 166 | panic("error on reading an inode"); 167 | } 168 | itab = (struct d_inode*)bp->b_data; 169 | // which different from above. 170 | memcpy(&itab[(ip->i_num-1)%IPB], ip, sizeof(struct d_inode)); 171 | ip->i_flag &= ~I_DIRTY; 172 | bwrite(bp); 173 | brelse(bp); 174 | return; 175 | } 176 | 177 | /*************************************************************/ 178 | 179 | void lock_ino(struct inode *ip){ 180 | while(ip->i_flag & I_LOCK){ 181 | sleep((uint)ip, PINOD); 182 | } 183 | ip->i_flag |= I_LOCK; 184 | } 185 | 186 | /* remember this just free with malloc. */ 187 | void unlk_ino(struct inode *ip){ 188 | cli(); 189 | if (ip->i_flag & I_WANTED) { 190 | wakeup((uint)ip); 191 | } 192 | ip->i_flag &= ~(I_LOCK | I_WANTED); 193 | sti(); 194 | } 195 | 196 | /*************************************************************/ 197 | 198 | void dump_inode(struct inode *ip){ 199 | printk("i_mode:%x\n", ip->i_mode); 200 | printk("i_uid:%x\n", ip->i_uid); 201 | printk("i_size:%x\n", ip->i_size); 202 | printk("i_mtime:%x\n", ip->i_mtime); 203 | printk("i_gid:%x\n", ip->i_gid); 204 | printk("i_nlink:%x\n", ip->i_nlink); 205 | printk("i_count:%x\n", ip->i_count); 206 | printk("i_dev:%x\n", ip->i_dev); 207 | printk("i_num:%x\n", ip->i_num); 208 | printk("i_flag:%x\n", ip->i_flag); 209 | int i=0; 210 | for(i=0;i<9;i++){ 211 | printk("i_zone[%d]: %x\n", i, ip->i_zone[i]); 212 | } 213 | 214 | /* 215 | uint nr; 216 | struct buf *bp; 217 | 218 | bp = bread(rootdev, nr); 219 | dump_buf(bp); 220 | brelse(bp); 221 | printk("\n"); */ 222 | } 223 | -------------------------------------------------------------------------------- /src/fs/link.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // 6 | #include 7 | #include 8 | // 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /* 16 | * link path1 to path2. 17 | * path1 is existing yet, create a new directory entry for path2, 18 | * and increase the reference count of path1's inode. 19 | * */ 20 | int do_link(char *path1, char *path2){ 21 | struct inode *tip, *dip; 22 | int ino, r; 23 | char *name; 24 | 25 | // get the inode number. 26 | tip = namei(path1, 0); 27 | if (tip==NULL) { 28 | iput(tip); 29 | syserr(ENOENT); 30 | return -1; 31 | } 32 | ino = tip->i_num; 33 | tip->i_nlink++; 34 | iupdate(tip); 35 | unlk_ino(tip); // the next namei may deadlock. so unlock it. 36 | 37 | // get the inode of the target's directory 38 | dip = namei_parent(path2, &name); 39 | if (strlen(name)==0 || strlen(name) >= NAMELEN) { 40 | syserr(ENOENT); 41 | goto _bad_name; 42 | } 43 | if (strcmp(name, ".")==0 || strcmp(name, "..")==0){ 44 | syserr(EPERM); 45 | goto _bad_name; 46 | } 47 | // if entry already exists, error. 48 | r = find_entry(dip, name, strlen(name)); 49 | if (r!=0) { 50 | syserr(EEXIST); 51 | goto _bad_name; 52 | } 53 | // create dir entry. 54 | lock_ino(tip); 55 | r = link_entry(dip, name, strlen(name), tip->i_num); 56 | if (r==0) { 57 | panic("bad link. "); 58 | } 59 | iupdate(tip); // ref count increased 60 | iput(tip); 61 | iput(dip); 62 | return 0; 63 | 64 | _bad_name: 65 | // undo something 66 | lock_ino(tip); 67 | tip->i_nlink--; 68 | iupdate(tip); 69 | iput(tip); 70 | iput(dip); 71 | return -1; 72 | } 73 | 74 | /* 75 | * remove a link to a file. 76 | * this file should not be a directory. 77 | * returns 0 on success. 78 | * */ 79 | int do_unlink(char *path){ 80 | struct inode *ip, *dip; 81 | int ino; 82 | char *name; 83 | 84 | dip = namei_parent(path, &name); 85 | // on path=='/' 86 | if (strlen(name)==0 || strlen(name) >= NAMELEN) 87 | goto _bad_name; 88 | if (strcmp(name, ".")==0 || strcmp(name, "..")==0) 89 | goto _bad_name; 90 | 91 | ino = unlink_entry(dip, name, strlen(name)); 92 | // entry not found 93 | if (ino<=0) 94 | goto _bad_name; 95 | ip = iget(dip->i_dev, ino); 96 | // can't unlink a directory, undo something. 97 | if ((ip->i_mode & S_IFMT) == S_IFDIR) { 98 | link_entry(dip, name, strlen(name), ip->i_num); 99 | iput(ip); 100 | iput(dip); 101 | syserr(EPERM); 102 | return -1; 103 | } 104 | ip->i_nlink--; 105 | iput(ip); 106 | iput(dip); 107 | return 0; 108 | 109 | _bad_name: 110 | iput(dip); 111 | syserr(EPERM); 112 | return -1; 113 | } 114 | 115 | -------------------------------------------------------------------------------- /src/fs/mount.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // 6 | #include 7 | #include 8 | // 9 | #include 10 | #include 11 | #include 12 | 13 | struct super *rootsp = NULL; 14 | 15 | /* load a super block in-core. and associate with an in-core inode (locked). 16 | * on mounting the root filesystem, do_mount(rootdev, NULL); 17 | * 18 | * if did not got any free slot, just simply raise an error instead 19 | * of sleep until somebody frees like what getblk does. 20 | * if dev==rootdev, set a pointer rootsp for a quicker access. 21 | * 22 | * */ 23 | struct super* do_mount(ushort dev, struct inode *ip){ 24 | struct super *sp; 25 | 26 | for(sp=&mnt[0]; sp<&mnt[NMOUNT]; sp++){ 27 | // found in cache 28 | if (sp->s_dev == dev) { 29 | sp->s_flag |= S_LOCK; 30 | goto _found; 31 | } 32 | } 33 | // not in cache, seek an free slot and read the disk. 34 | for(sp=&mnt[0]; sp<&mnt[NMOUNT]; sp++){ 35 | if (sp->s_dev == NODEV) { 36 | sp->s_dev = dev; 37 | spload(sp); 38 | goto _found; 39 | } 40 | } 41 | // not found 42 | printk("no free mount slot"); 43 | return NULL; 44 | 45 | _found: 46 | // if the inode as mount point is not a directory 47 | if ((ip!=NULL) && (ip->i_mode & S_IFMT)!=S_IFDIR){ 48 | putsp(sp); 49 | return NULL; 50 | } 51 | if (dev==rootdev) { 52 | rootsp = sp; 53 | } 54 | if (ip!=NULL) 55 | ip->i_count++; 56 | sp->s_imnt = ip; 57 | unlk_sp(sp); 58 | return sp; 59 | } 60 | 61 | /* 62 | * umount(); 63 | * unmount an device. 64 | * */ 65 | int do_umount(ushort dev){ 66 | struct super *sp; 67 | struct inode *ip; 68 | 69 | sp = getsp(dev); 70 | for(ip=&inode[0]; ip<&inode[NINODE]; ip++){ 71 | if (ip->i_num!=0 && ip->i_dev==dev) { 72 | syserr(EBUSY); 73 | return -1; 74 | } 75 | } 76 | spupdate(sp); 77 | sp->s_dev = 0; 78 | sp->s_flag = 0; 79 | iput(sp->s_imnt); 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /src/fs/namei.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // 6 | #include 7 | #include 8 | // 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | /* 16 | * fetch an inode number from a single directory file (via a locked inode, make sure 17 | * it's an directory). 18 | * returns 0 on fail. 19 | * NOTE: minix v1's direntry is aligned with a 32bytes boundary. 20 | * */ 21 | uint find_entry(struct inode* dip, char *name, uint len){ 22 | struct buf *bp; 23 | struct dirent *dep; 24 | int i, j, bn=0, ino=0; 25 | 26 | if ((dip->i_mode & S_IFMT)!=S_IFDIR) { 27 | syserr(EFAULT); 28 | return 0; 29 | } 30 | len = min(len, NAMELEN); 31 | 32 | for(i=0; ii_size/BLK+1; i++){ 33 | bn = bmap(dip, i, 0); 34 | bp = bread(dip->i_dev, bn); 35 | dep = (struct dirent *)bp->b_data; 36 | for(j=0; ji_mode & S_IFMT)!=S_IFDIR) { 57 | syserr(EFAULT); 58 | return 0; 59 | } 60 | len = min(len, NAMELEN); 61 | 62 | for(i=0; ii_size/BLK+1; i++){ 63 | bn = bmap(dip, i, 0); 64 | bp = bread(dip->i_dev, bn); 65 | dep = (struct dirent *)bp->b_data; 66 | for(j=0; ji_mode & S_IFMT)!=S_IFDIR) { 90 | syserr(ENOTDIR); 91 | return 0; 92 | } 93 | len = min(len, NAMELEN); 94 | 95 | for (off=0; off < dip->i_size; off+=sizeof(struct dirent)){ 96 | r = readi(dip, (char*)&de, off, sizeof(struct dirent)); 97 | if (r != sizeof(struct dirent)){ 98 | panic("bad read dir ino"); 99 | } 100 | if (de.d_ino == 0) { 101 | break; 102 | } 103 | } 104 | strncpy(de.d_name, name, len+1); 105 | de.d_ino = ino; 106 | r = writei(dip, (char*)&de, off, sizeof(struct dirent)); 107 | if (r != sizeof(struct dirent)){ 108 | panic("bad inode"); 109 | } 110 | return ino; 111 | } 112 | 113 | /* 114 | * returns a locked inode. NULL on error. 115 | * */ 116 | struct inode* _namei(char *path, uchar creat, uchar parent, char **name){ 117 | struct inode *wip=NULL, *cdp=NULL; 118 | ushort dev, ino, len; 119 | char* tmp; 120 | 121 | // if path starts from root 122 | // note if p_wdir==NULL, it's an early initialized process, 123 | // set it's root directory here. 124 | if (*path == '/') { 125 | wip = iget(rootdev, ROOTINO); 126 | } 127 | else { 128 | cdp = cu->p_wdir; 129 | wip = iget(cdp->i_dev, cdp->i_num); 130 | } 131 | 132 | // while there is more path name with '/' 133 | while (*path != '\0') { 134 | if (*path=='/'){ 135 | path++; 136 | continue; 137 | } 138 | // if working inode is root and componet is ".." 139 | if ((wip->i_num==ROOTINO) && (strncmp(path, "..", 2)==0)) { 140 | } 141 | 142 | // wip must be a directory 143 | if ((wip->i_mode & S_IFMT)!=S_IFDIR) { 144 | iput(wip); 145 | syserr(EISDIR); 146 | return NULL; 147 | } 148 | // TODO: check access 149 | tmp = strchr(path, '/'); 150 | // if got the parent inode. 151 | if (tmp==NULL) { 152 | if (parent) { 153 | *name = path; 154 | return wip; 155 | } 156 | len = strlen(path); 157 | dev = wip->i_dev; 158 | } 159 | else { 160 | len = tmp-path; 161 | } 162 | ino = find_entry(wip, path, len); 163 | // if not found 164 | if (ino <= 0){ 165 | if (creat==0) { 166 | iput(wip); 167 | return NULL; 168 | } 169 | // file is not found and creat is set, assign a new inode 170 | ino = ialloc(wip->i_dev); 171 | wip->i_flag |= I_LOCK; 172 | // what a fuck 173 | link_entry(wip, path, len, ino); 174 | } 175 | iput(wip); 176 | wip = iget(wip->i_dev, ino); 177 | path += len; 178 | } 179 | return wip; 180 | } 181 | 182 | /* returns NULL on error. 183 | * */ 184 | struct inode* namei(char *path, uchar creat){ 185 | return _namei(path, creat, 0, NULL); 186 | } 187 | 188 | struct inode* namei_parent(char *path, char **name){ 189 | return _namei(path, 0, 1, name); 190 | } 191 | -------------------------------------------------------------------------------- /src/fs/open.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // 6 | #include 7 | #include 8 | // 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | struct file file[NFILE]; 15 | 16 | /* ------------------------------------------------------------- */ 17 | 18 | /* 19 | * open a file. flag indicated opened type like O_RDONLY, O_TRUNC, O_CREAT and blah. And 20 | * mode only used in the O_CREAT scenary, indicated the file (inode) type. 21 | * 22 | * each proc has got one user file table(p_ofile[NOFILE]), it's each entry is also a number, 23 | * indicated the number in the system file table(file[NFILE]). when user opened a file, it 24 | * first allocate a user file table entry(aka. file descriptor), then attach it with a system 25 | * file table entry. It's reference count is increased in fork() or dup(). 26 | * */ 27 | int do_open(char *path, uint flag, uint mode){ 28 | struct inode *ip; 29 | struct file *fp; 30 | ushort dev; 31 | int fd; 32 | 33 | // on create a new file. 34 | if (flag & O_CREAT){ 35 | ip = namei(path, 1); 36 | // if file is not existing yet. 37 | if (ip->i_nlink==0) { 38 | ip->i_mode = mode; 39 | ip->i_uid = cu->p_euid; 40 | ip->i_gid = cu->p_egid; 41 | ip->i_mtime = time(); 42 | ip->i_nlink = 1; 43 | iupdate(ip); 44 | } 45 | } 46 | // an existing file. 47 | else { 48 | ip = namei(path, 0); 49 | if (ip == NULL){ 50 | syserr(ENFILE); 51 | return -1; 52 | } 53 | // TODO: check access 54 | // if it's a device file, the dev number is stored in zone[0]. 55 | dev = ip->i_zone[0]; 56 | switch(ip->i_mode & S_IFMT) { 57 | case S_IFBLK: 58 | (*bdevsw[MAJOR(dev)].d_open)(dev); 59 | break; 60 | case S_IFCHR: 61 | (*cdevsw[MAJOR(dev)].d_open)(dev); 62 | break; 63 | } 64 | } 65 | if (((fd=ufalloc())<0) || (fp=falloc(fd))==NULL) { 66 | iput(ip); 67 | return -1; 68 | } 69 | if (flag & O_TRUNC){ 70 | itrunc(ip); 71 | } 72 | unlk_ino(ip); 73 | fp->f_oflag = flag; 74 | fp->f_ino = ip; 75 | cu->p_fdflag[fd] = FD_CLOEXEC; 76 | return fd; 77 | } 78 | 79 | /* 80 | * close a user file discriptor. 81 | * remove the entry in the user file table, and decrease the entry in system 82 | * file table's ref count. and iput the inode. 83 | * */ 84 | int do_close(int fd){ 85 | struct file *fp; 86 | 87 | if ((fd>NOFILE) || (fd<0)){ 88 | syserr(EBADF); 89 | return -1; 90 | } 91 | 92 | fp = cu->p_ofile[fd]; 93 | if (fp==NULL || fp>&file[NFILE] || fp<&file[0]) { 94 | syserr(EBADF); 95 | return -1; 96 | } 97 | cu->p_ofile[fd] = NULL; 98 | iput(fp->f_ino); 99 | fp->f_count--; 100 | if (fp->f_count <= 0) { 101 | fp->f_count = 0; 102 | fp->f_oflag = 0; 103 | fp->f_offset = 0; 104 | } 105 | return 0; 106 | } 107 | 108 | /* duplicate a file descriptor, dup2 */ 109 | int do_dup(int fd){ 110 | struct file *fp; 111 | int newfd; 112 | 113 | fp = cu->p_ofile[fd]; 114 | if (fd>=NOFILE || fp==NULL){ 115 | syserr(EBADF); 116 | return -1; 117 | } 118 | if ((newfd=ufalloc())<0) { 119 | return -1; 120 | } 121 | fp->f_count++; 122 | fp->f_ino->i_count++; 123 | cu->p_ofile[newfd] = fp; 124 | return newfd; 125 | } 126 | 127 | /* close the newfd. */ 128 | int do_dup2(int fd, int newfd){ 129 | struct file *fp; 130 | 131 | fp = cu->p_ofile[fd]; 132 | if (fd>=NOFILE || fp==NULL){ 133 | syserr(EBADF); 134 | return -1; 135 | } 136 | 137 | do_close(newfd); 138 | fp->f_count++; 139 | fp->f_ino->i_count++; 140 | cu->p_ofile[newfd] = fp; 141 | return newfd; 142 | } 143 | 144 | /* -------------------------------------------------------------- */ 145 | 146 | /* allocate a user file descriptor. */ 147 | int ufalloc(){ 148 | int i; 149 | 150 | for(i=0; ip_ofile[i]==NULL) { 152 | return i; 153 | } 154 | } 155 | syserr(ENFILE); 156 | return -1; 157 | } 158 | 159 | /* allocate a file structure and attach it with an 160 | * user file descriptor. 161 | * */ 162 | struct file* falloc(int fd){ 163 | struct file *fp; 164 | 165 | for(fp=&file[0]; fp<&file[NFILE]; fp++){ 166 | if (fp->f_count==0) { 167 | fp->f_count = 1; 168 | cu->p_ofile[fd] = fp; 169 | fp->f_offset = 0; 170 | fp->f_oflag = 0; 171 | return fp; 172 | } 173 | } 174 | syserr(EMFILE); 175 | panic("no free file structure\n"); 176 | return NULL; 177 | } 178 | -------------------------------------------------------------------------------- /src/fs/rdwr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // 6 | #include 7 | #include 8 | #include 9 | // 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | struct file file[NFILE]; 16 | /* 17 | * read a file via a file descriptor. 18 | * returns -1 on EOF and error 19 | * 20 | * TODO: consider special file later. 21 | * */ 22 | int do_read(int fd, char *buf, int cnt){ 23 | struct file *fp; 24 | struct inode *ip; 25 | uint dev; 26 | int r; 27 | 28 | fp = cu->p_ofile[fd]; 29 | if ( fd<0 || fd>NOFILE || fp==NULL ) { 30 | syserr(ENFILE); 31 | return -1; 32 | } 33 | // on write only 34 | if (fp->f_oflag & O_WRONLY) { 35 | syserr(EBADF); 36 | return -1; 37 | } 38 | 39 | ip = fp->f_ino; 40 | switch(ip->i_mode & S_IFMT) { 41 | case S_IFBLK: 42 | // TODO; 43 | break; 44 | case S_IFCHR: 45 | dev = ip->i_zone[0]; 46 | r = (*cdevsw[MAJOR(dev)].d_read)(dev, buf, cnt); 47 | break; 48 | case S_IFDIR: 49 | case S_IFREG: 50 | default: 51 | lock_ino(fp->f_ino); 52 | r = readi(ip, buf, fp->f_offset, cnt); 53 | } 54 | if (r < 0){ 55 | unlk_ino(ip); 56 | return -1; 57 | } 58 | fp->f_offset += cnt; 59 | unlk_ino(ip); 60 | return r; 61 | } 62 | 63 | int do_write(int fd, char *buf, int cnt){ 64 | struct file *fp; 65 | struct inode *ip; 66 | int r, off; 67 | uint dev; 68 | 69 | fp = cu->p_ofile[fd]; 70 | if ( fd<0 || fd>NOFILE || fp==NULL) { 71 | syserr(ENFILE); 72 | return -1; 73 | } 74 | // on read only 75 | if (fp->f_oflag & O_RDONLY) { 76 | syserr(EBADF); 77 | return -1; 78 | } 79 | // 80 | if (fp->f_oflag & O_APPEND) { 81 | off = fp->f_ino->i_size; 82 | } 83 | else { 84 | off = fp->f_offset; 85 | } 86 | // 87 | ip = fp->f_ino; 88 | switch(ip->i_mode & S_IFMT) { 89 | case S_IFBLK: 90 | // TODO: 91 | break; 92 | case S_IFCHR: 93 | dev = ip->i_zone[0]; 94 | r = (*cdevsw[MAJOR(dev)].d_write)(dev, buf, cnt); 95 | break; 96 | case S_IFDIR: 97 | case S_IFREG: 98 | default: 99 | lock_ino(ip); 100 | r = writei(ip, buf, off, cnt); 101 | } 102 | if (r < 0){ 103 | unlk_ino(ip); 104 | return -1; 105 | } 106 | fp->f_offset = off + cnt; 107 | unlk_ino(ip); 108 | return r; 109 | } 110 | 111 | /* 112 | * reposition the opened file asscociated with the file descriptor fd 113 | * to the argument off, according to the directive whence below: 114 | * SEEK_SET: set the offset as the argument off 115 | * SEEK_CUR: set the offset to its current location plus off bytes. 116 | * SEEK_END: set the offset to its size plus off bytes. 117 | * */ 118 | int do_lseek(uint fd, int off, int whence){ 119 | struct file *fp; 120 | 121 | fp = cu->p_ofile[fd]; 122 | if ((fd >= NOFILE) || (fp==NULL) || (fp->f_ino==NULL)) { 123 | syserr(EBADF); 124 | return -1; 125 | } 126 | if (fp->f_ino->i_mode & S_IFIFO) { 127 | syserr(ESPIPE); 128 | return -1; 129 | } 130 | 131 | if (whence==SEEK_SET) { 132 | if (off < 0) 133 | goto _einval; 134 | fp->f_offset = off; 135 | } 136 | if (whence==SEEK_CUR) { 137 | if (fp->f_offset+off < fp->f_offset) 138 | goto _einval; 139 | fp->f_offset += off; 140 | } 141 | if (whence==SEEK_END) { 142 | if (fp->f_ino->i_size+off < fp->f_ino->i_size) 143 | goto _einval; 144 | fp->f_offset = fp->f_ino->i_size + off; 145 | } 146 | return fp->f_offset; 147 | 148 | _einval: 149 | syserr(EINVAL); 150 | return -1; 151 | } 152 | 153 | -------------------------------------------------------------------------------- /src/fs/rdwri.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // 6 | #include 7 | #include 8 | // 9 | #include 10 | #include 11 | #include 12 | 13 | /* 14 | * this file indicated the read/write operations of the inodes. 15 | * TODO: ignored special files yet. 16 | * */ 17 | 18 | /* 19 | * read data from a locked inode. 20 | * returns -1 on error. 21 | * */ 22 | int readi(struct inode *ip, char *buf, uint off, uint cnt){ 23 | struct buf *bp; 24 | uint tot=0, m=0, bn=0; 25 | 26 | // file size limit 27 | if ((off > ip->i_size) || (off+cnt < off)){ 28 | cu->p_error = E2BIG; 29 | return -1; 30 | } 31 | if (off+cnt > ip->i_size) { 32 | cnt = ip->i_size - off; 33 | } 34 | // read 35 | for(tot=0; totb_data + off%BLK, 0, m); 40 | } 41 | else { 42 | bp = bread(ip->i_dev, bn); 43 | memcpy(buf, bp->b_data + off%BLK, m); 44 | brelse(bp); 45 | } 46 | } 47 | return cnt; 48 | } 49 | 50 | /* 51 | * write data to a regular file. 52 | * */ 53 | int writei(struct inode *ip, char *buf, uint off, uint cnt){ 54 | struct buf *bp; 55 | uint tot=0, m=0, bn=0; 56 | 57 | if (off+cnt < off){ 58 | return -1; 59 | } 60 | if (off+cnt > MAX_FILESIZ) { 61 | cnt = MAX_FILESIZ - off; 62 | } 63 | // do write. 64 | for(tot=0; toti_dev, bn); // note here! 72 | memcpy(bp->b_data + off%BLK, buf, m); 73 | bwrite(bp); 74 | brelse(bp); 75 | } 76 | } 77 | // adjust the inode's file size 78 | if (cnt > 0 && off > ip->i_size) { 79 | ip->i_size = off; 80 | iupdate(ip); 81 | } 82 | return cnt; 83 | } 84 | -------------------------------------------------------------------------------- /src/fs/super.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // 6 | #include 7 | #include 8 | // 9 | #include 10 | #include 11 | #include 12 | 13 | struct super mnt[NMOUNT] = { {0, }, }; 14 | 15 | /* search the mount table. 16 | * note: super block is meaningless until the device is mounted 17 | * */ 18 | struct super* getsp(ushort dev){ 19 | struct super *sp; 20 | 21 | _loop: 22 | for (sp=&mnt[0]; sp<&mnt[NMOUNT]; sp++){ 23 | if (dev == sp->s_dev) { 24 | if (sp->s_flag & S_LOCK) { 25 | sp->s_flag |= S_WANTED; 26 | sleep((uint)sp, PINOD); 27 | goto _loop; 28 | } 29 | return sp; 30 | } 31 | } 32 | panic("no fs"); 33 | return NULL; 34 | } 35 | 36 | /*****************************************************************/ 37 | 38 | /* read a super block from disk. 39 | * only called on mounting, an inode in-core. (reference count remains 40 | * but unlocked, it's released at sys_umount) 41 | * */ 42 | int spload(struct super *sp){ 43 | struct buf *bp; 44 | 45 | // read and check. 46 | bp = bread(sp->s_dev, 1); 47 | if ((bp->b_flag & B_ERROR)!=0){ 48 | panic("disk read error"); 49 | return -1; 50 | } 51 | memcpy(sp, bp->b_data, sizeof(struct d_super)); 52 | brelse(bp); 53 | if (sp->s_magic!=S_MAGIC) { 54 | panic("not an availible s_dev"); 55 | return -1; 56 | } 57 | sp->s_imnt = NULL; 58 | return 0; 59 | } 60 | 61 | /* 62 | * write changes back to disk. 63 | * */ 64 | void spupdate(struct super *sp){ 65 | struct buf *bp; 66 | 67 | bp = getblk(sp->s_dev, 1); 68 | memcpy(bp->b_data, (char*)sp, sizeof(struct d_super)); 69 | bwrite(bp); 70 | brelse(bp); 71 | } 72 | 73 | 74 | /* update all the fs */ 75 | void update(){ 76 | } 77 | 78 | /* ---------------------------------------------- */ 79 | 80 | /* 81 | * unlock(release) a super 82 | * */ 83 | void unlk_sp(struct super *sp){ 84 | cli(); 85 | if (sp->s_flag & S_WANTED) { 86 | wakeup((uint)sp); 87 | } 88 | sp->s_flag &= ~(S_LOCK | S_WANTED); 89 | sti(); 90 | } 91 | 92 | /* TODO: called on umount */ 93 | void putsp(struct super *sp){ 94 | unlk_sp(sp); 95 | } 96 | 97 | /******************************************************************/ 98 | 99 | /* debug */ 100 | void dump_super(struct super *sp){ 101 | printk("s_max_inode:%d\n", sp->s_max_inode); 102 | printk("s_max_zone:%d\n", sp->s_max_zone); 103 | printk("s_nimap_blk:%d\n", sp->s_nimap_blk); 104 | printk("s_nzmap_blk:%d\n", sp->s_nzmap_blk); 105 | printk("s_zone0:%d\n", sp->s_data_zone0); 106 | printk("s_log_bz:%d\n", sp->s_log_bz); 107 | printk("s_max_size:%d\n", sp->s_max_size); 108 | printk("s_magic:%x\n", sp->s_magic); 109 | } 110 | -------------------------------------------------------------------------------- /src/inc/a.out.h: -------------------------------------------------------------------------------- 1 | #ifndef A_OUT_H 2 | #define A_OUT_H 3 | 4 | struct ahead { 5 | uint a_magic; /* Use macros N_MAGIC, etc for access */ 6 | uint a_tsize; /* size of text, in bytes */ 7 | uint a_dsize; /* size of data, in bytes */ 8 | uint a_bsize; /* size of uninitialized data area for file, in bytes */ 9 | uint a_syms; /* size of symbol table data in file, in bytes */ 10 | uint a_entry; /* start address */ 11 | uint a_trsize; /* size of relocation info for text, in bytes */ 12 | uint a_drsize; /* size of relocation info for data, in bytes */ 13 | }; 14 | 15 | #define NMAGIC 0x6400CC 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/inc/asm.h: -------------------------------------------------------------------------------- 1 | /* all inlined. */ 2 | 3 | struct pde; 4 | 5 | /* 6 | * iodelay. On older machines its necessary to give the PIC some time to react to 7 | * commands as they might not be processed quickly. 8 | * */ 9 | static inline void io_delay(){ 10 | asm volatile ( 11 | "jmp 1f; 1: jmp 1f; 1:" 12 | ); 13 | } 14 | 15 | /* inb & outb */ 16 | static inline uchar inb(ushort port){ 17 | uchar ret; 18 | asm volatile( "inb %1, %0" : "=a" (ret) : "dN" (port)); 19 | io_delay(); 20 | return ret; 21 | } 22 | 23 | static inline void outb(ushort port, uchar data){ 24 | asm volatile( "outb %1, %0" :: "dN" (port), "a" (data)); 25 | io_delay(); 26 | } 27 | 28 | /* inw & outw */ 29 | static inline uchar inw(ushort port){ 30 | ushort ret; 31 | asm volatile( "inw %1, %0" : "=a" (ret) : "dN" (port)); 32 | io_delay(); 33 | return ret; 34 | } 35 | 36 | static inline void outw(ushort port, ushort data){ 37 | asm volatile( "outw %1, %0" :: "dN" (port), "a" (data)); 38 | io_delay(); 39 | } 40 | 41 | /* insb & outsb */ 42 | static inline void insb(uint port, void *addr, int cnt) { 43 | asm volatile( 44 | "cld;" "repne;" "insb" 45 | :"=D" (addr), "=c" (cnt) 46 | :"d" (port), "0" (addr), "1" (cnt) 47 | :"memory", "cc"); 48 | io_delay(); 49 | } 50 | 51 | static inline void outsb(uint port, void *addr, int cnt) { 52 | asm volatile("cld;" "repne;" "outsb" 53 | :"=S" (addr), "=c" (cnt) 54 | :"d" (port), "0" (addr), "1" (cnt) 55 | :"cc"); 56 | io_delay(); 57 | } 58 | 59 | /* insl & outsl */ 60 | static inline void insl(uint port, void *addr, int cnt) { 61 | asm volatile( 62 | "cld;" "repne;" "insl" 63 | :"=D" (addr), "=c" (cnt) 64 | :"d" (port), "0" (addr), "1" (cnt) 65 | :"memory", "cc"); 66 | io_delay(); 67 | } 68 | 69 | static inline void outsl(uint port, void *addr, int cnt) { 70 | asm volatile("cld;" "repne;" "outsl" 71 | :"=S" (addr), "=c" (cnt) 72 | :"d" (port), "0" (addr), "1" (cnt) 73 | :"cc"); 74 | io_delay(); 75 | } 76 | 77 | /* -------------------------------------------- */ 78 | 79 | /* load TSS into tr */ 80 | static inline void ltr(uint n){ 81 | asm volatile("ltr %%ax"::"a"(n)); 82 | } 83 | 84 | static inline void lldt(uint n){ 85 | asm volatile("lldt %%ax"::"a"(n)); 86 | } 87 | 88 | /* flush the page directory */ 89 | static inline void lpgd(struct pde *pgdir){ 90 | asm volatile("mov %%eax, %%cr3":: "a"((uint)pgdir)); 91 | } 92 | 93 | /* set the cr0 bit and enable mmu */ 94 | static inline void mmu_enable(){ 95 | uint cr0, cr4; 96 | asm volatile("mov %%cr4, %0": "=r"(cr4)); 97 | cr4 |= 0x10; // set PSE, enable 4mb page 98 | asm volatile("mov %0, %%cr4":: "r"(cr4)); 99 | // 100 | asm volatile("mov %%cr0, %0": "=r"(cr0)); 101 | cr0 |= 0x80000000; // set the paging bit. 102 | asm volatile("mov %0, %%cr0":: "r"(cr0)); 103 | } 104 | 105 | /* ------------------------------------------------- */ 106 | 107 | 108 | /* load TSS into tr */ 109 | static inline void cli(){ 110 | asm volatile("cli"); 111 | } 112 | 113 | static inline void sti(){ 114 | asm volatile("sti"); 115 | } 116 | 117 | /* ---------------------------------------------- */ 118 | 119 | 120 | /* 121 | * ljmp seg, offset...Lovely little instruction. 122 | * But seg seems only availible for immediate value at compile time. 123 | * Tricks needed, *Sucks*. 124 | * */ 125 | static inline void ljmp(ushort seg, uint offset){ 126 | struct{ uint offset, seg; } _tmp; 127 | _tmp.offset = offset; 128 | _tmp.seg = seg; 129 | asm volatile( 130 | "ljmp %0" 131 | ::"m"(_tmp) 132 | ); 133 | } 134 | 135 | static inline void lcall(ushort seg, uint offset){ 136 | struct{ uint offset, seg; } _tmp; 137 | _tmp.offset = offset; 138 | _tmp.seg = seg; 139 | asm volatile( 140 | "lcall %0" 141 | ::"m"(_tmp) 142 | ); 143 | } 144 | -------------------------------------------------------------------------------- /src/inc/buf.h: -------------------------------------------------------------------------------- 1 | /* */ 2 | #ifndef BUF_H 3 | #define BUF_H 4 | 5 | struct buf { 6 | uint b_flag; 7 | struct buf *b_next; 8 | struct buf *b_prev; 9 | struct buf *av_next; 10 | struct buf *av_prev; 11 | short b_dev; 12 | uint b_blkno; 13 | char *b_data; 14 | int b_error; 15 | }; 16 | 17 | extern struct buf buff[NBUF]; 18 | 19 | /* 20 | * Each block device has a devtab, which contains private 21 | * state stuff and 2 list head: the b_head/b_tail list, 22 | * which is doubly linked and has all the buffers currently 23 | * associated with that major device; 24 | * and the av_head/av_tail list, which is private to the 25 | * device but in fact is always used for the head and tail 26 | * of the IO queue for the device. 27 | * Various routines in bio.c look at b_head/b_tail 28 | * but the rest is private to each device driver. 29 | * 30 | * note: Little trick here, devtab's header can be also 31 | * visited via a struct buf *. 32 | * */ 33 | struct devtab { 34 | uint d_active; /* busy flags */ 35 | struct buf *b_next; /* first buf for this dev */ 36 | struct buf *b_prev; /* last buf for this dev */ 37 | struct buf *av_next; /* head of IO queue */ 38 | struct buf *av_prev; /* tail of IO queue */ 39 | uint d_errcnt; /* error count (for recovery) */ 40 | }; 41 | 42 | /* 43 | * This is the head of the freelist. 44 | * */ 45 | extern struct buf bfreelist; 46 | 47 | #define B_WRITE 0x0 48 | #define B_READ 0x1 49 | #define B_DONE 0x2 50 | #define B_ERROR 0x4 51 | #define B_BUSY 0x8 52 | #define B_WANTED 0x10 53 | #define B_DIRTY 0x20 54 | #define B_ASYNC 0x40 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/inc/cmos.h: -------------------------------------------------------------------------------- 1 | /* some codes are copied from Linux-0.11, thank you linus. 2 | * */ 3 | 4 | #define RTC_SEC 0 5 | #define RTC_MIN 2 6 | #define RTC_HOUR 4 7 | #define RTC_MDAY 7 8 | #define RTC_MONTH 8 9 | #define RTC_YEAR 9 10 | #define RTC_CENTURY 0x32 11 | #define RTC_STAT_A 0xA 12 | #define RTC_STAT_B 0xB 13 | 14 | #define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10) 15 | 16 | #define MINUTE 60 17 | #define HOUR (60*MINUTE) 18 | #define DAY (24*HOUR) 19 | #define YEAR (365*DAY) 20 | 21 | static int monthtab[12] = { 22 | 0, 23 | DAY*(31), 24 | DAY*(31+29), 25 | DAY*(31+29+31), 26 | DAY*(31+29+31+30), 27 | DAY*(31+29+31+30+31), 28 | DAY*(31+29+31+30+31+30), 29 | DAY*(31+29+31+30+31+30+31), 30 | DAY*(31+29+31+30+31+30+31+31), 31 | DAY*(31+29+31+30+31+30+31+31+30), 32 | DAY*(31+29+31+30+31+30+31+31+30+31), 33 | DAY*(31+29+31+30+31+30+31+31+30+31+30) 34 | }; 35 | 36 | -------------------------------------------------------------------------------- /src/inc/conf.h: -------------------------------------------------------------------------------- 1 | /* */ 2 | 3 | #ifndef CONF_H 4 | #define CONF_H 5 | 6 | struct buf; 7 | 8 | struct bdevsw { 9 | int (*d_open)(); 10 | int (*d_close)(); 11 | int (*d_request)(struct buf *bp); 12 | struct devtab *d_tab; 13 | }; 14 | 15 | extern struct bdevsw bdevsw[NBLKDEV]; 16 | 17 | struct cdevsw { 18 | int (*d_open) (ushort dev); 19 | int (*d_close) (ushort dev); 20 | int (*d_read) (ushort dev, char *buf, uint cnt); 21 | int (*d_write) (ushort dev, char *buf, uint cnt); 22 | int (*d_sgtty)(); 23 | }; 24 | 25 | extern struct cdevsw cdevsw[NCHRDEV]; 26 | 27 | #define MAJOR(num) ((uchar)((num>>8)&0xFF)) 28 | #define MINOR(num) ((uchar)((num)&0xFF)) 29 | 30 | /* dev number is an ushort */ 31 | #define DEVNO(major, minor) ((ushort)(((uchar)major<<8) + (uchar)minor)) 32 | 33 | #define NODEV (DEVNO(0,0)) 34 | 35 | extern ushort rootdev; 36 | extern ushort swapdev; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/inc/dirent.h: -------------------------------------------------------------------------------- 1 | #ifndef DIRENT_H 2 | #define DIRENT_H 3 | 4 | /* directory entry */ 5 | #define NAMELEN 12 6 | 7 | struct dirent { 8 | ushort d_ino; 9 | char d_name[NAMELEN]; 10 | char __p[18]; /* a padding. each dirent is aligned with a 32 bytes boundary. */ 11 | }; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/inc/file.h: -------------------------------------------------------------------------------- 1 | #ifndef FILE_H 2 | #define FILE_H 3 | 4 | #include 5 | 6 | struct file { 7 | char f_oflag; 8 | char f_count; 9 | uint f_offset; 10 | struct inode *f_ino; 11 | }; 12 | 13 | extern struct file file[NFILE]; 14 | 15 | /* flags in open/fcntl */ 16 | #define O_ACCMODE 0x3 17 | 18 | #define O_RDONLY 0x0 // read only 19 | #define O_WRONLY 0x1 // write only 20 | #define O_RDWR 0x2 // read / write 21 | #define O_APPEND 0x40 // 22 | /* the rest can not be modified by fcntl */ 23 | #define O_CREAT 0x4 // creat a new file. 24 | #define O_EXCL 0x8 // a execulsive open 25 | #define O_NOCTTY 0x10 // 26 | #define O_TRUNC 0x20 // 27 | #define O_NONBLOCK 0x80 // 28 | 29 | /* fcntl */ 30 | #define F_DUPFD 0 /* dup */ 31 | #define F_GETFD 1 /* seems only FD_CLOEXEC associated with this. */ 32 | #define F_SETFD 2 33 | #define F_GETFL 3 /* get f_flag */ 34 | #define F_SETFL 4 /* set f_flag */ 35 | #define F_GETLK 5 /* aquire a lock. (not implemented) */ 36 | #define F_SETLK 6 37 | #define F_SETLKW 7 38 | 39 | #define FD_CLOEXEC 1 /* close this file on exec. (not implemented) */ 40 | 41 | /* seek */ 42 | #define SEEK_SET 0 43 | #define SEEK_CUR 1 44 | #define SEEK_END 2 45 | 46 | /* access */ 47 | #define F_OK 0 48 | #define X_OK 1 49 | #define W_OK 2 50 | #define R_OK 4 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/inc/gdt.h: -------------------------------------------------------------------------------- 1 | /* This file is modified from xv6 */ 2 | 3 | struct seg_desc { 4 | uint limit_lo:16; // Low bits of segment limit 5 | uint base_lo :16; // Low bits of segment base address 6 | uint base_mi :8; // Middle bits of segment base address 7 | uint type :4; // Segment type (see STS_ constants) 8 | uint s :1; // 0 = system, 1 = application 9 | uint dpl :2; // Descriptor Privilege Level 10 | uint present :1; // Present 11 | uint limit_hi:4; // High bits of segment limit 12 | uint avl :1; // Unused (available for software use) 13 | uint r :1; // Reserved 14 | uint db :1; // 0 = 16-bit segment, 1 = 32-bit segment 15 | uint g :1; // Granularity: limit scaled by 4K when set 16 | uint base_hi :8; // High bits of segment base address 17 | }; 18 | 19 | struct gdt_desc { 20 | ushort limit; 21 | uint base; 22 | } __attribute__((packed)); 23 | 24 | // Application segment type bits 25 | #define STA_X 0x8 // Executable segment 26 | #define STA_E 0x4 // Expand down (non-executable segments) 27 | #define STA_C 0x4 // Conforming code segment (executable only) 28 | #define STA_W 0x2 // Writeable (non-executable segments) 29 | #define STA_R 0x2 // Readable (executable segments) 30 | #define STA_A 0x1 // Accessed 31 | 32 | // System segment type bits 33 | #define STS_LDT 0x2 // Local Descriptor Table 34 | #define STS_TG 0x5 // Task Gate / Coum Transmitions 35 | #define STS_TA 0x9 // Available 32-bit TSS 36 | #define STS_TB 0xB // Busy 32-bit TSS 37 | #define STS_CG 0xC // 32-bit Call Gate 38 | #define STS_IG 0xE // 32-bit Interrupt Gate 39 | #define STS_TRG 0xF // 32-bit Trap Gate 40 | 41 | /* selectors */ 42 | #define KERN_CS (1<<3) 43 | #define KERN_DS (2<<3) 44 | #define USER_CS ((3<<3)|3) 45 | #define USER_DS ((4<<3)|3) 46 | 47 | #define TSS0 5 48 | #define _TSS (TSS0<<3) 49 | #define LDT0 6 50 | #define _LDT(n) ((LDT0+n)<<3) 51 | -------------------------------------------------------------------------------- /src/inc/hd.h: -------------------------------------------------------------------------------- 1 | /* */ 2 | 3 | extern struct devtab hdtab; 4 | 5 | /* TODO: add partition support 6 | * note: the first entry is the whole device 7 | * */ 8 | struct hd_minor { 9 | uint m_hd; 10 | uint m_start; 11 | uint m_limit; 12 | }; 13 | 14 | extern struct hd_minor hd_minor[16]; 15 | 16 | #define HD_STAT 0x1F7 17 | #define HD_CMD 0x1F7 18 | 19 | /* commands for HD_CMD */ 20 | #define HD_CMD_READ 0x20 21 | #define HD_CMD_WRITE 0x30 22 | 23 | /* flags for HD_STAT */ 24 | #define HD_BSY 0x80 25 | #define HD_DRDY 0x40 //Device Ready 26 | #define HD_DF 0x20 //Device Fault 27 | #define HD_ERR 0x01 28 | 29 | 30 | int hd_request(); 31 | int nulldev(); 32 | int nodev(); 33 | -------------------------------------------------------------------------------- /src/inc/idt.h: -------------------------------------------------------------------------------- 1 | /* this file is modified from xv6 */ 2 | 3 | #ifndef IDT_H 4 | #define IDT_H 5 | 6 | struct gate_desc { 7 | uint base_lo :16; // low address 8 | uint sel :16; // selector 9 | uint always0 :8; // reserved 10 | uint type :4; // type(STS_{TG,IG32,TG32}) 11 | uint sys :1; // must be 0 (system) 12 | uint dpl :2; // descriptor(meaning new) privilege level 13 | uint p :1; // Present 14 | uint base_hi :16; // high address 15 | } __attribute__((packed)); 16 | 17 | struct idt_desc { 18 | ushort limit; 19 | uint base; 20 | } __attribute__((packed)); 21 | 22 | struct trap { 23 | int gs, fs, es, ds; /* pushed the segs last */ 24 | int edi, esi, ebp, _esp, ebx, edx, ecx, eax; /* pushed by 'pusha', note the esp here is ignored. */ 25 | int int_no, err_code; /* our 'push byte #' and ecodes do this */ 26 | int eip, cs, eflags, esp, ss; /* pushed by the processor automatically */ 27 | } __attribute__((packed)); 28 | 29 | /* constants on PIC */ 30 | 31 | #define IRQ0 32 32 | #define IRQ_SLAVE 2 33 | 34 | #define PIC1 0x20 35 | #define PIC2 0xA0 36 | 37 | #define PIC1_CMD PIC1 38 | #define PIC2_CMD PIC2 39 | #define PIC1_DATA (PIC1+1) 40 | #define PIC2_DATA (PIC2+1) 41 | 42 | #define PIC_EOI 0x20 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/inc/inode.h: -------------------------------------------------------------------------------- 1 | #ifndef INODE_H 2 | #define INODE_H 3 | 4 | /* 5 | * the Minix v1 fs, you could build one via mkfs.minix under linux. 6 | * */ 7 | 8 | struct d_inode { 9 | ushort i_mode; /* file type, protection, etc. */ 10 | ushort i_uid; 11 | uint i_size; /* current file size in bytes */ 12 | uint i_mtime; 13 | uchar i_gid; 14 | uchar i_nlinks; /* how many links to this file. */ 15 | ushort i_zone[9]; /* zones number for direct, indirect and double indirect. */ 16 | }; 17 | 18 | struct inode { 19 | ushort i_mode; 20 | ushort i_uid; 21 | uint i_size; 22 | uint i_mtime; 23 | uchar i_gid; 24 | uchar i_nlink; 25 | ushort i_zone[9]; 26 | /* the rest only lies in core */ 27 | ushort i_atime; /* not used yet */ 28 | ushort i_ctime; /* not used yet */ 29 | ushort i_count; /* reference count*/ 30 | ushort i_dev; /* dev number */ 31 | uint i_num; /* inode number */ 32 | uint i_flag; 33 | }; 34 | 35 | extern struct inode inode[NINODE]; 36 | 37 | /* flags */ 38 | #define I_LOCK 0x1 /* for synchronize */ 39 | #define I_WANTED 0x2 /* - */ 40 | #define I_DIRTY 0x4 /* this inode has been modified*/ 41 | #define I_MOUNT 0x8 /* - */ 42 | #define I_TEXT 0x10 /* this inode is a running executable */ 43 | 44 | /* i_mode resides in stat.h */ 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/inc/keybd.h: -------------------------------------------------------------------------------- 1 | #ifndef KEYBD_H 2 | #define KEYBD_H 3 | 4 | #define KB_STAT 0x64 5 | #define KB_DATA 0x60 6 | 7 | #define KB_STAT_DIB 0x1 /* got data in buffer. */ 8 | 9 | // Special keycodes 10 | #define KEY_HOME 0xE0 11 | #define KEY_END 0xE1 12 | #define KEY_UP 0xE2 13 | #define KEY_DN 0xE3 14 | #define KEY_LF 0xE4 15 | #define KEY_RT 0xE5 16 | #define KEY_PGUP 0xE6 17 | #define KEY_PGDN 0xE7 18 | #define KEY_INS 0xE8 19 | #define KEY_DEL 0xE9 20 | 21 | static uchar keybd_map[256] = { 22 | NUL, 0x1B, '1', '2', '3', '4', '5', '6', // 0x00 23 | '7', '8', '9', '0', '-', '=', '\b', '\t', 24 | 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', // 0x10 25 | 'o', 'p', '[', ']', '\n', NUL, 'a', 's', 26 | 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', // 0x20 27 | '\'', '`', NUL, '\\', 'z', 'x', 'c', 'v', 28 | 'b', 'n', 'm', ',', '.', '/', NUL, '*', // 0x30 29 | NUL, ' ', NUL, NUL, NUL, NUL, NUL, NUL, 30 | NUL, NUL, NUL, NUL, NUL, NUL, NUL, '7', // 0x40 31 | '8', '9', '-', '4', '5', '6', '+', '1', 32 | '2', '3', '0', '.', NUL, NUL, NUL, NUL, // 0x50 33 | [0x9C] '\n', // KP_Enter 34 | [0xB5] '/', // KP_Div 35 | [0xC8] KEY_UP, [0xD0] KEY_DN, 36 | [0xC9] KEY_PGUP, [0xD1] KEY_PGDN, 37 | [0xCB] KEY_LF, [0xCD] KEY_RT, 38 | [0x97] KEY_HOME, [0xCF] KEY_END, 39 | [0xD2] KEY_INS, [0xD3] KEY_DEL 40 | }; 41 | 42 | static uchar shift_map[256] = { 43 | NUL, 033, '!', '@', '#', '$', '%', '^', // 0x00 44 | '&', '*', '(', ')', '_', '+', '\b', '\t', 45 | 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', // 0x10 46 | 'O', 'P', '{', '}', '\n', NUL, 'A', 'S', 47 | 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', // 0x20 48 | '"', '~', NUL, '|', 'Z', 'X', 'C', 'V', 49 | 'B', 'N', 'M', '<', '>', '?', NUL, '*', // 0x30 50 | NUL, ' ', NUL, NUL, NUL, NUL, NUL, NUL, 51 | NUL, NUL, NUL, NUL, NUL, NUL, NUL, '7', // 0x40 52 | '8', '9', '-', '4', '5', '6', '+', '1', 53 | '2', '3', '0', '.', NUL, NUL, NUL, NUL, // 0x50 54 | [0x9C] '\n', // KP_Enter 55 | [0xB5] '/', // KP_Div 56 | [0xC8] KEY_UP, [0xD0] KEY_DN, 57 | [0xC9] KEY_PGUP, [0xD1] KEY_PGDN, 58 | [0xCB] KEY_LF, [0xCD] KEY_RT, 59 | [0x97] KEY_HOME, [0xCF] KEY_END, 60 | [0xD2] KEY_INS, [0xD3] KEY_DEL 61 | }; 62 | 63 | /* status of shift, ctrl & alt */ 64 | #define SHIFT 0x1 65 | #define CTRL 0x2 66 | #define ALT 0x4 67 | #define E0ESC 0x8 68 | #define CAPSLOCK 0x10 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/inc/lib.h: -------------------------------------------------------------------------------- 1 | #ifndef LIB_H 2 | #define LIB_H 3 | 4 | #ifndef NULL 5 | #define NULL ((void*)0) 6 | #endif 7 | 8 | /* prototypes */ 9 | 10 | /* string */ 11 | void* memcpy(void *dest, void *src, unsigned int count); 12 | void* memset(void *dest, char val, unsigned int count); 13 | short* memsetw(short *dest, short val, unsigned int count); 14 | int strlen(char *str); 15 | int strnlen(char *str, unsigned int size); 16 | char* strcpy(char *dst, const char *src); 17 | char* strncpy(char *dst, const char *src, unsigned int cnt); 18 | char* strchr(const char *str, int c); 19 | char* strrchr(const char *str, int c); 20 | int strcmp(char *s1, char *s2); 21 | int strncmp(char *s1, char* s2, unsigned int n); 22 | 23 | /* bitmap */ 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/inc/malloc.h: -------------------------------------------------------------------------------- 1 | #ifndef MALLOC_H 2 | #define MALLOC_H 3 | 4 | struct bkentry { 5 | struct bkentry *bke_next; 6 | }; 7 | 8 | /* each bucket is associated with one page-size memory. */ 9 | struct bucket { 10 | uint bk_size; // each entry's size of this bucket 11 | uint bk_page; // the virtual address of each bucket's page. 12 | struct bucket *bk_next; // the next bucket (each bucket page memory) 13 | struct bkentry *bk_entry; // the first free entry of this bucket, NULL on full. 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/inc/mmu.h: -------------------------------------------------------------------------------- 1 | /* this file is modified from xv6 */ 2 | 3 | #ifndef MMU_H 4 | #define MMU_H 5 | 6 | struct pde { 7 | uint pd_flag:9; 8 | uint pd_avl:3; 9 | uint pd_off:20; 10 | }; 11 | 12 | struct pte { 13 | uint pt_flag:9; 14 | uint pt_avl:3; 15 | uint pt_off:20; 16 | }; 17 | 18 | // Page table/directory entry flags. 19 | #define PTE_P 0x001 // Present 20 | #define PTE_W 0x002 // Writeable 21 | #define PTE_U 0x004 // User 22 | #define PTE_PWT 0x008 // Write-Through 23 | #define PTE_PCD 0x010 // Cache-Disable 24 | #define PTE_A 0x020 // Accessed 25 | #define PTE_D 0x040 // Dirty 26 | #define PTE_PS 0x080 // Page Size 27 | #define PTE_MBZ 0x180 // Bits must be zero 28 | 29 | /* 30 | * A linear address 'la' has a three-part structure as follows: 31 | * 32 | * +--------10------+-------10-------+---------12----------+ 33 | * | Page Directory | Page Table | Offset within Page | 34 | * | Index | Index | | 35 | * +----------------+----------------+---------------------+ 36 | * \--- PDX(la) --/ \--- PTX(la) --/ \---- POFF(la) ----/ 37 | * \----------- PPN(la) -----------/ 38 | **/ 39 | 40 | #define PDX(la) ((uint)((la>>22)&0x3FF)) 41 | #define PTX(la) ((uint)((la>>12)&0x3FF)) 42 | #define POFF(la) ((uint)((la&0xFFF))) 43 | #define PPN(la) (((uint) (la)) >> 12) 44 | 45 | #define PG_ADDR(addr) ((uint)(addr) & ~0xFFF) 46 | 47 | /* CR2 stores the virtual address on which raised the page fault. 48 | * error code stores inside the trap frame. 49 | * */ 50 | 51 | // Page Fault error code flags 52 | #define PFE_P 0x001 // Causing the fault was not a Present page 53 | #define PFE_W 0x002 // Causing the fault was on a Wirite 54 | #define PFE_U 0x004 // The fault was caused in User mode 55 | #define PFE_RSVD 0x008 // The Fault was caused by reserved bits set to 1 in a page directory 56 | #define PFE_I 0x010 // The Fault was caused on a instruction fetch. 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/inc/page.h: -------------------------------------------------------------------------------- 1 | 2 | struct page { 3 | uchar pg_flag; 4 | uchar pg_count; /* ref count */ 5 | ushort pg_num; 6 | struct page *pg_next; 7 | }; 8 | 9 | extern struct page pgfreelist; 10 | extern struct page coremap[NPAGE]; 11 | 12 | #define PG_RSVD 0x2 // reserved pages, like kernel memory & bios 13 | #define PG_DMAP 0x4 // TODO: directed mapped to physical addresses 14 | 15 | -------------------------------------------------------------------------------- /src/inc/param.h: -------------------------------------------------------------------------------- 1 | typedef unsigned char uchar; 2 | typedef unsigned short ushort; 3 | typedef unsigned int uint; 4 | 5 | #define PBLK 512 /* physical block size */ 6 | #define BLK 1024 /* logical block size */ 7 | #define PAGE 0x1000 8 | 9 | #define PMEM 0x8000000 /* 128mb physical memory. */ 10 | #define KMEM_END 0x8000000 /* 128mb, the kernel's address space. */ 11 | #define KHEAP 0x300000 /* kernel's heap starts at 3mb. */ 12 | #define KSTACK0 0x1000 /* proc0's stack, takes one page and grows downward. */ 13 | 14 | #define ROOTINO 1 15 | 16 | #define NSYSC 64 17 | #define NPROC 64 18 | #define NSEG 6 19 | #define NBUF (0x200000/BLK) /* buffers take 2mb */ 20 | #define NBLKDEV 2 21 | #define NCHRDEV 2 22 | #define NCCS 17 23 | #define NINODE 128 24 | #define NFILE 128 25 | #define NOFILE 16 26 | #define NMOUNT 16 27 | #define NTTY 8 28 | #define NKPAGE (LO_MEM/PAGE) 29 | #define NPAGE (PMEM/PAGE) 30 | 31 | #define NINDBLK (BLK/sizeof(ushort)) 32 | #define MAX_FILESIZ ((7+NINDBLK+NINDBLK*NINDBLK)*BLK) 33 | #define MAX_PATHSIZ PAGE 34 | 35 | #define NULL ((void*)0) 36 | #define NUL 0 37 | 38 | extern char __kend__; 39 | 40 | #include 41 | -------------------------------------------------------------------------------- /src/inc/proc.h: -------------------------------------------------------------------------------- 1 | #ifndef PROC_H 2 | #define PROC_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* 11 | * struct proc indicated some info on sched. 12 | * */ 13 | struct proc { 14 | char p_stat; 15 | char p_flag; 16 | uint p_chan; /* the event channel which proc is awaiting */ 17 | int p_pri; /* on shedule */ 18 | int p_cpu; /* - */ 19 | int p_nice; /* - */ 20 | int p_time; /* on swap */ 21 | uint p_pid; 22 | uint p_ppid; /* parent's pid */ 23 | uint p_pgrp; /* process group */ 24 | uint p_euid; /* effective uid */ 25 | uint p_egid; /* effective gid */ 26 | uint p_ruid; /* real uid */ 27 | uint p_rgid; /* real gid */ 28 | uint p_umask; /* umask for files */ 29 | uint p_sig; /* a bitmap of the recieved signals */ 30 | uint p_sigmask; /* a bitmap of the blocked(masked) signals */ 31 | uint p_cursig; /* the current signal to be delivered */ 32 | char p_ret; /* the exit code */ 33 | uint p_error; /* the returned error code from a syscall. */ 34 | struct sigaction p_sigact[NSIG]; /* signal handlers */ 35 | struct inode *p_wdir; /* current working dir */ 36 | struct inode *p_iroot; /* the root dir */ 37 | struct file *p_ofile[NOFILE]; /* file desciptors of the current opened files */ 38 | uint p_fdflag[NOFILE]; /* flags for the file descriptors(only FD_CLOEXEC yet), which is proc specific */ 39 | struct vm p_vm; 40 | struct jmp_buf p_contxt; /* - */ 41 | struct trap *p_trap; /* saved on entering kernel from user, for psig(). */ 42 | }; 43 | 44 | extern struct proc *proc[NPROC]; 45 | 46 | extern struct proc *cu; 47 | 48 | /* flag for re-scheduling */ 49 | extern uint runrun; 50 | 51 | /* stat codes */ 52 | #define SSLEEP 1 // sleeping on high priority (unitterruptible) 53 | #define SWAIT 2 // sleeping on low priority (interruptible) 54 | #define SRUN 3 // running 55 | #define SZOMB 4 // proc is being terminated 56 | #define SSTOP 5 // proc is being traced 57 | 58 | /* flag codes */ 59 | #define SLOAD 0x1 // in core 60 | #define SSYS 0x2 // sheduling proc 61 | #define SLOCK 0x4 // proc cannot be swapped 62 | #define SSWAP 0x8 // proc is being swapped out 63 | #define STRC 0x10 // proc is being traced 64 | #define SWTED 0x20 // another tracing flag 65 | 66 | /* priorities 67 | * probably should not be altered too much. 68 | */ 69 | #define PSWP (-100) 70 | #define PINOD (-90) 71 | #define PRIBIO (-50) 72 | #define PPIPE 1 73 | #define PRITTY 10 74 | #define PWAIT 40 75 | #define PSLEP 90 76 | #define PUSER 100 77 | 78 | /* options for waitpid, WUNTRACED not supported */ 79 | #define WNOHANG 1 80 | #define WUNTRACED 2 81 | 82 | /* error codes */ 83 | #define ERROR 99 84 | #define EPERM 1 85 | #define ENOENT 2 86 | #define ESRCH 3 87 | #define EINTR 4 88 | #define EIO 5 89 | #define ENXIO 6 90 | #define E2BIG 7 91 | #define ENOEXEC 8 92 | #define EBADF 9 93 | #define ECHILD 10 94 | #define EAGAIN 11 95 | #define ENOMEM 12 96 | #define EACCES 13 97 | #define EFAULT 14 98 | #define ENOTBLK 15 99 | #define EBUSY 16 100 | #define EEXIST 17 101 | #define EXDEV 18 102 | #define ENODEV 19 103 | #define ENOTDIR 20 104 | #define EISDIR 21 105 | #define EINVAL 22 106 | #define ENFILE 23 107 | #define EMFILE 24 108 | #define ENOTTY 25 109 | #define ETXTBSY 26 110 | #define EFBIG 27 111 | #define ENOSPC 28 112 | #define ESPIPE 29 113 | #define EROFS 30 114 | #define EMLINK 31 115 | #define EPIPE 32 116 | #define EDOM 33 117 | #define ERANGE 34 118 | #define EDEADLK 35 119 | #define ENAMETOOLONG 36 120 | #define ENOLCK 37 121 | #define ENOSYS 38 122 | #define ENOTEMPTY 39 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /src/inc/proto.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTO_H 2 | #define PROTO_H 3 | 4 | struct trap; 5 | struct seg_desc; 6 | struct inode; 7 | struct pde; 8 | struct super; 9 | struct sigaction; 10 | struct proc; 11 | struct vm; 12 | struct tty; 13 | struct stat; 14 | struct jmp_buf; 15 | struct ahead; 16 | 17 | // tty.c 18 | void tty_init(); 19 | void cls(); 20 | void putch(char ch); 21 | void puts(char *ch); 22 | void printk(char *fmt, ...); 23 | 24 | // sched.c 25 | void wakeup(uint chan); 26 | void sleep(uint chan, int pri); 27 | void swtch(); 28 | void swtch_to(struct proc *to); 29 | void sched_cpu(); 30 | void setpri(struct proc *p); 31 | void setrun(struct proc *p); 32 | 33 | // entry.S 34 | void _do_swtch(struct jmp_buf *old, struct jmp_buf *new); 35 | void _retu(uint eip, uint esp3); 36 | 37 | // sysent.c 38 | int syserr(uint err); 39 | uint suser(); 40 | int nosys(struct trap *tf); 41 | 42 | // trap.c 43 | void idt_init(); 44 | void irq_enable(uchar irq); 45 | void set_hwint(int nr, int (*func)(struct trap *tf)); 46 | 47 | // seg.c 48 | uint get_seg_limit(struct seg_desc *seg); 49 | extern struct seg_desc gdt[]; 50 | void gdt_init(); 51 | 52 | // kern/fork.c 53 | void proc0_init(); 54 | int do_fork(struct trap *tf); 55 | struct proc* kspawn(void (*func)()); 56 | int find_pid(); 57 | 58 | // kern/wait.c 59 | int do_waitpid(int pid, int *stat, int opt); 60 | 61 | // kern/exit.c 62 | int do_exit(int ret); 63 | 64 | // mm/pm.c 65 | void mm_init(); 66 | int do_pgfault(struct trap *tf); 67 | struct page* pgalloc(); 68 | struct page* pgfind(uint pn); 69 | int pgfree(struct page *pp); 70 | struct pte* pgattach(struct pde *pgd, uint vaddr, struct page *pp, uint flag); 71 | 72 | // mm/pgfault.c 73 | void do_no_page(uint vaddr); 74 | void do_wp_page(uint vaddr); 75 | 76 | // timer.c 77 | uint time(); 78 | void timer_init(); 79 | 80 | // kern/syscall.c 81 | int do_syscall(struct trap* tf); 82 | void ltr(uint n); 83 | void lldt(uint n); 84 | void ljmp(ushort seg, uint offset); 85 | 86 | // kern/exec.c 87 | int upush(uint *esp, char *buf, int len); 88 | int upush_argv(uint *esp, char *tmp[]); 89 | int do_exec(char *path, char **argv); 90 | 91 | // kern/signal.c 92 | int issig(); 93 | void psig(); 94 | int sigsend(int pid, int n, int priv); 95 | int sigsend_g(int pgrp, int n, int priv); 96 | int do_kill(int pid, int sig); 97 | int do_signal(int sig, void (*ufunc)(int)); 98 | int do_sigaction(int sig, struct sigaction *sa, struct sigaction *old_sa); 99 | void usigsav(struct jmp_buf *buf, struct trap *tf, uint mask); 100 | 101 | // mm/vm.c 102 | int vm_verify(void* vaddr, uint size); 103 | int vm_clone(struct vm *to); 104 | int vm_clear(struct vm *vm); 105 | int vm_renew(struct vm *vm, struct ahead *ah, struct inode *ip); 106 | struct vma* find_vma(uint addr); 107 | int vma_init(struct vma *vp, uint base, uint size, uint flag, struct inode *ip, uint ioff); 108 | 109 | // mm/pte.c 110 | int pgd_init(struct pde *pgd); 111 | struct pte* find_pte(struct pde *pgd, uint vaddr, uint creat); 112 | int pt_free(struct pde *pgd); 113 | int pt_copy(struct pde *npgd, struct pde *opgd); 114 | void flmmu(); 115 | 116 | // mm/malloc.c 117 | void* kmalloc(uint size); 118 | int kfree(void* addr, uint size); 119 | 120 | // drv/bio.c 121 | int nodev(); 122 | int nulldev(); 123 | 124 | // blk/buf.c 125 | void buf_init(); 126 | struct buf* bread(int dev, uint blkno); 127 | void brelse(struct buf *bp); 128 | void bwrite(struct buf *bp); 129 | struct buf* getblk(int dev, uint blkno); 130 | void iodone(struct buf *bp); 131 | void iowait(struct buf *bp); 132 | void notavail(struct buf *bp); 133 | 134 | // blk/hd.c 135 | int hd_wait_ready(); 136 | void hd_start(); 137 | void hd_init(); 138 | int hd_cmd(uint drive, uint cmd, uint lba, uchar ns); 139 | int hd_request(struct buf *bp); 140 | int hd_wait_ready(); 141 | int do_hd_intr(struct trap *tf); 142 | 143 | 144 | // fs/rdwri.c 145 | int readi(struct inode *ip, char *buf, uint off, uint cnt); 146 | int writei(struct inode *ip, char *buf, uint off, uint cnt); 147 | 148 | // fs/rdwr.c 149 | int do_read(int fd, char *buf, int cnt); 150 | int do_write(int fd, char *buf, int cnt); 151 | int do_lseek(uint fd, int off, int whence); 152 | 153 | // fs/link.c 154 | int do_link(char *path1, char *path2); 155 | int do_unlink(char *path); 156 | 157 | // fs/mount.c 158 | struct super* do_mount(ushort dev, struct inode *ip); 159 | int do_umount(ushort dev); 160 | 161 | // fs/fcntl.c 162 | int do_fcntl(int fd, uint cmd, uint arg); 163 | int do_stat(struct inode *ip, struct stat *sbuf); 164 | int do_access(struct inode *ip, uint mode); 165 | int do_creat(char *path, int mode); 166 | int do_mknod(char *path, int mode, ushort dev); 167 | 168 | // fs/bmap.c 169 | int bmap(struct inode *ip, ushort nr, uchar creat); 170 | int itrunc(struct inode *ip); 171 | 172 | // fs/inode.c 173 | struct inode* iget(ushort dev, uint num); 174 | void iput(struct inode *ip); 175 | int iload(struct inode *ip); 176 | void iupdate(struct inode *ip); 177 | void lock_ino(struct inode *ip); 178 | void unlk_ino(struct inode *ip); 179 | void dump_inode(struct inode *ip); 180 | 181 | // fs/alloc.c 182 | int balloc(ushort dev); 183 | int bfree(ushort dev, uint nr); 184 | int bzero(ushort dev, uint bn); 185 | int ialloc(ushort dev); 186 | void ifree(ushort dev, uint ino); 187 | int find_bit(char *bm, int size); 188 | 189 | // fs/namei.c 190 | struct inode* namei(char *path, uchar creat); 191 | struct inode* namei_parent(char *path, char **name); 192 | uint find_entry(struct inode* dip, char *name, uint len); 193 | uint link_entry(struct inode *dip, char *name, uint len, uint ino); 194 | int unlink_entry(struct inode *dip, char *name, int len); 195 | 196 | // fs/file.c 197 | struct file* falloc(int fd); 198 | 199 | // fs/super.c 200 | struct super* getsp(ushort dev); 201 | int spload(struct super *sp); 202 | void spupdate(struct super *sp); 203 | void unlk_sp(struct super *sp); 204 | void putsp(struct super *sp); 205 | 206 | // fs/open.c 207 | int do_open(char *path, uint flag, uint mode); 208 | int do_dup(int fd); 209 | int do_close(int fd); 210 | int do_dup(int fd); 211 | int do_dup2(int fd, int newfd); 212 | int ufalloc(); 213 | struct file* falloc(int fd); 214 | 215 | // chr/tty.c 216 | int tty_read(ushort dev, char *buf, uint cnt); 217 | int tty_write(ushort dev, char *buf, uint cnt); 218 | int tty_open(ushort dev); 219 | int tty_input(struct tty *tp, char ch); 220 | 221 | // chr/keybd.c 222 | void keybd_init(); 223 | int do_keybd_intr(struct trap *tf); 224 | 225 | /* --------------------------------------------------- */ 226 | /* panic */ 227 | #define panic(str) \ 228 | do { \ 229 | printk("\nPANIC: %s:%d: %s\n", __FILE__, __LINE__, str);\ 230 | asm volatile("cli");\ 231 | for(;;);\ 232 | } while(0) 233 | 234 | #define max(a, b) (((a)>(b))?(a):(b)) 235 | #define min(a, b) (((a)<(b))?(a):(b)) 236 | 237 | #endif 238 | -------------------------------------------------------------------------------- /src/inc/signal.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGNAL_H 2 | #define SIGNAL_H 3 | 4 | struct sigaction{ 5 | void (*sa_handler)(int); 6 | uint sa_mask; 7 | int sa_flags; 8 | void (*sa_restorer)(void); 9 | }; 10 | 11 | /* flags for sa_flags */ 12 | #define SA_NOCLDSTOP 1 13 | #define SA_NOMASK 0x40000000 14 | #define SA_ONESHOT 0x80000000 15 | 16 | #define NSIG 32 17 | 18 | /* the list of signals */ 19 | #define SIGHUP 1 20 | #define SIGINT 2 21 | #define SIGQUIT 3 22 | #define SIGILL 4 23 | #define SIGTRAP 5 24 | #define SIGABRT 6 25 | #define SIGFPE 8 26 | #define SIGKILL 9 27 | #define SIGUSR1 10 28 | #define SIGSEGV 11 29 | #define SIGUSR2 12 30 | #define SIGPIPE 13 31 | #define SIGALRM 14 32 | #define SIGTERM 15 33 | #define SIGCHLD 17 34 | #define SIGCONT 18 35 | #define SIGSTOP 19 36 | #define SIGTSTP 20 37 | #define SIGTTIN 21 38 | #define SIGTTOU 22 39 | 40 | #define SIG_DFL ((void (*)(int))0) /* default signal handling */ 41 | #define SIG_IGN ((void (*)(int))1) /* ignore signal */ 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/inc/stat.h: -------------------------------------------------------------------------------- 1 | #ifndef STAT_H 2 | #define STAT_H 3 | 4 | struct stat { 5 | ushort st_dev; 6 | ushort st_ino; 7 | ushort st_mode; 8 | ushort st_nlink; 9 | ushort st_uid; 10 | ushort st_gid; 11 | ushort st_rdev; 12 | uint st_size; 13 | ushort st_atime; 14 | ushort st_mtime; 15 | ushort st_ctime; 16 | }; 17 | 18 | #define S_IFMT 00170000 19 | #define S_IFREG 0100000 /* regular */ 20 | #define S_IFBLK 0060000 /* blk device */ 21 | #define S_IFDIR 0040000 /* directory */ 22 | #define S_IFCHR 0020000 /* char device*/ 23 | #define S_IFIFO 0010000 /* fifo */ 24 | #define S_ISUID 0004000 25 | #define S_ISGID 0002000 26 | #define S_ISVTX 0001000 27 | 28 | /* predicates */ 29 | #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) 30 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 31 | #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) 32 | #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) 33 | #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) 34 | 35 | /* access */ 36 | #define RWX_MODES 0000777 /* mode bits for RWX only */ 37 | #define R_BIT 0000004 /* Rwx protection bit */ 38 | #define W_BIT 0000002 /* rWx protection bit */ 39 | #define X_BIT 0000001 /* rwX protection bit */ 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/inc/stdarg.h: -------------------------------------------------------------------------------- 1 | /*TODO:*/ 2 | -------------------------------------------------------------------------------- /src/inc/super.h: -------------------------------------------------------------------------------- 1 | /* it's a minix 2 fs's super block. 2 | * note that each minor device's first logical block(1024b, 2 physical block) 3 | * is reserved for the boot record, the second logical block is reserved for the 4 | * super block, which is also 1024b. 5 | * */ 6 | struct d_super { 7 | ushort s_max_inode; // - 8 | ushort s_max_zone; // - 9 | ushort s_nimap_blk; // number of inode bit map blocks 10 | ushort s_nzmap_blk; // number of zone bitmap blocks 11 | ushort s_zone0; // number of the first data zone. 12 | ushort s_log_bz; // log(blk,zone), lba == nr_zone >> s_log_bz 13 | uint s_max_filesiz; // the max size of one file (in bytes) 14 | ushort s_magic; // 0x138F 15 | ushort s_padding; // seems useless 16 | }; 17 | 18 | struct super { 19 | ushort s_max_inode; // - 20 | ushort s_max_zone; // - 21 | ushort s_nimap_blk; // number of inode bit map blocks 22 | ushort s_nzmap_blk; // number of zone bitmap blocks 23 | ushort s_data_zone0; // number of the first data zone. 24 | ushort s_log_bz; // log(blk,zone), lba == nr_zone >> s_log_bz 25 | uint s_max_size; // the max size of one file (in bytes) 26 | ushort s_magic; // 0x138F 27 | ushort s_padding; // seems useless 28 | /* the rest fields only lie in-core, for mount */ 29 | short s_dev; 30 | struct inode *s_imnt; // the mount point, like /mnt/dir 31 | uint s_flag; 32 | }; 33 | 34 | /* the mount table */ 35 | extern struct super mnt[NMOUNT]; 36 | /* the root super block */ 37 | extern struct super *rootsp; 38 | 39 | extern uint max_filesiz; 40 | 41 | #define S_MAGIC 0x138F 42 | 43 | /* flags */ 44 | #define S_LOCK 0x1 45 | #define S_WANTED 0x2 46 | #define S_RDONLY 0x4 47 | #define S_DIRTY 0x8 48 | 49 | /* helpers */ 50 | /* bits/inodes per block */ 51 | #define BPB (BLK*8) 52 | #define IPB (BLK/(sizeof(struct d_inode))) 53 | /* inode number/block number to each's bitmap block. 54 | * note that inode number starts at 1. 55 | * */ 56 | #define IMAPBLK(sp, in) (2 + ((in))/BPB) 57 | #define BMAPBLK(sp, bn) (2 + ((sp)->s_nimap_blk) + ((bn))/BPB) 58 | /* inode number to its block number */ 59 | #define IBLK(sp, ino) (2 + ((sp)->s_nimap_blk) + ((sp)->s_nzmap_blk) + ((ino)-1)/IPB) 60 | 61 | -------------------------------------------------------------------------------- /src/inc/tss.h: -------------------------------------------------------------------------------- 1 | struct tss_desc { 2 | uint link, esp0; 3 | ushort ss0, __1; 4 | uint esp1; 5 | ushort ss1, __2; 6 | uint esp2; 7 | ushort ss2, __3; 8 | uint cr3, eip, eflags; 9 | uint eax, ecx, edx, ebx, esp, ebp, esi, edi; 10 | ushort es, __4; 11 | ushort cs, __5; 12 | ushort ss, __6; 13 | ushort ds, __7; 14 | ushort fs, __8; 15 | ushort gs, __9; 16 | ushort ldt,__10; 17 | ushort trap, iomb; 18 | } __attribute__((packed)); 19 | 20 | extern struct tss_desc tss; 21 | -------------------------------------------------------------------------------- /src/inc/tty.h: -------------------------------------------------------------------------------- 1 | #ifndef TTY_H 2 | #define TTY_H 3 | 4 | #define QBUFSIZ 1024 // size of a line buffer, and the limit of each line input. 5 | 6 | /* 7 | * A cycle queue. 8 | * */ 9 | struct qbuf { 10 | uint q_start; 11 | uint q_end; 12 | uint q_count; 13 | char q_char[QBUFSIZ]; 14 | }; 15 | 16 | /* 17 | * */ 18 | struct tty { 19 | int t_flag; 20 | uint t_pgrp; 21 | int t_dev; // device number. 22 | int t_col; // position x of the cursor 23 | int t_row; // position y of the cursor 24 | void (*t_putc)(char); 25 | struct qbuf t_rawq; 26 | struct qbuf t_canq; 27 | struct qbuf t_outq; 28 | }; 29 | 30 | extern struct tty tty[NTTY]; 31 | 32 | /* flags */ 33 | #define TTY_CANON 0x0 /* if not raw, it's a canon */ 34 | #define TTY_RAW 0x1 35 | #define TTY_ECHO 0x2 36 | #define TTY_WANTED 0x10 37 | 38 | /* control characters */ 39 | #define CINTR 28 /* ctrl-C */ 40 | #define CQUIT 034 /* ctrl-\ */ 41 | #define CERASE '\b' /* DEL, BS */ 42 | #define CKILL 025 /* ctrl-X */ 43 | #define CEOF 004 /* ctrl-D */ 44 | #define CEOL 00 45 | #define CSTART 021 /* ctrl-Q */ 46 | #define CSTOP 023 /* ctrl-S */ 47 | #define CSUSP 032 /* ctrl-Z */ 48 | 49 | /* ------------------------------------ */ 50 | 51 | int sigsend_g(int pgrp, int n, int priv); 52 | 53 | #endif 54 | 55 | -------------------------------------------------------------------------------- /src/inc/usr/setjmp.h: -------------------------------------------------------------------------------- 1 | #ifndef SETJMP_H 2 | #define SETJMP_H 3 | 4 | struct jmp_buf { 5 | int eip; 6 | int esp; 7 | int ebx; // - callee registers 8 | int ecx; 9 | int edx; 10 | int esi; 11 | int edi; 12 | int ebp; 13 | uint __sigmask; 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/inc/usr/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef STDIO_H 2 | #define STDIO_H 3 | 4 | #endif 5 | -------------------------------------------------------------------------------- /src/inc/usr/stdlib.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flaneur2020/fleurix/5ee04c556e293654bdf2148b62a1683f980d5ebc/src/inc/usr/stdlib.h -------------------------------------------------------------------------------- /src/inc/vm.h: -------------------------------------------------------------------------------- 1 | #ifndef VM_H 2 | #define VM_H 3 | 4 | #include 5 | 6 | /* each vma asscociated with a file descripter, on page fault raised 7 | * do what it deserves. */ 8 | struct vma { 9 | uint v_flag; 10 | uint v_base; // must be one page aligned 11 | uint v_size; // must be one page aligned 12 | struct inode *v_ino; // inode 13 | uint v_ioff; // keep block aligned 14 | }; 15 | 16 | #define VMA_RDONLY 0x1 // read only 17 | #define VMA_STACK 0x2 // this vma indicates a stack, which grows downwards. 18 | #define VMA_ZERO 0x4 // demand-zero 19 | #define VMA_MMAP 0x8 // mapped from a file 20 | #define VMA_PRIVATE 0x10 // Copy On Write 21 | 22 | /* 23 | * each proc got one struct vm, which indicated it's page directory 24 | * and misc on address space. 25 | * */ 26 | struct vm { 27 | struct pde *vm_pgd; 28 | uint vm_entry; 29 | struct vma vm_area[0]; // trick here, treat the fields downblow as an array. 30 | struct vma vm_text; 31 | struct vma vm_data; 32 | struct vma vm_bss; 33 | struct vma vm_heap; 34 | struct vma vm_stack; 35 | }; 36 | 37 | #define NVMA 5 38 | 39 | #define VM_STACK 0x80000000 /* 2gb */ 40 | 41 | /* 42 | * proc0's page directory, initialize the kernel's address space here. 43 | * */ 44 | extern struct pde pgd0[]; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/inc/x86.h: -------------------------------------------------------------------------------- 1 | /* this file is modified from xv6 */ 2 | 3 | #ifndef X86_H 4 | #define X86_H 5 | 6 | // Eflags register 7 | #define FL_CF 0x00000001 // Carry Flag 8 | #define FL_PF 0x00000004 // Parity Flag 9 | #define FL_AF 0x00000010 // Auxiliary carry Flag 10 | #define FL_ZF 0x00000040 // Zero Flag 11 | #define FL_SF 0x00000080 // Sign Flag 12 | #define FL_TF 0x00000100 // Trap Flag 13 | #define FL_IF 0x00000200 // Interrupt Enable 14 | #define FL_DF 0x00000400 // Direction Flag 15 | #define FL_OF 0x00000800 // Overflow Flag 16 | #define FL_IOPL_MASK 0x00003000 // I/O Privilege Level bitmask 17 | #define FL_IOPL_0 0x00000000 // IOPL == 0 18 | #define FL_IOPL_1 0x00001000 // IOPL == 1 19 | #define FL_IOPL_2 0x00002000 // IOPL == 2 20 | #define FL_IOPL_3 0x00003000 // IOPL == 3 21 | #define FL_NT 0x00004000 // Nested Task 22 | #define FL_RF 0x00010000 // Resume Flag 23 | #define FL_VM 0x00020000 // Virtual 8086 mode 24 | #define FL_AC 0x00040000 // Alignment Check 25 | #define FL_VIF 0x00080000 // Virtual Interrupt Flag 26 | #define FL_VIP 0x00100000 // Virtual Interrupt Pending 27 | #define FL_ID 0x00200000 // ID flag 28 | 29 | // Control Register flags 30 | #define CR0_PE 0x00000001 // Protection Enable 31 | #define CR0_MP 0x00000002 // Monitor coProcessor 32 | #define CR0_EM 0x00000004 // Emulation 33 | #define CR0_TS 0x00000008 // Task Switched 34 | #define CR0_ET 0x00000010 // Extension Type 35 | #define CR0_NE 0x00000020 // Numeric Errror 36 | #define CR0_WP 0x00010000 // Write Protect 37 | #define CR0_AM 0x00040000 // Alignment Mask 38 | #define CR0_NW 0x20000000 // Not Writethrough 39 | #define CR0_CD 0x40000000 // Cache Disable 40 | #define CR0_PG 0x80000000 // Paging 41 | 42 | #define RING0 0 43 | #define RING3 3 44 | 45 | /*********************************************************************************/ 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #endif 53 | 54 | -------------------------------------------------------------------------------- /src/kern/entry.S: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | ;; 4 | ;; entry to kmain() in C, should never return 5 | ;; 6 | [extern kmain] 7 | jmp kmain 8 | _spin: 9 | jmp _spin 10 | 11 | 12 | ;; 13 | ;; on task switch 14 | ;; _do_swtch(struct jmp_buf *old, struct jmp_buf *new); 15 | ;; 16 | [global _do_swtch] 17 | _do_swtch: 18 | mov eax, dword [esp+4] ;; new 19 | pop dword [eax] ;; *old 20 | mov dword [eax+4], esp 21 | mov dword [eax+8], ebx 22 | mov dword [eax+12], ecx 23 | mov dword [eax+16], edx 24 | mov dword [eax+20], esi 25 | mov dword [eax+24], edi 26 | mov dword [eax+28], ebp 27 | 28 | mov eax, dword [esp+4] 29 | 30 | mov ebp, dword [eax+28] 31 | mov edi, dword [eax+24] 32 | mov esi, dword [eax+20] 33 | mov edx, dword [eax+16] 34 | mov ecx, dword [eax+12] 35 | mov ebx, dword [eax+8] 36 | mov esp, dword [eax+4] 37 | push dword [eax] 38 | ret 39 | 40 | ;; 41 | ;; retu(uint eip, uint esp3) 42 | ;; return to user mode via an IRET instruction. 43 | ;; note: 44 | ;; USER_CS = 0x1B 45 | ;; USER_DS = 0x23 46 | ;; 47 | [global _retu] 48 | _retu: 49 | pop dword eax ;; ignore the returned eip 50 | pop dword ebx ;; eip -> ebx 51 | pop dword ecx ;; esp3 -> ecx 52 | mov ax, 0x23 53 | mov ds, ax 54 | mov es, ax 55 | mov fs, ax 56 | mov gs, ax 57 | push dword 0x23 ;; ss3 58 | push dword ecx ;; esp3 59 | pushf ;; eflags 60 | push dword 0x1B ;; cs 61 | push dword ebx ;; eip 62 | iretd 63 | 64 | ;; 65 | ;; entry to trap handlers 66 | ;; 67 | 68 | [section .text] 69 | [global _hwint_ret] 70 | [extern hwint_common] 71 | 72 | ;; 73 | ;; hard coded, take an eye on what you does. 74 | ;; 75 | ;; this routine is called on each isr & irq is raised. store the current cpu state on the kernel stack. 76 | ;; kernel stack is pointed by the esp0 field inside tss. 77 | ;; 78 | ;; the routine _hwint_ret is the execution entry of a new proc. 79 | ;; 80 | _hwint_common_stub: 81 | sti 82 | pusha 83 | push ds 84 | push es 85 | push fs 86 | push gs 87 | mov ax, 0x10 88 | mov ds, ax 89 | mov es, ax 90 | mov eax, esp 91 | push eax ; esp is just the pointer to struct trap *. 92 | mov eax, hwint_common ; calls hwint_common() in C 93 | call eax 94 | pop eax 95 | _hwint_ret: 96 | pop gs 97 | pop fs 98 | pop es 99 | pop ds 100 | popa 101 | add esp, 8 102 | iret 103 | 104 | %macro hwint 1 105 | _hwint%1: 106 | %if %1 != 17 && %1 != 30 && (%1 < 8 || %1 > 14) 107 | push dword 0 108 | %endif 109 | push dword %1 110 | jmp _hwint_common_stub 111 | %endmacro 112 | 113 | %assign i 0 114 | %rep 129 115 | hwint i 116 | %assign i i+1 117 | %endrep 118 | 119 | %macro prologue 1 120 | dd _hwint%1 121 | %endmacro 122 | 123 | ; vector table 124 | [section .data] 125 | [global _hwint] 126 | _hwint: 127 | %assign i 0 128 | %rep 129 129 | prologue i 130 | %assign i i+1 131 | %endrep 132 | -------------------------------------------------------------------------------- /src/kern/exec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | // 7 | #include 8 | #include 9 | // 10 | #include 11 | #include 12 | #include 13 | // 14 | #include 15 | // 16 | #include 17 | #include 18 | #include 19 | // 20 | #include 21 | 22 | /* 23 | * exec.c 24 | * 25 | * this file indicated the implementation of exec(char* path, char **argv). 26 | * exec() create a NEW address space, which overlapped the old forked address 27 | * space, make it demand-reading. 28 | * */ 29 | 30 | static char** store_argv(char *path, char **argv); 31 | static int free_argv(char **tmp); 32 | 33 | /* ---------------------------------------------- */ 34 | 35 | /* initialize a new struct vm according to an a.out executable 36 | * image. 37 | * returns NULL on fail. 38 | * the user stack initialized like this: 39 | * |--------------- esp 40 | * | argc 41 | * |--------------- 42 | * | argv 43 | * |--------------- 44 | * | argv[0] "..." 45 | * | argv[1] "..." 46 | * | ... 47 | * | argv[n] "..." 48 | * --------------- VM_STACK 49 | * note: ignored envp yet. 50 | * */ 51 | int do_exec(char *path, char **argv){ 52 | struct inode *ip; 53 | struct buf *bp; 54 | struct sigaction *sa; 55 | struct ahead *ah; 56 | struct vm *vm; 57 | struct file *fp; 58 | uint bn, fd, fdflag, argc, esp, nr; 59 | char **tmp; 60 | 61 | ip = namei(path, 0); 62 | if (ip==NULL) { 63 | return syserr(ENOENT); 64 | } 65 | // read the first block of file to get the a.out header. 66 | bn = bmap(ip, 0, 0); 67 | if (bn == 0) { 68 | syserr(EINVAL); 69 | goto _badf; 70 | } 71 | bp = bread(ip->i_dev, bn); 72 | ah = (struct ahead*)bp->b_data; 73 | // check this a.out header. 74 | if (ah->a_magic != NMAGIC) { 75 | syserr(EINVAL); 76 | goto _badf; 77 | } 78 | // restore the path and argv temporarily 79 | tmp = store_argv(path, argv); 80 | // dettach the previous address space, and initialize a new one 81 | vm = &cu->p_vm; 82 | vm_clear(vm); 83 | vm_renew(vm, ah, ip); 84 | // push arguments to the end of user stack, which always the same address. 85 | esp = VM_STACK; 86 | argc = upush_argv(&esp, tmp); 87 | if (argc<0) 88 | panic("exec(): bad mem"); 89 | upush(&esp, (char*)&argc, sizeof(uint)); 90 | // 91 | free_argv(tmp); 92 | // close all the file descriptors with FD_CLOEXEC 93 | for (fd=0; fdp_ofile[fd]; 95 | fdflag = cu->p_fdflag[fd]; 96 | if ((fp!=NULL) && (fdflag & FD_CLOEXEC)) { 97 | do_close(fd); 98 | } 99 | } 100 | // clear all sigactions 101 | for (nr=0; nrp_sigact[nr]; 103 | sa->sa_handler = SIG_DFL; 104 | sa->sa_mask = 0; 105 | sa->sa_flags = 0; 106 | sa->sa_restorer = NULL; 107 | } 108 | // never forget this: 109 | brelse(bp); 110 | iput(ip); 111 | // enter user mode 112 | _retu(vm->vm_entry, esp); 113 | return 0; 114 | 115 | _badf: 116 | brelse(bp); 117 | iput(ip); 118 | return -1; 119 | } 120 | 121 | /* --------------------------------------------------------- */ 122 | 123 | /* push argv into user stack, returns argc. 124 | * note: vm_verify() may override proc's address space, take care. 125 | * */ 126 | int upush_argv(uint *esp, char *tmp[]){ 127 | uint arglen, argc; 128 | int i, r, tmp_esp; // TODO: some bugs hide here, when you deleted the unused variables. 129 | char *str, **uargv; 130 | 131 | argc = 0; 132 | if (tmp != NULL) { 133 | for (i=0; (str=tmp[i])!=NULL; i++) { 134 | arglen += strlen(str)+1; 135 | argc++; 136 | } 137 | } 138 | arglen += sizeof(char*) * argc; 139 | // note: vm_verify may modify proc's address space. 140 | if (vm_verify((void*)(*esp-arglen), arglen) < 0){ 141 | syserr(EINVAL); 142 | return -1; 143 | } 144 | // push to ustack finally 145 | uargv = (char**)(*esp - arglen); 146 | for (i=argc-1; i>=0; i--){ 147 | str = tmp[i]; 148 | upush(esp, str, strlen(str)+1); 149 | uargv[i] = (char *) *esp; 150 | } 151 | *esp = (uint)uargv; 152 | // push argv[] 153 | upush(esp, (char*)&uargv, sizeof(uint)); 154 | return argc; 155 | } 156 | 157 | /* push one string into the user stack. returns the new esp */ 158 | int upush(uint *esp, char *buf, int len){ 159 | uint tmp = *esp; // take care, *esp may overlaps *buf 160 | 161 | tmp -= len; 162 | if (vm_verify((void*)tmp, len) < 0) { 163 | panic("upush(): bad mem"); 164 | } 165 | memcpy(tmp, buf, len); 166 | return (*esp=tmp); 167 | } 168 | 169 | /* ---------------------------------------------------- */ 170 | 171 | /* store the argv into some new-allocated pages temporily */ 172 | static char** store_argv(char *path, char **argv){ 173 | char **tmp; 174 | int argc, i; 175 | 176 | argc = 1; 177 | if (argv!=NULL) 178 | for (; argv[argc-1]; argc++); 179 | // store the argv in temp 180 | tmp = (char**)kmalloc(PAGE); 181 | tmp[0] = (char*) kmalloc(PAGE); 182 | strncpy(tmp[0], path, PAGE-1); 183 | tmp[0][PAGE-1] = '\0'; 184 | for(i=1; ia_magic); 210 | printk("a_tsize: %x\n", ah->a_tsize); 211 | printk("a_dsize: %x\n", ah->a_dsize); 212 | printk("a_bsize: %x\n", ah->a_bsize); 213 | printk("a_syms: %x\n", ah->a_syms); 214 | printk("a_entry: %x\n", ah->a_entry); 215 | printk("a_trsize: %x\n", ah->a_trsize); 216 | printk("a_drsize: %x\n", ah->a_drsize); 217 | } 218 | -------------------------------------------------------------------------------- /src/kern/exit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | /* exit.c - 2011 fleurer 12 | * */ 13 | 14 | /* terminate the currenct proccess into ZOMBIE, and tell its parent. 15 | * the struct proc is freed by each proc's parent. 16 | * */ 17 | int do_exit(int ret){ 18 | struct file *fp; 19 | struct proc *p; 20 | uint fd, nr; 21 | 22 | cu->p_ret = ret; 23 | // clear all the signal handlers 24 | for (nr=0; nrp_sigact[nr].sa_handler = SIG_DFL; 26 | cu->p_sigact[nr].sa_flags = 0; 27 | } 28 | // close all the opened files, and iput the directories. 29 | for (fd=0; fdp_ofile[fd]; 31 | if (fp != NULL) { 32 | do_close(fd); 33 | } 34 | cu->p_ofile[fd] = NULL; 35 | } 36 | iput(cu->p_iroot); 37 | iput(cu->p_wdir); 38 | // tell its parent 39 | sigsend(cu->p_ppid, SIGCHLD, 1); 40 | // free the address space 41 | vm_clear(&cu->p_vm); 42 | kfree(cu->p_vm.vm_pgd, PAGE); 43 | // make this process Zombie, give all the children to proc[1] 44 | // and tell its parent 45 | cu->p_chan = 0; 46 | cu->p_stat = SZOMB; 47 | for (nr=1; nrp_ppid==cu->p_pid)) { 49 | p->p_ppid = 1; 50 | } 51 | } 52 | // wakeup proc[1] and its parent 53 | p = proc[cu->p_ppid]; 54 | wakeup((uint)p); 55 | wakeup((uint)proc[1]); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /src/kern/fork.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | /* 12 | * proc.c - 2010 fleurer 13 | * this file implies the initilization of proc[0] and the implementation 14 | * of fork(), 15 | * 16 | * */ 17 | 18 | struct proc proc0; 19 | 20 | struct proc *proc[NPROC] = {NULL, }; 21 | struct proc *cu = NULL; 22 | 23 | struct tss_desc tss; 24 | 25 | extern void _hwint_ret(); 26 | 27 | /* ----------------------------------------------------------------- */ 28 | 29 | /* 30 | * find an empty proc slot, return the number as pid 31 | * return 0 on fail 32 | * */ 33 | int find_pid(){ 34 | int nr; 35 | for(nr=0; nrp_stat = SSLEEP; // set SRUN later. 68 | p->p_pid = nr; 69 | p->p_ppid = cu->p_pid; 70 | p->p_pgrp = cu->p_pgrp; 71 | p->p_flag = cu->p_flag; 72 | p->p_cpu = cu->p_cpu; 73 | p->p_nice = cu->p_nice; 74 | p->p_pri = PUSER; 75 | // 76 | p->p_euid = cu->p_euid; 77 | p->p_egid = cu->p_egid; 78 | p->p_ruid = cu->p_ruid; 79 | p->p_rgid = cu->p_rgid; 80 | // increase the reference count of inodes, and dup files 81 | if (cu->p_wdir != NULL) { 82 | p->p_wdir = cu->p_wdir; 83 | p->p_wdir->i_count++; 84 | p->p_iroot = cu->p_iroot; 85 | p->p_iroot->i_count++; 86 | } 87 | // dup the files, and fdflag 88 | for (fd=0; fdp_ofile[fd]; 90 | if (fp != NULL) { 91 | fp->f_count++; 92 | fp->f_ino->i_count++; 93 | } 94 | p->p_ofile[fd] = fp; 95 | p->p_fdflag[fd] = cu->p_fdflag[fd]; 96 | } 97 | // signals 98 | p->p_sig = cu->p_sig; 99 | p->p_sigmask = cu->p_sigmask; 100 | for (n=0; np_sigact[n] = cu->p_sigact[n]; 102 | } 103 | // clone kernel's address space. 104 | vm_clone(&p->p_vm); 105 | p->p_contxt = cu->p_contxt; 106 | p->p_contxt.eip = (uint)func; 107 | p->p_contxt.esp = (uint)p+PAGE; 108 | p->p_stat = SRUN; 109 | return p; 110 | } 111 | 112 | /* 113 | * main part of sys_fork(). 114 | * note that the fact that ALL process swtching occurs in kernel 115 | * space, hence fork() just returns to _hwint_ret(in entry.S.rb), 116 | * and initialize a kernel stack just as intrrupt occurs here. 117 | * */ 118 | int do_fork(struct trap *tf){ 119 | struct proc *p; 120 | struct trap *ntf; 121 | 122 | p = kspawn(&_hwint_ret); 123 | ntf = (struct trap *)((uint)p+PAGE) - 1; 124 | *ntf = *tf; 125 | ntf->eax = 0; // this is why fork() returns 0. 126 | p->p_contxt.esp = (uint)ntf; 127 | p->p_trap = ntf; 128 | return p->p_pid; 129 | } 130 | 131 | /* ----------------------------------------------------------- */ 132 | 133 | /* 134 | * init proc[0] 135 | * set the LDT and th ONLY TSS into GDT 136 | * and make current as proc[0] 137 | */ 138 | void proc0_init(){ 139 | int fd; 140 | 141 | struct proc *p = cu = proc[0] = &proc0; 142 | p->p_pid = 0; 143 | p->p_ppid = 0; 144 | p->p_stat = SRUN; 145 | p->p_flag = SLOAD; 146 | // on shedule 147 | p->p_cpu = 0; 148 | p->p_pri = 0; 149 | p->p_nice = 20; 150 | // on user 151 | p->p_euid = 0; 152 | p->p_egid = 0; 153 | // attach the page table 154 | p->p_vm.vm_pgd = pgd0; 155 | // 156 | p->p_wdir = NULL; 157 | p->p_iroot = NULL; 158 | // init tss 159 | tss.ss0 = KERN_DS; 160 | tss.esp0 = KSTACK0; 161 | for (fd=0; fdp_ofile[fd] = NULL; 163 | } 164 | } 165 | 166 | /* --------------------------------------------------- */ 167 | 168 | void dump_proc(struct proc *p){ 169 | printk("%s ", (p==cu)? "-":" " ); 170 | printk("pid:%d pri:%d cpu:%d nice:%d stat:%d esp0:%x eip:%x \n", p->p_pid, p->p_pri, p->p_cpu, p->p_nice, p->p_stat, p->p_contxt.esp, p->p_contxt.eip); 171 | } 172 | 173 | void dump_procs(){ 174 | int i; 175 | struct proc *p; 176 | for(i=0; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | // 8 | #include 9 | #include 10 | // 11 | #include 12 | #include 13 | #include 14 | // 15 | #include 16 | // 17 | #include 18 | #include 19 | #include 20 | 21 | void init(); 22 | 23 | void kmain(){ 24 | cls(); 25 | gdt_init(); puts("* init gdt\n"); 26 | idt_init(); puts("* init idt\n"); 27 | mm_init(); puts("* init mm\n"); 28 | // 29 | proc0_init(); puts("* init proc0\n"); 30 | buf_init(); puts("* init buf\n"); 31 | tty_init(); puts("* init tty\n"); 32 | hd_init(); puts("* init hd\n"); 33 | timer_init(); puts("* init timer\n"); 34 | keybd_init(); puts("* init keybd\n"); 35 | puts("\n--- fleurix ---\n\n"); 36 | sti(); 37 | // 38 | kspawn(&init); 39 | for(;;){ 40 | sti(); 41 | swtch(); 42 | } 43 | } 44 | 45 | char *argv[] = {"abc\n", "testt\n", NULL}; 46 | 47 | void init() { 48 | struct inode *ip; 49 | 50 | cu->p_pgrp = 1; 51 | // mount rootfs 52 | do_mount(rootdev, NULL); 53 | ip = iget(rootdev, 1); 54 | cu->p_wdir = ip; 55 | cu->p_iroot = ip; 56 | ip->i_count += 2; 57 | iput(ip); 58 | // stdin, stdout, stderr 59 | if (do_open("/dev/tty0", O_RDWR, 0) < 0) { 60 | panic("bad /dev/tty0.\n"); 61 | } 62 | do_dup(0); // stdout 63 | do_dup(0); // stderr 64 | do_fcntl(0, F_SETFD, 0); // turn off FD_CLOEXEC 65 | do_fcntl(1, F_SETFD, 0); 66 | do_fcntl(2, F_SETFD, 0); 67 | // enter user mode, never returns. 68 | do_exec("/bin/init", NULL); 69 | for(;;); 70 | } 71 | -------------------------------------------------------------------------------- /src/kern/sched.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | /* TODO: the algorithm on runrun seems break */ 9 | uint runrun = 0; 10 | 11 | /*******************************************************************************/ 12 | 13 | /* mark a proccess SWAIT, commonly used on waiting a resource. 14 | * */ 15 | void sleep(uint chan, int pri){ 16 | if (pri < 0) { 17 | cli(); 18 | cu->p_chan = chan; 19 | cu->p_pri = pri; 20 | cu->p_stat = SSLEEP; // uninterruptible 21 | sti(); 22 | swtch(); 23 | } 24 | else { 25 | if (issig()) 26 | psig(); 27 | cli(); 28 | cu->p_chan = chan; 29 | cu->p_pri = pri; 30 | cu->p_stat = SWAIT; // interruptible 31 | sti(); 32 | if (issig()) 33 | psig(); 34 | swtch(); 35 | } 36 | } 37 | 38 | void wakeup(uint chan){ 39 | struct proc *p; 40 | int i; 41 | for(i=0; ip_chan == chan) { 45 | setrun(p); 46 | } 47 | } 48 | } 49 | 50 | void setrun(struct proc *p){ 51 | p->p_chan = 0; 52 | p->p_stat = SRUN; 53 | } 54 | 55 | /*******************************************************************/ 56 | 57 | /* re-caculate the proc's p_pri 58 | * if it's lower than the current proc's p_pri, set the re-schedule flag. 59 | * */ 60 | void setpri(struct proc *p){ 61 | int n; 62 | n = p->p_cpu/16 + PUSER + p->p_nice; 63 | if (n >= 127) n=127; 64 | if (n <= -126) n=-126; 65 | if ((p!=cu) && p->p_pri < cu->p_pri){ 66 | runrun = 1; 67 | } 68 | p->p_pri = n; 69 | } 70 | 71 | /* called once per second, re-caculate all the procs' p_pri 72 | * TODO: stil didn't catch the idea of traditional Unix's scheduling. 73 | * choose linus's approach instead later. 74 | * */ 75 | void sched_cpu(){ 76 | struct proc *p; 77 | int i; 78 | for(i=0;ip_cpu /= 2; 81 | if (p->p_pri > PUSER) { 82 | setpri(p); 83 | } 84 | } 85 | } 86 | } 87 | 88 | /* 89 | * find the next proc and switch it. 90 | * re-caculate the current proc's p_pri on the end of time quatum. 91 | * */ 92 | void swtch(){ 93 | int i; 94 | char n=127; 95 | struct proc *p=NULL, *np=NULL; 96 | 97 | // clear the re-schedule flag 98 | runrun = 0; 99 | // find the proc 100 | for(i=0;ip_stat==SRUN || p->p_pid==0)) { 102 | if (p->p_pri <= n){ 103 | n = p->p_pri; 104 | np = p; 105 | } 106 | } 107 | } 108 | if (np==NULL){ 109 | n = proc[0]->p_pri; 110 | np = proc[0]; 111 | } 112 | if (np!=cu) { 113 | swtch_to(np); 114 | } 115 | } 116 | 117 | /* 118 | * do the switch task! In software. 119 | * */ 120 | void swtch_to(struct proc *to){ 121 | struct proc *from; 122 | tss.esp0 = (uint)to + PAGE; 123 | from = cu; 124 | cu = to; 125 | lpgd(to->p_vm.vm_pgd); 126 | //dump_procs(); 127 | _do_swtch(&(from->p_contxt), &(to->p_contxt)); 128 | } 129 | -------------------------------------------------------------------------------- /src/kern/seg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct seg_desc gdt[NSEG] = { { 0, }, }; 7 | struct gdt_desc gdt_desc; 8 | 9 | /* ------------------------------------------------------ */ 10 | 11 | void set_seg(struct seg_desc *seg, uint base, uint limit, uint dpl, uint type){ 12 | seg->limit_lo = ((limit) >> 12) & 0xffff; 13 | seg->base_lo = (base) & 0xffff; 14 | seg->base_mi = ((base) >> 16) & 0xff; 15 | seg->type = type; 16 | seg->s = 1; 17 | seg->dpl = dpl; 18 | seg->present = 1; 19 | seg->limit_hi = (uint) (limit) >> 28; 20 | seg->avl = 0; 21 | seg->r = 0; 22 | seg->db = 1; 23 | seg->g = 1; 24 | seg->base_hi = (base) >> 24; 25 | } 26 | 27 | void set_ldt(struct seg_desc *seg, uint base){ 28 | set_seg(seg, base, 0, 0, STS_LDT); 29 | seg->limit_lo = 0x3; 30 | seg->s = 0; 31 | } 32 | 33 | // sizeof(tss_desc) == 104 34 | void set_tss(struct seg_desc *seg, uint base){ 35 | set_seg(seg, base, 0, 0, STS_TA); 36 | seg->limit_lo = 0x68; 37 | seg->s = 0; 38 | } 39 | 40 | /* ------------------------------------------------------ */ 41 | 42 | /* 43 | * refill the gdt(the ex-gdt initialized in boot/boot.S) 44 | * one tss is shared among all processes. 45 | */ 46 | void gdt_init(){ 47 | set_seg(&gdt[1], 0, 0xffffffff, RING0, STA_X | STA_R); 48 | set_seg(&gdt[2], 0, 0xffffffff, RING0, STA_W); 49 | set_seg(&gdt[3], 0, 0xffffffff, RING3, STA_X | STA_R); 50 | set_seg(&gdt[4], 0, 0xffffffff, RING3, STA_W); 51 | set_tss(&gdt[TSS0], (uint)&tss); 52 | gdt_desc.base = (uint)&gdt; 53 | gdt_desc.limit = (sizeof (struct seg_desc) * NSEG) - 1; 54 | // load gdt 55 | asm volatile( "lgdt %0" :: "m"(gdt_desc)); 56 | // load tss 57 | ltr(_TSS); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/kern/sys1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | /* 9 | * sys1.c 10 | * 11 | * syscalls on proc, time and misc. 12 | * 13 | * */ 14 | 15 | 16 | /* --------------------------- */ 17 | 18 | int sys_debug(struct trap *tf){ 19 | for(;;); 20 | return 0; 21 | } 22 | 23 | int sys_fork(struct trap *tf){ 24 | return do_fork(tf); 25 | } 26 | 27 | int sys__exit(struct trap *tf){ 28 | int code = (int)tf->ebx; 29 | return do_exit(code); 30 | } 31 | 32 | /* exec(char *path, char **argv) */ 33 | int sys_exec(struct trap *tf){ 34 | char *path = (char*)tf->ebx; 35 | char **argv = (char**)tf->ecx; 36 | 37 | return do_exec(path, argv); 38 | } 39 | 40 | int sys_brk(struct trap *tf){ 41 | return syserr(ENOSYS); 42 | } 43 | 44 | /* waitpid(int pid, int *stat, int opt) */ 45 | int sys_waitpid(struct trap *tf){ 46 | int pid = (int)tf->ebx; 47 | int *stat = (int*)tf->ecx; 48 | int opt = (int)tf->edx; 49 | 50 | return do_waitpid(pid, stat, opt); 51 | } 52 | 53 | int sys_wait(struct trap *tf){ 54 | int *stat = (int*)tf->ebx; 55 | 56 | return do_waitpid(-1, stat, 0); 57 | } 58 | 59 | /* --------------------------------------- */ 60 | 61 | 62 | /* --------------------------------------- */ 63 | -------------------------------------------------------------------------------- /src/kern/sys2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | /* syscalls on fs */ 14 | 15 | /* 16 | * WARNING: DANGEROUS here! While passing data between kernel 17 | * and user, a verification is nesscary. Just make a simulation 18 | * what the hardware does in user space, or it may cause corruption, 19 | * even overlaps the kernel memory, be careful. 20 | * 21 | * */ 22 | 23 | /* int access(char *path, int mode); */ 24 | int sys_access(struct trap *tf){ 25 | char *path = (char*)tf->ebx; 26 | int mode = tf->ecx; 27 | struct inode *ip; 28 | 29 | if (vm_verify(path, MAX_PATHSIZ) < 0) { 30 | syserr(EFAULT); 31 | return -1; 32 | } 33 | 34 | if (strnlen(path, MAX_PATHSIZ) == MAX_PATHSIZ) { 35 | syserr(ENAMETOOLONG); 36 | return -1; 37 | } 38 | 39 | ip = namei(path, 0); 40 | if (ip==NULL) { 41 | syserr(ENOENT); 42 | return -1; 43 | } 44 | return do_access(ip, mode); 45 | } 46 | 47 | int sys_open(struct trap *tf){ 48 | char *path = (char*)tf->ebx; 49 | int flag = (int)tf->ecx; 50 | int mode = tf->edx; 51 | 52 | if (vm_verify(path, MAX_PATHSIZ) < 0) { 53 | syserr(EFAULT); 54 | return -1; 55 | } 56 | 57 | if (strnlen(path, MAX_PATHSIZ) == MAX_PATHSIZ) { 58 | syserr(ENAMETOOLONG); 59 | return -1; 60 | } 61 | 62 | return do_open(path, flag, mode); 63 | } 64 | 65 | int sys_close(struct trap *tf){ 66 | int fd = tf->ebx; 67 | 68 | return do_close(fd); 69 | } 70 | 71 | /* ------------------------------------------- */ 72 | 73 | /* int read(int fd, char buf[], int cnt); */ 74 | int sys_read(struct trap *tf){ 75 | int fd = tf->ebx; 76 | int cnt = tf->edx; 77 | char *buf = (char*)tf->ecx; 78 | 79 | if(vm_verify(buf, cnt) < 0){ 80 | syserr(EFAULT); 81 | return -1; 82 | } 83 | return do_read(fd, buf, cnt); 84 | } 85 | 86 | /* int write(int fd, char buf[], int cnt); */ 87 | int sys_write(struct trap *tf){ 88 | int fd = tf->ebx; 89 | int cnt = tf->edx; 90 | char *buf = (char*)tf->ecx; 91 | 92 | if (vm_verify(buf, cnt) < 0) { 93 | syserr(EFAULT); 94 | return -1; 95 | } 96 | return do_write(fd, buf, cnt); 97 | } 98 | 99 | /* int lseek(int fd, unsigned int offset, int whence); */ 100 | int sys_lseek(struct trap *tf){ 101 | int fd = (int)tf->ebx; 102 | uint off = (uint)tf->ecx; 103 | int whence = (int)tf->edx; 104 | 105 | return do_lseek(fd, off, whence); 106 | } 107 | 108 | /* -------------------------------------------- */ 109 | 110 | int sys_link(struct trap *tf){ 111 | char *path1 = (char*) tf->ebx; 112 | char *path2 = (char*) tf->ecx; 113 | 114 | return do_link(path1, path2); 115 | } 116 | 117 | int sys_unlink(struct trap *tf){ 118 | char *path = (char *) tf->ebx; 119 | 120 | return do_unlink(path); 121 | } 122 | 123 | /* int mknod(char *path, int mode, ushort dev) */ 124 | int sys_mknod(struct trap *tf){ 125 | char *path = (char*) tf->ebx; 126 | int mode = (int) tf->ecx; 127 | int dev = (int) tf->edx; 128 | 129 | return do_mknod(path, mode, dev); 130 | } 131 | 132 | /* int creat(char *path, int mode); */ 133 | int sys_creat(struct trap *tf){ 134 | char *path = (char*) tf->ebx; 135 | int mode = (int) tf->ecx; 136 | 137 | return do_creat(path, mode); 138 | } 139 | 140 | /* int truncate(char *path, int off) */ 141 | int sys_truncate(struct trap *tf){ 142 | syserr(ENOSYS); 143 | return -1; 144 | } 145 | 146 | /* --------------------------------- */ 147 | 148 | /* int fstat(int fd, struct stat *buf); */ 149 | int sys_fstat(struct trap *tf){ 150 | int fd = (int)tf->ebx; 151 | struct stat *sbuf = (struct stat*)tf->ecx; 152 | struct file *fp; 153 | 154 | if (fd<0 || fd>=NOFILE || cu->p_ofile[fd]==NULL) { 155 | syserr(EBADF); 156 | return -1; 157 | } 158 | fp = cu->p_ofile[fd]; 159 | return do_stat(fp->f_ino, sbuf); 160 | } 161 | 162 | /* int stat(char *path, struct stat *buf); */ 163 | int sys_stat(struct trap *tf){ 164 | char *path = (char*)tf->ebx; 165 | struct stat *sbuf = (struct stat*)tf->ecx; 166 | struct inode *ip; 167 | 168 | if (vm_verify(sbuf, sizeof(struct stat))<0) { 169 | syserr(EFAULT); 170 | return -1; 171 | } 172 | ip = namei(path, 0); 173 | if (ip==NULL) { 174 | syserr(ENOENT); 175 | return -1; 176 | } 177 | return do_stat(ip, sbuf); 178 | } 179 | 180 | /* int fcntl(int fd, int cmd, int arg); */ 181 | int sys_fcntl(struct trap *tf){ 182 | int fd = (int)tf->ebx; 183 | int cmd = (int)tf->ecx; 184 | int arg = (int)tf->edx; 185 | 186 | return do_fcntl(fd, cmd, arg); 187 | } 188 | 189 | int sys_ioctl(struct trap *tf){ 190 | syserr(ENOSYS); 191 | return -1; 192 | } 193 | 194 | /* --------------------------------- */ 195 | 196 | /* int dup(int oldfd); */ 197 | int sys_dup(struct trap *tf){ 198 | int oldfd = (int)tf->ebx; 199 | 200 | return do_dup(oldfd); 201 | } 202 | 203 | /* int dup2(int oldfd, int newfd); */ 204 | int sys_dup2(struct trap *tf){ 205 | int oldfd = (int)tf->ebx; 206 | int newfd = (int)tf->ecx; 207 | 208 | return do_dup2(oldfd, newfd); 209 | } 210 | 211 | /* int pipe(int fd[2]); */ 212 | int sys_pipe(struct trap *tf){ 213 | return syserr(ENOSYS); 214 | } 215 | 216 | /* ----------------------------------------- */ 217 | 218 | /* int chroot(char *path); */ 219 | int sys_chroot(struct trap *tf){ 220 | char *path = (char*)tf->ebx; 221 | struct inode *ip; 222 | 223 | ip = namei(path, 0); 224 | if (ip==NULL) { 225 | syserr(ENOENT); 226 | return -1; 227 | } 228 | if ((ip->i_mode&S_IFMT) != S_IFDIR) { 229 | syserr(ENOTDIR); 230 | iput(ip); 231 | return -1; 232 | } 233 | iput(cu->p_iroot); 234 | cu->p_iroot = ip; 235 | unlk_ino(ip); 236 | return 0; 237 | } 238 | 239 | /* int chdir(char *path); */ 240 | int sys_chdir(struct trap *tf){ 241 | char *path = (char*)tf->ebx; 242 | struct inode *ip; 243 | 244 | ip = namei(path, 0); 245 | if (ip==NULL) { 246 | syserr(ENOENT); 247 | return -1; 248 | } 249 | if ((ip->i_mode&S_IFMT) != S_IFDIR) { 250 | syserr(ENOTDIR); 251 | iput(ip); 252 | return -1; 253 | } 254 | iput(cu->p_wdir); 255 | cu->p_wdir = ip; 256 | unlk_ino(ip); 257 | return 0; 258 | } 259 | -------------------------------------------------------------------------------- /src/kern/sys3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | /* 9 | * sys3.c 10 | * misc syscalls. 11 | * 12 | * */ 13 | 14 | int sys_nice(struct trap *tf){ 15 | int n = tf->ebx & 0xff; 16 | if (n > 20) n = 40; 17 | if (n < -39) n = -39; 18 | return 0; 19 | } 20 | 21 | int sys_getpid(struct trap *tf){ 22 | return cu->p_pid; 23 | } 24 | 25 | int sys_getppid(struct trap *tf){ 26 | return cu->p_ppid; 27 | } 28 | 29 | int sys_getpgrp(struct trap *tf){ 30 | return cu->p_pgrp; 31 | } 32 | 33 | int sys_getuid(struct trap *tf){ 34 | return cu->p_ruid; 35 | } 36 | 37 | int sys_getgid(struct trap *tf){ 38 | return cu->p_rgid; 39 | } 40 | 41 | int sys_geteuid(struct trap *tf){ 42 | return cu->p_euid; 43 | } 44 | 45 | int sys_getegid(struct trap *tf){ 46 | return cu->p_egid; 47 | } 48 | 49 | /* int setreuid(int ruid, int euid); */ 50 | int sys_setreuid(struct trap *tf){ 51 | int ruid = tf->ebx; 52 | int euid = tf->ecx; 53 | int old_ruid; 54 | 55 | old_ruid = cu->p_ruid; 56 | if (ruid > 0) { 57 | if ((cu->p_euid==ruid) || (old_ruid==ruid) || suser()) 58 | cu->p_ruid = ruid; 59 | else 60 | return syserr(EPERM); 61 | } 62 | if (euid > 0) { 63 | if ((cu->p_euid==euid) || (old_ruid==euid) || suser()) 64 | cu->p_euid = euid; 65 | else 66 | return syserr(EPERM); 67 | } 68 | return 0; 69 | } 70 | 71 | /* int setregid(int rgid, int egid); */ 72 | int sys_setregid(struct trap *tf){ 73 | int rgid = tf->ebx; 74 | int egid = tf->ecx; 75 | 76 | if (rgid > 0) { 77 | if ((cu->p_rgid==rgid) || suser()) 78 | cu->p_rgid = rgid; 79 | else 80 | return syserr(EPERM); 81 | } 82 | if (egid > 0) { 83 | if (cu->p_egid==egid || cu->p_rgid==egid || suser()) 84 | cu->p_egid = egid; 85 | else 86 | return syserr(EPERM); 87 | } 88 | return 0; 89 | } 90 | 91 | /* int setpgrp(void); */ 92 | int sys_setpgrp(struct trap *tf){ 93 | cu->p_pgrp = cu->p_pid; 94 | return 0; 95 | } 96 | 97 | /* -------------------------------- */ 98 | 99 | int sys_umask(struct trap *tf){ 100 | int mask = tf->ebx & 0777; 101 | int old; 102 | 103 | old = cu->p_umask; 104 | cu->p_umask = mask; 105 | return old; 106 | } 107 | 108 | /* -------------------------------- */ 109 | 110 | int sys_stime(struct trap *tf){ 111 | return syserr(ENOSYS); 112 | } 113 | 114 | int sys_utime(struct trap *tf){ 115 | return syserr(ENOSYS); 116 | } 117 | 118 | int sys_time(){ 119 | return syserr(ENOSYS); 120 | } 121 | 122 | -------------------------------------------------------------------------------- /src/kern/sys4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | /* 11 | * sys4.c 12 | * syscalls on signal 13 | * 14 | * */ 15 | 16 | /* kill(int pid, int sig); */ 17 | int sys_kill(struct trap *tf){ 18 | int pid = (int)tf->ebx; 19 | int sig = (int)tf->ecx; 20 | 21 | return do_kill(pid, sig); 22 | } 23 | 24 | int sys_pause(struct trap *tf){ 25 | sleep((uint)&sys_pause, PWAIT); 26 | return 0; 27 | } 28 | 29 | /* -------------------------------------------------- */ 30 | 31 | /* signal(int sig, void (*ufunc)(int)); */ 32 | int sys_signal(struct trap *tf){ 33 | int sig = (int)tf->ebx; 34 | uint ufunc = (uint)tf->ecx; 35 | 36 | return do_signal(sig, (void*)ufunc); 37 | } 38 | 39 | /* sigaction(int sig, struct sigaction *sa, struct sigaction *old_sa); */ 40 | int sys_sigaction(struct trap *tf){ 41 | int sig = (int) tf->ebx; 42 | struct sigaction *sa = (struct sigaction*) tf->ecx; 43 | struct sigaction *old_sa = (struct sigaction*)tf->edx; 44 | 45 | return do_sigaction(sig, sa, old_sa); 46 | } 47 | 48 | /* called on returning from the signal handler. 49 | * note: this syscall should NEVER be called directly. 50 | * */ 51 | int sys_sigreturn(struct trap *tf){ 52 | struct jmp_buf *ujbuf; 53 | ujbuf = (struct jmp_buf*)(tf->eip-46); // hard coded here, be careful 54 | tf->esp = ujbuf->esp; 55 | tf->eip = ujbuf->eip; 56 | tf->ebx = ujbuf->ebx; 57 | tf->ecx = ujbuf->ecx; 58 | tf->edx = ujbuf->edx; 59 | tf->edi = ujbuf->edi; 60 | tf->esi = ujbuf->esi; 61 | tf->ebp = ujbuf->ebp; 62 | cu->p_sigmask = ujbuf->__sigmask; 63 | return 0; 64 | } 65 | 66 | int sys_alarm(struct trap *tf){ 67 | syserr(ENOSYS); 68 | return -1; 69 | } 70 | 71 | /* --------------------------- */ 72 | 73 | int sys_sync(struct trap *tf){ 74 | syserr(ENOSYS); 75 | return -1; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /src/kern/sysent.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | /* 9 | * sys.c 10 | * 11 | * this file implies the common handler of all syscalls - do_syscall(); 12 | * each syscall has got one syscall number, and a trap frame as parameters, 13 | * eax is it's number, and ebx, ecx, edx, as parameters, return value 14 | * stores in eax. 15 | * 16 | * commonly returns -errno on error. 17 | * 18 | * */ 19 | 20 | int errno = 0; 21 | 22 | static void* sys_routines[NSYSC] = { 23 | [NR_debug] = &sys_debug, 24 | // 25 | [NR_access] = &sys_access, 26 | [NR_creat] = &sys_creat, 27 | [NR_open] = &sys_open, 28 | [NR_close] = &sys_close, 29 | [NR_fcntl] = &sys_fcntl, 30 | [NR_write] = &sys_write, 31 | [NR_read] = &sys_read, 32 | [NR_stat] = &sys_stat, 33 | [NR_fstat] = &sys_fstat, 34 | [NR_dup] = &sys_dup, 35 | [NR_dup2] = &sys_dup2, 36 | [NR_link] = &sys_link, 37 | [NR_unlink] = &sys_unlink, 38 | [NR_chroot] = &sys_chroot, 39 | [NR_chdir] = &sys_chdir, 40 | // 41 | [NR_fork] = &sys_fork, 42 | [NR_exec] = &sys_exec, 43 | [NR__exit] = &sys__exit, 44 | [NR_waitpid] = &sys_waitpid, 45 | [NR_wait] = &sys_wait, 46 | // 47 | [NR_nice] = &sys_nice, 48 | [NR_getpid] = &sys_getpid, 49 | [NR_getppid] = &sys_getppid, 50 | [NR_getuid] = &sys_getuid, 51 | [NR_geteuid] = &sys_geteuid, 52 | [NR_getgid] = &sys_getgid, 53 | [NR_getegid] = &sys_getegid, 54 | [NR_getpgrp] = &sys_getpgrp, 55 | [NR_setpgrp] = &sys_setpgrp, 56 | [NR_setreuid] = &sys_setreuid, 57 | [NR_setregid] = &sys_setregid, 58 | // 59 | [NR_pause] = &sys_pause, 60 | [NR_kill] = &sys_kill, 61 | [NR_signal] = &sys_signal, 62 | [NR_sigaction] = &sys_sigaction, 63 | [NR_sigreturn] = &sys_sigreturn, 64 | &nosys, 65 | }; 66 | 67 | /***********************************************************/ 68 | 69 | int nosys(struct trap *tf){ 70 | syserr(ENOSYS); 71 | return -1; 72 | } 73 | 74 | /* ---------------------------------------------- */ 75 | 76 | /* returns 1 on current is super user(aka. root) */ 77 | uint suser(){ 78 | if (cu->p_euid == 0) { 79 | return 1; 80 | } 81 | return 0; 82 | } 83 | 84 | /* returns a error code. always returns -1. */ 85 | int syserr(uint err){ 86 | cu->p_error = err; 87 | return -1; 88 | } 89 | 90 | /* common handlers for all syscalls, if an syserr raised, 91 | * returns a negative number: 0 - cu->p_error. */ 92 | int do_syscall(struct trap *tf){ 93 | int ret; 94 | int (*func)(struct trap *tf); 95 | 96 | if (tf->eax > NSYSC) { 97 | panic("bad syscall"); 98 | } 99 | cu->p_error = 0; 100 | func = sys_routines[tf->eax]; 101 | 102 | if (func == NULL) 103 | func = &nosys; 104 | ret = (*func)(tf); 105 | // 106 | if (ret < 0) 107 | tf->eax = 0 - cu->p_error; 108 | else 109 | tf->eax = ret; 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /src/kern/timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define HZ 100 8 | 9 | static volatile uint tick = 0; 10 | static volatile uint timestamp = 0; 11 | 12 | /*****************************************************/ 13 | 14 | /* read/write RTC */ 15 | char cmos_read(char port){ 16 | outb(0x70, port&0x7F); 17 | return BCD_TO_BIN(inb(0x71)); 18 | } 19 | 20 | void cmos_write(char port, char val){ 21 | outb(0x70, port&0x7F); 22 | outb(0x71, BCD_TO_BIN(val)); 23 | } 24 | 25 | /* get system time */ 26 | uint cmos_time(){ 27 | int year, month, mday, hour, min, sec; 28 | uint r; 29 | year = cmos_read(RTC_CENTURY)*100 + cmos_read(RTC_YEAR) - 1970; // start at UNIX era 30 | month = cmos_read(RTC_MONTH); 31 | mday = cmos_read(RTC_MDAY); 32 | hour = cmos_read(RTC_HOUR); 33 | min = cmos_read(RTC_MIN); 34 | sec = cmos_read(RTC_SEC); 35 | // magic offsets (y+1) needed to get leapyears right. 36 | r = YEAR*year + DAY*((year+1)/4); 37 | r += monthtab[month-1]; 38 | // and (y+2) here. If it wasn't a leap-year, we have to adjust. 39 | if (month>1 && ((year+2)%4)){ 40 | r -= DAY; 41 | } 42 | r += DAY*(mday-1); 43 | r += HOUR*hour; 44 | r += MINUTE*min; 45 | r += sec; 46 | return r; 47 | } 48 | 49 | uint time(){ 50 | return timestamp; 51 | } 52 | 53 | /*****************************************************/ 54 | 55 | int do_timer(struct trap *tf){ 56 | tick++; 57 | // on shedule 58 | if (cu->p_cpu+1 <= 127) { 59 | cu->p_cpu++; 60 | } 61 | // per second 62 | if (tick % HZ ==0){ 63 | sched_cpu(); 64 | timestamp++; 65 | } 66 | return 0; 67 | } 68 | 69 | /* Initialize PIT and CMOS time. */ 70 | void timer_init(){ 71 | uint di = 1193180/HZ; 72 | outb(0x43, 0x36); 73 | outb(0x40, (uchar)(di&0xff)); 74 | outb(0x40, (uchar)(di>>8)); 75 | // 76 | timestamp = cmos_time(); 77 | // 78 | irq_enable(0); 79 | set_hwint(IRQ0+0, &do_timer); 80 | // printk("current cmos time: %d\n", cmos_time()); 81 | } 82 | 83 | -------------------------------------------------------------------------------- /src/kern/trap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // from hwint.S 7 | extern uint _hwint[256]; 8 | 9 | // lidt idt_desc 10 | struct gate_desc idt[256]; 11 | struct idt_desc idt_desc; 12 | 13 | // handlers to each int_no 14 | // which inited as 0 15 | static void* hwint_routines[256] = {0, }; 16 | 17 | static char *trap_str[] = { 18 | "Division By Zero", 19 | "Debug", 20 | "Non Maskable Interrupt", 21 | "Breakpoint", 22 | "Into Detected Overflow", 23 | "Out of Bounds", 24 | "Invalid Opcode", 25 | "No Coprocessor", 26 | // 27 | "Double Fault", 28 | "Coprocessor Segment Overrun", 29 | "Bad TSS", 30 | "Segment Not Present", 31 | "Stack Fault", 32 | "General Protection Fault", 33 | "Page Fault", 34 | "Unknown Interrupt", 35 | // 36 | "Coprocessor Fault", 37 | "Alignment Check", 38 | "Machine Check", 39 | "Reserved", 40 | "Reserved", 41 | "Reserved", 42 | "Reserved", 43 | "Reserved", 44 | // 45 | "Reserved", 46 | "Reserved", 47 | "Reserved", 48 | "Reserved", 49 | "Reserved", 50 | "Reserved", 51 | "Reserved", 52 | "Reserved" 53 | }; 54 | 55 | /* ------------------------------------------------------------ */ 56 | 57 | /* 58 | * Remap the irq and initialize the IRQ mask. 59 | * 60 | * note:If you do not remap irq, a Double Fault comes 61 | * along with every interrupt. 62 | * After initialization, register 0xA1 and 0x21 are the 63 | * hi/lo bytes of irq mask, respectively. 64 | * */ 65 | void irq_init(){ 66 | // hard coded, don't touch. 67 | outb(PIC1, 0x11); 68 | outb(PIC2, 0x11); 69 | outb(PIC1+1, IRQ0); // offset 1, 0-7 70 | outb(PIC2+1, IRQ0+8); // offset 2, 7-15 71 | outb(PIC1+1, 4); 72 | outb(PIC2+1, 2); 73 | outb(PIC1+1, 0x01); 74 | outb(PIC2+1, 0x01); 75 | // Initialize IRQ mask has interrupt 2 enabled. 76 | outb(PIC1+1, 0xFF); 77 | outb(PIC2+1, 0xFF); 78 | irq_enable(2); 79 | } 80 | 81 | void irq_eoi(int nr){ 82 | outb(PIC1, PIC_EOI); 83 | if (nr >= 40) { 84 | outb(PIC2, PIC_EOI); 85 | } 86 | } 87 | 88 | void irq_enable(uchar irq){ 89 | ushort irq_mask = (inb(PIC2+1)<<8) + inb(PIC1+1); 90 | irq_mask &= ~(1<> 8); 93 | } 94 | 95 | /* ------------------------------------------------------------------- */ 96 | 97 | void idt_set_gate(uint nr, uint base, ushort sel, uchar type, uchar dpl) { 98 | idt[nr].base_lo = (base & 0xFFFF); 99 | idt[nr].base_hi = (base >> 16) & 0xFFFF; 100 | idt[nr].sel = sel; 101 | idt[nr].dpl = dpl; 102 | idt[nr].type = type; 103 | idt[nr].always0 = 0; 104 | idt[nr].p = 1; 105 | idt[nr].sys = 0; 106 | } 107 | 108 | static inline void syst_gate(uint nr, uint base){ 109 | idt_set_gate(nr, base, KERN_CS, STS_TRG, RING3); 110 | } 111 | static inline void intr_gate(uint nr, uint base){ 112 | idt_set_gate(nr, base, KERN_CS, STS_IG, RING0); 113 | } 114 | static inline void trap_gate(uint nr, uint base){ 115 | idt_set_gate(nr, base, KERN_CS, STS_TRG, RING0); 116 | } 117 | 118 | void hwint_init(){ 119 | int i; 120 | for(i=0; i<32; i++) 121 | trap_gate(i, _hwint[i]); 122 | for(i=32; i<48; i++) 123 | intr_gate(i, _hwint[i]); 124 | syst_gate(0x03, _hwint[0x03]); // int3 125 | syst_gate(0x04, _hwint[0x04]); // overflow 126 | syst_gate(0x05, _hwint[0x05]); // bound 127 | syst_gate(0x80, _hwint[0x80]); // syscall 128 | // Each handler handled in his file. 129 | set_hwint(0x80, &do_syscall); // in syscall.c 130 | } 131 | 132 | void lidt(struct idt_desc idtd){ 133 | asm volatile( 134 | "lidt %0" 135 | :: "m"(idtd)); 136 | } 137 | 138 | /* ------------------------------------------------------------------- */ 139 | 140 | /* 141 | * The comman handler for all IRQ request as a dispatcher. Each irq 142 | * handler were held inside the array *hwint_routines*. 143 | * 144 | * note: While an IRQ were recieved, we have to notice the 8259 chip 145 | * that End of Interrupt via a PIC_EOI. If the IRQ came from the Master 146 | * PIC, it is sufficient to issue this command only to the Master PIC; 147 | * however if the IRQ came from the Slave PIC, it is necessary to issue 148 | * the command to both PIC chips. 149 | * */ 150 | void hwint_common(struct trap *tf) { 151 | void (*func)(struct trap *tf); 152 | 153 | // save the current trap frame 154 | if ((tf->cs & 3)==RING3) { 155 | cu->p_trap = tf; 156 | } 157 | func = hwint_routines[tf->int_no]; 158 | if (tf->int_no < 32) { 159 | // trap 160 | if (func) 161 | func(tf); 162 | else 163 | sigsend(cu->p_pid, SIGTRAP, 1); 164 | } 165 | else { 166 | // irq, syscall 167 | irq_eoi(tf->int_no); 168 | if (func) 169 | func(tf); 170 | } 171 | // on signal 172 | if (issig() && (cu->p_stat!=SZOMB) && ((tf->cs & 3)==RING3)) { 173 | psig(); 174 | } 175 | // on sheduling 176 | // if the re-schedule flag is set, make an task swtch. 177 | // and make sure only swtch on returning to user mode, 178 | // thus to keep the kernel nonpremtive. 179 | setpri(cu); 180 | if ((tf->cs & 3)==RING3) { 181 | swtch(); 182 | } 183 | } 184 | 185 | void set_hwint(int nr, int (*func)(struct trap *tf)){ 186 | hwint_routines[nr] = func; 187 | } 188 | 189 | /***********************************************************************************/ 190 | 191 | void dump_tf(struct trap *tf){ 192 | printk("gs = %x, fs = %x, es = %x, ds = %x\n", tf->gs, tf->fs, tf->es, tf->ds); 193 | printk("edi = %x, esi = %x, ebp = %x \n",tf->edi, tf->esi, tf->ebp); 194 | printk("ebx = %x, edx = %x, ecx = %x, eax = %x \n",tf->ebx, tf->edx, tf->ecx, tf->eax); 195 | printk("int_no = %x, err_code = %x\n", tf->int_no, tf->err_code); 196 | printk("eip = %x, cs = %x, eflags = %x\n", tf->eip, tf->cs, tf->eflags); 197 | printk("esp = %x, ss = %x \n", tf->esp, tf->ss); 198 | uint cr2, kern_ss; 199 | asm("mov %%cr2, %%eax":"=a"(cr2)); 200 | printk("cr2 = %x, ", cr2); 201 | asm("mov %%ss, %%eax":"=a"(kern_ss)); 202 | printk("kern_ss = %x\n", kern_ss); 203 | printk("trap_str: %s", trap_str[tf->int_no]); 204 | } 205 | 206 | /***********************************************************************************/ 207 | 208 | void idt_init(){ 209 | // init idt_desc 210 | idt_desc.limit = (sizeof(struct gate_desc) * 256) - 1; 211 | idt_desc.base = (uint)&idt; 212 | // init irq 213 | irq_init(); 214 | // load intr vectors and lidt 215 | hwint_init(); 216 | lidt(idt_desc); 217 | } 218 | 219 | 220 | -------------------------------------------------------------------------------- /src/kern/wait.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // 6 | #include 7 | #include 8 | // 9 | #include 10 | 11 | 12 | /* 13 | * The value of pid can be: (via `man waitpid`) 14 | * < -1 wait for any child process whose process group ID is equal to the absolute value of pid. 15 | * -1 wait for any child process. 16 | * 0 wait for any child process whose process group ID is equal to that of the calling process. 17 | * > 0 wait for the child whose process ID is equal to the value of pid. 18 | * 19 | * opt: 20 | * WNOHANG : return immediately if no child exited. 21 | * 22 | */ 23 | int do_waitpid(int pid, int *stat, int opt){ 24 | struct proc *p; 25 | uint nr; 26 | 27 | if (vm_verify(stat, sizeof(int)) < 0){ 28 | syserr(EFAULT); 29 | return -1; 30 | } 31 | // 32 | _repeat: 33 | for(nr=1; nrp_ppid!=cu->p_pid || p->p_pgrp!=cu->p_pid) 37 | continue; 38 | } 39 | else if (pid == -1) { 40 | if (p->p_ppid!=cu->p_pid) 41 | continue; 42 | } 43 | else if (pid == 0) { 44 | if (p->p_ppid!=cu->p_pid || p->p_pgrp!=cu->p_pgrp) 45 | continue; 46 | } 47 | else if (pid > 0) { 48 | if (p->p_ppid!=cu->p_pid || p->p_pid!=pid) 49 | continue; 50 | } 51 | // on found 52 | switch(p->p_stat){ 53 | case SZOMB: 54 | *stat = p->p_ret; 55 | pid = p->p_pid; 56 | proc[pid] = NULL; 57 | kfree(p, PAGE); 58 | return pid; 59 | default: 60 | continue; 61 | } 62 | } 63 | } 64 | 65 | // if no child has found 66 | if (opt & WNOHANG) { 67 | return 0; 68 | } 69 | sleep((uint)cu, PWAIT); 70 | goto _repeat; 71 | } 72 | -------------------------------------------------------------------------------- /src/lib/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void* memcpy(void *dest, void *src, unsigned int count) { 4 | char *sp = (char *)src; 5 | char *dp = (char *)dest; 6 | int i; 7 | for (i=0; i 0) 55 | while (--cnt) 56 | *dst++ = '\0'; 57 | return tmp; 58 | } 59 | 60 | /* 61 | * note that '\0' is considered to be part of the string. 62 | * returns not a number but a pointer. 63 | * */ 64 | char* strchr(const char *str, int c){ 65 | char *tmp = (char*)str; 66 | 67 | for(; *tmp!='\0'; tmp++) { 68 | if (*tmp == (char)c) { 69 | return tmp; 70 | } 71 | } 72 | if (*tmp == (char)c) 73 | return tmp; 74 | return NULL; 75 | } 76 | 77 | /* just like strchr, but in reverse order. */ 78 | char* strrchr(const char *str, int c){ 79 | char *ret, *tmp; 80 | for(; *tmp!='\0'; tmp++){ 81 | if (*tmp == (char)c) { 82 | ret = tmp; 83 | } 84 | } 85 | if (*ret == (char)c) 86 | return ret; 87 | return NULL; 88 | } 89 | 90 | /* 91 | * TODO: debug all these. 92 | * */ 93 | int strcmp(char *s1, char *s2){ 94 | while (*s1 == *s2++) 95 | if (*s1++ == 0) 96 | return (0); 97 | return (*(unsigned char*)s1 - *(unsigned char*)(s2-1)); 98 | } 99 | 100 | int strncmp(char *s1, char* s2, unsigned int n) { 101 | if (n == 0) 102 | return 0; 103 | while(n-- != 0) { 104 | if (*s1 != *s2++) 105 | return (*(unsigned char*)s1 - *(unsigned char*)(s2-1)); 106 | if (*s1++ == 0) 107 | break; 108 | } 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /src/mm/malloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | /* 11 | * malloc.c 12 | * malloc could simplify the implemention of your kernel. 13 | * 14 | * However, this routine kmalloc() should returns a *virutal* memory 15 | * block, whose backend is a page-level allocator -- pgalloc(). 16 | * And the memory block should be aligned with a 2-powered boundary. 17 | * 18 | * */ 19 | 20 | /* 21 | * the bucket table, each slot got a different 2-powered size. 22 | * 1 << 3 == 32, 1 << 12 == 0x1000 23 | * */ 24 | struct bucket bktab[] = { 25 | { 32, 0, NULL, NULL }, 26 | { 64, 0, NULL, NULL }, 27 | { 128, 0, NULL, NULL }, 28 | { 256, 0, NULL, NULL }, 29 | { 512, 0, NULL, NULL }, 30 | { 1024, 0, NULL, NULL }, 31 | { 2048, 0, NULL, NULL }, 32 | { 4096, 0, NULL, NULL } 33 | }; 34 | 35 | struct bucket bkfreelist = {0, }; 36 | 37 | /* ---------------------------------------------------------- */ 38 | 39 | inline int bkslot(int size){ 40 | int n,i; 41 | 42 | if (size <= 0) 43 | return -1; 44 | n = 16; 45 | i = 0; 46 | while((n <<= 1)<=4096) { 47 | if (size <= n){ 48 | return i; 49 | } 50 | i++; 51 | } 52 | return -1; 53 | } 54 | 55 | /* 56 | * Allocate one bucket. All free buckets are cached in one free list, 57 | * if no free bucket, allocate one page and divide it into buckets. 58 | * */ 59 | struct bucket *bkalloc(){ 60 | struct bucket *bk, *bh; 61 | struct page *pg; 62 | uint page, page_end; 63 | 64 | // no free bucket, allocate one page and divide it into buckets 65 | if (bkfreelist.bk_next == NULL) { 66 | bh = &bkfreelist; 67 | pg = pgalloc(); 68 | page = pg->pg_num*PAGE; 69 | page_end = page + PAGE; 70 | cli(); 71 | for (bk = (struct bucket *)page; (uint)bk < page_end; bk++) { 72 | bh->bk_next = bk; 73 | bk->bk_next = NULL; 74 | bh = bk; 75 | } 76 | sti(); 77 | } 78 | // got free bucket, take the head. 79 | bk = bkfreelist.bk_next; 80 | bkfreelist.bk_next = bk->bk_next; 81 | return bk; 82 | } 83 | 84 | /* free one bucket back to the free list. */ 85 | int bkfree(struct bucket *bk){ 86 | cli(); 87 | bk->bk_next = bkfreelist.bk_next; 88 | bkfreelist.bk_next = bk; 89 | sti(); 90 | return 0; 91 | } 92 | 93 | int bkinit(struct bucket *bk, int size){ 94 | uint page; 95 | int i; 96 | struct page *pg; 97 | struct bkentry *beh, *be; 98 | 99 | pg = pgalloc(); 100 | page = (pg->pg_num)*PAGE; 101 | bk->bk_page = page; 102 | bk->bk_size = size; 103 | bk->bk_entry = beh = (struct bkentry *)page; 104 | for (i=0; ibke_next = be; // #GPF here 107 | be->bke_next = NULL; 108 | beh = be; 109 | } 110 | return 0; 111 | } 112 | 113 | /* -------------------------------------------------------- */ 114 | 115 | /* 116 | * kmalloc(). 117 | * one page size is special considered, for no need to arrange 118 | * any bucket. which symmeties in kfree. 119 | * */ 120 | void* kmalloc(uint size){ 121 | struct bucket *bk, *bh; 122 | struct bkentry *be; 123 | struct page *pg; 124 | int sn; 125 | 126 | sn = bkslot(size); 127 | if (sn < 0) { 128 | panic("kmalloc(): bad size"); 129 | } 130 | 131 | bk = bh = &bktab[sn]; 132 | size = bh->bk_size; 133 | // special case for one page size 134 | if (size==PAGE) { 135 | pg = pgalloc(); 136 | return (void*)(pg->pg_num * PAGE); 137 | } 138 | // normal case: 139 | _find: 140 | // tranverse each bucket 141 | while((bk = bk->bk_next) != NULL){ 142 | // got free entry 143 | if (bk->bk_entry != NULL) { 144 | be = bk->bk_entry; 145 | bk->bk_entry = be->bke_next; 146 | return (void*)be; 147 | } 148 | } 149 | // have no free bucket and no free entry 150 | bk = bkalloc(); 151 | bkinit(bk, size); 152 | bk->bk_next = bh->bk_next; 153 | bh->bk_next = bk; 154 | goto _find; 155 | } 156 | 157 | /* 158 | * 159 | * */ 160 | int kfree(void* addr, uint size){ 161 | int sn; 162 | uint page; 163 | struct page *pg; 164 | struct bucket *bh, *bk; 165 | struct bkentry *be; 166 | 167 | sn = bkslot(size); 168 | if (sn < 0) { 169 | panic("kfree(): bad size"); 170 | } 171 | page = PPN(addr) * PAGE; 172 | // 173 | bk = bh = &bktab[sn]; 174 | size = bh->bk_size; 175 | be = (struct bkentry *)addr; 176 | // special case for one page size 177 | if (size==PAGE) { 178 | pg = pgfind(PPN(addr)); 179 | pgfree(pg); 180 | return 0; 181 | } 182 | // normal case 183 | while((bk = bk->bk_next) != NULL) { 184 | if (bk->bk_page == page) { 185 | be->bke_next = bk->bk_entry; 186 | bk->bk_entry = be; 187 | return 0; 188 | } 189 | } 190 | panic("kfree(): not avail addr"); 191 | } 192 | -------------------------------------------------------------------------------- /src/mm/pgfault.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | /* 10 | * the handler of a page fault raised on PTE_P is off. 11 | * */ 12 | void do_no_page(uint vaddr){ 13 | struct vm *vm; 14 | struct vma *vp; 15 | struct pte *pte; 16 | struct page *pg; 17 | uint off; 18 | char *buf; 19 | 20 | vm = &cu->p_vm; 21 | // if this page lies on the edge of user stack, grows the stack. 22 | if (vm->vm_stack.v_base - vaddr <= PAGE) { 23 | vm->vm_stack.v_base -= PAGE; 24 | vm->vm_stack.v_size += PAGE; 25 | pg = pgalloc(); 26 | pgattach(vm->vm_pgd, PG_ADDR(vaddr), pg, PTE_U|PTE_W|PTE_P); 27 | return; 28 | } 29 | // else 30 | vp = find_vma(vaddr); 31 | if (vp==NULL) { 32 | sigsend(cu->p_pid, SIGSEGV, 1); 33 | return; 34 | } 35 | // demand zero 36 | if (vp->v_flag & VMA_ZERO) { 37 | pg = pgalloc(); 38 | pgattach(vm->vm_pgd, PG_ADDR(vaddr), pg, PTE_U|PTE_W|PTE_P); 39 | memset((void*)PG_ADDR(vaddr), 0, PAGE); 40 | return; 41 | } 42 | // demand file 43 | if (vp->v_flag & VMA_MMAP) { 44 | pg = pgalloc(); 45 | pte = pgattach(vm->vm_pgd, PG_ADDR(vaddr), pg, PTE_U|PTE_W|PTE_P); 46 | // fill this new-allocated page 47 | // hint: vaddr is *ALWAYS* greater than or equal with vp->v_base 48 | buf = (char*)PG_ADDR(vaddr); 49 | off = (uint)buf - vp->v_base + vp->v_ioff; 50 | lock_ino(vp->v_ino); 51 | readi(vp->v_ino, buf, off, PAGE); 52 | unlk_ino(vp->v_ino); 53 | pte->pt_flag &= ~(vp->v_flag&VMA_RDONLY? 0:PTE_W); 54 | flmmu(); 55 | return; 56 | } 57 | // segmentation fault 58 | panic("do_no_page()"); 59 | } 60 | 61 | /* 62 | * the handler of the read-only protection. here is the 'copy' action 63 | * of the implemtion of copy-on-write. 64 | * If this one is the last one who did the write, just mark the page as 65 | * write-able. 66 | * else allocate one page and associate inside the page table. 67 | * */ 68 | void do_wp_page(uint vaddr){ 69 | struct vma *vp; 70 | struct pte *pte; 71 | struct page *pg; 72 | char *old_page, *new_page; 73 | 74 | vp = find_vma(vaddr); 75 | if (vp->v_flag & VMA_RDONLY) { 76 | sigsend(cu->p_pid, SIGSEGV, 1); 77 | return; 78 | } 79 | if (vp->v_flag & VMA_PRIVATE) { 80 | pte = find_pte(cu->p_vm.vm_pgd, vaddr, 1); 81 | pg = pgfind(pte->pt_off); 82 | if (pg->pg_count > 1) { 83 | pg->pg_count--; //decrease the reference count of the old page. 84 | old_page = (char*)(pte->pt_off * PAGE); 85 | new_page = (char*)kmalloc(PAGE); 86 | memcpy(new_page, old_page, PAGE); 87 | pte->pt_off = PPN(new_page); 88 | pte->pt_flag |= PTE_W; 89 | flmmu(); 90 | } 91 | else if (pg->pg_count==1) { 92 | pte->pt_flag |= PTE_W; 93 | flmmu(); 94 | } 95 | } 96 | } 97 | 98 | /* 99 | * the common handler of all page faults, as a dispatcher. 100 | * */ 101 | int do_pgfault(struct trap *tf){ 102 | uint addr; 103 | 104 | asm volatile("movl %%cr2, %0":"=a"(addr)); 105 | //printk("do_pgfault(): %d err:%x addr: %x\n", cu->p_pid, tf->err_code, addr); 106 | // invalid page 107 | if ((tf->err_code & PFE_P)==0) { 108 | do_no_page(addr); 109 | return 0; 110 | } 111 | // write procted page 112 | if (tf->err_code & PFE_W) { 113 | do_wp_page(addr); 114 | return 0; 115 | } 116 | // raise a signal here, hence segmention fault. 117 | if (tf->err_code & PFE_U) { 118 | sigsend(cu->p_pid, SIGSEGV, 1); 119 | } 120 | 121 | return 0; 122 | } 123 | 124 | -------------------------------------------------------------------------------- /src/mm/pm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | // 7 | #include 8 | #include 9 | // 10 | #include 11 | #include 12 | #include 13 | // 14 | #include 15 | #include 16 | #include 17 | 18 | /* pm.c 19 | * this file implies some routines on the allocation, free, and modification of 20 | * physical pages(.aka page frames). 21 | * */ 22 | 23 | 24 | /* 25 | * the map for page frames. Each physical page is associated with one reference 26 | * count, and it's free on 0. Only 0 can be allocated via pgalloc(). 27 | * Reference count is increased on a fork. 28 | * 29 | * */ 30 | struct page coremap[NPAGE]; 31 | struct page pgfreelist; 32 | 33 | /* returns the page struct via a physical page number. */ 34 | struct page* pgfind(uint pn){ 35 | if (pn<0 || pn>=NPAGE ) { 36 | panic("pgfind(): bad page number."); 37 | } 38 | return &coremap[pn]; 39 | } 40 | 41 | /* 42 | * allocate an free physical page. (always success) 43 | * get the head of the freelist, remove it and increase the refcount. 44 | * */ 45 | struct page* pgalloc(){ 46 | struct page *pp; 47 | 48 | if (pgfreelist.pg_next == NULL) { 49 | panic("no free page.\n"); 50 | return NULL; 51 | } 52 | 53 | cli(); 54 | pp = pgfreelist.pg_next; 55 | pgfreelist.pg_next = pp->pg_next; 56 | pp->pg_count = 1; 57 | sti(); 58 | return pp; 59 | } 60 | 61 | /* 62 | * free a physical page. decrease the reference count and put it back 63 | * to the freelist. 64 | */ 65 | int pgfree(struct page *pp){ 66 | if (pp->pg_count==0) { 67 | panic("freeing a free page."); 68 | } 69 | 70 | cli(); 71 | pp->pg_count--; 72 | if (pp->pg_count==0) { 73 | pp->pg_next = pgfreelist.pg_next; 74 | pgfreelist.pg_next = pp; 75 | } 76 | sti(); 77 | return pp->pg_num; 78 | } 79 | 80 | /* 81 | * map a linear address to physical address, and flush the TLB. 82 | * */ 83 | struct pte* pgattach(struct pde *pgd, uint vaddr, struct page *pp, uint flag){ 84 | struct pte *pte; 85 | 86 | pte = find_pte(pgd, vaddr, 1); 87 | pte->pt_off = pp->pg_num; 88 | pte->pt_flag = flag; 89 | lpgd(pgd); 90 | return pte; 91 | } 92 | 93 | /* initialize pages' free list. */ 94 | int pm_init(){ 95 | struct page *pp, *ph; 96 | uint pn; 97 | 98 | // mark the reserved pages 99 | // 0~4kb is reserved for the kernel stack of proc0; 100 | // 640kb ~ 1mb is system reserved, BIOS and blah; 101 | // 1mb ~ __kend__ is reserved for the kernel image.; 102 | for (pn=0; pn<1; pn++) { 103 | coremap[pn].pg_num = pn; 104 | coremap[pn].pg_flag = PG_RSVD; 105 | coremap[pn].pg_count = 100; 106 | } 107 | for (pn=640*1024/PAGE; pnpg_flag & PG_RSVD) || (pp->pg_count > 0)) { 117 | continue; 118 | } 119 | pp->pg_num = pn; 120 | pp->pg_flag = 0; 121 | pp->pg_count = 0; 122 | // 123 | pp->pg_next = NULL; 124 | ph->pg_next = pp; 125 | ph = pp; 126 | } 127 | 128 | return 0; 129 | } 130 | 131 | /* Map the top 128mb virtual memory as physical memory. Initiliaze 132 | * the page-level allocator, setup the fault handler, enable paging 133 | * and misc. 134 | * */ 135 | void mm_init(){ 136 | // init kernel's address space 137 | pgd_init(pgd0); 138 | // init physical page allocator 139 | pm_init(); 140 | // set fault handler 141 | set_hwint(0x0E, do_pgfault); 142 | // load page directory and enable the MMU. 143 | lpgd(pgd0); 144 | mmu_enable(); 145 | } 146 | -------------------------------------------------------------------------------- /src/mm/pte.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // 6 | #include 7 | #include 8 | // 9 | #include 10 | #include 11 | #include 12 | // 13 | #include 14 | #include 15 | #include 16 | 17 | /* pte.c 18 | * some operations on page tables. 19 | * note: PGD and page tables are all one page size, allocated via the routine kmalloc(). 20 | * 21 | * note: on *Copy-On-Write*, both parent and child process will be marked 22 | * write-protected, and increase the reference count of each shared page 23 | * frame. 24 | * On write-proctection fault occured, if the reference count greater 25 | * than 1, allocate one page frame, attach it to where it deserves and 26 | * decrease the reference count; 27 | * If the reference count equals 1, just mark it Writeable. 28 | * 29 | * */ 30 | 31 | /* 32 | * the proc[0]'s page directory, as initialized, it will map the top 128mb virtual memory 33 | * as physical memory, by the 4mb big page tables. 34 | * */ 35 | struct pde pgd0[1024] __attribute__((aligned(4096))); 36 | 37 | /* --------------------------------------------------------- */ 38 | 39 | /* 40 | * given the current proc's page directory, find the pte where 41 | * the virtual address lied in. If the 'creat' parameter is set, 42 | * allocate a page as middle page table and always success. 43 | * */ 44 | struct pte* find_pte(struct pde *pgd, uint vaddr, uint creat){ 45 | struct pde *pde; 46 | struct pte *pt; 47 | struct page *pg; 48 | 49 | if (vaddr < KMEM_END) { 50 | panic("find_pte(): don't touch kernel's address space."); 51 | } 52 | pde = &pgd[PDX(vaddr)]; 53 | if ((pde->pd_flag & PTE_P)==0) { 54 | if (creat==0) { 55 | return NULL; 56 | } 57 | pg = pgalloc(); 58 | pde->pd_flag = PTE_P | PTE_U | PTE_W; 59 | pde->pd_off = pg->pg_num; 60 | pt = (struct pte*)(pde->pd_off * PAGE); 61 | memset(pt, 0, PAGE); 62 | flmmu(); 63 | } 64 | pt = (struct pte*)(pde->pd_off * PAGE); 65 | return &pt[PTX(vaddr)]; 66 | } 67 | 68 | /* initialize the PGD as mapping the kernel's address space. 69 | * called in mm_init() and vm_clone(). 70 | * */ 71 | int pgd_init(struct pde *pgd){ 72 | uint pn; 73 | 74 | // map the entire physical memory into the kernel's address space, via 4mb big pages 75 | for (pn=0; pnpd_flag = opde->pd_flag; 102 | if (opde->pd_flag & PTE_P) { 103 | old_pt = (struct pte*)(opde->pd_off * PAGE); 104 | new_pt = (struct pte*)kmalloc(PAGE); 105 | npde->pd_off = PPN(new_pt); 106 | for(pn=0; pn<1024; pn++){ 107 | opte = &old_pt[pn]; 108 | npte = &new_pt[pn]; 109 | npte->pt_off = opte->pt_off; 110 | npte->pt_flag = opte->pt_flag; 111 | if (opte->pt_flag & PTE_P) { 112 | // turn off each pte's PTE_W 113 | npte->pt_flag &= ~PTE_W; 114 | opte->pt_flag &= ~PTE_W; 115 | // increase the ref count 116 | pg = pgfind(opte->pt_off); 117 | pg->pg_count++; 118 | } 119 | } 120 | } 121 | } 122 | return 0; 123 | } 124 | 125 | /* decrease all the pages' reference count, and free the page tables. */ 126 | int pt_free(struct pde *pgd){ 127 | struct pde *pde; 128 | struct pte *pte, *pt; 129 | struct page *pg; 130 | uint pdn, pn; 131 | 132 | for(pdn=PDX(KMEM_END); pdn<1024; pdn++) { 133 | pde = &pgd[pdn]; 134 | if (pde->pd_flag & PTE_P) { 135 | pt = (struct pte*)(pde->pd_off * PAGE); 136 | for(pn=0; pn<1024; pn++) { 137 | pte = &pt[pn]; 138 | if (pte->pt_flag & PTE_P) { 139 | pg = pgfind(pte->pt_off); 140 | pgfree(pg); 141 | } 142 | } 143 | kfree(pt, PAGE); 144 | } 145 | } 146 | return 0; 147 | } 148 | 149 | /* flush the TLB */ 150 | void flmmu(){ 151 | lpgd(cu->p_vm.vm_pgd); 152 | } 153 | -------------------------------------------------------------------------------- /src/mm/vm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // 6 | #include 7 | #include 8 | // 9 | #include 10 | #include 11 | #include 12 | // 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | /* 19 | * vm.c 20 | * */ 21 | 22 | /* --------------------------------------------------------- */ 23 | 24 | /* 25 | * Clone the kernel's address space first, the only way on 26 | * initializing a struct vm. 27 | * */ 28 | int vm_clone(struct vm *to){ 29 | int i; 30 | struct vma *vp; 31 | 32 | to->vm_pgd = (struct pde*)kmalloc(PAGE); 33 | // clone kernel's address space 34 | pgd_init(to->vm_pgd); 35 | // clone user's, aka for each VMA. 36 | for (i=0; ip_vm.vm_area[i]); 38 | if (vp->v_flag != 0) { 39 | // increase the reference count of inode 40 | if (vp->v_ino) { 41 | vp->v_ino->i_count++; 42 | } 43 | to->vm_area[i] = *vp; 44 | } 45 | } 46 | // copy pages tables, with PTE_W turned off. 47 | pt_copy(to->vm_pgd, cu->p_vm.vm_pgd); 48 | return 0; 49 | } 50 | 51 | /* free all the pages used in this process, deallocate all the page tables, 52 | * this routine is called on freeing one task in do_exit(), or overlapping 53 | * a proc's address space on do_exec() is being called. 54 | * note: this routine will *NOT* free the pgd. 55 | * */ 56 | int vm_clear(struct vm *vm){ 57 | struct vma *vp; 58 | int i; 59 | 60 | for (i=0; ivm_area[i]; 62 | if (vp->v_flag != 0) { 63 | if (vp->v_ino) 64 | iput(vp->v_ino); 65 | vp->v_ino = NULL; 66 | vp->v_flag = 0; 67 | vp->v_base = 0; 68 | vp->v_size = 0; 69 | } 70 | } 71 | // free the page tables. (but pgd is not freed yet.) 72 | pt_free(vm->vm_pgd); 73 | return 0; 74 | } 75 | 76 | /* renew a adress space, called on do_exec() */ 77 | int vm_renew(struct vm *vm, struct ahead *ah, struct inode *ip){ 78 | uint base, text, data, bss, heap; 79 | 80 | base = ah->a_entry - sizeof(struct ahead); // note: keep alignment 81 | text = ah->a_entry - sizeof(struct ahead); 82 | data = text + ah->a_tsize; 83 | bss = data + ah->a_dsize; 84 | heap = bss + ah->a_bsize; 85 | // 86 | pgd_init(vm->vm_pgd); 87 | vm->vm_entry = ah->a_entry; 88 | vma_init(&(vm->vm_text), text, ah->a_tsize, VMA_MMAP | VMA_RDONLY | VMA_PRIVATE, ip, text-base); 89 | vma_init(&(vm->vm_data), data, ah->a_dsize, VMA_MMAP | VMA_PRIVATE, ip, data-base); 90 | vma_init(&(vm->vm_bss), bss, ah->a_bsize, VMA_ZERO | VMA_PRIVATE, NULL, 0); 91 | vma_init(&(vm->vm_heap), heap, PAGE, VMA_ZERO | VMA_PRIVATE, NULL, 0); 92 | vma_init(&(vm->vm_stack), VM_STACK, PAGE, VMA_STACK | VMA_ZERO | VMA_PRIVATE, NULL, 0); 93 | return 0; 94 | } 95 | 96 | /* Have a check of virtual memory area on getting a user space 97 | * pointer, on writing a write protected page, x86 do not raise 98 | * a page fault in ring0, so simulate a write only access as 99 | * what mmu does if nessary. 100 | * 101 | * note: 102 | * be aware that do NOT touch the memory in the second argument 103 | * like `vm_verify(path, strlen(path) + 1)`, which is a bug 104 | * 105 | * note2: 106 | * use this routine only before reading and writing the 107 | * user memory. 108 | * */ 109 | int vm_verify(void *vaddr, uint size){ 110 | struct pte *pte; 111 | uint page; 112 | uint addr = (uint)vaddr; 113 | 114 | if (addrp_vm.vm_pgd, page, 1); 120 | if ((pte->pt_flag & PTE_P)==0) { 121 | do_no_page(page); 122 | } 123 | else if ((pte->pt_flag & PTE_W)==0) { 124 | do_wp_page(page); 125 | } 126 | } 127 | return 0; 128 | } 129 | 130 | /* ------------------------------------------------------------------------- */ 131 | 132 | /* 133 | * find the vma where the vaddr lied in, mainly called on do_no_page() or do_wp_page(). 134 | * returns NULL on fail. 135 | * */ 136 | struct vma* find_vma(uint addr){ 137 | struct vma* vma; 138 | struct vma* vp; 139 | // 140 | vma = cu->p_vm.vm_area; 141 | for (vp=&vma[0]; vp<&vma[NVMA]; vp++) { 142 | if (addr >= vp->v_base && addr < vp->v_base+vp->v_size) { 143 | return vp; 144 | } 145 | } 146 | return NULL; 147 | } 148 | 149 | /* initialize a VMA. 150 | * note that each vma is associated with one inode. */ 151 | int vma_init(struct vma *vp, uint base, uint size, uint flag, struct inode *ip, uint ioff){ 152 | vp->v_flag = flag; 153 | vp->v_base = base; 154 | vp->v_size = size; 155 | vp->v_ioff = ioff; 156 | if (ip) { 157 | ip->i_count++; 158 | vp->v_ino = ip; 159 | } 160 | return 0; 161 | } 162 | 163 | /* -------------------------------------------------- */ 164 | 165 | void dump_vm(struct vm *vp){ 166 | printk("vm: %x\n", vp); 167 | printk("vm: ino: %x\n", vp->vm_text.v_ino); 168 | dump_inode(vp->vm_text.v_ino); 169 | } 170 | -------------------------------------------------------------------------------- /tool/boot.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("binary") 2 | ENTRY(_start) 3 | SECTIONS { 4 | .text 0x7c00 : { 5 | *(.text) 6 | *(.rodata) 7 | } 8 | .data : { 9 | *(.data) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tool/main.ld: -------------------------------------------------------------------------------- 1 | ENTRY(kmain) 2 | SECTIONS { 3 | __bios__ = 0xa0000; 4 | vgamem = 0xb8000; 5 | .text 0x100000 : { 6 | __kbegin__ = .; 7 | __code__ = .; 8 | bin/entry.o(.text) bin/main.o(.text) *(.text); 9 | . = ALIGN(4096); 10 | } 11 | .data : { 12 | __data__ = .; 13 | *(.rodata); 14 | *(.data); 15 | . = ALIGN(4096); 16 | } 17 | .bss : { 18 | __bss__ = .; 19 | *(.bss); 20 | . = ALIGN(4096); 21 | } 22 | __kend__ = .; 23 | } 24 | -------------------------------------------------------------------------------- /tool/user.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("a.out-i386-linux") 2 | ENTRY(_start) 3 | 4 | SECTIONS { 5 | . = 0x8000020; 6 | .text : { 7 | __text__ = .; 8 | bin/libsys/entry.o(.text) *(.text) 9 | *(.rodata .gnu.linkonce.*) 10 | . = ALIGN(0x1000); 11 | __text_end__ = .; 12 | } 13 | .data : { 14 | __data__ = .; 15 | *(.data) 16 | . = ALIGN(0x1000); 17 | } 18 | .bss : { 19 | __bss__ = .; 20 | *(.bss) 21 | . = ALIGN(0x1000); 22 | } 23 | /DISCARD/ : { 24 | *(.note .note.* .gnu.* .dynsym .comment .pdr .init .plt .fini .interp) 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /usr/cat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int cat(char *pathp){ 8 | int fd; 9 | char buf[32]; 10 | int n; 11 | 12 | fd = open(pathp, O_RDONLY, 0); 13 | if (fd < 0) 14 | return -1; 15 | 16 | while((n = read(fd, buf, 32)) > 0){ 17 | write(0, buf, n); 18 | } 19 | close(fd); 20 | } 21 | 22 | 23 | 24 | int main(int argc, char **argv){ 25 | int i = 0; 26 | 27 | if (argc < 1) { 28 | return -1; 29 | } 30 | 31 | for(i=1; i 2 | #include 3 | #include 4 | 5 | int i; 6 | 7 | int main(int argc, char **argv) { 8 | printf("hello!\n"); 9 | for(i=0; i 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv){ 6 | uint ret, pid; 7 | if (fork()==0) { 8 | exec("/bin/sh", NULL); 9 | } 10 | while(1) { 11 | pid = wait(&ret); 12 | //printf("exited - pid %d => %d\n", pid, ret); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /usr/libsys/entry.S: -------------------------------------------------------------------------------- 1 | ; the entry of all user programs 2 | ; make some initialization and jump to main() 3 | 4 | [global _start] 5 | [extern main] 6 | [extern exit] 7 | _start: 8 | call main 9 | push eax 10 | call exit 11 | 12 | [section .data] 13 | [global errno] 14 | errno dw 0 15 | -------------------------------------------------------------------------------- /usr/libsys/libsys.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int exit(int ret){ 5 | return _exit(ret); 6 | } 7 | -------------------------------------------------------------------------------- /usr/libsys/printf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* printf.c */ 5 | /* implement a printf() in the user mode. */ 6 | void putch(char c){ 7 | write(1, &c, 1); 8 | } 9 | 10 | void puts(char *str){ 11 | int i; 12 | for(i=0; i 2 | 3 | void* memcpy(void *dest, void *src, unsigned int count) { 4 | char *sp = (char *)src; 5 | char *dp = (char *)dest; 6 | int i; 7 | for (i=0; i 0) 57 | while (--cnt) 58 | *dst++ = '\0'; 59 | return tmp; 60 | } 61 | 62 | char *strcat(char *dst, const char *src){ 63 | char *tmp = dst; 64 | for(;*tmp; tmp++); 65 | while (*tmp++ = *src++); 66 | return dst; 67 | } 68 | 69 | char *strncat(char *dst, const char *src, unsigned int n){ 70 | char *tmp = dst; 71 | if (n==0) 72 | return dst; 73 | for(;*tmp; tmp++); 74 | while (*tmp++ = *src++) { 75 | if (--n <= 0) { 76 | *tmp = '\0'; 77 | break; 78 | } 79 | } 80 | return dst; 81 | } 82 | 83 | /* 84 | * note that '\0' is considered to be part of the string. 85 | * returns not a number but a pointer. 86 | * */ 87 | char* strchr(const char *str, int c){ 88 | for(; *str!='\0'; str++) { 89 | if (*str == (char)c) { 90 | return str; 91 | } 92 | } 93 | if (*str == (char)c) 94 | return str; 95 | return NULL; 96 | } 97 | 98 | /* just like strchr, but in reverse order. */ 99 | char* strrchr(const char *str, int c){ 100 | char *ret; 101 | for(; *str!='\0'; str++){ 102 | if (*str == (char)c) { 103 | ret = str; 104 | } 105 | } 106 | if (*ret == (char)c) 107 | return ret; 108 | return NULL; 109 | } 110 | 111 | /* 112 | * TODO: debug all these. 113 | * */ 114 | int strcmp(char *s1, char *s2){ 115 | while (*s1 == *s2++) 116 | if (*s1++ == 0) 117 | return (0); 118 | return (*(unsigned char*)s1 - *(unsigned char*)(s2-1)); 119 | } 120 | 121 | int strncmp(char *s1, char* s2, unsigned int n) { 122 | if (n == 0) 123 | return 0; 124 | while(n-- != 0) { 125 | if (*s1 != *s2++) 126 | return (*(unsigned char*)s1 - *(unsigned char*)(s2-1)); 127 | if (*s1++ == 0) 128 | break; 129 | } 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /usr/ls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int ls(char *pathp){ 8 | struct stat sbuf; 9 | struct dirent dbuf; 10 | char pathbuf[1024]; 11 | int fd, r; 12 | 13 | if (pathp==NULL) 14 | strcpy(pathbuf, "."); 15 | else 16 | strncpy(pathbuf, pathp, 1024); 17 | // 18 | fd = open(pathbuf, O_RDONLY, 0); 19 | if (fd<0) { 20 | return -1; 21 | } 22 | fstat(fd, &sbuf); 23 | if (!S_ISDIR(sbuf.st_mode)){ 24 | return -1; 25 | } 26 | 27 | while((r=read(fd, &dbuf, sizeof(struct dirent)))>0) 28 | printf("%s\t", dbuf.d_name); 29 | } 30 | 31 | int main(int argc, char **argv){ 32 | int i = 0; 33 | 34 | if (argc==1) 35 | ls(NULL); 36 | else{ 37 | for(i=1; i 2 | #include 3 | #include 4 | 5 | #define LINEBUFSIZ 1024 6 | #define ARGVBUFSIZ 1024 7 | #define PATHBUFSIZ 1024 8 | 9 | char linebuf[LINEBUFSIZ]; 10 | char* argvbuf[ARGVBUFSIZ]; 11 | char pathbuf[PATHBUFSIZ]; 12 | 13 | int hwsig(int sign){ 14 | printf("^C\n"); 15 | } 16 | 17 | int lparse(char *lbuf) { 18 | char *lp, c; 19 | int argc, i; 20 | 21 | argc = 0; 22 | lp = lbuf; 23 | while((c=*lp++) && lp<&linebuf[LINEBUFSIZ]) { 24 | if (c == ' ') 25 | continue; 26 | argvbuf[argc] = lp-1; 27 | argc++; 28 | while(*lp++ != ' '); 29 | } 30 | for(i=0; i 0) { 66 | if (strncmp(argvbuf[0], "cd", 2)==0) { 67 | chdir(argvbuf[1]); 68 | } 69 | else { 70 | if (fork()==0) { 71 | exec(argvbuf[0], &argvbuf[1]); 72 | strcpy(pathbuf, "/bin/"); 73 | strncat(pathbuf, argvbuf[0], PATHBUFSIZ); 74 | exec(pathbuf, &argvbuf[1]); 75 | exit(1); 76 | } 77 | wait(&ret); 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /usr/test/test_chdir.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int a=3; 6 | 7 | int main(int argc, char **argv) { 8 | int fd; 9 | 10 | printf("open about.txt: %d\n", open("about.txt", O_RDWR, 0)); 11 | chdir("home"); 12 | printf("cd home\n"); 13 | printf("open about.txt: %d\n", open("about.txt", O_RDWR, 0)); 14 | chdir("."); 15 | printf(".\n"); 16 | printf("open about.txt: %d\n", open("about.txt", O_RDWR, 0)); 17 | return 0; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /usr/test/test_exec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int a=3; 6 | 7 | int main(int argc, char **argv) { 8 | int fd; 9 | char str[] = "hello, world\n"; 10 | 11 | if (fork()==0) { 12 | write(1, "children\n", 10); 13 | exec("/bin/hello", NULL); 14 | } 15 | write(1, "parent proc\n", 13); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /usr/test/test_exit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int a=3; 6 | 7 | int main(int argc, char **argv) { 8 | int fd; 9 | int ret; 10 | char str[] = "proc1\n"; 11 | char str2[] = "proc2\n"; 12 | uint pid; 13 | 14 | fd = open("/dev/tty0", O_RDONLY, 0); 15 | if (fork()==0) { 16 | printf("child1\n"); 17 | exec("/bin/hello", NULL); 18 | } 19 | if (fork()==0) { 20 | printf("child2\n"); 21 | _exit(0); 22 | } 23 | if (fork()==0){ 24 | int *badmem = (int *)0; 25 | *badmem = 1; 26 | printf("so bad~~~\n"); 27 | } 28 | if (fork()==0) { 29 | } 30 | return 1; 31 | } 32 | -------------------------------------------------------------------------------- /usr/test/test_fork.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int a=3; 6 | 7 | int main(int argc, char **argv) { 8 | int fd; 9 | char str[] = "hello, world\n"; 10 | 11 | if (fork()==0){ 12 | while(1) printf("2"); 13 | } 14 | else if(fork()){ 15 | while(1) printf("1");; 16 | } 17 | else { 18 | while(1) printf("3");; 19 | } 20 | while(1); 21 | return 0; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /usr/test/test_pause.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int a=3; 7 | 8 | int main(int argc, char **argv) { 9 | int fd; 10 | int ret; 11 | uint pid; 12 | 13 | if ((pid=fork())==0) { 14 | pause(); 15 | printf("pause interrupted\n"); 16 | return 0; 17 | } 18 | kill(pid, SIGCONT); 19 | printf("SIGINT has been sent\n"); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /usr/test/test_signal.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int a=3; 7 | 8 | int hwsig(int n){ 9 | int i; 10 | char str[] = "sig handled\n"; 11 | 12 | printf("sig handled: %x\n", n); 13 | return 0; 14 | } 15 | 16 | int main(int argc, char **argv) { 17 | int fd, i, pid; 18 | char str[] = "hello, world\n"; 19 | struct sigaction sa; 20 | 21 | sa.sa_handler = hwsig; 22 | if ((pid=fork())==0) { 23 | signal(SIGINT, hwsig); 24 | write(1, str, sizeof(str)); 25 | for(;;); 26 | } 27 | kill(pid, SIGINT); 28 | for(i=0;i<10000;i++); 29 | kill(pid, SIGINT); 30 | return 0; 31 | } 32 | --------------------------------------------------------------------------------