├── .gitignore
├── LICENSE
├── README.md
└── code
├── Makefile
├── boot
├── asm.h
├── bootasm.S
└── bootmain.c
├── disk0
├── script
│ ├── test1.sh
│ ├── test2.sh
│ └── test3.sh
├── test
│ └── testfile
└── testman
│ ├── awk
│ ├── coreutils
│ ├── cat
│ ├── cp
│ ├── ls
│ ├── mv
│ └── rm
│ ├── cpp
│ ├── gcc
│ ├── gdb
│ ├── ld
│ ├── sed
│ └── zsh
├── kern
├── debug
│ ├── assert.h
│ ├── kdebug.c
│ ├── kdebug.h
│ ├── monitor.c
│ ├── monitor.h
│ ├── panic.c
│ └── stab.h
├── driver
│ ├── clock.c
│ ├── clock.h
│ ├── console.c
│ ├── console.h
│ ├── ide.c
│ ├── ide.h
│ ├── intr.c
│ ├── intr.h
│ ├── kbdreg.h
│ ├── picirq.c
│ └── picirq.h
├── fs
│ ├── devs
│ │ ├── dev.c
│ │ ├── dev.h
│ │ ├── dev_disk0.c
│ │ ├── dev_null.c
│ │ ├── dev_stdin.c
│ │ └── dev_stdout.c
│ ├── file.c
│ ├── file.h
│ ├── fs.c
│ ├── fs.h
│ ├── iobuf.c
│ ├── iobuf.h
│ ├── pipe
│ │ ├── pipe.c
│ │ ├── pipe.h
│ │ ├── pipe_inode.c
│ │ ├── pipe_root.c
│ │ ├── pipe_state.c
│ │ └── pipe_state.h
│ ├── sfs
│ │ ├── bitmap.c
│ │ ├── bitmap.h
│ │ ├── sfs.c
│ │ ├── sfs.h
│ │ ├── sfs_fs.c
│ │ ├── sfs_inode.c
│ │ ├── sfs_io.c
│ │ └── sfs_lock.c
│ ├── swap
│ │ ├── swapfs.c
│ │ └── swapfs.h
│ ├── sysfile.c
│ ├── sysfile.h
│ └── vfs
│ │ ├── inode.c
│ │ ├── inode.h
│ │ ├── vfs.c
│ │ ├── vfs.h
│ │ ├── vfsdev.c
│ │ ├── vfsfile.c
│ │ ├── vfslookup.c
│ │ └── vfspath.c
├── init
│ ├── entry.S
│ └── init.c
├── libs
│ ├── rb_tree.c
│ ├── rb_tree.h
│ ├── readline.c
│ ├── stdio.c
│ └── string.c
├── mm
│ ├── buddy_pmm.c
│ ├── buddy_pmm.h
│ ├── memlayout.h
│ ├── mmu.h
│ ├── pmm.c
│ ├── pmm.h
│ ├── shmem.c
│ ├── shmem.h
│ ├── slab.c
│ ├── slab.h
│ ├── swap.c
│ ├── swap.h
│ ├── vmm.c
│ └── vmm.h
├── process
│ ├── entry.S
│ ├── proc.c
│ ├── proc.h
│ └── switch.S
├── schedule
│ ├── sched.c
│ ├── sched.h
│ ├── sched_MLFQ.c
│ ├── sched_MLFQ.h
│ ├── sched_RR.c
│ └── sched_RR.h
├── sync
│ ├── event.c
│ ├── event.h
│ ├── ipc.h
│ ├── mbox.c
│ ├── mbox.h
│ ├── sem.c
│ ├── sem.h
│ ├── sync.c
│ ├── sync.h
│ ├── wait.c
│ └── wait.h
├── syscall
│ ├── syscall.c
│ └── syscall.h
└── trap
│ ├── trap.c
│ ├── trap.h
│ ├── trapentry.S
│ └── vectors.S
├── libs
├── atomic.h
├── dirent.h
├── elf.h
├── error.h
├── hash.c
├── list.h
├── mboxbuf.h
├── printfmt.c
├── rand.c
├── stat.h
├── stdarg.h
├── stdio.h
├── stdlib.h
├── string.c
├── string.h
├── types.h
├── unistd.h
└── x86.h
├── tools
├── function.mk
├── gdbinit
├── grade.sh
├── kernel.ld
├── mksfs.c
├── sign.c
├── user.ld
└── vector.c
└── user
├── badarg.c
├── badbrktest.c
├── badsegment.c
├── brkfreetest.c
├── brktest.c
├── buggy_event.c
├── buggy_wait.c
├── buggy_wait2.c
├── cat.c
├── cowtest.c
├── divzero.c
├── echo.c
├── eventtest.c
├── exit.c
├── faultread.c
├── faultreadkernel.c
├── forktest.c
├── forktree.c
├── fread_test.c
├── fread_test2.c
├── fwrite_test.c
├── hello.c
├── hello2.c
├── libs
├── clone.S
├── dir.c
├── dir.h
├── file.c
├── file.h
├── initcode.S
├── lock.h
├── malloc.c
├── malloc.h
├── panic.c
├── spipe.c
├── spipe.h
├── stdio.c
├── string.c
├── syscall.c
├── syscall.h
├── thread.c
├── thread.h
├── ulib.c
├── ulib.h
└── umain.c
├── link.c
├── ls.c
├── matrix.c
├── mboxmap.c
├── mboxtest.c
├── mkdir.c
├── mmaptest.c
├── nulldevfs_test.c
├── pgdir.c
├── pipetest.c
├── pipetest2.c
├── primer.c
├── primer2.c
├── primer3.c
├── pwd.c
├── rename.c
├── robot.c
├── sem_rf.c
├── sem_wf.c
├── semtest.c
├── semtest2.c
├── semtest3.c
├── semtest4.c
├── sfs_dirtest1.c
├── sfs_dirtest2.c
├── sfs_dirtest3.c
├── sfs_exectest1.c
├── sfs_exectest2.c
├── sfs_filetest1.c
├── sfs_filetest2.c
├── sfs_filetest3.c
├── sh.c
├── shmemtest.c
├── sleep.c
├── sleepkill.c
├── softint.c
├── spin.c
├── spipetest.c
├── spipetest2.c
├── swaptest.c
├── testbss.c
├── threadfork.c
├── threadgroup1.c
├── threadgroup2.c
├── threadtest.c
├── threadwork.c
├── unlink.c
├── waitkill.c
└── yield.c
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 | obj/
3 | *~
4 | *.bak
5 | *.d
6 | *.o
7 | *.org
8 | .gdb.in
9 | .qemu.out
10 |
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 一步一步构建ucore OS(配套代码)
2 | ======================
3 | "操作系统简单实现与基本原理 — 基于ucore" (持续更新) http://chyyuu.gitbooks.io/ucorebook/
4 |
5 | 介绍
6 | ======================
7 | ucore OS是用于清华大学计算机系本科操作系统课程的OS教学试验内容。
8 | ucore OS起源于MIT CSAIL PDOS课题组开发的xv6&jos、哈佛大学开发的
9 | OS161教学操作系统、以及Linux-2.4内核。
10 |
11 | ucore OS中包含的xv6&jos代码版权属于Frans Kaashoek, Robert Morris,
12 | and Russ Cox,使用MIT License。ucore OS中包含的OS/161代码版权属于
13 | David A. Holland。其他代码版权属于陈渝、王乃铮、向勇,并采用GPL License.
14 | ucore OS相关的文档版权属于陈渝、向勇,并采用 Creative Commons
15 | Attribution/Share-Alike (CC-BY-SA) License.
16 |
17 | 开发维护人员
18 | ======================
19 | * 陈渝 http://soft.cs.tsinghua.edu.cn/~chen
20 | * 茅俊杰 eternal.n08 AT gmail.com
21 |
22 | 相关资料
23 | ======================
24 | * https://github.com/chyyuu/mooc_os
25 |
--------------------------------------------------------------------------------
/code/boot/asm.h:
--------------------------------------------------------------------------------
1 | #ifndef __BOOT_ASM_H__
2 | #define __BOOT_ASM_H__
3 |
4 | /* Assembler macros to create x86 segments */
5 |
6 | /* Normal segment */
7 | #define SEG_NULLASM \
8 | .word 0, 0; \
9 | .byte 0, 0, 0, 0
10 |
11 | #define SEG_ASM(type,base,lim) \
12 | .word (((lim) >> 12) & 0xffff), ((base) & 0xffff); \
13 | .byte (((base) >> 16) & 0xff), (0x90 | (type)), \
14 | (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff)
15 |
16 |
17 | /* Application segment type bits */
18 | #define STA_X 0x8 // Executable segment
19 | #define STA_E 0x4 // Expand down (non-executable segments)
20 | #define STA_C 0x4 // Conforming code segment (executable only)
21 | #define STA_W 0x2 // Writeable (non-executable segments)
22 | #define STA_R 0x2 // Readable (executable segments)
23 | #define STA_A 0x1 // Accessed
24 |
25 | #endif /* !__BOOT_ASM_H__ */
26 |
27 |
--------------------------------------------------------------------------------
/code/disk0/script/test1.sh:
--------------------------------------------------------------------------------
1 | ls
2 | cd test
3 | pwd
4 | ls /testman > xx
5 | cat xx
6 | unlink xx
7 | echo test1.sh end.
8 |
9 |
--------------------------------------------------------------------------------
/code/disk0/script/test2.sh:
--------------------------------------------------------------------------------
1 | cd test
2 | mkdir pp
3 | cd pp
4 | ls /bin | cat > qq
5 | link qq pp
6 | ls
7 | cd ..
8 | link pp/pp orz
9 | unlink pp/pp pp/qq
10 | rename pp qq
11 | unlink qq
12 | unlink orz
13 | echo test2.sh end.
14 |
15 |
--------------------------------------------------------------------------------
/code/disk0/script/test3.sh:
--------------------------------------------------------------------------------
1 | cat script/test2.sh > test/tmp.sh
2 | ls test
3 | sh < test/tmp.sh
4 | unlink test/tmp.sh
5 | echo test3.sh end.
6 |
7 |
--------------------------------------------------------------------------------
/code/disk0/test/testfile:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chyyuu/ucorebook_code/18da356a2f3ef90680aca9cc50ef328d1e84585e/code/disk0/test/testfile
--------------------------------------------------------------------------------
/code/disk0/testman/coreutils/cat:
--------------------------------------------------------------------------------
1 | CAT(1) User Commands CAT(1)
2 |
3 |
4 |
5 | NAME
6 | cat - concatenate files and print on the standard output
7 |
8 | SYNOPSIS
9 | cat [OPTION]... [FILE]...
10 |
11 | DESCRIPTION
12 | Concatenate FILE(s), or standard input, to standard output.
13 |
14 | -A, --show-all
15 | equivalent to -vET
16 |
17 | -b, --number-nonblank
18 | number nonempty output lines
19 |
20 | -e equivalent to -vE
21 |
22 | -E, --show-ends
23 | display $ at end of each line
24 |
25 | -n, --number
26 | number all output lines
27 |
28 | -s, --squeeze-blank
29 | suppress repeated empty output lines
30 |
31 | -t equivalent to -vT
32 |
33 | -T, --show-tabs
34 | display TAB characters as ^I
35 |
36 | -u (ignored)
37 |
38 | -v, --show-nonprinting
39 | use ^ and M- notation, except for LFD and TAB
40 |
41 | --help display this help and exit
42 |
43 | --version
44 | output version information and exit
45 |
46 | With no FILE, or when FILE is -, read standard input.
47 |
48 | EXAMPLES
49 | cat f - g
50 | Output f's contents, then standard input, then g's contents.
51 |
52 | cat Copy standard input to standard output.
53 |
54 | AUTHOR
55 | Written by Torbjorn Granlund and Richard M. Stallman.
56 |
57 | REPORTING BUGS
58 | Report cat bugs to bug-coreutils@gnu.org
59 | GNU coreutils home page:
60 | General help using GNU software:
61 | Report cat translation bugs to
62 |
63 | COPYRIGHT
64 | Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU
65 | GPL version 3 or later .
66 | This is free software: you are free to change and redistribute it.
67 | There is NO WARRANTY, to the extent permitted by law.
68 |
69 | SEE ALSO
70 | The full documentation for cat is maintained as a Texinfo manual. If
71 | the info and cat programs are properly installed at your site, the com-
72 | mand
73 |
74 | info coreutils 'cat invocation'
75 |
76 | should give you access to the complete manual.
77 |
78 |
79 |
80 | GNU coreutils 8.5 April 2010 CAT(1)
81 |
--------------------------------------------------------------------------------
/code/disk0/testman/coreutils/mv:
--------------------------------------------------------------------------------
1 | MV(1) User Commands MV(1)
2 |
3 |
4 |
5 | NAME
6 | mv - move (rename) files
7 |
8 | SYNOPSIS
9 | mv [OPTION]... [-T] SOURCE DEST
10 | mv [OPTION]... SOURCE... DIRECTORY
11 | mv [OPTION]... -t DIRECTORY SOURCE...
12 |
13 | DESCRIPTION
14 | Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
15 |
16 | Mandatory arguments to long options are mandatory for short options
17 | too.
18 |
19 | --backup[=CONTROL]
20 | make a backup of each existing destination file
21 |
22 | -b like --backup but does not accept an argument
23 |
24 | -f, --force
25 | do not prompt before overwriting
26 |
27 | -i, --interactive
28 | prompt before overwrite
29 |
30 | -n, --no-clobber
31 | do not overwrite an existing file
32 |
33 | If you specify more than one of -i, -f, -n, only the final one takes
34 | effect.
35 |
36 | --strip-trailing-slashes
37 | remove any trailing slashes from each SOURCE argument
38 |
39 | -S, --suffix=SUFFIX
40 | override the usual backup suffix
41 |
42 | -t, --target-directory=DIRECTORY
43 | move all SOURCE arguments into DIRECTORY
44 |
45 | -T, --no-target-directory
46 | treat DEST as a normal file
47 |
48 | -u, --update
49 | move only when the SOURCE file is newer than the destination
50 | file or when the destination file is missing
51 |
52 | -v, --verbose
53 | explain what is being done
54 |
55 | --help display this help and exit
56 |
57 | --version
58 | output version information and exit
59 |
60 | The backup suffix is `~', unless set with --suffix or SIM-
61 | PLE_BACKUP_SUFFIX. The version control method may be selected via the
62 | --backup option or through the VERSION_CONTROL environment variable.
63 | Here are the values:
64 |
65 | none, off
66 | never make backups (even if --backup is given)
67 |
68 | numbered, t
69 | make numbered backups
70 |
71 | existing, nil
72 | numbered if numbered backups exist, simple otherwise
73 |
74 | simple, never
75 | always make simple backups
76 |
77 | AUTHOR
78 | Written by Mike Parker, David MacKenzie, and Jim Meyering.
79 |
80 | REPORTING BUGS
81 | Report mv bugs to bug-coreutils@gnu.org
82 | GNU coreutils home page:
83 | General help using GNU software:
84 | Report mv translation bugs to
85 |
86 | COPYRIGHT
87 | Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU
88 | GPL version 3 or later .
89 | This is free software: you are free to change and redistribute it.
90 | There is NO WARRANTY, to the extent permitted by law.
91 |
92 | SEE ALSO
93 | rename(2)
94 |
95 | The full documentation for mv is maintained as a Texinfo manual. If
96 | the info and mv programs are properly installed at your site, the com-
97 | mand
98 |
99 | info coreutils 'mv invocation'
100 |
101 | should give you access to the complete manual.
102 |
103 |
104 |
105 | GNU coreutils 8.5 April 2010 MV(1)
106 |
--------------------------------------------------------------------------------
/code/kern/debug/assert.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_DEBUG_ASSERT_H__
2 | #define __KERN_DEBUG_ASSERT_H__
3 |
4 | void __warn(const char *file, int line, const char *fmt, ...);
5 | void __panic(const char *file, int line, const char *fmt, ...) __attribute__((noreturn));
6 |
7 | #define warn(...) \
8 | __warn(__FILE__, __LINE__, __VA_ARGS__)
9 |
10 | #define panic(...) \
11 | __panic(__FILE__, __LINE__, __VA_ARGS__)
12 |
13 | #define assert(x) \
14 | do { \
15 | if (!(x)) { \
16 | panic("assertion failed: %s", #x); \
17 | } \
18 | } while (0)
19 |
20 | // static_assert(x) will generate a compile-time error if 'x' is false.
21 | #define static_assert(x) \
22 | switch (x) { case 0: case (x): ; }
23 |
24 | #endif /* !__KERN_DEBUG_ASSERT_H__ */
25 |
26 |
--------------------------------------------------------------------------------
/code/kern/debug/kdebug.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_DEBUG_KDEBUG_H__
2 | #define __KERN_DEBUG_KDEBUG_H__
3 |
4 | #include
5 | #include
6 |
7 | void print_kerninfo(void);
8 | void print_stackframe(void);
9 | void print_debuginfo(uintptr_t eip);
10 |
11 | // number of debug registers
12 | #define MAX_DR_NUM 4
13 |
14 | // index of DR6-Debug status and DR7-Debug control
15 | #define DR_STATUS 6
16 | #define DR_CONTROL 7
17 |
18 | /* DR6 Register */
19 | #define DR6_B0_BIT 0x00000001
20 | #define DR6_B1_BIT 0x00000002
21 | #define DR6_B2_BIT 0x00000004
22 | #define DR6_B3_BIT 0x00000008
23 |
24 | /* DR7 Register */
25 | #define DR7_L0_BIT 0x00000001
26 | #define DR7_G0_BIT 0x00000002
27 | #define DR7_L1_BIT 0x00000004
28 | #define DR7_G1_BIT 0x00000008
29 | #define DR7_L2_BIT 0x00000010
30 | #define DR7_G2_BIT 0x00000020
31 | #define DR7_L3_BIT 0x00000040
32 | #define DR7_G3_BIT 0x00000080
33 | #define DR7_LEXACT 0x00000100
34 | #define DR7_GEXACT 0x00000200
35 | #define DR7_GDETECT 0x00002000
36 | #define DR7_MASK 0xFFFF0000
37 |
38 | void debug_init(void);
39 | void debug_monitor(struct trapframe *tf);
40 | void debug_list_dr(void);
41 | int debug_enable_dr(unsigned regnum, uintptr_t addr, unsigned type, unsigned len);
42 | int debug_disable_dr(unsigned regnum);
43 |
44 | #endif /* !__KERN_DEBUG_KDEBUG_H__ */
45 |
46 |
--------------------------------------------------------------------------------
/code/kern/debug/monitor.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_DEBUG_MONITOR_H__
2 | #define __KERN_DEBUG_MONITOR_H__
3 |
4 | #include
5 |
6 | void monitor(struct trapframe *tf);
7 |
8 | int mon_help(int argc, char **argv, struct trapframe *tf);
9 | int mon_kerninfo(int argc, char **argv, struct trapframe *tf);
10 | int mon_backtrace(int argc, char **argv, struct trapframe *tf);
11 | int mon_continue(int argc, char **argv, struct trapframe *tf);
12 | int mon_step(int argc, char **argv, struct trapframe *tf);
13 | int mon_breakpoint(int argc, char **argv, struct trapframe *tf);
14 | int mon_watchpoint(int argc, char **argv, struct trapframe *tf);
15 | int mon_delete_dr(int argc, char **argv, struct trapframe *tf);
16 | int mon_list_dr(int argc, char **argv, struct trapframe *tf);
17 |
18 | #endif /* !__KERN_DEBUG_MONITOR_H__ */
19 |
20 |
--------------------------------------------------------------------------------
/code/kern/debug/panic.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | static bool is_panic = 0;
7 |
8 | /* *
9 | * __panic - __panic is called on unresolvable fatal errors. it prints
10 | * "panic: 'message'", and then enters the kernel monitor.
11 | * */
12 | void
13 | __panic(const char *file, int line, const char *fmt, ...) {
14 | if (is_panic) {
15 | goto panic_dead;
16 | }
17 | is_panic = 1;
18 |
19 | // print the 'message'
20 | va_list ap;
21 | va_start(ap, fmt);
22 | cprintf("kernel panic at %s:%d:\n ", file, line);
23 | vcprintf(fmt, ap);
24 | cprintf("\n");
25 | va_end(ap);
26 |
27 | panic_dead:
28 | intr_disable();
29 | while (1) {
30 | monitor(NULL);
31 | }
32 | }
33 |
34 | /* __warn - like panic, but don't */
35 | void
36 | __warn(const char *file, int line, const char *fmt, ...) {
37 | va_list ap;
38 | va_start(ap, fmt);
39 | cprintf("kernel warning at %s:%d:\n ", file, line);
40 | vcprintf(fmt, ap);
41 | cprintf("\n");
42 | va_end(ap);
43 | }
44 |
45 | bool
46 | is_kernel_panic(void) {
47 | return is_panic;
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/code/kern/debug/stab.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_DEBUG_STAB_H__
2 | #define __KERN_DEBUG_STAB_H__
3 |
4 | #include
5 |
6 | /* *
7 | * STABS debugging info
8 | *
9 | * The kernel debugger can understand some debugging information in
10 | * the STABS format. For more information on this format, see
11 | * http://sources.redhat.com/gdb/onlinedocs/stabs_toc.html
12 | *
13 | * The constants below define some symbol types used by various debuggers
14 | * and compilers. Kernel uses the N_SO, N_SOL, N_FUN, and N_SLINE types.
15 | * */
16 |
17 | #define N_GSYM 0x20 // global symbol
18 | #define N_FNAME 0x22 // F77 function name
19 | #define N_FUN 0x24 // procedure name
20 | #define N_STSYM 0x26 // data segment variable
21 | #define N_LCSYM 0x28 // bss segment variable
22 | #define N_MAIN 0x2a // main function name
23 | #define N_PC 0x30 // global Pascal symbol
24 | #define N_RSYM 0x40 // register variable
25 | #define N_SLINE 0x44 // text segment line number
26 | #define N_DSLINE 0x46 // data segment line number
27 | #define N_BSLINE 0x48 // bss segment line number
28 | #define N_SSYM 0x60 // structure/union element
29 | #define N_SO 0x64 // main source file name
30 | #define N_LSYM 0x80 // stack variable
31 | #define N_BINCL 0x82 // include file beginning
32 | #define N_SOL 0x84 // included source file name
33 | #define N_PSYM 0xa0 // parameter variable
34 | #define N_EINCL 0xa2 // include file end
35 | #define N_ENTRY 0xa4 // alternate entry point
36 | #define N_LBRAC 0xc0 // left bracket
37 | #define N_EXCL 0xc2 // deleted include file
38 | #define N_RBRAC 0xe0 // right bracket
39 | #define N_BCOMM 0xe2 // begin common
40 | #define N_ECOMM 0xe4 // end common
41 | #define N_ECOML 0xe8 // end common (local name)
42 | #define N_LENG 0xfe // length of preceding entry
43 |
44 | /* Entries in the STABS table are formatted as follows. */
45 | struct stab {
46 | uint32_t n_strx; // index into string table of name
47 | uint8_t n_type; // type of symbol
48 | uint8_t n_other; // misc info (usually empty)
49 | uint16_t n_desc; // description field
50 | uintptr_t n_value; // value of symbol
51 | };
52 |
53 | #endif /* !__KERN_DEBUG_STAB_H__ */
54 |
55 |
--------------------------------------------------------------------------------
/code/kern/driver/clock.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | /* *
7 | * Support for time-related hardware gadgets - the 8253 timer,
8 | * which generates interruptes on IRQ-0.
9 | * */
10 |
11 | #define IO_TIMER1 0x040 // 8253 Timer #1
12 |
13 | /* *
14 | * Frequency of all three count-down timers; (TIMER_FREQ/freq)
15 | * is the appropriate count to generate a frequency of freq Hz.
16 | * */
17 |
18 | #define TIMER_FREQ 1193182
19 | #define TIMER_DIV(x) ((TIMER_FREQ + (x) / 2) / (x))
20 |
21 | #define TIMER_MODE (IO_TIMER1 + 3) // timer mode port
22 | #define TIMER_SEL0 0x00 // select counter 0
23 | #define TIMER_RATEGEN 0x04 // mode 2, rate generator
24 | #define TIMER_16BIT 0x30 // r/w counter 16 bits, LSB first
25 |
26 | volatile size_t ticks;
27 |
28 | /* *
29 | * clock_init - initialize 8253 clock to interrupt 100 times per second,
30 | * and then enable IRQ_TIMER.
31 | * */
32 | void
33 | clock_init(void) {
34 | // set 8253 timer-chip
35 | outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
36 | outb(IO_TIMER1, TIMER_DIV(100) % 256);
37 | outb(IO_TIMER1, TIMER_DIV(100) / 256);
38 |
39 | // initialize time counter 'ticks' to zero
40 | ticks = 0;
41 |
42 | cprintf("++ setup timer interrupts\n");
43 | pic_enable(IRQ_TIMER);
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/code/kern/driver/clock.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_DRIVER_CLOCK_H__
2 | #define __KERN_DRIVER_CLOCK_H__
3 |
4 | #include
5 |
6 | extern volatile size_t ticks;
7 |
8 | void clock_init(void);
9 |
10 | #endif /* !__KERN_DRIVER_CLOCK_H__ */
11 |
12 |
--------------------------------------------------------------------------------
/code/kern/driver/console.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_DRIVER_CONSOLE_H__
2 | #define __KERN_DRIVER_CONSOLE_H__
3 |
4 | void cons_init(void);
5 | void cons_putc(int c);
6 | int cons_getc(void);
7 | void serial_intr(void);
8 | void kbd_intr(void);
9 |
10 | #endif /* !__KERN_DRIVER_CONSOLE_H__ */
11 |
12 |
--------------------------------------------------------------------------------
/code/kern/driver/ide.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_DRIVER_IDE_H__
2 | #define __KERN_DRIVER_IDE_H__
3 |
4 | #include
5 |
6 | void ide_init(void);
7 | bool ide_device_valid(unsigned short ideno);
8 | size_t ide_device_size(unsigned short ideno);
9 |
10 | int ide_read_secs(unsigned short ideno, uint32_t secno, void *dst, size_t nsecs);
11 | int ide_write_secs(unsigned short ideno, uint32_t secno, const void *src, size_t nsecs);
12 |
13 | #endif /* !__KERN_DRIVER_IDE_H__ */
14 |
15 |
--------------------------------------------------------------------------------
/code/kern/driver/intr.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | /* intr_enable - enable irq interrupt */
5 | void
6 | intr_enable(void) {
7 | sti();
8 | }
9 |
10 | /* intr_disable - disable irq interrupt */
11 | void
12 | intr_disable(void) {
13 | cli();
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/code/kern/driver/intr.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_DRIVER_INTR_H__
2 | #define __KERN_DRIVER_INTR_H__
3 |
4 | void intr_enable(void);
5 | void intr_disable(void);
6 |
7 | #endif /* !__KERN_DRIVER_INTR_H__ */
8 |
9 |
--------------------------------------------------------------------------------
/code/kern/driver/picirq.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | // I/O Addresses of the two programmable interrupt controllers
6 | #define IO_PIC1 0x20 // Master (IRQs 0-7)
7 | #define IO_PIC2 0xA0 // Slave (IRQs 8-15)
8 |
9 | #define IRQ_SLAVE 2 // IRQ at which slave connects to master
10 |
11 | // Current IRQ mask.
12 | // Initial IRQ mask has interrupt 2 enabled (for slave 8259A).
13 | static uint16_t irq_mask = 0xFFFF & ~(1 << IRQ_SLAVE);
14 | static bool did_init = 0;
15 |
16 | static void
17 | pic_setmask(uint16_t mask) {
18 | irq_mask = mask;
19 | if (did_init) {
20 | outb(IO_PIC1 + 1, mask);
21 | outb(IO_PIC2 + 1, mask >> 8);
22 | }
23 | }
24 |
25 | void
26 | pic_enable(unsigned int irq) {
27 | pic_setmask(irq_mask & ~(1 << irq));
28 | }
29 |
30 | /* pic_init - initialize the 8259A interrupt controllers */
31 | void
32 | pic_init(void) {
33 | did_init = 1;
34 |
35 | // mask all interrupts
36 | outb(IO_PIC1 + 1, 0xFF);
37 | outb(IO_PIC2 + 1, 0xFF);
38 |
39 | // Set up master (8259A-1)
40 |
41 | // ICW1: 0001g0hi
42 | // g: 0 = edge triggering, 1 = level triggering
43 | // h: 0 = cascaded PICs, 1 = master only
44 | // i: 0 = no ICW4, 1 = ICW4 required
45 | outb(IO_PIC1, 0x11);
46 |
47 | // ICW2: Vector offset
48 | outb(IO_PIC1 + 1, IRQ_OFFSET);
49 |
50 | // ICW3: (master PIC) bit mask of IR lines connected to slaves
51 | // (slave PIC) 3-bit # of slave's connection to master
52 | outb(IO_PIC1 + 1, 1 << IRQ_SLAVE);
53 |
54 | // ICW4: 000nbmap
55 | // n: 1 = special fully nested mode
56 | // b: 1 = buffered mode
57 | // m: 0 = slave PIC, 1 = master PIC
58 | // (ignored when b is 0, as the master/slave role
59 | // can be hardwired).
60 | // a: 1 = Automatic EOI mode
61 | // p: 0 = MCS-80/85 mode, 1 = intel x86 mode
62 | outb(IO_PIC1 + 1, 0x3);
63 |
64 | // Set up slave (8259A-2)
65 | outb(IO_PIC2, 0x11); // ICW1
66 | outb(IO_PIC2 + 1, IRQ_OFFSET + 8); // ICW2
67 | outb(IO_PIC2 + 1, IRQ_SLAVE); // ICW3
68 | // NB Automatic EOI mode doesn't tend to work on the slave.
69 | // Linux source code says it's "to be investigated".
70 | outb(IO_PIC2 + 1, 0x3); // ICW4
71 |
72 | // OCW3: 0ef01prs
73 | // ef: 0x = NOP, 10 = clear specific mask, 11 = set specific mask
74 | // p: 0 = no polling, 1 = polling mode
75 | // rs: 0x = NOP, 10 = read IRR, 11 = read ISR
76 | outb(IO_PIC1, 0x68); // clear specific mask
77 | outb(IO_PIC1, 0x0a); // read IRR by default
78 |
79 | outb(IO_PIC2, 0x68); // OCW3
80 | outb(IO_PIC2, 0x0a); // OCW3
81 |
82 | if (irq_mask != 0xFFFF) {
83 | pic_setmask(irq_mask);
84 | }
85 | }
86 |
87 |
--------------------------------------------------------------------------------
/code/kern/driver/picirq.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_DRIVER_PICIRQ_H__
2 | #define __KERN_DRIVER_PICIRQ_H__
3 |
4 | void pic_init(void);
5 | void pic_enable(unsigned int irq);
6 |
7 | #define IRQ_OFFSET 32
8 |
9 | #endif /* !__KERN_DRIVER_PICIRQ_H__ */
10 |
11 |
--------------------------------------------------------------------------------
/code/kern/fs/devs/dev.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_FS_DEVS_DEV_H__
2 | #define __KERN_FS_DEVS_DEV_H__
3 |
4 | #include
5 |
6 | struct inode;
7 | struct iobuf;
8 |
9 | /*
10 | * Filesystem-namespace-accessible device.
11 | * d_io is for both reads and writes; the iob indicates the io buffer, write indicates direction.
12 | */
13 | struct device {
14 | size_t d_blocks;
15 | size_t d_blocksize;
16 | int (*d_open)(struct device *dev, uint32_t open_flags);
17 | int (*d_close)(struct device *dev);
18 | int (*d_io)(struct device *dev, struct iobuf *iob, bool write);
19 | int (*d_ioctl)(struct device *dev, int op, void *data);
20 | };
21 |
22 | #define dop_open(dev, open_flags) ((dev)->d_open(dev, open_flags))
23 | #define dop_close(dev) ((dev)->d_close(dev))
24 | #define dop_io(dev, iob, write) ((dev)->d_io(dev, iob, write))
25 | #define dop_ioctl(dev, op, data) ((dev)->d_ioctl(dev, op, data))
26 |
27 | void dev_init(void);
28 | /* Create inode for a vfs-level device. */
29 | struct inode *dev_create_inode(void);
30 |
31 | #endif /* !__KERN_FS_DEVS_DEV_H__ */
32 |
33 |
--------------------------------------------------------------------------------
/code/kern/fs/devs/dev_null.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Implementation of the null device, "null:", which generates an
3 | * immediate EOF on read and throws away anything written to it.
4 | */
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | /* For open() */
14 | static int
15 | null_open(struct device *dev, uint32_t open_flags) {
16 | return 0;
17 | }
18 |
19 | /* For close() */
20 | static int
21 | null_close(struct device *dev) {
22 | return 0;
23 | }
24 |
25 | /* For dop_io() */
26 | static int
27 | null_io(struct device *dev, struct iobuf *iob, bool write) {
28 | /*
29 | * On write, discard everything without looking at it.
30 | * On read, do nothing, generating an immediate EOF.
31 | */
32 | if (write) {
33 | iob->io_resid = 0;
34 | }
35 | return 0;
36 | }
37 |
38 | /* For ioctl() */
39 | static int
40 | null_ioctl(struct device *dev, int op, void *data) {
41 | return -E_INVAL;
42 | }
43 |
44 | static void
45 | null_device_init(struct device *dev) {
46 | dev->d_blocks = 0;
47 | dev->d_blocksize = 1;
48 | dev->d_open = null_open;
49 | dev->d_close = null_close;
50 | dev->d_io = null_io;
51 | dev->d_ioctl = null_ioctl;
52 | }
53 |
54 | /*
55 | * Function to create and attach null:
56 | */
57 | void
58 | dev_init_null(void) {
59 | struct inode *node;
60 | if ((node = dev_create_inode()) == NULL) {
61 | panic("null: dev_create_node.\n");
62 | }
63 | null_device_init(vop_info(node, device));
64 |
65 | int ret;
66 | if ((ret = vfs_add_dev("null", node, 0)) != 0) {
67 | panic("null: vfs_add_dev: %e.\n", ret);
68 | }
69 | }
70 |
71 |
--------------------------------------------------------------------------------
/code/kern/fs/devs/dev_stdin.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #define STDIN_BUFSIZE 4096
16 |
17 | static char stdin_buffer[STDIN_BUFSIZE];
18 | static off_t p_rpos, p_wpos;
19 | static wait_queue_t __wait_queue, *wait_queue = &__wait_queue;
20 |
21 | void
22 | dev_stdin_write(char c) {
23 | bool intr_flag;
24 | if (c != '\0') {
25 | local_intr_save(intr_flag);
26 | {
27 | stdin_buffer[p_wpos % STDIN_BUFSIZE] = c;
28 | if (p_wpos - p_rpos < STDIN_BUFSIZE) {
29 | p_wpos ++;
30 | }
31 | if (!wait_queue_empty(wait_queue)) {
32 | wakeup_queue(wait_queue, WT_KBD, 1);
33 | }
34 | }
35 | local_intr_restore(intr_flag);
36 | }
37 | }
38 |
39 | static int
40 | dev_stdin_read(char *buf, size_t len) {
41 | int ret = 0;
42 | bool intr_flag;
43 | local_intr_save(intr_flag);
44 | {
45 | for (; ret < len; ret ++, p_rpos ++) {
46 | try_again:
47 | if (p_rpos < p_wpos) {
48 | *buf ++ = stdin_buffer[p_rpos % STDIN_BUFSIZE];
49 | }
50 | else {
51 | wait_t __wait, *wait = &__wait;
52 | wait_current_set(wait_queue, wait, WT_KBD);
53 | local_intr_restore(intr_flag);
54 |
55 | schedule();
56 |
57 | local_intr_save(intr_flag);
58 | wait_current_del(wait_queue, wait);
59 | if (wait->wakeup_flags == WT_KBD) {
60 | goto try_again;
61 | }
62 | break;
63 | }
64 | }
65 | }
66 | local_intr_restore(intr_flag);
67 | return ret;
68 | }
69 |
70 | static int
71 | stdin_open(struct device *dev, uint32_t open_flags) {
72 | if (open_flags != O_RDONLY) {
73 | return -E_INVAL;
74 | }
75 | return 0;
76 | }
77 |
78 | static int
79 | stdin_close(struct device *dev) {
80 | return 0;
81 | }
82 |
83 | static int
84 | stdin_io(struct device *dev, struct iobuf *iob, bool write) {
85 | if (!write) {
86 | int ret;
87 | if ((ret = dev_stdin_read(iob->io_base, iob->io_resid)) > 0) {
88 | iob->io_resid -= ret;
89 | }
90 | return ret;
91 | }
92 | return -E_INVAL;
93 | }
94 |
95 | static int
96 | stdin_ioctl(struct device *dev, int op, void *data) {
97 | return -E_INVAL;
98 | }
99 |
100 | static void
101 | stdin_device_init(struct device *dev) {
102 | dev->d_blocks = 0;
103 | dev->d_blocksize = 1;
104 | dev->d_open = stdin_open;
105 | dev->d_close = stdin_close;
106 | dev->d_io = stdin_io;
107 | dev->d_ioctl = stdin_ioctl;
108 |
109 | p_rpos = p_wpos = 0;
110 | wait_queue_init(wait_queue);
111 | }
112 |
113 | void
114 | dev_init_stdin(void) {
115 | struct inode *node;
116 | if ((node = dev_create_inode()) == NULL) {
117 | panic("stdin: dev_create_node.\n");
118 | }
119 | stdin_device_init(vop_info(node, device));
120 |
121 | int ret;
122 | if ((ret = vfs_add_dev("stdin", node, 0)) != 0) {
123 | panic("stdin: vfs_add_dev: %e.\n", ret);
124 | }
125 | }
126 |
127 |
--------------------------------------------------------------------------------
/code/kern/fs/devs/dev_stdout.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | static int
12 | stdout_open(struct device *dev, uint32_t open_flags) {
13 | if (open_flags != O_WRONLY) {
14 | return -E_INVAL;
15 | }
16 | return 0;
17 | }
18 |
19 | static int
20 | stdout_close(struct device *dev) {
21 | return 0;
22 | }
23 |
24 | static int
25 | stdout_io(struct device *dev, struct iobuf *iob, bool write) {
26 | if (write) {
27 | char *data = iob->io_base;
28 | for (; iob->io_resid != 0; iob->io_resid --) {
29 | cputchar(*data ++);
30 | }
31 | return 0;
32 | }
33 | return -E_INVAL;
34 | }
35 |
36 | static int
37 | stdout_ioctl(struct device *dev, int op, void *data) {
38 | return -E_INVAL;
39 | }
40 |
41 | static void
42 | stdout_device_init(struct device *dev) {
43 | dev->d_blocks = 0;
44 | dev->d_blocksize = 1;
45 | dev->d_open = stdout_open;
46 | dev->d_close = stdout_close;
47 | dev->d_io = stdout_io;
48 | dev->d_ioctl = stdout_ioctl;
49 | }
50 |
51 | void
52 | dev_init_stdout(void) {
53 | struct inode *node;
54 | if ((node = dev_create_inode()) == NULL) {
55 | panic("stdout: dev_create_node.\n");
56 | }
57 | stdout_device_init(vop_info(node, device));
58 |
59 | int ret;
60 | if ((ret = vfs_add_dev("stdout", node, 0)) != 0) {
61 | panic("stdout: vfs_add_dev: %e.\n", ret);
62 | }
63 | }
64 |
65 |
--------------------------------------------------------------------------------
/code/kern/fs/file.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_FS_FILE_H__
2 | #define __KERN_FS_FILE_H__
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | struct inode;
11 | struct stat;
12 | struct dirent;
13 |
14 | struct file {
15 | enum {
16 | FD_NONE, FD_INIT, FD_OPENED, FD_CLOSED,
17 | } status;
18 | bool readable;
19 | bool writable;
20 | int fd;
21 | off_t pos;
22 | struct inode *node;
23 | atomic_t open_count;
24 | };
25 |
26 | void filemap_init(struct file *filemap);
27 | void filemap_open(struct file *file);
28 | void filemap_close(struct file *file);
29 | void filemap_dup(struct file *to, struct file *from);
30 | bool file_testfd(int fd, bool readable, bool writable);
31 |
32 | int file_open(char *path, uint32_t open_flags);
33 | int file_close(int fd);
34 | int file_read(int fd, void *base, size_t len, size_t *copied_store);
35 | int file_write(int fd, void *base, size_t len, size_t *copied_store);
36 | int file_seek(int fd, off_t pos, int whence);
37 | int file_fstat(int fd, struct stat *stat);
38 | int file_fsync(int fd);
39 | int file_getdirentry(int fd, struct dirent *dirent);
40 | int file_dup(int fd1, int fd2);
41 | int file_pipe(int fd[]);
42 | int file_mkfifo(const char *name, uint32_t open_flags);
43 |
44 | static inline int
45 | fopen_count(struct file *file) {
46 | return atomic_read(&(file->open_count));
47 | }
48 |
49 | static inline int
50 | fopen_count_inc(struct file *file) {
51 | return atomic_add_return(&(file->open_count), 1);
52 | }
53 |
54 | static inline int
55 | fopen_count_dec(struct file *file) {
56 | return atomic_sub_return(&(file->open_count), 1);
57 | }
58 |
59 | #endif /* !__KERN_FS_FILE_H__ */
60 |
61 |
--------------------------------------------------------------------------------
/code/kern/fs/fs.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | void
13 | fs_init(void) {
14 | vfs_init();
15 | dev_init();
16 | pipe_init();
17 | sfs_init();
18 | }
19 |
20 | void
21 | fs_cleanup(void) {
22 | vfs_cleanup();
23 | }
24 |
25 | void
26 | lock_fs(struct fs_struct *fs_struct) {
27 | down(&(fs_struct->fs_sem));
28 | }
29 |
30 | void
31 | unlock_fs(struct fs_struct *fs_struct) {
32 | up(&(fs_struct->fs_sem));
33 | }
34 |
35 | struct fs_struct *
36 | fs_create(void) {
37 | static_assert((int)FS_STRUCT_NENTRY > 128);
38 | struct fs_struct *fs_struct;
39 | if ((fs_struct = kmalloc(sizeof(struct fs_struct) + FS_STRUCT_BUFSIZE)) != NULL) {
40 | fs_struct->pwd = NULL;
41 | fs_struct->filemap = (void *)(fs_struct + 1);
42 | atomic_set(&(fs_struct->fs_count), 0);
43 | sem_init(&(fs_struct->fs_sem), 1);
44 | filemap_init(fs_struct->filemap);
45 | }
46 | return fs_struct;
47 | }
48 |
49 | void
50 | fs_destroy(struct fs_struct *fs_struct) {
51 | assert(fs_struct != NULL && fs_count(fs_struct) == 0);
52 | if (fs_struct->pwd != NULL) {
53 | vop_ref_dec(fs_struct->pwd);
54 | }
55 | int i;
56 | struct file *file = fs_struct->filemap;
57 | for (i = 0; i < FS_STRUCT_NENTRY; i ++, file ++) {
58 | if (file->status == FD_OPENED) {
59 | filemap_close(file);
60 | }
61 | assert(file->status == FD_NONE);
62 | }
63 | kfree(fs_struct);
64 | }
65 |
66 | void
67 | fs_closeall(struct fs_struct *fs_struct) {
68 | assert(fs_struct != NULL && fs_count(fs_struct) > 0);
69 | int i;
70 | struct file *file = fs_struct->filemap;
71 | for (i = 2, file += 2; i < FS_STRUCT_NENTRY; i ++, file ++) {
72 | if (file->status == FD_OPENED) {
73 | filemap_close(file);
74 | }
75 | }
76 | }
77 |
78 | int
79 | dup_fs(struct fs_struct *to, struct fs_struct *from) {
80 | assert(to != NULL && from != NULL);
81 | assert(fs_count(to) == 0 && fs_count(from) > 0);
82 | if ((to->pwd = from->pwd) != NULL) {
83 | vop_ref_inc(to->pwd);
84 | }
85 | int i;
86 | struct file *to_file = to->filemap, *from_file = from->filemap;
87 | for (i = 0; i < FS_STRUCT_NENTRY; i ++, to_file ++, from_file ++) {
88 | if (from_file->status == FD_OPENED) {
89 | /* alloc_fd first */
90 | to_file->status = FD_INIT;
91 | filemap_dup(to_file, from_file);
92 | }
93 | }
94 | return 0;
95 | }
96 |
97 |
--------------------------------------------------------------------------------
/code/kern/fs/fs.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_FS_FS_H__
2 | #define __KERN_FS_FS_H__
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #define SECTSIZE 512
10 | #define PAGE_NSECT (PGSIZE / SECTSIZE)
11 |
12 | #define SWAP_DEV_NO 1
13 | #define DISK0_DEV_NO 2
14 |
15 | void fs_init(void);
16 | void fs_cleanup(void);
17 |
18 | struct inode;
19 | struct file;
20 |
21 | struct fs_struct {
22 | struct inode *pwd;
23 | struct file *filemap;
24 | atomic_t fs_count;
25 | semaphore_t fs_sem;
26 | };
27 |
28 | #define FS_STRUCT_BUFSIZE (PGSIZE - sizeof(struct fs_struct))
29 | #define FS_STRUCT_NENTRY (FS_STRUCT_BUFSIZE / sizeof(struct file))
30 |
31 | void lock_fs(struct fs_struct *fs_struct);
32 | void unlock_fs(struct fs_struct *fs_struct);
33 |
34 | struct fs_struct *fs_create(void);
35 | void fs_destroy(struct fs_struct *fs_struct);
36 | void fs_closeall(struct fs_struct *fs_struct);
37 | int dup_fs(struct fs_struct *to, struct fs_struct *from);
38 |
39 | static inline int
40 | fs_count(struct fs_struct *fs_struct) {
41 | return atomic_read(&(fs_struct->fs_count));
42 | }
43 |
44 | static inline int
45 | fs_count_inc(struct fs_struct *fs_struct) {
46 | return atomic_add_return(&(fs_struct->fs_count), 1);
47 | }
48 |
49 | static inline int
50 | fs_count_dec(struct fs_struct *fs_struct) {
51 | return atomic_sub_return(&(fs_struct->fs_count), 1);
52 | }
53 |
54 | #endif /* !__KERN_FS_FS_H__ */
55 |
56 |
--------------------------------------------------------------------------------
/code/kern/fs/iobuf.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | struct iobuf *
8 | iobuf_init(struct iobuf *iob, void *base, size_t len, off_t offset) {
9 | iob->io_base = base;
10 | iob->io_offset = offset;
11 | iob->io_len = iob->io_resid = len;
12 | return iob;
13 | }
14 |
15 | int
16 | iobuf_move(struct iobuf *iob, void *data, size_t len, bool m2b, size_t *copiedp) {
17 | size_t alen;
18 | if ((alen = iob->io_resid) > len) {
19 | alen = len;
20 | }
21 | if (alen > 0) {
22 | void *src = iob->io_base, *dst = data;
23 | if (m2b) {
24 | void *tmp = src;
25 | src = dst, dst = tmp;
26 | }
27 | memmove(dst, src, alen);
28 | iobuf_skip(iob, alen), len -= alen;
29 | }
30 | if (copiedp != NULL) {
31 | *copiedp = alen;
32 | }
33 | return (len == 0) ? 0 : -E_NO_MEM;
34 | }
35 |
36 | int
37 | iobuf_move_zeros(struct iobuf *iob, size_t len, size_t *copiedp) {
38 | size_t alen;
39 | if ((alen = iob->io_resid) > len) {
40 | alen = len;
41 | }
42 | if (alen > 0) {
43 | memset(iob->io_base, 0, alen);
44 | iobuf_skip(iob, alen), len -= alen;
45 | }
46 | if (copiedp != NULL) {
47 | *copiedp = alen;
48 | }
49 | return (len == 0) ? 0 : -E_NO_MEM;
50 | }
51 |
52 | void
53 | iobuf_skip(struct iobuf *iob, size_t n) {
54 | assert(iob->io_resid >= n);
55 | iob->io_base += n, iob->io_offset += n, iob->io_resid -= n;
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/code/kern/fs/iobuf.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_FS_IOBUF_H__
2 | #define __KERN_FS_IOBUF_H__
3 |
4 | #include
5 |
6 | /*
7 | * Like BSD uio, but simplified a lot. (In BSD, there can be one or more
8 | * iovec in a uio.)
9 | *
10 | */
11 |
12 | struct iobuf {
13 | void *io_base; /* The base addr of object */
14 | off_t io_offset; /* Desired offset into object */
15 | size_t io_len; /* The lenght of Data */
16 | size_t io_resid; /* Remaining amt of data to xfer */
17 | };
18 |
19 | /*
20 | * Copy data from a kernel buffer to a data region defined by a iobuf struct,
21 | * updating the iobuf struct's offset and resid fields.
22 | *
23 | * Before calling this, you should
24 | * (1) set up iobuf to point to the buffer you want to transfer
25 | * to;
26 | * (2) initialize iobuf's offset as desired;
27 | * (3) initialize iobuf's resid to the total amount of data that can be
28 | * transferred through this iobuf;
29 | *
30 | * After calling,
31 | * (1) the contents of iobuf may be altered and should not be interpreted;
32 | * (2) iobuf's offset will have been incremented by the amount transferred;
33 | * (3) iobuf's resid will have been decremented by the amount transferred;
34 | *
35 | * iobuf_move() may be called repeatedly on the same iobuf to transfer
36 | * additional data until the available buffer space the iobuf refers to
37 | * is exhausted.
38 | *
39 | * Note that the actual value of iobuf's offset is not interpreted. It is
40 | * provided to allow for easier file seek pointer management.
41 | *
42 | */
43 |
44 | #define iobuf_used(iob) ((size_t)((iob)->io_len - (iob)->io_resid))
45 |
46 | struct iobuf *iobuf_init(struct iobuf *iob, void *base, size_t len, off_t offset);
47 | int iobuf_move(struct iobuf *iob, void *data, size_t len, bool m2b, size_t *copiedp);
48 | /*
49 | * Like uiomove, but sends zeros.
50 | */
51 | int iobuf_move_zeros(struct iobuf *iob, size_t len, size_t *copiedp);
52 | void iobuf_skip(struct iobuf *iob, size_t n);
53 |
54 | #endif /* !__KERN_FS_IOBUF_H__ */
55 |
56 |
--------------------------------------------------------------------------------
/code/kern/fs/pipe/pipe.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | void
12 | lock_pipe(struct pipe_fs *pipe) {
13 | down(&(pipe->pipe_sem));
14 | }
15 |
16 | void
17 | unlock_pipe(struct pipe_fs *pipe) {
18 | up(&(pipe->pipe_sem));
19 | }
20 |
21 | static int
22 | pipe_sync(struct fs *fs) {
23 | return 0;
24 | }
25 |
26 | static struct inode *
27 | pipe_get_root(struct fs *fs) {
28 | struct pipe_fs *pipe = fsop_info(fs, pipe);
29 | vop_ref_inc(pipe->root);
30 | return pipe->root;
31 | }
32 |
33 | static int
34 | pipe_unmount(struct fs *fs) {
35 | return -E_INVAL;
36 | }
37 |
38 | static void
39 | pipe_cleanup(struct fs *fs) {
40 | /* do nothing */
41 | }
42 |
43 | static void
44 | pipe_fs_init(struct fs *fs) {
45 | struct pipe_fs *pipe = fsop_info(fs, pipe);
46 | if ((pipe->root = pipe_create_root(fs)) == NULL) {
47 | panic("pipe: create root inode failed.\n");
48 | }
49 | sem_init(&(pipe->pipe_sem), 1);
50 | list_init(&(pipe->pipe_list));
51 |
52 | fs->fs_sync = pipe_sync;
53 | fs->fs_get_root = pipe_get_root;
54 | fs->fs_unmount = pipe_unmount;
55 | fs->fs_cleanup = pipe_cleanup;
56 | }
57 |
58 | void
59 | pipe_init(void) {
60 | struct fs *fs;
61 | if ((fs = alloc_fs(pipe)) == NULL) {
62 | panic("pipe: create pipe_fs failed.\n");
63 | }
64 | pipe_fs_init(fs);
65 |
66 | int ret;
67 | if ((ret = vfs_add_fs("pipe", fs)) != 0) {
68 | panic("pipe: vfs_add_fs: %e.\n", ret);
69 | }
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/code/kern/fs/pipe/pipe.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_FS_PIPE_PIPE_H__
2 | #define __KERN_FS_PIPE_PIPE_H__
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | struct fs;
9 | struct inode;
10 | struct pipe_state;
11 |
12 | struct pipe_fs {
13 | struct inode *root;
14 | semaphore_t pipe_sem;
15 | list_entry_t pipe_list;
16 | };
17 |
18 | void pipe_init(void);
19 | void lock_pipe(struct pipe_fs *pipe);
20 | void unlock_pipe(struct pipe_fs *pipe);
21 |
22 | struct pipe_root {
23 | /* empty */
24 | };
25 |
26 | struct pipe_inode {
27 | enum {
28 | PIN_RDONLY, PIN_WRONLY,
29 | } pin_type;
30 | char *name;
31 | int reclaim_count;
32 | struct pipe_state *state;
33 | list_entry_t pipe_link;
34 | };
35 |
36 | #define le2pin(le, member) \
37 | to_struct((le), struct pipe_inode, member)
38 |
39 | struct inode *pipe_create_root(struct fs *fs);
40 | struct inode *pipe_create_inode(struct fs *fs, const char *name, struct pipe_state *state, bool readonly);
41 | int pipe_open(struct inode **rnode_store, struct inode **wnode_store);
42 |
43 | #endif /* !__KERN_FS_PIPE_PIPE_H__ */
44 |
45 |
--------------------------------------------------------------------------------
/code/kern/fs/pipe/pipe_state.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_FS_PIPE_PIPE_STATE_H__
2 | #define __KERN_FS_PIPE_PIPE_STATE_H__
3 |
4 | struct pipe_state;
5 |
6 | struct pipe_state *pipe_state_create(void);
7 | void pipe_state_acquire(struct pipe_state *state);
8 | void pipe_state_release(struct pipe_state *state);
9 | void pipe_state_close(struct pipe_state *state);
10 |
11 | size_t pipe_state_size(struct pipe_state *state, bool write);
12 | size_t pipe_state_read(struct pipe_state *state, void *buf, size_t n);
13 | size_t pipe_state_write(struct pipe_state *state, void *buf, size_t n);
14 |
15 | #endif /* !__KERN_FS_PIPE_PIPE_STATE_H__ */
16 |
17 |
--------------------------------------------------------------------------------
/code/kern/fs/sfs/bitmap.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #define WORD_TYPE uint32_t
9 | #define WORD_BITS (sizeof(WORD_TYPE) * CHAR_BIT)
10 |
11 | struct bitmap {
12 | uint32_t nbits;
13 | uint32_t nwords;
14 | WORD_TYPE *map;
15 | };
16 |
17 | struct bitmap *
18 | bitmap_create(uint32_t nbits) {
19 | static_assert(WORD_BITS != 0);
20 | assert(nbits != 0 && nbits + WORD_BITS > nbits);
21 |
22 | struct bitmap *bitmap;
23 | if ((bitmap = kmalloc(sizeof(struct bitmap))) == NULL) {
24 | return NULL;
25 | }
26 |
27 | uint32_t nwords = ROUNDUP_DIV(nbits, WORD_BITS);
28 | WORD_TYPE *map;
29 | if ((map = kmalloc(sizeof(WORD_TYPE) * nwords)) == NULL) {
30 | kfree(bitmap);
31 | return NULL;
32 | }
33 |
34 | bitmap->nbits = nbits, bitmap->nwords = nwords;
35 | bitmap->map = memset(map, 0xFF, sizeof(WORD_TYPE) * nwords);
36 |
37 | /* mark any leftover bits at the end in use(0) */
38 | if (nbits != nwords * WORD_BITS) {
39 | uint32_t ix = nwords - 1, overbits = nbits - ix * WORD_BITS;
40 |
41 | assert(nbits / WORD_BITS == ix);
42 | assert(overbits > 0 && overbits < WORD_BITS);
43 |
44 | for (; overbits < WORD_BITS; overbits ++) {
45 | bitmap->map[ix] ^= (1 << overbits);
46 | }
47 | }
48 | return bitmap;
49 | }
50 |
51 | int
52 | bitmap_alloc(struct bitmap *bitmap, uint32_t *index_store) {
53 | WORD_TYPE *map = bitmap->map;
54 | uint32_t ix, offset, nwords = bitmap->nwords;
55 | for (ix = 0; ix < nwords; ix ++) {
56 | if (map[ix] != 0) {
57 | for (offset = 0; offset < WORD_BITS; offset ++) {
58 | WORD_TYPE mask = (1 << offset);
59 | if (map[ix] & mask) {
60 | map[ix] ^= mask;
61 | *index_store = ix * WORD_BITS + offset;
62 | return 0;
63 | }
64 | }
65 | assert(0);
66 | }
67 | }
68 | return -E_NO_MEM;
69 | }
70 |
71 | static void
72 | bitmap_translate(struct bitmap *bitmap, uint32_t index, WORD_TYPE **word, WORD_TYPE *mask) {
73 | assert(index < bitmap->nbits);
74 | uint32_t ix = index / WORD_BITS, offset = index % WORD_BITS;
75 | *word = bitmap->map + ix;
76 | *mask = (1 << offset);
77 | }
78 |
79 | bool
80 | bitmap_test(struct bitmap *bitmap, uint32_t index) {
81 | WORD_TYPE *word, mask;
82 | bitmap_translate(bitmap, index, &word, &mask);
83 | return (*word & mask);
84 | }
85 |
86 | void
87 | bitmap_free(struct bitmap *bitmap, uint32_t index) {
88 | WORD_TYPE *word, mask;
89 | bitmap_translate(bitmap, index, &word, &mask);
90 | assert(!(*word & mask));
91 | *word |= mask;
92 | }
93 |
94 | void
95 | bitmap_destroy(struct bitmap *bitmap) {
96 | kfree(bitmap->map);
97 | kfree(bitmap);
98 | }
99 |
100 | void *
101 | bitmap_getdata(struct bitmap *bitmap, size_t *len_store) {
102 | if (len_store != NULL) {
103 | *len_store = sizeof(WORD_TYPE) * bitmap->nwords;
104 | }
105 | return bitmap->map;
106 | }
107 |
108 |
--------------------------------------------------------------------------------
/code/kern/fs/sfs/bitmap.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_FS_SFS_BITMAP_H__
2 | #define __KERN_FS_SFS_BITMAP_H__
3 |
4 | #include
5 |
6 | struct bitmap;
7 |
8 | struct bitmap *bitmap_create(uint32_t nbits);
9 | int bitmap_alloc(struct bitmap *bitmap, uint32_t *index_store);
10 | bool bitmap_test(struct bitmap *bitmap, uint32_t index);
11 | void bitmap_free(struct bitmap *bitmap, uint32_t index);
12 | void bitmap_destroy(struct bitmap *bitmap);
13 | void *bitmap_getdata(struct bitmap *bitmap, size_t *len_store);
14 |
15 | #endif /* !__KERN_FS_SFS_BITMAP_H__ */
16 |
17 |
--------------------------------------------------------------------------------
/code/kern/fs/sfs/sfs.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | void
7 | sfs_init(void) {
8 | int ret;
9 | if ((ret = sfs_mount("disk0")) != 0) {
10 | panic("failed: sfs: sfs_mount: %e.\n", ret);
11 | }
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/code/kern/fs/sfs/sfs_io.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | static int
10 | sfs_rwblock_nolock(struct sfs_fs *sfs, void *buf, uint32_t blkno, bool write, bool check) {
11 | assert((blkno != 0 || !check) && blkno < sfs->super.blocks);
12 | struct iobuf __iob, *iob = iobuf_init(&__iob, buf, SFS_BLKSIZE, blkno * SFS_BLKSIZE);
13 | return dop_io(sfs->dev, iob, write);
14 | }
15 |
16 | static int
17 | sfs_rwblock(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks, bool write) {
18 | int ret = 0;
19 | lock_sfs_io(sfs);
20 | {
21 | while (nblks != 0) {
22 | if ((ret = sfs_rwblock_nolock(sfs, buf, blkno, write, 1)) != 0) {
23 | break;
24 | }
25 | blkno ++, nblks --;
26 | buf += SFS_BLKSIZE;
27 | }
28 | }
29 | unlock_sfs_io(sfs);
30 | return ret;
31 | }
32 |
33 | int
34 | sfs_rblock(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks) {
35 | return sfs_rwblock(sfs, buf, blkno, nblks, 0);
36 | }
37 |
38 | int
39 | sfs_wblock(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks) {
40 | return sfs_rwblock(sfs, buf, blkno, nblks, 1);
41 | }
42 |
43 | int
44 | sfs_rbuf(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset) {
45 | assert(offset >= 0 && offset < SFS_BLKSIZE && offset + len <= SFS_BLKSIZE);
46 | int ret;
47 | lock_sfs_io(sfs);
48 | {
49 | if ((ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, blkno, 0, 1)) == 0) {
50 | memcpy(buf, sfs->sfs_buffer + offset, len);
51 | }
52 | }
53 | unlock_sfs_io(sfs);
54 | return ret;
55 | }
56 |
57 | int
58 | sfs_wbuf(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset) {
59 | assert(offset >= 0 && offset < SFS_BLKSIZE && offset + len <= SFS_BLKSIZE);
60 | int ret;
61 | lock_sfs_io(sfs);
62 | {
63 | if ((ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, blkno, 0, 1)) == 0) {
64 | memcpy(sfs->sfs_buffer + offset, buf, len);
65 | ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, blkno, 1, 1);
66 | }
67 | }
68 | unlock_sfs_io(sfs);
69 | return ret;
70 | }
71 |
72 | int
73 | sfs_sync_super(struct sfs_fs *sfs) {
74 | int ret;
75 | lock_sfs_io(sfs);
76 | {
77 | memset(sfs->sfs_buffer, 0, SFS_BLKSIZE);
78 | memcpy(sfs->sfs_buffer, &(sfs->super), sizeof(sfs->super));
79 | ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, SFS_BLKN_SUPER, 1, 0);
80 | }
81 | unlock_sfs_io(sfs);
82 | return ret;
83 | }
84 |
85 | int
86 | sfs_sync_freemap(struct sfs_fs *sfs) {
87 | uint32_t nblks = sfs_freemap_blocks(&(sfs->super));
88 | return sfs_wblock(sfs, bitmap_getdata(sfs->freemap, NULL), SFS_BLKN_FREEMAP, nblks);
89 | }
90 |
91 | int
92 | sfs_clear_block(struct sfs_fs *sfs, uint32_t blkno, uint32_t nblks) {
93 | int ret;
94 | lock_sfs_io(sfs);
95 | {
96 | memset(sfs->sfs_buffer, 0, SFS_BLKSIZE);
97 | while (nblks != 0) {
98 | if ((ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, blkno, 1, 1)) != 0) {
99 | break;
100 | }
101 | blkno ++, nblks --;
102 | }
103 | }
104 | unlock_sfs_io(sfs);
105 | return ret;
106 | }
107 |
108 |
--------------------------------------------------------------------------------
/code/kern/fs/sfs/sfs_lock.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | void
6 | lock_sfs_fs(struct sfs_fs *sfs) {
7 | down(&(sfs->fs_sem));
8 | }
9 |
10 | void
11 | lock_sfs_io(struct sfs_fs *sfs) {
12 | down(&(sfs->io_sem));
13 | }
14 |
15 | void
16 | lock_sfs_mutex(struct sfs_fs *sfs) {
17 | down(&(sfs->mutex_sem));
18 | }
19 |
20 | void
21 | unlock_sfs_fs(struct sfs_fs *sfs) {
22 | up(&(sfs->fs_sem));
23 | }
24 |
25 | void
26 | unlock_sfs_io(struct sfs_fs *sfs) {
27 | up(&(sfs->io_sem));
28 | }
29 |
30 | void
31 | unlock_sfs_mutex(struct sfs_fs *sfs) {
32 | up(&(sfs->mutex_sem));
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/code/kern/fs/swap/swapfs.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | void
10 | swapfs_init(void) {
11 | static_assert((PGSIZE % SECTSIZE) == 0);
12 | if (!ide_device_valid(SWAP_DEV_NO)) {
13 | panic("swap fs isn't available.\n");
14 | }
15 | max_swap_offset = ide_device_size(SWAP_DEV_NO) / (PGSIZE / SECTSIZE);
16 | }
17 |
18 | int
19 | swapfs_read(swap_entry_t entry, struct Page *page) {
20 | return ide_read_secs(SWAP_DEV_NO, swap_offset(entry) * PAGE_NSECT, page2kva(page), PAGE_NSECT);
21 | }
22 |
23 | int
24 | swapfs_write(swap_entry_t entry, struct Page *page) {
25 | return ide_write_secs(SWAP_DEV_NO, swap_offset(entry) * PAGE_NSECT, page2kva(page), PAGE_NSECT);
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/code/kern/fs/swap/swapfs.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_FS_SWAP_SWAPFS_H__
2 | #define __KERN_FS_SWAP_SWAPFS_H__
3 |
4 | #include
5 | #include
6 |
7 | void swapfs_init(void);
8 | int swapfs_read(swap_entry_t entry, struct Page *page);
9 | int swapfs_write(swap_entry_t entry, struct Page *page);
10 |
11 | #endif /* !__KERN_FS_SWAP_SWAPFS_H__ */
12 |
13 |
--------------------------------------------------------------------------------
/code/kern/fs/sysfile.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_FS_SYSFILE_H__
2 | #define __KERN_FS_SYSFILE_H__
3 |
4 | #include
5 |
6 | struct stat;
7 | struct dirent;
8 |
9 | int sysfile_open(const char *path, uint32_t open_flags);
10 | int sysfile_close(int fd);
11 | int sysfile_read(int fd, void *base, size_t len);
12 | int sysfile_write(int fd, void *base, size_t len);
13 | int sysfile_seek(int fd, off_t pos, int whence);
14 | int sysfile_fstat(int fd, struct stat *stat);
15 | int sysfile_fsync(int fd);
16 | int sysfile_chdir(const char *path);
17 | int sysfile_mkdir(const char *path);
18 | int sysfile_link(const char *path1, const char *path2);
19 | int sysfile_rename(const char *path1, const char *path2);
20 | int sysfile_unlink(const char *path);
21 | int sysfile_getcwd(char *buf, size_t len);
22 | int sysfile_getdirentry(int fd, struct dirent *direntp);
23 | int sysfile_dup(int fd1, int fd2);
24 | int sysfile_pipe(int *fd_store);
25 | int sysfile_mkfifo(const char *name, uint32_t open_flags);
26 |
27 | #endif /* !__KERN_FS_SYSFILE_H__ */
28 |
29 |
--------------------------------------------------------------------------------
/code/kern/fs/vfs/vfs.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | static semaphore_t bootfs_sem;
11 | static struct inode *bootfs_node = NULL;
12 |
13 | extern void vfs_devlist_init(void);
14 |
15 | struct fs *
16 | __alloc_fs(int type) {
17 | struct fs *fs;
18 | if ((fs = kmalloc(sizeof(struct fs))) != NULL) {
19 | fs->fs_type = type;
20 | }
21 | return fs;
22 | }
23 |
24 | void
25 | vfs_init(void) {
26 | sem_init(&bootfs_sem, 1);
27 | vfs_devlist_init();
28 | }
29 |
30 | static void
31 | lock_bootfs(void) {
32 | down(&bootfs_sem);
33 | }
34 |
35 | static void
36 | unlock_bootfs(void) {
37 | up(&bootfs_sem);
38 | }
39 |
40 | /*
41 | * Helper function for actually changing bootfs_inode.
42 | */
43 | static void
44 | change_bootfs(struct inode *node) {
45 | struct inode *old;
46 | lock_bootfs();
47 | {
48 | old = bootfs_node, bootfs_node = node;
49 | }
50 | unlock_bootfs();
51 | if (old != NULL) {
52 | vop_ref_dec(old);
53 | }
54 | }
55 |
56 | /*
57 | * Set bootfs_node.
58 | *
59 | * Bootfs_node is the inode used for beginning path translation of
60 | * pathnames starting with /.
61 | *
62 | * It is also incidentally the system's first current directory.
63 | */
64 | int
65 | vfs_set_bootfs(char *fsname) {
66 | struct inode *node = NULL;
67 | if (fsname != NULL) {
68 | char *s;
69 | if ((s = strchr(fsname, ':')) == NULL || s[1] != '\0') {
70 | return -E_INVAL;
71 | }
72 | int ret;
73 | if ((ret = vfs_chdir(fsname)) != 0) {
74 | return ret;
75 | }
76 | if ((ret = vfs_get_curdir(&node)) != 0) {
77 | return ret;
78 | }
79 | }
80 | change_bootfs(node);
81 | return 0;
82 | }
83 |
84 | /*
85 | * Get bootfs_inode.
86 | */
87 | int
88 | vfs_get_bootfs(struct inode **node_store) {
89 | struct inode *node = NULL;
90 | if (bootfs_node != NULL) {
91 | lock_bootfs();
92 | {
93 | if ((node = bootfs_node) != NULL) {
94 | vop_ref_inc(bootfs_node);
95 | }
96 | }
97 | unlock_bootfs();
98 | }
99 | if (node == NULL) {
100 | return -E_NOENT;
101 | }
102 | *node_store = node;
103 | return 0;
104 | }
105 |
106 |
--------------------------------------------------------------------------------
/code/kern/fs/vfs/vfslookup.c:
--------------------------------------------------------------------------------
1 | /*
2 | * VFS operations relating to pathname translation
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | /*
13 | * Common code to pull the device name, if any, off the front of a
14 | * path and choose the inode to begin the name lookup relative to.
15 | */
16 | static int
17 | get_device(char *path, char **subpath, struct inode **node_store) {
18 | int i, slash = -1, colon = -1;
19 | /*
20 | * Locate the first colon or slash.
21 | */
22 | for (i = 0; path[i] != '\0'; i ++) {
23 | if (path[i] == ':') { colon = i; break; }
24 | if (path[i] == '/') { slash = i; break; }
25 | }
26 | if (colon < 0 && slash != 0) {
27 | /* *
28 | * No colon before a slash, so no device name specified, and the slash isn't leading
29 | * or is also absent, so this is a relative path or just a bare filename. Start from
30 | * the current directory, and use the whole thing as the subpath.
31 | * */
32 | *subpath = path;
33 | return vfs_get_curdir(node_store);
34 | }
35 | if (colon > 0) {
36 | /* device:path - get root of device's filesystem */
37 | path[colon] = '\0';
38 |
39 | /* device:/path - skip slash, treat as device:path */
40 | while (path[++ colon] == '/');
41 | *subpath = path + colon;
42 | return vfs_get_root(path, node_store);
43 | }
44 |
45 | /* *
46 | * we have either /path or :path
47 | * /path is a path relative to the root of the "boot filesystem"
48 | * :path is a path relative to the root of the current filesystem
49 | * */
50 | int ret;
51 | if (*path == '/') {
52 | if ((ret = vfs_get_bootfs(node_store)) != 0) {
53 | return ret;
54 | }
55 | }
56 | else {
57 | assert(*path == ':');
58 | struct inode *node;
59 | if ((ret = vfs_get_curdir(&node)) != 0) {
60 | return ret;
61 | }
62 | /* The current directory may not be a device, so it must have a fs. */
63 | assert(node->in_fs != NULL);
64 | *node_store = fsop_get_root(node->in_fs);
65 | vop_ref_dec(node);
66 | }
67 |
68 | /* ///... or :/... */
69 | while (*(++ path) == '/');
70 | *subpath = path;
71 | return 0;
72 | }
73 |
74 | /*
75 | * Name-to-inode translation.
76 | * (In BSD, both of these are subsumed by namei().)
77 | */
78 |
79 | int
80 | vfs_lookup(char *path, struct inode **node_store) {
81 | int ret;
82 | struct inode *node;
83 | if ((ret = get_device(path, &path, &node)) != 0) {
84 | return ret;
85 | }
86 | if (*path != '\0') {
87 | ret = vop_lookup(node, path, node_store);
88 | vop_ref_dec(node);
89 | return ret;
90 | }
91 | *node_store = node;
92 | return 0;
93 | }
94 |
95 | int
96 | vfs_lookup_parent(char *path, struct inode **node_store, char **endp) {
97 | int ret;
98 | struct inode *node;
99 | if ((ret = get_device(path, &path, &node)) != 0) {
100 | return ret;
101 | }
102 | ret = (*path != '\0') ? vop_lookup_parent(node, path, node_store, endp) : -E_INVAL;
103 | vop_ref_dec(node);
104 | return ret;
105 | }
106 |
107 |
--------------------------------------------------------------------------------
/code/kern/fs/vfs/vfspath.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | static struct inode *
12 | get_cwd_nolock(void) {
13 | return current->fs_struct->pwd;
14 | }
15 |
16 | static void
17 | set_cwd_nolock(struct inode *pwd) {
18 | current->fs_struct->pwd = pwd;
19 | }
20 |
21 | static void
22 | lock_cfs(void) {
23 | lock_fs(current->fs_struct);
24 | }
25 |
26 | static void
27 | unlock_cfs(void) {
28 | unlock_fs(current->fs_struct);
29 | }
30 |
31 | /*
32 | * Get current directory as a inode.
33 | *
34 | * We do not synchronize current->fs_struct->pwd, because it belongs exclusively
35 | * to its own process(or threads) with the holding lock.
36 | */
37 | int
38 | vfs_get_curdir(struct inode **dir_store) {
39 | struct inode *node;
40 | if ((node = get_cwd_nolock()) != NULL) {
41 | vop_ref_inc(node);
42 | *dir_store = node;
43 | return 0;
44 | }
45 | return -E_NOENT;
46 | }
47 |
48 | /*
49 | * Set current directory as a vnode.
50 | * The passed inode must in fact be a directory.
51 | */
52 | int
53 | vfs_set_curdir(struct inode *dir) {
54 | int ret = 0;
55 | lock_cfs();
56 | struct inode *old_dir;
57 | if ((old_dir = get_cwd_nolock()) != dir) {
58 | if (dir != NULL) {
59 | uint32_t type;
60 | if ((ret = vop_gettype(dir, &type)) != 0) {
61 | goto out;
62 | }
63 | if (!S_ISDIR(type)) {
64 | ret = -E_NOTDIR;
65 | goto out;
66 | }
67 | vop_ref_inc(dir);
68 | }
69 | set_cwd_nolock(dir);
70 | if (old_dir != NULL) {
71 | vop_ref_dec(old_dir);
72 | }
73 | }
74 | out:
75 | unlock_cfs();
76 | return ret;
77 | }
78 |
79 | /*
80 | * Set current directory, as a pathname. Use vfs_lookup to translate
81 | * it to a inode.
82 | */
83 | int
84 | vfs_chdir(char *path) {
85 | int ret;
86 | struct inode *node;
87 | if ((ret = vfs_lookup(path, &node)) == 0) {
88 | ret = vfs_set_curdir(node);
89 | vop_ref_dec(node);
90 | }
91 | return ret;
92 | }
93 |
94 | /*
95 | * Get current directory, as a pathname.
96 | * Use vop_namefile to get the pathname.
97 | */
98 | int
99 | vfs_getcwd(struct iobuf *iob) {
100 | int ret;
101 | struct inode *node;
102 | if ((ret = vfs_get_curdir(&node)) != 0) {
103 | return ret;
104 | }
105 | /* The current dir must be a directory, and thus it is not a device. */
106 | assert(node->in_fs != NULL);
107 |
108 | const char *devname = vfs_get_devname(node->in_fs);
109 | if ((ret = iobuf_move(iob, (char *)devname, strlen(devname), 1, NULL)) != 0) {
110 | goto out;
111 | }
112 | char colon = ':';
113 | if ((ret = iobuf_move(iob, &colon, sizeof(colon), 1, NULL)) != 0) {
114 | goto out;
115 | }
116 | ret = vop_namefile(node, iob);
117 |
118 | out:
119 | vop_ref_dec(node);
120 | return ret;
121 | }
122 |
123 |
--------------------------------------------------------------------------------
/code/kern/init/entry.S:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #define REALLOC(x) (x - KERNBASE)
5 |
6 | .text
7 | .globl kern_entry
8 | kern_entry:
9 | # reload temperate gdt (second time) to remap all physical memory
10 | # virtual_addr 0~4G=linear_addr&physical_addr -KERNBASE~4G-KERNBASE
11 | lgdt REALLOC(__gdtdesc)
12 | movl $KERNEL_DS, %eax
13 | movw %ax, %ds
14 | movw %ax, %es
15 | movw %ax, %ss
16 |
17 | ljmp $KERNEL_CS, $relocated
18 |
19 | relocated:
20 |
21 | # set ebp, esp
22 | movl $0x0, %ebp
23 | # the kernel stack region is from bootstack -- bootstacktop,
24 | # the kernel stack size is KSTACKSIZE (8KB)defined in memlayout.h
25 | movl $bootstacktop, %esp
26 | # now kernel stack is ready , call the first C function
27 | call kern_init
28 |
29 | # should never get here
30 | spin:
31 | jmp spin
32 |
33 | .data
34 | .align PGSIZE
35 | .globl bootstack
36 | bootstack:
37 | .space KSTACKSIZE
38 | .globl bootstacktop
39 | bootstacktop:
40 |
41 | .align 4
42 | __gdt:
43 | SEG_NULL
44 | SEG_ASM(STA_X | STA_R, - KERNBASE, 0xFFFFFFFF) # code segment
45 | SEG_ASM(STA_W, - KERNBASE, 0xFFFFFFFF) # data segment
46 | __gdtdesc:
47 | .word 0x17 # sizeof(__gdt) - 1
48 | .long REALLOC(__gdt)
49 |
50 |
--------------------------------------------------------------------------------
/code/kern/init/init.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | int kern_init(void) __attribute__((noreturn));
19 |
20 | int
21 | kern_init(void) {
22 | extern char edata[], end[];
23 | memset(edata, 0, end - edata);
24 |
25 | cons_init(); // init the console
26 |
27 | const char *message = "(THU.CST) os is loading ...";
28 | cprintf("%s\n\n", message);
29 |
30 | print_kerninfo();
31 |
32 | debug_init(); // init debug registers
33 | pmm_init(); // init physical memory management
34 |
35 | pic_init(); // init interrupt controller
36 | idt_init(); // init interrupt descriptor table
37 |
38 | vmm_init(); // init virtual memory management
39 | sched_init(); // init scheduler
40 | proc_init(); // init process table
41 | sync_init(); // init sync struct
42 |
43 | ide_init(); // init ide devices
44 | swap_init(); // init swap
45 | fs_init(); // init fs
46 |
47 | clock_init(); // init clock interrupt
48 | intr_enable(); // enable irq interrupt
49 |
50 | cpu_idle(); // run idle process
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/code/kern/libs/rb_tree.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_LIBS_RB_TREE_H__
2 | #define __KERN_LIBS_RB_TREE_H__
3 |
4 | #include
5 |
6 | typedef struct rb_node {
7 | bool red; // if red = 0, it's a black node
8 | struct rb_node *parent;
9 | struct rb_node *left, *right;
10 | } rb_node;
11 |
12 | typedef struct rb_tree {
13 | // compare function should return -1 if *node1 < *node2, 1 if *node1 > *node2, and 0 otherwise
14 | int (*compare)(rb_node *node1, rb_node *node2);
15 | struct rb_node *nil, *root;
16 | } rb_tree;
17 |
18 | rb_tree *rb_tree_create(int (*compare)(rb_node *node1, rb_node *node2));
19 | void rb_tree_destroy(rb_tree *tree);
20 | void rb_insert(rb_tree *tree, rb_node *node);
21 | void rb_delete(rb_tree *tree, rb_node *node);
22 | rb_node *rb_search(rb_tree *tree, int (*compare)(rb_node *node, void *key), void *key);
23 | rb_node *rb_node_prev(rb_tree *tree, rb_node *node);
24 | rb_node *rb_node_next(rb_tree *tree, rb_node *node);
25 | rb_node *rb_node_root(rb_tree *tree);
26 | rb_node *rb_node_left(rb_tree *tree, rb_node *node);
27 | rb_node *rb_node_right(rb_tree *tree, rb_node *node);
28 |
29 | void check_rb_tree(void);
30 |
31 | #endif /* !__KERN_LIBS_RBTREE_H__ */
32 |
33 |
--------------------------------------------------------------------------------
/code/kern/libs/readline.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #define BUFSIZE 1024
4 | static char buf[BUFSIZE];
5 |
6 | /* *
7 | * readline - get a line from stdin
8 | * @prompt: the string to be written to stdout
9 | *
10 | * The readline() function will write the input string @prompt to
11 | * stdout first. If the @prompt is NULL or the empty string,
12 | * no prompt is issued.
13 | *
14 | * This function will keep on reading characters and saving them to buffer
15 | * 'buf' until '\n' or '\r' is encountered.
16 | *
17 | * Note that, if the length of string that will be read is longer than
18 | * buffer size, the end of string will be discarded.
19 | *
20 | * The readline() function returns the text of the line read. If some errors
21 | * are happened, NULL is returned. The return value is a global variable,
22 | * thus it should be copied before it is used.
23 | * */
24 | char *
25 | readline(const char *prompt) {
26 | if (prompt != NULL) {
27 | cprintf("%s", prompt);
28 | }
29 | int i = 0, c;
30 | while (1) {
31 | c = getchar();
32 | if (c < 0) {
33 | return NULL;
34 | }
35 | else if (c >= ' ' && i < BUFSIZE - 1) {
36 | cputchar(c);
37 | buf[i ++] = c;
38 | }
39 | else if (c == '\b' && i > 0) {
40 | cputchar(c);
41 | i --;
42 | }
43 | else if (c == '\n' || c == '\r') {
44 | cputchar(c);
45 | buf[i] = '\0';
46 | return buf;
47 | }
48 | }
49 | }
50 |
51 |
--------------------------------------------------------------------------------
/code/kern/libs/stdio.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | /* HIGH level console I/O */
7 |
8 | /* *
9 | * cputch - writes a single character @c to stdout, and it will
10 | * increace the value of counter pointed by @cnt.
11 | * */
12 | static void
13 | cputch(int c, int *cnt) {
14 | cons_putc(c);
15 | (*cnt) ++;
16 | }
17 |
18 | /* *
19 | * vcprintf - format a string and writes it to stdout
20 | *
21 | * The return value is the number of characters which would be
22 | * written to stdout.
23 | *
24 | * Call this function if you are already dealing with a va_list.
25 | * Or you probably want cprintf() instead.
26 | * */
27 | int
28 | vcprintf(const char *fmt, va_list ap) {
29 | int cnt = 0;
30 | vprintfmt((void*)cputch, NO_FD, &cnt, fmt, ap);
31 | return cnt;
32 | }
33 |
34 | /* *
35 | * cprintf - formats a string and writes it to stdout
36 | *
37 | * The return value is the number of characters which would be
38 | * written to stdout.
39 | * */
40 | int
41 | cprintf(const char *fmt, ...) {
42 | va_list ap;
43 | int cnt;
44 | va_start(ap, fmt);
45 | cnt = vcprintf(fmt, ap);
46 | va_end(ap);
47 | return cnt;
48 | }
49 |
50 | /* cputchar - writes a single character to stdout */
51 | void
52 | cputchar(int c) {
53 | cons_putc(c);
54 | }
55 |
56 | /* *
57 | * cputs- writes the string pointed by @str to stdout and
58 | * appends a newline character.
59 | * */
60 | int
61 | cputs(const char *str) {
62 | int cnt = 0;
63 | char c;
64 | while ((c = *str ++) != '\0') {
65 | cputch(c, &cnt);
66 | }
67 | cputch('\n', &cnt);
68 | return cnt;
69 | }
70 |
71 | /* getchar - reads a single non-zero character from stdin */
72 | int
73 | getchar(void) {
74 | int c;
75 | while ((c = cons_getc()) == 0)
76 | /* do nothing */;
77 | return c;
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/code/kern/libs/string.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | char *
5 | strdup(const char *src) {
6 | char *dst;
7 | size_t len = strlen(src);
8 | if ((dst = kmalloc(len + 1)) != NULL) {
9 | memcpy(dst, src, len);
10 | dst[len] = '\0';
11 | }
12 | return dst;
13 | }
14 |
15 | char *
16 | stradd(const char *src1, const char *src2) {
17 | char *ret, *dst;
18 | size_t len1 = strlen(src1), len2 = strlen(src2);
19 | if ((ret = dst = kmalloc(len1 + len2 + 1)) != NULL) {
20 | memcpy(dst, src1, len1), dst += len1;
21 | memcpy(dst, src2, len2), dst += len2;
22 | *dst = '\0';
23 | }
24 | return ret;
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/code/kern/mm/buddy_pmm.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_MM_BUDDY_PMM_H__
2 | #define __KERN_MM_BUDDY_PMM_H__
3 |
4 | #include
5 |
6 | extern const struct pmm_manager buddy_pmm_manager;
7 |
8 | #endif /* !__KERN_MM_BUDDY_PMM_H__ */
9 |
10 |
--------------------------------------------------------------------------------
/code/kern/mm/shmem.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_MM_SHMEM_H__
2 | #define __KERN_MM_SHMEM_H__
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | typedef struct shmn_s {
12 | uintptr_t start;
13 | uintptr_t end;
14 | pte_t *entry;
15 | list_entry_t list_link;
16 | } shmn_t;
17 |
18 | #define SHMN_NENTRY (PGSIZE / sizeof(pte_t))
19 |
20 | #define le2shmn(le, member) \
21 | to_struct((le), shmn_t, member)
22 |
23 | struct shmem_struct {
24 | list_entry_t shmn_list;
25 | shmn_t *shmn_cache;
26 | size_t len;
27 | atomic_t shmem_ref;
28 | semaphore_t shmem_sem;
29 | };
30 |
31 | struct shmem_struct *shmem_create(size_t len);
32 | void shmem_destroy(struct shmem_struct *shmem);
33 | pte_t *shmem_get_entry(struct shmem_struct *shmem, uintptr_t addr, bool create);
34 | int shmem_insert_entry(struct shmem_struct *shmem, uintptr_t addr, pte_t entry);
35 | int shmem_remove_entry(struct shmem_struct *shmem, uintptr_t addr);
36 |
37 | static inline int
38 | shmem_ref(struct shmem_struct *shmem) {
39 | return atomic_read(&(shmem->shmem_ref));
40 | }
41 |
42 | static inline void
43 | set_shmem_ref(struct shmem_struct *shmem, int val) {
44 | atomic_set(&(shmem->shmem_ref), val);
45 | }
46 |
47 | static inline int
48 | shmem_ref_inc(struct shmem_struct *shmem) {
49 | return atomic_add_return(&(shmem->shmem_ref), 1);
50 | }
51 |
52 | static inline int
53 | shmem_ref_dec(struct shmem_struct *shmem) {
54 | return atomic_sub_return(&(shmem->shmem_ref), 1);
55 | }
56 |
57 | static inline void
58 | lock_shmem(struct shmem_struct *shmem) {
59 | down(&(shmem->shmem_sem));
60 | }
61 |
62 | static inline void
63 | unlock_shmem(struct shmem_struct *shmem) {
64 | up(&(shmem->shmem_sem));
65 | }
66 |
67 | #endif /* !__KERN_MM_SHMEM_H__ */
68 |
69 |
--------------------------------------------------------------------------------
/code/kern/mm/slab.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_MM_SLAB_H__
2 | #define __KERN_MM_SLAB_H__
3 |
4 | #include
5 |
6 | #define KMALLOC_MAX_ORDER 10
7 |
8 | void slab_init(void);
9 |
10 | void *kmalloc(size_t n);
11 | void kfree(void *objp);
12 |
13 | size_t slab_allocated(void);
14 |
15 | #endif /* !__KERN_MM_SLAB_H__ */
16 |
17 |
--------------------------------------------------------------------------------
/code/kern/mm/swap.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_MM_SWAP_H__
2 | #define __KERN_MM_SWAP_H__
3 |
4 | #include
5 | #include
6 |
7 | /* *
8 | * swap_entry_t
9 | * --------------------------------------------
10 | * | offset | reserved | 0 |
11 | * --------------------------------------------
12 | * 24 bits 7 bits 1 bit
13 | * */
14 |
15 | #define MAX_SWAP_OFFSET_LIMIT (1 << 24)
16 |
17 | extern size_t max_swap_offset;
18 |
19 | /* *
20 | * swap_offset - takes a swap_entry (saved in pte), and returns
21 | * the corresponding offset in swap mem_map.
22 | * */
23 | #define swap_offset(entry) ({ \
24 | size_t __offset = (entry >> 8); \
25 | if (!(__offset > 0 && __offset < max_swap_offset)) { \
26 | panic("invalid swap_entry_t = %08x.\n", entry); \
27 | } \
28 | __offset; \
29 | })
30 |
31 | void swap_init(void);
32 | bool try_free_pages(size_t n);
33 |
34 | void swap_remove_entry(swap_entry_t entry);
35 | int swap_page_count(struct Page *page);
36 | void swap_duplicate(swap_entry_t entry);
37 | int swap_in_page(swap_entry_t entry, struct Page **pagep);
38 | int swap_copy_entry(swap_entry_t entry, swap_entry_t *store);
39 |
40 | int kswapd_main(void *arg) __attribute__((noreturn));
41 |
42 | #endif /* !__KERN_MM_SWAP_H__ */
43 |
44 |
--------------------------------------------------------------------------------
/code/kern/process/entry.S:
--------------------------------------------------------------------------------
1 | .text
2 | .globl kernel_thread_entry
3 | kernel_thread_entry: # void kernel_thread(void)
4 |
5 | pushl %edx # push arg
6 | call *%ebx # call fn
7 |
8 | pushl %eax # save the return value of fn(arg)
9 | call do_exit # call do_exit to terminate current thread
10 |
11 |
--------------------------------------------------------------------------------
/code/kern/process/switch.S:
--------------------------------------------------------------------------------
1 | .text
2 | .globl switch_to
3 | switch_to: # switch_to(from, to)
4 |
5 | # save from's registers
6 | movl 4(%esp), %eax # eax points to from
7 | popl 0(%eax) # save eip !popl
8 | movl %esp, 4(%eax)
9 | movl %ebx, 8(%eax)
10 | movl %ecx, 12(%eax)
11 | movl %edx, 16(%eax)
12 | movl %esi, 20(%eax)
13 | movl %edi, 24(%eax)
14 | movl %ebp, 28(%eax)
15 |
16 | # restore to's registers
17 | movl 4(%esp), %eax # not 8(%esp): popped return address already
18 | # eax now points to to
19 | movl 28(%eax), %ebp
20 | movl 24(%eax), %edi
21 | movl 20(%eax), %esi
22 | movl 16(%eax), %edx
23 | movl 12(%eax), %ecx
24 | movl 8(%eax), %ebx
25 | movl 4(%eax), %esp
26 |
27 | pushl 0(%eax) # push eip
28 |
29 | ret
30 |
31 |
--------------------------------------------------------------------------------
/code/kern/schedule/sched.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_SCHEDULE_SCHED_H__
2 | #define __KERN_SCHEDULE_SCHED_H__
3 |
4 | #include
5 | #include
6 |
7 | struct proc_struct;
8 |
9 | typedef struct {
10 | unsigned int expires;
11 | struct proc_struct *proc;
12 | list_entry_t timer_link;
13 | } timer_t;
14 |
15 | #define le2timer(le, member) \
16 | to_struct((le), timer_t, member)
17 |
18 | static inline timer_t *
19 | timer_init(timer_t *timer, struct proc_struct *proc, int expires) {
20 | timer->expires = expires;
21 | timer->proc = proc;
22 | list_init(&(timer->timer_link));
23 | return timer;
24 | }
25 |
26 | struct run_queue;
27 |
28 | // The introduction of scheduling classes is borrrowed from Linux, and makes the
29 | // core scheduler quite extensible. These classes (the scheduler modules) encapsulate
30 | // the scheduling policies.
31 | struct sched_class {
32 | // the name of sched_class
33 | const char *name;
34 | // Init the run queue
35 | void (*init)(struct run_queue *rq);
36 | // put the proc into runqueue, and this function must be called with rq_lock
37 | void (*enqueue)(struct run_queue *rq, struct proc_struct *proc);
38 | // get the proc out runqueue, and this function must be called with rq_lock
39 | void (*dequeue)(struct run_queue *rq, struct proc_struct *proc);
40 | // choose the next runnable task
41 | struct proc_struct *(*pick_next)(struct run_queue *rq);
42 | // dealer of the time-tick
43 | void (*proc_tick)(struct run_queue *rq, struct proc_struct *proc);
44 | /* for SMP support in the future
45 | * load_balance
46 | * void (*load_balance)(struct rq* rq);
47 | * get some proc from this rq, used in load_balance,
48 | * return value is the num of gotten proc
49 | * int (*get_proc)(struct rq* rq, struct proc* procs_moved[]);
50 | */
51 | };
52 |
53 | struct run_queue {
54 | list_entry_t run_list;
55 | unsigned int proc_num;
56 | int max_time_slice;
57 | list_entry_t rq_link;
58 | };
59 |
60 | #define le2rq(le, member) \
61 | to_struct((le), struct run_queue, member)
62 |
63 | void sched_init(void);
64 | void wakeup_proc(struct proc_struct *proc);
65 | void schedule(void);
66 | void add_timer(timer_t *timer);
67 | void del_timer(timer_t *timer);
68 | void run_timer_list(void);
69 |
70 | #endif /* !__KERN_SCHEDULE_SCHED_H__ */
71 |
72 |
--------------------------------------------------------------------------------
/code/kern/schedule/sched_MLFQ.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | static struct sched_class *sched_class;
10 |
11 | static void
12 | MLFQ_init(struct run_queue *rq) {
13 | sched_class = &RR_sched_class;
14 | list_entry_t *list = &(rq->rq_link), *le = list;
15 | do {
16 | sched_class->init(le2rq(le, rq_link));
17 | le = list_next(le);
18 | } while (le != list);
19 | }
20 |
21 | static void
22 | MLFQ_enqueue(struct run_queue *rq, struct proc_struct *proc) {
23 | assert(list_empty(&(proc->run_link)));
24 | struct run_queue *nrq = rq;
25 | if (proc->rq != NULL && proc->time_slice == 0) {
26 | nrq = le2rq(list_next(&(proc->rq->rq_link)), rq_link);
27 | if (nrq == rq) {
28 | nrq = proc->rq;
29 | }
30 | }
31 | sched_class->enqueue(nrq, proc);
32 | }
33 |
34 | static void
35 | MLFQ_dequeue(struct run_queue *rq, struct proc_struct *proc) {
36 | assert(!list_empty(&(proc->run_link)));
37 | sched_class->dequeue(proc->rq, proc);
38 | }
39 |
40 | static struct proc_struct *
41 | MLFQ_pick_next(struct run_queue *rq) {
42 | struct proc_struct *next;
43 | list_entry_t *list = &(rq->rq_link), *le = list;
44 | do {
45 | if ((next = sched_class->pick_next(le2rq(le, rq_link))) != NULL) {
46 | break;
47 | }
48 | le = list_next(le);
49 | } while (le != list);
50 | return next;
51 | }
52 |
53 | static void
54 | MLFQ_proc_tick(struct run_queue *rq, struct proc_struct *proc) {
55 | sched_class->proc_tick(proc->rq, proc);
56 | }
57 |
58 | struct sched_class MLFQ_sched_class = {
59 | .name = "MLFQ_scheduler",
60 | .init = MLFQ_init,
61 | .enqueue = MLFQ_enqueue,
62 | .dequeue = MLFQ_dequeue,
63 | .pick_next = MLFQ_pick_next,
64 | .proc_tick = MLFQ_proc_tick,
65 | };
66 |
67 |
--------------------------------------------------------------------------------
/code/kern/schedule/sched_MLFQ.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_SCHEDULE_SCHED_MLFQ_H__
2 | #define __KERN_SCHEDULE_SCHED_MLFQ_H__
3 |
4 | #include
5 |
6 | extern struct sched_class MLFQ_sched_class;
7 |
8 | #endif /* !__KERN_SCHEDULE_SCHED_MLFQ_H__ */
9 |
10 |
--------------------------------------------------------------------------------
/code/kern/schedule/sched_RR.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | static void
8 | RR_init(struct run_queue *rq) {
9 | list_init(&(rq->run_list));
10 | rq->proc_num = 0;
11 | }
12 |
13 | static void
14 | RR_enqueue(struct run_queue *rq, struct proc_struct *proc) {
15 | assert(list_empty(&(proc->run_link)));
16 | list_add_before(&(rq->run_list), &(proc->run_link));
17 | if (proc->time_slice == 0 || proc->time_slice > rq->max_time_slice) {
18 | proc->time_slice = rq->max_time_slice;
19 | }
20 | proc->rq = rq;
21 | rq->proc_num ++;
22 | }
23 |
24 | static void
25 | RR_dequeue(struct run_queue *rq, struct proc_struct *proc) {
26 | assert(!list_empty(&(proc->run_link)) && proc->rq == rq);
27 | list_del_init(&(proc->run_link));
28 | rq->proc_num --;
29 | }
30 |
31 | static struct proc_struct *
32 | RR_pick_next(struct run_queue *rq) {
33 | list_entry_t *le = list_next(&(rq->run_list));
34 | if (le != &(rq->run_list)) {
35 | return le2proc(le, run_link);
36 | }
37 | return NULL;
38 | }
39 |
40 | static void
41 | RR_proc_tick(struct run_queue *rq, struct proc_struct *proc) {
42 | if (proc->time_slice > 0) {
43 | proc->time_slice --;
44 | }
45 | if (proc->time_slice == 0) {
46 | proc->need_resched = 1;
47 | }
48 | }
49 |
50 | struct sched_class RR_sched_class = {
51 | .name = "RR_scheduler",
52 | .init = RR_init,
53 | .enqueue = RR_enqueue,
54 | .dequeue = RR_dequeue,
55 | .pick_next = RR_pick_next,
56 | .proc_tick = RR_proc_tick,
57 | };
58 |
59 |
--------------------------------------------------------------------------------
/code/kern/schedule/sched_RR.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_SCHEDULE_SCHED_RR_H__
2 | #define __KERN_SCHEDULE_SCHED_RR_H__
3 |
4 | #include
5 |
6 | extern struct sched_class RR_sched_class;
7 |
8 | #endif /* !__KERN_SCHEDULE_SCHED_RR_H__ */
9 |
10 |
--------------------------------------------------------------------------------
/code/kern/sync/event.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_SYNC_EVENT_H__
2 | #define __KERN_SYNC_EVENT_H__
3 |
4 | #include
5 | #include
6 |
7 | typedef struct {
8 | int event;
9 | wait_queue_t wait_queue;
10 | } event_t;
11 |
12 | void event_box_init(event_t *event_box);
13 |
14 | int ipc_event_send(int pid, int event, unsigned int timeout);
15 | int ipc_event_recv(int *pid_store, int *event_store, unsigned int timeout);
16 |
17 | #endif /* !__KERN_SYNC_EVENT_H__ */
18 |
19 |
--------------------------------------------------------------------------------
/code/kern/sync/ipc.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_SYNC_IPC_H__
2 | #define __KERN_SYNC_IPC_H__
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | static inline void
11 | ipc_add_timer(timer_t *timer) {
12 | if (timer != NULL) {
13 | add_timer(timer);
14 | }
15 | }
16 |
17 | static inline void
18 | ipc_del_timer(timer_t *timer) {
19 | if (timer != NULL) {
20 | del_timer(timer);
21 | }
22 | }
23 |
24 | static inline timer_t *
25 | ipc_timer_init(unsigned int timeout, unsigned long *saved_ticks, timer_t *timer) {
26 | if (timeout != 0) {
27 | *saved_ticks = ticks;
28 | return timer_init(timer, current, timeout);
29 | }
30 | return NULL;
31 | }
32 |
33 | static inline int
34 | ipc_check_timeout(unsigned int timeout, unsigned long saved_ticks) {
35 | if (timeout != 0) {
36 | unsigned long delt = (unsigned long)(ticks - saved_ticks);
37 | if (delt >= timeout) {
38 | return -E_TIMEOUT;
39 | }
40 | }
41 | return -1;
42 | }
43 |
44 | #endif /* !__KERN_SYNC_IPC_H__ */
45 |
46 |
--------------------------------------------------------------------------------
/code/kern/sync/mbox.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_SYNC_MBOX_H__
2 | #define __KERN_SYNC_MBOX_H__
3 |
4 | #include
5 |
6 | void mbox_init(void);
7 |
8 | struct mboxbuf;
9 | struct mboxinfo;
10 |
11 | int ipc_mbox_init(unsigned int max_slots);
12 | int ipc_mbox_send(int id, struct mboxbuf *buf, unsigned int timeout);
13 | int ipc_mbox_recv(int id, struct mboxbuf *buf, unsigned int timeout);
14 | int ipc_mbox_free(int id);
15 | int ipc_mbox_info(int id, struct mboxinfo *info);
16 |
17 | void mbox_cleanup(void);
18 |
19 | #endif /* !__KERN_SYNC_MBOX_H__ */
20 |
21 |
--------------------------------------------------------------------------------
/code/kern/sync/sem.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_SYNC_SEM_H__
2 | #define __KERN_SYNC_SEM_H__
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | typedef struct {
9 | int value;
10 | bool valid;
11 | atomic_t count;
12 | wait_queue_t wait_queue;
13 | } semaphore_t;
14 |
15 | // The sem_undo_t is used to permit semaphore manipulations that can be undone. If a process
16 | // crashes after modifying a semaphore, the information held in the list is used to return the semaphore
17 | // to its state prior to modification. The mechanism is useful when the crashed process has made changes
18 | // after which processes waiting on the semaphore can no longer be woken. By undoing these actions (using
19 | // the information in the sem_undo list), the semaphore can be returned to a consistent state, thus preventing
20 | // deadlocks.
21 | typedef struct sem_undo {
22 | semaphore_t *sem;
23 | list_entry_t semu_link;
24 | } sem_undo_t;
25 |
26 | #define le2semu(le, member) \
27 | to_struct((le), sem_undo_t, member)
28 |
29 | typedef struct sem_queue {
30 | semaphore_t sem;
31 | atomic_t count;
32 | list_entry_t semu_list;
33 | } sem_queue_t;
34 |
35 | void sem_init(semaphore_t *sem, int value);
36 | void up(semaphore_t *sem);
37 | void down(semaphore_t *sem);
38 | bool try_down(semaphore_t *sem);
39 |
40 | sem_undo_t *semu_create(semaphore_t *sem, int value);
41 | void semu_destroy(sem_undo_t *semu);
42 |
43 | sem_queue_t *sem_queue_create(void);
44 | void sem_queue_destroy(sem_queue_t *sem_queue);
45 | int dup_sem_queue(sem_queue_t *to, sem_queue_t *from);
46 | void exit_sem_queue(sem_queue_t *sem_queue);
47 |
48 | int ipc_sem_init(int value);
49 | int ipc_sem_post(sem_t sem_id);
50 | int ipc_sem_wait(sem_t sem_id, unsigned int timeout);
51 | int ipc_sem_free(sem_t sem_id);
52 | int ipc_sem_get_value(sem_t sem_id, int *value_store);
53 |
54 | static inline int
55 | sem_count(semaphore_t *sem) {
56 | return atomic_read(&(sem->count));
57 | }
58 |
59 | static inline void
60 | set_sem_count(semaphore_t *sem, int val) {
61 | atomic_set(&(sem->count), val);
62 | }
63 |
64 | static inline int
65 | sem_count_inc(semaphore_t *sem) {
66 | return atomic_add_return(&(sem->count), 1);
67 | }
68 |
69 | static inline int
70 | sem_count_dec(semaphore_t *sem) {
71 | return atomic_sub_return(&(sem->count), 1);
72 | }
73 |
74 | static inline int
75 | sem_queue_count(sem_queue_t *sq) {
76 | return atomic_read(&(sq->count));
77 | }
78 |
79 | static inline void
80 | set_sem_queue_count(sem_queue_t *sq, int val) {
81 | atomic_set(&(sq->count), val);
82 | }
83 |
84 | static inline int
85 | sem_queue_count_inc(sem_queue_t *sq) {
86 | return atomic_add_return(&(sq->count), 1);
87 | }
88 |
89 | static inline int
90 | sem_queue_count_dec(sem_queue_t *sq) {
91 | return atomic_sub_return(&(sq->count), 1);
92 | }
93 |
94 | #endif /* !__KERN_SYNC_SEM_H__ */
95 |
96 |
--------------------------------------------------------------------------------
/code/kern/sync/sync.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | void
5 | sync_init(void) {
6 | mbox_init();
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/code/kern/sync/sync.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_SYNC_SYNC_H__
2 | #define __KERN_SYNC_SYNC_H__
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | static inline bool
12 | __intr_save(void) {
13 | if (read_eflags() & FL_IF) {
14 | intr_disable();
15 | return 1;
16 | }
17 | return 0;
18 | }
19 |
20 | static inline void
21 | __intr_restore(bool flag) {
22 | if (flag) {
23 | intr_enable();
24 | }
25 | }
26 |
27 | #define local_intr_save(x) do { x = __intr_save(); } while (0)
28 | #define local_intr_restore(x) __intr_restore(x);
29 |
30 | void sync_init(void);
31 |
32 | #endif /* !__KERN_SYNC_SYNC_H__ */
33 |
34 |
--------------------------------------------------------------------------------
/code/kern/sync/wait.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_SYNC_WAIT_H__
2 | #define __KERN_SYNC_WAIT_H__
3 |
4 | #include
5 |
6 | typedef struct {
7 | list_entry_t wait_head;
8 | } wait_queue_t;
9 |
10 | struct proc_struct;
11 |
12 | typedef struct {
13 | struct proc_struct *proc;
14 | uint32_t wakeup_flags;
15 | wait_queue_t *wait_queue;
16 | list_entry_t wait_link;
17 | } wait_t;
18 |
19 | #define le2wait(le, member) \
20 | to_struct((le), wait_t, member)
21 |
22 | void wait_init(wait_t *wait, struct proc_struct *proc);
23 | void wait_queue_init(wait_queue_t *queue);
24 | void wait_queue_add(wait_queue_t *queue, wait_t *wait);
25 | void wait_queue_del(wait_queue_t *queue, wait_t *wait);
26 |
27 | wait_t *wait_queue_next(wait_queue_t *queue, wait_t *wait);
28 | wait_t *wait_queue_prev(wait_queue_t *queue, wait_t *wait);
29 | wait_t *wait_queue_first(wait_queue_t *queue);
30 | wait_t *wait_queue_last(wait_queue_t *queue);
31 |
32 | bool wait_queue_empty(wait_queue_t *queue);
33 | bool wait_in_queue(wait_t *wait);
34 | void wakeup_wait(wait_queue_t *queue, wait_t *wait, uint32_t wakeup_flags, bool del);
35 | void wakeup_first(wait_queue_t *queue, uint32_t wakeup_flags, bool del);
36 | void wakeup_queue(wait_queue_t *queue, uint32_t wakeup_flags, bool del);
37 |
38 | void wait_current_set(wait_queue_t *queue, wait_t *wait, uint32_t wait_state);
39 |
40 | #define wait_current_del(queue, wait) \
41 | do { \
42 | if (wait_in_queue(wait)) { \
43 | wait_queue_del(queue, wait); \
44 | } \
45 | } while (0)
46 |
47 | #endif /* !__KERN_SYNC_WAIT_H__ */
48 |
49 |
--------------------------------------------------------------------------------
/code/kern/syscall/syscall.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_SYSCALL_SYSCALL_H__
2 | #define __KERN_SYSCALL_SYSCALL_H__
3 |
4 | void syscall(void);
5 |
6 | #endif /* !__KERN_SYSCALL_SYSCALL_H__ */
7 |
8 |
--------------------------------------------------------------------------------
/code/kern/trap/trap.h:
--------------------------------------------------------------------------------
1 | #ifndef __KERN_TRAP_TRAP_H__
2 | #define __KERN_TRAP_TRAP_H__
3 |
4 | #include
5 |
6 | /* Trap Numbers */
7 |
8 | /* Processor-defined: */
9 | #define T_DIVIDE 0 // divide error
10 | #define T_DEBUG 1 // debug exception
11 | #define T_NMI 2 // non-maskable interrupt
12 | #define T_BRKPT 3 // breakpoint
13 | #define T_OFLOW 4 // overflow
14 | #define T_BOUND 5 // bounds check
15 | #define T_ILLOP 6 // illegal opcode
16 | #define T_DEVICE 7 // device not available
17 | #define T_DBLFLT 8 // double fault
18 | // #define T_COPROC 9 // reserved (not used since 486)
19 | #define T_TSS 10 // invalid task switch segment
20 | #define T_SEGNP 11 // segment not present
21 | #define T_STACK 12 // stack exception
22 | #define T_GPFLT 13 // general protection fault
23 | #define T_PGFLT 14 // page fault
24 | // #define T_RES 15 // reserved
25 | #define T_FPERR 16 // floating point error
26 | #define T_ALIGN 17 // aligment check
27 | #define T_MCHK 18 // machine check
28 | #define T_SIMDERR 19 // SIMD floating point error
29 |
30 | /* Hardware IRQ numbers. We receive these as (IRQ_OFFSET + IRQ_xx) */
31 | #define IRQ_OFFSET 32 // IRQ 0 corresponds to int IRQ_OFFSET
32 |
33 | #define IRQ_TIMER 0
34 | #define IRQ_KBD 1
35 | #define IRQ_COM1 4
36 | #define IRQ_IDE1 14
37 | #define IRQ_IDE2 15
38 | #define IRQ_ERROR 19
39 | #define IRQ_SPURIOUS 31
40 |
41 | /* registers as pushed by pushal */
42 | struct pushregs {
43 | uint32_t reg_edi;
44 | uint32_t reg_esi;
45 | uint32_t reg_ebp;
46 | uint32_t reg_oesp; /* Useless */
47 | uint32_t reg_ebx;
48 | uint32_t reg_edx;
49 | uint32_t reg_ecx;
50 | uint32_t reg_eax;
51 | };
52 |
53 | struct trapframe {
54 | struct pushregs tf_regs;
55 | uint16_t tf_es;
56 | uint16_t tf_padding1;
57 | uint16_t tf_ds;
58 | uint16_t tf_padding2;
59 | uint32_t tf_trapno;
60 | /* below here defined by x86 hardware */
61 | uint32_t tf_err;
62 | uintptr_t tf_eip;
63 | uint16_t tf_cs;
64 | uint16_t tf_padding3;
65 | uint32_t tf_eflags;
66 | /* below here only when crossing rings, such as from user to kernel */
67 | uintptr_t tf_esp;
68 | uint16_t tf_ss;
69 | uint16_t tf_padding4;
70 | } __attribute__((packed));
71 |
72 | void idt_init(void);
73 | void print_trapframe(struct trapframe *tf);
74 | void print_regs(struct pushregs *regs);
75 | bool trap_in_kernel(struct trapframe *tf);
76 |
77 | #endif /* !__KERN_TRAP_TRAP_H__ */
78 |
79 |
--------------------------------------------------------------------------------
/code/kern/trap/trapentry.S:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | # vectors.S sends all traps here.
4 | .text
5 | .globl __alltraps
6 | __alltraps:
7 | # push registers to build a trap frame
8 | # therefore make the stack look like a struct trapframe
9 | pushl %ds
10 | pushl %es
11 | pushal
12 |
13 | # load GD_KDATA into %ds and %es to set up data segments for kernel
14 | movl $GD_KDATA, %eax
15 | movw %ax, %ds
16 | movw %ax, %es
17 |
18 | # push %esp to pass a pointer to the trapframe as an argument to trap()
19 | pushl %esp
20 |
21 | # call trap(tf), where tf=%esp
22 | call trap
23 |
24 | # pop the pushed stack pointer
25 | popl %esp
26 |
27 | # return falls through to trapret...
28 | .globl __trapret
29 | __trapret:
30 | # restore registers from stack
31 | popal
32 |
33 | # restore %ds and %es
34 | popl %es
35 | popl %ds
36 |
37 | # get rid of the trap number and error code
38 | addl $0x8, %esp
39 | iret
40 |
41 | .globl forkrets
42 | forkrets:
43 | # set stack to this new process's trapframe
44 | movl 4(%esp), %esp
45 | jmp __trapret
46 |
47 |
--------------------------------------------------------------------------------
/code/libs/dirent.h:
--------------------------------------------------------------------------------
1 | #ifndef __LIBS_DIRENT_H__
2 | #define __LIBS_DIRENT_H__
3 |
4 | #include
5 | #include
6 |
7 | struct dirent {
8 | off_t offset;
9 | char name[FS_MAX_FNAME_LEN + 1];
10 | };
11 |
12 | #endif /* !__LIBS_DIRENT_H__ */
13 |
14 |
--------------------------------------------------------------------------------
/code/libs/elf.h:
--------------------------------------------------------------------------------
1 | #ifndef __LIBS_ELF_H__
2 | #define __LIBS_ELF_H__
3 |
4 | #include
5 |
6 | #define ELF_MAGIC 0x464C457FU // "\x7FELF" in little endian
7 |
8 | /* file header */
9 | struct elfhdr {
10 | uint32_t e_magic; // must equal ELF_MAGIC
11 | uint8_t e_elf[12];
12 | uint16_t e_type; // 1=relocatable, 2=executable, 3=shared object, 4=core image
13 | uint16_t e_machine; // 3=x86, 4=68K, etc.
14 | uint32_t e_version; // file version, always 1
15 | uint32_t e_entry; // entry point if executable
16 | uint32_t e_phoff; // file position of program header or 0
17 | uint32_t e_shoff; // file position of section header or 0
18 | uint32_t e_flags; // architecture-specific flags, usually 0
19 | uint16_t e_ehsize; // size of this elf header
20 | uint16_t e_phentsize; // size of an entry in program header
21 | uint16_t e_phnum; // number of entries in program header or 0
22 | uint16_t e_shentsize; // size of an entry in section header
23 | uint16_t e_shnum; // number of entries in section header or 0
24 | uint16_t e_shstrndx; // section number that contains section name strings
25 | };
26 |
27 | /* program section header */
28 | struct proghdr {
29 | uint32_t p_type; // loadable code or data, dynamic linking info,etc.
30 | uint32_t p_offset; // file offset of segment
31 | uint32_t p_va; // virtual address to map segment
32 | uint32_t p_pa; // physical address, not used
33 | uint32_t p_filesz; // size of segment in file
34 | uint32_t p_memsz; // size of segment in memory (bigger if contains bss)
35 | uint32_t p_flags; // read/write/execute bits
36 | uint32_t p_align; // required alignment, invariably hardware page size
37 | };
38 |
39 | /* values for Proghdr::p_type */
40 | #define ELF_PT_LOAD 1
41 |
42 | /* flag bits for Proghdr::p_flags */
43 | #define ELF_PF_X 1
44 | #define ELF_PF_W 2
45 | #define ELF_PF_R 4
46 |
47 | #endif /* !__LIBS_ELF_H__ */
48 |
49 |
--------------------------------------------------------------------------------
/code/libs/error.h:
--------------------------------------------------------------------------------
1 | #ifndef __LIBS_ERROR_H__
2 | #define __LIBS_ERROR_H__
3 |
4 | /* kernel error codes -- keep in sync with list in lib/printfmt.c */
5 | #define E_UNSPECIFIED 1 // Unspecified or unknown problem
6 | #define E_BAD_PROC 2 // Process doesn't exist or otherwise
7 | #define E_INVAL 3 // Invalid parameter
8 | #define E_NO_MEM 4 // Request failed due to memory shortage
9 | #define E_NO_FREE_PROC 5 // Attempt to create a new process beyond
10 | #define E_FAULT 6 // Memory fault
11 | #define E_SWAP_FAULT 7 // SWAP READ/WRITE fault
12 | #define E_INVAL_ELF 8 // Invalid elf file
13 | #define E_KILLED 9 // Process is killed
14 | #define E_PANIC 10 // Panic Failure
15 | #define E_TIMEOUT 11 // Timeout
16 | #define E_TOO_BIG 12 // Argument is Too Big
17 | #define E_NO_DEV 13 // No such Device
18 | #define E_NA_DEV 14 // Device Not Available
19 | #define E_BUSY 15 // Device/File is Busy
20 | #define E_NOENT 16 // No Such File or Directory
21 | #define E_ISDIR 17 // Is a Directory
22 | #define E_NOTDIR 18 // Not a Directory
23 | #define E_XDEV 19 // Cross Device-Link
24 | #define E_UNIMP 20 // Unimplemented Feature
25 | #define E_SEEK 21 // Illegal Seek
26 | #define E_MAX_OPEN 22 // Too Many Files are Open
27 | #define E_EXISTS 23 // File/Directory Already Exists
28 | #define E_NOTEMPTY 24 // Directory is Not Empty
29 | /* the maximum allowed */
30 | #define MAXERROR 24
31 |
32 | #endif /* !__LIBS_ERROR_H__ */
33 |
34 |
--------------------------------------------------------------------------------
/code/libs/hash.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | /* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
4 | #define GOLDEN_RATIO_PRIME_32 0x9e370001UL
5 |
6 | /* *
7 | * hash32 - generate a hash value in the range [0, 2^@bits - 1]
8 | * @val: the input value
9 | * @bits: the number of bits in a return value
10 | *
11 | * High bits are more random, so we use them.
12 | * */
13 | uint32_t
14 | hash32(uint32_t val, unsigned int bits) {
15 | uint32_t hash = val * GOLDEN_RATIO_PRIME_32;
16 | return (hash >> (32 - bits));
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/code/libs/mboxbuf.h:
--------------------------------------------------------------------------------
1 | #ifndef __LIBS_MBOXBUF_H__
2 | #define __LIBS_MBOXBUF_H__
3 |
4 | #include
5 |
6 | #define MAX_MSG_SLOTS 0x1000
7 | #define MAX_MSG_BYTES 0x10000
8 |
9 | struct mboxbuf {
10 | int from;
11 | size_t len;
12 | size_t size;
13 | void *data;
14 | };
15 |
16 | struct mboxinfo {
17 | size_t slots;
18 | size_t max_slots;
19 | bool inuse;
20 | bool has_sender;
21 | bool has_receiver;
22 | };
23 |
24 | #endif /* !__LIBS_MBOXBUF_H__ */
25 |
26 |
27 |
--------------------------------------------------------------------------------
/code/libs/rand.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | static unsigned long long next = 1;
5 |
6 | /* *
7 | * rand - returns a pseudo-random integer
8 | *
9 | * The rand() function return a value in the range [0, RAND_MAX].
10 | * */
11 | int
12 | rand(void) {
13 | next = (next * 0x5DEECE66DLL + 0xBLL) & ((1LL << 48) - 1);
14 | unsigned long long result = (next >> 12);
15 | return (int)do_div(result, RAND_MAX + 1);
16 | }
17 |
18 | /* *
19 | * srand - seed the random number generator with the given number
20 | * @seed: the required seed number
21 | * */
22 | void
23 | srand(unsigned int seed) {
24 | next = seed;
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/code/libs/stat.h:
--------------------------------------------------------------------------------
1 | #ifndef __LIBS_STAT_H__
2 | #define __LIBS_STAT_H__
3 |
4 | #include
5 |
6 | struct stat {
7 | uint32_t st_mode; // protection mode and file type
8 | size_t st_nlinks; // number of hard links
9 | size_t st_blocks; // number of blocks file is using
10 | size_t st_size; // file size (bytes)
11 | };
12 |
13 | #define S_IFMT 070000 // mask for type of file
14 | #define S_IFREG 010000 // ordinary regular file
15 | #define S_IFDIR 020000 // directory
16 | #define S_IFLNK 030000 // symbolic link
17 | #define S_IFCHR 040000 // character device
18 | #define S_IFBLK 050000 // block device
19 |
20 | #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) // regular file
21 | #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) // directory
22 | #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) // symlink
23 | #define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) // char device
24 | #define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) // block device
25 |
26 | #endif /* !__LIBS_STAT_H__ */
27 |
28 |
--------------------------------------------------------------------------------
/code/libs/stdarg.h:
--------------------------------------------------------------------------------
1 | #ifndef __LIBS_STDARG_H__
2 | #define __LIBS_STDARG_H__
3 |
4 | /* compiler provides size of save area */
5 | typedef __builtin_va_list va_list;
6 |
7 | #define va_start(ap, last) (__builtin_va_start(ap, last))
8 | #define va_arg(ap, type) (__builtin_va_arg(ap, type))
9 | #define va_end(ap) /*nothing*/
10 |
11 | #endif /* !__LIBS_STDARG_H__ */
12 |
13 |
--------------------------------------------------------------------------------
/code/libs/stdio.h:
--------------------------------------------------------------------------------
1 | #ifndef __LIBS_STDIO_H__
2 | #define __LIBS_STDIO_H__
3 |
4 | #include
5 | #include
6 |
7 | /* kern/libs/stdio.c */
8 | int cprintf(const char *fmt, ...);
9 | int vcprintf(const char *fmt, va_list ap);
10 | void cputchar(int c);
11 | int cputs(const char *str);
12 | int getchar(void);
13 |
14 | /* kern/libs/readline.c */
15 | char *readline(const char *prompt);
16 |
17 | /* libs/printfmt.c */
18 | void printfmt(void (*putch)(int, void *, int), int fd, void *putdat, const char *fmt, ...);
19 | void vprintfmt(void (*putch)(int, void *, int), int fd, void *putdat, const char *fmt, va_list ap);
20 | int snprintf(char *str, size_t size, const char *fmt, ...);
21 | int vsnprintf(char *str, size_t size, const char *fmt, va_list ap);
22 |
23 | #endif /* !__LIBS_STDIO_H__ */
24 |
25 |
--------------------------------------------------------------------------------
/code/libs/stdlib.h:
--------------------------------------------------------------------------------
1 | #ifndef __LIBS_STDLIB_H__
2 | #define __LIBS_STDLIB_H__
3 |
4 | #include
5 |
6 | /* the largest number rand will return */
7 | #define RAND_MAX 2147483647UL
8 |
9 | /* libs/rand.c */
10 | int rand(void);
11 | void srand(unsigned int seed);
12 |
13 | /* libs/hash.c */
14 | uint32_t hash32(uint32_t val, unsigned int bits);
15 |
16 | #endif /* !__LIBS_RAND_H__ */
17 |
18 |
--------------------------------------------------------------------------------
/code/libs/string.h:
--------------------------------------------------------------------------------
1 | #ifndef __LIBS_STRING_H__
2 | #define __LIBS_STRING_H__
3 |
4 | #include
5 |
6 | size_t strlen(const char *s);
7 | size_t strnlen(const char *s, size_t len);
8 |
9 | char *strcpy(char *dst, const char *src);
10 | char *strncpy(char *dst, const char *src, size_t len);
11 | char *strcat(char *dst, const char *src);
12 | char *strdup(const char *src);
13 | char *stradd(const char *src1, const char *src2);
14 |
15 | int strcmp(const char *s1, const char *s2);
16 | int strncmp(const char *s1, const char *s2, size_t n);
17 |
18 | char *strchr(const char *s, char c);
19 | char *strfind(const char *s, char c);
20 | long strtol(const char *s, char **endptr, int base);
21 |
22 | void *memset(void *s, char c, size_t n);
23 | void *memmove(void *dst, const void *src, size_t n);
24 | void *memcpy(void *dst, const void *src, size_t n);
25 | int memcmp(const void *v1, const void *v2, size_t n);
26 |
27 | #endif /* !__LIBS_STRING_H__ */
28 |
29 |
--------------------------------------------------------------------------------
/code/libs/types.h:
--------------------------------------------------------------------------------
1 | #ifndef __LIBS_TYPES_H__
2 | #define __LIBS_TYPES_H__
3 |
4 | #ifndef NULL
5 | #define NULL ((void *)0)
6 | #endif
7 |
8 | #define CHAR_BIT 8
9 |
10 | /* Represents true-or-false values */
11 | typedef int bool;
12 |
13 | /* Explicitly-sized versions of integer types */
14 | typedef char int8_t;
15 | typedef unsigned char uint8_t;
16 | typedef short int16_t;
17 | typedef unsigned short uint16_t;
18 | typedef int int32_t;
19 | typedef unsigned int uint32_t;
20 | typedef long long int64_t;
21 | typedef unsigned long long uint64_t;
22 |
23 | /* *
24 | * Pointers and addresses are 32 bits long.
25 | * We use pointer types to represent addresses,
26 | * uintptr_t to represent the numerical values of addresses.
27 | * */
28 | typedef int32_t intptr_t;
29 | typedef uint32_t uintptr_t;
30 |
31 | /* size_t is used for memory object sizes */
32 | typedef uintptr_t size_t;
33 |
34 | /* off_t is used for file offsets and lengths */
35 | typedef intptr_t off_t;
36 |
37 | /* used for page numbers */
38 | typedef size_t ppn_t;
39 |
40 | /* sem_t is used for semaphore id */
41 | typedef uintptr_t sem_t;
42 |
43 | /* *
44 | * Rounding operations (efficient when n is a power of 2)
45 | * Round down to the nearest multiple of n
46 | * */
47 | #define ROUNDDOWN(a, n) ({ \
48 | size_t __a = (size_t)(a); \
49 | (typeof(a))(__a - __a % (n)); \
50 | })
51 |
52 | /* Round up to the nearest multiple of n */
53 | #define ROUNDUP(a, n) ({ \
54 | size_t __n = (size_t)(n); \
55 | (typeof(a))(ROUNDDOWN((size_t)(a) + __n - 1, __n)); \
56 | })
57 |
58 | /* Round up the result of dividing of n */
59 | #define ROUNDUP_DIV(a, n) ({ \
60 | uint32_t __n = (uint32_t)(n); \
61 | (typeof(a))(((a) + __n - 1) / __n); \
62 | })
63 |
64 | /* Return the offset of 'member' relative to the beginning of a struct type */
65 | #define offsetof(type, member) \
66 | ((size_t)(&((type *)0)->member))
67 |
68 | /* *
69 | * to_struct - get the struct from a ptr
70 | * @ptr: a struct pointer of member
71 | * @type: the type of the struct this is embedded in
72 | * @member: the name of the member within the struct
73 | * */
74 | #define to_struct(ptr, type, member) \
75 | ((type *)((char *)(ptr) - offsetof(type, member)))
76 |
77 | #endif /* !__LIBS_TYPES_H__ */
78 |
79 |
--------------------------------------------------------------------------------
/code/libs/unistd.h:
--------------------------------------------------------------------------------
1 | #ifndef __LIBS_UNISTD_H__
2 | #define __LIBS_UNISTD_H__
3 |
4 | #define T_SYSCALL 0x80
5 |
6 | /* syscall number */
7 | #define SYS_exit 1
8 | #define SYS_fork 2
9 | #define SYS_wait 3
10 | #define SYS_exec 4
11 | #define SYS_clone 5
12 | #define SYS_exit_thread 9
13 | #define SYS_yield 10
14 | #define SYS_sleep 11
15 | #define SYS_kill 12
16 | #define SYS_gettime 17
17 | #define SYS_getpid 18
18 | #define SYS_brk 19
19 | #define SYS_mmap 20
20 | #define SYS_munmap 21
21 | #define SYS_shmem 22
22 | #define SYS_putc 30
23 | #define SYS_pgdir 31
24 | #define SYS_sem_init 40
25 | #define SYS_sem_post 41
26 | #define SYS_sem_wait 42
27 | #define SYS_sem_free 43
28 | #define SYS_sem_get_value 44
29 | #define SYS_event_send 48
30 | #define SYS_event_recv 49
31 | #define SYS_mbox_init 50
32 | #define SYS_mbox_send 51
33 | #define SYS_mbox_recv 52
34 | #define SYS_mbox_free 53
35 | #define SYS_mbox_info 54
36 | #define SYS_open 100
37 | #define SYS_close 101
38 | #define SYS_read 102
39 | #define SYS_write 103
40 | #define SYS_seek 104
41 | #define SYS_fstat 110
42 | #define SYS_fsync 111
43 | #define SYS_chdir 120
44 | #define SYS_getcwd 121
45 | #define SYS_mkdir 122
46 | #define SYS_link 123
47 | #define SYS_rename 124
48 | #define SYS_readlink 125
49 | #define SYS_symlink 126
50 | #define SYS_unlink 127
51 | #define SYS_getdirentry 128
52 | #define SYS_dup 130
53 | #define SYS_pipe 140
54 | #define SYS_mkfifo 141
55 |
56 | /* SYS_fork flags */
57 | #define CLONE_VM 0x00000100 // set if VM shared between processes
58 | #define CLONE_THREAD 0x00000200 // thread group
59 | #define CLONE_SEM 0x00000400 // set if shared between processes
60 | #define CLONE_FS 0x00000800 // set if shared between processes
61 |
62 | /* SYS_mmap flags */
63 | #define MMAP_WRITE 0x00000100
64 | #define MMAP_STACK 0x00000200
65 |
66 | /* VFS flags */
67 | // flags for open: choose one of these
68 | #define O_RDONLY 0 // open for reading only
69 | #define O_WRONLY 1 // open for writing only
70 | #define O_RDWR 2 // open for reading and writing
71 | // then or in any of these:
72 | #define O_CREAT 0x00000004 // create file if it does not exist
73 | #define O_EXCL 0x00000008 // error if O_CREAT and the file exists
74 | #define O_TRUNC 0x00000010 // truncate file upon open
75 | #define O_APPEND 0x00000020 // append on each write
76 | // additonal related definition
77 | #define O_ACCMODE 3 // mask for O_RDONLY / O_WRONLY / O_RDWR
78 |
79 | #define NO_FD -0x9527 // invalid fd
80 |
81 | /* lseek codes */
82 | #define LSEEK_SET 0 // seek relative to beginning of file
83 | #define LSEEK_CUR 1 // seek relative to current position in file
84 | #define LSEEK_END 2 // seek relative to end of file
85 |
86 | #define FS_MAX_DNAME_LEN 31
87 | #define FS_MAX_FNAME_LEN 255
88 | #define FS_MAX_FPATH_LEN 4095
89 |
90 | #define EXEC_MAX_ARG_NUM 32
91 | #define EXEC_MAX_ARG_LEN 4095
92 |
93 | #endif /* !__LIBS_UNISTD_H__ */
94 |
95 |
--------------------------------------------------------------------------------
/code/tools/function.mk:
--------------------------------------------------------------------------------
1 | OBJPREFIX := __objs_
2 |
3 | .SECONDEXPANSION:
4 | # -------------------- function begin --------------------
5 |
6 | # list all files in some directories: (#directories, #types)
7 | listf = $(filter $(if $(2),$(addprefix %.,$(2)),%),\
8 | $(wildcard $(addsuffix $(SLASH)*,$(1))))
9 |
10 | # get .o obj files: (#files[, packet])
11 | toobj = $(addprefix $(OBJDIR)$(SLASH)$(if $(2),$(2)$(SLASH)),\
12 | $(addsuffix .o,$(basename $(1))))
13 |
14 | # get .d dependency files: (#files[, packet])
15 | todep = $(patsubst %.o,%.d,$(call toobj,$(1),$(2)))
16 |
17 | totarget = $(addprefix $(BINDIR)$(SLASH),$(1))
18 |
19 | # change $(name) to $(OBJPREFIX)$(name): (#names)
20 | packetname = $(if $(1),$(addprefix $(OBJPREFIX),$(1)),$(OBJPREFIX))
21 |
22 | # cc compile template, generate rule for dep, obj: (file, cc[, flags, dir])
23 | define cc_template
24 | $$(call todep,$(1),$(4)): $(1) | $$$$(dir $$$$@)
25 | @$(2) -I$$(dir $(1)) $(3) -MM $$< -MT "$$(patsubst %.d,%.o,$$@) $$@"> $$@
26 | $$(call toobj,$(1),$(4)): $(1) | $$$$(dir $$$$@)
27 | @echo + cc $$<
28 | $(V)$(2) -I$$(dir $(1)) $(3) -c $$< -o $$@
29 | ALLOBJS += $$(call toobj,$(1),$(4))
30 | endef
31 |
32 | # compile file: (#files, cc[, flags, dir])
33 | define do_cc_compile
34 | $$(foreach f,$(1),$$(eval $$(call cc_template,$$(f),$(2),$(3),$(4))))
35 | endef
36 |
37 | # add files to packet: (#files, cc[, flags, packet, dir])
38 | define do_add_files_to_packet
39 | __temp_packet__ := $(call packetname,$(4))
40 | ifeq ($$(origin $$(__temp_packet__)),undefined)
41 | $$(__temp_packet__) :=
42 | endif
43 | __temp_objs__ := $(call toobj,$(1),$(5))
44 | $$(foreach f,$(1),$$(eval $$(call cc_template,$$(f),$(2),$(3),$(5))))
45 | $$(__temp_packet__) += $$(__temp_objs__)
46 | endef
47 |
48 | # add objs to packet: (#objs, packet)
49 | define do_add_objs_to_packet
50 | __temp_packet__ := $(call packetname,$(2))
51 | ifeq ($$(origin $$(__temp_packet__)),undefined)
52 | $$(__temp_packet__) :=
53 | endif
54 | $$(__temp_packet__) += $(1)
55 | endef
56 |
57 | # add packets and objs to target (target, #packes, #objs[, cc, flags])
58 | define do_create_target
59 | __temp_target__ = $(call totarget,$(1))
60 | __temp_objs__ = $$(foreach p,$(call packetname,$(2)),$$($$(p))) $(3)
61 | TARGETS += $$(__temp_target__)
62 | ifneq ($(4),)
63 | $$(__temp_target__): $$(__temp_objs__) | $$$$(dir $$$$@)
64 | $(V)$(4) $(5) $$^ -o $$@
65 | else
66 | $$(__temp_target__): $$(__temp_objs__) | $$$$(dir $$$$@)
67 | endif
68 | endef
69 |
70 | # finish all
71 | define do_finish_all
72 | ALLDEPS = $$(ALLOBJS:.o=.d)
73 | $$(sort $$(dir $$(ALLOBJS)) $(BINDIR)$(SLASH) $(OBJDIR)$(SLASH)):
74 | @$(MKDIR) $$@
75 | endef
76 |
77 | # -------------------- function end --------------------
78 | # compile file: (#files, cc[, flags, dir])
79 | cc_compile = $(eval $(call do_cc_compile,$(1),$(2),$(3),$(4)))
80 |
81 | # add files to packet: (#files, cc[, flags, packet, dir])
82 | add_files = $(eval $(call do_add_files_to_packet,$(1),$(2),$(3),$(4),$(5)))
83 |
84 | # add objs to packet: (#objs, packet)
85 | add_objs = $(eval $(call do_add_objs_to_packet,$(1),$(2)))
86 |
87 | # add packets and objs to target (target, #packes, #objs, cc, [, flags])
88 | create_target = $(eval $(call do_create_target,$(1),$(2),$(3),$(4),$(5)))
89 |
90 | read_packet = $(foreach p,$(call packetname,$(1)),$($(p)))
91 |
92 | add_dependency = $(eval $(1): $(2))
93 |
94 | finish_all = $(eval $(call do_finish_all))
95 |
96 |
--------------------------------------------------------------------------------
/code/tools/gdbinit:
--------------------------------------------------------------------------------
1 | file bin/kernel
2 | target remote :1234
3 | break kern_init
4 |
--------------------------------------------------------------------------------
/code/tools/kernel.ld:
--------------------------------------------------------------------------------
1 | /* Simple linker script for the ucore kernel.
2 | See the GNU ld 'info' manual ("info ld") to learn the syntax. */
3 |
4 | OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
5 | OUTPUT_ARCH(i386)
6 | ENTRY(kern_entry)
7 |
8 | SECTIONS {
9 | /* Load the kernel at this address: "." means the current address */
10 | . = 0xC0100000;
11 |
12 | .text : {
13 | *(.text .stub .text.* .gnu.linkonce.t.*)
14 | }
15 |
16 | PROVIDE(etext = .); /* Define the 'etext' symbol to this value */
17 |
18 | .rodata : {
19 | *(.rodata .rodata.* .gnu.linkonce.r.*)
20 | }
21 |
22 | /* Include debugging information in kernel memory */
23 | .stab : {
24 | PROVIDE(__STAB_BEGIN__ = .);
25 | *(.stab);
26 | PROVIDE(__STAB_END__ = .);
27 | BYTE(0) /* Force the linker to allocate space
28 | for this section */
29 | }
30 |
31 | .stabstr : {
32 | PROVIDE(__STABSTR_BEGIN__ = .);
33 | *(.stabstr);
34 | PROVIDE(__STABSTR_END__ = .);
35 | BYTE(0) /* Force the linker to allocate space
36 | for this section */
37 | }
38 |
39 | /* Adjust the address for the data segment to the next page */
40 | . = ALIGN(0x1000);
41 |
42 | /* The data segment */
43 | .data : {
44 | *(.data)
45 | }
46 |
47 | PROVIDE(edata = .);
48 |
49 | .bss : {
50 | *(.bss)
51 | }
52 |
53 | PROVIDE(end = .);
54 |
55 | /DISCARD/ : {
56 | *(.eh_frame .note.GNU-stack)
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/code/tools/sign.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int
7 | main(int argc, char *argv[]) {
8 | struct stat st;
9 | if (argc != 3) {
10 | fprintf(stderr, "Usage: