├── Makefile ├── README.md ├── boot ├── Makefile └── start.S ├── drivers ├── Makefile └── gxconsole │ ├── Makefile │ ├── console.c │ └── dev_cons.h ├── fs ├── Makefile ├── bintoc ├── fs.c ├── fs.h ├── fsformat ├── fsformat.c ├── ide.c ├── ide_asm.S ├── motd ├── newmotd ├── serv.c ├── test.c ├── test │ ├── QAQ │ │ └── gccccc.c │ ├── hello.txt │ ├── tree_test │ │ └── ll │ └── try └── view ├── gxemul ├── .DS_Store ├── elfinfo ├── fsformat ├── r3000 ├── r3000_test ├── test └── view ├── include.mk ├── include ├── args.h ├── asm-mips3k │ ├── asm.h │ ├── asm.h~ │ ├── cp0regdef.h │ └── regdef.h ├── asm │ ├── asm.h │ ├── asm.h~ │ ├── cp0regdef.h │ └── regdef.h ├── env.h ├── error.h ├── fs.h ├── kclock.h ├── kerelf.h ├── mmu.h ├── pmap.h ├── print.h ├── printf.h ├── queue.h ├── sched.h ├── stackframe.h ├── trap.h ├── types.h └── unistd.h ├── init ├── Makefile ├── code.c ├── code_a.c ├── code_b.c ├── init.c └── main.c ├── lib ├── Makefile ├── env.c ├── env_asm.S ├── genex.S ├── getc.S ├── kclock.c ├── kclock_asm.S ├── kernel_elfloader.c ├── print.c ├── printf.c ├── sched.c ├── syscall.S ├── syscall_all.c └── traps.c ├── mm ├── Makefile ├── pmap.all ├── pmap.c └── tlb_asm.S ├── tools ├── fsformat ├── scse0_3.lds └── scse0_3.lds~ └── user ├── Makefile ├── bintoc ├── cat.c ├── clear.c ├── console.c ├── counter.c ├── echo.c ├── entry.S ├── fd.c ├── fd.h ├── file.c ├── fktest.c ├── fork.c ├── fprintf.c ├── fsipc.c ├── fstest.c ├── history.c ├── icode.c ├── idle.c ├── init.c ├── ipc.c ├── lib.h ├── libos.c ├── ls.c ├── mkdir.c ├── num.c ├── pageref.c ├── pgfault.c ├── pingpong.c ├── pipe.c ├── print.c ├── printf.c ├── rm.c ├── sh.c ├── spawn.c ├── string.c ├── sum.c ├── syscall_lib.c ├── syscall_wrap.S ├── testarg.c ├── testfdsharing.c ├── testpipe.c ├── testpiperace.c ├── testptelibrary.c ├── touch.c ├── tree.c ├── user.lds └── wait.c /Makefile: -------------------------------------------------------------------------------- 1 | # Main makefile 2 | # 3 | # Copyright (C) 2007 Beihang University 4 | # Written by Zhu Like ( zlike@cse.buaa.edu.cn ) 5 | # 6 | 7 | drivers_dir := drivers 8 | boot_dir := boot 9 | user_dir := user 10 | init_dir := init 11 | lib_dir := lib 12 | fs_dir := fs 13 | mm_dir := mm 14 | tools_dir := tools 15 | vmlinux_elf := gxemul/vmlinux 16 | user_disk := gxemul/fs.img 17 | 18 | link_script := $(tools_dir)/scse0_3.lds 19 | 20 | modules := boot drivers init lib mm user fs 21 | objects := $(boot_dir)/start.o \ 22 | $(init_dir)/main.o \ 23 | $(init_dir)/init.o \ 24 | $(init_dir)/code.o \ 25 | $(drivers_dir)/gxconsole/console.o \ 26 | $(lib_dir)/*.o \ 27 | $(user_dir)/*.x \ 28 | $(fs_dir)/*.x \ 29 | $(mm_dir)/*.o 30 | 31 | .PHONY: all $(modules) clean 32 | 33 | all: $(modules) vmlinux 34 | 35 | vmlinux: $(modules) 36 | $(LD) -o $(vmlinux_elf) -N -T $(link_script) $(objects) 37 | 38 | $(modules): 39 | $(MAKE) --directory=$@ 40 | 41 | clean: 42 | for d in $(modules); \ 43 | do \ 44 | $(MAKE) --directory=$$d clean; \ 45 | done; \ 46 | rm -rf *.o *~ $(vmlinux_elf) $(user_disk) 47 | 48 | run: 49 | /OSLAB/gxemul -E testmips -C R3000 -M 64 -d gxemul/fs.img $(vmlinux_elf) 50 | 51 | dbg: 52 | /OSLAB/gxemul -E testmips -C R3000 -M 64 -d gxemul/fs.img $(vmlinux_elf) -V 53 | 54 | include include.mk 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SOMOS 2 | === 3 | 4 | > Shell On MIPS(R3000) Operating System 5 | 6 | **SOMOS** is based on **BUAA-MOS**. 7 | 8 | --- 9 | 10 | ## Acknowledgement 11 | 12 | The code refers to the following repositories: 13 | * **Login256**: [BUAA-OS-2019](https://github.com/login256/BUAA-OS-2019) 14 | * **refkxh**: [BUAA_OS_2020Spring](https://github.com/refkxh/BUAA_OS_2020Spring) 15 | 16 | Without their help, @Coekjan could hardly have completed the entire MOS-Lab. 17 | 18 | ## Focus 19 | 20 | Support [Local Development](https://coekjan.github.io/2022/03/05/Local-Development/). 21 | 22 | Post some **Key Content Analysis** on [my blog](https://coekjan.github.io/)... 23 | 1. [Introduction](https://coekjan.github.io/2021/07/15/Introduction/) 24 | * CP0, TLB, Interrupt & Exception 25 | 2. [Boot And Memory Management](https://coekjan.github.io/2021/07/23/Boot-And-Memory-Management/) 26 | * Boot & Initialization, Physical Memory Management, Virtual Memory Management 27 | 3. [Process](https://coekjan.github.io/2021/08/15/Process/) 28 | * Process, Schedule, Switch Address Space 29 | 4. [Interrupt And Exception](https://coekjan.github.io/2021/08/26/Interrupt-And-Exception/) 30 | * Details of interrupt & exception 31 | 32 | --- 33 | 34 | If you have **any questions** about the code, please contact me and I will be very happy to discuss them with you. 35 | -------------------------------------------------------------------------------- /boot/Makefile: -------------------------------------------------------------------------------- 1 | # Main makefile 2 | # 3 | # Copyright (C) 2007 Beihang University 4 | # Written by Zhu Like ( zlike@cse.buaa.edu.cn ) 5 | # 6 | 7 | # ========= Configuration ========= 8 | 9 | INCLUDES := -I../include/ 10 | 11 | # ======== End of configuration === 12 | 13 | %.o: %.S 14 | $(CC) $(CFLAGS) $(INCLUDES) -c $< 15 | 16 | .PHONY: clean 17 | 18 | all: start.o 19 | 20 | clean: 21 | rm -rf *~ *.o 22 | 23 | include ../include.mk 24 | -------------------------------------------------------------------------------- /boot/start.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2001 MontaVista Software Inc. 3 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License as published by the 7 | * Free Software Foundation; either version 2 of the License, or (at your 8 | * option) any later version. 9 | * 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | .section .text.exc_vec3 16 | /*** exercise 3.11 ***/ 17 | NESTED(except_vec3, 0, sp) 18 | .set noat 19 | .set noreorder 20 | 1: 21 | mfc0 k1, CP0_CAUSE 22 | la k0, exception_handlers 23 | andi k1, 0x7c 24 | addu k0, k1 25 | lw k0, (k0) 26 | nop 27 | jr k0 28 | nop 29 | END(except_vec3) 30 | .set at 31 | 32 | .data 33 | .globl mCONTEXT 34 | mCONTEXT: 35 | .word 0 36 | 37 | .globl delay 38 | delay: 39 | .word 0 40 | 41 | .globl tlbra 42 | tlbra: 43 | .word 0 44 | 45 | .section .data.stk 46 | KERNEL_STACK: 47 | .space 0x8000 48 | 49 | 50 | .text 51 | LEAF(_start) 52 | 53 | .set mips2 54 | .set reorder 55 | 56 | /* Disable interrupts */ 57 | mtc0 zero, CP0_STATUS 58 | 59 | /* Disable watch exception. */ 60 | mtc0 zero, CP0_WATCHLO 61 | mtc0 zero, CP0_WATCHHI 62 | 63 | /* disable kernel mode cache */ 64 | mfc0 t0, CP0_CONFIG 65 | and t0, ~0x7 66 | ori t0, 0x2 67 | mtc0 t0, CP0_CONFIG 68 | 69 | /* set up stack */ 70 | li sp, 0x80400000 71 | 72 | li t0,0x80400000 73 | sw t0,mCONTEXT 74 | 75 | /* jump to main */ 76 | jal main 77 | 78 | loop: 79 | j loop 80 | nop 81 | END(_start) 82 | 83 | -------------------------------------------------------------------------------- /drivers/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for gxconsole module 2 | # 3 | # Copyright (C) 2007 Beihang Unversity. 4 | # Written by Zhu Like, zlike@cse.buaa.edu.cn 5 | 6 | # ========== Configuration ============= 7 | 8 | CROSS_COMPILE := /opt/eldk/usr/bin/mips_4KC- 9 | CC := $(CROSS_COMPILE)gcc 10 | CFLAGS := -O -G 0 -mno-abicalls -fno-builtin -Wall 11 | 12 | # ========= End of configuration ======= 13 | 14 | drivers := gxconsole 15 | 16 | .PHONY: all $(drivers) 17 | 18 | all: $(drivers) 19 | 20 | $(drivers): 21 | $(MAKE) --directory=$@ 22 | 23 | clean: 24 | for d in $(drivers); \ 25 | do \ 26 | $(MAKE) --directory=$$d clean; \ 27 | done 28 | -------------------------------------------------------------------------------- /drivers/gxconsole/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for gxconsole module 2 | # 3 | # Copyright (C) 2007 Beihang Unversity. 4 | # Written by Zhu Like, zlike@cse.buaa.edu.cn 5 | 6 | %.o: %.c %.h 7 | $(CC) $(CFLAGS) -c $< -o $*.o 8 | 9 | .PHONY: clean 10 | all: console.o 11 | 12 | clean: 13 | rm -rf *.o *~ 14 | 15 | 16 | 17 | include ../../include.mk 18 | -------------------------------------------------------------------------------- /drivers/gxconsole/console.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: hello.c,v 1.3 2006/05/22 04:53:52 debug Exp $ 3 | * 4 | * GXemul demo: Hello World 5 | * 6 | * This file is in the Public Domain. 7 | */ 8 | 9 | #include "dev_cons.h" 10 | 11 | #define PHYSADDR_OFFSET ((signed int)0x80000000) 12 | 13 | #define PUTCHAR_ADDRESS (PHYSADDR_OFFSET + \ 14 | DEV_CONS_ADDRESS + DEV_CONS_PUTGETCHAR) 15 | #define HALT_ADDRESS (PHYSADDR_OFFSET + \ 16 | DEV_CONS_ADDRESS + DEV_CONS_HALT) 17 | 18 | void printcharc(char ch) 19 | { 20 | *((volatile unsigned char *)PUTCHAR_ADDRESS) = ch; 21 | } 22 | 23 | void halt(void) 24 | { 25 | *((volatile unsigned char *)HALT_ADDRESS) = 0; 26 | } 27 | 28 | void printstr(char *s) 29 | { 30 | while (*s) 31 | printcharc(*s++); 32 | } 33 | -------------------------------------------------------------------------------- /drivers/gxconsole/dev_cons.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTMACHINE_CONS_H 2 | #define TESTMACHINE_CONS_H 3 | 4 | /* 5 | * Definitions used by the "cons" device in GXemul. 6 | * 7 | * $Id: dev_cons.h,v 1.2 2006/07/05 05:38:36 debug Exp $ 8 | * This file is in the public domain. 9 | */ 10 | 11 | //#define DEV_CONS_ADDRESS 0x180003f8 12 | #define DEV_CONS_ADDRESS 0x10000000 13 | #define DEV_CONS_LENGTH 0x0000000000000020 14 | #define DEV_CONS_PUTGETCHAR 0x0000 15 | #define DEV_CONS_HALT 0x0010 16 | 17 | #endif /* TESTMACHINE_CONS_H */ 18 | -------------------------------------------------------------------------------- /fs/Makefile: -------------------------------------------------------------------------------- 1 | INCLUDES = -I../include/ -I../user/ 2 | 3 | user_dir := ../user 4 | tools_dir := . 5 | USERLIB := $(user_dir)/printf.o \ 6 | $(user_dir)/print.o \ 7 | $(user_dir)/libos.o \ 8 | $(user_dir)/fork.o \ 9 | $(user_dir)/pgfault.o \ 10 | $(user_dir)/syscall_lib.o \ 11 | $(user_dir)/ipc.o \ 12 | $(user_dir)/string.o \ 13 | $(user_dir)/fd.o \ 14 | $(user_dir)/pageref.o \ 15 | $(user_dir)/file.o \ 16 | $(user_dir)/fsipc.o \ 17 | $(user_dir)/wait.o \ 18 | $(user_dir)/spawn.o \ 19 | $(user_dir)/pipe.o \ 20 | $(user_dir)/console.o \ 21 | $(user_dir)/fprintf.o 22 | 23 | FSLIB := fs.o \ 24 | ide.o \ 25 | test.o 26 | 27 | USERAPPS := $(user_dir)/num.b \ 28 | $(user_dir)/echo.b \ 29 | $(user_dir)/ls.b \ 30 | $(user_dir)/cat.b \ 31 | $(user_dir)/tree.b \ 32 | $(user_dir)/mkdir.b \ 33 | $(user_dir)/touch.b \ 34 | $(user_dir)/rm.b \ 35 | $(user_dir)/sh.b \ 36 | $(user_dir)/counter.b \ 37 | $(user_dir)/history.b \ 38 | $(user_dir)/sum.b 39 | 40 | 41 | FSIMGFILES := test/ motd newmotd $(user_dir)/init.b $(USERAPPS) 42 | 43 | CFLAGS += -nostdlib -static 44 | 45 | all: serv.x fs.img serv.b 46 | 47 | %.x: %.b.c 48 | echo cc1 $< 49 | $(CC) $(INCLUDES) $(CFLAGS) -c -o $@ $< 50 | 51 | %.b.c: %.b 52 | echo create $@ 53 | echo bintoc $* $< > $@~ 54 | chmod +x $(tools_dir)/bintoc 55 | $(tools_dir)/bintoc $* $< > $@~ && mv -f $@~ $@ 56 | # grep \. $@ 57 | 58 | %.b: ../user/entry.o ../user/syscall_wrap.o %.o $(USERLIB) $(FSLIB) 59 | echo ld $@ 60 | $(LD) -o $@ $(LDFLAGS) -G 0 -static -n -nostdlib -T $(user_dir)/user.lds $^ 61 | 62 | %.o: %.c 63 | echo user1 cc $< 64 | $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< 65 | 66 | %.o: %.S 67 | echo as $< 68 | $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< 69 | 70 | %.o: $(user_dir)/lib.h 71 | 72 | fs.img: $(FSIMGFILES) 73 | dd if=/dev/zero of=../gxemul/fs.img bs=4096 count=1024 2>/dev/null 74 | gcc $(INCLUDES) -g fsformat.c -o $(tools_dir)/fsformat -m32 75 | chmod +x $(tools_dir)/fsformat 76 | $(tools_dir)/fsformat ../gxemul/fs.img -r $(FSIMGFILES) 77 | 78 | .PHONY: clean 79 | 80 | clean: 81 | rm -rf *~ *.o *.b.c *.b *.x 82 | 83 | include ../include.mk 84 | -------------------------------------------------------------------------------- /fs/bintoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coekjan/SOMOS/284bd72bfd7712697798a76eb30bda63c087eaab/fs/bintoc -------------------------------------------------------------------------------- /fs/fs.h: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #include 3 | #include 4 | 5 | /* IDE disk number to look on for our file system */ 6 | #define DISKNO 1 7 | 8 | #define BY2SECT 512 /* Bytes per disk sector */ 9 | #define SECT2BLK (BY2BLK / BY2SECT) /* sectors to a block */ 10 | 11 | /* Disk block n, when in memory, is mapped into the file system 12 | * server's address space at DISKMAP+(n*BY2BLK). */ 13 | #define DISKMAP 0x10000000 14 | 15 | /* Maximum disk size we can handle (1GB) */ 16 | #define DISKMAX 0x40000000 17 | 18 | /* ide.c */ 19 | void ide_read(u_int diskno, u_int secno, void *dst, u_int nsecs); 20 | void ide_write(u_int diskno, u_int secno, void *src, u_int nsecs); 21 | 22 | /* fs.c */ 23 | int file_open(char *path, struct File **pfile); 24 | int file_get_block(struct File *f, u_int blockno, void **pblk); 25 | int file_set_size(struct File *f, u_int newsize); 26 | void file_close(struct File *f); 27 | int file_remove(char *path); 28 | void fs_init(void); 29 | int file_dirty(struct File *f, u_int offset); 30 | void fs_sync(void); 31 | void file_flush(struct File *); 32 | extern u_int *bitmap; 33 | int map_block(u_int); 34 | int alloc_block(void); 35 | 36 | /* test.c */ 37 | void fs_test(void); 38 | -------------------------------------------------------------------------------- /fs/fsformat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coekjan/SOMOS/284bd72bfd7712697798a76eb30bda63c087eaab/fs/fsformat -------------------------------------------------------------------------------- /fs/ide.c: -------------------------------------------------------------------------------- 1 | /* 2 | * operations on IDE disk. 3 | */ 4 | 5 | #include "fs.h" 6 | #include "lib.h" 7 | #include 8 | 9 | // Overview: 10 | // read data from IDE disk. First issue a read request through 11 | // disk register and then copy data from disk buffer 12 | // (512 bytes, a sector) to destination array. 13 | // 14 | // Parameters: 15 | // diskno: disk number. 16 | // secno: start sector number. 17 | // dst: destination for data read from IDE disk. 18 | // nsecs: the number of sectors to read. 19 | // 20 | // Post-Condition: 21 | // If error occurred during read the IDE disk, panic. 22 | // 23 | // Hint: use syscalls to access device registers and buffers 24 | void ide_read(u_int diskno, u_int secno, void *dst, u_int nsecs) 25 | { 26 | // 0x200: the size of a sector: 512 bytes. 27 | int offset_begin = secno * 0x200; 28 | int offset_end = offset_begin + nsecs * 0x200; 29 | int offset = 0; 30 | 31 | u_int zero = 0; 32 | u_int cur_offset = 0; 33 | 34 | while (offset_begin + offset < offset_end) 35 | { 36 | // Your code here 37 | // error occurred, then panic. 38 | cur_offset = offset_begin + offset; 39 | if (syscall_write_dev((u_int)&diskno, 0x13000010, 4) < 0) 40 | user_panic("ide_read panic"); 41 | if (syscall_write_dev((u_int)&cur_offset, 0x13000000, 4) < 0) 42 | user_panic("ide_read panic"); 43 | if (syscall_write_dev((u_int)&zero, 0x13000020, 4) < 0) 44 | user_panic("ide_read panic"); 45 | u_int succ; 46 | if (syscall_read_dev((u_int)&succ, 0x13000030, 4) < 0) 47 | user_panic("ide_read panic"); 48 | if (!succ) 49 | user_panic("ide_read panic"); 50 | if (syscall_read_dev((u_int)(dst + offset), 0x13004000, 0x200) < 0) 51 | user_panic("ide_read panic"); 52 | offset += 0x200; 53 | } 54 | } 55 | 56 | // Overview: 57 | // write data to IDE disk. 58 | // 59 | // Parameters: 60 | // diskno: disk number. 61 | // secno: start sector number. 62 | // src: the source data to write into IDE disk. 63 | // nsecs: the number of sectors to write. 64 | // 65 | // Post-Condition: 66 | // If error occurred during read the IDE disk, panic. 67 | // 68 | // Hint: use syscalls to access device registers and buffers 69 | void ide_write(u_int diskno, u_int secno, void *src, u_int nsecs) 70 | { 71 | // Your code here 72 | int offset_begin = secno * 0x200; 73 | int offset_end = offset_begin + nsecs * 0x200; 74 | int offset = 0; 75 | 76 | u_int one = 1; 77 | u_int cur_offset = 0; 78 | 79 | // DO NOT DELETE WRITEF !!! 80 | // writef("diskno: %d\n", diskno); 81 | 82 | while (offset_begin + offset < offset_end) 83 | { 84 | // copy data from source array to disk buffer. 85 | // if error occur, then panic. 86 | cur_offset = offset_begin + offset; 87 | if (syscall_write_dev((u_int)(src + offset), 0x13004000, 0x200) < 0) 88 | user_panic("ide_write panic"); 89 | if (syscall_write_dev((u_int)&diskno, 0x13000010, 4) < 0) 90 | user_panic("ide_write panic"); 91 | if (syscall_write_dev((u_int)&cur_offset, 0x13000000, 4) < 0) 92 | user_panic("ide_write panic"); 93 | if (syscall_write_dev((u_int)&one, 0x13000020, 4) < 0) 94 | user_panic("ide_write panic"); 95 | u_int succ; 96 | if (syscall_read_dev((u_int)&succ, 0x13000030, 4) < 0) 97 | user_panic("ide_write panic"); 98 | offset += 0x200; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /fs/ide_asm.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | LEAF(read_sector) 6 | 7 | 8 | sw a0, 0x93000000 9 | li t0, 0 10 | sw t0 , 0x93000010 11 | li t0, 0 12 | sb t0 , 0x93000020 13 | lw v0, 0x93000030 14 | //1: j 1b 15 | nop 16 | jr ra 17 | nop 18 | END(read_sector) 19 | 20 | LEAF(write_sector) 21 | sw a0, 0x93000000 22 | li t0, 0 23 | sw t0 , 0x93000010 24 | li t0, 1 25 | sb t0 , 0x93000020 26 | lw v0, 0x93000030 27 | jr ra 28 | nop 29 | END(write_sector) 30 | -------------------------------------------------------------------------------- /fs/motd: -------------------------------------------------------------------------------- 1 | This is /motd, the message of the day. 2 | 3 | Welcome to the 6.828 kernel, now with a file system! 4 | 5 | -------------------------------------------------------------------------------- /fs/newmotd: -------------------------------------------------------------------------------- 1 | This is the NEW message of the day! 2 | 3 | -------------------------------------------------------------------------------- /fs/serv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File system server main loop - 3 | * serves IPC requests from other environments. 4 | */ 5 | 6 | #include "fs.h" 7 | #include "fd.h" 8 | #include "lib.h" 9 | #include 10 | 11 | struct Open 12 | { 13 | struct File *o_file; // mapped descriptor for open file 14 | u_int o_fileid; // file id 15 | int o_mode; // open mode 16 | struct Filefd *o_ff; // va of filefd page 17 | }; 18 | 19 | // Max number of open files in the file system at once 20 | #define MAXOPEN 1024 21 | #define FILEVA 0x60000000 22 | 23 | // initialize to force into data section 24 | struct Open opentab[MAXOPEN] = {{0, 0, 1}}; 25 | 26 | // Virtual address at which to receive page mappings containing client requests. 27 | #define REQVA 0x0ffff000 28 | 29 | // Overview: 30 | // Initialize file system server process. 31 | void serve_init(void) 32 | { 33 | int i; 34 | u_int va; 35 | 36 | // Set virtual address to map. 37 | va = FILEVA; 38 | 39 | // Initial array opentab. 40 | for (i = 0; i < MAXOPEN; i++) 41 | { 42 | opentab[i].o_fileid = i; 43 | opentab[i].o_ff = (struct Filefd *)va; 44 | va += BY2PG; 45 | } 46 | } 47 | 48 | // Overview: 49 | // Allocate an open file. 50 | int open_alloc(struct Open **o) 51 | { 52 | int i, r; 53 | 54 | // Find an available open-file table entry 55 | for (i = 0; i < MAXOPEN; i++) 56 | { 57 | switch (pageref(opentab[i].o_ff)) 58 | { 59 | case 0: 60 | if ((r = syscall_mem_alloc(0, (u_int)opentab[i].o_ff, 61 | PTE_V | PTE_R | PTE_LIBRARY)) < 0) 62 | { 63 | return r; 64 | } 65 | case 1: 66 | opentab[i].o_fileid += MAXOPEN; 67 | *o = &opentab[i]; 68 | user_bzero((void *)opentab[i].o_ff, BY2PG); 69 | return (*o)->o_fileid; 70 | } 71 | } 72 | 73 | return -E_MAX_OPEN; 74 | } 75 | 76 | // Overview: 77 | // Look up an open file for envid. 78 | int open_lookup(u_int envid, u_int fileid, struct Open **po) 79 | { 80 | struct Open *o; 81 | 82 | o = &opentab[fileid % MAXOPEN]; 83 | 84 | if (pageref(o->o_ff) == 1 || o->o_fileid != fileid) 85 | { 86 | return -E_INVAL; 87 | } 88 | 89 | *po = o; 90 | return 0; 91 | } 92 | 93 | // Serve requests, sending responses back to envid. 94 | // To send a result back, ipc_send(envid, r, 0, 0). 95 | // To include a page, ipc_send(envid, r, srcva, perm). 96 | 97 | void serve_open(u_int envid, struct Fsreq_open *rq) 98 | { 99 | // writef("serve_open %08x %x 0x%x\n", envid, (int)rq->req_path, rq->req_omode); 100 | 101 | u_char path[MAXPATHLEN]; 102 | struct File *f; 103 | struct Filefd *ff; 104 | int fileid; 105 | int r; 106 | struct Open *o; 107 | 108 | // Copy in the path, making sure it's null-terminated 109 | user_bcopy(rq->req_path, path, MAXPATHLEN); 110 | path[MAXPATHLEN - 1] = 0; 111 | 112 | // Find a file id. 113 | if ((r = open_alloc(&o)) < 0) 114 | { 115 | user_panic("open_alloc failed: %d, invalid path: %s", r, path); 116 | ipc_send(envid, r, 0, 0); 117 | } 118 | 119 | fileid = r; 120 | 121 | // Open the file. 122 | if ((r = file_open((char *)path, &f)) < 0) 123 | { 124 | // user_panic("file_open failed: %d, invalid path: %s", r, path); 125 | if (rq->req_omode & O_CREAT) 126 | { 127 | if ((r = file_create(path, &f)) < 0) 128 | { 129 | return r; 130 | } 131 | f->f_type = FTYPE_REG; 132 | } 133 | else 134 | { 135 | ipc_send(envid, r, 0, 0); 136 | return; 137 | } 138 | } 139 | 140 | // Save the file pointer. 141 | o->o_file = f; 142 | 143 | // Fill out the Filefd structure 144 | ff = (struct Filefd *)o->o_ff; 145 | ff->f_file = *f; 146 | ff->f_fileid = o->o_fileid; 147 | o->o_mode = rq->req_omode; 148 | ff->f_fd.fd_omode = o->o_mode; 149 | ff->f_fd.fd_dev_id = devfile.dev_id; 150 | 151 | ipc_send(envid, 0, (u_int)o->o_ff, PTE_V | PTE_R | PTE_LIBRARY); 152 | } 153 | 154 | void serve_map(u_int envid, struct Fsreq_map *rq) 155 | { 156 | 157 | struct Open *pOpen; 158 | 159 | u_int filebno; 160 | 161 | void *blk; 162 | 163 | int r; 164 | 165 | if ((r = open_lookup(envid, rq->req_fileid, &pOpen)) < 0) 166 | { 167 | ipc_send(envid, r, 0, 0); 168 | return; 169 | } 170 | 171 | filebno = rq->req_offset / BY2BLK; 172 | 173 | if ((r = file_get_block(pOpen->o_file, filebno, &blk)) < 0) 174 | { 175 | ipc_send(envid, r, 0, 0); 176 | return; 177 | } 178 | 179 | ipc_send(envid, 0, (u_int)blk, PTE_V | PTE_R | PTE_LIBRARY); 180 | } 181 | 182 | void serve_set_size(u_int envid, struct Fsreq_set_size *rq) 183 | { 184 | struct Open *pOpen; 185 | int r; 186 | if ((r = open_lookup(envid, rq->req_fileid, &pOpen)) < 0) 187 | { 188 | ipc_send(envid, r, 0, 0); 189 | return; 190 | } 191 | 192 | if ((r = file_set_size(pOpen->o_file, rq->req_size)) < 0) 193 | { 194 | ipc_send(envid, r, 0, 0); 195 | return; 196 | } 197 | 198 | ipc_send(envid, 0, 0, 0); 199 | } 200 | 201 | void serve_close(u_int envid, struct Fsreq_close *rq) 202 | { 203 | struct Open *pOpen; 204 | 205 | int r; 206 | 207 | if ((r = open_lookup(envid, rq->req_fileid, &pOpen)) < 0) 208 | { 209 | ipc_send(envid, r, 0, 0); 210 | return; 211 | } 212 | 213 | file_close(pOpen->o_file); 214 | ipc_send(envid, 0, 0, 0); 215 | } 216 | 217 | // Overview: 218 | // fs service used to delete a file according path in `rq`. 219 | void serve_remove(u_int envid, struct Fsreq_remove *rq) 220 | { 221 | int r; 222 | u_char path[MAXPATHLEN]; 223 | 224 | // Step 1: Copy in the path, making sure it's terminated. 225 | // Notice: add \0 to the tail of the path 226 | user_bcopy(rq->req_path, path, MAXPATHLEN); 227 | path[MAXPATHLEN - 1] = '\0'; 228 | // Step 2: Remove file from file system and response to user-level process. 229 | // Call file_remove and ipc_send an approprite value to corresponding env. 230 | r = file_remove(path); 231 | ipc_send(envid, r, 0, 0); 232 | } 233 | 234 | void serve_dirty(u_int envid, struct Fsreq_dirty *rq) 235 | { 236 | 237 | // Your code here 238 | struct Open *pOpen; 239 | int r; 240 | 241 | if ((r = open_lookup(envid, rq->req_fileid, &pOpen)) < 0) 242 | { 243 | ipc_send(envid, r, 0, 0); 244 | return; 245 | } 246 | 247 | if ((r = file_dirty(pOpen->o_file, rq->req_offset)) < 0) 248 | { 249 | ipc_send(envid, r, 0, 0); 250 | return; 251 | } 252 | 253 | ipc_send(envid, 0, 0, 0); 254 | } 255 | 256 | void serve_sync(u_int envid) 257 | { 258 | fs_sync(); 259 | ipc_send(envid, 0, 0, 0); 260 | } 261 | 262 | void serve_create(u_int envid, struct Fsreq_create *rq) 263 | { 264 | int r; 265 | char path[MAXPATHLEN]; 266 | struct File *f; 267 | user_bcopy(rq->req_path, path, MAXPATHLEN); 268 | path[MAXPATHLEN - 1] = 0; 269 | r = file_create(path, &f); 270 | if (r < 0) 271 | { 272 | ipc_send(envid, r, 0, 0); 273 | return; 274 | } 275 | f->f_type = rq->type; 276 | ipc_send(envid, 0, 0, 0); 277 | } 278 | 279 | void serve(void) 280 | { 281 | u_int req, whom, perm; 282 | 283 | for (;;) 284 | { 285 | perm = 0; 286 | req = ipc_recv(&whom, REQVA, &perm); 287 | 288 | // All requests must contain an argument page 289 | if (!(perm & PTE_V)) 290 | { 291 | writef("Invalid request from %08x: no argument page\n", whom); 292 | continue; // just leave it hanging, waiting for the next request. 293 | } 294 | 295 | switch (req) 296 | { 297 | case FSREQ_OPEN: 298 | serve_open(whom, (struct Fsreq_open *)REQVA); 299 | break; 300 | 301 | case FSREQ_MAP: 302 | serve_map(whom, (struct Fsreq_map *)REQVA); 303 | break; 304 | 305 | case FSREQ_SET_SIZE: 306 | serve_set_size(whom, (struct Fsreq_set_size *)REQVA); 307 | break; 308 | 309 | case FSREQ_CLOSE: 310 | serve_close(whom, (struct Fsreq_close *)REQVA); 311 | break; 312 | 313 | case FSREQ_DIRTY: 314 | serve_dirty(whom, (struct Fsreq_dirty *)REQVA); 315 | break; 316 | 317 | case FSREQ_REMOVE: 318 | serve_remove(whom, (struct Fsreq_remove *)REQVA); 319 | break; 320 | 321 | case FSREQ_SYNC: 322 | serve_sync(whom); 323 | break; 324 | case FSREQ_CREATE: 325 | serve_create(whom, (struct Fsreq_create *)REQVA); 326 | break; 327 | 328 | default: 329 | writef("Invalid request code %d from %08x\n", whom, req); 330 | break; 331 | } 332 | 333 | syscall_mem_unmap(0, REQVA); 334 | } 335 | } 336 | 337 | void umain(void) 338 | { 339 | user_assert(sizeof(struct File) == BY2FILE); 340 | 341 | writef("FS is running\n"); 342 | 343 | writef("FS can do I/O\n"); 344 | 345 | serve_init(); 346 | fs_init(); 347 | // fs_test(); 348 | 349 | serve(); 350 | } 351 | -------------------------------------------------------------------------------- /fs/test.c: -------------------------------------------------------------------------------- 1 | #include "fs.h" 2 | #include "lib.h" 3 | 4 | int strecmp(char *a, char *b) 5 | { 6 | while (*b) 7 | if (*a++ != *b++) 8 | return 1; 9 | return 0; 10 | } 11 | 12 | static char *msg = "This is the NEW message of the day!\r\n\r\n"; 13 | 14 | void fs_test(void) 15 | { 16 | struct File *f; 17 | int r; 18 | void *blk; 19 | u_int *bits; 20 | 21 | // back up bitmap 22 | if ((r = syscall_mem_alloc(0, BY2PG, PTE_V | PTE_R)) < 0) 23 | user_panic("syscall_mem_alloc: %e", r); 24 | bits = (u_int *)BY2PG; 25 | user_bcopy(bitmap, bits, BY2PG); 26 | // allocate block 27 | if ((r = alloc_block()) < 0) 28 | user_panic("alloc_block: %e", r); 29 | // check that block was free 30 | user_assert(bits[r / 32] & (1 << (r % 32))); 31 | // and is not free any more 32 | user_assert(!(bitmap[r / 32] & (1 << (r % 32)))); 33 | writef("alloc_block is good\n"); 34 | 35 | if ((r = file_open("/not-found", &f)) < 0 && r != -E_NOT_FOUND) 36 | user_panic("file_open /not-found: %e", r); 37 | else if (r == 0) 38 | user_panic("file_open /not-found succeeded!"); 39 | if ((r = file_open("/newmotd", &f)) < 0) 40 | user_panic("file_open /newmotd: %d", r); 41 | writef("file_open is good\n"); 42 | 43 | if ((r = file_get_block(f, 0, &blk)) < 0) 44 | user_panic("file_get_block: %e", r); 45 | if (strecmp(blk, msg) != 0) 46 | user_panic("file_get_block returned wrong data"); 47 | writef("file_get_block is good\n"); 48 | 49 | *(volatile char *)blk = *(volatile char *)blk; 50 | //^^^user_assert(((* vpt)[VPN(blk)]&PTE_D)); 51 | file_flush(f); 52 | //^^^user_assert(!((* vpt)[VPN(blk)]&PTE_D)); 53 | writef("file_flush is good\n"); 54 | 55 | if ((r = file_set_size(f, 0)) < 0) 56 | user_panic("file_set_size: %e", r); 57 | user_assert(f->f_direct[0] == 0); 58 | //^^^user_assert(!((* vpt)[VPN(f)]&PTE_D)); 59 | writef("file_truncate is good\n"); 60 | 61 | if ((r = file_set_size(f, strlen(msg))) < 0) 62 | user_panic("file_set_size 2: %e", r); 63 | //^^^user_assert(!((* vpt)[VPN(f)]&PTE_D));user_panic("##########################"); 64 | if ((r = file_get_block(f, 0, &blk)) < 0) 65 | user_panic("file_get_block 2: %e", r); 66 | strcpy((char *)blk, msg); 67 | //^^^user_assert(((* vpt)[VPN(blk)]&PTE_D)); 68 | file_flush(f); 69 | //^^^user_assert(!((* vpt)[VPN(blk)]&PTE_D)); 70 | file_close(f); 71 | //^^^user_assert(!((* vpt)[VPN(f)]&PTE_D)); 72 | writef("file rewrite is good\n"); 73 | } 74 | -------------------------------------------------------------------------------- /fs/test/QAQ/gccccc.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | printf("Hello World!\n"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /fs/test/hello.txt: -------------------------------------------------------------------------------- 1 | 123123 2 | 3 | 4 | QAQ Hello! 5 | -------------------------------------------------------------------------------- /fs/test/tree_test/ll: -------------------------------------------------------------------------------- 1 | U can really dance!? 2 | 3 | What a coincidance! 4 | -------------------------------------------------------------------------------- /fs/test/try: -------------------------------------------------------------------------------- 1 | hello! 2 | 3 | this is a file in the directory! 4 | 5 | can you see me? QAQ 6 | -------------------------------------------------------------------------------- /fs/view: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coekjan/SOMOS/284bd72bfd7712697798a76eb30bda63c087eaab/fs/view -------------------------------------------------------------------------------- /gxemul/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coekjan/SOMOS/284bd72bfd7712697798a76eb30bda63c087eaab/gxemul/.DS_Store -------------------------------------------------------------------------------- /gxemul/elfinfo: -------------------------------------------------------------------------------- 1 | ELF Header: 2 | Magic: 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00 3 | Class: ELF32 4 | Data: 2's complement, big endian 5 | Version: 1 (current) 6 | OS/ABI: UNIX - System V 7 | ABI Version: 0 8 | Type: EXEC (Executable file) 9 | Machine: MIPS R3000 10 | Version: 0x1 11 | Entry point address: 0x82000000 12 | Start of program headers: 52 (bytes into file) 13 | Start of section headers: 37164 (bytes into file) 14 | Flags: 0x50001001, noreorder, o32, mips32 15 | Size of this header: 52 (bytes) 16 | Size of program headers: 32 (bytes) 17 | Number of program headers: 3 18 | Size of section headers: 40 (bytes) 19 | Number of section headers: 14 20 | Section header string table index: 11 21 | 22 | Section Headers: 23 | [Nr] Name Type Addr Off Size ES Flg Lk Inf Al 24 | [ 0] NULL 00000000 000000 000000 00 0 0 0 25 | [ 1] .text PROGBITS 82000000 0000a0 000ae0 00 WAX 0 0 16 26 | [ 2] .reginfo MIPS_REGINFO 82000ae0 000b80 000018 18 A 0 0 4 27 | [ 3] .rodata.str1.4 PROGBITS 82000af8 000b98 0000a2 01 AMS 0 0 4 28 | [ 4] .rodata PROGBITS 82000ba0 000c40 000210 00 A 0 0 16 29 | [ 5] .data PROGBITS 82000db0 000e50 000000 00 WA 0 0 16 30 | [ 6] .data.stk PROGBITS 82000db0 000e50 008000 00 WA 0 0 1 31 | [ 7] .bss NOBITS 80500000 000094 000000 00 WA 0 0 16 32 | [ 8] .pdr PROGBITS 00000000 008e50 0001a0 00 0 0 4 33 | [ 9] .mdebug.abi32 PROGBITS 00000000 008ff0 000000 00 0 0 1 34 | [10] .comment PROGBITS 00000000 008ff0 0000c8 00 0 0 1 35 | [11] .shstrtab STRTAB 00000000 0090b8 000072 00 0 0 1 36 | [12] .symtab SYMTAB 00000000 00935c 000240 10 13 24 4 37 | [13] .strtab STRTAB 00000000 00959c 0000be 00 0 0 1 38 | Key to Flags: 39 | W (write), A (alloc), X (execute), M (merge), S (strings) 40 | I (info), L (link order), G (group), x (unknown) 41 | O (extra OS processing required) o (OS specific), p (processor specific) 42 | 43 | There are no section groups in this file. 44 | 45 | Program Headers: 46 | Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align 47 | REGINFO 0x000b80 0x82000ae0 0x82000ae0 0x00018 0x00018 R 0x4 48 | LOAD 0x000090 0x80500000 0x80500000 0x00000 0x00000 RW 0x10 49 | LOAD 0x0000a0 0x82000000 0x82000000 0x08db0 0x08db0 RWE 0x10 50 | 51 | Section to Segment mapping: 52 | Segment Sections... 53 | 00 .reginfo 54 | 01 55 | 02 .text .reginfo .rodata.str1.4 .rodata .data.stk 56 | 57 | There is no dynamic section in this file. 58 | 59 | There are no relocations in this file. 60 | 61 | There are no unwind sections in this file. 62 | 63 | Symbol table '.symtab' contains 36 entries: 64 | Num: Value Size Type Bind Vis Ndx Name 65 | 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 66 | 1: 82000000 0 SECTION LOCAL DEFAULT 1 67 | 2: 82000ae0 0 SECTION LOCAL DEFAULT 2 68 | 3: 82000af8 0 SECTION LOCAL DEFAULT 3 69 | 4: 82000ba0 0 SECTION LOCAL DEFAULT 4 70 | 5: 82000db0 0 SECTION LOCAL DEFAULT 5 71 | 6: 82000db0 0 SECTION LOCAL DEFAULT 6 72 | 7: 80500000 0 SECTION LOCAL DEFAULT 7 73 | 8: 00000000 0 SECTION LOCAL DEFAULT 8 74 | 9: 00000000 0 SECTION LOCAL DEFAULT 9 75 | 10: 00000000 0 SECTION LOCAL DEFAULT 10 76 | 11: 00000000 0 SECTION LOCAL DEFAULT 11 77 | 12: 00000000 0 SECTION LOCAL DEFAULT 12 78 | 13: 00000000 0 SECTION LOCAL DEFAULT 13 79 | 14: 00000000 0 FILE LOCAL DEFAULT ABS start.S 80 | 15: 82000db0 0 NOTYPE LOCAL DEFAULT 6 KERNEL_STACK 81 | 16: 82000034 0 NOTYPE LOCAL DEFAULT 1 loop 82 | 17: 00000000 0 FILE LOCAL DEFAULT ABS main.c 83 | 18: 00000000 0 FILE LOCAL DEFAULT ABS init.c 84 | 19: 00000000 0 FILE LOCAL DEFAULT ABS console.c 85 | 20: 00000000 0 FILE LOCAL DEFAULT ABS print.c 86 | 21: 82000ba0 25 OBJECT LOCAL DEFAULT 4 theFatalMsg 87 | 22: 00000000 0 FILE LOCAL DEFAULT ABS printf.c 88 | 23: 820009a0 148 FUNC LOCAL DEFAULT 1 myoutput 89 | 24: 82000120 1388 FUNC GLOBAL DEFAULT 1 lp_Print 90 | 25: 82000a70 100 FUNC GLOBAL DEFAULT 1 _panic 91 | 26: 820000d8 60 FUNC GLOBAL DEFAULT 1 printstr 92 | 27: 82000a34 60 FUNC GLOBAL DEFAULT 1 printf 93 | 28: 82000814 384 FUNC GLOBAL DEFAULT 1 PrintNum 94 | 29: 820000b0 20 FUNC GLOBAL DEFAULT 1 printcharc 95 | 30: 82000000 64 FUNC GLOBAL DEFAULT 1 _start 96 | 31: 8200070c 264 FUNC GLOBAL DEFAULT 1 PrintString 97 | 32: 82000040 52 FUNC GLOBAL DEFAULT 1 main 98 | 33: 8200068c 128 FUNC GLOBAL DEFAULT 1 PrintChar 99 | 34: 820000c4 20 FUNC GLOBAL DEFAULT 1 halt 100 | 35: 82000080 44 FUNC GLOBAL DEFAULT 1 mips_init 101 | 102 | No version information found in this file. 103 | -------------------------------------------------------------------------------- /gxemul/fsformat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coekjan/SOMOS/284bd72bfd7712697798a76eb30bda63c087eaab/gxemul/fsformat -------------------------------------------------------------------------------- /gxemul/r3000: -------------------------------------------------------------------------------- 1 | name("MALTA R3000") 2 | 3 | machine( 4 | name("SCSE-1 Testing") 5 | 6 | type("testmips") 7 | 8 | cpu("R3000") 9 | 10 | memory(64) 11 | 12 | disk("fs.img") 13 | 14 | load("vmlinux") 15 | 16 | ) 17 | -------------------------------------------------------------------------------- /gxemul/r3000_test: -------------------------------------------------------------------------------- 1 | name("MALTA R3000") 2 | 3 | machine( 4 | name("SCSE-1 Testing") 5 | 6 | type("testmips") 7 | 8 | cpu("R3000") 9 | 10 | memory(64) 11 | 12 | load("test") 13 | 14 | ) 15 | -------------------------------------------------------------------------------- /gxemul/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coekjan/SOMOS/284bd72bfd7712697798a76eb30bda63c087eaab/gxemul/test -------------------------------------------------------------------------------- /gxemul/view: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coekjan/SOMOS/284bd72bfd7712697798a76eb30bda63c087eaab/gxemul/view -------------------------------------------------------------------------------- /include.mk: -------------------------------------------------------------------------------- 1 | # Common includes in Makefile 2 | # 3 | # Copyright (C) 2007 Beihang University 4 | # Written By Zhu Like ( zlike@cse.buaa.edu.cn ) 5 | 6 | 7 | 8 | # Exercise 1.1. Please modify the CROSS_COMPILE path. 9 | 10 | CROSS_COMPILE := /OSLAB/compiler/usr/bin/mips_4KC- 11 | CC := $(CROSS_COMPILE)gcc 12 | CFLAGS := -O -G 0 -mno-abicalls -fno-builtin -Wa,-xgot -Wall -fPIC -march=r3000 13 | LD := $(CROSS_COMPILE)ld 14 | -------------------------------------------------------------------------------- /include/args.h: -------------------------------------------------------------------------------- 1 | /* simple command line parser from Plan 9 -- you are not expected to understand this */ 2 | /* see http://plan9.bell-labs.com/magic/man2html/2/arg */ 3 | 4 | #define _ARGSET(x) (x) = 0 5 | #define _ARGUSED(x) \ 6 | if (x) \ 7 | { \ 8 | } \ 9 | else 10 | 11 | #define ARGBEGIN \ 12 | for ((argv ? 0 : (argv = (void *)&argc)), \ 13 | argv++, argc--; \ 14 | argv[0] && argv[0][0] == '-' && argv[0][1]; \ 15 | argc--, argv++) \ 16 | { \ 17 | char *_args, *_argt; \ 18 | char _argc; \ 19 | _args = &argv[0][1]; \ 20 | if (_args[0] == '-' && _args[1] == 0) \ 21 | { \ 22 | argc--; \ 23 | argv++; \ 24 | break; \ 25 | } \ 26 | _argc = 0; \ 27 | while (*_args && (_argc = *_args++)) \ 28 | switch (_argc) 29 | #define ARGEND \ 30 | _ARGSET(_argt); \ 31 | _ARGUSED(_argt); \ 32 | _ARGUSED(_argc); \ 33 | _ARGUSED(_args); \ 34 | } \ 35 | _ARGUSED(argv); \ 36 | _ARGUSED(argc); 37 | #define ARGF() (_argt = _args, _args = "", \ 38 | (*_argt ? _argt : argv[1] ? (argc--, *++argv) \ 39 | : 0)) 40 | #define EARGF(x) (_argt = _args, _args = "", \ 41 | (*_argt ? _argt : argv[1] ? (argc--, *++argv) \ 42 | : ((x), abort(), (char *)0))) 43 | 44 | #define ARGC() _argc 45 | -------------------------------------------------------------------------------- /include/asm-mips3k/asm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * asm.h: Assembler macros to make things easier to read. 3 | * 4 | * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) 5 | * Copyright (C) 1998 Ralf Baechle 6 | */ 7 | 8 | #include "regdef.h" 9 | #include "cp0regdef.h" 10 | 11 | /* 12 | * LEAF - declare leaf routine 13 | */ 14 | #define LEAF(symbol) \ 15 | .globl symbol; \ 16 | .align 2; \ 17 | .type symbol,@function; \ 18 | .ent symbol,0; \ 19 | symbol: .frame sp,0,ra 20 | 21 | /* 22 | * NESTED - declare nested routine entry point 23 | */ 24 | #define NESTED(symbol, framesize, rpc) \ 25 | .globl symbol; \ 26 | .align 2; \ 27 | .type symbol,@function; \ 28 | .ent symbol,0; \ 29 | symbol: .frame sp, framesize, rpc 30 | 31 | 32 | /* 33 | * END - mark end of function 34 | */ 35 | #define END(function) \ 36 | .end function; \ 37 | .size function,.-function 38 | 39 | 40 | -------------------------------------------------------------------------------- /include/asm-mips3k/asm.h~: -------------------------------------------------------------------------------- 1 | /* 2 | * asmmacro.h: Assembler macros to make things easier to read. 3 | * 4 | * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) 5 | * Copyright (C) 1998 Ralf Baechle 6 | */ 7 | 8 | #include "regdef.h" 9 | #include "cp0regdef.h" 10 | 11 | /* 12 | * LEAF - declare leaf routine 13 | */ 14 | #define LEAF(symbol) \ 15 | .globl symbol; \ 16 | .align 2; \ 17 | .type symbol,@function; \ 18 | .ent symbol,0; \ 19 | symbol: .frame sp,0,ra 20 | 21 | /* 22 | * NESTED - declare nested routine entry point 23 | */ 24 | #define NESTED(symbol, framesize, rpc) \ 25 | .globl symbol; \ 26 | .align 2; \ 27 | .type symbol,@function; \ 28 | .ent symbol,0; \ 29 | symbol: .frame sp, framesize, rpc 30 | 31 | 32 | /* 33 | * END - mark end of function 34 | */ 35 | #define END(function) \ 36 | .end function; \ 37 | .size function,.-function 38 | 39 | 40 | -------------------------------------------------------------------------------- /include/asm-mips3k/cp0regdef.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 1994, 1995, 1996, 1997, 2000, 2001 by Ralf Baechle 3 | * 4 | * Copyright (C) 2001, Monta Vista Software 5 | * Author: jsun@mvista.com or jsun@junsun.net 6 | */ 7 | #ifndef _cp0regdef_h_ 8 | #define _cp0regdef_h_ 9 | 10 | #define CP0_INDEX $0 11 | #define CP0_RANDOM $1 12 | #define CP0_ENTRYLO0 $2 13 | #define CP0_ENTRYLO1 $3 14 | #define CP0_CONTEXT $4 15 | #define CP0_PAGEMASK $5 16 | #define CP0_WIRED $6 17 | #define CP0_BADVADDR $8 18 | #define CP0_COUNT $9 19 | #define CP0_ENTRYHI $10 20 | #define CP0_COMPARE $11 21 | #define CP0_STATUS $12 22 | #define CP0_CAUSE $13 23 | #define CP0_EPC $14 24 | #define CP0_PRID $15 25 | #define CP0_CONFIG $16 26 | #define CP0_LLADDR $17 27 | #define CP0_WATCHLO $18 28 | #define CP0_WATCHHI $19 29 | #define CP0_XCONTEXT $20 30 | #define CP0_FRAMEMASK $21 31 | #define CP0_DIAGNOSTIC $22 32 | #define CP0_PERFORMANCE $25 33 | #define CP0_ECC $26 34 | #define CP0_CACHEERR $27 35 | #define CP0_TAGLO $28 36 | #define CP0_TAGHI $29 37 | #define CP0_ERROREPC $30 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /include/asm-mips3k/regdef.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is subject to the terms and conditions of the GNU General Public 3 | * License. See the file "COPYING" in the main directory of this archive 4 | * for more details. 5 | * 6 | * Copyright (C) 1994, 1995 by Ralf Baechle 7 | */ 8 | 9 | #ifndef __ASM_MIPS_REGDEF_H 10 | #define __ASM_MIPS_REGDEF_H 11 | 12 | /* 13 | * Symbolic register names for 32 bit ABI 14 | */ 15 | #define zero $0 /* wired zero */ 16 | #define AT $1 /* assembler temp - uppercase because of ".set at" */ 17 | #define v0 $2 /* return value */ 18 | #define v1 $3 19 | #define a0 $4 /* argument registers */ 20 | #define a1 $5 21 | #define a2 $6 22 | #define a3 $7 23 | #define t0 $8 /* caller saved */ 24 | #define t1 $9 25 | #define t2 $10 26 | #define t3 $11 27 | #define t4 $12 28 | #define t5 $13 29 | #define t6 $14 30 | #define t7 $15 31 | #define s0 $16 /* callee saved */ 32 | #define s1 $17 33 | #define s2 $18 34 | #define s3 $19 35 | #define s4 $20 36 | #define s5 $21 37 | #define s6 $22 38 | #define s7 $23 39 | #define t8 $24 /* caller saved */ 40 | #define t9 $25 41 | #define jp $25 /* PIC jump register */ 42 | #define k0 $26 /* kernel scratch */ 43 | #define k1 $27 44 | #define gp $28 /* global pointer */ 45 | #define sp $29 /* stack pointer */ 46 | #define fp $30 /* frame pointer */ 47 | #define s8 $30 /* same like fp! */ 48 | #define ra $31 /* return address */ 49 | 50 | #endif /* __ASM_MIPS_REGDEF_H */ 51 | -------------------------------------------------------------------------------- /include/asm/asm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * asm.h: Assembler macros to make things easier to read. 3 | * 4 | * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) 5 | * Copyright (C) 1998 Ralf Baechle 6 | */ 7 | 8 | #include "regdef.h" 9 | #include "cp0regdef.h" 10 | 11 | /* 12 | * LEAF - declare leaf routine 13 | */ 14 | #define LEAF(symbol) \ 15 | .globl symbol; \ 16 | .align 2; \ 17 | .type symbol,@function; \ 18 | .ent symbol,0; \ 19 | symbol: .frame sp,0,ra 20 | 21 | /* 22 | * NESTED - declare nested routine entry point 23 | */ 24 | #define NESTED(symbol, framesize, rpc) \ 25 | .globl symbol; \ 26 | .align 2; \ 27 | .type symbol,@function; \ 28 | .ent symbol,0; \ 29 | symbol: .frame sp, framesize, rpc 30 | 31 | 32 | /* 33 | * END - mark end of function 34 | */ 35 | #define END(function) \ 36 | .end function; \ 37 | .size function,.-function 38 | 39 | #define EXPORT(symbol) \ 40 | .globl symbol; \ 41 | symbol: 42 | 43 | #define FEXPORT(symbol) \ 44 | .globl symbol; \ 45 | .type symbol,@function; \ 46 | symbol: 47 | 48 | 49 | -------------------------------------------------------------------------------- /include/asm/asm.h~: -------------------------------------------------------------------------------- 1 | /* 2 | * asmmacro.h: Assembler macros to make things easier to read. 3 | * 4 | * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) 5 | * Copyright (C) 1998 Ralf Baechle 6 | */ 7 | 8 | #include "regdef.h" 9 | #include "cp0regdef.h" 10 | 11 | /* 12 | * LEAF - declare leaf routine 13 | */ 14 | #define LEAF(symbol) \ 15 | .globl symbol; \ 16 | .align 2; \ 17 | .type symbol,@function; \ 18 | .ent symbol,0; \ 19 | symbol: .frame sp,0,ra 20 | 21 | /* 22 | * NESTED - declare nested routine entry point 23 | */ 24 | #define NESTED(symbol, framesize, rpc) \ 25 | .globl symbol; \ 26 | .align 2; \ 27 | .type symbol,@function; \ 28 | .ent symbol,0; \ 29 | symbol: .frame sp, framesize, rpc 30 | 31 | 32 | /* 33 | * END - mark end of function 34 | */ 35 | #define END(function) \ 36 | .end function; \ 37 | .size function,.-function 38 | 39 | 40 | -------------------------------------------------------------------------------- /include/asm/cp0regdef.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 1994, 1995, 1996, 1997, 2000, 2001 by Ralf Baechle 3 | * 4 | * Copyright (C) 2001, Monta Vista Software 5 | * Author: jsun@mvista.com or jsun@junsun.net 6 | */ 7 | #ifndef _cp0regdef_h_ 8 | #define _cp0regdef_h_ 9 | 10 | #define CP0_INDEX $0 11 | #define CP0_RANDOM $1 12 | #define CP0_ENTRYLO0 $2 13 | #define CP0_ENTRYLO1 $3 14 | #define CP0_CONTEXT $4 15 | #define CP0_PAGEMASK $5 16 | #define CP0_WIRED $6 17 | #define CP0_BADVADDR $8 18 | #define CP0_COUNT $9 19 | #define CP0_ENTRYHI $10 20 | #define CP0_COMPARE $11 21 | #define CP0_STATUS $12 22 | #define CP0_CAUSE $13 23 | #define CP0_EPC $14 24 | #define CP0_PRID $15 25 | #define CP0_CONFIG $16 26 | #define CP0_LLADDR $17 27 | #define CP0_WATCHLO $18 28 | #define CP0_WATCHHI $19 29 | #define CP0_XCONTEXT $20 30 | #define CP0_FRAMEMASK $21 31 | #define CP0_DIAGNOSTIC $22 32 | #define CP0_PERFORMANCE $25 33 | #define CP0_ECC $26 34 | #define CP0_CACHEERR $27 35 | #define CP0_TAGLO $28 36 | #define CP0_TAGHI $29 37 | #define CP0_ERROREPC $30 38 | 39 | 40 | #define STATUSF_IP4 0x1000 41 | #define STATUS_CU0 0x10000000 42 | #define STATUS_KUC 0x2 43 | #endif 44 | -------------------------------------------------------------------------------- /include/asm/regdef.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is subject to the terms and conditions of the GNU General Public 3 | * License. See the file "COPYING" in the main directory of this archive 4 | * for more details. 5 | * 6 | * Copyright (C) 1994, 1995 by Ralf Baechle 7 | */ 8 | 9 | #ifndef __ASM_MIPS_REGDEF_H 10 | #define __ASM_MIPS_REGDEF_H 11 | 12 | /* 13 | * Symbolic register names for 32 bit ABI 14 | */ 15 | #define zero $0 /* wired zero */ 16 | #define AT $1 /* assembler temp - uppercase because of ".set at" */ 17 | #define v0 $2 /* return value */ 18 | #define v1 $3 19 | #define a0 $4 /* argument registers */ 20 | #define a1 $5 21 | #define a2 $6 22 | #define a3 $7 23 | #define t0 $8 /* caller saved */ 24 | #define t1 $9 25 | #define t2 $10 26 | #define t3 $11 27 | #define t4 $12 28 | #define t5 $13 29 | #define t6 $14 30 | #define t7 $15 31 | #define s0 $16 /* callee saved */ 32 | #define s1 $17 33 | #define s2 $18 34 | #define s3 $19 35 | #define s4 $20 36 | #define s5 $21 37 | #define s6 $22 38 | #define s7 $23 39 | #define t8 $24 /* caller saved */ 40 | #define t9 $25 41 | #define jp $25 /* PIC jump register */ 42 | #define k0 $26 /* kernel scratch */ 43 | #define k1 $27 44 | #define gp $28 /* global pointer */ 45 | #define sp $29 /* stack pointer */ 46 | #define fp $30 /* frame pointer */ 47 | #define s8 $30 /* same like fp! */ 48 | #define ra $31 /* return address */ 49 | 50 | #endif /* __ASM_MIPS_REGDEF_H */ 51 | -------------------------------------------------------------------------------- /include/env.h: -------------------------------------------------------------------------------- 1 | /* See COPYRIGHT for copyright information. */ 2 | 3 | #ifndef _ENV_H_ 4 | #define _ENV_H_ 5 | 6 | #include "types.h" 7 | #include "queue.h" 8 | #include "trap.h" 9 | #include "mmu.h" 10 | 11 | #define LOG2NENV 10 12 | #define NENV (1 << LOG2NENV) 13 | #define ENVX(envid) ((envid) & (NENV - 1)) 14 | #define GET_ENV_ASID(envid) (((envid) >> 11) << 6) 15 | 16 | // Values of env_status in struct Env 17 | #define ENV_FREE 0 18 | #define ENV_RUNNABLE 1 19 | #define ENV_NOT_RUNNABLE 2 20 | 21 | struct Env 22 | { 23 | struct Trapframe env_tf; // Saved registers 24 | LIST_ENTRY(Env) 25 | env_link; // Free list 26 | u_int env_id; // Unique environment identifier 27 | u_int env_parent_id; // env_id of this env's parent 28 | u_int env_status; // Status of the environment 29 | Pde *env_pgdir; // Kernel virtual address of page dir 30 | u_int env_cr3; 31 | LIST_ENTRY(Env) 32 | env_sched_link; 33 | u_int env_pri; 34 | // Lab 4 IPC 35 | u_int env_ipc_value; // data value sent to us 36 | u_int env_ipc_from; // envid of the sender 37 | u_int env_ipc_recving; // env is blocked receiving 38 | u_int env_ipc_dstva; // va at which to map received page 39 | u_int env_ipc_perm; // perm of page mapping received 40 | 41 | // Lab 4 fault handling 42 | u_int env_pgfault_handler; // page fault state 43 | u_int env_xstacktop; // top of exception stack 44 | 45 | // Lab 6 scheduler counts 46 | u_int env_runs; // number of times been env_run'ed 47 | u_int env_nop; // align to avoid mul instruction 48 | }; 49 | 50 | LIST_HEAD(Env_list, Env); 51 | extern struct Env *envs; // All environments 52 | extern struct Env *curenv; // the current env 53 | extern struct Env_list env_sched_list[2]; // runnable env list 54 | 55 | void env_init(void); 56 | int env_alloc(struct Env **e, u_int parent_id); 57 | void env_free(struct Env *); 58 | void env_create_priority(u_char *binary, int size, int priority); 59 | void env_create(u_char *binary, int size); 60 | void env_destroy(struct Env *e); 61 | 62 | int envid2env(u_int envid, struct Env **penv, int checkperm); 63 | void env_run(struct Env *e); 64 | 65 | // for the grading script 66 | #define ENV_CREATE2(x, y) \ 67 | { \ 68 | extern u_char x[], y[]; \ 69 | env_create(x, (int)y); \ 70 | } 71 | #define ENV_CREATE_PRIORITY(x, y) \ 72 | { \ 73 | extern u_char binary_##x##_start[]; \ 74 | extern u_int binary_##x##_size; \ 75 | env_create_priority(binary_##x##_start, \ 76 | (u_int)binary_##x##_size, y); \ 77 | } 78 | #define ENV_CREATE(x) \ 79 | { \ 80 | extern u_char binary_##x##_start[]; \ 81 | extern u_int binary_##x##_size; \ 82 | env_create(binary_##x##_start, \ 83 | (u_int)binary_##x##_size); \ 84 | } 85 | 86 | #endif // !_ENV_H_ 87 | -------------------------------------------------------------------------------- /include/error.h: -------------------------------------------------------------------------------- 1 | /* See COPYRIGHT for copyright information. */ 2 | 3 | #ifndef _ERROR_H_ 4 | #define _ERROR_H_ 5 | 6 | // Kernel error codes -- keep in sync with list in kern/printf.c. 7 | #define E_UNSPECIFIED 1 // Unspecified or unknown problem 8 | #define E_BAD_ENV 2 // Environment doesn't exist or otherwise 9 | // cannot be used in requested action 10 | #define E_INVAL 3 // Invalid parameter 11 | #define E_NO_MEM 4 // Request failed due to memory shortage 12 | #define E_NO_FREE_ENV 5 // Attempt to create a new environment beyond 13 | // the maximum allowed 14 | #define E_IPC_NOT_RECV 6 // Attempt to send to env that is not recving. 15 | 16 | // File system error codes -- only seen in user-level 17 | #define E_NO_DISK 7 // No free space left on disk 18 | #define E_MAX_OPEN 8 // Too many files are open 19 | #define E_NOT_FOUND 9 // File or block not found 20 | #define E_BAD_PATH 10 // Bad path 21 | #define E_FILE_EXISTS 11 // File already exists 22 | #define E_NOT_EXEC 12 // File not a valid executable 23 | 24 | #define ENV_VAR_NOT_FOUND 1 25 | #define ENV_VAR_FULL 2 26 | #define ENV_VAR_RDONLY 3 27 | 28 | #define MAXERROR 12 29 | 30 | #endif // _ERROR_H_ 31 | -------------------------------------------------------------------------------- /include/fs.h: -------------------------------------------------------------------------------- 1 | // See COPYRIGHT for copyright information. 2 | 3 | #ifndef _FS_H_ 4 | #define _FS_H_ 1 5 | 6 | #include 7 | 8 | // File nodes (both in-memory and on-disk) 9 | 10 | // Bytes per file system block - same as page size 11 | #define BY2BLK BY2PG 12 | #define BIT2BLK (BY2BLK * 8) 13 | 14 | // Maximum size of a filename (a single path component), including null 15 | #define MAXNAMELEN 128 16 | 17 | // Maximum size of a complete pathname, including null 18 | #define MAXPATHLEN 1024 19 | 20 | // Number of (direct) block pointers in a File descriptor 21 | #define NDIRECT 10 22 | #define NINDIRECT (BY2BLK / 4) 23 | 24 | #define MAXFILESIZE (NINDIRECT * BY2BLK) 25 | 26 | #define BY2FILE 256 27 | 28 | struct File 29 | { 30 | u_char f_name[MAXNAMELEN]; // filename 31 | u_int f_size; // file size in bytes 32 | u_int f_type; // file type 33 | u_int f_direct[NDIRECT]; 34 | u_int f_indirect; 35 | 36 | struct File *f_dir; // valid only in memory 37 | u_char f_pad[256 - MAXNAMELEN - 4 - 4 - NDIRECT * 4 - 4 - 4]; 38 | }; 39 | 40 | #define FILE2BLK (BY2BLK / sizeof(struct File)) 41 | 42 | // File types 43 | #define FTYPE_REG 0 // Regular file 44 | #define FTYPE_DIR 1 // Directory 45 | #define FTYPE_BIN 2 // Binary file 46 | 47 | // File system super-block (both in-memory and on-disk) 48 | 49 | #define FS_MAGIC 0x68286097 // Everyone's favorite OS class 50 | 51 | struct Super 52 | { 53 | u_int s_magic; // Magic number: FS_MAGIC 54 | u_int s_nblocks; // Total number of blocks on disk 55 | struct File s_root; // Root directory node 56 | }; 57 | 58 | // Definitions for requests from clients to file system 59 | 60 | #define FSREQ_OPEN 1 61 | #define FSREQ_MAP 2 62 | #define FSREQ_SET_SIZE 3 63 | #define FSREQ_CLOSE 4 64 | #define FSREQ_DIRTY 5 65 | #define FSREQ_REMOVE 6 66 | #define FSREQ_SYNC 7 67 | #define FSREQ_CREATE 8 68 | 69 | struct Fsreq_open 70 | { 71 | char req_path[MAXPATHLEN]; 72 | u_int req_omode; 73 | }; 74 | 75 | struct Fsreq_create 76 | { 77 | char req_path[MAXPATHLEN]; 78 | int type; 79 | }; 80 | 81 | struct Fsreq_map 82 | { 83 | int req_fileid; 84 | u_int req_offset; 85 | }; 86 | 87 | struct Fsreq_set_size 88 | { 89 | int req_fileid; 90 | u_int req_size; 91 | }; 92 | 93 | struct Fsreq_close 94 | { 95 | int req_fileid; 96 | }; 97 | 98 | struct Fsreq_dirty 99 | { 100 | int req_fileid; 101 | u_int req_offset; 102 | }; 103 | 104 | struct Fsreq_remove 105 | { 106 | u_char req_path[MAXPATHLEN]; 107 | }; 108 | 109 | #endif // _FS_H_ 110 | -------------------------------------------------------------------------------- /include/kclock.h: -------------------------------------------------------------------------------- 1 | /* See COPYRIGHT for copyright information. */ 2 | 3 | #ifndef _KCLOCK_H_ 4 | #define _KCLOCK_H_ 5 | #define IO_RTC 0xb5000100 /* RTC port */ 6 | #ifndef __ASSEMBLER__ 7 | void kclock_init(void); 8 | #endif /* !__ASSEMBLER__ */ 9 | #endif 10 | -------------------------------------------------------------------------------- /include/kerelf.h: -------------------------------------------------------------------------------- 1 | /* This file defines standard ELF types, structures, and macros. 2 | Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. 3 | This file is part of the GNU C Library. 4 | Contributed by Ian Lance Taylor . 5 | 6 | The GNU C Library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Library General Public License as 8 | published by the Free Software Foundation; either version 2 of the 9 | License, or (at your option) any later version. 10 | 11 | The GNU C Library is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | Library General Public License for more details. 15 | 16 | You should have received a copy of the GNU Library General Public 17 | License along with the GNU C Library; see the file COPYING.LIB. If not, 18 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | Boston, MA 02111-1307, USA. */ 20 | 21 | #ifndef _KER_ELF_H 22 | #define _KER_ELF_H 23 | 24 | /* ELF defination file from GNU C Library. We simplefied this 25 | * file for our lab, removing definations about ELF64, structs and 26 | * enums which we don't care. 27 | */ 28 | 29 | #include 30 | 31 | typedef u_int64_t uint64_t; 32 | typedef u_int32_t uint32_t; 33 | typedef u_int16_t uint16_t; 34 | 35 | /* Type for a 16-bit quantity. */ 36 | typedef uint16_t Elf32_Half; 37 | 38 | /* Types for signed and unsigned 32-bit quantities. */ 39 | typedef uint32_t Elf32_Word; 40 | typedef int32_t Elf32_Sword; 41 | 42 | /* Types for signed and unsigned 64-bit quantities. */ 43 | typedef uint64_t Elf32_Xword; 44 | typedef int64_t Elf32_Sxword; 45 | 46 | /* Type of addresses. */ 47 | typedef uint32_t Elf32_Addr; 48 | 49 | /* Type of file offsets. */ 50 | typedef uint32_t Elf32_Off; 51 | 52 | /* Type for section indices, which are 16-bit quantities. */ 53 | typedef uint16_t Elf32_Section; 54 | 55 | /* Type of symbol indices. */ 56 | typedef uint32_t Elf32_Symndx; 57 | 58 | /* The ELF file header. This appears at the start of every ELF file. */ 59 | 60 | #define EI_NIDENT (16) 61 | 62 | typedef struct 63 | { 64 | unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ 65 | Elf32_Half e_type; /* Object file type */ 66 | Elf32_Half e_machine; /* Architecture */ 67 | Elf32_Word e_version; /* Object file version */ 68 | Elf32_Addr e_entry; /* Entry point virtual address */ 69 | Elf32_Off e_phoff; /* Program header table file offset */ 70 | Elf32_Off e_shoff; /* Section header table file offset */ 71 | Elf32_Word e_flags; /* Processor-specific flags */ 72 | Elf32_Half e_ehsize; /* ELF header size in bytes */ 73 | Elf32_Half e_phentsize; /* Program header table entry size */ 74 | Elf32_Half e_phnum; /* Program header table entry count */ 75 | Elf32_Half e_shentsize; /* Section header table entry size */ 76 | Elf32_Half e_shnum; /* Section header table entry count */ 77 | Elf32_Half e_shstrndx; /* Section header string table index */ 78 | } Elf32_Ehdr; 79 | 80 | /* Fields in the e_ident array. The EI_* macros are indices into the 81 | array. The macros under each EI_* macro are the values the byte 82 | may have. */ 83 | 84 | #define EI_MAG0 0 /* File identification byte 0 index */ 85 | #define ELFMAG0 0x7f /* Magic number byte 0 */ 86 | 87 | #define EI_MAG1 1 /* File identification byte 1 index */ 88 | #define ELFMAG1 'E' /* Magic number byte 1 */ 89 | 90 | #define EI_MAG2 2 /* File identification byte 2 index */ 91 | #define ELFMAG2 'L' /* Magic number byte 2 */ 92 | 93 | #define EI_MAG3 3 /* File identification byte 3 index */ 94 | #define ELFMAG3 'F' /* Magic number byte 3 */ 95 | 96 | /* Program segment header. */ 97 | 98 | typedef struct 99 | { 100 | Elf32_Word p_type; /* Segment type */ 101 | Elf32_Off p_offset; /* Segment file offset */ 102 | Elf32_Addr p_vaddr; /* Segment virtual address */ 103 | Elf32_Addr p_paddr; /* Segment physical address */ 104 | Elf32_Word p_filesz; /* Segment size in file */ 105 | Elf32_Word p_memsz; /* Segment size in memory */ 106 | Elf32_Word p_flags; /* Segment flags */ 107 | Elf32_Word p_align; /* Segment alignment */ 108 | } Elf32_Phdr; 109 | 110 | /* Legal values for p_type (segment type). */ 111 | 112 | #define PT_NULL 0 /* Program header table entry unused */ 113 | #define PT_LOAD 1 /* Loadable program segment */ 114 | #define PT_DYNAMIC 2 /* Dynamic linking information */ 115 | #define PT_INTERP 3 /* Program interpreter */ 116 | #define PT_NOTE 4 /* Auxiliary information */ 117 | #define PT_SHLIB 5 /* Reserved */ 118 | #define PT_PHDR 6 /* Entry for header table itself */ 119 | #define PT_NUM 7 /* Number of defined types. */ 120 | #define PT_LOOS 0x60000000 /* Start of OS-specific */ 121 | #define PT_HIOS 0x6fffffff /* End of OS-specific */ 122 | #define PT_LOPROC 0x70000000 /* Start of processor-specific */ 123 | #define PT_HIPROC 0x7fffffff /* End of processor-specific */ 124 | 125 | /* Legal values for p_flags (segment flags). */ 126 | 127 | #define PF_X (1 << 0) /* Segment is executable */ 128 | #define PF_W (1 << 1) /* Segment is writable */ 129 | #define PF_R (1 << 2) /* Segment is readable */ 130 | #define PF_MASKPROC 0xf0000000 /* Processor-specific */ 131 | 132 | int load_elf(u_char *binary, int size, 133 | u_long *entry_point, void *user_data, 134 | int (*map)(u_long, u_int32_t, u_char *, u_int32_t, void *)); 135 | 136 | #endif /* kerelf.h */ 137 | -------------------------------------------------------------------------------- /include/mmu.h: -------------------------------------------------------------------------------- 1 | #ifndef _MMU_H_ 2 | #define _MMU_H_ 3 | 4 | /* 5 | * This file contains: 6 | * 7 | * Part 1. MIPS definitions. 8 | * Part 2. Our conventions. 9 | * Part 3. Our helper functions. 10 | */ 11 | 12 | /* 13 | * Part 1. MIPS definitions. 14 | */ 15 | #define BY2PG 4096 // bytes to a page 16 | #define PDMAP (4 * 1024 * 1024) // bytes mapped by a page directory entry 17 | #define PGSHIFT 12 18 | #define PDSHIFT 22 // log2(PDMAP) 19 | #define PDX(va) ((((u_long)(va)) >> 22) & 0x03FF) 20 | #define PTX(va) ((((u_long)(va)) >> 12) & 0x03FF) 21 | #define PTE_ADDR(pte) ((u_long)(pte) & ~0xFFF) 22 | 23 | // page number field of address 24 | #define PPN(va) (((u_long)(va)) >> 12) 25 | #define VPN(va) PPN(va) 26 | 27 | #define VA2PFN(va) (((u_long)(va)) & 0xFFFFF000) // va 2 PFN for EntryLo0/1 28 | #define PTE2PT 1024 29 | //$#define VA2PDE(va) (((u_long)(va)) & 0xFFC00000 ) // for context 30 | 31 | /* Page Table/Directory Entry flags 32 | * these are defined by the hardware 33 | */ 34 | #define PTE_G 0x0100 // Global bit 35 | #define PTE_V 0x0200 // Valid bit 36 | #define PTE_R 0x0400 // Dirty bit ,'0' means only read ,otherwise make interrupt 37 | #define PTE_D 0x0002 // fileSystem Cached is dirty 38 | #define PTE_COW 0x0001 // Copy On Write 39 | #define PTE_UC 0x0800 // unCached 40 | #define PTE_LIBRARY 0x0004 // share memmory 41 | /* 42 | * Part 2. Our conventions. 43 | */ 44 | 45 | /* 46 | o 4G -----------> +----------------------------+------------0x100000000 47 | o | ... | kseg3 48 | o +----------------------------+------------0xe000 0000 49 | o | ... | kseg2 50 | o +----------------------------+------------0xc000 0000 51 | o | Interrupts & Exception | kseg1 52 | o +----------------------------+------------0xa000 0000 53 | o | Invalid memory | /|\ 54 | o +----------------------------+----|-------Physics Memory Max 55 | o | ... | kseg0 56 | o VPT,KSTACKTOP-----> +----------------------------+----|-------0x8040 0000-------end 57 | o | Kernel Stack | | KSTKSIZE /|\ 58 | o +----------------------------+----|------ | 59 | o | Kernel Text | | PDMAP 60 | o KERNBASE -----> +----------------------------+----|-------0x8001 0000 | 61 | o | Interrupts & Exception | \|/ \|/ 62 | o ULIM -----> +----------------------------+------------0x8000 0000------- 63 | o | User VPT | PDMAP /|\ 64 | o UVPT -----> +----------------------------+------------0x7fc0 0000 | 65 | o | PAGES | PDMAP | 66 | o UPAGES -----> +----------------------------+------------0x7f80 0000 | 67 | o | ENVS | PDMAP | 68 | o UTOP,UENVS -----> +----------------------------+------------0x7f40 0000 | 69 | o UXSTACKTOP -/ | user exception stack | BY2PG | 70 | o +----------------------------+------------0x7f3f f000 | 71 | o | Invalid memory | BY2PG | 72 | o USTACKTOP ----> +----------------------------+------------0x7f3f e000 | 73 | o | normal user stack | BY2PG | 74 | o +----------------------------+------------0x7f3f d000 | 75 | a | | | 76 | a ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 77 | a . . | 78 | a . . kuseg 79 | a . . | 80 | a |~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | 81 | a | | | 82 | o UTEXT -----> +----------------------------+ | 83 | o | | 2 * PDMAP \|/ 84 | a 0 ------------> +----------------------------+ ----------------------------- 85 | o 86 | */ 87 | 88 | #define KERNBASE 0x80010000 89 | 90 | #define VPT (ULIM + PDMAP) 91 | #define KSTACKTOP (VPT - 0x100) 92 | #define KSTKSIZE (8 * BY2PG) 93 | #define ULIM 0x80000000 94 | 95 | #define UVPT (ULIM - PDMAP) 96 | #define UPAGES (UVPT - PDMAP) 97 | #define UENVS (UPAGES - PDMAP) 98 | 99 | #define UTOP UENVS 100 | #define UXSTACKTOP (UTOP) 101 | #define TIMESTACK 0x82000000 102 | 103 | #define USTACKTOP (UTOP - 2 * BY2PG) 104 | #define UTEXT 0x00400000 105 | 106 | #define E_UNSPECIFIED 1 // Unspecified or unknown problem 107 | #define E_BAD_ENV 2 // Environment doesn't exist or otherwise 108 | // cannot be used in requested action 109 | #define E_INVAL 3 // Invalid parameter 110 | #define E_NO_MEM 4 // Request failed due to memory shortage 111 | #define E_NO_FREE_ENV 5 // Attempt to create a new environment beyond 112 | // the maximum allowed 113 | #define E_IPC_NOT_RECV 6 // Attempt to send to env that is not recving. 114 | 115 | // File system error codes -- only seen in user-level 116 | #define E_NO_DISK 7 // No free space left on disk 117 | #define E_MAX_OPEN 8 // Too many files are open 118 | #define E_NOT_FOUND 9 // File or block not found 119 | #define E_BAD_PATH 10 // Bad path 120 | #define E_FILE_EXISTS 11 // File already exists 121 | #define E_NOT_EXEC 12 // File not a valid executable 122 | 123 | #define ENV_VAR_NOT_FOUND 1 124 | #define ENV_VAR_FULL 2 125 | #define ENV_VAR_RDONLY 3 126 | 127 | #define MAXERROR 12 128 | 129 | #ifndef __ASSEMBLER__ 130 | 131 | /* 132 | * Part 3. Our helper functions. 133 | */ 134 | #include "types.h" 135 | void bcopy(const void *, void *, size_t); 136 | void bzero(void *, size_t); 137 | 138 | extern char bootstacktop[], bootstack[]; 139 | 140 | extern u_long npage; 141 | 142 | typedef u_long Pde; 143 | typedef u_long Pte; 144 | 145 | extern volatile Pte *vpt[]; 146 | extern volatile Pde *vpd[]; 147 | 148 | #define PADDR(kva) \ 149 | ( \ 150 | { \ 151 | u_long a = (u_long)(kva); \ 152 | if (a < ULIM) \ 153 | panic("PADDR called with invalid kva %08lx", a); \ 154 | a - ULIM; \ 155 | }) 156 | 157 | // translates from physical address to kernel virtual address 158 | #define KADDR(pa) \ 159 | ( \ 160 | { \ 161 | u_long ppn = PPN(pa); \ 162 | if (ppn >= npage) \ 163 | panic("KADDR called with invalid pa %08lx", (u_long)pa); \ 164 | (pa) + ULIM; \ 165 | }) 166 | 167 | #define assert(x) \ 168 | do \ 169 | { \ 170 | if (!(x)) \ 171 | panic("assertion failed: %s", #x); \ 172 | } while (0) 173 | 174 | #define TRUP(_p) \ 175 | ( \ 176 | { \ 177 | register typeof((_p)) __m_p = (_p); \ 178 | (u_int) __m_p > ULIM ? (typeof(_p))ULIM : __m_p; \ 179 | }) 180 | 181 | extern void tlb_out(u_int entryhi); 182 | #endif //!__ASSEMBLER__ 183 | #endif // !_MMU_H_ 184 | -------------------------------------------------------------------------------- /include/pmap.h: -------------------------------------------------------------------------------- 1 | #ifndef _PMAP_H_ 2 | #define _PMAP_H_ 3 | 4 | #include "types.h" 5 | #include "queue.h" 6 | #include "mmu.h" 7 | #include "printf.h" 8 | 9 | LIST_HEAD(Page_list, Page); 10 | typedef LIST_ENTRY(Page) Page_LIST_entry_t; 11 | 12 | struct Page 13 | { 14 | Page_LIST_entry_t pp_link; /* free list link */ 15 | 16 | // Ref is the count of pointers (usually in page table entries) 17 | // to this page. This only holds for pages allocated using 18 | // page_alloc. Pages allocated at boot time using pmap.c's "alloc" 19 | // do not have valid reference count fields. 20 | 21 | u_short pp_ref; 22 | }; 23 | 24 | extern struct Page *pages; 25 | static inline u_long 26 | page2ppn(struct Page *pp) 27 | { 28 | return pp - pages; 29 | } 30 | 31 | static inline u_long 32 | page2pa(struct Page *pp) 33 | { 34 | return page2ppn(pp) << PGSHIFT; 35 | } 36 | 37 | static inline struct Page * 38 | pa2page(u_long pa) 39 | { 40 | if (PPN(pa) >= npage) 41 | panic("pa2page called with invalid pa: %x", pa); 42 | return &pages[PPN(pa)]; 43 | } 44 | 45 | static inline u_long 46 | page2kva(struct Page *pp) 47 | { 48 | return KADDR(page2pa(pp)); 49 | } 50 | 51 | static inline u_long 52 | va2pa(Pde *pgdir, u_long va) 53 | { 54 | Pte *p; 55 | 56 | pgdir = &pgdir[PDX(va)]; 57 | if (!(*pgdir & PTE_V)) 58 | return ~0; 59 | p = (Pte *)KADDR(PTE_ADDR(*pgdir)); 60 | if (!(p[PTX(va)] & PTE_V)) 61 | return ~0; 62 | return PTE_ADDR(p[PTX(va)]); 63 | } 64 | 65 | void mips_detect_memory(); 66 | 67 | void mips_vm_init(); 68 | 69 | void mips_init(); 70 | void page_init(void); 71 | void page_check(); 72 | int page_alloc(struct Page **pp); 73 | void page_free(struct Page *pp); 74 | void page_decref(struct Page *pp); 75 | int pgdir_walk(Pde *pgdir, u_long va, int create, Pte **ppte); 76 | int page_insert(Pde *pgdir, struct Page *pp, u_long va, u_int perm); 77 | struct Page *page_lookup(Pde *pgdir, u_long va, Pte **ppte); 78 | void page_remove(Pde *pgdir, u_long va); 79 | void tlb_invalidate(Pde *pgdir, u_long va); 80 | 81 | void boot_map_segment(Pde *pgdir, u_long va, u_long size, u_long pa, int perm); 82 | 83 | extern struct Page *pages; 84 | 85 | #endif /* _PMAP_H_ */ 86 | -------------------------------------------------------------------------------- /include/print.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2001 MontaVista Software Inc. 3 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License as published by the 7 | * Free Software Foundation; either version 2 of the License, or (at your 8 | * option) any later version. 9 | * 10 | */ 11 | 12 | #ifndef _print_h_ 13 | #define _print_h_ 14 | 15 | #include 16 | 17 | /* this is the maximum width for a variable */ 18 | #define LP_MAX_BUF 1000 19 | 20 | /* -*- 21 | * output function takes an void pointer which is passed in as the 22 | * second argument in lp_Print(). This black-box argument gives output 23 | * function a way to track state. 24 | * 25 | * The second argument in output function is a pointer to char buffer. 26 | * The third argument specifies the number of chars to outputed. 27 | * 28 | * output function cannot assume the buffer is null-terminated after 29 | * l number of chars. 30 | */ 31 | void lp_Print(void (*output)(void *, char *, int), 32 | void *arg, 33 | char *fmt, 34 | va_list ap); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /include/printf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2001 MontaVista Software Inc. 3 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License as published by the 7 | * Free Software Foundation; either version 2 of the License, or (at your 8 | * option) any later version. 9 | * 10 | */ 11 | 12 | #ifndef _printf_h_ 13 | #define _printf_h_ 14 | 15 | #include 16 | void printf(char *fmt, ...); 17 | 18 | void _panic(const char *, int, const char *, ...) 19 | __attribute__((noreturn)); 20 | 21 | #define panic(...) _panic(__FILE__, __LINE__, __VA_ARGS__) 22 | 23 | #endif /* _printf_h_ */ 24 | -------------------------------------------------------------------------------- /include/sched.h: -------------------------------------------------------------------------------- 1 | /* See COPYRIGHT for copyright information. */ 2 | 3 | #ifndef __SCHED_H__ 4 | #define __SCHED_H__ 5 | 6 | void sched_init(void); 7 | void sched_yield(void); 8 | void sched_intr(int); 9 | 10 | #endif /* __SCHED_H__ */ 11 | -------------------------------------------------------------------------------- /include/stackframe.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | .macro STI 7 | mfc0 t0, CP0_STATUS 8 | li t1, (STATUS_CU0 | 0x1) 9 | or t0, t1 10 | mtc0 t0, CP0_STATUS 11 | 12 | .endm 13 | 14 | 15 | .macro CLI 16 | mfc0 t0, CP0_STATUS 17 | li t1, (STATUS_CU0 | 0x1) 18 | or t0, t1 19 | xor t0, 0x1 20 | mtc0 t0, CP0_STATUS 21 | .endm 22 | 23 | .macro SAVE_ALL 24 | 25 | mfc0 k0,CP0_STATUS 26 | sll k0,3 /* extract cu0 bit */ 27 | bltz k0,1f 28 | nop 29 | /* 30 | * Called from user mode, new stack 31 | */ 32 | //lui k1,%hi(kernelsp) 33 | //lw k1,%lo(kernelsp)(k1) //not clear right now 34 | 35 | 1: 36 | move k0,sp 37 | get_sp 38 | move k1,sp 39 | subu sp,k1,TF_SIZE 40 | sw k0,TF_REG29(sp) 41 | sw $2,TF_REG2(sp) 42 | mfc0 v0,CP0_STATUS 43 | sw v0,TF_STATUS(sp) 44 | mfc0 v0,CP0_CAUSE 45 | sw v0,TF_CAUSE(sp) 46 | mfc0 v0,CP0_EPC 47 | sw v0,TF_EPC(sp) 48 | mfc0 v0, CP0_BADVADDR 49 | sw v0, TF_BADVADDR(sp) 50 | mfhi v0 51 | sw v0,TF_HI(sp) 52 | mflo v0 53 | sw v0,TF_LO(sp) 54 | sw $0,TF_REG0(sp) 55 | sw $1,TF_REG1(sp) 56 | //sw $2,TF_REG2(sp) 57 | sw $3,TF_REG3(sp) 58 | sw $4,TF_REG4(sp) 59 | sw $5,TF_REG5(sp) 60 | sw $6,TF_REG6(sp) 61 | sw $7,TF_REG7(sp) 62 | sw $8,TF_REG8(sp) 63 | sw $9,TF_REG9(sp) 64 | sw $10,TF_REG10(sp) 65 | sw $11,TF_REG11(sp) 66 | sw $12,TF_REG12(sp) 67 | sw $13,TF_REG13(sp) 68 | sw $14,TF_REG14(sp) 69 | sw $15,TF_REG15(sp) 70 | sw $16,TF_REG16(sp) 71 | sw $17,TF_REG17(sp) 72 | sw $18,TF_REG18(sp) 73 | sw $19,TF_REG19(sp) 74 | sw $20,TF_REG20(sp) 75 | sw $21,TF_REG21(sp) 76 | sw $22,TF_REG22(sp) 77 | sw $23,TF_REG23(sp) 78 | sw $24,TF_REG24(sp) 79 | sw $25,TF_REG25(sp) 80 | sw $26,TF_REG26(sp) 81 | sw $27,TF_REG27(sp) 82 | sw $28,TF_REG28(sp) 83 | sw $30,TF_REG30(sp) 84 | sw $31,TF_REG31(sp) 85 | .endm 86 | /* 87 | * Note that we restore the IE flags from stack. This means 88 | * that a modified IE mask will be nullified. 89 | */ 90 | .macro RESTORE_SOME 91 | .set mips1 92 | mfc0 t0,CP0_STATUS 93 | ori t0,0x3 94 | xori t0,0x3 95 | mtc0 t0,CP0_STATUS 96 | lw v0,TF_STATUS(sp) 97 | li v1, 0xff00 98 | and t0, v1 99 | nor v1, $0, v1 100 | and v0, v1 101 | or v0, t0 102 | mtc0 v0,CP0_STATUS 103 | lw v1,TF_LO(sp) 104 | mtlo v1 105 | lw v0,TF_HI(sp) 106 | lw v1,TF_EPC(sp) 107 | mthi v0 108 | mtc0 v1,CP0_EPC 109 | lw $31,TF_REG31(sp) 110 | lw $30,TF_REG30(sp) 111 | lw $28,TF_REG28(sp) 112 | lw $25,TF_REG25(sp) 113 | lw $24,TF_REG24(sp) 114 | lw $23,TF_REG23(sp) 115 | lw $22,TF_REG22(sp) 116 | lw $21,TF_REG21(sp) 117 | lw $20,TF_REG20(sp) 118 | lw $19,TF_REG19(sp) 119 | lw $18,TF_REG18(sp) 120 | lw $17,TF_REG17(sp) 121 | lw $16,TF_REG16(sp) 122 | lw $15,TF_REG15(sp) 123 | lw $14,TF_REG14(sp) 124 | lw $13,TF_REG13(sp) 125 | lw $12,TF_REG12(sp) 126 | lw $11,TF_REG11(sp) 127 | lw $10,TF_REG10(sp) 128 | lw $9,TF_REG9(sp) 129 | lw $8,TF_REG8(sp) 130 | lw $7,TF_REG7(sp) 131 | lw $6,TF_REG6(sp) 132 | lw $5,TF_REG5(sp) 133 | lw $4,TF_REG4(sp) 134 | lw $3,TF_REG3(sp) 135 | lw $2,TF_REG2(sp) 136 | lw $1,TF_REG1(sp) 137 | .endm 138 | 139 | .macro RESTORE_ALL 140 | RESTORE_SOME 141 | lw sp,TF_REG29(sp) /* Deallocate stack */ 142 | .endm 143 | 144 | .set noreorder 145 | .macro RESTORE_ALL_AND_RET 146 | RESTORE_SOME 147 | lw k0,TF_EPC(sp) 148 | lw sp,TF_REG29(sp) /* Deallocate stack */ 149 | jr k0 150 | rfe 151 | .endm 152 | 153 | 154 | .macro get_sp 155 | mfc0 k1, CP0_CAUSE 156 | andi k1, 0x107C 157 | xori k1, 0x1000 158 | bnez k1, 1f 159 | nop 160 | li sp, 0x82000000 161 | j 2f 162 | nop 163 | 1: 164 | bltz sp, 2f 165 | nop 166 | lw sp, KERNEL_SP 167 | nop 168 | 169 | 2: nop 170 | 171 | 172 | .endm 173 | -------------------------------------------------------------------------------- /include/trap.h: -------------------------------------------------------------------------------- 1 | #ifndef _TRAP_H_ 2 | #define _TRAP_H_ 3 | 4 | /* these are processor defined */ 5 | #define T_DIVIDE 0 /* divide error */ 6 | #define T_DEBUG 1 /* debug exception */ 7 | #define T_NMI 2 /* non-maskable interrupt */ 8 | #define T_BRKPT 3 /* breakpoint */ 9 | #define T_OFLOW 4 /* overflow */ 10 | #define T_BOUND 5 /* bounds check */ 11 | #define T_ILLOP 6 /* illegal opcode */ 12 | #define T_DEVICE 7 /* device not available */ 13 | #define T_DBLFLT 8 /* double fault */ 14 | /* 9 is reserved */ 15 | #define T_TSS 10 /* invalid task switch segment */ 16 | #define T_SEGNP 11 /* segment not present */ 17 | #define T_STACK 12 /* stack exception */ 18 | #define T_GPFLT 13 /* genernal protection fault */ 19 | #define T_PGFLT 14 /* page fault */ 20 | /* 15 is reserved */ 21 | #define T_FPERR 16 /* floating point error */ 22 | #define T_ALIGN 17 /* aligment check */ 23 | #define T_MCHK 18 /* machine check */ 24 | 25 | /* These are arbitrarily chosen, but with care not to overlap 26 | * processor defined exceptions or interrupt vectors. 27 | */ 28 | #define T_SYSCALL 0x30 /* system call */ 29 | #define T_DEFAULT 500 /* catchall */ 30 | 31 | #ifndef __ASSEMBLER__ 32 | 33 | #include 34 | 35 | struct Trapframe { //lr:need to be modified(reference to linux pt_regs) TODO 36 | /* Saved main processor registers. */ 37 | unsigned long regs[32]; 38 | 39 | /* Saved special registers. */ 40 | unsigned long cp0_status; 41 | unsigned long hi; 42 | unsigned long lo; 43 | unsigned long cp0_badvaddr; 44 | unsigned long cp0_cause; 45 | unsigned long cp0_epc; 46 | unsigned long pc; 47 | }; 48 | void *set_except_vector(int n, void * addr); 49 | void trap_init(); 50 | 51 | #endif /* !__ASSEMBLER__ */ 52 | /* 53 | * Stack layout for all exceptions: 54 | * 55 | * ptrace needs to have all regs on the stack. If the order here is changed, 56 | * it needs to be updated in include/asm-mips/ptrace.h 57 | * 58 | * The first PTRSIZE*5 bytes are argument save space for C subroutines. 59 | */ 60 | 61 | #define TF_REG0 0 62 | #define TF_REG1 ((TF_REG0) + 4) 63 | #define TF_REG2 ((TF_REG1) + 4) 64 | #define TF_REG3 ((TF_REG2) + 4) 65 | #define TF_REG4 ((TF_REG3) + 4) 66 | #define TF_REG5 ((TF_REG4) + 4) 67 | #define TF_REG6 ((TF_REG5) + 4) 68 | #define TF_REG7 ((TF_REG6) + 4) 69 | #define TF_REG8 ((TF_REG7) + 4) 70 | #define TF_REG9 ((TF_REG8) + 4) 71 | #define TF_REG10 ((TF_REG9) + 4) 72 | #define TF_REG11 ((TF_REG10) + 4) 73 | #define TF_REG12 ((TF_REG11) + 4) 74 | #define TF_REG13 ((TF_REG12) + 4) 75 | #define TF_REG14 ((TF_REG13) + 4) 76 | #define TF_REG15 ((TF_REG14) + 4) 77 | #define TF_REG16 ((TF_REG15) + 4) 78 | #define TF_REG17 ((TF_REG16) + 4) 79 | #define TF_REG18 ((TF_REG17) + 4) 80 | #define TF_REG19 ((TF_REG18) + 4) 81 | #define TF_REG20 ((TF_REG19) + 4) 82 | #define TF_REG21 ((TF_REG20) + 4) 83 | #define TF_REG22 ((TF_REG21) + 4) 84 | #define TF_REG23 ((TF_REG22) + 4) 85 | #define TF_REG24 ((TF_REG23) + 4) 86 | #define TF_REG25 ((TF_REG24) + 4) 87 | /* 88 | * $26 (k0) and $27 (k1) not saved 89 | */ 90 | #define TF_REG26 ((TF_REG25) + 4) 91 | #define TF_REG27 ((TF_REG26) + 4) 92 | #define TF_REG28 ((TF_REG27) + 4) 93 | #define TF_REG29 ((TF_REG28) + 4) 94 | #define TF_REG30 ((TF_REG29) + 4) 95 | #define TF_REG31 ((TF_REG30) + 4) 96 | 97 | #define TF_STATUS ((TF_REG31) + 4) 98 | 99 | #define TF_HI ((TF_STATUS) + 4) 100 | #define TF_LO ((TF_HI) + 4) 101 | 102 | #define TF_BADVADDR ((TF_LO)+4) 103 | #define TF_CAUSE ((TF_BADVADDR) + 4) 104 | #define TF_EPC ((TF_CAUSE) + 4) #define TF_PC ((TF_EPC) + 4) 105 | /* 106 | * Size of stack frame, word/double word alignment 107 | */ 108 | #define TF_SIZE ((TF_PC)+4) 109 | #endif /* _TRAP_H_ */ 110 | -------------------------------------------------------------------------------- /include/types.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: types.h,v 1.12 1997/11/30 18:50:18 millert Exp $ */ 2 | /* $NetBSD: types.h,v 1.29 1996/11/15 22:48:25 jtc Exp $ */ 3 | 4 | #ifndef _INC_TYPES_H_ 5 | #define _INC_TYPES_H_ 6 | 7 | #ifndef NULL 8 | #define NULL ((void *) 0) 9 | #endif /* !NULL */ 10 | 11 | 12 | typedef unsigned char u_int8_t; 13 | typedef short int16_t; 14 | typedef unsigned short u_int16_t; 15 | typedef int int32_t; 16 | typedef unsigned int u_int32_t; 17 | typedef long long int64_t; 18 | typedef unsigned long long u_int64_t; 19 | 20 | typedef int32_t register_t; 21 | 22 | typedef unsigned char u_char; 23 | typedef unsigned short u_short; 24 | typedef unsigned int u_int; 25 | typedef unsigned long u_long; 26 | 27 | typedef u_int64_t u_quad_t; /* quads */ 28 | typedef int64_t quad_t; 29 | typedef quad_t * qaddr_t; 30 | 31 | typedef u_int32_t size_t; 32 | 33 | 34 | #define MIN(_a, _b) \ 35 | ({ \ 36 | typeof(_a) __a = (_a); \ 37 | typeof(_b) __b = (_b); \ 38 | __a <= __b ? __a : __b; \ 39 | }) 40 | 41 | /* Static assert, for compile-time assertion checking */ 42 | #define static_assert(c) switch (c) case 0: case(c): 43 | 44 | #define offsetof(type, member) ((size_t)(&((type *)0)->member)) 45 | 46 | /* Rounding; only works for n = power of two */ 47 | #define ROUND(a, n) (((((u_long)(a))+(n)-1)) & ~((n)-1)) 48 | #define ROUNDDOWN(a, n) (((u_long)(a)) & ~((n)-1)) 49 | 50 | 51 | #endif /* !_INC_TYPES_H_ */ 52 | -------------------------------------------------------------------------------- /include/unistd.h: -------------------------------------------------------------------------------- 1 | #ifndef UNISTD_H 2 | #define UNISTD_H 3 | 4 | #define __SYSCALL_BASE 9527 5 | #define __NR_SYSCALLS 20 6 | 7 | 8 | #define SYS_putchar ((__SYSCALL_BASE ) + (0 ) ) 9 | #define SYS_getenvid ((__SYSCALL_BASE ) + (1 ) ) 10 | #define SYS_yield ((__SYSCALL_BASE ) + (2 ) ) 11 | #define SYS_env_destroy ((__SYSCALL_BASE ) + (3 ) ) 12 | #define SYS_set_pgfault_handler ((__SYSCALL_BASE ) + (4 ) ) 13 | #define SYS_mem_alloc ((__SYSCALL_BASE ) + (5 ) ) 14 | #define SYS_mem_map ((__SYSCALL_BASE ) + (6 ) ) 15 | #define SYS_mem_unmap ((__SYSCALL_BASE ) + (7 ) ) 16 | #define SYS_env_alloc ((__SYSCALL_BASE ) + (8 ) ) 17 | #define SYS_set_env_status ((__SYSCALL_BASE ) + (9 ) ) 18 | #define SYS_set_trapframe ((__SYSCALL_BASE ) + (10 ) ) 19 | #define SYS_panic ((__SYSCALL_BASE ) + (11 ) ) 20 | #define SYS_ipc_can_send ((__SYSCALL_BASE ) + (12 ) ) 21 | #define SYS_ipc_recv ((__SYSCALL_BASE ) + (13 ) ) 22 | #define SYS_cgetc ((__SYSCALL_BASE ) + (14 ) ) 23 | #define SYS_write_dev ((__SYSCALL_BASE ) + (15) ) 24 | #define SYS_read_dev ((__SYSCALL_BASE ) + (16) ) 25 | #define SYS_wait_cons ((__SYSCALL_BASE ) + 17) 26 | #define SYS_signal_cons ((__SYSCALL_BASE ) + 18) 27 | #define SYS_set_env ((__SYSCALL_BASE ) + 19) 28 | #define SYS_get_env ((__SYSCALL_BASE ) + 20) 29 | #define SYS_list_env_var ((__SYSCALL_BASE ) + 21) 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /init/Makefile: -------------------------------------------------------------------------------- 1 | INCLUDES := -I../include 2 | 3 | %.o: %.c 4 | $(CC) $(CFLAGS) $(INCLUDES) -c $< 5 | 6 | .PHONY: clean 7 | 8 | all: init.o main.o code.o 9 | 10 | clean: 11 | rm -rf *~ *.o 12 | 13 | 14 | include ../include.mk 15 | 16 | -------------------------------------------------------------------------------- /init/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | extern char aoutcode[]; 9 | extern char boutcode[]; 10 | 11 | void mips_init() 12 | { 13 | printf("init.c:\tmips_init() is called\n"); 14 | mips_detect_memory(); 15 | 16 | mips_vm_init(); 17 | page_init(); 18 | //page_check(); 19 | 20 | env_init(); 21 | 22 | //ENV_CREATE(user_fktest); 23 | //ENV_CREATE(user_pt1); 24 | //ENV_CREATE(user_idle); 25 | //ENV_CREATE(user_fktest); 26 | //ENV_CREATE(user_pingpong); 27 | //ENV_CREATE(user_testfdsharing); 28 | // ENV_CREATE(user_testpipe); 29 | //ENV_CREATE(user_testpiperace); 30 | ENV_CREATE(user_icode); 31 | ENV_CREATE(fs_serv); 32 | // ENV_CREATE(user_testpiperace); 33 | // ENV_CREATE(user_testptelibrary); 34 | //ENV_CREATE(user_icode); 35 | trap_init(); 36 | kclock_init(); 37 | //env_run(&envs[0]); 38 | 39 | //env_run(&envs[1]); 40 | 41 | panic("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); 42 | while (1) 43 | ; 44 | panic("init.c:\tend of mips_init() reached!"); 45 | } 46 | 47 | void bcopy(const void *src, void *dst, size_t len) 48 | { 49 | void *max; 50 | 51 | max = dst + len; 52 | // copy machine words while possible 53 | while (dst + 3 < max) 54 | { 55 | *(int *)dst = *(int *)src; 56 | dst += 4; 57 | src += 4; 58 | } 59 | // finish remaining 0-3 bytes 60 | while (dst < max) 61 | { 62 | *(char *)dst = *(char *)src; 63 | dst += 1; 64 | src += 1; 65 | } 66 | } 67 | 68 | void bzero(void *b, size_t len) 69 | { 70 | void *max; 71 | 72 | max = b + len; 73 | 74 | //printf("init.c:\tzero from %x to %x\n",(int)b,(int)max); 75 | 76 | // zero machine words while possible 77 | 78 | while (b + 3 < max) 79 | { 80 | *(int *)b = 0; 81 | b += 4; 82 | } 83 | 84 | // finish remaining 0-3 bytes 85 | while (b < max) 86 | { 87 | *(char *)b++ = 0; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /init/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2001 MontaVista Software Inc. 3 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License as published by the 7 | * Free Software Foundation; either version 2 of the License, or (at your 8 | * option) any later version. 9 | * 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | int main() 16 | { 17 | printf("main.c:\tmain is start ...\n"); 18 | 19 | mips_init(); 20 | panic("main is over is error!"); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /lib/Makefile: -------------------------------------------------------------------------------- 1 | INCLUDES := -I./ -I../ -I../include/ 2 | %.o: %.c 3 | $(CC) $(CFLAGS) $(INCLUDES) -c $< 4 | 5 | %.o: %.S 6 | $(CC) $(CFLAGS) $(INCLUDES) -c $< 7 | 8 | .PHONY: clean 9 | 10 | all: kernel_elfloader.o env.o print.o printf.o sched.o env_asm.o kclock.o traps.o genex.o kclock_asm.o syscall.o syscall_all.o getc.o 11 | 12 | clean: 13 | rm -rf *~ *.o 14 | 15 | 16 | include ../include.mk 17 | -------------------------------------------------------------------------------- /lib/env_asm.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../include/asm/cp0regdef.h" 3 | #include 4 | #include 5 | .data 6 | .global KERNEL_SP; 7 | KERNEL_SP: 8 | .word 0 9 | 10 | 11 | 12 | .text 13 | .set noreorder 14 | // .set noat 15 | LEAF(env_pop_tf) 16 | .set mips1 17 | //1: j 1b 18 | nop 19 | move k0,a0 20 | mtc0 a1,CP0_ENTRYHI 21 | 22 | 23 | mfc0 t0,CP0_STATUS 24 | ori t0,0x3 25 | xori t0,0x3 26 | mtc0 t0,CP0_STATUS 27 | 28 | lw v1,TF_LO(k0) 29 | mtlo v1 30 | lw v0,TF_HI(k0) 31 | lw v1,TF_EPC(k0) 32 | mthi v0 33 | mtc0 v1,CP0_EPC 34 | lw $31,TF_REG31(k0) 35 | lw $30,TF_REG30(k0) 36 | lw $29,TF_REG29(k0) 37 | lw $28,TF_REG28(k0) 38 | lw $25,TF_REG25(k0) 39 | lw $24,TF_REG24(k0) 40 | lw $23,TF_REG23(k0) 41 | lw $22,TF_REG22(k0) 42 | lw $21,TF_REG21(k0) 43 | lw $20,TF_REG20(k0) 44 | lw $19,TF_REG19(k0) 45 | lw $18,TF_REG18(k0) 46 | lw $17,TF_REG17(k0) 47 | lw $16,TF_REG16(k0) 48 | lw $15,TF_REG15(k0) 49 | lw $14,TF_REG14(k0) 50 | lw $13,TF_REG13(k0) 51 | lw $12,TF_REG12(k0) 52 | lw $11,TF_REG11(k0) 53 | lw $10,TF_REG10(k0) 54 | lw $9,TF_REG9(k0) 55 | lw $8,TF_REG8(k0) 56 | lw $7,TF_REG7(k0) 57 | lw $6,TF_REG6(k0) 58 | lw $5,TF_REG5(k0) 59 | lw $4,TF_REG4(k0) 60 | lw $3,TF_REG3(k0) 61 | lw $2,TF_REG2(k0) 62 | lw $1,TF_REG1(k0) 63 | 64 | lw k1,TF_PC(k0) 65 | 66 | lw k0,TF_STATUS(k0) 67 | nop 68 | mtc0 k0,CP0_STATUS 69 | 70 | 71 | 72 | j k1 73 | rfe 74 | nop 75 | 76 | 77 | END(env_pop_tf) 78 | 79 | LEAF(lcontext) 80 | .extern mCONTEXT 81 | sw a0,mCONTEXT 82 | jr ra 83 | nop 84 | END(lcontext) 85 | 86 | 87 | -------------------------------------------------------------------------------- /lib/genex.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | .macro __build_clear_sti 7 | STI 8 | .endm 9 | 10 | .macro __build_clear_cli 11 | CLI 12 | .endm 13 | 14 | .macro BUILD_HANDLER exception handler clear 15 | .align 5 16 | NESTED(handle_\exception, TF_SIZE, sp) 17 | //.set noat 18 | 19 | nop 20 | 21 | SAVE_ALL 22 | __build_clear_\clear 23 | .set at 24 | move a0, sp 25 | jal \handler 26 | nop 27 | j ret_from_exception 28 | nop 29 | END(handle_\exception) 30 | .endm 31 | 32 | FEXPORT(ret_from_exception) 33 | .set noat 34 | .set noreorder 35 | RESTORE_SOME 36 | .set at 37 | lw k0,TF_EPC(sp) 38 | lw sp,TF_REG29(sp) /* Deallocate stack */ 39 | //1: j 1b 40 | nop 41 | jr k0 42 | rfe 43 | 44 | 45 | 46 | .set noreorder 47 | .align 5 48 | NESTED(handle_int, TF_SIZE, sp) 49 | //.set noat 50 | 51 | //1: j 1b 52 | nop 53 | 54 | SAVE_ALL 55 | CLI 56 | .set at 57 | mfc0 t0, CP0_CAUSE 58 | mfc0 t2, CP0_STATUS 59 | and t0, t2 60 | 61 | andi t1, t0, STATUSF_IP4 62 | bnez t1, timer_irq 63 | nop 64 | END(handle_int) 65 | 66 | .extern delay 67 | 68 | timer_irq: 69 | 70 | 1: j sched_yield 71 | nop 72 | /*li t1, 0xff 73 | lw t0, delay 74 | addu t0, 1 75 | sw t0, delay 76 | beq t0,t1,1f 77 | nop*/ 78 | j ret_from_exception 79 | nop 80 | 81 | LEAF(do_reserved) 82 | END(do_reserved) 83 | 84 | .extern tlbra 85 | .set noreorder 86 | NESTED(do_refill,0 , sp) 87 | //li k1, '?' 88 | //sb k1, 0x90000000 89 | .extern mCONTEXT 90 | //this "1" is important 91 | 1: //j 1b 92 | nop 93 | lw k1,mCONTEXT 94 | and k1,0xfffff000 95 | mfc0 k0,CP0_BADVADDR 96 | srl k0,20 97 | and k0,0xfffffffc 98 | addu k0,k1 99 | 100 | lw k1,0(k0) 101 | nop 102 | move t0,k1 103 | and t0,0x0200 104 | beqz t0,NOPAGE 105 | nop 106 | and k1,0xfffff000 107 | mfc0 k0,CP0_BADVADDR 108 | srl k0,10 109 | and k0,0xfffffffc 110 | and k0,0x00000fff 111 | addu k0,k1 112 | 113 | or k0,0x80000000 114 | lw k1,0(k0) 115 | nop 116 | move t0,k1 117 | and t0,0x0200 118 | beqz t0,NOPAGE 119 | nop 120 | move k0,k1 121 | and k0,0x1 122 | beqz k0,NoCOW 123 | nop 124 | and k1,0xfffffbff 125 | NoCOW: 126 | mtc0 k1,CP0_ENTRYLO0 127 | nop 128 | tlbwr 129 | 130 | j 2f 131 | nop 132 | NOPAGE: 133 | //3: j 3b 134 | nop 135 | mfc0 a0,CP0_BADVADDR 136 | lw a1,mCONTEXT 137 | nop 138 | 139 | sw ra,tlbra 140 | jal pageout 141 | nop 142 | //3: j 3b 143 | nop 144 | lw ra,tlbra 145 | nop 146 | 147 | j 1b 148 | 2: nop 149 | 150 | jr ra 151 | nop 152 | END(do_refill) 153 | 154 | 155 | 156 | BUILD_HANDLER reserved do_reserved cli 157 | BUILD_HANDLER tlb do_refill cli 158 | BUILD_HANDLER mod page_fault_handler cli 159 | -------------------------------------------------------------------------------- /lib/getc.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | .set noreorder 6 | LEAF(sys_cgetc) 7 | 8 | lb t0, 0x90000000 9 | move v0,t0 10 | jr ra 11 | nop 12 | END(sys_cgetc) 13 | -------------------------------------------------------------------------------- /lib/kclock.c: -------------------------------------------------------------------------------- 1 | /* See COPYRIGHT for copyright information. */ 2 | 3 | /* The Run Time Clock and other NVRAM access functions that go with it. */ 4 | /* The run time clock is hard-wired to IRQ8. */ 5 | 6 | #include 7 | 8 | extern void set_timer(); 9 | 10 | void kclock_init(void) 11 | { 12 | set_timer(); 13 | } 14 | -------------------------------------------------------------------------------- /lib/kclock_asm.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | 8 | .macro setup_c0_status set clr 9 | .set push 10 | mfc0 t0, CP0_STATUS 11 | or t0, \set|\clr 12 | xor t0, \clr 13 | mtc0 t0, CP0_STATUS 14 | .set pop 15 | .endm 16 | 17 | .text 18 | LEAF(set_timer) 19 | 20 | li t0, 0x01 21 | sb t0, 0xb5000100 22 | sw sp, KERNEL_SP 23 | setup_c0_status STATUS_CU0|0x1001 0 24 | jr ra 25 | 26 | nop 27 | END(set_timer) 28 | -------------------------------------------------------------------------------- /lib/kernel_elfloader.c: -------------------------------------------------------------------------------- 1 | /* This is a simplefied ELF loader for kernel. 2 | * You can contact me if you find any bugs. 3 | * 4 | * Luming Wang 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | /* Overview: 12 | * Check whether it is a ELF file. 13 | * 14 | * Pre-Condition: 15 | * binary must longer than 4 byte. 16 | * 17 | * Post-Condition: 18 | * Return 0 if `binary` isn't an elf. Otherwise 19 | * return 1. 20 | */ 21 | int is_elf_format(u_char *binary) 22 | { 23 | Elf32_Ehdr *ehdr = (Elf32_Ehdr *)binary; 24 | 25 | if (ehdr->e_ident[0] == EI_MAG0 && 26 | ehdr->e_ident[1] == EI_MAG1 && 27 | ehdr->e_ident[2] == EI_MAG2 && 28 | ehdr->e_ident[3] == EI_MAG3) 29 | { 30 | return 0; 31 | } 32 | 33 | return 1; 34 | } 35 | 36 | /* Overview: 37 | * load an elf format binary file. Map all section 38 | * at correct virtual address. 39 | * 40 | * Pre-Condition: 41 | * `binary` can't be NULL and `size` is the size of binary. 42 | * 43 | * Post-Condition: 44 | * Return 0 if success. Otherwise return < 0. 45 | * If success, the entry point of `binary` will be stored in `start` 46 | */ 47 | /*** exercise 3.7 ***/ 48 | int load_elf(u_char *binary, int size, u_long *entry_point, void *user_data, 49 | int (*map)(u_long va, u_int32_t sgsize, 50 | u_char *bin, u_int32_t bin_size, void *user_data)) 51 | { 52 | Elf32_Ehdr *ehdr = (Elf32_Ehdr *)binary; 53 | Elf32_Phdr *phdr = NULL; 54 | /* As a loader, we just care about segment, 55 | * so we just parse program headers. 56 | */ 57 | u_char *ptr_ph_table = NULL; 58 | Elf32_Half ph_entry_count; 59 | Elf32_Half ph_entry_size; 60 | int r; 61 | 62 | // check whether `binary` is a ELF file. 63 | if (size < 4 || !is_elf_format(binary)) 64 | { 65 | return -1; 66 | } 67 | 68 | ptr_ph_table = binary + ehdr->e_phoff; 69 | ph_entry_count = ehdr->e_phnum; 70 | ph_entry_size = ehdr->e_phentsize; 71 | 72 | while (ph_entry_count--) 73 | { 74 | phdr = (Elf32_Phdr *)ptr_ph_table; 75 | 76 | if (phdr->p_type == PT_LOAD) 77 | { 78 | /* Your task here! */ 79 | /* Real map all section at correct virtual address.Return < 0 if error. */ 80 | /* Hint: Call the callback function you have achieved before. */ 81 | r = map(phdr->p_vaddr, phdr->p_memsz, binary + phdr->p_offset, phdr->p_filesz, user_data); 82 | if (r != 0) 83 | return r; 84 | } 85 | 86 | ptr_ph_table += ph_entry_size; 87 | } 88 | 89 | *entry_point = ehdr->e_entry; 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /lib/print.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2001 MontaVista Software Inc. 3 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License as published by the 7 | * Free Software Foundation; either version 2 of the License, or (at your 8 | * option) any later version. 9 | * 10 | */ 11 | 12 | #include 13 | 14 | /* macros */ 15 | #define IsDigit(x) (((x) >= '0') && ((x) <= '9')) 16 | #define Ctod(x) ((x) - '0') 17 | 18 | /* forward declaration */ 19 | extern int PrintChar(char *, char, int, int); 20 | extern int PrintString(char *, char *, int, int); 21 | extern int PrintNum(char *, unsigned long, int, int, int, int, char, int); 22 | 23 | /* private variable */ 24 | static const char theFatalMsg[] = "fatal error in lp_Print!"; 25 | 26 | /* -*- 27 | * A low level printf() function. 28 | */ 29 | void lp_Print(void (*output)(void *, char *, int), 30 | void *arg, 31 | char *fmt, 32 | va_list ap) 33 | { 34 | 35 | #define OUTPUT(arg, s, l) \ 36 | { \ 37 | if (((l) < 0) || ((l) > LP_MAX_BUF)) \ 38 | { \ 39 | (*output)(arg, (char *)theFatalMsg, sizeof(theFatalMsg) - 1); \ 40 | for (;;) \ 41 | ; \ 42 | } \ 43 | else \ 44 | { \ 45 | (*output)(arg, s, l); \ 46 | } \ 47 | } 48 | 49 | char buf[LP_MAX_BUF]; 50 | 51 | char c; 52 | char *s; 53 | long int num; 54 | 55 | int longFlag; 56 | int negFlag; 57 | int width; 58 | int prec; 59 | int ladjust; 60 | char padc; 61 | 62 | int length; 63 | 64 | /* 65 | Exercise 1.5. Please fill in two parts in this file. 66 | */ 67 | 68 | for (; *fmt;) 69 | { 70 | 71 | /* Part1: your code here */ 72 | if (*fmt != '%') 73 | { 74 | /* scan for the next '%' */ 75 | /* flush the string found so far */ 76 | length = PrintChar(buf, *fmt, 1, 0); 77 | OUTPUT(arg, buf, length); 78 | fmt++; 79 | /* check "are we hitting the end?" */ 80 | continue; 81 | } 82 | fmt++; 83 | /* we found a '%' */ 84 | ladjust = 0; 85 | padc = ' '; 86 | width = 0; 87 | prec = 0; 88 | negFlag = 0; 89 | longFlag = 0; 90 | if (*fmt == '-') 91 | { 92 | ladjust = 1; 93 | fmt++; 94 | } 95 | /* check for long */ 96 | if (*fmt == '0') 97 | { 98 | padc = '0'; 99 | fmt++; 100 | } 101 | /* check for other prefixes */ 102 | while (IsDigit(*fmt)) 103 | { 104 | width = width * 10 + (Ctod(*fmt)); 105 | fmt++; 106 | } 107 | /* check format flag */ 108 | if (*fmt == '.') 109 | { 110 | fmt++; 111 | prec = 0; 112 | while (IsDigit(*fmt)) 113 | { 114 | prec = prec * 10 + Ctod(*fmt); 115 | fmt++; 116 | } 117 | } 118 | else 119 | { 120 | prec = 6; 121 | } 122 | if (*fmt == 'l') 123 | { 124 | longFlag = 1; 125 | fmt++; 126 | } 127 | 128 | switch (*fmt) 129 | { 130 | case 'b': 131 | if (longFlag) 132 | { 133 | num = va_arg(ap, long int); 134 | } 135 | else 136 | { 137 | num = va_arg(ap, int); 138 | } 139 | length = PrintNum(buf, num, 2, 0, width, ladjust, padc, 0); 140 | OUTPUT(arg, buf, length); 141 | break; 142 | 143 | case 'd': 144 | case 'D': 145 | if (longFlag) 146 | { 147 | num = va_arg(ap, long int); 148 | } 149 | else 150 | { 151 | num = va_arg(ap, int); 152 | } 153 | 154 | /* Part2: 155 | your code here. 156 | Refer to other part (case 'b',case 'o' etc.) and func PrintNum to complete this part. 157 | Think the difference between case 'd' and others. (hint: negFlag). 158 | */ 159 | if (num < 0) 160 | { 161 | negFlag = 1; 162 | num = -num; 163 | } 164 | length = PrintNum(buf, num, 10, negFlag, width, ladjust, padc, 0); 165 | OUTPUT(arg, buf, length); 166 | break; 167 | case 'o': 168 | case 'O': 169 | if (longFlag) 170 | { 171 | num = va_arg(ap, long int); 172 | } 173 | else 174 | { 175 | num = va_arg(ap, int); 176 | } 177 | length = PrintNum(buf, num, 8, 0, width, ladjust, padc, 0); 178 | OUTPUT(arg, buf, length); 179 | break; 180 | 181 | case 'u': 182 | case 'U': 183 | if (longFlag) 184 | { 185 | num = va_arg(ap, long int); 186 | } 187 | else 188 | { 189 | num = va_arg(ap, int); 190 | } 191 | length = PrintNum(buf, num, 10, 0, width, ladjust, padc, 0); 192 | OUTPUT(arg, buf, length); 193 | break; 194 | 195 | case 'x': 196 | if (longFlag) 197 | { 198 | num = va_arg(ap, long int); 199 | } 200 | else 201 | { 202 | num = va_arg(ap, int); 203 | } 204 | length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 0); 205 | OUTPUT(arg, buf, length); 206 | break; 207 | 208 | case 'X': 209 | if (longFlag) 210 | { 211 | num = va_arg(ap, long int); 212 | } 213 | else 214 | { 215 | num = va_arg(ap, int); 216 | } 217 | length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 1); 218 | OUTPUT(arg, buf, length); 219 | break; 220 | 221 | case 'c': 222 | c = (char)va_arg(ap, int); 223 | length = PrintChar(buf, c, width, ladjust); 224 | OUTPUT(arg, buf, length); 225 | break; 226 | 227 | case 's': 228 | s = (char *)va_arg(ap, char *); 229 | length = PrintString(buf, s, width, ladjust); 230 | OUTPUT(arg, buf, length); 231 | break; 232 | 233 | case '\0': 234 | fmt--; 235 | break; 236 | 237 | default: 238 | /* output this char as it is */ 239 | OUTPUT(arg, fmt, 1); 240 | } /* switch (*fmt) */ 241 | 242 | fmt++; 243 | } /* for(;;) */ 244 | 245 | /* special termination call */ 246 | OUTPUT(arg, "\0", 1); 247 | } 248 | 249 | /* --------------- local help functions --------------------- */ 250 | int PrintChar(char *buf, char c, int length, int ladjust) 251 | { 252 | int i; 253 | 254 | if (length < 1) 255 | length = 1; 256 | if (ladjust) 257 | { 258 | *buf = c; 259 | for (i = 1; i < length; i++) 260 | buf[i] = ' '; 261 | } 262 | else 263 | { 264 | for (i = 0; i < length - 1; i++) 265 | buf[i] = ' '; 266 | buf[length - 1] = c; 267 | } 268 | return length; 269 | } 270 | 271 | int PrintString(char *buf, char *s, int length, int ladjust) 272 | { 273 | int i; 274 | int len = 0; 275 | char *s1 = s; 276 | while (*s1++) 277 | len++; 278 | if (length < len) 279 | length = len; 280 | 281 | if (ladjust) 282 | { 283 | for (i = 0; i < len; i++) 284 | buf[i] = s[i]; 285 | for (i = len; i < length; i++) 286 | buf[i] = ' '; 287 | } 288 | else 289 | { 290 | for (i = 0; i < length - len; i++) 291 | buf[i] = ' '; 292 | for (i = length - len; i < length; i++) 293 | buf[i] = s[i - length + len]; 294 | } 295 | return length; 296 | } 297 | 298 | int PrintNum(char *buf, unsigned long u, int base, int negFlag, 299 | int length, int ladjust, char padc, int upcase) 300 | { 301 | /* algorithm : 302 | * 1. prints the number from left to right in reverse form. 303 | * 2. fill the remaining spaces with padc if length is longer than 304 | * the actual length 305 | * TRICKY : if left adjusted, no "0" padding. 306 | * if negtive, insert "0" padding between "0" and number. 307 | * 3. if (!ladjust) we reverse the whole string including paddings 308 | * 4. otherwise we only reverse the actual string representing the num. 309 | */ 310 | 311 | int actualLength = 0; 312 | char *p = buf; 313 | int i; 314 | 315 | do 316 | { 317 | int tmp = u % base; 318 | if (tmp <= 9) 319 | { 320 | *p++ = '0' + tmp; 321 | } 322 | else if (upcase) 323 | { 324 | *p++ = 'A' + tmp - 10; 325 | } 326 | else 327 | { 328 | *p++ = 'a' + tmp - 10; 329 | } 330 | u /= base; 331 | } while (u != 0); 332 | 333 | if (negFlag) 334 | { 335 | *p++ = '-'; 336 | } 337 | 338 | /* figure out actual length and adjust the maximum length */ 339 | actualLength = p - buf; 340 | if (length < actualLength) 341 | length = actualLength; 342 | 343 | /* add padding */ 344 | if (ladjust) 345 | { 346 | padc = ' '; 347 | } 348 | if (negFlag && !ladjust && (padc == '0')) 349 | { 350 | for (i = actualLength - 1; i < length - 1; i++) 351 | buf[i] = padc; 352 | buf[length - 1] = '-'; 353 | } 354 | else 355 | { 356 | for (i = actualLength; i < length; i++) 357 | buf[i] = padc; 358 | } 359 | 360 | /* prepare to reverse the string */ 361 | { 362 | int begin = 0; 363 | int end; 364 | if (ladjust) 365 | { 366 | end = actualLength - 1; 367 | } 368 | else 369 | { 370 | end = length - 1; 371 | } 372 | 373 | while (end > begin) 374 | { 375 | char tmp = buf[begin]; 376 | buf[begin] = buf[end]; 377 | buf[end] = tmp; 378 | begin++; 379 | end--; 380 | } 381 | } 382 | 383 | /* adjust the string pointer */ 384 | return length; 385 | } 386 | -------------------------------------------------------------------------------- /lib/printf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2001 MontaVista Software Inc. 3 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License as published by the 7 | * Free Software Foundation; either version 2 of the License, or (at your 8 | * option) any later version. 9 | * 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | void printcharc(char ch); 17 | 18 | void halt(void); 19 | 20 | static void myoutput(void *arg, char *s, int l) 21 | { 22 | int i; 23 | 24 | // special termination call 25 | if ((l == 1) && (s[0] == '\0')) 26 | return; 27 | 28 | for (i = 0; i < l; i++) 29 | { 30 | printcharc(s[i]); 31 | // if (s[i] == '\n') printcharc('\n'); 32 | } 33 | } 34 | 35 | void printf(char *fmt, ...) 36 | { 37 | va_list ap; 38 | va_start(ap, fmt); 39 | lp_Print(myoutput, 0, fmt, ap); 40 | va_end(ap); 41 | } 42 | 43 | void _panic(const char *file, int line, const char *fmt, ...) 44 | { 45 | va_list ap; 46 | 47 | va_start(ap, fmt); 48 | printf("panic at %s:%d: ", file, line); 49 | lp_Print(myoutput, 0, (char *)fmt, ap); 50 | printf("\n"); 51 | va_end(ap); 52 | 53 | for (;;) 54 | ; 55 | } 56 | -------------------------------------------------------------------------------- /lib/sched.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* Overview: 6 | * Implement simple round-robin scheduling. 7 | * 8 | * 9 | * Hints: 10 | * 1. The variable which is for counting should be defined as 'static'. 11 | * 2. Use variable 'env_sched_list', which is a pointer array. 12 | * 3. CANNOT use `return` statement! 13 | */ 14 | /*** exercise 3.14 ***/ 15 | void sched_yield(void) 16 | { 17 | static int count = 0; // remaining time slices of current env 18 | static int point = 0; // current env_sched_list index 19 | static struct Env *e = NULL; 20 | /* hint: 21 | * 1. if (count==0), insert `e` into `env_sched_list[1-point]` 22 | * using LIST_REMOVE and LIST_INSERT_TAIL. 23 | * 2. if (env_sched_list[point] is empty), point = 1 - point; 24 | * then search through `env_sched_list[point]` for a runnable env `e`, 25 | * and set count = e->env_pri 26 | * 3. count-- 27 | * 4. env_run() 28 | * 29 | * functions or macros below may be used (not all): 30 | * LIST_INSERT_TAIL, LIST_REMOVE, LIST_FIRST, LIST_EMPTY 31 | */ 32 | if (count == 0 || e == NULL || e->env_status != ENV_RUNNABLE) 33 | { 34 | if (e != NULL) 35 | { 36 | LIST_REMOVE(e, env_sched_link); 37 | if (e->env_status != ENV_FREE) 38 | { 39 | LIST_INSERT_TAIL(&env_sched_list[1 - point], e, env_sched_link); 40 | } 41 | } 42 | while (1) 43 | { 44 | while (LIST_EMPTY(&env_sched_list[point])) 45 | point = 1 - point; 46 | e = LIST_FIRST(&env_sched_list[point]); 47 | if (e->env_status == ENV_FREE) 48 | LIST_REMOVE(e, env_sched_link); 49 | else if (e->env_status == ENV_NOT_RUNNABLE) 50 | { 51 | LIST_REMOVE(e, env_sched_link); 52 | LIST_INSERT_TAIL(&env_sched_list[1 - point], e, env_sched_link); 53 | } 54 | else 55 | { 56 | count = e->env_pri; 57 | break; 58 | } 59 | } 60 | } 61 | count--; 62 | e->env_runs++; 63 | env_run(e); 64 | // env_run(LIST_FIRST(env_sched_list)); 65 | } 66 | -------------------------------------------------------------------------------- /lib/syscall.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /*** exercise 4.2 ***/ 8 | NESTED(handle_sys,TF_SIZE, sp) 9 | SAVE_ALL // Macro used to save trapframe 10 | CLI // Clean Interrupt Mask 11 | nop 12 | .set at // Resume use of $at 13 | 14 | // TODO: Fetch EPC from Trapframe, calculate a proper value and store it back to trapframe. 15 | 16 | lw t0, TF_EPC(sp) 17 | addiu t0, t0, 4 18 | sw t0, TF_EPC(sp) 19 | // TODO: Copy the syscall number into $a0. 20 | 21 | lw a0, TF_REG4(sp) 22 | 23 | addiu a0, a0, -__SYSCALL_BASE // a0 <- relative syscall number 24 | sll t0, a0, 2 // t0 <- relative syscall number times 4 25 | la t1, sys_call_table // t1 <- syscall table base 26 | addu t1, t1, t0 // t1 <- table entry of specific syscall 27 | lw t2, 0(t1) // t2 <- function entry of specific syscall 28 | 29 | lw t0, TF_REG29(sp) // t0 <- user stack pointer 30 | lw t3, 16(t0) // t3 <- the 5th argument of msyscall 31 | lw t4, 20(t0) // t4 <- the 6th argument of msyscall 32 | 33 | // TODO: Allocate a space of six arguments on current kernel stack and copy the six arguments to proper location 34 | lw a0, TF_REG4(sp) 35 | lw a1, TF_REG5(sp) 36 | lw a2, TF_REG6(sp) 37 | lw a3, TF_REG7(sp) 38 | addiu sp, sp, -24 39 | sw a0, 0(sp) 40 | sw a1, 4(sp) 41 | sw a2, 8(sp) 42 | sw a3, 12(sp) 43 | sw t3, 16(sp) 44 | sw t4, 20(sp) 45 | 46 | jalr t2 // Invoke sys_* function 47 | nop 48 | 49 | // TODO: Resume current kernel stack 50 | addiu sp, sp, 24 51 | 52 | 53 | sw v0, TF_REG2(sp) // Store return value of function sys_* (in $v0) into trapframe 54 | 55 | j ret_from_exception // Return from exeception 56 | nop 57 | END(handle_sys) 58 | 59 | sys_call_table: // Syscall Table 60 | .align 2 61 | .word sys_putchar 62 | .word sys_getenvid 63 | .word sys_yield 64 | .word sys_env_destroy 65 | .word sys_set_pgfault_handler 66 | .word sys_mem_alloc 67 | .word sys_mem_map 68 | .word sys_mem_unmap 69 | .word sys_env_alloc 70 | .word sys_set_env_status 71 | .word sys_set_trapframe 72 | .word sys_panic 73 | .word sys_ipc_can_send 74 | .word sys_ipc_recv 75 | .word sys_cgetc 76 | .word sys_write_dev 77 | .word sys_read_dev 78 | .word sys_wait_cons 79 | .word sys_signal_cons 80 | .word sys_set_env 81 | .word sys_get_env 82 | .word sys_list_env_var 83 | -------------------------------------------------------------------------------- /lib/traps.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | extern void handle_int(); 6 | extern void handle_reserved(); 7 | extern void handle_tlb(); 8 | extern void handle_sys(); 9 | extern void handle_mod(); 10 | unsigned long exception_handlers[32]; 11 | 12 | void trap_init() 13 | { 14 | int i; 15 | 16 | for (i = 0; i < 32; i++) 17 | { 18 | set_except_vector(i, handle_reserved); 19 | } 20 | 21 | set_except_vector(0, handle_int); 22 | set_except_vector(1, handle_mod); 23 | set_except_vector(2, handle_tlb); 24 | set_except_vector(3, handle_tlb); 25 | set_except_vector(8, handle_sys); 26 | } 27 | void *set_except_vector(int n, void *addr) 28 | { 29 | unsigned long handler = (unsigned long)addr; 30 | unsigned long old_handler = exception_handlers[n]; 31 | exception_handlers[n] = handler; 32 | return (void *)old_handler; 33 | } 34 | 35 | struct pgfault_trap_frame 36 | { 37 | u_int fault_va; 38 | u_int err; 39 | u_int sp; 40 | u_int eflags; 41 | u_int pc; 42 | u_int empty1; 43 | u_int empty2; 44 | u_int empty3; 45 | u_int empty4; 46 | u_int empty5; 47 | }; 48 | 49 | /*** exercise 4.11 ***/ 50 | void page_fault_handler(struct Trapframe *tf) 51 | { 52 | struct Trapframe PgTrapFrame; 53 | extern struct Env *curenv; 54 | 55 | bcopy(tf, &PgTrapFrame, sizeof(struct Trapframe)); 56 | 57 | if (tf->regs[29] >= (curenv->env_xstacktop - BY2PG) && 58 | tf->regs[29] <= (curenv->env_xstacktop - 1)) 59 | { 60 | tf->regs[29] = tf->regs[29] - sizeof(struct Trapframe); 61 | bcopy(&PgTrapFrame, (void *)tf->regs[29], sizeof(struct Trapframe)); 62 | } 63 | else 64 | { 65 | tf->regs[29] = curenv->env_xstacktop - sizeof(struct Trapframe); 66 | bcopy(&PgTrapFrame, (void *)curenv->env_xstacktop - sizeof(struct Trapframe), sizeof(struct Trapframe)); 67 | } 68 | // TODO: Set EPC to a proper value in the trapframe 69 | tf->cp0_epc = curenv->env_pgfault_handler; 70 | return; 71 | } 72 | -------------------------------------------------------------------------------- /mm/Makefile: -------------------------------------------------------------------------------- 1 | INCLUDES := -I./ -I../ -I../include/ 2 | 3 | %.o: %.c 4 | $(CC) $(CFLAGS) $(INCLUDES) -c $< 5 | 6 | %.o: %.S 7 | $(CC) $(CFLAGS) $(INCLUDES) -c $< 8 | 9 | .PHONY: clean 10 | 11 | all: pmap.o tlb_asm.o 12 | 13 | clean: 14 | rm -rf *~ *.o 15 | 16 | 17 | include ../include.mk 18 | -------------------------------------------------------------------------------- /mm/pmap.all: -------------------------------------------------------------------------------- 1 | # 1 "pmap.c" 2 | # 1 "" 3 | # 1 "" 4 | # 1 "pmap.c" 5 | # 1 "mmu.h" 1 6 | 7 | 8 | 9 | # 1 "types.h" 1 10 | # 12 "types.h" 11 | typedef unsigned char u_int8_t; 12 | typedef short int16_t; 13 | typedef unsigned short u_int16_t; 14 | typedef int int32_t; 15 | typedef unsigned int u_int32_t; 16 | typedef long long int64_t; 17 | typedef unsigned long long u_int64_t; 18 | 19 | typedef int32_t register_t; 20 | 21 | typedef unsigned char u_char; 22 | typedef unsigned short u_short; 23 | typedef unsigned int u_int; 24 | typedef unsigned long u_long; 25 | 26 | typedef u_int64_t u_quad_t; 27 | typedef int64_t quad_t; 28 | typedef quad_t * qaddr_t; 29 | 30 | typedef u_int32_t size_t; 31 | # 5 "mmu.h" 2 32 | # 101 "mmu.h" 33 | void bcopy(const void *, void *, size_t); 34 | void bzero(void *, size_t); 35 | 36 | extern char bootstacktop[], bootstack[]; 37 | 38 | extern u_long npage; 39 | 40 | typedef u_long Pde; 41 | # 2 "pmap.c" 2 42 | # 1 "pmap.h" 1 43 | 44 | 45 | 46 | 47 | # 1 "queue.h" 1 48 | # 6 "pmap.h" 2 49 | 50 | 51 | struct Page_list { struct Page *lh_first; }; 52 | typedef struct { struct Page *le_next; struct Page **le_prev; } Page_LIST_entry_t; 53 | 54 | struct Page { 55 | Page_LIST_entry_t pp_link; 56 | 57 | 58 | 59 | 60 | 61 | 62 | u_short pp_ref; 63 | }; 64 | 65 | void i386_detect_memory(void); 66 | 67 | void mips_vm_init(); 68 | # 3 "pmap.c" 2 69 | # 1 "printf.h" 1 70 | # 15 "printf.h" 71 | # 1 "/usr/eldk/usr/bin/../lib/gcc/mips-linux/4.0.0/include/stdarg.h" 1 3 4 72 | # 43 "/usr/eldk/usr/bin/../lib/gcc/mips-linux/4.0.0/include/stdarg.h" 3 4 73 | typedef __builtin_va_list __gnuc_va_list; 74 | # 105 "/usr/eldk/usr/bin/../lib/gcc/mips-linux/4.0.0/include/stdarg.h" 3 4 75 | typedef __gnuc_va_list va_list; 76 | # 16 "printf.h" 2 77 | void printf(char *fmt, ...); 78 | 79 | void _panic(const char *, int, const char *, ...) 80 | __attribute__((noreturn)); 81 | # 4 "pmap.c" 2 82 | # 1 "env.h" 1 83 | # 19 "env.h" 84 | struct Env { 85 | 86 | struct { struct Env *le_next; struct Env **le_prev; } env_link; 87 | u_int env_id; 88 | u_int env_parent_id; 89 | u_int env_status; 90 | Pde *env_pgdir; 91 | u_int env_cr3; 92 | 93 | 94 | u_int env_ipc_value; 95 | u_int env_ipc_from; 96 | u_int env_ipc_recving; 97 | u_int env_ipc_dstva; 98 | u_int env_ipc_perm; 99 | 100 | 101 | u_int env_pgfault_handler; 102 | u_int env_xstacktop; 103 | 104 | 105 | u_int env_runs; 106 | }; 107 | # 5 "pmap.c" 2 108 | # 1 "error.h" 1 109 | # 6 "pmap.c" 2 110 | 111 | 112 | 113 | u_long maxpa; 114 | u_long npage; 115 | u_long basemem; 116 | u_long extmem; 117 | 118 | Pde* boot_pgdir; 119 | 120 | struct Page *pages; 121 | static u_long freemem; 122 | 123 | 124 | void mips_detect_memory() 125 | { 126 | 127 | basemem = 64*1024*1024; 128 | extmem = 0; 129 | maxpa = basemem; 130 | 131 | npage = maxpa / 4096; 132 | 133 | printf("Physical memory: %dK available, ", (int)(maxpa/1024)); 134 | printf("base = %dK, extended = %dK\n", (int)(basemem/1024), (int)(extmem/1024)); 135 | } 136 | 137 | static void * alloc(u_int n, u_int align, int clear) 138 | { 139 | extern char end[]; 140 | void *v; 141 | u_long alloced_mem; 142 | 143 | if (freemem == 0) 144 | freemem = (u_long)end; 145 | 146 | printf("pmap.c:\talloc from %x",freemem); 147 | 148 | 149 | freemem = (((((u_long)(freemem))+(align)-1)) & ~((align)-1)); 150 | 151 | alloced_mem = freemem; 152 | 153 | freemem = freemem + n; 154 | 155 | 156 | printf(" to %x\n",freemem); 157 | 158 | if (({ u_long a = (u_long) (freemem); if (a < 0x80000000) _panic("pmap.c", 54, "PADDR called with invalid kva %08lx", a); a - 0x80000000; }) >= maxpa) 159 | { 160 | _panic("pmap.c", 56, "out of memorty\n"); 161 | return -4; 162 | } 163 | 164 | if(clear) bzero(alloced_mem,n); 165 | 166 | return alloced_mem; 167 | 168 | } 169 | 170 | static Pde* boot_pgdir_walk(Pde *pgdir, u_long va, int create) 171 | { 172 | 173 | if(va>=0x80000000) _panic("pmap.c", 69, "mmu only working in low 2G space!\n"); 174 | 175 | printf("pmap.c:\tboot_pgdir_walk()\tva=%x\tpte=%x\n",va,(int)(&pgdir[((((u_long)(va))>>12) & 0x0FFFFF)*2])); 176 | 177 | return (Pde*)(&pgdir[((((u_long)(va))>>12) & 0x0FFFFF)*2]); 178 | } 179 | 180 | 181 | 182 | 183 | 184 | 185 | static void boot_map_segment(Pde *pgdir, u_long va, u_long size, u_long pa, int perm) 186 | { 187 | int i; 188 | int perm_p; 189 | u_long va_temp; 190 | Pde *pgtable_entry; 191 | 192 | if(size%4096!=0) _panic("pmap.c", 88, "size is not a multiple of BY2PG\n"); 193 | 194 | if(va>=0x80000000) _panic("pmap.c", 90, "mmu only working in low 2G space!\n"); 195 | 196 | perm_p = perm|0x002; 197 | 198 | for(i = 0;i < size;i+=4096) 199 | { 200 | va_temp = va+i; 201 | pgtable_entry = boot_pgdir_walk(pgdir, va_temp,1); 202 | *pgtable_entry = ((((u_long)(pa + i))>> 2) & 0x3FFFFFC0 )|perm_p; 203 | printf("pmap.c:\tmap()\tva=%x\tpa=%x\n",va_temp,pa+i); 204 | } 205 | 206 | return; 207 | } 208 | 209 | 210 | void mips_vm_init() 211 | { 212 | extern char KVPT[]; 213 | extern struct Env *envs; 214 | Pde* pgdir; 215 | u_int n; 216 | 217 | pgdir = (u_long *) KVPT; 218 | 219 | boot_pgdir=pgdir; 220 | printf("pmap.c:\tinit()\tKVPT:%x\n",(int)(&pgdir)); 221 | 222 | _panic("pmap.c", 118, "-------------------init not finish-------------"); 223 | 224 | pages = (struct Page*)alloc(npage*sizeof(struct Page),4096,1); 225 | n = (((((u_long)(npage * sizeof(struct Page)))+(4096)-1)) & ~((4096)-1)); 226 | boot_map_segment(pgdir,((0x80000000 - (4*1024*1024)) - (4*1024*1024)),n,({ u_long a = (u_long) (pages); if (a < 0x80000000) _panic("pmap.c", 122, "PADDR called with invalid kva %08lx", a); a - 0x80000000; }),0x018|0x004); 227 | 228 | 229 | envs = (struct Env*)alloc((1<<10)*sizeof(struct Env),4096,1); 230 | boot_map_segment(pgdir,(((0x80000000 - (4*1024*1024)) - (4*1024*1024)) - (4*1024*1024)),(1<<10)*sizeof(struct Env),({ u_long a = (u_long) (envs); if (a < 0x80000000) _panic("pmap.c", 126, "PADDR called with invalid kva %08lx", a); a - 0x80000000; }),0x018|0x004); 231 | 232 | } 233 | -------------------------------------------------------------------------------- /mm/tlb_asm.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | LEAF(tlb_out) 6 | //1: j 1b 7 | nop 8 | mfc0 k1,CP0_ENTRYHI 9 | mtc0 a0,CP0_ENTRYHI 10 | nop 11 | tlbp 12 | nop 13 | nop 14 | nop 15 | nop 16 | mfc0 k0,CP0_INDEX 17 | bltz k0,NOFOUND 18 | nop 19 | mtc0 zero,CP0_ENTRYHI 20 | mtc0 zero,CP0_ENTRYLO0 21 | nop 22 | tlbwi 23 | NOFOUND: 24 | 25 | mtc0 k1,CP0_ENTRYHI 26 | 27 | j ra 28 | nop 29 | END(tlb_out) 30 | -------------------------------------------------------------------------------- /tools/fsformat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coekjan/SOMOS/284bd72bfd7712697798a76eb30bda63c087eaab/tools/fsformat -------------------------------------------------------------------------------- /tools/scse0_3.lds: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(mips) 2 | ENTRY(_start) 3 | 4 | SECTIONS 5 | { 6 | . = 0x80000080; 7 | .except_vec3 : { 8 | *(.text.exc_vec3) 9 | } 10 | 11 | . = 0x80010000; 12 | 13 | /*** exercise 3.12 ***/ 14 | 15 | .text : { 16 | *(.text) 17 | } 18 | 19 | .bss : { 20 | *(.bss) 21 | } 22 | 23 | .data : { 24 | *(.data) 25 | } 26 | 27 | .sdata : { 28 | *(.sdata) 29 | } 30 | 31 | . = 0x80400000; 32 | 33 | end = . ; 34 | } 35 | -------------------------------------------------------------------------------- /tools/scse0_3.lds~: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(mips) 2 | ENTRY(_start) 3 | 4 | SECTIONS 5 | { 6 | . = 0x80000000; 7 | .interrupt1 : { 8 | *(.text.rftlb1) 9 | } 10 | 11 | . = 0x80000080; 12 | .interrupt2 : { 13 | *(.text.rftlb2) 14 | } 15 | 16 | . = 0x80010000; 17 | .text : { 18 | *(.text) 19 | *(.rodata) 20 | *(.rodata1) 21 | *(.rodata.str1.4) 22 | } 23 | 24 | .reginfo : { *(.reginfo) } 25 | 26 | .date : { 27 | *(.data) 28 | } 29 | 30 | .bss : { 31 | *(.dynbss) 32 | *(.bss) 33 | } 34 | 35 | . = 0x803F8000; 36 | .kernelstk : { 37 | *(.data.stk) 38 | } 39 | 40 | . = 0x80400000; 41 | KVPT = . ; 42 | .kernelvpt : { 43 | *(.data.vpt) 44 | } 45 | 46 | end = . ; 47 | } 48 | -------------------------------------------------------------------------------- /user/Makefile: -------------------------------------------------------------------------------- 1 | INCLUDES = -I../include/ 2 | 3 | #CROSS_COMPILE := /usr/eldk/usr/bin/mips_4KC- 4 | #CC := $(CROSS_COMPILE)gcc 5 | #CFLAGS := -O -G 0 -mno-abicalls -fno-builtin -Wa,-xgot -Wall -fPIC 6 | #LD := $(CROSS_COMPILE)ld 7 | # For embedding one program in another 8 | 9 | USERLIB := printf.o \ 10 | print.o \ 11 | libos.o \ 12 | fork.o \ 13 | pgfault.o \ 14 | syscall_lib.o \ 15 | ipc.o \ 16 | string.o \ 17 | fd.o \ 18 | pageref.o \ 19 | file.o \ 20 | pipe.o \ 21 | fsipc.o \ 22 | wait.o \ 23 | spawn.o \ 24 | console.o \ 25 | fprintf.o 26 | 27 | CFLAGS += -nostdlib -static 28 | 29 | 30 | all: pingpong.x echo.x echo.b num.x num.b idle.x icode.x init.b sh.b cat.b ls.b tree.x tree.b mkdir.x mkdir.b touch.x touch.b rm.x rm.b history.b history.x counter.x counter.b sum.x sum.b $(USERLIB) entry.o syscall_wrap.o 31 | 32 | %.x: %.b.c 33 | echo cc1 $< 34 | $(CC) $(CFLAGS) -c -o $@ $< 35 | 36 | %.b.c: %.b 37 | echo create $@ 38 | echo bintoc $* $< > $@~ 39 | chmod +x ./bintoc 40 | ./bintoc $* $< > $@~ && mv -f $@~ $@ 41 | # grep \. $@ 42 | 43 | %.b: entry.o syscall_wrap.o %.o $(USERLIB) 44 | echo ld $@ 45 | $(LD) -o $@ $(LDFLAGS) -G 0 -static -n -nostdlib -T ./user.lds $^ 46 | 47 | %.o: %.c 48 | echo user1 cc $< 49 | $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< 50 | 51 | %.o: %.S 52 | echo as $< 53 | $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< 54 | 55 | %.o: lib.h 56 | 57 | .PHONY: clean 58 | 59 | clean: 60 | rm -rf *~ *.o *.b.c *.x *.b 61 | 62 | include ../include.mk 63 | -------------------------------------------------------------------------------- /user/bintoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coekjan/SOMOS/284bd72bfd7712697798a76eb30bda63c087eaab/user/bintoc -------------------------------------------------------------------------------- /user/cat.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | char buf[8192]; 4 | 5 | void cat(int f, char *s) 6 | { 7 | long n; 8 | int r; 9 | 10 | while ((n = read(f, buf, (long)sizeof buf)) > 0) 11 | if ((r = write(1, buf, n)) != n) 12 | user_panic("write error copying %s: %e", s, r); 13 | if (n < 0) 14 | user_panic("error reading %s: %e", s, n); 15 | } 16 | 17 | void umain(int argc, char **argv) 18 | { 19 | int f, i; 20 | struct Stat st; 21 | if (argc == 1) 22 | cat(0, ""); 23 | else 24 | for (i = 1; i < argc; i++) 25 | { 26 | if (stat(argv[i], &st) < 0) 27 | { 28 | writef("cannot open file: %s\n", argv[i]); 29 | continue; 30 | } 31 | else if (st.st_type != FTYPE_REG) 32 | { 33 | writef("specified path should be file\n"); 34 | continue; 35 | } 36 | f = open(argv[i], O_RDONLY); 37 | cat(f, argv[i]); 38 | close(f); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /user/clear.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | void umain(int argc, char **argv) 4 | { 5 | if (argc != 1) 6 | { 7 | fwritef(1, "usage: clear\n"); 8 | return; 9 | } 10 | fwritef(1, "\x1b[2J\x1b[H"); 11 | } 12 | -------------------------------------------------------------------------------- /user/console.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #include 3 | 4 | static int cons_read(struct Fd *, void *, u_int, u_int); 5 | static int cons_write(struct Fd *, const void *, u_int, u_int); 6 | static int cons_close(struct Fd *); 7 | static int cons_stat(struct Fd *, struct Stat *); 8 | 9 | struct Dev devcons = 10 | { 11 | .dev_id = 'c', 12 | .dev_name = "cons", 13 | .dev_read = cons_read, 14 | .dev_write = cons_write, 15 | .dev_close = cons_close, 16 | .dev_stat = cons_stat, 17 | }; 18 | 19 | int iscons(int fdnum) 20 | { 21 | int r; 22 | struct Fd *fd; 23 | 24 | if ((r = fd_lookup(fdnum, &fd)) < 0) 25 | return r; 26 | return fd->fd_dev_id == devcons.dev_id; 27 | } 28 | 29 | int opencons(void) 30 | { 31 | int r; 32 | struct Fd *fd; 33 | 34 | if ((r = fd_alloc(&fd)) < 0) 35 | return r; 36 | if ((r = syscall_mem_alloc(0, (u_int)fd, PTE_V | PTE_R | PTE_LIBRARY)) < 0) 37 | return r; 38 | fd->fd_dev_id = devcons.dev_id; 39 | fd->fd_omode = O_RDWR; 40 | return fd2num(fd); 41 | } 42 | 43 | int cons_read(struct Fd *fd, void *vbuf, u_int n, u_int offset) 44 | { 45 | int c; 46 | 47 | USED(offset); 48 | // printf("got into cons_read"); 49 | if (n == 0) 50 | return 0; 51 | 52 | while ((c = syscall_cgetc()) == 0) 53 | syscall_yield(); 54 | 55 | if (c != '\r') 56 | { 57 | writef("%c", c); 58 | } 59 | else 60 | writef("\n"); 61 | if (c < 0) 62 | return c; 63 | if (c == 0x04) // ctl-d is eof 64 | return 0; 65 | *(char *)vbuf = c; 66 | return 1; 67 | } 68 | 69 | int cons_write(struct Fd *fd, const void *vbuf, u_int n, u_int offset) 70 | { 71 | int tot, m; 72 | char buf[128]; 73 | 74 | USED(offset); 75 | 76 | // mistake: have to nul-terminate arg to syscall_cputs, 77 | // so we have to copy vbuf into buf in chunks and nul-terminate. 78 | for (tot = 0; tot < n; tot += m) 79 | { 80 | m = n - tot; 81 | if (m > sizeof buf - 1) 82 | m = sizeof buf - 1; 83 | user_bcopy((char *)vbuf + tot, buf, m); 84 | buf[m] = 0; 85 | writef("%s", buf); 86 | } 87 | return tot; 88 | } 89 | 90 | int cons_close(struct Fd *fd) 91 | { 92 | USED(fd); 93 | 94 | return 0; 95 | } 96 | 97 | int cons_stat(struct Fd *fd, struct Stat *stat) 98 | { 99 | strcpy(stat->st_name, ""); 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /user/counter.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int get_num(char *src) 4 | { 5 | int num = 0; 6 | while (*src) 7 | num = (num << 1) + (num << 3) + (*src++ - '0'); 8 | return num; 9 | } 10 | 11 | void umain(int argc, char **argv) 12 | { 13 | int i; 14 | int max = 200000000; 15 | if (argc == 2) 16 | { 17 | max = get_num(argv[1]); 18 | } 19 | else if (argc > 2) 20 | { 21 | fwritef(1, "usage: counter [num]\n"); 22 | return; 23 | } 24 | for (i = 0; i < max; ++i) 25 | { 26 | } 27 | fwritef(1, "Done: loop %d times\n", max); 28 | } 29 | -------------------------------------------------------------------------------- /user/echo.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | void umain(int argc, char **argv) 4 | { 5 | int i, nflag; 6 | 7 | nflag = 0; 8 | if (argc > 1 && strcmp(argv[1], "-n") == 0) 9 | { 10 | nflag = 1; 11 | argc--; 12 | argv++; 13 | } 14 | for (i = 1; i < argc; i++) 15 | { 16 | if (i > 1) 17 | write(1, " ", 1); 18 | write(1, argv[i], strlen(argv[i])); 19 | } 20 | // if (!nflag) 21 | // write(1, "\n", 1); 22 | } 23 | -------------------------------------------------------------------------------- /user/entry.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | .data 7 | 8 | .p2align 12 9 | 10 | .globl fsipcbuf 11 | fsipcbuf: 12 | .space BY2PG 13 | .globl fdtab 14 | fdtab: 15 | .space BY2PG 16 | 17 | 18 | .globl envs 19 | envs: 20 | .word UENVS 21 | 22 | .globl pages 23 | pages: 24 | .word UPAGES 25 | 26 | .globl vpt 27 | vpt: 28 | .word UVPT 29 | 30 | .globl vpd 31 | vpd: 32 | .word (UVPT+(UVPT>>12)*4) 33 | 34 | .globl __pgfault_handler 35 | __pgfault_handler: 36 | .word 0 37 | 38 | 39 | .extern libmain 40 | 41 | .text 42 | .globl _start 43 | _start: 44 | //1: j 1b 45 | lw a0, 0(sp) 46 | lw a1, 4(sp) 47 | //sw a0, -4(sp) 48 | //sw a1, -0(sp) 49 | nop 50 | jal libmain 51 | nop 52 | 53 | .set noreorder 54 | .text 55 | .globl __asm_pgfault_handler 56 | __asm_pgfault_handler: 57 | // save the caller-save registers 58 | // (your code here) 59 | //1: j 1b 60 | nop 61 | lw a0, TF_BADVADDR(sp) 62 | //sw t0, (sp) 63 | //subu sp,16 64 | lw t1, __pgfault_handler 65 | jalr t1 66 | 67 | nop 68 | // push trap-time eip, eflags onto trap-time stack 69 | // (your code here) 70 | //addu sp,16 71 | lw v1,TF_LO(sp) 72 | mtlo v1 73 | lw v0,TF_HI(sp) 74 | lw v1,TF_EPC(sp) 75 | mthi v0 76 | mtc0 v1,CP0_EPC 77 | lw $31,TF_REG31(sp) 78 | lw $30,TF_REG30(sp) 79 | lw $28,TF_REG28(sp) 80 | lw $25,TF_REG25(sp) 81 | lw $24,TF_REG24(sp) 82 | lw $23,TF_REG23(sp) 83 | lw $22,TF_REG22(sp) 84 | lw $21,TF_REG21(sp) 85 | lw $20,TF_REG20(sp) 86 | lw $19,TF_REG19(sp) 87 | lw $18,TF_REG18(sp) 88 | lw $17,TF_REG17(sp) 89 | lw $16,TF_REG16(sp) 90 | lw $15,TF_REG15(sp) 91 | lw $14,TF_REG14(sp) 92 | lw $13,TF_REG13(sp) 93 | lw $12,TF_REG12(sp) 94 | lw $11,TF_REG11(sp) 95 | lw $10,TF_REG10(sp) 96 | lw $9,TF_REG9(sp) 97 | lw $8,TF_REG8(sp) 98 | lw $7,TF_REG7(sp) 99 | lw $6,TF_REG6(sp) 100 | lw $5,TF_REG5(sp) 101 | lw $4,TF_REG4(sp) 102 | lw $3,TF_REG3(sp) 103 | lw $2,TF_REG2(sp) 104 | lw $1,TF_REG1(sp) 105 | lw k0,TF_EPC(sp) //atomic operation needed 106 | jr k0 // 107 | lw sp,TF_REG29(sp) /* Deallocate stack */ 108 | 109 | -------------------------------------------------------------------------------- /user/fd.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #include "fd.h" 3 | #include 4 | #include 5 | 6 | static struct Dev *devtab[] = { 7 | &devfile, 8 | &devcons, 9 | &devpipe, 10 | 0}; 11 | 12 | int dev_lookup(int dev_id, struct Dev **dev) 13 | { 14 | int i; 15 | 16 | for (i = 0; devtab[i]; i++) 17 | if (devtab[i]->dev_id == dev_id) 18 | { 19 | *dev = devtab[i]; 20 | return 0; 21 | } 22 | 23 | writef("[%08x] unknown device type %d\n", env->env_id, dev_id); 24 | return -E_INVAL; 25 | } 26 | 27 | int fd_alloc(struct Fd **fd) 28 | { 29 | // Find the smallest i from 0 to MAXFD-1 that doesn't have 30 | // its fd page mapped. Set *fd to the fd page virtual address. 31 | // (Do not allocate a page. It is up to the caller to allocate 32 | // the page. This means that if someone calls fd_alloc twice 33 | // in a row without allocating the first page we return, we'll 34 | // return the same page the second time.) 35 | // Return 0 on success, or an error code on error. 36 | u_int va; 37 | u_int fdno; 38 | 39 | for (fdno = 0; fdno < MAXFD - 1; fdno++) 40 | { 41 | va = INDEX2FD(fdno); 42 | 43 | if (((*vpd)[va / PDMAP] & PTE_V) == 0) 44 | { 45 | *fd = (struct Fd *)va; 46 | return 0; 47 | } 48 | 49 | if (((*vpt)[va / BY2PG] & PTE_V) == 0) 50 | { //the fd is not used 51 | *fd = (struct Fd *)va; 52 | return 0; 53 | } 54 | } 55 | 56 | return -E_MAX_OPEN; 57 | } 58 | 59 | void fd_close(struct Fd *fd) 60 | { 61 | syscall_mem_unmap(0, (u_int)fd); 62 | } 63 | 64 | int fd_lookup(int fdnum, struct Fd **fd) 65 | { 66 | // Check that fdnum is in range and mapped. If not, return -E_INVAL. 67 | // Set *fd to the fd page virtual address. Return 0. 68 | u_int va; 69 | 70 | if (fdnum >= MAXFD) 71 | { 72 | return -E_INVAL; 73 | } 74 | 75 | va = INDEX2FD(fdnum); 76 | 77 | if (((*vpt)[va / BY2PG] & PTE_V) != 0) 78 | { //the fd is used 79 | *fd = (struct Fd *)va; 80 | return 0; 81 | } 82 | 83 | return -E_INVAL; 84 | } 85 | 86 | u_int fd2data(struct Fd *fd) 87 | { 88 | return INDEX2DATA(fd2num(fd)); 89 | } 90 | 91 | int fd2num(struct Fd *fd) 92 | { 93 | return ((u_int)fd - FDTABLE) / BY2PG; 94 | } 95 | 96 | int num2fd(int fd) 97 | { 98 | return fd * BY2PG + FDTABLE; 99 | } 100 | 101 | int close(int fdnum) 102 | { 103 | int r; 104 | struct Dev *dev; 105 | struct Fd *fd; 106 | 107 | if ((r = fd_lookup(fdnum, &fd)) < 0 || (r = dev_lookup(fd->fd_dev_id, &dev)) < 0) 108 | { 109 | return r; 110 | } 111 | 112 | r = (*dev->dev_close)(fd); 113 | fd_close(fd); 114 | return r; 115 | } 116 | 117 | void close_all(void) 118 | { 119 | int i; 120 | 121 | for (i = 0; i < MAXFD; i++) 122 | { 123 | close(i); 124 | } 125 | } 126 | 127 | int dup(int oldfdnum, int newfdnum) 128 | { 129 | int i, r; 130 | u_int ova, nva, pte; 131 | struct Fd *oldfd, *newfd; 132 | 133 | if ((r = fd_lookup(oldfdnum, &oldfd)) < 0) 134 | { 135 | return r; 136 | } 137 | 138 | close(newfdnum); 139 | newfd = (struct Fd *)INDEX2FD(newfdnum); 140 | ova = fd2data(oldfd); 141 | nva = fd2data(newfd); 142 | 143 | if ((*vpd)[PDX(ova)]) 144 | { 145 | for (i = 0; i < PDMAP; i += BY2PG) 146 | { 147 | pte = (*vpt)[VPN(ova + i)]; 148 | 149 | if (pte & PTE_V) 150 | { 151 | // should be no error here -- pd is already allocated 152 | if ((r = syscall_mem_map(0, ova + i, 0, nva + i, 153 | pte & (PTE_V | PTE_R | PTE_LIBRARY))) < 0) 154 | { 155 | goto err; 156 | } 157 | } 158 | } 159 | } 160 | 161 | if ((r = syscall_mem_map(0, (u_int)oldfd, 0, (u_int)newfd, 162 | ((*vpt)[VPN(oldfd)]) & (PTE_V | PTE_R | PTE_LIBRARY))) < 0) 163 | { 164 | goto err; 165 | } 166 | return newfdnum; 167 | 168 | err: 169 | syscall_mem_unmap(0, (u_int)newfd); 170 | 171 | for (i = 0; i < PDMAP; i += BY2PG) 172 | { 173 | syscall_mem_unmap(0, nva + i); 174 | } 175 | 176 | return r; 177 | } 178 | 179 | // Overview: 180 | // Read 'n' bytes from 'fd' at the current seek position into 'buf'. 181 | // 182 | // Post-Condition: 183 | // Update seek position. 184 | // Return the number of bytes read successfully. 185 | // < 0 on error 186 | int read(int fdnum, void *buf, u_int n) 187 | { 188 | int r; 189 | struct Dev *dev; 190 | struct Fd *fd; 191 | 192 | // Similar to 'write' function. 193 | // Step 1: Get fd and dev. 194 | 195 | if ((r = fd_lookup(fdnum, &fd)) < 0 || (r = dev_lookup(fd->fd_dev_id, &dev)) < 0) 196 | { 197 | return r; 198 | } 199 | 200 | if ((fd->fd_omode & O_ACCMODE) == O_WRONLY) 201 | { 202 | writef("[%08x] read %d -- bad mode\n", env->env_id, fdnum); 203 | return -E_INVAL; 204 | } 205 | 206 | if (debug) 207 | writef("read %d %p %d via dev %s\n", 208 | fdnum, buf, n, dev->dev_name); 209 | 210 | r = (*dev->dev_read)(fd, buf, n, fd->fd_offset); 211 | 212 | if (r > 0) 213 | { 214 | fd->fd_offset += r; 215 | } 216 | 217 | ((char *)buf)[r] = '\0'; 218 | 219 | return r; 220 | } 221 | 222 | int readn(int fdnum, void *buf, u_int n) 223 | { 224 | int m, tot; 225 | 226 | for (tot = 0; tot < n; tot += m) 227 | { 228 | m = read(fdnum, (char *)buf + tot, n - tot); 229 | 230 | if (m < 0) 231 | { 232 | return m; 233 | } 234 | 235 | if (m == 0) 236 | { 237 | break; 238 | } 239 | } 240 | 241 | return tot; 242 | } 243 | 244 | int write(int fdnum, const void *buf, u_int n) 245 | { 246 | int r; 247 | struct Dev *dev; 248 | struct Fd *fd; 249 | 250 | if ((r = fd_lookup(fdnum, &fd)) < 0 || (r = dev_lookup(fd->fd_dev_id, &dev)) < 0) 251 | { 252 | return r; 253 | } 254 | 255 | if ((fd->fd_omode & O_ACCMODE) == O_RDONLY) 256 | { 257 | writef("[%08x] write %d -- bad mode\n", env->env_id, fdnum); 258 | return -E_INVAL; 259 | } 260 | 261 | if (debug) 262 | writef("write %d %p %d via dev %s\n", 263 | fdnum, buf, n, dev->dev_name); 264 | 265 | r = (*dev->dev_write)(fd, buf, n, fd->fd_offset); 266 | 267 | if (r > 0) 268 | { 269 | fd->fd_offset += r; 270 | } 271 | 272 | return r; 273 | } 274 | 275 | int seek(int fdnum, u_int offset) 276 | { 277 | int r; 278 | struct Fd *fd; 279 | 280 | if ((r = fd_lookup(fdnum, &fd)) < 0) 281 | { 282 | return r; 283 | } 284 | 285 | fd->fd_offset = offset; 286 | return 0; 287 | } 288 | 289 | int fstat(int fdnum, struct Stat *stat) 290 | { 291 | int r; 292 | struct Dev *dev; 293 | struct Fd *fd; 294 | 295 | if ((r = fd_lookup(fdnum, &fd)) < 0 || (r = dev_lookup(fd->fd_dev_id, &dev)) < 0) 296 | { 297 | return r; 298 | } 299 | 300 | stat->st_name[0] = 0; 301 | stat->st_size = 0; 302 | stat->st_type = FTYPE_REG; 303 | stat->st_dev = dev; 304 | return (*dev->dev_stat)(fd, stat); 305 | } 306 | 307 | int stat(const char *path, struct Stat *stat) 308 | { 309 | int fd, r; 310 | 311 | if ((fd = open(path, O_RDONLY)) < 0) 312 | { 313 | return fd; 314 | } 315 | 316 | r = fstat(fd, stat); 317 | close(fd); 318 | return r; 319 | } 320 | -------------------------------------------------------------------------------- /user/fd.h: -------------------------------------------------------------------------------- 1 | #ifndef _USER_FD_H_ 2 | #define _USER_FD_H_ 1 3 | 4 | #include 5 | #include 6 | 7 | // pre-declare for forward references 8 | struct Fd; 9 | struct Stat; 10 | struct Dev; 11 | 12 | struct Dev 13 | { 14 | int dev_id; 15 | char *dev_name; 16 | int (*dev_read)(struct Fd *, void *, u_int, u_int); 17 | int (*dev_write)(struct Fd *, const void *, u_int, u_int); 18 | int (*dev_close)(struct Fd *); 19 | int (*dev_stat)(struct Fd *, struct Stat *); 20 | int (*dev_seek)(struct Fd *, u_int); 21 | }; 22 | 23 | struct Fd 24 | { 25 | u_int fd_dev_id; 26 | u_int fd_offset; 27 | u_int fd_omode; 28 | }; 29 | 30 | struct Stat 31 | { 32 | char st_name[MAXNAMELEN]; 33 | u_int st_size; 34 | u_int st_type; 35 | struct Dev *st_dev; 36 | }; 37 | 38 | struct Filefd 39 | { 40 | struct Fd f_fd; 41 | u_int f_fileid; 42 | struct File f_file; 43 | }; 44 | 45 | int fd_alloc(struct Fd **fd); 46 | int fd_lookup(int fdnum, struct Fd **fd); 47 | u_int fd2data(struct Fd *); 48 | int fd2num(struct Fd *); 49 | int dev_lookup(int dev_id, struct Dev **dev); 50 | int num2fd(int fd); 51 | extern struct Dev devcons; 52 | extern struct Dev devfile; 53 | extern struct Dev devpipe; 54 | #define debug 0 55 | 56 | #define MAXFD 32 57 | #define FILEBASE 0x60000000 58 | #define FDTABLE (FILEBASE - PDMAP) 59 | 60 | #define INDEX2FD(i) (FDTABLE + (i)*BY2PG) 61 | #define INDEX2DATA(i) (FILEBASE + (i)*PDMAP) 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /user/file.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #include 3 | 4 | #define debug 0 5 | 6 | static int file_close(struct Fd *fd); 7 | static int file_read(struct Fd *fd, void *buf, u_int n, u_int offset); 8 | static int file_write(struct Fd *fd, const void *buf, u_int n, u_int offset); 9 | static int file_stat(struct Fd *fd, struct Stat *stat); 10 | 11 | // Dot represents choosing the variable of the same name within struct declaration 12 | // to assign, and no need to consider order of variables. 13 | struct Dev devfile = 14 | { 15 | .dev_id = 'f', 16 | .dev_name = "file", 17 | .dev_read = file_read, 18 | .dev_write = file_write, 19 | .dev_close = file_close, 20 | .dev_stat = file_stat, 21 | }; 22 | 23 | // Overview: 24 | // Open a file (or directory). 25 | // 26 | // Returns: 27 | // the file descriptor onsuccess, 28 | // < 0 on failure. 29 | int open(const char *path, int mode) 30 | { 31 | struct Fd *fd; 32 | struct Filefd *ffd; 33 | u_int size, fileid; 34 | int r; 35 | u_int va; 36 | u_int i; 37 | 38 | // Step 1: Alloc a new Fd, return error code when fail to alloc. 39 | // Hint: Please use fd_alloc. 40 | r = fd_alloc(&fd); 41 | if (r) 42 | return r; 43 | 44 | // Step 2: Get the file descriptor of the file to open. 45 | // Hint: Read fsipc.c, and choose a function. 46 | r = fsipc_open(path, mode, fd); 47 | if (r) 48 | return r; 49 | 50 | // Step 3: Set the start address storing the file's content. Set size and fileid correctly. 51 | // Hint: Use fd2data to get the start address. 52 | va = fd2data(fd); 53 | 54 | // Step 4: Alloc memory, map the file content into memory. 55 | ffd = fd; 56 | size = ffd->f_file.f_size; 57 | fileid = ffd->f_fileid; 58 | // Step 5: Return the number of file descriptor. 59 | for (i = 0; i < size; i += BY2PG) 60 | { 61 | r = syscall_mem_alloc(0, va + i, PTE_R | PTE_V); 62 | if (r) 63 | return r; 64 | r = fsipc_map(fileid, i, va + i); 65 | if (r) 66 | return r; 67 | } 68 | int fdnum = fd2num(fd); 69 | if (mode & O_APPND) 70 | seek(fdnum, size); 71 | return fdnum; 72 | } 73 | 74 | int create(const char *path, int type) 75 | { 76 | return fsipc_create(path, type); 77 | } 78 | 79 | // Overview: 80 | // Close a file descriptor 81 | int file_close(struct Fd *fd) 82 | { 83 | int r; 84 | struct Filefd *ffd; 85 | u_int va, size, fileid; 86 | u_int i; 87 | 88 | ffd = (struct Filefd *)fd; 89 | fileid = ffd->f_fileid; 90 | size = ffd->f_file.f_size; 91 | 92 | // Set the start address storing the file's content. 93 | va = fd2data(fd); 94 | 95 | // Tell the file server the dirty page. 96 | for (i = 0; i < size; i += BY2PG) 97 | { 98 | fsipc_dirty(fileid, i); 99 | } 100 | 101 | // Request the file server to close the file with fsipc. 102 | if ((r = fsipc_close(fileid)) < 0) 103 | { 104 | writef("cannot close the file\n"); 105 | return r; 106 | } 107 | 108 | // Unmap the content of file, release memory. 109 | if (size == 0) 110 | { 111 | return 0; 112 | } 113 | for (i = 0; i < size; i += BY2PG) 114 | { 115 | if ((r = syscall_mem_unmap(0, va + i)) < 0) 116 | { 117 | writef("cannont unmap the file.\n"); 118 | return r; 119 | } 120 | } 121 | return 0; 122 | } 123 | 124 | // Overview: 125 | // Read 'n' bytes from 'fd' at the current seek position into 'buf'. Since files 126 | // are memory-mapped, this amounts to a user_bcopy() surrounded by a little red 127 | // tape to handle the file size and seek pointer. 128 | static int 129 | file_read(struct Fd *fd, void *buf, u_int n, u_int offset) 130 | { 131 | u_int size; 132 | struct Filefd *f; 133 | f = (struct Filefd *)fd; 134 | 135 | // Avoid reading past the end of file. 136 | size = f->f_file.f_size; 137 | 138 | if (offset > size) 139 | { 140 | return 0; 141 | } 142 | 143 | if (offset + n > size) 144 | { 145 | n = size - offset; 146 | } 147 | 148 | user_bcopy((char *)fd2data(fd) + offset, buf, n); 149 | return n; 150 | } 151 | 152 | // Overview: 153 | // Find the virtual address of the page that maps the file block 154 | // starting at 'offset'. 155 | int read_map(int fdnum, u_int offset, void **blk) 156 | { 157 | int r; 158 | u_int va; 159 | struct Fd *fd; 160 | 161 | if ((r = fd_lookup(fdnum, &fd)) < 0) 162 | { 163 | return r; 164 | } 165 | 166 | if (fd->fd_dev_id != devfile.dev_id) 167 | { 168 | return -E_INVAL; 169 | } 170 | 171 | va = fd2data(fd) + offset; 172 | 173 | if (offset >= MAXFILESIZE) 174 | { 175 | return -E_NO_DISK; 176 | } 177 | 178 | if (!((*vpd)[PDX(va)] & PTE_V) || !((*vpt)[VPN(va)] & PTE_V)) 179 | { 180 | return -E_NO_DISK; 181 | } 182 | 183 | *blk = (void *)va; 184 | return 0; 185 | } 186 | 187 | // Overview: 188 | // Write 'n' bytes from 'buf' to 'fd' at the current seek position. 189 | static int 190 | file_write(struct Fd *fd, const void *buf, u_int n, u_int offset) 191 | { 192 | int r; 193 | u_int tot; 194 | struct Filefd *f; 195 | 196 | f = (struct Filefd *)fd; 197 | 198 | // Don't write more than the maximum file size. 199 | tot = offset + n; 200 | 201 | if (tot > MAXFILESIZE) 202 | { 203 | return -E_NO_DISK; 204 | } 205 | 206 | // Increase the file's size if necessary 207 | if (tot != f->f_file.f_size) 208 | { 209 | if ((r = ftruncate(fd2num(fd), tot)) < 0) 210 | { 211 | return r; 212 | } 213 | } 214 | // Write the data 215 | user_bcopy(buf, (char *)fd2data(fd) + offset, n); 216 | return n; 217 | } 218 | 219 | static int 220 | file_stat(struct Fd *fd, struct Stat *st) 221 | { 222 | struct Filefd *f; 223 | 224 | f = (struct Filefd *)fd; 225 | 226 | strcpy(st->st_name, (char *)f->f_file.f_name); 227 | st->st_size = f->f_file.f_size; 228 | st->st_type = f->f_file.f_type; 229 | return 0; 230 | } 231 | 232 | // Overview: 233 | // Truncate or extend an open file to 'size' bytes 234 | int ftruncate(int fdnum, u_int size) 235 | { 236 | int i, r; 237 | struct Fd *fd; 238 | struct Filefd *f; 239 | u_int oldsize, va, fileid; 240 | 241 | if (size > MAXFILESIZE) 242 | { 243 | return -E_NO_DISK; 244 | } 245 | 246 | if ((r = fd_lookup(fdnum, &fd)) < 0) 247 | { 248 | return r; 249 | } 250 | 251 | if (fd->fd_dev_id != devfile.dev_id) 252 | { 253 | return -E_INVAL; 254 | } 255 | 256 | f = (struct Filefd *)fd; 257 | fileid = f->f_fileid; 258 | oldsize = f->f_file.f_size; 259 | f->f_file.f_size = size; 260 | 261 | if ((r = fsipc_set_size(fileid, size)) < 0) 262 | { 263 | return r; 264 | } 265 | 266 | va = fd2data(fd); 267 | 268 | // Map any new pages needed if extending the file 269 | for (i = ROUND(oldsize, BY2PG); i < ROUND(size, BY2PG); i += BY2PG) 270 | { 271 | if ((r = fsipc_map(fileid, i, va + i)) < 0) 272 | { 273 | fsipc_set_size(fileid, oldsize); 274 | return r; 275 | } 276 | } 277 | 278 | // Unmap pages if truncating the file 279 | for (i = ROUND(size, BY2PG); i < ROUND(oldsize, BY2PG); i += BY2PG) 280 | if ((r = syscall_mem_unmap(0, va + i)) < 0) 281 | { 282 | user_panic("ftruncate: syscall_mem_unmap %08x: %e", va + i, r); 283 | } 284 | 285 | return 0; 286 | } 287 | 288 | // Overview: 289 | // Delete a file or directory. 290 | int remove(const char *path) 291 | { 292 | // Your code here. 293 | // Call fsipc_remove. 294 | return fsipc_remove(path); 295 | } 296 | 297 | // Overview: 298 | // Synchronize disk with buffer cache 299 | int sync(void) 300 | { 301 | return fsipc_sync(); 302 | } 303 | -------------------------------------------------------------------------------- /user/fktest.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | void umain() 4 | { 5 | int a = 0; 6 | int id = 0; 7 | 8 | if ((id = fork()) == 0) 9 | { 10 | if ((id = fork()) == 0) 11 | { 12 | a += 3; 13 | for (;;) 14 | writef("\t\tthis is child2 :a:%d\n", a); 15 | } 16 | a += 2; 17 | for (;;) 18 | writef("\tthis is child :a:%d\n", a); 19 | } 20 | a++; 21 | for (;;) 22 | writef("this is father: a:%d\n", a); 23 | } 24 | -------------------------------------------------------------------------------- /user/fork.c: -------------------------------------------------------------------------------- 1 | // implement fork from user space 2 | 3 | #include "lib.h" 4 | #include 5 | #include 6 | 7 | /* ----------------- help functions ---------------- */ 8 | 9 | /* Overview: 10 | * Copy `len` bytes from `src` to `dst`. 11 | * 12 | * Pre-Condition: 13 | * `src` and `dst` can't be NULL. Also, the `src` area 14 | * shouldn't overlap the `dest`, otherwise the behavior of this 15 | * function is undefined. 16 | */ 17 | void user_bcopy(const void *src, void *dst, size_t len) 18 | { 19 | void *max; 20 | 21 | // writef("~~~~~~~~~~~~~~~~ src:%x dst:%x len:%x\n",(int)src,(int)dst,len); 22 | max = dst + len; 23 | 24 | // copy machine words while possible 25 | if (((int)src % 4 == 0) && ((int)dst % 4 == 0)) 26 | { 27 | while (dst + 3 < max) 28 | { 29 | *(int *)dst = *(int *)src; 30 | dst += 4; 31 | src += 4; 32 | } 33 | } 34 | 35 | // finish remaining 0-3 bytes 36 | while (dst < max) 37 | { 38 | *(char *)dst = *(char *)src; 39 | dst += 1; 40 | src += 1; 41 | } 42 | 43 | //for(;;); 44 | } 45 | 46 | /* Overview: 47 | * Sets the first n bytes of the block of memory 48 | * pointed by `v` to zero. 49 | * 50 | * Pre-Condition: 51 | * `v` must be valid. 52 | * 53 | * Post-Condition: 54 | * the content of the space(from `v` to `v`+ n) 55 | * will be set to zero. 56 | */ 57 | void user_bzero(void *v, u_int n) 58 | { 59 | char *p; 60 | int m; 61 | 62 | p = v; 63 | m = n; 64 | 65 | while (--m >= 0) 66 | { 67 | *p++ = 0; 68 | } 69 | } 70 | /*--------------------------------------------------------------*/ 71 | 72 | /* Overview: 73 | * Custom page fault handler - if faulting page is copy-on-write, 74 | * map in our own private writable copy. 75 | * 76 | * Pre-Condition: 77 | * `va` is the address which leads to a TLBS exception. 78 | * 79 | * Post-Condition: 80 | * Launch a user_panic if `va` is not a copy-on-write page. 81 | * Otherwise, this handler should map a private writable copy of 82 | * the faulting page at correct address. 83 | */ 84 | /*** exercise 4.13 ***/ 85 | static void 86 | pgfault(u_int va) 87 | { 88 | u_int *tmp = USTACKTOP; 89 | // writef("fork.c:pgfault():\t va:%x\n",va); 90 | u_long perm = ((Pte *)(*vpt))[VPN(va)] & 0xfff; 91 | if ((perm & PTE_COW) == 0) 92 | { 93 | user_panic("pgfault err: COW not found"); 94 | } 95 | perm -= PTE_COW; 96 | //map the new page at a temporary place 97 | syscall_mem_alloc(0, tmp, perm); 98 | //copy the content 99 | user_bcopy(ROUNDDOWN(va, BY2PG), tmp, BY2PG); 100 | //map the page on the appropriate place 101 | syscall_mem_map(0, tmp, 0, va, perm); 102 | //unmap the temporary place 103 | syscall_mem_unmap(0, tmp); 104 | } 105 | 106 | /* Overview: 107 | * Map our virtual page `pn` (address pn*BY2PG) into the target `envid` 108 | * at the same virtual address. 109 | * 110 | * Post-Condition: 111 | * if the page is writable or copy-on-write, the new mapping must be 112 | * created copy on write and then our mapping must be marked 113 | * copy on write as well. In another word, both of the new mapping and 114 | * our mapping should be copy-on-write if the page is writable or 115 | * copy-on-write. 116 | * 117 | * Hint: 118 | * PTE_LIBRARY indicates that the page is shared between processes. 119 | * A page with PTE_LIBRARY may have PTE_R at the same time. You 120 | * should process it correctly. 121 | */ 122 | /*** exercise 4.10 ***/ 123 | static void 124 | duppage(u_int envid, u_int pn) 125 | { 126 | u_int addr = pn << PGSHIFT; 127 | u_int perm = ((Pte *)(*vpt))[pn] & 0xfff; 128 | 129 | int flag = 0; 130 | if ((perm & PTE_R) && !(perm & PTE_LIBRARY)) 131 | { 132 | perm |= PTE_COW; 133 | flag = 1; 134 | } 135 | syscall_mem_map(0, addr, envid, addr, perm); 136 | if (flag) 137 | syscall_mem_map(0, addr, 0, addr, perm); 138 | // user_panic("duppage not implemented"); 139 | } 140 | 141 | /* Overview: 142 | * User-level fork. Create a child and then copy our address space 143 | * and page fault handler setup to the child. 144 | * 145 | * Hint: use vpd, vpt, and duppage. 146 | * Hint: remember to fix "env" in the child process! 147 | * Note: `set_pgfault_handler`(user/pgfault.c) is different from 148 | * `syscall_set_pgfault_handler`. 149 | */ 150 | /*** exercise 4.9 4.15***/ 151 | extern void __asm_pgfault_handler(void); 152 | int fork(void) 153 | { 154 | // Your code here. 155 | u_int newenvid; 156 | extern struct Env *envs; 157 | extern struct Env *env; 158 | u_int i; 159 | 160 | //The parent installs pgfault using set_pgfault_handler 161 | set_pgfault_handler(pgfault); 162 | 163 | //alloc a new alloc 164 | newenvid = syscall_env_alloc(); 165 | if (newenvid == 0) 166 | { 167 | env = envs + ENVX(syscall_getenvid()); 168 | return 0; 169 | } 170 | 171 | for (i = 0; i < VPN(USTACKTOP); ++i) 172 | { 173 | if (((*vpd)[i >> 10] & PTE_V) && ((*vpt)[i] & PTE_V)) 174 | duppage(newenvid, i); 175 | } 176 | syscall_mem_alloc(newenvid, UXSTACKTOP - BY2PG, PTE_V | PTE_R); 177 | syscall_set_pgfault_handler(newenvid, __asm_pgfault_handler, UXSTACKTOP); 178 | syscall_set_env_status(newenvid, ENV_RUNNABLE); 179 | return newenvid; 180 | } 181 | 182 | // Challenge! 183 | int sfork(void) 184 | { 185 | user_panic("sfork not implemented"); 186 | return -E_INVAL; 187 | } 188 | -------------------------------------------------------------------------------- /user/fprintf.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | static void user_out2string(void *arg, char *s, int l) 4 | { 5 | int i; 6 | char *b = (char *)arg; 7 | // special termination call 8 | if ((l == 1) && (s[0] == '\0')) 9 | return; 10 | 11 | for (i = 0; i < l; i++) 12 | { 13 | b[i] = s[i]; 14 | } 15 | } 16 | 17 | int fwritef(int fd, const char *fmt, ...) 18 | { 19 | char buf[512]; 20 | va_list ap; 21 | va_start(ap, fmt); 22 | user_bzero((void *)buf, 512); 23 | user_lp_Print(user_out2string, buf, fmt, ap); 24 | va_end(ap); 25 | return write(fd, buf, strlen(buf)); 26 | } 27 | -------------------------------------------------------------------------------- /user/fsipc.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #include 3 | #include 4 | 5 | #define debug 0 6 | 7 | extern u_char fsipcbuf[BY2PG]; // page-aligned, declared in entry.S 8 | 9 | // Overview: 10 | // Send an IPC request to the file server, and wait for a reply. 11 | // 12 | // Parameters: 13 | // @type: request code, passed as the simple integer IPC value. 14 | // @fsreq: page to send containing additional request data, usually fsipcbuf. 15 | // Can be modified by server to return additional response info. 16 | // @dstva: virtual address at which to receive reply page, 0 if none. 17 | // @*perm: permissions of received page. 18 | // 19 | // Returns: 20 | // 0 if successful, 21 | // < 0 on failure. 22 | static int 23 | fsipc(u_int type, void *fsreq, u_int dstva, u_int *perm) 24 | { 25 | u_int whom; 26 | // NOTEICE: Our file system no.1 process! 27 | ipc_send(envs[1].env_id, type, (u_int)fsreq, PTE_V | PTE_R); 28 | return ipc_recv(&whom, dstva, perm); 29 | } 30 | 31 | // Overview: 32 | // Send file-open request to the file server. Includes path and 33 | // omode in request, sets *fileid and *size from reply. 34 | // 35 | // Returns: 36 | // 0 on success, 37 | // < 0 on failure. 38 | int fsipc_open(const char *path, u_int omode, struct Fd *fd) 39 | { 40 | u_int perm; 41 | struct Fsreq_open *req; 42 | 43 | req = (struct Fsreq_open *)fsipcbuf; 44 | 45 | // The path is too long. 46 | if (strlen(path) >= MAXPATHLEN) 47 | { 48 | return -E_BAD_PATH; 49 | } 50 | 51 | strcpy((char *)req->req_path, path); 52 | req->req_omode = omode; 53 | return fsipc(FSREQ_OPEN, req, (u_int)fd, &perm); 54 | } 55 | 56 | int fsipc_create(const char *path, int type) 57 | { 58 | struct Fsreq_create *req; 59 | req = (struct Fsreq_create *)fsipcbuf; 60 | if (strlen(path) >= MAXPATHLEN) 61 | return -E_BAD_PATH; 62 | strcpy(req->req_path, path); 63 | req->type = type; 64 | return fsipc(FSREQ_CREATE, req, 0, 0); 65 | } 66 | 67 | // Overview: 68 | // Make a map-block request to the file server. We send the fileid and 69 | // the (byte) offset of the desired block in the file, and the server sends 70 | // us back a mapping for a page containing that block. 71 | // 72 | // Returns: 73 | // 0 on success, 74 | // < 0 on failure. 75 | int fsipc_map(u_int fileid, u_int offset, u_int dstva) 76 | { 77 | int r; 78 | u_int perm; 79 | struct Fsreq_map *req; 80 | 81 | req = (struct Fsreq_map *)fsipcbuf; 82 | req->req_fileid = fileid; 83 | req->req_offset = offset; 84 | 85 | if ((r = fsipc(FSREQ_MAP, req, dstva, &perm)) < 0) 86 | { 87 | return r; 88 | } 89 | 90 | if ((perm & ~(PTE_R | PTE_LIBRARY)) != (PTE_V)) 91 | { 92 | user_panic("fsipc_map: unexpected permissions %08x for dstva %08x", perm, 93 | dstva); 94 | } 95 | 96 | return 0; 97 | } 98 | 99 | // Overview: 100 | // Make a set-file-size request to the file server. 101 | int fsipc_set_size(u_int fileid, u_int size) 102 | { 103 | struct Fsreq_set_size *req; 104 | 105 | req = (struct Fsreq_set_size *)fsipcbuf; 106 | req->req_fileid = fileid; 107 | req->req_size = size; 108 | return fsipc(FSREQ_SET_SIZE, req, 0, 0); 109 | } 110 | 111 | // Overview: 112 | // Make a file-close request to the file server. After this the fileid is invalid. 113 | int fsipc_close(u_int fileid) 114 | { 115 | struct Fsreq_close *req; 116 | 117 | req = (struct Fsreq_close *)fsipcbuf; 118 | req->req_fileid = fileid; 119 | return fsipc(FSREQ_CLOSE, req, 0, 0); 120 | } 121 | 122 | // Overview: 123 | // Ask the file server to mark a particular file block dirty. 124 | int fsipc_dirty(u_int fileid, u_int offset) 125 | { 126 | struct Fsreq_dirty *req; 127 | 128 | req = (struct Fsreq_dirty *)fsipcbuf; 129 | req->req_fileid = fileid; 130 | req->req_offset = offset; 131 | return fsipc(FSREQ_DIRTY, req, 0, 0); 132 | } 133 | 134 | // Overview: 135 | // Ask the file server to delete a file, given its pathname. 136 | int fsipc_remove(const char *path) 137 | { 138 | struct Fsreq_remove *req; 139 | // Step 1: Check the length of path, decide if the path is valid. 140 | if (path[0] == '\0' || strlen(path) >= MAXPATHLEN) 141 | return -E_BAD_PATH; 142 | // Step 2: Transform fsipcbuf to struct Fsreq_remove* 143 | req = fsipcbuf; 144 | // Step 3: Copy path to path in req. 145 | strcpy(req->req_path, path); 146 | // Step 4: Send request to fs server with IPC. 147 | return fsipc(FSREQ_REMOVE, req, 0, 0); 148 | } 149 | 150 | // Overview: 151 | // Ask the file server to update the disk by writing any dirty 152 | // blocks in the buffer cache. 153 | int fsipc_sync(void) 154 | { 155 | return fsipc(FSREQ_SYNC, fsipcbuf, 0, 0); 156 | } 157 | -------------------------------------------------------------------------------- /user/fstest.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | static char *msg = "This is the NEW message of the day!\r\n\r\n"; 4 | static char *diff_msg = "This is a different massage of the day!\r\n\r\n"; 5 | 6 | void umain() 7 | { 8 | int r; 9 | int fdnum; 10 | char buf[512]; 11 | int n; 12 | 13 | if ((r = open("/newmotd", O_RDWR)) < 0) 14 | { 15 | user_panic("open /newmotd: %d", r); 16 | } 17 | fdnum = r; 18 | writef("open is good\n"); 19 | 20 | if ((n = read(fdnum, buf, 511)) < 0) 21 | { 22 | user_panic("read /newmotd: %d", r); 23 | } 24 | if (strcmp(buf, diff_msg) != 0) 25 | { 26 | user_panic("read returned wrong data"); 27 | } 28 | writef("read is good\n"); 29 | 30 | if ((r = ftruncate(fdnum, 0)) < 0) 31 | { 32 | user_panic("ftruncate: %d", r); 33 | } 34 | seek(fdnum, 0); 35 | 36 | if ((r = write(fdnum, msg, strlen(msg) + 1)) < 0) 37 | { 38 | user_panic("write /newmotd: %d", r); 39 | } 40 | 41 | if ((r = close(fdnum)) < 0) 42 | { 43 | user_panic("close /newmotd: %d", r); 44 | } 45 | 46 | //read again 47 | if ((r = open("/newmotd", O_RDONLY)) < 0) 48 | { 49 | user_panic("open /newmotd: %d", r); 50 | } 51 | fdnum = r; 52 | writef("open again: OK\n"); 53 | 54 | if ((n = read(fdnum, buf, 511)) < 0) 55 | { 56 | user_panic("read /newmotd: %d", r); 57 | } 58 | if (strcmp(buf, msg) != 0) 59 | { 60 | user_panic("read returned wrong data"); 61 | } 62 | writef("read again: OK\n"); 63 | 64 | if ((r = close(fdnum)) < 0) 65 | { 66 | user_panic("close /newmotd: %d", r); 67 | } 68 | writef("file rewrite is good\n"); 69 | if ((r = remove("/newmotd")) < 0) 70 | { 71 | user_panic("remove /newmotd: %d", r); 72 | } 73 | if ((r = open("/newmotd", O_RDONLY)) >= 0) 74 | { 75 | user_panic("open after remove /newmotd: %d", r); 76 | } 77 | writef("file remove: OK\n"); 78 | while (1) 79 | { 80 | //writef("IDLE!"); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /user/history.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | void umain(int argc, char **argv) 4 | { 5 | if (argc != 1) 6 | { 7 | fwritef(1, "usage: history\n"); 8 | return; 9 | } 10 | int his = open(".history", O_RDONLY | O_CREAT); 11 | char ch; 12 | fwritef(1, "\x1b[33m-*- HISTORY -*-\x1b[0m\n"); 13 | fwritef(1, "\x1b[33m1\x1b[0m\t"); 14 | int cnt = 1; 15 | int fl = 0; 16 | while (read(his, &ch, 1) == 1) 17 | { 18 | if (fl) 19 | { 20 | fwritef(1, "\x1b[33m%d\x1b[0m\t", cnt); 21 | fl = 0; 22 | } 23 | fwritef(1, "%c", ch); 24 | if (ch == '\n') 25 | { 26 | cnt++; 27 | fl = 1; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /user/icode.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | void umain(void) 4 | { 5 | int fd, n, r; 6 | char buf[512 + 1]; 7 | 8 | writef("icode: open /motd\n"); 9 | if ((fd = open("/motd", O_RDONLY)) < 0) 10 | user_panic("icode: open /motd: %e", fd); 11 | 12 | writef("icode: read /motd\n"); 13 | while ((n = read(fd, buf, sizeof buf - 1)) > 0) 14 | { 15 | buf[n] = 0; 16 | writef("%s\n", buf); 17 | } 18 | 19 | writef("icode: close /motd\n"); 20 | // close(fd); 21 | 22 | writef("icode: spawn /init\n"); 23 | if ((r = spawnl("init.b", "init", "initarg1", "initarg2", (char *)0)) < 0) 24 | user_panic("icode: spawn /init: %e", r); 25 | 26 | writef("icode: exiting\n"); 27 | } 28 | -------------------------------------------------------------------------------- /user/idle.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | umain() 4 | { 5 | while (1) 6 | writef("IDLE!"); 7 | } 8 | -------------------------------------------------------------------------------- /user/init.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | struct 4 | { 5 | char msg1[5000]; 6 | char msg2[1000]; 7 | } data = { 8 | "this is initialized data", 9 | "so is this"}; 10 | 11 | char bss[6000]; 12 | 13 | inline int MY_MUL(int a, int b) 14 | { 15 | int i; 16 | int sum; 17 | for (i = 0, sum = 0; i < b; sum += a, i++) 18 | ; 19 | return sum; 20 | } 21 | 22 | int sum(char *s, int n) 23 | { 24 | int i, tot; 25 | 26 | tot = 0; 27 | for (i = 0; i < n; i++) 28 | tot ^= MY_MUL(i, s[i]); 29 | return tot; 30 | } 31 | 32 | void umain(int argc, char **argv) 33 | { 34 | int i, r, x, want; 35 | 36 | writef("init: running\n"); 37 | 38 | want = 0xf989e; 39 | if ((x = sum((char *)&data, sizeof data)) != want) 40 | writef("init: data is not initialized: got sum %08x wanted %08x\n", 41 | x, want); 42 | else 43 | writef("init: data seems okay\n"); 44 | if ((x = sum(bss, sizeof bss)) != 0) 45 | writef("bss is not initialized: wanted sum 0 got %08x\n", x); 46 | else 47 | writef("init: bss seems okay\n"); 48 | 49 | writef("init: args:"); 50 | for (i = 0; i < argc; i++) 51 | writef(" '%s'", argv[i]); 52 | writef("\n"); 53 | 54 | writef("init: running sh\n"); 55 | 56 | // being run directly from kernel, so no file descriptors open yet 57 | close(0); 58 | if ((r = opencons()) < 0) 59 | user_panic("opencons: %e", r); 60 | if (r != 0) 61 | user_panic("first opencons used fd %d", r); 62 | if ((r = dup(0, 1)) < 0) 63 | user_panic("dup: %d", r); 64 | 65 | // write(1,"LALA",4); 66 | 67 | for (;;) 68 | { 69 | writef("init: starting sh\n"); 70 | r = spawnl("sh.b", "sh", (char *)0); 71 | if (r < 0) 72 | { 73 | writef("init: spawn sh: %e\n", r); 74 | continue; 75 | } 76 | wait(r); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /user/ipc.c: -------------------------------------------------------------------------------- 1 | // User-level IPC library routines 2 | 3 | #include "lib.h" #include < mmu.h> 4 | #include 5 | 6 | extern struct Env *env; 7 | 8 | // Send val to whom. This function keeps trying until 9 | // it succeeds. It should panic() on any error other than 10 | // -E_IPC_NOT_RECV. 11 | // 12 | // Hint: use syscall_yield() to be CPU-friendly. 13 | void ipc_send(u_int whom, u_int val, u_int srcva, u_int perm) 14 | { 15 | int r; 16 | 17 | while ((r = syscall_ipc_can_send(whom, val, srcva, perm)) == -E_IPC_NOT_RECV) 18 | { 19 | syscall_yield(); 20 | //writef("QQ"); 21 | } 22 | if (r == 0) 23 | return; 24 | user_panic("error in ipc_send: %d", r); 25 | } 26 | 27 | // Receive a value. Return the value and store the caller's envid 28 | // in *whom. 29 | // 30 | // Hint: use env to discover the value and who sent it. 31 | u_int ipc_recv(u_int *whom, u_int dstva, u_int *perm) 32 | { 33 | //printf("ipc_recv:come 0\n"); 34 | syscall_ipc_recv(dstva); 35 | 36 | if (whom) 37 | *whom = env->env_ipc_from; 38 | if (perm) 39 | *perm = env->env_ipc_perm; 40 | return env->env_ipc_value; 41 | } 42 | -------------------------------------------------------------------------------- /user/lib.h: -------------------------------------------------------------------------------- 1 | #ifndef LIB_H 2 | #define LIB_H 3 | #include "fd.h" 4 | #include "pmap.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | /////////////////////////////////////////////////////head 11 | extern void umain(); 12 | extern void libmain(); 13 | extern void exit(); 14 | 15 | extern struct Env *env; 16 | 17 | #define ENV_VAR_MAX 128 18 | #define ENV_NAME_MAX 16 19 | #define ENV_VALUE_MAX 64 20 | 21 | typedef struct 22 | { 23 | char name[ENV_NAME_MAX]; 24 | char value[ENV_VALUE_MAX]; 25 | u_int readonly; 26 | } env_var; 27 | 28 | #define USED(x) (void)(x) 29 | //////////////////////////////////////////////////////printf 30 | #include 31 | //#define LP_MAX_BUF 80 32 | 33 | void user_lp_Print(void (*output)(void *, const char *, int), 34 | void *arg, 35 | const char *fmt, 36 | va_list ap); 37 | 38 | void writef(char *fmt, ...); 39 | 40 | void _user_panic(const char *, int, const char *, ...) 41 | __attribute__((noreturn)); 42 | 43 | #define user_panic(...) _user_panic(__FILE__, __LINE__, __VA_ARGS__) 44 | 45 | /////////////////////////////////////////////////////fork spawn 46 | int spawn(char *prog, char **argv); 47 | int spawnl(char *prot, char *args, ...); 48 | int fork(void); 49 | 50 | void user_bcopy(const void *src, void *dst, size_t len); 51 | void user_bzero(void *v, u_int n); 52 | //////////////////////////////////////////////////syscall_lib 53 | extern int msyscall(int, int, int, int, int, int); 54 | 55 | void syscall_putchar(char ch); 56 | u_int syscall_getenvid(void); 57 | void syscall_yield(void); 58 | inline static int syscall_env_destroy(u_int envid) 59 | { 60 | return msyscall(SYS_env_destroy, envid, 0, 0, 0, 0); 61 | } 62 | int syscall_set_pgfault_handler(u_int envid, void (*func)(void), 63 | u_int xstacktop); 64 | int syscall_mem_alloc(u_int envid, u_int va, u_int perm); 65 | int syscall_mem_map(u_int srcid, u_int srcva, u_int dstid, u_int dstva, 66 | u_int perm); 67 | int syscall_mem_unmap(u_int envid, u_int va); 68 | 69 | inline static int syscall_env_alloc(void) 70 | { 71 | return msyscall(SYS_env_alloc, 0, 0, 0, 0, 0); 72 | } 73 | 74 | int syscall_set_env_status(u_int envid, u_int status); 75 | int syscall_set_trapframe(u_int envid, struct Trapframe *tf); 76 | void syscall_panic(char *msg); 77 | int syscall_ipc_can_send(u_int envid, u_int value, u_int srcva, u_int perm); 78 | void syscall_ipc_recv(u_int dstva); 79 | int syscall_cgetc(); 80 | int syscall_write_dev(u_int va, u_int dev, u_int offset); 81 | int syscall_read_dev(u_int va, u_int dev, u_int offset); 82 | int syscall_wait_cons(); 83 | int syscall_signal_cons(); 84 | int syscall_set_env(char *name, char *value, int readonly); 85 | int syscall_get_env(char *name, char *value); 86 | int syscall_list_env_var(env_var *list); 87 | 88 | // string.c 89 | int strlen(const char *s); 90 | char *strcpy(char *dst, const char *src); 91 | char *strcat(char *dst, const char *src); 92 | const char *strchr(const char *s, char c); 93 | void *memcpy(void *destaddr, void const *srcaddr, u_int len); 94 | int strcmp(const char *p, const char *q); 95 | // ipc.c 96 | void ipc_send(u_int whom, u_int val, u_int srcva, u_int perm); 97 | u_int ipc_recv(u_int *whom, u_int dstva, u_int *perm); 98 | 99 | // wait.c 100 | void wait(u_int envid); 101 | 102 | // console.c 103 | int opencons(void); 104 | int iscons(int fdnum); 105 | 106 | // pipe.c 107 | int pipe(int pfd[2]); 108 | int pipeisclosed(int fdnum); 109 | 110 | // pageref.c 111 | int pageref(void *); 112 | 113 | // pgfault.c 114 | void set_pgfault_handler(void (*fn)(u_int va)); 115 | 116 | // fprintf.c 117 | int fwritef(int fd, const char *fmt, ...); 118 | 119 | // fsipc.c 120 | int fsipc_open(const char *, u_int, struct Fd *); 121 | int fsipc_create(const char *, int); 122 | int fsipc_map(u_int, u_int, u_int); 123 | int fsipc_set_size(u_int, u_int); 124 | int fsipc_close(u_int); 125 | int fsipc_dirty(u_int, u_int); 126 | int fsipc_remove(const char *); 127 | int fsipc_sync(void); 128 | int fsipc_incref(u_int); 129 | 130 | // fd.c 131 | int close(int fd); 132 | int read(int fd, void *buf, u_int nbytes); 133 | int write(int fd, const void *buf, u_int nbytes); 134 | int seek(int fd, u_int offset); 135 | void close_all(void); 136 | int readn(int fd, void *buf, u_int nbytes); 137 | int dup(int oldfd, int newfd); 138 | int fstat(int fdnum, struct Stat *stat); 139 | int stat(const char *path, struct Stat *); 140 | 141 | // file.c 142 | int open(const char *path, int mode); 143 | int create(const char *path, int type); 144 | int read_map(int fd, u_int offset, void **blk); 145 | int delete (const char *path); 146 | int ftruncate(int fd, u_int size); 147 | int sync(void); 148 | 149 | #define user_assert(x) \ 150 | do \ 151 | { \ 152 | if (!(x)) \ 153 | user_panic("assertion failed: %s", #x); \ 154 | } while (0) 155 | 156 | /* File open modes */ 157 | #define O_RDONLY 0x0000 /* open for reading only */ 158 | #define O_WRONLY 0x0001 /* open for writing only */ 159 | #define O_RDWR 0x0002 /* open for reading and writing */ 160 | #define O_ACCMODE 0x0003 /* mask for above modes */ 161 | 162 | #define O_CREAT 0x0100 /* create if nonexistent */ 163 | #define O_TRUNC 0x0200 /* truncate to zero length */ 164 | #define O_EXCL 0x0400 /* error if already exists */ 165 | #define O_MKDIR 0x0800 /* create directory, not regular file */ 166 | #define O_APPND 0x1000 167 | 168 | #endif 169 | -------------------------------------------------------------------------------- /user/libos.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #include 3 | #include 4 | 5 | void exit(void) 6 | { 7 | close_all(); 8 | syscall_env_destroy(0); 9 | } 10 | 11 | struct Env *env; 12 | 13 | void libmain(int argc, char **argv) 14 | { 15 | // set env to point at our env structure in envs[]. 16 | env = 0; // Your code here. 17 | //writef("xxxxxxxxx %x %x xxxxxxxxx\n",argc,(int)argv); 18 | int envid; 19 | envid = syscall_getenvid(); 20 | envid = ENVX(envid); 21 | env = &envs[envid]; 22 | // call user main routine 23 | umain(argc, argv); 24 | // exit gracefully 25 | exit(); 26 | //syscall_env_destroy(0); 27 | } 28 | -------------------------------------------------------------------------------- /user/ls.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int flag[256]; 4 | 5 | void lsdir(char *, char *); 6 | void ls1(char *, u_int, u_int, char *); 7 | 8 | void ls(char *path, char *prefix) 9 | { 10 | int r; 11 | struct Stat st; 12 | 13 | if ((r = stat(path, &st)) < 0) 14 | { 15 | writef("file not found\n"); 16 | return; 17 | } 18 | if (st.st_type == FTYPE_DIR && !flag['d']) 19 | lsdir(path, prefix); 20 | else 21 | ls1(0, st.st_type, st.st_size, path); 22 | } 23 | 24 | void lsdir(char *path, char *prefix) 25 | { 26 | int fd, n; 27 | struct File f; 28 | 29 | if ((fd = open(path, O_RDONLY)) < 0) 30 | user_panic("open %s: %e", path, fd); 31 | while ((n = readn(fd, &f, sizeof f)) == sizeof f) 32 | if (f.f_name[0] && (flag['a'] || f.f_name[0] != '.')) 33 | ls1(prefix, f.f_type, f.f_size, f.f_name); 34 | if (n > 0) 35 | user_panic("short read in directory %s", path); 36 | if (n < 0) 37 | user_panic("error reading directory %s: %e", path, n); 38 | } 39 | 40 | void ls1(char *prefix, u_int type, u_int size, char *name) 41 | { 42 | char *sep; 43 | if (flag['l']) 44 | fwritef(1, "%11d %c ", size, type == FTYPE_DIR ? 'd' : type == FTYPE_BIN ? 'x' 45 | : '-'); 46 | if (prefix) 47 | { 48 | if (prefix[0] && prefix[strlen(prefix) - 1] != '/') 49 | sep = "/"; 50 | else 51 | sep = ""; 52 | fwritef(1, "%s%s", prefix, sep); 53 | } 54 | fwritef(1, type == FTYPE_DIR ? "\x1b[36m%s\x1b[0m" : type == FTYPE_BIN ? "\x1b[31m%s\x1b[0m" 55 | : "%s", 56 | name); 57 | if (flag['F'] && type == FTYPE_DIR) 58 | fwritef(1, "/"); 59 | if (flag['F'] && type == FTYPE_BIN) 60 | fwritef(1, "*"); 61 | fwritef(1, flag['l'] ? "\n" : " "); 62 | } 63 | 64 | void usage(void) 65 | { 66 | fwritef(1, "usage: ls [-adFl] [file...]\n"); 67 | exit(); 68 | } 69 | 70 | void umain(int argc, char **argv) 71 | { 72 | int i; 73 | 74 | ARGBEGIN 75 | { 76 | default: 77 | usage(); 78 | case 'a': 79 | case 'd': 80 | case 'F': 81 | case 'l': 82 | flag[(u_char)ARGC()]++; 83 | break; 84 | } 85 | ARGEND 86 | 87 | if (argc == 0) 88 | ls("/", ""); 89 | else 90 | { 91 | for (i = 0; i < argc; i++) 92 | ls(argv[i], argv[i]); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /user/mkdir.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | void umain(int argc, char **argv) 4 | { 5 | if (argc != 2) 6 | { 7 | fwritef(1, "usage: mkdir directory_name\n"); 8 | return; 9 | } 10 | int fd; 11 | fd = open(argv[1], O_RDONLY); 12 | if (fd >= 0) 13 | { 14 | fwritef(1, "directory duplicated\n"); 15 | return; 16 | } 17 | if (create(argv[1], FTYPE_DIR) < 0) 18 | { 19 | fwritef(1, "fail to create directory\n"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /user/num.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int bol = 1; 4 | int line = 0; 5 | 6 | void num(int f, const char *s) 7 | { 8 | long n; 9 | int r; 10 | char c; 11 | 12 | while ((n = read(f, &c, 1)) > 0) 13 | { 14 | if (bol) 15 | { 16 | writef("%5d ", ++line); 17 | bol = 0; 18 | } 19 | if ((r = write(1, &c, 1)) != 1) 20 | user_panic("write error copying %s: %e", s, r); 21 | if (c == '\n') 22 | bol = 1; 23 | } 24 | if (n < 0) 25 | user_panic("error reading %s: %e", s, n); 26 | } 27 | 28 | void umain(int argc, char **argv) 29 | { 30 | int f, i; 31 | 32 | //binaryname = "num.b"; 33 | if (argc == 1) 34 | num(0, ""); 35 | else 36 | for (i = 1; i < argc; i++) 37 | { 38 | f = open(argv[i], O_RDONLY); 39 | if (f < 0) 40 | { 41 | writef("cannot open file: %s", argv[i]); 42 | exit(); 43 | } 44 | else 45 | { 46 | num(f, argv[i]); 47 | close(f); 48 | } 49 | } 50 | exit(); 51 | } 52 | -------------------------------------------------------------------------------- /user/pageref.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int pageref(void *v) 4 | { 5 | u_int pte; 6 | 7 | if (!((*vpd)[PDX(v)] & PTE_V)) 8 | return 0; 9 | pte = (*vpt)[VPN(v)]; 10 | if (!(pte & PTE_V)) 11 | return 0; 12 | return pages[PPN(pte)].pp_ref; 13 | } 14 | -------------------------------------------------------------------------------- /user/pgfault.c: -------------------------------------------------------------------------------- 1 | // User-level page fault handler. We use an assembly wrapper around a C function. 2 | // The assembly wrapper is in entry.S. 3 | 4 | #include "lib.h" 5 | #include 6 | 7 | extern void (*__pgfault_handler)(u_int); 8 | extern void __asm_pgfault_handler(void); 9 | 10 | // 11 | // Set the page fault handler function. 12 | // If there isn't one yet, _pgfault_handler will be 0. 13 | // The first time we register a handler, we need to 14 | // allocate an exception stack and tell the kernel to 15 | // call _asm_pgfault_handler on it. 16 | // 17 | void set_pgfault_handler(void (*fn)(u_int va)) 18 | { 19 | if (__pgfault_handler == 0) 20 | { 21 | // Your code here: 22 | // map one page of exception stack with top at UXSTACKTOP 23 | // register assembly handler and stack with operating system 24 | if (syscall_mem_alloc(0, UXSTACKTOP - BY2PG, PTE_V | PTE_R) < 0 || 25 | syscall_set_pgfault_handler(0, __asm_pgfault_handler, UXSTACKTOP) < 0) 26 | { 27 | writef("cannot set pgfault handler\n"); 28 | return; 29 | } 30 | 31 | // panic("set_pgfault_handler not implemented"); 32 | } 33 | 34 | // Save handler pointer for assembly to call. 35 | __pgfault_handler = fn; 36 | } 37 | -------------------------------------------------------------------------------- /user/pingpong.c: -------------------------------------------------------------------------------- 1 | // Ping-pong a counter between two processes. 2 | // Only need to start one of these -- splits into two with fork. 3 | 4 | #include "lib.h" 5 | 6 | void umain(void) 7 | { 8 | u_int who, i; 9 | 10 | if ((who = fork()) != 0) 11 | { 12 | // get the ball rolling 13 | writef("\n@@@@@send 0 from %x to %x\n", syscall_getenvid(), who); 14 | ipc_send(who, 0, 0, 0); 15 | //user_panic("&&&&&&&&&&&&&&&&&&&&&&&&m"); 16 | } 17 | 18 | for (;;) 19 | { 20 | writef("%x am waiting.....\n", syscall_getenvid()); 21 | i = ipc_recv(&who, 0, 0); 22 | 23 | writef("%x got %d from %x\n", syscall_getenvid(), i, who); 24 | 25 | //user_panic("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); 26 | if (i == 10) 27 | return; 28 | i++; 29 | writef("\n@@@@@send 0 from %x to %x\n", syscall_getenvid(), who); 30 | ipc_send(who, i, 0, 0); 31 | if (i == 10) 32 | return; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /user/pipe.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #include 3 | #include 4 | #define debug 0 5 | 6 | static int pipeclose(struct Fd *); 7 | static int piperead(struct Fd *fd, void *buf, u_int n, u_int offset); 8 | static int pipestat(struct Fd *, struct Stat *); 9 | static int pipewrite(struct Fd *fd, const void *buf, u_int n, u_int offset); 10 | 11 | struct Dev devpipe = 12 | { 13 | .dev_id = 'p', 14 | .dev_name = "pipe", 15 | .dev_read = piperead, 16 | .dev_write = pipewrite, 17 | .dev_close = pipeclose, 18 | .dev_stat = pipestat, 19 | }; 20 | 21 | #define BY2PIPE 32 // small to provoke races 22 | 23 | struct Pipe 24 | { 25 | u_int p_rpos; // read position 26 | u_int p_wpos; // write position 27 | u_char p_buf[BY2PIPE]; // data buffer 28 | }; 29 | 30 | int pipe(int pfd[2]) 31 | { 32 | int r, va; 33 | struct Fd *fd0, *fd1; 34 | 35 | // allocate the file descriptor table entries 36 | if ((r = fd_alloc(&fd0)) < 0 || (r = syscall_mem_alloc(0, (u_int)fd0, PTE_V | PTE_R | PTE_LIBRARY)) < 0) 37 | goto err; 38 | 39 | if ((r = fd_alloc(&fd1)) < 0 || (r = syscall_mem_alloc(0, (u_int)fd1, PTE_V | PTE_R | PTE_LIBRARY)) < 0) 40 | goto err1; 41 | 42 | // allocate the pipe structure as first data page in both 43 | va = fd2data(fd0); 44 | if ((r = syscall_mem_alloc(0, va, PTE_V | PTE_R | PTE_LIBRARY)) < 0) 45 | goto err2; 46 | if ((r = syscall_mem_map(0, va, 0, fd2data(fd1), PTE_V | PTE_R | PTE_LIBRARY)) < 0) 47 | goto err3; 48 | 49 | // set up fd structures 50 | fd0->fd_dev_id = devpipe.dev_id; 51 | fd0->fd_omode = O_RDONLY; 52 | 53 | fd1->fd_dev_id = devpipe.dev_id; 54 | fd1->fd_omode = O_WRONLY; 55 | 56 | // writef("[%08x] pipecreate \n", env->env_id, (* vpt)[VPN(va)]); 57 | 58 | pfd[0] = fd2num(fd0); 59 | pfd[1] = fd2num(fd1); 60 | return 0; 61 | 62 | err3: 63 | syscall_mem_unmap(0, va); 64 | err2: 65 | syscall_mem_unmap(0, (u_int)fd1); 66 | err1: 67 | syscall_mem_unmap(0, (u_int)fd0); 68 | err: 69 | return r; 70 | } 71 | 72 | static int 73 | _pipeisclosed(struct Fd *fd, struct Pipe *p) 74 | { 75 | // Your code here. 76 | // 77 | // Check pageref(fd) and pageref(p), 78 | // returning 1 if they're the same, 0 otherwise. 79 | // 80 | // The logic here is that pageref(p) is the total 81 | // number of readers *and* writers, whereas pageref(fd) 82 | // is the number of file descriptors like fd (readers if fd is 83 | // a reader, writers if fd is a writer). 84 | // 85 | // If the number of file descriptors like fd is equal 86 | // to the total number of readers and writers, then 87 | // everybody left is what fd is. So the other end of 88 | // the pipe is closed. 89 | int pfd, pfp, runs; 90 | do 91 | { 92 | runs = env->env_runs; 93 | pfd = pageref(fd); 94 | pfp = pageref(p); 95 | } while (runs != env->env_runs); 96 | 97 | if (pfd == pfp) 98 | return 1; 99 | 100 | // user_panic("_pipeisclosed not implemented"); 101 | return 0; 102 | } 103 | 104 | int pipeisclosed(int fdnum) 105 | { 106 | struct Fd *fd; 107 | struct Pipe *p; 108 | int r; 109 | 110 | if ((r = fd_lookup(fdnum, &fd)) < 0) 111 | return r; 112 | p = (struct Pipe *)fd2data(fd); 113 | return _pipeisclosed(fd, p); 114 | } 115 | 116 | static int 117 | piperead(struct Fd *fd, void *vbuf, u_int n, u_int offset) 118 | { 119 | // Your code here. See the lab text for a description of 120 | // what piperead needs to do. Write a loop that 121 | // transfers one byte at a time. If you decide you need 122 | // to yield (because the pipe is empty), only yield if 123 | // you have not yet copied any bytes. (If you have copied 124 | // some bytes, return what you have instead of yielding.) 125 | // If the pipe is empty and closed and you didn't copy any data out, return 0. 126 | // Use _pipeisclosed to check whether the pipe is closed. 127 | int i; 128 | struct Pipe *p; 129 | char *rbuf; 130 | 131 | p = fd2data(fd); 132 | rbuf = (char *)vbuf; 133 | for (i = 0; i < n; ++i) 134 | { 135 | while (p->p_rpos == p->p_wpos) 136 | { 137 | if (_pipeisclosed(fd, p) || i > 0) 138 | return i; 139 | syscall_yield(); 140 | } 141 | rbuf[i] = p->p_buf[p->p_rpos % BY2PIPE]; 142 | p->p_rpos++; 143 | } 144 | return n; 145 | 146 | // user_panic("piperead not implemented"); 147 | // return -E_INVAL; 148 | } 149 | 150 | static int 151 | pipewrite(struct Fd *fd, const void *vbuf, u_int n, u_int offset) 152 | { 153 | // Your code here. See the lab text for a description of what 154 | // pipewrite needs to do. Write a loop that transfers one byte 155 | // at a time. Unlike in read, it is not okay to write only some 156 | // of the data. If the pipe fills and you've only copied some of 157 | // the data, wait for the pipe to empty and then keep copying. 158 | // If the pipe is full and closed, return 0. 159 | // Use _pipeisclosed to check whether the pipe is closed. 160 | int i; 161 | struct Pipe *p; 162 | char *wbuf; 163 | 164 | p = fd2data(fd); 165 | wbuf = (char *)vbuf; 166 | for (i = 0; i < n; ++i) 167 | { 168 | while (p->p_wpos - p->p_rpos == BY2PIPE) 169 | { 170 | if (_pipeisclosed(fd, p)) 171 | return 0; 172 | syscall_yield(); 173 | } 174 | p->p_buf[p->p_wpos % BY2PIPE] = wbuf[i]; 175 | p->p_wpos++; 176 | } 177 | 178 | // return -E_INVAL; 179 | // user_panic("pipewrite not implemented"); 180 | 181 | return n; 182 | } 183 | 184 | static int 185 | pipestat(struct Fd *fd, struct Stat *stat) 186 | { 187 | struct Pipe *p; 188 | } 189 | 190 | static int 191 | pipeclose(struct Fd *fd) 192 | { 193 | syscall_mem_unmap(0, fd); 194 | syscall_mem_unmap(0, fd2data(fd)); 195 | return 0; 196 | } 197 | -------------------------------------------------------------------------------- /user/print.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2001 MontaVista Software Inc. 3 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License as published by the 7 | * Free Software Foundation; either version 2 of the License, or (at your 8 | * option) any later version. 9 | * 10 | */ 11 | 12 | #include 13 | 14 | /* macros */ 15 | #define IsDigit(x) (((x) >= '0') && ((x) <= '9')) 16 | #define Ctod(x) ((x) - '0') 17 | 18 | /* forward declaration */ 19 | extern int user_PrintChar(char *, char, int, int); 20 | extern int user_PrintString(char *, char *, int, int); 21 | extern int user_PrintNum(char *, unsigned long, int, int, int, int, char, int); 22 | 23 | /* private variable */ 24 | static const char user_theFatalMsg[] = "fatal error in user_lp_Print!"; 25 | 26 | /* -*- 27 | * A low level printf() function. 28 | */ 29 | void user_lp_Print(void (*output)(void *, char *, int), 30 | void *arg, 31 | char *fmt, 32 | va_list ap) 33 | { 34 | 35 | #define OUTPUT(arg, s, l) \ 36 | { \ 37 | if (((l) < 0) || ((l) > LP_MAX_BUF)) \ 38 | { \ 39 | (*output)(arg, (char *)user_theFatalMsg, sizeof(user_theFatalMsg) - 1); \ 40 | for (;;) \ 41 | ; \ 42 | } \ 43 | else \ 44 | { \ 45 | (*output)(arg, s, l); \ 46 | arg += l; \ 47 | } \ 48 | } 49 | 50 | char buf[LP_MAX_BUF]; 51 | 52 | char c; 53 | char *s; 54 | long int num; 55 | 56 | int longFlag; 57 | int negFlag; 58 | int width; 59 | int prec; 60 | int ladjust; 61 | char padc; 62 | 63 | int length; 64 | 65 | for (;;) 66 | { 67 | { 68 | /* scan for the next '%' */ 69 | char *fmtStart = fmt; 70 | while ((*fmt != '\0') && (*fmt != '%')) 71 | { 72 | fmt++; 73 | } 74 | 75 | /* flush the string found so far */ 76 | OUTPUT(arg, fmtStart, fmt - fmtStart); 77 | 78 | /* are we hitting the end? */ 79 | if (*fmt == '\0') 80 | break; 81 | } 82 | 83 | /* we found a '%' */ 84 | fmt++; 85 | 86 | /* check for long */ 87 | if (*fmt == 'l') 88 | { 89 | longFlag = 1; 90 | fmt++; 91 | } 92 | else 93 | { 94 | longFlag = 0; 95 | } 96 | 97 | /* check for other prefixes */ 98 | width = 0; 99 | prec = -1; 100 | ladjust = 0; 101 | padc = ' '; 102 | 103 | if (*fmt == '-') 104 | { 105 | ladjust = 1; 106 | fmt++; 107 | } 108 | 109 | if (*fmt == '0') 110 | { 111 | padc = '0'; 112 | fmt++; 113 | } 114 | 115 | if (IsDigit(*fmt)) 116 | { 117 | while (IsDigit(*fmt)) 118 | { 119 | width = 10 * width + Ctod(*fmt++); 120 | } 121 | } 122 | 123 | if (*fmt == '.') 124 | { 125 | fmt++; 126 | if (IsDigit(*fmt)) 127 | { 128 | prec = 0; 129 | while (IsDigit(*fmt)) 130 | { 131 | prec = prec * 10 + Ctod(*fmt++); 132 | } 133 | } 134 | } 135 | 136 | /* check format flag */ 137 | negFlag = 0; 138 | switch (*fmt) 139 | { 140 | case 'b': 141 | if (longFlag) 142 | { 143 | num = va_arg(ap, long int); 144 | } 145 | else 146 | { 147 | num = va_arg(ap, int); 148 | } 149 | length = user_PrintNum(buf, num, 2, 0, width, ladjust, padc, 0); 150 | OUTPUT(arg, buf, length); 151 | break; 152 | 153 | case 'd': 154 | case 'D': 155 | if (longFlag) 156 | { 157 | num = va_arg(ap, long int); 158 | } 159 | else 160 | { 161 | num = va_arg(ap, int); 162 | } 163 | if (num < 0) 164 | { 165 | num = -num; 166 | negFlag = 1; 167 | } 168 | length = user_PrintNum(buf, num, 10, negFlag, width, ladjust, padc, 0); 169 | OUTPUT(arg, buf, length); 170 | break; 171 | 172 | case 'o': 173 | case 'O': 174 | if (longFlag) 175 | { 176 | num = va_arg(ap, long int); 177 | } 178 | else 179 | { 180 | num = va_arg(ap, int); 181 | } 182 | length = user_PrintNum(buf, num, 8, 0, width, ladjust, padc, 0); 183 | OUTPUT(arg, buf, length); 184 | break; 185 | 186 | case 'u': 187 | case 'U': 188 | if (longFlag) 189 | { 190 | num = va_arg(ap, long int); 191 | } 192 | else 193 | { 194 | num = va_arg(ap, int); 195 | } 196 | length = user_PrintNum(buf, num, 10, 0, width, ladjust, padc, 0); 197 | OUTPUT(arg, buf, length); 198 | break; 199 | 200 | case 'x': 201 | if (longFlag) 202 | { 203 | num = va_arg(ap, long int); 204 | } 205 | else 206 | { 207 | num = va_arg(ap, int); 208 | } 209 | length = user_PrintNum(buf, num, 16, 0, width, ladjust, padc, 0); 210 | OUTPUT(arg, buf, length); 211 | break; 212 | 213 | case 'X': 214 | if (longFlag) 215 | { 216 | num = va_arg(ap, long int); 217 | } 218 | else 219 | { 220 | num = va_arg(ap, int); 221 | } 222 | length = user_PrintNum(buf, num, 16, 0, width, ladjust, padc, 1); 223 | OUTPUT(arg, buf, length); 224 | break; 225 | 226 | case 'c': 227 | c = (char)va_arg(ap, int); 228 | length = user_PrintChar(buf, c, width, ladjust); 229 | OUTPUT(arg, buf, length); 230 | break; 231 | 232 | case 's': 233 | s = (char *)va_arg(ap, char *); 234 | length = user_PrintString(buf, s, width, ladjust); 235 | OUTPUT(arg, buf, length); 236 | break; 237 | 238 | case '\0': 239 | fmt--; 240 | break; 241 | 242 | default: 243 | /* output this char as it is */ 244 | OUTPUT(arg, fmt, 1); 245 | } /* switch (*fmt) */ 246 | 247 | fmt++; 248 | } /* for(;;) */ 249 | 250 | /* special termination call */ 251 | OUTPUT(arg, "\0", 1); 252 | } 253 | 254 | /* --------------- local help functions --------------------- */ 255 | int user_PrintChar(char *buf, char c, int length, int ladjust) 256 | { 257 | int i; 258 | 259 | if (length < 1) 260 | length = 1; 261 | if (ladjust) 262 | { 263 | *buf = c; 264 | for (i = 1; i < length; i++) 265 | buf[i] = ' '; 266 | } 267 | else 268 | { 269 | for (i = 0; i < length - 1; i++) 270 | buf[i] = ' '; 271 | buf[length - 1] = c; 272 | } 273 | return length; 274 | } 275 | 276 | int user_PrintString(char *buf, char *s, int length, int ladjust) 277 | { 278 | int i; 279 | int len = 0; 280 | char *s1 = s; 281 | while (*s1++) 282 | len++; 283 | if (length < len) 284 | length = len; 285 | 286 | if (ladjust) 287 | { 288 | for (i = 0; i < len; i++) 289 | buf[i] = s[i]; 290 | for (i = len; i < length; i++) 291 | buf[i] = ' '; 292 | } 293 | else 294 | { 295 | for (i = 0; i < length - len; i++) 296 | buf[i] = ' '; 297 | for (i = length - len; i < length; i++) 298 | buf[i] = s[i - length + len]; 299 | } 300 | return length; 301 | } 302 | 303 | int user_PrintNum(char *buf, unsigned long u, int base, int negFlag, 304 | int length, int ladjust, char padc, int upcase) 305 | { 306 | /* algorithm : 307 | * 1. prints the number from left to right in reverse form. 308 | * 2. fill the remaining spaces with padc if length is longer than 309 | * the actual length 310 | * TRICKY : if left adjusted, no "0" padding. 311 | * if negtive, insert "0" padding between "0" and number. 312 | * 3. if (!ladjust) we reverse the whole string including paddings 313 | * 4. otherwise we only reverse the actual string representing the num. 314 | */ 315 | 316 | int actualLength = 0; 317 | char *p = buf; 318 | int i; 319 | 320 | do 321 | { 322 | int tmp = u % base; 323 | if (tmp <= 9) 324 | { 325 | *p++ = '0' + tmp; 326 | } 327 | else if (upcase) 328 | { 329 | *p++ = 'A' + tmp - 10; 330 | } 331 | else 332 | { 333 | *p++ = 'a' + tmp - 10; 334 | } 335 | u /= base; 336 | } while (u != 0); 337 | 338 | if (negFlag) 339 | { 340 | *p++ = '-'; 341 | } 342 | 343 | /* figure out actual length and adjust the maximum length */ 344 | actualLength = p - buf; 345 | if (length < actualLength) 346 | length = actualLength; 347 | 348 | /* add padding */ 349 | if (ladjust) 350 | { 351 | padc = ' '; 352 | } 353 | if (negFlag && !ladjust && (padc == '0')) 354 | { 355 | for (i = actualLength - 1; i < length - 1; i++) 356 | buf[i] = padc; 357 | buf[length - 1] = '-'; 358 | } 359 | else 360 | { 361 | for (i = actualLength; i < length; i++) 362 | buf[i] = padc; 363 | } 364 | 365 | /* prepare to reverse the string */ 366 | { 367 | int begin = 0; 368 | int end; 369 | if (ladjust) 370 | { 371 | end = actualLength - 1; 372 | } 373 | else 374 | { 375 | end = length - 1; 376 | } 377 | 378 | while (end > begin) 379 | { 380 | char tmp = buf[begin]; 381 | buf[begin] = buf[end]; 382 | buf[end] = tmp; 383 | begin++; 384 | end--; 385 | } 386 | } 387 | 388 | /* adjust the string pointer */ 389 | return length; 390 | } 391 | -------------------------------------------------------------------------------- /user/printf.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "lib.h" 4 | 5 | void halt(void); 6 | 7 | static void user_myoutput(void *arg, char *s, int l) 8 | { 9 | int i; 10 | 11 | // special termination call 12 | if ((l == 1) && (s[0] == '\0')) 13 | return; 14 | 15 | for (i = 0; i < l; i++) 16 | { 17 | syscall_putchar(s[i]); 18 | // if (s[i] == '\n') syscall_putchar('\n'); 19 | } 20 | } 21 | 22 | void writef(char *fmt, ...) 23 | { 24 | syscall_wait_cons(); 25 | va_list ap; 26 | va_start(ap, fmt); 27 | user_lp_Print(user_myoutput, 0, fmt, ap); 28 | va_end(ap); 29 | syscall_signal_cons(); 30 | } 31 | 32 | void _user_panic(const char *file, int line, const char *fmt, ...) 33 | { 34 | va_list ap; 35 | 36 | va_start(ap, fmt); 37 | writef("panic at %s:%d: ", file, line); 38 | user_lp_Print(user_myoutput, 0, (char *)fmt, ap); 39 | writef("\n"); 40 | va_end(ap); 41 | 42 | for (;;) 43 | ; 44 | } 45 | -------------------------------------------------------------------------------- /user/rm.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | void umain(int argc, char **argv) 4 | { 5 | if (argc == 1) 6 | { 7 | fwritef(1, "usage: rm file_1 [file_2... file_n]\n"); 8 | return; 9 | } 10 | int i; 11 | struct Stat state; 12 | for (i = 1; i < argc; ++i) 13 | { 14 | if (stat(argv[i], &state) < 0) 15 | { 16 | fwritef(1, "cannot open file: %s\n", argv[i]); 17 | continue; 18 | } 19 | if (state.st_type != FTYPE_REG) 20 | { 21 | fwritef(1, "specified path should be file\n", argv[i]); 22 | continue; 23 | } 24 | remove(argv[i]); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /user/spawn.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #define debug 0 7 | #define TMPPAGE (BY2PG) 8 | #define TMPPAGETOP (TMPPAGE + BY2PG) 9 | 10 | int init_stack(u_int child, char **argv, u_int *init_esp) 11 | { 12 | int argc, i, r, tot; 13 | char *strings; 14 | u_int *args; 15 | 16 | // Count the number of arguments (argc) 17 | // and the total amount of space needed for strings (tot) 18 | tot = 0; 19 | for (argc = 0; argv[argc]; argc++) 20 | tot += strlen(argv[argc]) + 1; 21 | 22 | // Make sure everything will fit in the initial stack page 23 | if (ROUND(tot, 4) + 4 * (argc + 3) > BY2PG) 24 | return -E_NO_MEM; 25 | 26 | // Determine where to place the strings and the args array 27 | strings = (char *)TMPPAGETOP - tot; 28 | args = (u_int *)(TMPPAGETOP - ROUND(tot, 4) - 4 * (argc + 1)); 29 | 30 | if ((r = syscall_mem_alloc(0, TMPPAGE, PTE_V | PTE_R)) < 0) 31 | return r; 32 | // Replace this with your code to: 33 | // 34 | // - copy the argument strings into the stack page at 'strings' 35 | char *ctemp, *argv_temp; 36 | u_int j; 37 | ctemp = strings; 38 | for (i = 0; i < argc; i++) 39 | { 40 | argv_temp = argv[i]; 41 | for (j = 0; j < strlen(argv[i]); j++) 42 | { 43 | *ctemp = *argv_temp; 44 | ctemp++; 45 | argv_temp++; 46 | } 47 | *ctemp = 0; 48 | ctemp++; 49 | } 50 | // - initialize args[0..argc-1] to be pointers to these strings 51 | // that will be valid addresses for the child environment 52 | // (for whom this page will be at USTACKTOP-BY2PG!). 53 | ctemp = (char *)(USTACKTOP - TMPPAGETOP + (u_int)strings); 54 | for (i = 0; i < argc; i++) 55 | { 56 | args[i] = (u_int)ctemp; 57 | ctemp += strlen(argv[i]) + 1; 58 | } 59 | // - set args[argc] to 0 to null-terminate the args array. 60 | ctemp--; 61 | args[argc] = ctemp; 62 | // - push two more words onto the child's stack below 'args', 63 | // containing the argc and argv parameters to be passed 64 | // to the child's umain() function. 65 | u_int *pargv_ptr; 66 | pargv_ptr = args - 1; 67 | *pargv_ptr = USTACKTOP - TMPPAGETOP + (u_int)args; 68 | pargv_ptr--; 69 | *pargv_ptr = argc; 70 | // 71 | // - set *init_esp to the initial stack pointer for the child 72 | // 73 | *init_esp = USTACKTOP - TMPPAGETOP + (u_int)pargv_ptr; 74 | // *init_esp = USTACKTOP; // Change this! 75 | 76 | if ((r = syscall_mem_map(0, TMPPAGE, child, USTACKTOP - BY2PG, PTE_V | PTE_R)) < 0) 77 | goto error; 78 | if ((r = syscall_mem_unmap(0, TMPPAGE)) < 0) 79 | goto error; 80 | 81 | return 0; 82 | 83 | error: 84 | syscall_mem_unmap(0, TMPPAGE); 85 | return r; 86 | } 87 | 88 | int usr_is_elf_format(u_char *binary) 89 | { 90 | Elf32_Ehdr *ehdr = (Elf32_Ehdr *)binary; 91 | if (ehdr->e_ident[0] == ELFMAG0 && 92 | ehdr->e_ident[1] == ELFMAG1 && 93 | ehdr->e_ident[2] == ELFMAG2 && 94 | ehdr->e_ident[3] == ELFMAG3) 95 | { 96 | return 1; 97 | } 98 | 99 | return 0; 100 | } 101 | 102 | int usr_load_elf(int fd, Elf32_Phdr *ph, int child_envid) 103 | { 104 | //Hint: maybe this function is useful 105 | // If you want to use this func, you should fill it ,it's not hard 106 | // writef("QAQAQAQAQAQAQAQAQ\n"); 107 | u_long va = ph->p_vaddr; 108 | u_int32_t sgsize = ph->p_memsz; 109 | u_int32_t bin_size = ph->p_filesz; 110 | u_char *bin; 111 | u_long i; 112 | int r; 113 | u_long offset = va - ROUNDDOWN(va, BY2PG); 114 | r = read_map(fd, ph->p_offset, &bin); 115 | if (r < 0) 116 | return r; 117 | if (offset != 0) 118 | { 119 | if ((r = syscall_mem_alloc(child_envid, va, PTE_V | PTE_R)) < 0) 120 | return r; 121 | if ((r = syscall_mem_map(child_envid, va, 0, USTACKTOP, PTE_V | PTE_R)) < 0) 122 | return r; 123 | user_bcopy(bin, USTACKTOP + offset, MIN(BY2PG - offset, bin_size)); 124 | if ((r = syscall_mem_unmap(0, USTACKTOP)) < 0) 125 | return r; 126 | } 127 | for (i = offset ? MIN(BY2PG - offset, bin_size) : 0; i < bin_size; i += BY2PG) 128 | { 129 | if ((r = syscall_mem_alloc(child_envid, va + i, PTE_V | PTE_R)) < 0) 130 | return r; 131 | if ((r = syscall_mem_map(child_envid, va + i, 0, USTACKTOP, PTE_V | PTE_R)) < 0) 132 | return r; 133 | user_bcopy(bin + i, USTACKTOP, MIN(BY2PG, bin_size - i)); 134 | if ((r = syscall_mem_unmap(0, USTACKTOP)) < 0) 135 | return r; 136 | } 137 | while (i < sgsize) 138 | { 139 | if ((r = syscall_mem_alloc(child_envid, va + i, PTE_V | PTE_R)) < 0) 140 | return r; 141 | i += BY2PG; 142 | } 143 | return 0; 144 | } 145 | 146 | int spawn(char *prog, char **argv) 147 | { 148 | u_char elfbuf[512]; 149 | int r; 150 | int fd; 151 | u_int child_envid; 152 | int size, text_start; 153 | u_int i, *blk; 154 | u_int esp; 155 | Elf32_Ehdr *elf; 156 | Elf32_Phdr *ph; 157 | // Note 0: some variable may be not used,you can cancel them as you like 158 | // Step 1: Open the file specified by `prog` (prog is the path of the program) 159 | 160 | char progname[32]; 161 | int name_len = strlen(prog); 162 | strcpy(progname, prog); 163 | if (name_len <= 2 || prog[name_len - 1] != 'b' || prog[name_len - 2] != '.') 164 | { 165 | strcat(progname, ".b"); 166 | } 167 | 168 | if ((r = open(progname, O_RDONLY)) < 0) 169 | { 170 | // user_panic("spawn ::open line 102 RDONLY wrong !\n"); 171 | progname[strlen(progname) - 2] = 0; 172 | writef("command [%s] is not found.\n", progname); 173 | return r; 174 | } 175 | // Your code begins here 176 | fd = r; 177 | if ((r = readn(fd, elfbuf, sizeof(Elf32_Ehdr))) < 0) 178 | return r; 179 | 180 | elf = (Elf32_Ehdr *)elfbuf; 181 | 182 | // Before Step 2 , You had better check the "target" spawned is a execute bin 183 | if (!usr_is_elf_format(elf) || elf->e_type != 2) 184 | return -E_INVAL; 185 | 186 | // Step 2: Allocate an env (Hint: using syscall_env_alloc()) 187 | r = syscall_env_alloc(); 188 | if (r < 0) 189 | return r; 190 | if (r == 0) 191 | { 192 | env = envs + ENVX(syscall_getenvid()); 193 | return 0; 194 | } 195 | child_envid = r; 196 | 197 | // Step 3: Using init_stack(...) to initialize the stack of the allocated env 198 | init_stack(child_envid, argv, &esp); 199 | 200 | // Step 3: Map file's content to new env's text segment 201 | // Hint 1: what is the offset of the text segment in file? try to use objdump to find out. 202 | // Hint 2: using read_map(...) 203 | // Hint 3: Important!!! sometimes ,its not safe to use read_map ,guess why 204 | // If you understand, you can achieve the "load APP" with any method 205 | // Note1: Step 1 and 2 need sanity check. In other words, you should check whether 206 | // the file is opened successfully, and env is allocated successfully. 207 | // Note2: You can achieve this func in any way ,remember to ensure the correctness 208 | // Maybe you can review lab3 209 | // Your code ends here 210 | // writef("before copy\n"); 211 | // size = ((struct Filefd *)num2fd(fd))->f_file.f_size; 212 | text_start = elf->e_phoff; 213 | size = elf->e_phentsize; 214 | for (i = 0; i < elf->e_phnum; ++i) 215 | { 216 | if ((r = seek(fd, text_start)) < 0) 217 | return r; 218 | if ((r = readn(fd, elfbuf, size)) < 0) 219 | return r; 220 | ph = (Elf32_Phdr *)elfbuf; 221 | if (ph->p_type == PT_LOAD) 222 | { 223 | // writef("copy %d\n", i); 224 | r = usr_load_elf(fd, ph, child_envid); 225 | if (r < 0) 226 | return r; 227 | } 228 | text_start += size; 229 | } 230 | // writef("after copy\n"); 231 | 232 | struct Trapframe *tf; 233 | // writef("\n::::::::::spawn size : %x sp : %x::::::::\n", size * elf->e_phnum, esp); 234 | tf = &(envs[ENVX(child_envid)].env_tf); 235 | tf->pc = UTEXT; 236 | tf->regs[29] = esp; 237 | 238 | // Share memory 239 | u_int pdeno = 0; 240 | u_int pteno = 0; 241 | u_int pn = 0; 242 | u_int va = 0; 243 | for (pdeno = 0; pdeno < PDX(UTOP); pdeno++) 244 | { 245 | if (!((*vpd)[pdeno] & PTE_V)) 246 | continue; 247 | for (pteno = 0; pteno <= PTX(~0); pteno++) 248 | { 249 | pn = (pdeno << 10) + pteno; 250 | if (((*vpt)[pn] & PTE_V) && ((*vpt)[pn] & PTE_LIBRARY)) 251 | { 252 | va = pn * BY2PG; 253 | 254 | if ((r = syscall_mem_map(0, va, child_envid, va, (PTE_V | PTE_R | PTE_LIBRARY))) < 0) 255 | { 256 | 257 | writef("va: %x child_envid: %x \n", va, child_envid); 258 | user_panic("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 259 | return r; 260 | } 261 | } 262 | } 263 | } 264 | 265 | // writef("QAQAQAQAQAQAQAQAQ\n"); 266 | if ((r = syscall_set_env_status(child_envid, ENV_RUNNABLE)) < 0) 267 | { 268 | writef("set child runnable is wrong\n"); 269 | return r; 270 | } 271 | return child_envid; 272 | } 273 | 274 | int spawnl(char *prog, char *args, ...) 275 | { 276 | return spawn(prog, &args); 277 | } 278 | -------------------------------------------------------------------------------- /user/string.c: -------------------------------------------------------------------------------- 1 | // String routines. Not hardware optimized, but not shabby. 2 | 3 | #include "lib.h" 4 | 5 | int strlen(const char *s) 6 | { 7 | int n; 8 | 9 | for (n = 0; *s; s++) 10 | n++; 11 | return n; 12 | } 13 | 14 | char *strcpy(char *dst, const char *src) 15 | { 16 | char *ret; 17 | 18 | ret = dst; 19 | while ((*dst++ = *src++) != 0) 20 | ; 21 | return ret; 22 | } 23 | 24 | char *strcat(char *dst, const char *src) 25 | { 26 | char *ret = dst; 27 | while (*ret) 28 | ret++; 29 | while ((*ret++ = *src++) != 0) 30 | ; 31 | return dst; 32 | } 33 | 34 | const char *strchr(const char *s, char c) 35 | { 36 | for (; *s; s++) 37 | if (*s == c) 38 | return s; 39 | return 0; 40 | } 41 | 42 | void *memcpy(void *destaddr, void const *srcaddr, u_int len) 43 | { 44 | char *dest = destaddr; 45 | char const *src = srcaddr; 46 | 47 | while (len-- > 0) 48 | *dest++ = *src++; 49 | return destaddr; 50 | } 51 | 52 | int strcmp(const char *p, const char *q) 53 | { 54 | while (*p && *p == *q) 55 | p++, q++; 56 | if ((u_int)*p < (u_int)*q) 57 | return -1; 58 | if ((u_int)*p > (u_int)*q) 59 | return 1; 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /user/sum.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int get_num() 4 | { 5 | int num = 0; 6 | char ch; 7 | while (read(0, &ch, sizeof(char)) == sizeof(char)) 8 | { 9 | if (ch == '\n' || ch == '\r') 10 | break; 11 | num = (num << 1) + (num << 3) + ch - '0'; 12 | } 13 | return num; 14 | } 15 | 16 | void umain(int argc, char **argv) 17 | { 18 | int max = get_num(); // positive number 19 | int sum = 0; 20 | for (; max > 0; max--) 21 | sum += max; 22 | fwritef(1, "%d\n", sum); 23 | } 24 | -------------------------------------------------------------------------------- /user/syscall_lib.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void syscall_putchar(char ch) 8 | { 9 | msyscall(SYS_putchar, (int)ch, 0, 0, 0, 0); 10 | } 11 | 12 | u_int syscall_getenvid(void) 13 | { 14 | return msyscall(SYS_getenvid, 0, 0, 0, 0, 0); 15 | } 16 | 17 | void syscall_yield(void) 18 | { 19 | msyscall(SYS_yield, 0, 0, 0, 0, 0); 20 | } 21 | 22 | int syscall_set_pgfault_handler(u_int envid, void (*func)(void), u_int xstacktop) 23 | { 24 | return msyscall(SYS_set_pgfault_handler, envid, (int)func, xstacktop, 0, 0); 25 | } 26 | 27 | int syscall_mem_alloc(u_int envid, u_int va, u_int perm) 28 | { 29 | return msyscall(SYS_mem_alloc, envid, va, perm, 0, 0); 30 | } 31 | 32 | int syscall_mem_map(u_int srcid, u_int srcva, u_int dstid, u_int dstva, u_int perm) 33 | { 34 | return msyscall(SYS_mem_map, srcid, srcva, dstid, dstva, perm); 35 | } 36 | 37 | int syscall_mem_unmap(u_int envid, u_int va) 38 | { 39 | return msyscall(SYS_mem_unmap, envid, va, 0, 0, 0); 40 | } 41 | 42 | int syscall_set_env_status(u_int envid, u_int status) 43 | { 44 | return msyscall(SYS_set_env_status, envid, status, 0, 0, 0); 45 | } 46 | 47 | int syscall_set_trapframe(u_int envid, struct Trapframe *tf) 48 | { 49 | return msyscall(SYS_set_trapframe, envid, (int)tf, 0, 0, 0); 50 | } 51 | 52 | void syscall_panic(char *msg) 53 | { 54 | msyscall(SYS_panic, (int)msg, 0, 0, 0, 0); 55 | } 56 | 57 | int syscall_ipc_can_send(u_int envid, u_int value, u_int srcva, u_int perm) 58 | { 59 | return msyscall(SYS_ipc_can_send, envid, value, srcva, perm, 0); 60 | } 61 | 62 | void syscall_ipc_recv(u_int dstva) 63 | { 64 | msyscall(SYS_ipc_recv, dstva, 0, 0, 0, 0); 65 | } 66 | 67 | int syscall_cgetc() 68 | { 69 | return msyscall(SYS_cgetc, 0, 0, 0, 0, 0); 70 | } 71 | int syscall_write_dev(u_int va, u_int dev, u_int offset) 72 | { 73 | return msyscall(SYS_write_dev, va, dev, offset, 0, 0); 74 | } 75 | 76 | int syscall_read_dev(u_int va, u_int dev, u_int offset) 77 | { 78 | return msyscall(SYS_read_dev, va, dev, offset, 0, 0); 79 | } 80 | 81 | int syscall_wait_cons() 82 | { 83 | return msyscall(SYS_wait_cons, 0, 0, 0, 0, 0); 84 | } 85 | 86 | int syscall_signal_cons() 87 | { 88 | return msyscall(SYS_signal_cons, 0, 0, 0, 0, 0); 89 | } 90 | 91 | int syscall_set_env(char *name, char *value, int readonly) 92 | { 93 | return msyscall(SYS_set_env, name, value, readonly, 0, 0); 94 | } 95 | 96 | int syscall_get_env(char *name, char *value) 97 | { 98 | return msyscall(SYS_get_env, name, value, 0, 0, 0); 99 | } 100 | 101 | int syscall_list_env_var(env_var *list) 102 | { 103 | return msyscall(SYS_list_env_var, list, 0, 0, 0, 0); 104 | } 105 | -------------------------------------------------------------------------------- /user/syscall_wrap.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /*** exercise 4.1 ***/ 6 | LEAF(msyscall) 7 | // TODO: you JUST need to execute a `syscall` instruction and return from msyscall 8 | syscall 9 | nop 10 | jr ra 11 | nop 12 | END(msyscall) 13 | 14 | -------------------------------------------------------------------------------- /user/testarg.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | void umain(int argc, char **argv) 4 | { 5 | int i; 6 | for (i = 0; i < argc; i++) 7 | { 8 | writef("'''''''' %s '''''''''\n", argv[i]); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /user/testfdsharing.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | char buf[512], buf2[512]; 4 | 5 | int memcmp(char *a, char *b, int n) 6 | { 7 | int i; 8 | 9 | for (i = 0; i < n; i++) 10 | if (a[i] != b[i]) 11 | return 1; 12 | return 0; 13 | } 14 | 15 | void umain(int argc, char **argv) 16 | { 17 | int fd, r, n, n2; 18 | 19 | if ((fd = open("motd", O_RDONLY)) < 0) 20 | user_panic("open motd: %e", fd); 21 | seek(fd, 0); 22 | if ((n = readn(fd, buf, sizeof buf)) <= 0) 23 | user_panic("readn: %e", n); 24 | 25 | if ((r = fork()) < 0) 26 | user_panic("fork: %e", r); 27 | if (r == 0) 28 | { 29 | seek(fd, 0); 30 | writef("going to read in child (might page fault if your sharing is buggy)\n"); 31 | if ((n2 = readn(fd, buf2, sizeof buf2)) != n2) 32 | user_panic("read in parent got %d, read in child got %d", n, n2); 33 | if (memcmp(buf, buf2, n) != 0) 34 | user_panic("read in parent got different bytes from read in child"); 35 | writef("read in child succeeded\n"); 36 | seek(fd, 0); 37 | close(fd); 38 | exit(); 39 | } 40 | wait(r); 41 | //seek(fd, 0); 42 | if ((n2 = readn(fd, buf2, sizeof buf2)) != n) 43 | user_panic("read in parent got %d, then got %d", n, n2); 44 | writef("buf : %s\n", buf); 45 | writef("read in parent succeeded\n"); 46 | } 47 | -------------------------------------------------------------------------------- /user/testpipe.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | char *msg = "Now is the time for all good men to come to the aid of their party."; 4 | 5 | void umain(void) 6 | { 7 | char buf[100]; 8 | int i, pid, p[2]; 9 | 10 | if ((i = pipe(p)) < 0) 11 | user_panic("pipe: %e", i); 12 | 13 | if ((pid = fork()) < 0) 14 | user_panic("fork: %e", i); 15 | 16 | if (pid == 0) 17 | { 18 | writef("[%08x] pipereadeof close %d\n", env->env_id, p[1]); 19 | close(p[1]); 20 | writef("[%08x] pipereadeof readn %d\n", env->env_id, p[0]); 21 | i = readn(p[0], buf, sizeof buf - 1); 22 | if (i < 0) 23 | user_panic("read: %e", i); 24 | buf[i] = 0; 25 | if (strcmp(buf, msg) == 0) 26 | writef("\npipe read closed properly\n"); 27 | else 28 | writef("\ngot %d bytes: %s\n", i, buf); 29 | exit(); 30 | } 31 | else 32 | { 33 | writef("[%08x] pipereadeof close %d\n", env->env_id, p[0]); 34 | close(p[0]); 35 | writef("[%08x] pipereadeof write %d\n", env->env_id, p[1]); 36 | if ((i = write(p[1], msg, strlen(msg))) != strlen(msg)) 37 | user_panic("write: %e", i); 38 | close(p[1]); 39 | } 40 | wait(pid); 41 | 42 | if ((i = pipe(p)) < 0) 43 | user_panic("pipe: %e", i); 44 | 45 | if ((pid = fork()) < 0) 46 | user_panic("fork: %e", i); 47 | 48 | if (pid == 0) 49 | { 50 | close(p[0]); 51 | for (;;) 52 | { 53 | writef("."); 54 | if (write(p[1], "x", 1) != 1) 55 | break; 56 | } 57 | writef("\npipe write closed properly\n"); 58 | } 59 | close(p[0]); 60 | close(p[1]); 61 | wait(pid); 62 | 63 | writef("pipe tests passed\n"); 64 | } 65 | -------------------------------------------------------------------------------- /user/testpiperace.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | void umain(void) 4 | { 5 | int p[2], r, pid, i, max; 6 | u_int va; 7 | struct Fd *fd; 8 | struct Env *kid; 9 | 10 | writef("testing for dup race...\n"); 11 | if ((r = pipe(p)) < 0) 12 | user_panic("pipe: %e", r); 13 | max = 200; 14 | if ((r = fork()) < 0) 15 | user_panic("fork: %e", r); 16 | if (r == 0) 17 | { 18 | close(p[1]); 19 | // 20 | // Now the ref count for p[0] will toggle between 2 and 3 21 | // as the parent dups and closes it (there's a close implicit in dup). 22 | // 23 | // The ref count for p[1] is 1. 24 | // Thus the ref count for the underlying pipe structure 25 | // will toggle between 3 and 4. 26 | // 27 | // If a clock interrupt catches close between unmapping 28 | // the pipe structure and unmapping the fd, we'll have 29 | // a ref count for p[0] of 3, a ref count for p[1] of 1, 30 | // and a ref count for the pipe structure of 3, which is 31 | // a no-no. 32 | // 33 | // If a clock interrupt catches dup between mapping the 34 | // fd and mapping the pipe structure, we'll have the same 35 | // ref counts, still a no-no. 36 | // 37 | for (i = 0; i < max; i++) 38 | { 39 | if (pipeisclosed(p[0])) 40 | { 41 | writef("RACE: pipe appears closed\n"); 42 | exit(); 43 | } 44 | syscall_yield(); 45 | } 46 | // do something to be not runnable besides exiting 47 | ipc_recv(0, 0, 0); 48 | } 49 | pid = r; 50 | writef("pid is %d\n", pid); 51 | va = 0; 52 | kid = &envs[ENVX(pid)]; 53 | writef("kid is %d\n", kid - envs); 54 | dup(p[0], 10); 55 | while (kid->env_status == ENV_RUNNABLE) 56 | dup(p[0], 10); 57 | 58 | writef("child done with loop\n"); 59 | if (pipeisclosed(p[0])) 60 | user_panic("somehow the other end of p[0] got closed!"); 61 | if ((r = fd_lookup(p[0], &fd)) < 0) 62 | user_panic("cannot look up p[0]: %e", r); 63 | va = fd2data(fd); 64 | if (pageref((void *)va) != 3 + 1) 65 | writef("\nchild detected race\n"); 66 | else 67 | writef("\nrace didn't happen\n", max); 68 | } 69 | -------------------------------------------------------------------------------- /user/testptelibrary.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #define TMPVA ((char *)0x50005000) 3 | const char *msg = "hello world!\n"; 4 | const char *msg2 = "goodbye ,world!\n"; 5 | 6 | void childofspawn(void); 7 | 8 | void umain(int argc, char **argv) 9 | { 10 | int r; 11 | if (argc != 0) 12 | childofspawn(); 13 | 14 | if ((r = syscall_mem_alloc(0, TMPVA, PTE_R | PTE_V | PTE_LIBRARY)) < 0) 15 | user_panic("syscall error!"); 16 | if ((r = fork()) < 0) 17 | user_panic("fork: %d", r); 18 | if (r == 0) 19 | { 20 | strcpy(TMPVA, msg); 21 | exit(); 22 | } 23 | 24 | wait(r); 25 | writef("TMPVAis %s \n", TMPVA); 26 | if (strcmp(TMPVA, msg) == 0) 27 | writef("fork solved the problem of PTE_LIBRARY,congratulations!\n"); 28 | else 29 | user_panic("sorry , your fork may be wrong\n"); 30 | if ((r = spawnl("testptelibrary.b", "testptelibrary", "arg", 0)) < 0) 31 | user_panic("spawn wrong: %d", r); 32 | wait(r); 33 | if (strcmp(TMPVA, msg2) == 0) 34 | writef("spawn solved the problem of PTE_LIBRARY,congratulations!\n"); 35 | else 36 | user_panic("sorry , your spawn may be wrong\n"); 37 | } 38 | 39 | void childofspawn(void) 40 | { 41 | strcpy(TMPVA, msg2); 42 | exit(); 43 | } 44 | -------------------------------------------------------------------------------- /user/touch.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | void umain(int argc, char **argv) 4 | { 5 | if (argc != 2) 6 | { 7 | fwritef(1, "usage: touch file_name\n"); 8 | return; 9 | } 10 | int fd = open(argv[1], O_RDONLY); 11 | if (fd >= 0) 12 | { 13 | fwritef(1, "file duplicated\n"); 14 | return; 15 | } 16 | if (create(argv[1], FTYPE_REG) < 0) 17 | { 18 | fwritef(1, "fail to create file\n"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /user/tree.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | char path[MAXPATHLEN]; 4 | 5 | void tree(char *curdir, int indent) 6 | { 7 | int fd, n; 8 | char buf[MAXNAMELEN]; 9 | struct File f; 10 | 11 | fd = open(curdir, O_RDONLY); 12 | if (fd < 0) 13 | { 14 | user_panic("open %s: %e", curdir, fd); 15 | } 16 | 17 | int i; 18 | 19 | while ((n = readn(fd, &f, sizeof(struct File))) == sizeof(struct File)) 20 | { 21 | if (f.f_name[0]) 22 | { 23 | for (i = 0; i < indent; ++i) 24 | { 25 | fwritef(1, "| "); 26 | } 27 | if (f.f_type == FTYPE_DIR) 28 | { 29 | fwritef(1, "|-- \x1b[36m%s\x1b[0m\n", f.f_name); 30 | strcpy(buf, curdir); 31 | strcat(buf, f.f_name); 32 | strcat(buf, "/"); 33 | tree(buf, indent + 1); 34 | } 35 | else 36 | { 37 | fwritef(1, f.f_type == FTYPE_BIN ? "|-- \x1b[31m%s\x1b[0m\n" : "|-- %s\n", f.f_name); 38 | } 39 | } 40 | } 41 | 42 | close(fd); 43 | if (n) 44 | user_panic("error in directory %s: %e", curdir, n); 45 | } 46 | 47 | void usage() 48 | { 49 | fwritef(1, "usage: tree [path]\n"); 50 | } 51 | 52 | void umain(int argc, char **argv) 53 | { 54 | if (argc > 2) 55 | { 56 | usage(); 57 | return; 58 | } 59 | struct Stat st; 60 | if (argc == 1) 61 | tree("/", 0); 62 | else 63 | { 64 | strcpy(path, argv[1]); 65 | if (stat(path, &st) < 0) 66 | { 67 | fwritef(1, "cannot open directory\n"); 68 | return; 69 | } 70 | if (st.st_type != FTYPE_DIR) 71 | { 72 | fwritef(1, "specified path should be directory\n"); 73 | return; 74 | } 75 | if (path[strlen(path) - 1] != '/') 76 | strcat(path, "/"); 77 | tree(path, 0); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /user/user.lds: -------------------------------------------------------------------------------- 1 | /* ld script to make i386 Linux kernel 2 | * Written by Martin Mares ; 3 | */ 4 | OUTPUT_ARCH(mips) 5 | ENTRY(_start) 6 | SECTIONS 7 | { 8 | . = 0x00400000; 9 | 10 | _text = .; /* Text and read-only data */ 11 | .text : { 12 | *(.text) 13 | *(.fixup) 14 | *(.gnu.warning) 15 | } 16 | 17 | _etext = .; /* End of text section */ 18 | 19 | .data : { /* Data */ 20 | *(.data) 21 | *(.rodata) 22 | *(.rodata.*) 23 | *(.eh_frame) 24 | CONSTRUCTORS 25 | } 26 | 27 | _edata = .; /* End of data section */ 28 | 29 | 30 | 31 | __bss_start = .; /* BSS */ 32 | .bss : { 33 | *(.bss) 34 | } 35 | /DISCARD/ : { 36 | *(.comment) 37 | *(.debug_*) 38 | } 39 | end = . ; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /user/wait.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #include 3 | void wait(u_int envid) 4 | { 5 | struct Env *e; 6 | 7 | //writef("envid:%x wait()~~~~~~~~~",envid); 8 | e = &envs[ENVX(envid)]; 9 | while (e->env_id == envid && e->env_status != ENV_FREE) 10 | syscall_yield(); 11 | } 12 | --------------------------------------------------------------------------------