├── doc ├── os.png ├── dirty_block_cache.txt └── memory.txt ├── TODO ├── video ├── sys.c ├── Makefile └── text.c ├── user ├── utils │ ├── sync.c │ ├── pwd.c │ ├── rm.c │ ├── rmdir.c │ ├── mkdir.c │ ├── cat.c │ ├── stat.c │ ├── ls.c │ └── cp.c ├── libc │ ├── entry.S │ ├── Makefile │ ├── system.c │ ├── file.c │ ├── print.c │ ├── syscall.c │ └── string.c ├── hello.c ├── include │ ├── ctype.h │ ├── varg.h │ ├── string.h │ ├── types.h │ ├── syscall.h │ └── ulib.h ├── shell │ ├── Makefile │ ├── process.c │ ├── parse.c │ ├── main.c │ └── builtin.c ├── Makefile └── init.c ├── include ├── compile.h ├── varg.h ├── print.h ├── dirty_block.h ├── asm.h ├── string.h ├── disk.h ├── wait_queue.h ├── boot.h ├── types.h ├── file.h ├── elf.h ├── syscall.h ├── block.h ├── fs.h ├── 8259A.h ├── slab.h ├── task.h ├── mm.h ├── pit.h ├── inode.h ├── page.h ├── keyboard.h ├── paging.h ├── int.h ├── minix_fs.h └── list.h ├── mm ├── Makefile ├── memory.c ├── page.c ├── boot_memory.c └── buddy.c ├── keyboard ├── Makefile ├── keybuf.c ├── key.c └── scancode.c ├── kernel ├── timer.c ├── pit.c ├── Makefile ├── wait_queue.c ├── init.c ├── syscall.c ├── entry.S ├── schedule.c ├── interrupt.S ├── exit.c ├── task.c ├── fork.c ├── print.c ├── int.c └── string.c ├── fs ├── minix │ ├── Makefile │ ├── test.c │ └── init.c ├── filesystem.c ├── Makefile ├── hd.c ├── ide.c ├── dirty_block.c ├── path.c ├── file.c ├── sys.c ├── inode.c └── block.c ├── .gitignore ├── tools ├── Makefile ├── bochs.bxrc ├── fs.h ├── build.c └── mkfs.minix.c ├── README.md ├── boot ├── Makefile ├── main.c └── boot.S ├── kernel.ld └── Makefile /doc/os.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chobits/tinyos/HEAD/doc/os.png -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | TODOLIST: 2 | - nic driver 3 | - merge tapip(github.com/chobits/tapip) as TCP/IP stack 4 | - lock 5 | -------------------------------------------------------------------------------- /video/sys.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int sys_puts(char *str) 4 | { 5 | return text_puts(str); 6 | } 7 | -------------------------------------------------------------------------------- /user/utils/sync.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) 4 | { 5 | sync(); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /user/libc/entry.S: -------------------------------------------------------------------------------- 1 | .code32 2 | .text 3 | 4 | .globl _start 5 | _start: 6 | call main 7 | _exit: 8 | push %eax 9 | call exit 10 | _die: 11 | jmp _die 12 | -------------------------------------------------------------------------------- /include/compile.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMPILE_H 2 | #define __COMPILE_H 3 | 4 | #undef _inline 5 | #define _inline inline __attribute__((always_inline)) 6 | 7 | #endif /* compile.h */ 8 | -------------------------------------------------------------------------------- /user/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) 4 | { 5 | printf("[%d] %s", getpid(), argv[1]); 6 | exit(getpid()); 7 | return 0; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /user/include/ctype.h: -------------------------------------------------------------------------------- 1 | #ifndef __CTYPE_H 2 | #define __CTYPE_H 3 | 4 | #include 5 | 6 | static _inline int isblank(int c) 7 | { 8 | return ((c == ' ') || (c == '\t')); 9 | } 10 | 11 | #endif /* ctype.h */ 12 | -------------------------------------------------------------------------------- /video/Makefile: -------------------------------------------------------------------------------- 1 | SUBDIR = video 2 | 3 | video.o:text.o sys.o 4 | $(Q)$(LD) $(LDFLAGS) -r $^ -o $@ 5 | @echo " [LD] $(SUBDIR)/$@" 6 | 7 | %.o:%.c 8 | $(Q)$(CC) $(CFLAGS) $< -c -o $@ 9 | @echo " [CC] $(SUBDIR)/$@" 10 | -------------------------------------------------------------------------------- /mm/Makefile: -------------------------------------------------------------------------------- 1 | SUBDIR = mm 2 | 3 | mm.o:memory.o buddy.o boot_memory.o paging.o slab.o page.o 4 | $(Q)$(LD) $(LDFLAGS) -r $^ -o $@ 5 | @echo " [LD] $(SUBDIR)/$@" 6 | 7 | %.o:%.c 8 | $(Q)$(CC) $(CFLAGS) $< -c -o $@ 9 | @echo " [CC] $(SUBDIR)/$@" 10 | -------------------------------------------------------------------------------- /keyboard/Makefile: -------------------------------------------------------------------------------- 1 | SUBDIR = keyboard 2 | 3 | OBJS = key.o keybuf.o scancode.o 4 | 5 | keyboard.o:$(OBJS) 6 | $(Q)$(LD) $(LDFLAGS) -r $^ -o $@ 7 | @echo " [LD] $(SUBDIR)/$@" 8 | 9 | %.o:%.c 10 | $(Q)$(CC) $(CFLAGS) $< -c -o $@ 11 | @echo " [CC] $(SUBDIR)/$@" 12 | 13 | -------------------------------------------------------------------------------- /kernel/timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | unsigned int ticks = 0; 7 | 8 | extern void task_switch(struct task *); 9 | void timer_interrupt(struct regs *reg) 10 | { 11 | ticks++; 12 | schedule(); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /fs/minix/Makefile: -------------------------------------------------------------------------------- 1 | MINIXSUBDIR = $(SUBDIR)/minix 2 | CFLAGS += -I../../include 3 | 4 | minixfs.o:init.o inode.o map.o test.o 5 | $(Q)$(LD) $(LDFLAGS) -r $^ -o $@ 6 | @echo " [LD] $(MINIXSUBDIR)/$@" 7 | 8 | %.o:%.c 9 | $(Q)$(CC) $(CFLAGS) $< -c -o $@ 10 | @echo " [CC] $(MINIXSUBDIR)/$@" 11 | -------------------------------------------------------------------------------- /user/utils/pwd.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define BUF_SIZE 4096 4 | static char buf[BUF_SIZE]; 5 | 6 | int main(int argc, char **argv) 7 | { 8 | char *cwd; 9 | 10 | cwd = getcwd(buf, BUF_SIZE); 11 | if (!cwd) 12 | cwd = "error"; 13 | 14 | printf("%s\n", cwd); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /mm/memory.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern void boot_memory_init(void); 4 | extern void pages_init(void); 5 | extern void paging_init(void); 6 | extern void slab_init(void); 7 | 8 | void mm_init(void) 9 | { 10 | boot_memory_init(); 11 | paging_init(); 12 | pages_init(); 13 | slab_init(); 14 | } 15 | -------------------------------------------------------------------------------- /user/shell/Makefile: -------------------------------------------------------------------------------- 1 | SHELLSUBDIR = $(SUBDIR)/libc 2 | CFLAGS += -I../include 3 | 4 | shell.o:main.o builtin.o process.o parse.o 5 | $(Q)$(LD) $(LDFLAGS) -r $^ -o $@ 6 | @echo " [LD] $(SHELLSUBDIR)/$@" 7 | 8 | %.o:%.c 9 | $(Q)$(CC) $(CFLAGS) $< -c -o $@ 10 | @echo " [CC] $(SHELLSUBDIR)/$@" 11 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.sym 3 | *.asm 4 | .offset 5 | boot/boot.bin 6 | boot/boot.elf 7 | disk.img 8 | kernel.bin 9 | kernel.elf 10 | tools/build 11 | tools/mkfs.minix 12 | user/cat 13 | user/cp 14 | user/hello 15 | user/init 16 | user/ls 17 | user/mkdir 18 | user/rm 19 | user/rmdir 20 | user/sh 21 | user/stat 22 | user/sync 23 | user/pwd 24 | 25 | -------------------------------------------------------------------------------- /user/utils/rm.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) 4 | { 5 | int i; 6 | if (argc == 1) { 7 | printf("Usage: rm files...\n"); 8 | return -1; 9 | } 10 | for (i = 1; i < argc; i++) { 11 | /* make directory */ 12 | if (rm(argv[i]) < 0) 13 | printf("cannot remove files: %s\n", argv[i]); 14 | } 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /user/utils/rmdir.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) 4 | { 5 | int i; 6 | if (argc == 1) { 7 | printf("Usage: rmdir dirs...\n"); 8 | return -1; 9 | } 10 | for (i = 1; i < argc; i++) { 11 | /* make directory */ 12 | if (rmdir(argv[i]) < 0) 13 | printf("cannot remove directory: %s\n", argv[i]); 14 | } 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /include/varg.h: -------------------------------------------------------------------------------- 1 | #ifndef __VARG_H 2 | #define __VARG_H 3 | 4 | typedef char *va_list; 5 | #define va_mask (sizeof(int) - 1) 6 | #define va_size(type) ((sizeof(type) + va_mask) & ~va_mask) 7 | #define va_start(ap, last) (ap = (va_list)&(last) + va_size(last)) 8 | #define va_arg(ap, type) (ap += va_size(type), *(type *)(ap - va_size(type))) 9 | #define va_end(ap) 10 | 11 | #endif /* varg.h */ 12 | -------------------------------------------------------------------------------- /user/include/varg.h: -------------------------------------------------------------------------------- 1 | #ifndef __VARG_H 2 | #define __VARG_H 3 | 4 | typedef char *va_list; 5 | #define va_mask (sizeof(int) - 1) 6 | #define va_size(type) ((sizeof(type) + va_mask) & ~va_mask) 7 | #define va_start(ap, last) (ap = (va_list)&(last) + va_size(last)) 8 | #define va_arg(ap, type) (ap += va_size(type), *(type *)(ap - va_size(type))) 9 | #define va_end(ap) 10 | 11 | #endif /* varg.h */ 12 | -------------------------------------------------------------------------------- /user/libc/Makefile: -------------------------------------------------------------------------------- 1 | LIBCSUBDIR = $(SUBDIR)/libc 2 | CFLAGS += -I../include 3 | 4 | libc.o:entry.o system.o syscall.o string.o print.o file.o 5 | $(Q)$(LD) $(LDFLAGS) -r $^ -o $@ 6 | @echo " [LD] $(LIBCSUBDIR)/$@" 7 | 8 | %.o:%.c 9 | $(Q)$(CC) $(CFLAGS) $< -c -o $@ 10 | @echo " [CC] $(LIBCSUBDIR)/$@" 11 | 12 | %.o:%.S 13 | $(Q)$(CC) $(CFLAGS) $< -c -o $@ 14 | @echo " [CC] $(LIBCSUBDIR)/$@" 15 | -------------------------------------------------------------------------------- /fs/filesystem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void minix_fs_init(void); 7 | struct slab *file_slab; 8 | void fs_init(void) 9 | { 10 | /* init virtual file system */ 11 | file_slab = alloc_slab(sizeof(struct file)); 12 | if (!file_slab) 13 | panic("No memory for file slab"); 14 | /* load real file system */ 15 | minix_fs_init(); 16 | } 17 | -------------------------------------------------------------------------------- /tools/Makefile: -------------------------------------------------------------------------------- 1 | #Author:chobit_s 2 | all:mkfs.minix 3 | mkfs.minix:mkfs.minix.c 4 | gcc $< -o $@ 5 | 6 | #generate 1024MB file(data:0),which can be used as block device 7 | data: 8 | dd if=/dev/zero of=./data bs=1024 count=1024 9 | install: 10 | sudo mount -t minix data -o loop test_mount_dir/ 11 | un: 12 | sudo umount test_mount_dir/ 13 | clean: 14 | rm -rf data mkfs.minix 15 | -------------------------------------------------------------------------------- /user/utils/mkdir.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) 4 | { 5 | int fd, i; 6 | if (argc == 1) { 7 | printf("Usage: mkdir dirs...\n"); 8 | return -1; 9 | } 10 | for (i = 1; i < argc; i++) { 11 | /* make directory */ 12 | fd = mkdir(argv[i], 0); 13 | if (fd < 0) 14 | printf("cannot make directory: %s\n", argv[i]); 15 | else 16 | close(fd); 17 | } 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /include/print.h: -------------------------------------------------------------------------------- 1 | #ifndef __PRINT_H 2 | #define __PRINT_H 3 | 4 | extern int text_puts(char *s); 5 | extern int text_nputs(char *s, int n); 6 | extern void text_putc(char c); 7 | extern int printk(char *format, ...); 8 | extern void panic(char *format, ...); 9 | struct regs; 10 | extern void dump_stack(struct regs *); 11 | 12 | #define debug(fmt, argv...) printk("%s: "fmt"\n", __FUNCTION__, ##argv) 13 | 14 | #endif /* print.h */ 15 | -------------------------------------------------------------------------------- /kernel/pit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include <8259A.h> 3 | #include 4 | #include 5 | #include 6 | 7 | void pit_init(void) 8 | { 9 | /* channel 0, rate generator, low&high bytes */ 10 | outb(PIT_MODE, PIT_MODE_CH0 | PIT_MODE_2 | PIT_MODE_LOHI); 11 | outb(PIT_CH0, FREQ_DIV & 255); /* low byte */ 12 | outb(PIT_CH0, FREQ_DIV >> 8); /* high byte */ 13 | unmask_8259A(IRQ_TIMER); 14 | printk("pit init\n"); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /fs/Makefile: -------------------------------------------------------------------------------- 1 | SUBDIR = fs 2 | export SUBDIR 3 | 4 | SRC = $(wildcard *.c) 5 | OBJS = $(patsubst %.c, %.o, $(SRC)) minix/minixfs.o 6 | 7 | fs.o:$(OBJS) 8 | $(Q)$(LD) $(LDFLAGS) -r $^ -o $@ 9 | @echo " [LD] $(SUBDIR)/$@" 10 | 11 | minix/minixfs.o:minix/*.c 12 | @make -C minix/ 13 | 14 | %.o:%.c 15 | $(Q)$(CC) $(CFLAGS) $< -c -o $@ 16 | @echo " [CC] $(SUBDIR)/$@" 17 | 18 | %.o:%.S 19 | $(Q)$(CC) $(CFLAGS) -D__ASM__ $< -c -o $@ 20 | @echo " [CC] $(SUBDIR)/$@" 21 | -------------------------------------------------------------------------------- /kernel/Makefile: -------------------------------------------------------------------------------- 1 | SUBDIR = kernel 2 | 3 | OBJS = entry.o init.o interrupt.o int.o print.o string.o task.o execute.o\ 4 | syscall.o fork.o schedule.o exit.o wait_queue.o pit.o timer.o 5 | 6 | kernel.o:$(OBJS) 7 | $(Q)$(LD) $(LDFLAGS) -r $^ -o $@ 8 | @echo " [LD] $(SUBDIR)/$@" 9 | 10 | %.o:%.c 11 | $(Q)$(CC) $(CFLAGS) $< -c -o $@ 12 | @echo " [CC] $(SUBDIR)/$@" 13 | 14 | %.o:%.S 15 | $(Q)$(CC) $(CFLAGS) -D__ASM__ $< -c -o $@ 16 | @echo " [CC] $(SUBDIR)/$@" 17 | -------------------------------------------------------------------------------- /include/dirty_block.h: -------------------------------------------------------------------------------- 1 | #ifndef __DIRTY_BLOCK_H 2 | #define __DIRTY_BLOCK_H 3 | 4 | struct dirty_block_cache { 5 | int size; 6 | int free; /* free block slot index */ 7 | struct dirty_block_cache *next; 8 | struct block *blocks[0]; /* dynamic alloced slots based on size */ 9 | }; 10 | 11 | #define dbcsize(s) ((s) * sizeof(struct block) + sizeof(struct dirty_block_cache)) 12 | #define DBC_FIRST_SIZE 16 13 | #define DBC_INC_REATE 2 14 | 15 | #endif /* dirty_block.h */ 16 | -------------------------------------------------------------------------------- /user/libc/system.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int fork(void) 4 | { 5 | return usys_fork(); 6 | } 7 | 8 | void yield(void) 9 | { 10 | return usys_yield(); 11 | } 12 | 13 | int getpid(void) 14 | { 15 | return usys_getpid(); 16 | } 17 | 18 | void exit(int status) 19 | { 20 | usys_exit(status); 21 | } 22 | 23 | int wait(int *status) 24 | { 25 | return usys_wait(status); 26 | } 27 | 28 | int execute(char *path, int argc, char **argv) 29 | { 30 | return usys_execute(path, argc, argv); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /user/shell/process.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void run_process_command(int argc, char **argv) 4 | { 5 | int pid; 6 | int rpid, rv = 0; 7 | pid = fork(); 8 | if (pid < 0) { 9 | printf("fork error\n"); 10 | return; 11 | } 12 | /* child */ 13 | if (pid == 0) { 14 | execute(argv[0], argc, argv); 15 | printf("execute %s error\n", argv[0]); 16 | exit(-1); 17 | } 18 | /* wait pid */ 19 | rpid = wait(&rv); 20 | if (rpid != pid) 21 | printf("wait error pid: %d return %d\n", rpid, rv); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /include/asm.h: -------------------------------------------------------------------------------- 1 | #ifndef __ASM_H 2 | #define __ASM_H 3 | 4 | #define _ENTRY(name)\ 5 | .global name;\ 6 | name: 7 | 8 | #define ENTRY(name)\ 9 | .global name;\ 10 | .align 4, 0x90;\ 11 | name: 12 | 13 | #define ENTRY_NOERRCODE(func, num)\ 14 | ENTRY(func);\ 15 | pushl $0;\ 16 | pushl $(num);\ 17 | jmp interrupt_entry 18 | 19 | #define ENTRY_ERRCODE(func, num)\ 20 | ENTRY(func);\ 21 | pushl $(num);\ 22 | jmp interrupt_entry 23 | 24 | #define ENTRY_INT(func, num) ENTRY_NOERRCODE(func, num) 25 | 26 | #endif /* asm.h */ 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | chos 2 | ==== 3 | A monolithic 32-bit kernel. 4 | 5 | ![os](doc/os.png) 6 | 7 | Quick start 8 | =========== 9 | ``` 10 | # make <- compile and generate bootable disk image 11 | # make loaduser <- install basic usermode programs into disk image 12 | # make [bochs|kvm] <- run it in bochs or kvm 13 | ``` 14 | 15 | Debug 16 | ===== 17 | ``` 18 | # make debug 19 | # gdb -q [boot/boot.elf | kernel.elf | user/*] 20 | ... 21 | # vim [boot/boot.asm | kernel.asm | user/*.asm] 22 | ... 23 | # grep "some symbol" [boot/boot.sym | kernel.sym | user/*.sym] 24 | ... 25 | ``` 26 | 27 | Documentation 28 | ============= 29 | See doc/*.txt 30 | -------------------------------------------------------------------------------- /boot/Makefile: -------------------------------------------------------------------------------- 1 | LFLAGS = -Ttext=0x0000 --oformat=binary -e boot_start 2 | SUBDIR = boot 3 | 4 | boot.bin:boot.elf 5 | $(Q)$(OBJCOPY) $< -O binary $@ 6 | @echo " [GEN] $(SUBDIR)/$@" 7 | 8 | boot.elf:boot.o main.o 9 | $(Q)$(LD) $(LDFLAGS) -N -Ttext=0x0000 -e boot_start $^ -o boot.elf 10 | @echo " [LD] $(SUBDIR)/$@" 11 | 12 | main.o:main.c 13 | $(Q)$(CC) $(CFLAGS) $< -c -o $@ 14 | @echo " [CC] $(SUBDIR)/$@" 15 | 16 | boot.o:boot.S 17 | $(Q)$(CC) $(CFLAGS) -D__ASM__ $< -c -o $@ 18 | @echo " [CC] $(SUBDIR)/$@" 19 | 20 | debug:boot.asm boot.sym 21 | boot.asm:boot.elf 22 | $(Q)$(OBJDUMP) -S $< > $@ 23 | @echo " [DASM] $(SUBDIR)/$@" 24 | boot.sym:boot.elf 25 | $(Q)$(NM) -n $< > $@ 26 | @echo " [NM] $(SUBDIR)/$@" 27 | -------------------------------------------------------------------------------- /kernel/wait_queue.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * The default wait queue is FIFO queue. 6 | * The last-in wait entry is always waken up firstly. 7 | */ 8 | void wake_up(struct wait_queue *wq) 9 | { 10 | struct wait_entry *wait = wait_dequeue(wq); 11 | if (!wait) 12 | return; 13 | wait->func(wait); 14 | } 15 | 16 | static void default_wake_up(struct wait_entry *wait) 17 | { 18 | wait->task->state = TASK_RUNNABLE; 19 | } 20 | 21 | void sleep_on(struct wait_queue *wq) 22 | { 23 | struct wait_entry wait; 24 | /* init wait */ 25 | wait.func = &default_wake_up; 26 | wait.task = ctask; 27 | /* add to wait queue */ 28 | wait_enqueue(wq, &wait); 29 | ctask->state = TASK_SLEEP; 30 | schedule(); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /tools/bochs.bxrc: -------------------------------------------------------------------------------- 1 | # how much memory the emulated machine will have 2 | megs: 64 3 | 4 | # filename of ROM images 5 | romimage: file=$BXSHARE/BIOS-bochs-latest 6 | 7 | vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest 8 | 9 | # ATA 10 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 11 | 12 | # what disk images will be used 13 | ata0-master: type=disk, mode=flat, path="disk.img", cylinders=100, heads=10, spt=10 14 | 15 | # choose the boot disk. 16 | boot: disk 17 | 18 | # where do we send log messages? 19 | log: /dev/null 20 | 21 | # disable the mouse, since chos is text only 22 | mouse: enabled=0 23 | 24 | # enable key mapping, using US layout as default. 25 | keyboard: keymap=$BXSHARE/keymaps/x11-pc-us.map 26 | keyboard: serial_delay=250 27 | keyboard: paste_delay=100000 28 | 29 | private_colormap: enabled=0 30 | -------------------------------------------------------------------------------- /user/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef __STRING_H 2 | #define __STRING_H 3 | 4 | extern int setbit(void *src, int bits); 5 | extern int clearbit(void *src, int bits); 6 | extern int searchzerobit(void *src, int bits, int set); 7 | extern int strnncpy(char *dst, char *src, int n); 8 | extern int testbit(void *src, int bits); 9 | extern void memmove(void *dst, void *src, int n); 10 | extern int strtoi(char *nptr, char **endptr, int base); 11 | extern int itostr(int n, char *nptr, int base); 12 | extern int utostr(unsigned int n, char *nptr, int base); 13 | extern void memset(void *dst, int c, int n); 14 | extern void wmemset(void *dst, int c, int n); 15 | extern void memcpy(void *dst, void *src, int n); 16 | extern int strcpy(char *dst, char *src); 17 | extern int strncpy(char *dst, char *src, int n); 18 | extern int log2(int n); 19 | extern int log2up(int n); 20 | extern int strncmp(char *s1, char *s2, unsigned int n); 21 | extern int strcmp(char *s1, char *s2); 22 | 23 | #endif /* string.h */ 24 | -------------------------------------------------------------------------------- /user/shell/parse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int get_line(char *buf, int bufsz) 5 | { 6 | int len; 7 | len = gets(buf, bufsz - 1); 8 | buf[len] = '\0'; 9 | if (len > 0 && buf[len - 1] == '\n') { 10 | buf[len - 1] = '\0'; 11 | len--; 12 | } 13 | return len; 14 | } 15 | 16 | static char *get_arg(char **pp) 17 | { 18 | char *ret, *p; 19 | ret = NULL; 20 | p = *pp; 21 | /* skip white space and fill \0 */ 22 | while (isblank(*p)) { 23 | *p = '\0'; 24 | p++; 25 | } 26 | if (*p == '\0') 27 | goto out; 28 | ret = p; 29 | /* skip normal character */ 30 | while (*p && !isblank(*p)) 31 | p++; 32 | out: 33 | *pp = p; 34 | return ret; 35 | } 36 | 37 | int parse_line(char *line, int len, char **argv) 38 | { 39 | int argc; 40 | char *p, *pp; 41 | /* assert len >= 0 */ 42 | if (len == 0) 43 | return 0; 44 | 45 | p = pp = line; 46 | argc = 0; 47 | while ((p = get_arg(&pp)) != NULL) 48 | argv[argc++] = p; 49 | return argc; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /user/utils/cat.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) 4 | { 5 | char buf[512]; 6 | struct file_stat fs; 7 | int fd, n, r = -1; 8 | 9 | /* parse arguments */ 10 | if (argc > 2) { 11 | printf("Usage: cat [file]\n"); 12 | return -1; 13 | } 14 | 15 | /* cat the keyboard input */ 16 | if (argc == 1) { 17 | while ((n = gets(buf, 512)) > 0) 18 | printf("%*s", n, buf); 19 | return 0; 20 | } 21 | 22 | /* open file */ 23 | fd = open(argv[1], 0); 24 | if (fd < 0) { 25 | printf("cat: open file %s error\n", argv[1]); 26 | return -1; 27 | } 28 | /* get stat */ 29 | if (fstat(fd, &fs) == 0) { 30 | if (S_ISREG(fs.mode)) { 31 | /* cat it! */ 32 | while ((n = read(fd, buf, 512)) > 0) 33 | printf("%*s", n, buf); 34 | r = 0; 35 | } else { 36 | printf("%s is not regular file\n", argv[1]); 37 | } 38 | } else { 39 | printf("Cannot get stat of file %s\n", argv[1]); 40 | } 41 | /* safe exit */ 42 | close(fd); 43 | return r; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /doc/dirty_block_cache.txt: -------------------------------------------------------------------------------- 1 | Dirty Block Cache(dbc) 2 | --- 3 | 4 | SRC: 5 | fs/dirty_block.c 6 | 7 | APIS: 8 | inode_add_dbc() 9 | inode_sync_dbc() 10 | 11 | Related syscall: 12 | sys_fsync(fd) 13 | 14 | How to use? 15 | When fs(minixfs) makes block dirty related some inode, it just calls: 16 | inode_add_dbc(inode, block) 17 | Finally, fs wants to flush all dirty blocks related some inode, it calls: 18 | inode_sync_dbc(inode) 19 | 20 | The dirty block must be related with some inode 21 | 1. block which contains inode copy in disk (d_inode) 22 | 2. data block of some inode (block == minix_d_inode->i_zone[?]) 23 | 24 | How to work? 25 | dbc only caches block pointers, which is different from block buffer. 26 | and every inode has a dbc pointer(NULL). 27 | First call of inode_add_dbc will alloc a dbc for inode. 28 | 29 | Why? 30 | Without dirty block cache, it will traverse all blocks of some inode 31 | to detect whether the block is dirty, when user wants to sync some file. 32 | -------------------------------------------------------------------------------- /include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef __STRING_H 2 | #define __STRING_H 3 | 4 | extern int setbit(void *src, int bits); 5 | extern int clearbit(void *src, int bits); 6 | extern int searchzerobit(void *src, int bits, int set); 7 | extern int strnncpy(char *dst, char *src, int n); 8 | extern int testbit(void *src, int bits); 9 | extern void memmove(void *dst, void *src, int n); 10 | extern int strtoi(char *nptr, char **endptr, int base); 11 | extern int itostr(int n, char *nptr, int base); 12 | extern int utostr(unsigned int n, char *nptr, int base); 13 | extern void memset(void *dst, int c, int n); 14 | extern void wmemset(void *dst, int c, int n); 15 | extern void memcpy(void *dst, void *src, int n); 16 | extern int strcpy(char *dst, char *src); 17 | extern int strlen(char *); 18 | extern int strncpy(char *dst, char *src, int n); 19 | extern int log2(int n); 20 | extern int log2up(int n); 21 | extern int strncmp(char *s1, char *s2, unsigned int n); 22 | extern int strcmp(char *s1, char *s2); 23 | 24 | #endif /* string.h */ 25 | -------------------------------------------------------------------------------- /include/disk.h: -------------------------------------------------------------------------------- 1 | #ifndef __DISK_H 2 | #define __DISK_H 3 | 4 | /* ATA Master Drive */ 5 | #define ATA_MASTER_DATA 0x1f0 6 | #define ATA_MASTER_ERR 0x1f1 7 | #define ATA_MASTER_SECS 0x1f2 8 | #define ATA_MASTER_LBALOW 0x1f3 9 | #define ATA_MASTER_LBAMID 0x1f4 10 | #define ATA_MASTER_LBAHI 0x1f5 11 | #define ATA_MASTER_LBAEX 0x1f6 12 | #define ATA_MASTER_CMD 0x1f7 13 | 14 | /* ATA Status Bits */ 15 | #define ATA_STATUS_ERR 0x01 /* set for disk error */ 16 | #define ATA_STATUS_DRQ 0x08 17 | #define ATA_STATUS_SRV 0x10 18 | #define ATA_STATUS_DF 0x20 19 | #define ATA_STATUS_RDY 0x40 /* set for ready */ 20 | #define ATA_STATUS_BSY 0x80 /* set for busy */ 21 | 22 | #define ATA_CMD_READ 0x20 23 | #define ATA_CMD_WRITE 0x30 24 | 25 | #define SECT_SHIFT 9 26 | #define SECT_SIZE (1 << SECT_SHIFT) 27 | #define SECT_MASK (SECT_SIZE - 1) 28 | 29 | extern int ide_read_sect(int sects, void *dst, int lba); 30 | extern int ide_write_sect(int sects, void *src, int lba); 31 | extern int ide_blocks(void); 32 | 33 | #endif /* disk.h */ 34 | -------------------------------------------------------------------------------- /kernel/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void mm_init(void); 7 | void text_init(void); 8 | void int_init(void); 9 | void block_init(void); 10 | void task_init(void); 11 | void fs_init(void); 12 | void pit_init(void); 13 | void keyboard_init(void); 14 | void load_first_program(char *, int, char **); 15 | void first_open_interrupt(); 16 | 17 | void kidle(void) 18 | { 19 | printk("Kernel is idle now\n\n"); 20 | /* Open interrupt */ 21 | first_open_interrupt(); 22 | while (1) { 23 | hlt(); 24 | } 25 | } 26 | 27 | void load_init(void) 28 | { 29 | char *argv[] = { "/init", NULL }; 30 | load_first_program("/init", 1, argv); 31 | } 32 | 33 | void init(void) 34 | { 35 | /* 36 | * Init video before initing memory. 37 | * Assert that video initialization dont need boot_alloc. 38 | */ 39 | text_init(); 40 | mm_init(); 41 | int_init(); 42 | task_init(); 43 | block_init(); 44 | fs_init(); 45 | keyboard_init(); 46 | pit_init(); 47 | load_init(); 48 | kidle(); 49 | } 50 | -------------------------------------------------------------------------------- /include/wait_queue.h: -------------------------------------------------------------------------------- 1 | #ifndef __WAIT_QUEUE_H 2 | #define __WAIT_QUEUE_H 3 | 4 | #include 5 | #include 6 | struct task; 7 | 8 | struct wait_queue { 9 | int num; 10 | struct list_head queue; 11 | }; 12 | 13 | struct wait_entry { 14 | void (*func)(struct wait_entry *); 15 | struct list_head entry; 16 | struct task *task; 17 | }; 18 | 19 | #define INIT_WAIT_QUEUE(name) { 0, INIT_LIST_HEAD(name.queue) } 20 | #define WAIT_QUEUE(name) struct wait_queue name = INIT_WAIT_QUEUE(name) 21 | 22 | static _inline struct wait_entry *wait_dequeue(struct wait_queue *wq) 23 | { 24 | struct wait_entry *wait = NULL; 25 | if (wq->num > 0) { 26 | wq->num--; 27 | wait = list_first_entry(&wq->queue, struct wait_entry, entry); 28 | list_del(&wait->entry); 29 | } 30 | return wait; 31 | } 32 | 33 | static _inline void wait_enqueue(struct wait_queue *wq, struct wait_entry *wait) 34 | { 35 | wq->num++; 36 | list_add(&wait->entry, &wq->queue); 37 | } 38 | 39 | extern void sleep_on(struct wait_queue *wq); 40 | extern void wake_up(struct wait_queue *wq); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/boot.h: -------------------------------------------------------------------------------- 1 | #ifndef __BOOT_H 2 | #define __BOOT_H 3 | 4 | /* segment base is 0x7c00 */ 5 | #define BOOT_PADDR(offset) ((offset) + 0x7c00) 6 | 7 | /* linux uses 128 as max entries. */ 8 | #define E820_MAX 128 9 | #define E820_ENTRY_SIZE 24 10 | #define E820_TYPE_FREE 1 11 | #define E820_TYPE_RESERVED 2 12 | #define E820_TYPE_ACPIRECLAIM 3 13 | #define E820_TYPE_ACPINVS 4 14 | #define SMAP 0x534D4150 15 | 16 | #ifndef __ASM__ 17 | struct e820_entry { 18 | unsigned int addr; 19 | unsigned int addr_high; 20 | unsigned int length; 21 | unsigned int length_high; 22 | unsigned int type; 23 | unsigned int pad; 24 | }; 25 | 26 | struct boot_param { 27 | struct e820_entry e820_list[E820_MAX]; 28 | unsigned int e820_num; 29 | }; 30 | 31 | #define BOOT_PARAM_ADDR 0x8c00 32 | /* used by bootloader */ 33 | #define KERNEL_SECTS *(unsigned short *)(0x7c00 + 508) 34 | /* used by kernel init */ 35 | #define MINIXFS_START *(unsigned short *)VADDR(0x7c00 + 506) 36 | #define IDE_DISK_SECTS *(unsigned int *)VADDR(0x7c00 + 500) 37 | 38 | #endif /* __ASM__ */ 39 | 40 | #endif /* boot.h */ 41 | -------------------------------------------------------------------------------- /user/shell/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * simple shell for net stack debug and monitor 3 | */ 4 | #include 5 | 6 | int run_builtin_command(int, char **); 7 | int run_process_command(int, char **); 8 | 9 | int get_line(char *, int); 10 | int parse_line(char *, int, char **); 11 | 12 | static char *prompt = "[shell]"; 13 | 14 | static void run_command(int argc, char **argv) 15 | { 16 | if (run_builtin_command(argc, argv) < 0) 17 | run_process_command(argc, argv); 18 | } 19 | 20 | static _inline void print_prompt(void) 21 | { 22 | printf("%s: ", prompt); 23 | } 24 | 25 | void shell_run(char *prompt_str) 26 | { 27 | char linebuf[128]; 28 | int linelen; 29 | char *argv[16]; 30 | int argc; 31 | 32 | /* shell master */ 33 | if (prompt_str && *prompt_str) 34 | prompt = prompt_str; 35 | while (1) { 36 | print_prompt(); 37 | linelen = get_line(linebuf, 128); 38 | argc = parse_line(linebuf, linelen, argv); 39 | if (argc > 0) 40 | run_command(argc, argv); 41 | else if (argc < 0) 42 | printf("-shell: too many arguments\n"); 43 | } 44 | } 45 | 46 | int main(int argc, char **argv) 47 | { 48 | shell_run(NULL); 49 | return 0; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /keyboard/keybuf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | WAIT_QUEUE(key_wait_queue); 8 | static int key_free; /* free index */ 9 | static int eof; 10 | static char key_buf[KEY_BUF_SIZE]; 11 | 12 | void key_putc(char c) 13 | { 14 | int out = 1; 15 | if (!key_wait_queue.num) 16 | return; 17 | /* EOF */ 18 | if (c == '\0') { 19 | out = 0; 20 | eof = 1; 21 | key_buf[key_free] = c; 22 | } else if (c == '\b') { 23 | if (key_free > 0) 24 | key_free--; 25 | else 26 | out = 0; 27 | } else { 28 | key_buf[key_free] = c; 29 | key_free++; 30 | } 31 | /* output to video */ 32 | if (out) 33 | text_putc(c); 34 | /* wake up process who is waiting for the line buffer */ 35 | if (c == '\0' || c == '\n' || key_free >= KEY_BUF_SIZE) 36 | wake_up(&key_wait_queue); 37 | } 38 | 39 | int sys_gets(char *buf, int size) 40 | { 41 | if (size < 0) 42 | return size; 43 | while (key_free <= 0 && !eof) 44 | sleep_on(&key_wait_queue); 45 | 46 | size = min(size, key_free); 47 | key_free = 0; 48 | eof = 0; 49 | memcpy(buf, key_buf, size); 50 | return size; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /kernel/syscall.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define __sys_call_entry(name) [SYS_##name] = (syscall_t)sys_##name 7 | static syscall_t sys_call_table[SYS_CALL_MAX + 1] = { 8 | __sys_call_entry(puts), 9 | __sys_call_entry(gets), 10 | __sys_call_entry(open), 11 | __sys_call_entry(read), 12 | __sys_call_entry(write), 13 | __sys_call_entry(fsync), 14 | __sys_call_entry(fstat), 15 | __sys_call_entry(close), 16 | __sys_call_entry(lseek), 17 | __sys_call_entry(fork), 18 | __sys_call_entry(yield), 19 | __sys_call_entry(getpid), 20 | __sys_call_entry(exit), 21 | __sys_call_entry(wait), 22 | __sys_call_entry(execute), 23 | __sys_call_entry(fchdir), 24 | __sys_call_entry(fgetdir), 25 | __sys_call_entry(mkdir), 26 | __sys_call_entry(sync), 27 | __sys_call_entry(rmdir), 28 | __sys_call_entry(rm), 29 | __sys_call_entry(truncate), 30 | __sys_call_entry(getcwd), 31 | }; 32 | 33 | void do_sys_call(struct regs *reg) 34 | { 35 | syscall_t sys_call; 36 | if (reg->eax > SYS_CALL_MAX) { 37 | reg->eax = -1; 38 | return; 39 | } 40 | ctask->reg = reg; 41 | sys_call = sys_call_table[reg->eax]; 42 | reg->eax = sys_call(reg->ebx, reg->ecx, reg->edx, reg->edi, reg->esi); 43 | } 44 | -------------------------------------------------------------------------------- /user/utils/stat.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void parse_stat(char *file, struct file_stat *stat) 4 | { 5 | printf("%s: ", file); 6 | switch (stat->mode & S_IFMT) { 7 | case S_IFSOCK: 8 | printf("socket"); 9 | break; 10 | case S_IFLNK: 11 | printf("link"); 12 | break; 13 | case S_IFREG: 14 | printf("regular"); 15 | break; 16 | case S_IFBLK: 17 | printf("block"); 18 | break; 19 | case S_IFDIR: 20 | printf("directory"); 21 | break; 22 | case S_IFCHR: 23 | printf("char"); 24 | break; 25 | case S_IFIFO: 26 | printf("fifo"); 27 | break; 28 | default: 29 | printf(""); 30 | } 31 | printf("\nsize:%d bytes ino: %d refcnt:%d link:%d\n", 32 | stat->size, stat->inode, stat->iref, stat->link); 33 | } 34 | 35 | int main(int argc, char **argv) 36 | { 37 | struct file_stat stat; 38 | int fd; 39 | int r = -1; 40 | if (argc != 2) { 41 | printf("Usage: stat file\n"); 42 | return -1; 43 | } 44 | fd = open(argv[1], 0); 45 | if (fd < 0) { 46 | printf("stat: cannot open file: %s\n", argv[1]); 47 | return -1; 48 | } 49 | r = fstat(fd, &stat); 50 | if (r == 0) 51 | parse_stat(argv[1], &stat); 52 | else 53 | printf("stat: cannot get information of file:%s\n", argv[1]); 54 | close(fd); 55 | return r; 56 | } 57 | -------------------------------------------------------------------------------- /fs/hd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define HD_DEVNO 3 6 | 7 | static int hd_read_block(struct block *block); 8 | static int hd_write_block(struct block *block); 9 | static int hd_set_block_size(struct block_device *bdev, int size); 10 | 11 | struct block_device hd_bdev; 12 | static struct bdev_ops hd_bdev_ops = { 13 | .read = hd_read_block, 14 | .write = hd_write_block, 15 | .set_block_size = hd_set_block_size, 16 | }; 17 | 18 | static int hd_set_block_size(struct block_device *bdev, int size) 19 | { 20 | if (size < 0 || size & BLOCK_SIZE) 21 | return -1; 22 | bdev->size = size; 23 | return 0; 24 | } 25 | 26 | static int hd_read_block(struct block *block) 27 | { 28 | int r; 29 | r = ide_read_sect(block->b_sects, block->b_data, 30 | block->b_nr * block->b_sects); 31 | return (r == block->b_sects) ? 0 : -1; 32 | } 33 | 34 | static int hd_write_block(struct block *block) 35 | { 36 | int r; 37 | r = ide_write_sect(block->b_sects, block->b_data, 38 | block->b_nr * block->b_sects); 39 | return (r == block->b_sects) ? 0 : -1; 40 | } 41 | 42 | void hd_init(void) 43 | { 44 | hd_bdev.size = BLOCK_SIZE; 45 | hd_bdev.blocks = ide_blocks(); 46 | hd_bdev.ops = &hd_bdev_ops; 47 | hd_bdev.no = HD_DEVNO; 48 | list_init(&hd_bdev.block_list); 49 | } 50 | -------------------------------------------------------------------------------- /mm/page.c: -------------------------------------------------------------------------------- 1 | /* 2 | * high-level APIs associated pages 3 | */ 4 | #include 5 | #include 6 | #include 7 | 8 | void *kva_page(struct page *page) 9 | { 10 | /* If page is highmem page, we map it to kernel space address */ 11 | /* Not implemented now! */ 12 | return (void *)PG2VADDR(page); 13 | } 14 | 15 | void hold_page(struct page *page) 16 | { 17 | page->pg_refcnt++; 18 | } 19 | 20 | void free_page(struct page *p) 21 | { 22 | p->pg_refcnt--; 23 | if (p->pg_refcnt == 0) { 24 | if (p->pg_cowshare) 25 | panic("alloc page with cow share %d", p->pg_cowshare); 26 | free_pages(p, 0); 27 | } else if (p->pg_refcnt < 0) 28 | panic("Free free page(%d)\n", p->pg_refcnt); 29 | } 30 | 31 | void put_free_page(void *p) 32 | { 33 | free_page(VADDR2PG(p)); 34 | } 35 | 36 | /* using reference count in 0-order page */ 37 | void *get_free_page(void) 38 | { 39 | struct page *p = alloc_pages(PG_ZONE_NOR, 0); 40 | if (!p) 41 | return NULL; 42 | if (p->pg_cowshare) 43 | panic("alloc page with cow share %d", p->pg_cowshare); 44 | p->pg_refcnt = 1; 45 | return (void *)PG2VADDR(p); 46 | } 47 | 48 | void *get_free_page_pa(void) 49 | { 50 | struct page *p = alloc_pages(PG_ZONE_NOR, 0); 51 | if (!p) 52 | return NULL; 53 | if (p->pg_cowshare) 54 | panic("alloc page with cow share %d", p->pg_cowshare); 55 | p->pg_refcnt = 1; 56 | return (void *)PG2ADDR(p); 57 | } 58 | 59 | -------------------------------------------------------------------------------- /include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H 2 | #define __TYPES_H 3 | 4 | /* precise n-bit type */ 5 | typedef unsigned char u8; 6 | typedef char s8; 7 | typedef unsigned short u16; 8 | typedef short s16; 9 | typedef unsigned int u32; 10 | typedef int s32; 11 | typedef long long s64; 12 | typedef unsigned long long u64; 13 | 14 | typedef unsigned int size_t; 15 | typedef int off_t; 16 | 17 | #define offsetof(type, member) ((size_t)&((type *)0)->member) 18 | 19 | #define container_of(ptr, type, member) \ 20 | ({ \ 21 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 22 | (type *)((char *)__mptr - offsetof(type, member)); \ 23 | }) 24 | 25 | #define min(a, b) \ 26 | ({ \ 27 | typeof(a) __a = (a); \ 28 | typeof(b) __b = (b); \ 29 | __a < __b ? __a : __b; \ 30 | }) 31 | 32 | #define max(a, b) \ 33 | ({ \ 34 | typeof(a) __a = (a); \ 35 | typeof(b) __b = (b); \ 36 | __a >= __b ? __a : __b; \ 37 | }) 38 | 39 | #define ALIGN_DOWN(val, align) \ 40 | ({ \ 41 | u32 __val = (u32)(val); \ 42 | (typeof(val))(__val - (__val % (u32)(align))); \ 43 | }) 44 | 45 | #define ALIGN_UP(val, align) \ 46 | ((typeof(val))ALIGN_DOWN((u32)(val) + (u32)(align) - 1, (align))) 47 | 48 | #define DIV_UP(dividend, divisor) \ 49 | (((u32)(dividend) + (u32)(divisor) - 1) / (u32)divisor) 50 | 51 | #define MIN_INT ((~0U >> 1) + 1) 52 | #define NULL ((void *)0) 53 | 54 | #endif /* types.h */ 55 | -------------------------------------------------------------------------------- /kernel.ld: -------------------------------------------------------------------------------- 1 | /* Script for linking kernel.elf */ 2 | OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") 3 | OUTPUT_ARCH(i386) 4 | ENTRY(kernel_start) 5 | 6 | SECTIONS 7 | { 8 | /* text section: start at 0xc1000000 */ 9 | . = 0xc1000000; 10 | .text : { 11 | _stext = .; /* define the '_stext' symbol to this value */ 12 | *(.entry.text) 13 | *(.text) 14 | _etext = .; 15 | } = 0x9090 /* Internal space is filled with 'nop'. */ 16 | 17 | /* data section */ 18 | . = ALIGN(4096); 19 | .data : { 20 | _sdata = .; 21 | *(.entry.data) 22 | *(.data) 23 | } 24 | .rodata : { 25 | *(.rodata) 26 | *(.rodata1) 27 | _edata = .; 28 | } 29 | 30 | /* bss section */ 31 | . = ALIGN(4096); 32 | .bss : { 33 | __bss_start = .; 34 | *(.bss) 35 | __bss_end = .; 36 | } 37 | _end = .; 38 | 39 | /* DWARF debug starts at 0, otherwise gdb cannot find debug info */ 40 | .debug_aranges 0: { *(.debug_aranges) } /* Does this exist? */ 41 | .debug_ranges 0: { *(.debug_ranges) } 42 | .debug_pubnames 0: { *(.debug_pubnames) } 43 | .debug_info 0: { *(.debug_info) } 44 | .debug_abbrev 0: { *(.debug_abbrev) } 45 | .debug_line 0: { *(.debug_line) } 46 | .debug_frame 0: { *(.debug_frame) } 47 | .debug_str 0: { *(.debug_str) } 48 | .debug_pubtypes 0: { *(.debug_pubtypes) } 49 | 50 | /DISCARD/ : { *(.*) } 51 | 52 | . = ASSERT(_end <= 0xc2000000, "kernel image is larger than 16MB"); 53 | } 54 | -------------------------------------------------------------------------------- /include/file.h: -------------------------------------------------------------------------------- 1 | #ifndef __FILE_H 2 | #define __FILE_H 3 | 4 | #include 5 | 6 | struct file_stat; 7 | struct dir_stat; 8 | struct inode; 9 | struct file { 10 | off_t f_pos; 11 | struct inode *f_inode; 12 | int f_refcnt; 13 | unsigned int f_mode; 14 | }; 15 | 16 | #define FD_SAVED ((struct file *)0xffffdead) 17 | #define FD_SIZE 16 18 | 19 | struct fd_table { 20 | struct file *files[FD_SIZE]; 21 | }; 22 | 23 | extern struct file *file_open(char *path, unsigned int mode); 24 | extern void file_close(struct file *file); 25 | extern int file_read(struct file *file, char *buf, size_t size); 26 | extern int file_write(struct file *file, char *buf, size_t size); 27 | extern struct file *get_file(struct file *file); 28 | extern void put_file(struct file *file); 29 | extern off_t file_lseek(struct file *file, off_t offset, int whence); 30 | extern void file_sync(struct file *file); 31 | extern int file_stat(struct file *file, struct file_stat *stat); 32 | extern void ft_close(struct fd_table *); 33 | extern struct file *alloc_file(struct inode *, unsigned int); 34 | extern struct file *file_mkdir(char *, unsigned int); 35 | extern int file_chdir(struct file *file); 36 | extern int file_getdir(struct file *file, int start, int num, struct dir_stat *ds); 37 | extern int file_rmdir(char *path); 38 | extern int file_rm(char *path); 39 | extern int file_truncate(struct file *); 40 | 41 | #endif /* file.h */ 42 | -------------------------------------------------------------------------------- /include/elf.h: -------------------------------------------------------------------------------- 1 | #ifndef __ELF_H 2 | #define __ELF_H 3 | 4 | #include 5 | 6 | #define ELF_MAGIC 0x464C457FU /* "\x7FELF" in little endian */ 7 | 8 | struct elf { 9 | u32 e_magic; /* must equal ELF_MAGIC */ 10 | u8 e_elf[12]; 11 | u16 e_type; 12 | u16 e_machine; 13 | u32 e_version; 14 | u32 e_entry; 15 | u32 e_phoff; 16 | u32 e_shoff; 17 | u32 e_flags; 18 | u16 e_ehsize; 19 | u16 e_phentsize; 20 | u16 e_phnum; 21 | u16 e_shentsize; 22 | u16 e_shnum; 23 | u16 e_shstrndx; 24 | }; 25 | 26 | struct proghdr { 27 | u32 p_type; 28 | u32 p_offset; 29 | u32 p_va; 30 | u32 p_pa; 31 | u32 p_filesz; 32 | u32 p_memsz; 33 | u32 p_flags; 34 | u32 p_align; 35 | }; 36 | 37 | struct secthdr { 38 | u32 sh_name; 39 | u32 sh_type; 40 | u32 sh_flags; 41 | u32 sh_addr; 42 | u32 sh_offset; 43 | u32 sh_size; 44 | u32 sh_link; 45 | u32 sh_info; 46 | u32 sh_addralign; 47 | u32 sh_entsize; 48 | }; 49 | 50 | #define ELF_PROGHDR_SIZE sizeof(struct proghdr) 51 | 52 | /* Values for proghdr::p_type */ 53 | #define ELF_PROG_LOAD 1 54 | 55 | /* Flag bits for proghdr::p_flags */ 56 | #define ELF_PROG_FLAG_EXEC 1 57 | #define ELF_PROG_FLAG_WRITE 2 58 | #define ELF_PROG_FLAG_READ 4 59 | 60 | /* Values for secthdr::sh_type */ 61 | #define ELF_SHT_NULL 0 62 | #define ELF_SHT_PROGBITS 1 63 | #define ELF_SHT_SYMTAB 2 64 | #define ELF_SHT_STRTAB 3 65 | 66 | /* Values for Secthdr::sh_name */ 67 | #define ELF_SHN_UNDEF 0 68 | 69 | #endif /* elf.h */ 70 | -------------------------------------------------------------------------------- /user/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H 2 | #define __TYPES_H 3 | 4 | /* precise n-bit type */ 5 | typedef unsigned char u8; 6 | typedef char s8; 7 | typedef unsigned short u16; 8 | typedef short s16; 9 | typedef unsigned int u32; 10 | typedef int s32; 11 | typedef long long s64; 12 | typedef unsigned long long u64; 13 | 14 | typedef unsigned int size_t; 15 | typedef int off_t; 16 | 17 | #define offsetof(type, member) ((size_t)&((type *)0)->member) 18 | 19 | #define container_of(ptr, type, member) \ 20 | ({ \ 21 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 22 | (type *)((char *)__mptr - offsetof(type, member)); \ 23 | }) 24 | 25 | #define min(a, b) \ 26 | ({ \ 27 | typeof(a) __a = (a); \ 28 | typeof(b) __b = (b); \ 29 | __a < __b ? __a : __b; \ 30 | }) 31 | 32 | #define max(a, b) \ 33 | ({ \ 34 | typeof(a) __a = (a); \ 35 | typeof(b) __b = (b); \ 36 | __a >= __b ? __a : __b; \ 37 | }) 38 | 39 | #define ALIGN_DOWN(val, align) \ 40 | ({ \ 41 | u32 __val = (u32)(val); \ 42 | (typeof(val))(__val - (__val % (u32)(align))); \ 43 | }) 44 | 45 | #define ALIGN_UP(val, align) \ 46 | ((typeof(val))ALIGN_DOWN((u32)(val) + (u32)(align) - 1, (align))) 47 | 48 | #define DIV_UP(dividend, divisor) \ 49 | (((u32)(dividend) + (u32)(divisor) - 1) / (u32)divisor) 50 | 51 | #define MIN_INT ((~0U >> 1) + 1) 52 | #define NULL ((void *)0) 53 | 54 | #undef _inline 55 | #define _inline inline __attribute__((always_inline)) 56 | 57 | #endif /* types.h */ 58 | -------------------------------------------------------------------------------- /user/utils/ls.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static int linelen = 0; 4 | static char *dir = "."; 5 | struct dir_stat ds[16]; 6 | struct file_stat fs; 7 | 8 | /* This program only works for minixfs. */ 9 | #define MINIX_DENTRY_SIZE 16 10 | 11 | static void display_dir(int n) 12 | { 13 | int k; 14 | for (k = 0; k < n; k++) { 15 | if (linelen + ds[k].len + 1 >= 80) { 16 | printf("\n"); 17 | linelen = 0; 18 | } 19 | linelen += ds[k].len + 1; 20 | printf("%*s ", ds[k].len, ds[k].name); 21 | } 22 | } 23 | 24 | static int list_dir(int fd) 25 | { 26 | int r, i, n; 27 | n = fs.size / MINIX_DENTRY_SIZE; 28 | /* get dir stat entry and display it */ 29 | for (i = 0; i < n; i += 16) { 30 | r = fgetdir(fd, i, 16, ds); 31 | if (r > 0) 32 | display_dir(r); 33 | else 34 | break; 35 | } 36 | if (r < 0) 37 | printf("fgetdir error\n"); 38 | else if (linelen > 0) 39 | printf("\n"); 40 | return r; 41 | } 42 | 43 | int main(int argc, char **argv) 44 | { 45 | int fd, r; 46 | if (argc > 2) { 47 | printf("Usage: ls [file]\n"); 48 | return -1; 49 | } else if (argc == 2) { 50 | dir = argv[1]; 51 | } 52 | /* open dir */ 53 | fd = open(dir, 0); 54 | if (fd < 0) { 55 | printf("Cannot open %s\n", dir); 56 | return -1; 57 | } 58 | /* get stat */ 59 | if (fstat(fd, &fs) == 0) { 60 | if (S_ISDIR(fs.mode)) 61 | r = list_dir(fd); /* list dir */ 62 | else 63 | printf("%s is not dir\n", dir); 64 | } else { 65 | printf("Cannot get stat of file %s\n", dir); 66 | } 67 | /* close dir */ 68 | close(fd); 69 | return r; 70 | } 71 | -------------------------------------------------------------------------------- /kernel/entry.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | .code32 6 | .section ".entry.text", "ax" 7 | 8 | /* 9 | * All kernel is mapped to KERNEL_BASE + 1MB, which is at physical address 1MB 10 | * We play a trick to make the virtual address `change` to physical address 11 | * via segment base address: -KERNEL_BASE. 12 | */ 13 | 14 | _ENTRY(kernel_start) 15 | /* ignore interrupt still */ 16 | lgdt PADDR(gdt_desc) 17 | /* init segments and registers */ 18 | movw $KERN_DATA_SEG, %ax 19 | movw %ax, %ds 20 | movw %ax, %es 21 | movw %ax, %fs 22 | movw %ax, %gs 23 | movw %ax, %ss 24 | movl $ENTRY_STACK_TOP, %esp /* init entry stack */ 25 | xorl %ebp, %ebp /* clear frame pointer */ 26 | ljmp $KERN_CODE_SEG, $init /* kernel/init.c:init() */ 27 | 28 | .section ".entry.data", "a" 29 | .align 4 30 | _ENTRY(gdt) 31 | /* 32 | * GDT: first inited in entry.S 33 | * last inited in init.c 34 | * NOTE: limit must be set 4G. 35 | * limit means offset range of `seg:offset`. 36 | */ 37 | /* none seg */ 38 | GDT_SEG_NONE 39 | /* kernel code seg: base -3G, limit 4G, execute/read */ 40 | GDT_SEG(-KERNEL_BASE, 0xffffffff, STA_X|STA_R) 41 | /* kernel data seg: base -3G, limit 4G, write */ 42 | GDT_SEG(-KERNEL_BASE, 0xffffffff, STA_W) 43 | /* user code seg */ 44 | GDT_SEG_NONE 45 | /* user data seg */ 46 | GDT_SEG_NONE 47 | /* tss seg */ 48 | GDT_SEG_NONE 49 | /* ldt seg */ 50 | GDT_SEG_NONE 51 | /* none seg (align to 8 segs) */ 52 | GDT_SEG_NONE 53 | 54 | _ENTRY(gdt_desc) 55 | .word 63 /* gdt limit: gdt size - 1 */ 56 | .long PADDR(gdt) /* gdt linear address(using physical 57 | * address, the paging mode is not open 58 | * now) */ 59 | -------------------------------------------------------------------------------- /boot/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static void disk_wait(void) 7 | { 8 | /* wait for disk ready */ 9 | while (((inb(ATA_MASTER_CMD) & (ATA_STATUS_RDY|ATA_STATUS_BSY))) 10 | != ATA_STATUS_RDY) 11 | /* do nothing */; 12 | } 13 | 14 | static void disk_readsect(void *dst, int lba) 15 | { 16 | /* wait for disk to be ready */ 17 | disk_wait(); 18 | /* 28 bit LBA PIO mode read on the Primary bus */ 19 | outb(ATA_MASTER_SECS, 1); /* read sector count = 1 */ 20 | outb(ATA_MASTER_LBALOW, lba & 0xff); 21 | outb(ATA_MASTER_LBAMID, (lba >> 8) & 0xff); 22 | outb(ATA_MASTER_LBAHI, (lba >> 16) & 0xff); 23 | outb(ATA_MASTER_LBAEX, ((lba >> 24) & 0xf) | 0xe0); /* 0xe0 for master */ 24 | outb(ATA_MASTER_CMD, ATA_CMD_READ); 25 | /* wait for disk to be ready */ 26 | disk_wait(); 27 | /* read sector to memory */ 28 | insl(ATA_MASTER_DATA, dst, SECT_SIZE / sizeof(int)); 29 | } 30 | 31 | static void load_kernel(void) 32 | { 33 | void *kern_addr = (void *)KERNEL_START; 34 | int i = KERNEL_START_SECT; 35 | int n = KERNEL_SECTS; 36 | /* 37 | * Note: 38 | * 1. We dont init ata for convience. 39 | * 2. Assert that ata master disk exists. 40 | * 3. Assert that ata master drive I/O port start from 0x1f7 41 | */ 42 | while (i <= KERNEL_START_SECT + n) { 43 | disk_readsect(kern_addr, i); 44 | kern_addr += SECT_SIZE; 45 | i++; 46 | } 47 | } 48 | 49 | /* 50 | * Read kernel from disk to memory [0x100000, 0xf00000) 51 | * Assert that kernel image size is smaller than 14MB(0xe00000) 52 | */ 53 | void boot_main(void) 54 | { 55 | /* copy kernel from disk to memory */ 56 | load_kernel(); 57 | /* run kernel */ 58 | ((void (*)(void))KERNEL_START)(); 59 | } 60 | 61 | -------------------------------------------------------------------------------- /fs/minix/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static void debug_inode(struct minix_d_inode *mdi) 11 | { 12 | int i; 13 | printk("mode: %8x uid: %8x size: %d\n" 14 | "time: %8x gid: %8x link: %8x\n", 15 | mdi->i_mode, mdi->i_uid, mdi->i_size, 16 | mdi->i_time, mdi->i_gid, mdi->i_nlinks); 17 | printk("zones: "); 18 | for (i = 0; i < 9; i++) 19 | printk("%4d ", mdi->i_zone[i]); 20 | printk("\n"); 21 | } 22 | 23 | void minix_fs_test(void) 24 | { 25 | struct file *file; 26 | char *f = "/a"; 27 | 28 | /* "/" */ 29 | printk("Root dir:\n"); 30 | debug_inode(i2mdi(ctask->fs.root_dir)); 31 | 32 | /* "/b" */ 33 | file = file_open(f, 0777); 34 | if (!file) 35 | panic("Cannot open file %s", f); 36 | printk("file %s:\n", f); 37 | debug_inode(i2mdi(file->f_inode)); 38 | //#define TEST_READ 39 | #ifdef TEST_READ 40 | char buf[128]; 41 | int size; 42 | int all; 43 | all = 0; 44 | while ((size = file_read(file, buf, 128)) > 0) { 45 | printk("%*s", size, buf); 46 | all += size; 47 | } 48 | printk("%dbytes is read\n", all); 49 | #endif 50 | 51 | #ifdef TEST_WRITE 52 | int i; 53 | int all; 54 | for (i = 33216+1; i > 0; i--) 55 | if ((all = file_write(file, "hello world1234\n", 16)) != 16) 56 | panic("file write %d", i); 57 | sync_blocks(); 58 | #endif 59 | 60 | #ifdef TEST_LSEEK 61 | char buf[128]; 62 | int r; 63 | if ((r = file_lseek(file, -5, SEEK_END)) == -1) 64 | panic("file_seek"); 65 | printk("Seek to offset %d\n", r); 66 | r = file_read(file, buf, 128); 67 | if (r < 0) 68 | panic("file read"); 69 | printk("[%d][%*s]", r, r, buf); 70 | #endif 71 | } 72 | 73 | -------------------------------------------------------------------------------- /include/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYSCALL_H 2 | #define __SYSCALL_H 3 | 4 | #include 5 | 6 | struct file_stat; 7 | struct dir_stat; 8 | 9 | typedef u32 (*syscall_t)(u32, u32, u32, u32, u32); 10 | 11 | #define SYS_puts 1 12 | #define SYS_gets 2 13 | #define SYS_open 3 14 | #define SYS_read 4 15 | #define SYS_write 5 16 | #define SYS_fsync 6 17 | #define SYS_fstat 7 18 | #define SYS_close 8 19 | #define SYS_lseek 9 20 | #define SYS_fork 10 21 | #define SYS_yield 11 22 | #define SYS_getpid 12 23 | #define SYS_exit 13 24 | #define SYS_wait 14 25 | #define SYS_execute 15 26 | #define SYS_fchdir 16 27 | #define SYS_fgetdir 17 28 | #define SYS_mkdir 18 29 | #define SYS_sync 19 30 | #define SYS_rmdir 20 31 | #define SYS_rm 21 32 | #define SYS_truncate 22 33 | #define SYS_getcwd 23 34 | #define SYS_CALL_MAX 23 35 | 36 | extern int sys_puts(char *); 37 | extern int sys_gets(char *, int); 38 | extern int sys_open(char *, unsigned int); 39 | extern int sys_read(int, char *, size_t); 40 | extern int sys_write(int, char *, size_t); 41 | extern int sys_fsync(int); 42 | extern int sys_fstat(struct file_stat *); 43 | extern int sys_close(int); 44 | extern off_t sys_lseek(int, off_t, unsigned int); 45 | extern int sys_fork(void); 46 | extern void sys_yield(void); 47 | extern int sys_getpid(void); 48 | extern void sys_exit(int); 49 | extern int sys_wait(int *); 50 | extern int sys_execute(char *, int, char **); 51 | extern int sys_fchdir(int); 52 | extern int sys_fgetdir(int, int, int, struct dir_stat *); 53 | extern int sys_mkdir(char *, unsigned int); 54 | extern void sys_sync(void); 55 | extern int sys_rmdir(char *); 56 | extern int sys_rm(char *); 57 | extern int sys_truncate(int); 58 | extern int sys_getcwd(char *buf, size_t size); 59 | 60 | #endif /* syscall.h */ 61 | -------------------------------------------------------------------------------- /user/include/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYSCALL_H 2 | #define __SYSCALL_H 3 | 4 | #include 5 | 6 | struct file_stat; 7 | struct dir_stat; 8 | 9 | #define INTNO_SYSCALL 48 10 | 11 | #define SYS_puts 1 12 | #define SYS_gets 2 13 | #define SYS_open 3 14 | #define SYS_read 4 15 | #define SYS_write 5 16 | #define SYS_fsync 6 17 | #define SYS_fstat 7 18 | #define SYS_close 8 19 | #define SYS_lseek 9 20 | #define SYS_fork 10 21 | #define SYS_yield 11 22 | #define SYS_getpid 12 23 | #define SYS_exit 13 24 | #define SYS_wait 14 25 | #define SYS_execute 15 26 | #define SYS_fchdir 16 27 | #define SYS_fgetdir 17 28 | #define SYS_mkdir 18 29 | #define SYS_sync 19 30 | #define SYS_rmdir 20 31 | #define SYS_rm 21 32 | #define SYS_truncate 22 33 | #define SYS_getcwd 23 34 | 35 | extern int usys_puts(char *); 36 | extern int usys_gets(char *, int); 37 | extern int usys_open(char *, unsigned int); 38 | extern int usys_read(int, char *, unsigned int); 39 | extern int usys_write(int, char *, unsigned int); 40 | extern int usys_fsync(int); 41 | extern int usys_fstat(int, struct file_stat *); 42 | extern int usys_close(int); 43 | extern off_t usys_lseek(int, off_t, unsigned int); 44 | extern int usys_fork(void); 45 | extern void usys_yield(void); 46 | extern int usys_getpid(void); 47 | extern void usys_exit(int); 48 | extern int usys_wait(int *); 49 | extern int usys_execute(char *, int, char **); 50 | extern int usys_fchdir(int); 51 | extern int usys_fgetdir(int fd, int s, int n, struct dir_stat *ds); 52 | extern int usys_mkdir(char *, unsigned int); 53 | extern void usys_sync(void); 54 | extern int usys_rmdir(char *); 55 | extern int usys_rm(char *); 56 | extern int usys_truncate(int); 57 | extern int usys_getcwd(char *buf, size_t size); 58 | 59 | #endif /* syscall.h */ 60 | -------------------------------------------------------------------------------- /user/utils/cp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | char buf[1024]; 4 | char *sfile, *dfile; 5 | 6 | int check(int src, int dst) 7 | { 8 | struct file_stat ss, ds; 9 | if (fstat(src, &ss) < 0) { 10 | printf("Cannot stat %s\n", sfile); 11 | return -1; 12 | } 13 | if (fstat(dst, &ds) < 0) { 14 | printf("Cannot stat %s\n", dfile); 15 | return -1; 16 | } 17 | if (ss.inode == ds.inode) { 18 | printf("%s and %s are the same file\n", sfile, dfile); 19 | return -1; 20 | } 21 | if (!S_ISREG(ss.mode)) { 22 | printf("%s is not regular file\n", sfile); 23 | return -1; 24 | } 25 | if (!S_ISREG(ds.mode)) { 26 | printf("%s is not regular file\n", dfile); 27 | return -1; 28 | } 29 | /* truncate it */ 30 | if (truncate(dst) < 0) { 31 | printf("%s cannot be truncated\n", dfile); 32 | return -1; 33 | } 34 | return 0; 35 | } 36 | 37 | int copy(int src, int dst) 38 | { 39 | int size; 40 | while ((size = read(src, buf, 1024)) > 0) { 41 | if (write(dst, buf, size) != size) { 42 | printf("Write %s error\n", dfile); 43 | return -1; 44 | } 45 | } 46 | if (size < 0) 47 | printf("Read %s error\n", sfile); 48 | return size; 49 | } 50 | 51 | int main(int argc, char **argv) 52 | { 53 | int src, dst; 54 | int r = -1; 55 | if (argc != 3) { 56 | printf("Usage: cp srcfile dstfile\n"); 57 | return -1; 58 | } 59 | 60 | sfile = argv[1]; 61 | dfile = argv[2]; 62 | /* open */ 63 | src = open(sfile, 0); 64 | if (src < 0) 65 | goto out; 66 | dst = open(dfile, O_CREATE); 67 | if (dst < 0) 68 | goto out_close; 69 | /* check the files */ 70 | r = check(src, dst); 71 | if (!r) { 72 | /* copy! */ 73 | r = copy(src, dst); 74 | } 75 | /* close */ 76 | close(dst); 77 | out_close: 78 | close(src); 79 | out: 80 | return r; 81 | } 82 | 83 | -------------------------------------------------------------------------------- /include/block.h: -------------------------------------------------------------------------------- 1 | #ifndef __BLOCK_H 2 | #define __BLOCK_H 3 | 4 | #include 5 | #include 6 | 7 | #define BLOCK_SHIFT 10 8 | #define BLOCK_SIZE (1 << BLOCK_SHIFT) 9 | #define BLOCK_MASK (BLOCK_SIZE - 1) 10 | 11 | /* block buffer structure */ 12 | struct block { 13 | struct hlist_node b_hnode; /* listed in block hash table */ 14 | struct list_head b_list; /* listed in block device */ 15 | int b_nr; /* block number: start from 0 */ 16 | int b_sects; /* sectors of block: hd drive uses it */ 17 | int b_size; /* block size */ 18 | int b_refcnt; /* reference count */ 19 | void *b_data; /* data point */ 20 | struct block_device *b_dev; 21 | unsigned int b_dirty:1, /* block is writen ,not synhcronized */ 22 | b_read:1, /* set if disk data has been read */ 23 | b_buffer:1; /* in the block buffer */ 24 | unsigned int b_private; /* associated inode or some other structure */ 25 | }; 26 | 27 | struct block_device; 28 | struct bdev_ops { 29 | int (*read)(struct block *); 30 | int (*write)(struct block *); 31 | int (*set_block_size)(struct block_device *, int); 32 | }; 33 | 34 | struct block_device { 35 | struct list_head block_list; /* all in-memory blocks of device */ 36 | int size; /* block size */ 37 | int blocks; /* number of total blocks */ 38 | int no; 39 | struct bdev_ops *ops; /* virtual functions table */ 40 | }; 41 | 42 | extern int set_block_size(struct block_device *bdev, int size); 43 | extern void flush_block_buffer(void); 44 | extern struct block *get_block(struct block_device *bdev, int blk); 45 | extern void put_block(struct block *block); 46 | extern int write_block(struct block *block); 47 | extern void sync_blocks(void); 48 | 49 | static _inline void flush_block(struct block *block) 50 | { 51 | if (block->b_dirty) 52 | write_block(block); 53 | } 54 | 55 | #endif /* block.h */ 56 | -------------------------------------------------------------------------------- /include/fs.h: -------------------------------------------------------------------------------- 1 | #ifndef __FS_H 2 | #define __FS_H 3 | 4 | #include 5 | 6 | struct super_block { 7 | struct block_device *s_bdev; /* deive of file system */ 8 | int s_start; /* start block number of file system */ 9 | struct block *s_block; /* real super block */ 10 | }; 11 | 12 | /* used by system call: fstat */ 13 | struct file_stat { 14 | unsigned int size; 15 | unsigned int inode; 16 | unsigned int mode; 17 | unsigned int iref; /* inode reference count */ 18 | unsigned int link; /* inode link number */ 19 | }; 20 | 21 | #define DIR_SIZE 32 22 | struct dir_stat { 23 | char name[DIR_SIZE]; 24 | int len; 25 | unsigned int inode; 26 | }; 27 | 28 | #define S_IFMT 00170000 29 | 30 | #define S_IFSOCK 00140000 31 | #define S_IFLNK 00120000 32 | #define S_IFREG 00100000 33 | #define S_IFBLK 00060000 34 | #define S_IFDIR 00040000 35 | #define S_IFCHR 00020000 36 | #define S_IFIFO 00010000 37 | 38 | #define S_ISUID 00004000 39 | #define S_ISGID 00002000 40 | #define S_ISVTX 00001000 41 | 42 | #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) 43 | #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) 44 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 45 | #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) 46 | #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) 47 | #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) 48 | #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) 49 | 50 | #define S_IRWXU 00700 51 | #define S_IRUSR 00400 52 | #define S_IWUSR 00200 53 | #define S_IXUSR 00100 54 | 55 | #define S_IRWXG 00070 56 | #define S_IRGRP 00040 57 | #define S_IWGRP 00020 58 | #define S_IXGRP 00010 59 | 60 | #define S_IRWXO 00007 61 | #define S_IROTH 00004 62 | #define S_IWOTH 00002 63 | #define S_IXOTH 00001 64 | 65 | #define SEEK_SET 0 66 | #define SEEK_CUR 1 67 | #define SEEK_END 2 68 | 69 | #define O_CREATE 0x80000000 70 | #define O_TRUNCATE 0x40000000 71 | 72 | #endif /* fs.h */ 73 | -------------------------------------------------------------------------------- /include/8259A.h: -------------------------------------------------------------------------------- 1 | #ifndef __8259A_H 2 | #define __8259A_H 3 | 4 | #define ICW1_BIT4 0x10 /* must be set */ 5 | #define ICW1_LTIM 0x08 /* level triggered mode (0 for edge) */ 6 | #define ICW1_ADI 0x04 /* call address interval:4 (0 for 8) */ 7 | #define ICW1_SNGL 0x02 /* sigle (0 for cascade mode)*/ 8 | #define ICW1_IC4 0x01 /* IC4 is needed */ 9 | 10 | #define ICW1 (ICW1_BIT4 | ICW1_IC4) /* edge cascade 8interval IC4 */ 11 | #define ICW3_MASTER 0x04 /* slave PIC is cascaded on IRQ2 */ 12 | #define ICW3_SLAVE 0x02 /* ?? */ 13 | 14 | #define ICW4_uPM 0x01 /* 8086/8088 mode(0 for MCS-80/85 mode) */ 15 | #define ICW4_AEOI 0x02 /* auto EOI (0 for normal EOI) */ 16 | #define ICW4_MS 0x04 /* X non buffer|0 buffer slave|1 buffer master */ 17 | #define ICW4_BUF 0x08 /* 0 non buffer|1 buffer slave|1 buffer master */ 18 | #define ICW4_SFNM 0x10 /* special fully nested mode(non nested) */ 19 | 20 | #define ICW4_MASTER (ICW4_uPM) /* non-buffer 8086 NEOI non-nested */ 21 | #define ICW4_SLAVE (ICW4_uPM) /* non-buffer 8086 NEOI non-nested */ 22 | 23 | #define REG_PIC1 0x20 24 | #define REG_PIC2 0xa0 25 | #define PIC_A0 0x01 /* A0 bit */ 26 | #define PIC_MASTER_CMD REG_PIC1 /* master command register */ 27 | #define PIC_MASTER_DATA (REG_PIC1 | PIC_A0) /* master data register */ 28 | #define PIC_SLAVE_CMD REG_PIC2 /* slave command register */ 29 | #define PIC_SLAVE_DATA (REG_PIC2 | PIC_A0) /* slave data register */ 30 | #define PIC_MASTER_IMR PIC_MASTER_DATA /* interrupt mask register */ 31 | #define PIC_SLAVE_IMR PIC_SLAVE_DATA /* interrupt mask register */ 32 | 33 | #define OCW2_R 0x80 34 | #define OCW2_SL 0x40 35 | #define OCW2_EOI 0x20 36 | #define OCW2_L2 0x04 37 | #define OCW2_L1 0x02 38 | #define OCW2_L0 0x01 39 | 40 | #define EOI 0x20 /* non-specific EOI command */ 41 | 42 | extern void unmask_8259A(int irq); 43 | extern void EOI_8259A(int irq); 44 | extern void mask_8259A(int irq); 45 | 46 | #endif /* 8259A.h */ 47 | -------------------------------------------------------------------------------- /include/slab.h: -------------------------------------------------------------------------------- 1 | #ifndef __SLAB_H 2 | #define __SLAB_H 3 | 4 | #include 5 | 6 | struct slab_object { 7 | struct slab_object *next; 8 | }; 9 | 10 | /* 11 | * Slab cache and objects are in the same page. 12 | * Why? 13 | * If we alloc a slab for slab cache, then slab cache will 14 | * recurse infinitely when slab cache allocs slab cache! 15 | */ 16 | struct slab_cache { 17 | int total; /* total objects */ 18 | int free; /* free objects */ 19 | struct slab_object *object; /* free object list */ 20 | struct list_head list; /* listed in its slab */ 21 | }; 22 | 23 | struct slab { 24 | int size; /* object size */ 25 | int pages; /* cache contaning max pages number */ 26 | struct slab_cache *current; /* one free cache of all cache */ 27 | struct list_head cache; /* pages containing in-use objects */ 28 | struct list_head free_cache; /* pages containing free objects */ 29 | struct list_head list; /* listed in global slab list */ 30 | }; 31 | 32 | #define slab_next_object(s, o) ((struct slab_object *)((void *)(o) + (s)->size)) 33 | 34 | #define KMALLOC_CUBES 10 35 | #define KMALLOC_MAX_SIZE (4 << KMALLOC_CUBES) 36 | 37 | #define SLAB_CACHE_SIZE sizeof(struct slab_cache) 38 | #define SLAB_CACHE_MIN_OBJECTS 16 39 | #define SLAB_CACHE_FREE_QUOTA(c) ((cache)->total / 2) 40 | #define SLAB_OBJECT_MAX_SIZE 2048 41 | 42 | #define PGSLAB(p) ((struct slab *)(p)->pg_list.prev) 43 | #define PGSLABCACHE(p) ((struct slab_cache *)(p)->pg_list.next) 44 | #define SLAB_PGS(size) PGS_UP(SLAB_CACHE_MIN_OBJECTS * (size) + SLAB_CACHE_SIZE) 45 | /* cache is at the bottom of cache buffer */ 46 | #define PG2CACHE(p, n) (((struct slab_cache *)PG2VADDR((p) + (n))) - 1) 47 | 48 | extern void kfree(void *); 49 | extern void *kmalloc(int); 50 | extern void free_slab(struct slab *); 51 | extern struct slab *alloc_slab(int); 52 | extern void slab_free_object(struct slab *, void *); 53 | extern void *slab_alloc_object(struct slab *); 54 | 55 | #endif /* slab.h */ 56 | -------------------------------------------------------------------------------- /user/shell/builtin.c: -------------------------------------------------------------------------------- 1 | /* shell builtin command */ 2 | #include 3 | #include 4 | 5 | struct builtin_command { 6 | char *cmd; 7 | char *info; 8 | void (*func)(int, char **); 9 | }; 10 | 11 | #define BUILTIN_CMDS (sizeof(cmds) / sizeof(cmds[0])) 12 | 13 | static void builtin_cd(int argc, char **argv); 14 | static void builtin_echo(int argc, char **argv); 15 | static void builtin_pid(int argc, char **argv); 16 | static void builtin_help(int argc, char **argv); 17 | static void builtin_exit(int argc, char **argv); 18 | 19 | static struct builtin_command cmds[] = { 20 | { "help", "display manual of this shell", builtin_help }, 21 | { "cd", "change current directory", builtin_cd }, 22 | { "echo", "display a line of text", builtin_echo }, 23 | { "pid", "display the ID of shell", builtin_pid }, 24 | { "exit", "cause the shell to exit", builtin_exit }, 25 | }; 26 | 27 | static void builtin_help(int argc, char **argv) 28 | { 29 | int i; 30 | for (i = 0; i < BUILTIN_CMDS; i++) 31 | printf("%-8s - %s\n", cmds[i].cmd, cmds[i].info); 32 | } 33 | 34 | static void builtin_cd(int argc, char **argv) 35 | { 36 | char *dir = "No dir"; 37 | if (argc > 2) { 38 | printf("too many arguments for cd\n"); 39 | return; 40 | } 41 | if (argc == 2) { 42 | dir = argv[1]; 43 | } else { 44 | dir = "/"; 45 | } 46 | chdir(dir); 47 | } 48 | 49 | static void builtin_echo(int argc, char **argv) 50 | { 51 | int i; 52 | for (i = 1; i < argc; i++) 53 | printf("%s ", argv[i]); 54 | printf("\n"); 55 | } 56 | 57 | static void builtin_pid(int argc, char **argv) 58 | { 59 | printf("%d\n", getpid()); 60 | } 61 | 62 | static void builtin_exit(int argc, char **argv) 63 | { 64 | printf("exit\n"); 65 | exit(0); 66 | } 67 | 68 | int run_builtin_command(int argc, char **argv) 69 | { 70 | int i; 71 | for (i = 0; i < BUILTIN_CMDS; i++) 72 | if (strcmp(argv[0], cmds[i].cmd) == 0) 73 | goto found; 74 | return -1; 75 | found: 76 | cmds[i].func(argc, argv); 77 | return 0; 78 | } 79 | 80 | -------------------------------------------------------------------------------- /tools/fs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file has definitions for some important file table 3 | * structures etc, which is used _only_ for tools/mkfs.minix.c 4 | */ 5 | #ifndef __FS_H 6 | #define __FS_H 7 | 8 | #include 9 | 10 | #define BLKGETSIZE 0x00001260 11 | #define NAME_LEN 14 12 | #define ROOT_INO 1 13 | 14 | #define I_MAP_SLOTS 8 15 | #define Z_MAP_SLOTS 8 16 | #define MINIX_SUPER_MAGIC 0x137F 17 | 18 | #define INODE_SIZE (sizeof(struct d_inode)) 19 | #define BLOCK_SIZE 1024 20 | #define BLOCK_SIZE_BITS 10 21 | #ifndef NULL 22 | #define NULL ((void *) 0) 23 | #endif 24 | 25 | #define INODES_PER_BLOCK ((BLOCK_SIZE)/ INODE_SIZE) 26 | #define DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct dir_entry))) 27 | 28 | #define ALIGN_UP(n, align) ((n + ((align) - 1)) / (align)) 29 | 30 | /* number of blocks containing inodes */ 31 | #define INODES(sb) ALIGN_UP((sb)->s_ninodes , INODES_PER_BLOCK) 32 | /* inode-block starting block nr */ 33 | #define INODE_BLK(sb) (2 + (sb)->s_imap_blocks + (sb)->s_zmap_blocks) 34 | 35 | /* first logic data block nr */ 36 | #define FIRST_ZONE_BLK(sb) \ 37 | (2 + INODES(sb) + (sb)->s_imap_blocks + (sb)->s_zmap_blocks) 38 | 39 | /* inode in device(disk) */ 40 | struct d_inode { 41 | unsigned short i_mode; 42 | unsigned short i_uid; 43 | unsigned long i_size; 44 | unsigned long i_time; 45 | unsigned char i_gid; 46 | unsigned char i_nlinks; 47 | unsigned short i_zone[9]; 48 | }; 49 | 50 | /* super_block in device(disk) */ 51 | struct d_super_block { 52 | unsigned short s_ninodes; 53 | unsigned short s_nzones; /* max disk size is 64MB */ 54 | unsigned short s_imap_blocks; 55 | /* 56 | * zone map stands for logic data block 57 | * *excluding* boot|sb|imap|zmap|inodeblk 58 | */ 59 | unsigned short s_zmap_blocks; 60 | unsigned short s_firstdatazone; 61 | unsigned short s_log_zone_size; 62 | unsigned long s_max_size; 63 | unsigned short s_magic; 64 | }; 65 | 66 | struct dir_entry { 67 | unsigned short inode; 68 | char name[NAME_LEN]; 69 | }; 70 | 71 | #endif /* fs.h */ 72 | -------------------------------------------------------------------------------- /user/Makefile: -------------------------------------------------------------------------------- 1 | SUBDIR = user 2 | CFLAGS = -Wall -Werror -fno-builtin -nostdinc -nostdlib -Iinclude -g -m32 3 | export SUBDIR CFLAGS 4 | APPS = $(patsubst user/%, %, $(USER_APPS)) 5 | ASMS = $(patsubst %, %.asm, $(APPS)) 6 | SYMS = $(patsubst %, %.sym, $(APPS)) 7 | 8 | all:$(APPS) 9 | # basic programs 10 | hello:hello.o libc/libc.o 11 | $(Q)$(LD) $(LDFLAGS) $^ -o $@ 12 | @echo " [LD] $(SUBDIR)/$@" 13 | init:init.o libc/libc.o 14 | $(Q)$(LD) $(LDFLAGS) $^ -o $@ 15 | @echo " [LD] $(SUBDIR)/$@" 16 | sh:shell/shell.o libc/libc.o 17 | $(Q)$(LD) $(LDFLAGS) $^ -o $@ 18 | @echo " [LD] $(SUBDIR)/$@" 19 | # utilities 20 | cat:utils/cat.o libc/libc.o 21 | $(Q)$(LD) $(LDFLAGS) $^ -o $@ 22 | @echo " [LD] $(SUBDIR)/$@" 23 | 24 | stat:utils/stat.o libc/libc.o 25 | $(Q)$(LD) $(LDFLAGS) $^ -o $@ 26 | @echo " [LD] $(SUBDIR)/$@" 27 | mkdir:utils/mkdir.o libc/libc.o 28 | $(Q)$(LD) $(LDFLAGS) $^ -o $@ 29 | @echo " [LD] $(SUBDIR)/$@" 30 | ls:utils/ls.o libc/libc.o 31 | $(Q)$(LD) $(LDFLAGS) $^ -o $@ 32 | @echo " [LD] $(SUBDIR)/$@" 33 | sync:utils/sync.o libc/libc.o 34 | $(Q)$(LD) $(LDFLAGS) $^ -o $@ 35 | @echo " [LD] $(SUBDIR)/$@" 36 | rmdir:utils/rmdir.o libc/libc.o 37 | $(Q)$(LD) $(LDFLAGS) $^ -o $@ 38 | @echo " [LD] $(SUBDIR)/$@" 39 | rm:utils/rm.o libc/libc.o 40 | $(Q)$(LD) $(LDFLAGS) $^ -o $@ 41 | @echo " [LD] $(SUBDIR)/$@" 42 | cp:utils/cp.o libc/libc.o 43 | $(Q)$(LD) $(LDFLAGS) $^ -o $@ 44 | @echo " [LD] $(SUBDIR)/$@" 45 | pwd:utils/pwd.o libc/libc.o 46 | $(Q)$(LD) $(LDFLAGS) $^ -o $@ 47 | @echo " [LD] $(SUBDIR)/$@" 48 | 49 | # objects 50 | %.o:%.c 51 | $(Q)$(CC) $(CFLAGS) $< -c -o $@ 52 | @echo " [CC] $(SUBDIR)/$@" 53 | utils/%.o:utils/%.c 54 | $(Q)$(CC) $(CFLAGS) $< -c -o $@ 55 | @echo " [CC] $(SUBDIR)/utils/$@" 56 | 57 | libc/libc.o:libc/*.c libc/*.S 58 | @make -C libc/ 59 | shell/shell.o:shell/*.c 60 | @make -C shell/ 61 | 62 | debug:$(ASMS) $(SYMS) 63 | %.asm:% 64 | $(Q)$(OBJDUMP) -S $< > $@ 65 | @echo " [DASM] $(SUBDIR)/$@" 66 | %.sym:% 67 | $(Q)$(NM) -n $< > $@ 68 | @echo " [NM] $(SUBDIR)/$@" 69 | -------------------------------------------------------------------------------- /user/libc/file.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int open(char *path, unsigned int mode) 5 | { 6 | return usys_open(path, mode); 7 | } 8 | 9 | int close(int fd) 10 | { 11 | return usys_close(fd); 12 | } 13 | 14 | int read(int fd, char *buf, size_t size) 15 | { 16 | return usys_read(fd, buf, size); 17 | } 18 | 19 | int write(int fd, char *buf, size_t size) 20 | { 21 | return usys_write(fd, buf, size); 22 | } 23 | 24 | 25 | off_t lseek(int fd, off_t offset, int whence) 26 | { 27 | return usys_lseek(fd, offset, whence); 28 | } 29 | 30 | int fsync(int fd) 31 | { 32 | return usys_fsync(fd); 33 | } 34 | 35 | int fstat(int fd, struct file_stat *stat) 36 | { 37 | return usys_fstat(fd, stat); 38 | } 39 | 40 | int fchdir(int fd) 41 | { 42 | return usys_fchdir(fd); 43 | } 44 | 45 | int chdir(char *path) 46 | { 47 | struct file_stat stat; 48 | int fd, r; 49 | fd = open(path, 0); 50 | if (fd < 0) { 51 | printf("Cannot open file: %s\n", path); 52 | return -1; 53 | } 54 | if ((r = fstat(fd, &stat)) < 0) { 55 | printf("Cannot get file stat: %s\n", path); 56 | } else if (!S_ISDIR(stat.mode)) { 57 | printf("%s is not dir\n", path); 58 | } else { 59 | r = fchdir(fd); 60 | if (r < 0) 61 | printf("error for fchdir\n"); 62 | } 63 | close(fd); 64 | return r; 65 | } 66 | 67 | int fgetdir(int fd, int s, int n, struct dir_stat *ds) 68 | { 69 | if (s < 0 || n <= 0) 70 | return -1; 71 | return usys_fgetdir(fd, s, n, ds); 72 | } 73 | 74 | int mkdir(char *path, unsigned int mode) 75 | { 76 | return usys_mkdir(path, mode); 77 | } 78 | 79 | int rmdir(char *path) 80 | { 81 | return usys_rmdir(path); 82 | } 83 | 84 | int rm(char *path) 85 | { 86 | return usys_rm(path); 87 | } 88 | 89 | void sync(void) 90 | { 91 | usys_sync(); 92 | } 93 | 94 | int truncate(int fd) 95 | { 96 | return usys_truncate(fd); 97 | } 98 | 99 | char *getcwd(char *buf, size_t size) 100 | { 101 | if (usys_getcwd(buf, size)) 102 | return NULL; 103 | 104 | return buf; 105 | } 106 | -------------------------------------------------------------------------------- /include/task.h: -------------------------------------------------------------------------------- 1 | #ifndef __TASK_H 2 | #define __TASK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* switch current task to this context */ 10 | struct context { 11 | unsigned int esp; 12 | unsigned int eip; 13 | }; 14 | 15 | #ifdef VMAP 16 | /* virtual address map */ 17 | struct vmap { 18 | unsigned int va_start; 19 | unsigned int va_size; 20 | unsigned int va_flags; 21 | struct tree_node va_node; 22 | }; 23 | #endif 24 | 25 | struct userspace { 26 | #ifdef VMAP 27 | struct tree_node vmap_root; 28 | #endif 29 | pde_t *pgdir; 30 | }; 31 | 32 | struct fsinfo { 33 | struct fd_table ft; 34 | struct inode *current_dir; 35 | struct inode *root_dir; 36 | }; 37 | 38 | struct task { 39 | struct list_head list; /* all task list entry */ 40 | struct list_head sibling; /* listed in parent */ 41 | struct list_head childs; /* all childs */ 42 | struct task *parent; 43 | void *kstacktop; /* kernel-mode stack top of task */ 44 | struct fsinfo fs; /* association with file system */ 45 | struct context con; /* association with task switching */ 46 | struct userspace us; /* association with usermode */ 47 | struct regs *reg; 48 | unsigned int state; 49 | int priority; 50 | int pid; 51 | int retval; /* exit value */ 52 | }; 53 | 54 | #define TASK_RUNNABLE 1 55 | #define TASK_SLEEP 2 56 | #define TASK_DYING 3 57 | #define TASK_WAITCHILD 4 58 | 59 | #define for_each_task(t) list_for_each_entry(t, &task_list, list) 60 | 61 | #define PIDS 128 /* process id range: [0, PIDS - 1] */ 62 | #define PIDBYTES (PIDS / 8) 63 | /* current task */ 64 | struct pidset { 65 | unsigned char bitmap[PIDBYTES]; /* set for used */ 66 | int freepids; 67 | }; 68 | 69 | /* execute arguments */ 70 | struct execute_args { 71 | void *stack; 72 | unsigned int stackoff; 73 | }; 74 | 75 | extern struct task *ctask; /* current task */ 76 | extern struct task *alloc_task(void); 77 | extern void free_task(struct task *); 78 | extern void fork_child_return(void); 79 | extern void task_switch(struct task *); 80 | extern void schedule(void); 81 | extern struct tss common_tss; 82 | extern struct list_head task_list; 83 | 84 | #endif /* task.h */ 85 | -------------------------------------------------------------------------------- /keyboard/key.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include <8259A.h> 4 | #include 5 | #include 6 | 7 | extern unsigned char scancode_types[]; 8 | extern char scancode_ascii[]; 9 | extern char scancode_shift_ascii[]; 10 | void key_putc(char); 11 | 12 | static struct key_desc keys; 13 | 14 | void keyboard_interrupt(struct regs *reg) 15 | { 16 | /* 17 | * We must read this scan code from the buffer 18 | * otherwise the keyboard interrupt will be closed. 19 | */ 20 | u8 scan_code = inb(0x60); 21 | u8 press = 1; 22 | int type; 23 | char c; 24 | /* Just skip prefix code: 0xE0 */ 25 | if (scan_code == KEY_E0) 26 | return; 27 | /* scan code of pause key: 0xe1 0x1d 0x45 0xe1 0x4d 0xc5 */ 28 | if (scan_code == KEY_E1 || keys.pause) { 29 | keys.pause = 1; 30 | if (scan_code == 0xc5) 31 | keys.pause = 0; 32 | return; 33 | } 34 | 35 | if (scan_code & KEY_RELEASE_BIT) { 36 | scan_code &= 0x7f; 37 | press = 0; 38 | } 39 | 40 | /* get scancode types */ 41 | type = scancode_types[scan_code]; 42 | /* handle none code */ 43 | if (press && type == KEY_NONE) { 44 | printk("None scan code: %x\n", scan_code); 45 | return; 46 | } 47 | /* handle prefix code */ 48 | if (scancode_types[scan_code] == KEY_PREFIX) { 49 | switch (scan_code) { 50 | case KEY_ESC: 51 | keys.esc = press; 52 | break; 53 | case KEY_CAPSLOCK: 54 | if (press) 55 | keys.capslock = !keys.capslock; 56 | break; 57 | case KEY_LSHIFT: 58 | case KEY_RSHIFT: 59 | keys.shift = press; 60 | break; 61 | case KEY_START: 62 | keys.start = press; 63 | break; 64 | case KEY_ALT: 65 | keys.alt = press; 66 | break; 67 | case KEY_CTRL: 68 | keys.ctrl = press; 69 | break; 70 | } 71 | return; 72 | } 73 | /* handle acsii scan code */ 74 | if (press && type == KEY_ASCII) { 75 | if (keys.capslock || keys.shift) 76 | c = scancode_shift_ascii[scan_code]; 77 | else 78 | c = scancode_ascii[scan_code]; 79 | /* EOF */ 80 | if ((c == 'd' || c == 'D') && keys.ctrl) 81 | c = '\0'; 82 | key_putc(c); 83 | } 84 | } 85 | 86 | void keyboard_init(void) 87 | { 88 | /* open keyboard interrupt */ 89 | unmask_8259A(IRQ_KEYBOARD); 90 | } 91 | -------------------------------------------------------------------------------- /fs/minix/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static struct super_block minix_sb; 11 | 12 | static void minix_check_super(struct minix_d_super_block *msb) 13 | { 14 | if (msb->s_magic != MINIX_SUPER_MAGIC) 15 | panic("Unknown fs type, not minix"); 16 | if (msb->s_nzones > minix_sb.s_bdev->blocks - minix_sb.s_start) 17 | panic("zones %d is larger then %d usable blocks", 18 | msb->s_nzones, minix_sb.s_bdev->blocks - minix_sb.s_start); 19 | if (msb->s_max_size != MINIX_MAX_SIZE) 20 | panic("Invalid max size %d", msb->s_max_size); 21 | if (msb->s_log_zone_size != 0) 22 | panic("Invalid log zone size %d", msb->s_log_zone_size); 23 | if (msb->s_firstdatazone != FIRST_ZONE_BLK(msb)) 24 | panic("Invalid first data zone %d", msb->s_firstdatazone); 25 | if (msb->s_imap_blocks != INODE_MAP_BLOCKS(msb)) 26 | panic("Invalid imap blocks"); 27 | if (msb->s_zmap_blocks != ZONE_MAP_BLOCKS(msb)) 28 | panic("Invalid zmap blocks"); 29 | printk("The super block of minix filesystem is ok!\n"); 30 | } 31 | 32 | extern struct block_device hd_bdev; 33 | 34 | struct block *minix_get_block(struct super_block *s, int blk) 35 | { 36 | return get_block(s->s_bdev, s->s_start + blk); 37 | } 38 | 39 | extern void minix_fs_test(void); 40 | extern void minix_inode_init(void); 41 | void minix_fs_init(void) 42 | { 43 | /* get super block */ 44 | minix_sb.s_bdev = &hd_bdev; 45 | set_block_size(minix_sb.s_bdev, MINIX_BLOCK_SIZE); 46 | minix_sb.s_start = MINIXFS_START; 47 | if (minix_sb.s_start >= minix_sb.s_bdev->blocks) 48 | panic("minixfs starts from %d block over %d blocks of device", 49 | minix_sb.s_start, minix_sb.s_bdev->blocks); 50 | minix_sb.s_block = minix_get_block(&minix_sb, MINIX_SUPER_BLK); 51 | if (!minix_sb.s_block) 52 | panic("Cannot get minixfs super block"); 53 | /* check super block */ 54 | minix_check_super(minixsuper(&minix_sb)); 55 | 56 | minix_inode_init(); 57 | 58 | /* init root dir */ 59 | ctask->fs.root_dir = minix_get_inode(&minix_sb, MINIX_ROOT_INO); 60 | if (!ctask->fs.root_dir) 61 | panic("Cannot get minix root dir"); 62 | ctask->fs.current_dir = get_inode_ref(ctask->fs.root_dir); 63 | /* debug inode */ 64 | // minix_fs_test(); 65 | } 66 | -------------------------------------------------------------------------------- /fs/ide.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static int ide_wait(int check) 8 | { 9 | int r; 10 | /* wait for disk ready */ 11 | while ((((r = inb(ATA_MASTER_CMD)) & (ATA_STATUS_RDY|ATA_STATUS_BSY))) 12 | != ATA_STATUS_RDY) 13 | /* do nothing */; 14 | if (check && (r & (ATA_STATUS_DF | ATA_STATUS_ERR ))) 15 | return -1; 16 | return 0; 17 | } 18 | 19 | int ide_read_sect(int sects, void *dst, int lba) 20 | { 21 | int r; 22 | #ifdef DEBUG_IDE 23 | debug("read sects %d lba %d", sects, lba); 24 | #endif 25 | if (sects <= 0) 26 | return -1; 27 | /* wait for disk to be ready */ 28 | ide_wait(0); 29 | /* 28 bit LBA PIO mode read on the Primary bus */ 30 | outb(ATA_MASTER_SECS, sects); /* read sector count = 1 */ 31 | outb(ATA_MASTER_LBALOW, lba & 0xff); 32 | outb(ATA_MASTER_LBAMID, (lba >> 8) & 0xff); 33 | outb(ATA_MASTER_LBAHI, (lba >> 16) & 0xff); 34 | outb(ATA_MASTER_LBAEX, ((lba >> 24) & 0xf) | 0xe0); /* 0xe0 for master */ 35 | outb(ATA_MASTER_CMD, ATA_CMD_READ); 36 | /* copy to dest buffer */ 37 | for (r = 0; r < sects; r++) { 38 | /* wait for disk to be ready */ 39 | if (ide_wait(1) < 0) 40 | break; 41 | /* read sector to memory */ 42 | insl(ATA_MASTER_DATA, dst, SECT_SIZE / sizeof(int)); 43 | dst += SECT_SIZE; 44 | } 45 | return r; 46 | } 47 | 48 | int ide_write_sect(int sects, void *src, int lba) 49 | { 50 | int r; 51 | #ifdef DEBUG_IDE 52 | debug("write sects %d lba %d", sects, lba); 53 | #endif 54 | if (sects <= 0) 55 | return -1; 56 | /* wait for disk to be ready */ 57 | ide_wait(0); 58 | /* 28 bit LBA PIO mode read on the Primary bus */ 59 | outb(ATA_MASTER_SECS, sects); /* read sector count = 1 */ 60 | outb(ATA_MASTER_LBALOW, lba & 0xff); 61 | outb(ATA_MASTER_LBAMID, (lba >> 8) & 0xff); 62 | outb(ATA_MASTER_LBAHI, (lba >> 16) & 0xff); 63 | outb(ATA_MASTER_LBAEX, ((lba >> 24) & 0xf) | 0xe0); /* 0xe0 for master */ 64 | outb(ATA_MASTER_CMD, ATA_CMD_WRITE); 65 | /* copy to ide bus */ 66 | for (r = 0; r < sects; r++) { 67 | /* wait for disk to be ready */ 68 | if (ide_wait(1) < 0) 69 | break; 70 | /* read sector to memory */ 71 | outsl(ATA_MASTER_DATA, src, SECT_SIZE / sizeof(int)); 72 | src += SECT_SIZE; 73 | } 74 | return r; 75 | } 76 | 77 | int ide_blocks(void) 78 | { 79 | return IDE_DISK_SECTS / 2; 80 | } 81 | -------------------------------------------------------------------------------- /kernel/schedule.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct list_head task_list; 7 | struct task init_task; 8 | static struct task dummy_task; /* for switching to the same ctack */ 9 | 10 | /* It is safe to switch to current task, which is not recommended. */ 11 | void task_switch(struct task *next) 12 | { 13 | struct task *prev; 14 | /* 15 | * If swiching to current task, using dummy task as prev. 16 | * Otherwise, prev_[esp|eip] will overlap next_[esp|eip] 17 | */ 18 | prev = (ctask == next) ? &dummy_task : ctask; 19 | ctask = next; 20 | /* When user jumps to kernel, tss::esp0|ss0 will be loaded. */ 21 | common_tss.esp0 = (unsigned int)next->kstacktop; 22 | load_cr3(PADDR(next->us.pgdir)); 23 | asm volatile ( 24 | "pushfl;" 25 | "pushl %%ebp;" 26 | "movl %%esp, %[prev_esp];" 27 | "movl $1f, %[prev_eip];" 28 | "movl %[next_esp], %%esp;" 29 | "pushl %[next_eip];" 30 | "ret;" 31 | "1:" 32 | "popl %%ebp;" 33 | "popfl;" 34 | : [prev_esp] "=m" (prev->con.esp), 35 | [prev_eip] "=m" (prev->con.eip) 36 | : [next_esp] "m" (next->con.esp), 37 | [next_eip] "m" (next->con.eip) 38 | : "memory"); 39 | } 40 | 41 | void debug_task(void) 42 | { 43 | struct task *task; 44 | for_each_task(task) { 45 | if (task->state == TASK_RUNNABLE) 46 | printk("[%d]", task->pid); 47 | } 48 | } 49 | 50 | void schedule(void) 51 | { 52 | struct task *task, *next = NULL; 53 | 54 | /* 55 | * FIXME: add lock to solve race condition for task_list 56 | * FIXED: close interrupt when schedule is called() via interrupt level 57 | * (schedule is called by sys_yield or timer_interrupt) 58 | */ 59 | 60 | for_each_task(task) { 61 | if (task == ctask || task->state != TASK_RUNNABLE) 62 | continue; 63 | if (!next || task->priority > next->priority) 64 | next = task; 65 | } 66 | 67 | if (!next) { 68 | if (ctask == &init_task) { 69 | #ifdef DEBUG_SCHED_TASK 70 | debug_task(); 71 | #endif 72 | return; 73 | } 74 | next = &init_task; 75 | } 76 | next->priority--; 77 | task_switch(next); 78 | } 79 | 80 | extern void close_interrupt(void); 81 | extern void open_interrupt(void); 82 | 83 | void sys_yield(void) 84 | { 85 | close_interrupt(); 86 | schedule(); 87 | open_interrupt(); 88 | } 89 | 90 | int sys_getpid(void) 91 | { 92 | return ctask->pid; 93 | } 94 | -------------------------------------------------------------------------------- /include/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef __MM_H 2 | #define __MM_H 3 | 4 | /* make entry stack overlap bootloader */ 5 | #define ENTRY_STACK_TOP VADDR(0x8c00) 6 | #define KERNEL_BASE 0xc0000000 7 | 8 | #ifdef __ASM__ 9 | 10 | /* Macro for entry.S */ 11 | #define PADDR(va) ((va) - KERNEL_BASE) 12 | #define VADDR(pa) ((pa) + KERNEL_BASE) 13 | 14 | #else /* !__ASM__ */ 15 | 16 | /* kernel address space: [0xc0000000, 0xffffffff] */ 17 | #define PADDR(va) ((unsigned int)(va) - KERNEL_BASE) 18 | #define VADDR(pa) ((unsigned int)(pa) + KERNEL_BASE) 19 | 20 | /* user stack address */ 21 | #define USER_STACK_SIZE PGSIZE 22 | #define USER_STACK_TOP (KERNEL_BASE - PGSIZE) /* reserve a page hole */ 23 | #define USER_STACK (USER_STACK_TOP - USER_STACK_SIZE) 24 | 25 | /* kernel stack size: 8KB */ 26 | #define KERN_STACK_PAGES 2 27 | #define KERN_STACK_SIZE (KERN_STACK_PAGES * PGSIZE) 28 | /* kernel image starts from physical memory 16MB */ 29 | #define KERNEL_START 0x01000000 30 | /* high memory start from physical memory 768MB */ 31 | #define HIGH_MEM 0x30000000 32 | /* bootloader contains 4KB in disk */ 33 | #define KERNEL_START_SECT 8 34 | 35 | #define PGSHIFT 12 36 | #define PTSHIFT 22 37 | #define PGSIZE 0x1000 38 | #define NPDE(addr) (((unsigned int)addr) >> PTSHIFT) 39 | #define NPTE(addr) (((unsigned int)addr) >> PGSHIFT) 40 | /* page table size: 4MB (1024 * PGSIZE) */ 41 | #define PTSIZE 0x400000 42 | 43 | #define KBASE_PDE NPDE(KERNEL_BASE) 44 | #define KBASE_PDE_SIZE (PGSIZE - KBASE_PDE * sizeof(pde_t)) 45 | #define KBASE_PTE NPTE(KERNEL_BASE) 46 | #define KSTART_PDE NPDE(KERNEL_START) 47 | #define VKSTART_PDE NPDE(VADDR(KERNEL_START)) 48 | 49 | extern unsigned int _stext[]; 50 | extern unsigned int _etext[]; 51 | extern unsigned int _sdata[]; 52 | extern unsigned int _edata[]; 53 | extern unsigned int __bss_start[]; 54 | extern unsigned int __bss_end[]; 55 | extern unsigned int _end[]; 56 | extern void *boot_alloc(int, int); 57 | extern void *get_free_page(void); 58 | extern void put_free_page(void *); 59 | extern void *get_free_page_pa(void); 60 | struct page; 61 | extern struct page *alloc_pages(int zone, int order); 62 | extern void free_pages(struct page *page, int order); 63 | extern void free_page(struct page *page); 64 | extern void *kva_page(struct page *page); 65 | extern void get_page_ref(struct page *page); 66 | extern void hold_page(struct page *page); 67 | extern void zone_debug(int); 68 | 69 | #endif /* __ASM__ */ 70 | 71 | #endif /* mm.h */ 72 | -------------------------------------------------------------------------------- /include/pit.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Programmbale Interval Timer(PIT) chip (8253/8254 chip) 3 | */ 4 | #ifndef __PIT_H 5 | #define __PIT_H 6 | 7 | #define PIT_CH0 0x40 /* Channle 0 data port(read/write) */ 8 | #define PIT_CH1 0x41 /* Channle 1 data port(read/write) */ 9 | #define PIT_CH2 0x42 /* Channle 2 data port(read/write) */ 10 | #define PIT_MODE 0x43 /* Mode/Command register(write only, a read is ignored) */ 11 | 12 | /* 13 | * The Mode/Command register at I/O address 0x43 contains the following: 14 | * Bits Usage 15 | * 6, 7 Select channel : 16 | * (7 6) 17 | * 0 0 = Channel 0 18 | * 0 1 = Channel 1 19 | * 1 0 = Channel 2 20 | * 1 1 = Read-back command (8254 only) 21 | * 4, 5 Access mode : 22 | * (5 4) 23 | * 0 0 = Latch count value command 24 | * 0 1 = Access mode: lobyte only 25 | * 1 0 = Access mode: hibyte only 26 | * 1 1 = Access mode: lobyte/hibyte 27 | * 1, 2, 3 Operating mode : 28 | * (3 2 1) 29 | * 0 0 0 = Mode 0 (interrupt on terminal count) 30 | * 0 0 1 = Mode 1 (hardware re-triggerable one-shot) 31 | * 0 1 0 = Mode 2 (rate generator) 32 | * 0 1 1 = Mode 3 (square wave generator) 33 | * 1 0 0 = Mode 4 (software triggered strobe) 34 | * 1 0 1 = Mode 5 (hardware triggered strobe) 35 | * 1 1 0 = Mode 2 (rate generator, same as 010b) 36 | * 1 1 1 = Mode 3 (square wave generator, same as 011b) 37 | * 0 BCD/Binary mode: 0 = 16-bit binary, 1 = four-digit BCD 38 | */ 39 | #define PIT_MODE_CH0 0x00 40 | #define PIT_MODE_CH1 0x40 41 | #define PIT_MODE_CH2 0x80 42 | #define PIT_MODE_RB 0xc0 43 | 44 | #define PIT_MODE_LATCH 0x00 45 | #define PIT_MODE_LOW 0x10 46 | #define PIT_MODE_HIGH 0x20 47 | #define PIT_MODE_LOHI 0x30 48 | 49 | #define PIT_MODE_0 0x00 50 | #define PIT_MODE_1 0x02 51 | #define PIT_MODE_2 0x04 52 | #define PIT_MODE_3 0x06 53 | #define PIT_MODE_4 0x08 54 | #define PIT_MODE_5 0x09 55 | #define PIT_MODE_6 0x0a 56 | #define PIT_MODE_7 0x0e 57 | 58 | #define TIMER_FREQ 1000 /* timer interrupt frequence: 100 times/sec */ 59 | #define PIT_FREQ 1193182 /* 8253 chip frequence: 1.193181666MHz */ 60 | #define FREQ_DIV (PIT_FREQ / TIMER_FREQ) 61 | 62 | #endif /* pit.h */ 63 | -------------------------------------------------------------------------------- /keyboard/scancode.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define P KEY_PREFIX 4 | #define N KEY_NONE 5 | #define A KEY_ASCII 6 | #define S KEY_SPECIAL 7 | 8 | unsigned char scancode_types[128] = { 9 | /* 00: ESC 1 2 3 4 5 6 */ 10 | N, P, A, A, A, A, A, A, 11 | /* 08: 7 8 9 0 - = backspace tab */ 12 | A, A, A, A, A, A, A, A, 13 | /* 10: q w e r t y u i */ 14 | A, A, A, A, A, A, A, A, 15 | /* 18: o p [ ] enter ctrl/pause a s */ 16 | A, A, A, A, A, P, A, A, 17 | /* 20: d f g h j k l ; */ 18 | A, A, A, A, A, A, A, A, 19 | /* 28: ' ` lshirt \ z x c v */ 20 | A, A, P, A, A, A, A, A, 21 | /* 30: b n m , < . > / ? rshift */ 22 | A, A, A, A, A, A, P, N, 23 | /* 38: alt space capslock F1 F2 F3 F4 F5 */ 24 | P, A, P, S, S, S, S, S, 25 | /* 40: F6 F7 F8 F9 F10 pause scrlk home */ 26 | S, S, S, S, S, S, S, S, 27 | /* 48: up pgup left right end */ 28 | S, S, N, S, N, S, N, S, 29 | /* 50: down pgdn insert delete F11 */ 30 | S, S, S, S, N, N, N, S, 31 | /* 58: F12 start book,mouse */ 32 | S, N, N, S, N, S, N, N, 33 | /* 60: */ 34 | N, N, N, N, N, N, N, N, 35 | /* 68: */ 36 | N, N, N, N, N, N, N, N, 37 | /* 70: */ 38 | N, N, N, N, N, N, N, N, 39 | /* 78: */ 40 | N, N, N, N, N, N, N, N, 41 | }; 42 | 43 | #define UNA 0 /* unascii */ 44 | char scancode_ascii[0x40] = { 45 | UNA, UNA, '1', '2', '3', '4', '5', '6', 46 | '7', '8', '9', '0', '-', '=', '\b', '\t', 47 | 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 48 | 'o', 'p', '[', ']', '\n', UNA, 'a', 's', 49 | 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 50 | '\'', '`', UNA, '\\', 'z', 'x', 'c', 'v', 51 | 'b', 'n', 'm', ',', '.', '/', UNA, UNA, 52 | UNA, ' ', UNA, UNA, UNA, UNA, UNA, UNA, 53 | }; 54 | 55 | char scancode_shift_ascii[0x40] = { 56 | UNA, UNA, '!', '@', '#', '$', '%', '^', 57 | '&', '*', '(', ')', '_', '+', '\b', '\t', 58 | 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 59 | 'O', 'P', '{', '}', '\n', UNA, 'A', 'S', 60 | 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', 61 | '"', '~', UNA, '|', 'Z', 'X', 'C', 'V', 62 | 'B', 'N', 'M', '<', '>', '?', UNA, UNA, 63 | UNA, ' ', UNA, UNA, UNA, UNA, UNA, UNA, 64 | }; 65 | 66 | -------------------------------------------------------------------------------- /fs/dirty_block.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Dirty block cache for fast file data synchronization 3 | * (Currentry dirty blocks cache is associated with global inode.) 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static struct dirty_block_cache *alloc_dbc(int size) 13 | { 14 | struct dirty_block_cache *dbc; 15 | dbc = kmalloc(dbcsize(size)); 16 | if (dbc) { 17 | memset(dbc, 0x0, dbcsize(size)); 18 | dbc->size = size; 19 | } 20 | return dbc; 21 | } 22 | 23 | static _inline void free_dbc(struct dirty_block_cache *dbc) 24 | { 25 | kfree(dbc); 26 | } 27 | 28 | static _inline void add_dbc(struct dirty_block_cache *dbc, struct block *block) 29 | { 30 | dbc->blocks[dbc->free++] = block; 31 | } 32 | 33 | static struct dirty_block_cache *inode_lookup_free_dbc(struct inode *inode) 34 | { 35 | struct dirty_block_cache **prev, *dbc; 36 | prev = &inode->i_dbc; 37 | dbc = inode->i_dbc; 38 | while (dbc) { 39 | /* find the free dbc */ 40 | if (dbc->free < dbc->size) { 41 | if (dbc != inode->i_dbc) { 42 | /* add free dbc to head of inode dbc list */ 43 | *prev = dbc->next; 44 | dbc->next = inode->i_dbc; 45 | inode->i_dbc = dbc; 46 | } 47 | break; 48 | } 49 | prev = &dbc->next; 50 | dbc = dbc->next; 51 | } 52 | return dbc; 53 | } 54 | 55 | static struct dirty_block_cache *inode_alloc_dbc(struct inode *inode) 56 | { 57 | struct dirty_block_cache *dbc = alloc_dbc(DBC_FIRST_SIZE); 58 | if (!dbc) 59 | panic("No memory for dirty block cache"); 60 | if (inode->i_dbc) 61 | dbc->next = inode->i_dbc; 62 | inode->i_dbc = dbc; 63 | return dbc; 64 | } 65 | 66 | /* Caller should check whether block is in dbc. */ 67 | void inode_add_dbc(struct inode *inode, struct block *block) 68 | { 69 | struct dirty_block_cache *dbc = inode->i_dbc; 70 | /* lookup free dbc */ 71 | dbc = inode_lookup_free_dbc(inode); 72 | /* if no free dbc, alloc new one */ 73 | if (!dbc) 74 | dbc = inode_alloc_dbc(inode); 75 | add_dbc(dbc, block); 76 | } 77 | 78 | void inode_free_dbc(struct inode *inode) 79 | { 80 | struct dirty_block_cache *dbc, *next; 81 | for (dbc = inode->i_dbc; dbc; dbc = next) { 82 | next = dbc->next; 83 | free_dbc(dbc); 84 | } 85 | inode->i_dbc = NULL; 86 | } 87 | 88 | void inode_sync_dbc(struct inode *inode) 89 | { 90 | struct dirty_block_cache *dbc; 91 | int i; 92 | for (dbc = inode->i_dbc; dbc; dbc = dbc->next) { 93 | for (i = dbc->free - 1; i >= 0; i--) 94 | flush_block(dbc->blocks[i]); 95 | dbc->free = 0; 96 | } 97 | } 98 | 99 | -------------------------------------------------------------------------------- /fs/path.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct inode *inode_sub_lookup(struct inode *dir, char *basename, int len) 7 | { 8 | struct inode *inode = NULL; 9 | if (dir->i_ops->sub_lookup) 10 | inode = dir->i_ops->sub_lookup(dir, basename, len); 11 | return inode; 12 | } 13 | 14 | struct inode *inode_sub_lookup_put(struct inode *dir, char *base, int len) 15 | { 16 | struct inode *inode = inode_sub_lookup(dir, base, len); 17 | put_inode(dir); 18 | return inode; 19 | } 20 | 21 | int path_next_entry(char **path) 22 | { 23 | char *p = *path; 24 | int len = 0; 25 | while (*p && *p != '/') { 26 | p++; 27 | len++; 28 | } 29 | /* skip slash */ 30 | while (*p == '/') 31 | p++; 32 | *path = p; 33 | return len; 34 | } 35 | 36 | struct inode *path_lookup_dir(char *path, char **basename, int *baselen) 37 | { 38 | struct inode *dir, *prev, *start; 39 | char *base; 40 | int len, ddff = 0; /* double dot fast fails */ 41 | /* get start dir inode */ 42 | if (path[0] == '/') { 43 | start = ctask->fs.root_dir; 44 | prev = get_inode_ref(start); 45 | /* skip slash */ 46 | while (*path == '/') 47 | path++; 48 | } else { 49 | start = ctask->fs.current_dir; 50 | prev = NULL; 51 | } 52 | dir = get_inode_ref(start); 53 | while (1) { 54 | base = path; 55 | len = path_next_entry(&path); 56 | if (path[0] == '\0') 57 | break; 58 | /* 59 | * Fast path lookup of '.' or '..': 60 | * we dont save all previous dir inode, so '..' fast lookup 61 | * maybe fail when prev equals NULL. 62 | */ 63 | ddff = 0; 64 | if (base[0] == '.') { 65 | if (len == 1) { 66 | continue; 67 | } else if (len == 2 && base[1] == '.') { 68 | if (prev) { 69 | put_inode(dir); 70 | dir = get_inode_ref(prev); 71 | if (dir != start) { 72 | put_inode(prev); 73 | prev = NULL; 74 | } 75 | continue; 76 | } 77 | ddff = 1; 78 | } 79 | } 80 | 81 | if (!S_ISDIR(dir->i_mode)) { 82 | dir = NULL; 83 | len = 0; 84 | break; 85 | } 86 | if (!ddff) { 87 | if (prev) 88 | put_inode(prev); 89 | prev = get_inode_ref(dir); 90 | } 91 | dir = inode_sub_lookup_put(dir, base, len); 92 | if (!dir) { 93 | len = 0; 94 | break; 95 | } 96 | } 97 | if (prev) 98 | put_inode(prev); 99 | if (len == 0) 100 | base = NULL; 101 | if (basename) 102 | *basename = base; 103 | if (baselen) 104 | *baselen = len; 105 | return dir; 106 | } 107 | 108 | -------------------------------------------------------------------------------- /user/include/ulib.h: -------------------------------------------------------------------------------- 1 | #ifndef __ULIB_H 2 | #define __ULIB_H 3 | 4 | #include 5 | 6 | struct file_stat; 7 | struct dir_stat; 8 | 9 | extern int printf(char *, ...); 10 | extern int gets(char *, int); 11 | extern int fork(void); 12 | extern void yield(void); 13 | extern int getpid(void); 14 | extern void exit(int); 15 | extern int wait(int *); 16 | extern int execute(char *, int, char **); 17 | /* file I/O */ 18 | extern int open(char *path, unsigned int mode); 19 | extern int close(int fd); 20 | extern off_t lseek(int fd, off_t offset, int whence); 21 | extern int write(int fd, char *buf, size_t size); 22 | extern int read(int fd, char *buf, size_t size); 23 | extern int fsync(int fd); 24 | extern int fstat(int fd, struct file_stat *); 25 | extern int fchdir(int fd); 26 | extern int chdir(char *); 27 | extern int fgetdir(int, int, int, struct dir_stat *); 28 | extern int mkdir(char *, unsigned int); 29 | extern int rmdir(char *); 30 | extern int rm(char *); 31 | extern void sync(void); 32 | extern int truncate(int); 33 | extern char *getcwd(char *buf, size_t size); 34 | 35 | #define S_IFMT 00170000 36 | #define S_IFSOCK 0140000 37 | #define S_IFLNK 0120000 38 | #define S_IFREG 0100000 39 | #define S_IFBLK 0060000 40 | #define S_IFDIR 0040000 41 | #define S_IFCHR 0020000 42 | #define S_IFIFO 0010000 43 | #define S_ISUID 0004000 44 | #define S_ISGID 0002000 45 | #define S_ISVTX 0001000 46 | 47 | #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) 48 | #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) 49 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 50 | #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) 51 | #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) 52 | #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) 53 | #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) 54 | 55 | #define S_IRWXU 00700 56 | #define S_IRUSR 00400 57 | #define S_IWUSR 00200 58 | #define S_IXUSR 00100 59 | 60 | #define S_IRWXG 00070 61 | #define S_IRGRP 00040 62 | #define S_IWGRP 00020 63 | #define S_IXGRP 00010 64 | 65 | #define S_IRWXO 00007 66 | #define S_IROTH 00004 67 | #define S_IWOTH 00002 68 | #define S_IXOTH 00001 69 | 70 | #define O_CREATE 0x80000000 71 | #define O_TRUNCATE 0x40000000 72 | 73 | #define SEEK_SET 0 74 | #define SEEK_CUR 1 75 | #define SEEK_END 2 76 | 77 | /* used by system call: fstat */ 78 | struct file_stat { 79 | unsigned int size; 80 | unsigned int inode; 81 | unsigned int mode; 82 | unsigned int iref; 83 | unsigned int link; 84 | }; 85 | 86 | #define DIR_SIZE 32 87 | struct dir_stat { 88 | char name[DIR_SIZE]; 89 | int len; 90 | unsigned int inode; 91 | }; 92 | 93 | #endif /* ulib.h */ 94 | -------------------------------------------------------------------------------- /mm/boot_memory.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct boot_param *boot_param = (struct boot_param *)VADDR(BOOT_PARAM_ADDR); 8 | static void *boot_memory_start; 9 | static void *boot_memory_free; 10 | unsigned int memory_end; 11 | 12 | static const char *e820_str[] = { 13 | "ignored", 14 | "free", 15 | "reserved", 16 | "acpi reclaim", 17 | "acpi invs" 18 | }; 19 | 20 | void boot_memory_init(void) 21 | { 22 | struct e820_entry *entry = boot_param->e820_list; 23 | int i, num = boot_param->e820_num; 24 | boot_memory_start = (void *)ALIGN_UP(PADDR(_end), PGSIZE); 25 | boot_memory_free = boot_memory_start; 26 | /* 27 | * We reserve memory below 1MB and use 820 map table 28 | * to find end of memory, ignoring real maps. 29 | */ 30 | memory_end = 0; 31 | printk("Memory map:\n"); 32 | printk(" %-10s|%-10s|%-12s|\n", "addr", "length", "type"); 33 | for (i = 0; i < num; i++) { 34 | printk(" 0x%08x|0x%08x|%-12s|\n", entry[i].addr, 35 | entry[i].length, e820_str[entry[i].type]); 36 | if (entry[i].type != E820_TYPE_FREE) 37 | continue; 38 | if (entry[i].addr + entry[i].length > memory_end) 39 | memory_end = entry[i].addr + entry[i].length; 40 | } 41 | /* caculate the number of memory pages */ 42 | npage = memory_end / PGSIZE; 43 | printk("memory size: %dKB(%dMB)\n", npage * 4, npage * 4 / 1024); 44 | } 45 | 46 | /* 47 | * Caller dont need to check the return value of it, 48 | * but assure that @size an @num are positive. 49 | * If free memory is not enough, it panics directly! 50 | */ 51 | void *boot_alloc(int size, int num) 52 | { 53 | void *ret; 54 | if (!boot_memory_free) 55 | panic("Boot memory allocator dies."); 56 | ret = ALIGN_UP(boot_memory_free, size); 57 | boot_memory_free = ret + size * num; 58 | if (boot_memory_free > (void *)memory_end) 59 | panic("Out of boot memory: alloc %d from %p", 60 | num * size, boot_memory_free); 61 | 62 | return (void *)VADDR(ret); 63 | } 64 | 65 | void e820_memory_reserved(void) 66 | { 67 | struct e820_entry *entry = boot_param->e820_list; 68 | int num = boot_param->e820_num; 69 | int pn, n, i; 70 | for (i = 0; i < num; i++) { 71 | if (entry[i].type == E820_TYPE_FREE) 72 | continue; 73 | if (entry[i].addr + entry[i].length > memory_end) 74 | continue; 75 | n = PN(entry[i].addr + entry[i].length + PGSIZE - 1); 76 | for (pn = PN(entry[i].addr); pn < n; pn++) 77 | setpagereserved(&page_table[pn]); 78 | } 79 | } 80 | 81 | void *boot_memory_exit(void) 82 | { 83 | void *last = ALIGN_UP(boot_memory_free, PGSIZE); 84 | boot_memory_free = NULL; 85 | return last; 86 | } 87 | -------------------------------------------------------------------------------- /kernel/interrupt.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | ENTRY_NOERRCODE(de_entry, INTNO_DE) 6 | /* Vector 1 is reserved */ 7 | ENTRY_NOERRCODE(nmi_entry, INTNO_NMI) 8 | ENTRY_NOERRCODE(bp_entry, INTNO_BP) 9 | ENTRY_NOERRCODE(of_entry, INTNO_OF) 10 | ENTRY_NOERRCODE(br_entry, INTNO_BR) 11 | ENTRY_NOERRCODE(ud_entry, INTNO_UD) 12 | ENTRY_NOERRCODE(nm_entry, INTNO_NM) 13 | ENTRY_ERRCODE(df_entry, INTNO_DF) 14 | /* Vector 9 is reserved */ 15 | ENTRY_ERRCODE(ts_entry, INTNO_TS) 16 | ENTRY_ERRCODE(np_entry, INTNO_NP) 17 | ENTRY_ERRCODE(ss_entry, INTNO_SS) 18 | ENTRY_ERRCODE(gp_entry, INTNO_GP) 19 | ENTRY_ERRCODE(pf_entry, INTNO_PF) 20 | /* Vector 15 is reserved */ 21 | ENTRY_NOERRCODE(mf_entry, INTNO_MF) 22 | ENTRY_ERRCODE(ac_entry, INTNO_AC) 23 | ENTRY_NOERRCODE(mc_entry, INTNO_MC) 24 | ENTRY_NOERRCODE(xm_entry, INTNO_XM) 25 | /* Vector 20-31 are reserved */ 26 | /* Vector 32-47(IRQ 0-15) */ 27 | ENTRY_INT(irq0_entry, INTNO_IRQ0) 28 | ENTRY_INT(irq1_entry, INTNO_IRQ1) 29 | ENTRY_INT(irq2_entry, INTNO_IRQ2) 30 | ENTRY_INT(irq3_entry, INTNO_IRQ3) 31 | ENTRY_INT(irq4_entry, INTNO_IRQ4) 32 | ENTRY_INT(irq5_entry, INTNO_IRQ5) 33 | ENTRY_INT(irq6_entry, INTNO_IRQ6) 34 | ENTRY_INT(irq7_entry, INTNO_IRQ7) 35 | ENTRY_INT(irq8_entry, INTNO_IRQ8) 36 | ENTRY_INT(irq9_entry, INTNO_IRQ9) 37 | ENTRY_INT(irq10_entry, INTNO_IRQ10) 38 | ENTRY_INT(irq11_entry, INTNO_IRQ11) 39 | ENTRY_INT(irq12_entry, INTNO_IRQ12) 40 | ENTRY_INT(irq13_entry, INTNO_IRQ13) 41 | ENTRY_INT(irq14_entry, INTNO_IRQ14) 42 | ENTRY_INT(irq15_entry, INTNO_IRQ15) 43 | /* Vector 48 (system_call)*/ 44 | ENTRY_INT(syscall_entry, INTNO_SYSCALL) 45 | 46 | ENTRY(interrupt_entry) 47 | xchgl %eax, (%esp) /* push eax & eax <- interrupt number */ 48 | pushl %ebx 49 | pushl %ecx 50 | pushl %edx 51 | pushl %edi 52 | pushl %esi 53 | pushl %ebp 54 | push %gs 55 | push %fs 56 | push %es 57 | push %ds 58 | 59 | /* Reset kernel data segments */ 60 | movl $KERN_DATA_SEG, %ecx 61 | movw %cx, %ds 62 | movw %cx, %es 63 | movw %cx, %fs 64 | movw %cx, %gs 65 | 66 | /* Call interrupt handler */ 67 | pushl %esp /* poiner of regs */ 68 | pushl %eax /* first argument of interrupt_handler */ 69 | call interrupt_handler 70 | addl $8, %esp 71 | 72 | interrupt_return: 73 | pop %ds 74 | pop %es 75 | pop %fs 76 | pop %gs 77 | popl %ebp 78 | popl %esi 79 | popl %edi 80 | popl %edx 81 | popl %ecx 82 | popl %ebx 83 | popl %eax 84 | addl $4, %esp /* skip error code */ 85 | iret 86 | 87 | ENTRY(fork_child_return) 88 | /* send EOI of timer interrupt */ 89 | pushl $INTNO_IRQ0 90 | call EOI_8259A 91 | addl $4, %esp 92 | call open_interrupt 93 | /* return to usermode */ 94 | jmp interrupt_return 95 | -------------------------------------------------------------------------------- /include/inode.h: -------------------------------------------------------------------------------- 1 | #ifndef __INODE_H 2 | #define __INODE_H 3 | 4 | #include 5 | 6 | struct dirty_block_cache; 7 | struct block; 8 | struct inode; 9 | struct file_stat; 10 | struct dir_stat; 11 | 12 | struct inode_operations { 13 | int (*read)(struct inode *, char *, size_t, off_t); 14 | int (*write)(struct inode *, char *, size_t, off_t); 15 | struct inode *(*sub_lookup)(struct inode *, char *, int); 16 | struct inode *(*create)(struct inode *, char *, int); 17 | void (*update_size)(struct inode *, size_t); 18 | void (*release)(struct inode *); 19 | void (*sync)(struct inode *); 20 | int (*getdir)(struct inode *, int, int, struct dir_stat *); 21 | struct inode *(*mkdir)(struct inode *, char *, int); 22 | int (*rmdir)(struct inode *, char *, int); 23 | int (*rm)(struct inode *, char *, int); 24 | void (*stat)(struct inode *, struct file_stat *); 25 | void (*truncate)(struct inode *); 26 | int (*get_pathname)(struct inode *, char *, size_t); 27 | }; 28 | 29 | struct inode { 30 | unsigned int i_size; 31 | unsigned int i_ino; 32 | unsigned int i_mode; 33 | int i_refcnt; 34 | struct inode_operations *i_ops; 35 | struct super_block *i_sb; 36 | struct dirty_block_cache *i_dbc; 37 | }; 38 | 39 | extern struct inode *inode_sub_lookup(struct inode *dir, char *basename, int len); 40 | extern struct inode *path_lookup_dir(char *path, char **basename, int *baselen); 41 | extern struct inode *inode_path_lookup(char *path); 42 | extern struct inode *get_inode_ref(struct inode *inode); 43 | extern int inode_read(struct inode *inode, char *buf, size_t size, off_t off); 44 | extern int inode_write(struct inode *inode, char *buf, size_t size, off_t off); 45 | extern struct inode *inode_open(char *path, unsigned int mode); 46 | extern void inode_close(struct inode *inode); 47 | extern void put_inode(struct inode *inode); 48 | extern void inode_sync(struct inode *inode); 49 | extern void inode_stat(struct inode *, struct file_stat *); 50 | /* dirty block cache */ 51 | extern void inode_sync_dbc(struct inode *inode); 52 | extern void inode_free_dbc(struct inode *inode); 53 | extern void inode_add_dbc(struct inode *inode, struct block *block); 54 | extern void inode_chdir(struct inode *inode); 55 | extern int inode_getdir(struct inode *inode, int start, int num, struct dir_stat *ds); 56 | extern struct inode *inode_mkdir(char *path); 57 | extern void inode_update_size(struct inode *inode, size_t size); 58 | extern int inode_rmdir(char *path); 59 | extern int inode_rm(char *path); 60 | extern struct inode *inode_sub_lookup_put(struct inode *, char *, int); 61 | extern int inode_truncate(struct inode *); 62 | extern int inode_get_pathname(struct inode *, char *, size_t); 63 | 64 | #endif /* inode.h */ 65 | -------------------------------------------------------------------------------- /tools/build.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static char *boot, *kernel; 9 | static int bfd, kfd; 10 | static int ksize, fsoff; 11 | static unsigned int sectors; 12 | 13 | static void die(char *str) 14 | { 15 | if (errno) 16 | perror(str); 17 | else 18 | fprintf(stderr, "%s\n", str); 19 | exit(EXIT_FAILURE); 20 | } 21 | 22 | static void usage(void) 23 | { 24 | fprintf(stderr, "build bootimage kernelimage sectors\n"); 25 | exit(EXIT_FAILURE); 26 | } 27 | 28 | static void parse_args(int argc, char **argv) 29 | { 30 | if (argc != 4) 31 | usage(); 32 | boot = argv[1]; 33 | kernel = argv[2]; 34 | sectors = atoll(argv[3]); 35 | /* must be larger than 2MB */ 36 | if (sectors < 4096) 37 | die("sectors size is too small"); 38 | } 39 | 40 | void fwriteoffset(unsigned int offset) 41 | { 42 | FILE *fp = fopen(".offset", "w"); 43 | if (!fp) 44 | die("Cannot create .offset file"); 45 | fprintf(fp, "%u", offset); 46 | fclose(fp); 47 | } 48 | 49 | static void open_image(void) 50 | { 51 | bfd = open(boot, O_WRONLY); 52 | if (bfd == -1) 53 | die("open boot image"); 54 | kfd = open(kernel, O_RDONLY); 55 | if (kfd == -1) 56 | die("open kernel image"); 57 | } 58 | 59 | static void build_image(void) 60 | { 61 | /* write sectors of kernel image into offset 508(2 bytes) of boot.bin*/ 62 | ksize = lseek(kfd, 0, SEEK_END); 63 | if (ksize < 0) 64 | die("lseek kernel image"); 65 | ksize = (ksize + 511) / 512; 66 | if (ksize > 0xffff) 67 | die("kernel image size is too large!"); 68 | if (lseek(bfd, 508, SEEK_SET) != 508) 69 | die("lseek boot image"); 70 | if (write(bfd, &ksize, 2) != 2) 71 | die("write boot image"); 72 | /* write filesystem start block number into offset 506(2 bytes) of boot.bin */ 73 | fsoff = ((8 + ksize) + 1) / 2; 74 | if (fsoff > 0xffff) 75 | die("file system offset is too large!"); 76 | if (lseek(bfd, 506, SEEK_SET) != 506) 77 | die("lseek boot image"); 78 | if (write(bfd, &fsoff, 2) != 2) 79 | die("write boot image"); 80 | fwriteoffset(fsoff * 1024); 81 | /* 82 | * write sectors of disk into offset 500(4 bytes) of boot.bin 83 | * (support max size of 2TB) 84 | */ 85 | if (lseek(bfd, 500, SEEK_SET) != 500) 86 | die("lseek boot image"); 87 | if (write(bfd, §ors, 4) != 4) 88 | die("write boot image"); 89 | } 90 | 91 | static void close_image(void) 92 | { 93 | close(bfd); 94 | close(kfd); 95 | } 96 | 97 | int main(int argc, char **argv) 98 | { 99 | parse_args(argc, argv); 100 | open_image(); 101 | build_image(); 102 | close_image(); 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /include/page.h: -------------------------------------------------------------------------------- 1 | #ifndef __PAGE_H 2 | #define __PAGE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define LOW_MEM_START 0x00000000 /* low memory: [0, 16M) */ 9 | #define NOR_MEM_START 0x01000000 /* normal memory: [16M, 768M) */ 10 | #define HIGH_MEM_START 0x30000000 /* high memory: [768M, ~) */ 11 | 12 | #define PGSHIFT 12 13 | #define PGMASK (PGSIZE - 1) 14 | #define PGOFFSET(v) (((unsigned int)(v)) & PGMASK) 15 | #define PN(addr) (((unsigned int )addr) >> PGSHIFT) 16 | #define VPN(vaddr) PN(PADDR(vaddr)) 17 | #define PNADDR(pn) ((pn) << PGSHIFT) 18 | #define PNVADDR(pn) VADDR(PNADDR(pn)) 19 | 20 | #define PGS_UP(size) (((size) + PGMASK) >> PGSHIFT) 21 | #define PG_SIZE(n) PNADDR(n) 22 | 23 | #define LOW_MEM_PN PN(LOW_MEM_START) 24 | #define NOR_MEM_PN PN(NOR_MEM_START) 25 | #define HIGH_MEM_PN PN(HIGH_MEM_START) 26 | 27 | #define PG_MAX_ORDER 10 28 | #define PG_ORDERS (PG_MAX_ORDER + 1) 29 | #define PG_NIL_ORDER -1 30 | 31 | #define PG_ZONE_LOW 0 32 | #define PG_ZONE_NOR 1 33 | #define PG_ZONE_HIGH 2 34 | #define PG_ZONES 3 35 | 36 | #define PG2PN(p) (((struct page *)p) - page_table) 37 | #define PG2ADDR(p) PNADDR(PG2PN(p)) 38 | #define PG2VADDR(p) PNVADDR(PG2PN(p)) 39 | #define PN2PG(pn) (&page_table[pn]) 40 | #define ADDR2PG(pa) PN2PG(PN(pa)) 41 | #define VADDR2PG(va) PN2PG(VPN(va)) 42 | 43 | struct page_area { 44 | struct list_head free_list; 45 | int free_num; 46 | }; 47 | 48 | struct page_zone { 49 | struct page_area area[PG_ORDERS]; 50 | int start; /* start page number */ 51 | int total; /* total page number */ 52 | int free; /* free page number */ 53 | }; 54 | 55 | struct page { 56 | int pg_refcnt; 57 | struct list_head pg_list; 58 | unsigned int pg_zone:2, 59 | pg_reserved:1, /* page is reserved */ 60 | pg_buddy:1; /* page is in area::free_list */ 61 | int pg_order; /* area order */ 62 | int pg_cowshare; /* copy-on-page share numbers */ 63 | void *pg_private; 64 | }; 65 | 66 | static _inline void setpagezone(struct page *p, int type) 67 | { 68 | p->pg_zone = type; 69 | } 70 | 71 | /* name: capital letter */ 72 | #define __PAGE_FLAG_CLEAR(name)\ 73 | static _inline void unsetpage##name(struct page *page)\ 74 | { page->pg_##name = 0; } 75 | 76 | #define __PAGE_FLAG_SET(name)\ 77 | static _inline void setpage##name(struct page *page)\ 78 | { page->pg_##name = 1; } 79 | 80 | #define __PAGE_FLAG_DETECT(name)\ 81 | static _inline int page_##name(struct page *page)\ 82 | { return !!page->pg_##name; } 83 | 84 | #define PAGE_FLAGS(name)\ 85 | __PAGE_FLAG_CLEAR(name)\ 86 | __PAGE_FLAG_SET(name)\ 87 | __PAGE_FLAG_DETECT(name) 88 | 89 | PAGE_FLAGS(reserved); 90 | PAGE_FLAGS(buddy); 91 | 92 | extern struct page *page_table; 93 | extern unsigned int npage; 94 | 95 | #endif /* page.h */ 96 | -------------------------------------------------------------------------------- /doc/memory.txt: -------------------------------------------------------------------------------- 1 | How does tinyos manage memory? 2 | === 3 | 4 | 1. All used memory management algorithm 5 | 6 | -------------------+-----------------+------------------+------------------ 7 | Allocator | Unit | Example | Source 8 | -------------------+-----------------+------------------+------------------ 9 | slab allocator | size of | inode,block,task | mm/slab.c 10 | | alloced object | kmalloc cubes | 11 | -------------------+-----------------+------------------+------------------ 12 | buddy algorithm | 4KB page | | mm/buddy.c 13 | | | | mm/page.c 14 | -------------------+-----------------+------------------+------------------ 15 | boot-time physical | any size | | mm/boot_memory.c 16 | memory allocator | physical memory | | 17 | -------------------+-----------------+------------------+------------------ 18 | paing mechanism | 2-level, 4K page| | mm/paging.c 19 | -------------------+-----------------+------------------+------------------ 20 | 21 | 2. Memory Map 22 | 23 | * Userspace Memory Map 24 | ---------------------- 0xffff ffff 25 | - [kernel space] 26 | ---------------------- 0xc000 0000 27 | - 4KB hole 28 | ---------------------- 0xbfff f000 29 | - 4KB user stack 30 | ---------------------- 0xbfff e000 31 | - [other parts] 32 | ---------------------- 0x0000 0000 33 | 34 | 35 | * Kernel Address Space Buddy Algorithm 36 | ---------------------- 0xffff ffff ---*---> --------------- 37 | - HIGH MEMORY 38 | ---------------------- 0xe000 0000 ---*---> --------------- 39 | - 40 | ---------------------- 0xc200 0000 41 | - [not used spaces] 42 | ---------------------- ----------- 43 | - page_table[] 44 | - 4KB kernel stack alloced by NORMAL MEMORY 45 | - 4MB page table bootmem 46 | - 4KB page directory 47 | ---------------------- ----------- 48 | - [4KB alignment] (_end) 49 | - kernel.elf in memory 50 | ---------------------- 0xc100 0000 (_stext) ---------------- 51 | - LOW MEMORY 52 | ---------------------- 0xc000 0000 ---*---> ---------------- 53 | 54 | NOTE: '---*--->' means paging map from virtual address to physical address. 55 | 56 | 57 | * Physical Address 58 | ---------------------- 0x???? ???? 59 | - HIGH MEMORY (???MB) 60 | ---------------------- 0x3000 0000 61 | - NORMAL MEMORY(752MB) 62 | ---------------------- 0x0100 0000 63 | - LOW MEMORY (16MB) 64 | ---------------------- 0x0000 0000 65 | -------------------------------------------------------------------------------- /user/libc/print.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* 6 | * Special format: 7 | * "%*s", number, string : print number-width string 8 | */ 9 | int vsprintf(char *buf, char *fmt, va_list args) 10 | { 11 | char *dst = buf; 12 | unsigned int u; /* value for %u/%x */ 13 | int d; /* value for %d */ 14 | char *s; /* value for %s */ 15 | void *p; /* value for %p */ 16 | int zero; /* completion with 0 */ 17 | int width; /* width field */ 18 | int left; /* left aligned */ 19 | int len; /* parsed string length */ 20 | int swidth; /* special format: %*s */ 21 | 22 | while (*fmt) { 23 | if (*fmt != '%') { 24 | *dst++ = *fmt++; 25 | continue; 26 | } 27 | fmt++; /* skip '%' */ 28 | zero = 0; 29 | width = 0; 30 | swidth = 0; 31 | left = 0; 32 | /* handle alignment direction */ 33 | while (*fmt == '+' || *fmt == '-') { 34 | left = (*fmt == '-'); 35 | fmt++; 36 | } 37 | /* handle width */ 38 | while (*fmt == '0') { /* 0 completion */ 39 | zero = 1; 40 | fmt++; 41 | } 42 | if (*fmt >= '1' && *fmt <= '9') 43 | width = strtoi(fmt, &fmt, 10); 44 | /* handle undefinite width of string */ 45 | if (*fmt == '*') { 46 | swidth = va_arg(args, int); 47 | width = 0; /* zero standard width */ 48 | fmt++; 49 | } 50 | /* handle format char */ 51 | switch (*fmt) { 52 | case '%': 53 | *dst = '%'; 54 | len = 1; 55 | break; 56 | case 'c': 57 | *dst = va_arg(args, char); 58 | len = 1; 59 | break; 60 | case 'd': 61 | d = va_arg(args, int); 62 | len = itostr(d, dst, 10); 63 | break; 64 | case 'u': 65 | u = va_arg(args, unsigned int); 66 | len = utostr(u, dst, 10); 67 | break; 68 | case 'x': 69 | u = va_arg(args, unsigned int); 70 | len = utostr(u, dst, 16); 71 | break; 72 | case 'p': 73 | p = va_arg(args, void *); 74 | *dst++ = '0'; 75 | *dst++ = 'x'; 76 | len = utostr((unsigned int)p, dst, 16); 77 | break; 78 | case 's': 79 | s = va_arg(args, char *); 80 | if (swidth > 0) 81 | len = strnncpy(dst, s, swidth); 82 | else 83 | len = strcpy(dst, s); 84 | break; 85 | } 86 | if (width > len) { 87 | if (left) { 88 | memset(dst + len, ' ', width - len); 89 | } else { 90 | memmove(dst + width - len, dst, len); 91 | memset(dst, zero ? '0' : ' ', width - len); 92 | } 93 | len = width; 94 | } 95 | fmt++; 96 | dst += len; 97 | } 98 | *dst = '\0'; 99 | return (dst - buf); 100 | } 101 | 102 | static char ustrbuf[0x1000]; 103 | 104 | int printf(char *format, ...) 105 | { 106 | va_list args; 107 | int i; 108 | va_start(args, format); 109 | i = vsprintf(ustrbuf, format, args); 110 | va_end(args); 111 | return usys_puts(ustrbuf); 112 | } 113 | 114 | int gets(char *buf, int size) 115 | { 116 | return usys_gets(buf, size); 117 | } 118 | 119 | -------------------------------------------------------------------------------- /include/keyboard.h: -------------------------------------------------------------------------------- 1 | #ifndef __KEYBOARD_H 2 | #define __KEYBOARD_H 3 | 4 | struct key_desc { 5 | unsigned int esc:1, 6 | capslock:1, 7 | shift:1, 8 | ctrl:1, 9 | alt:1, 10 | start:1, 11 | pause:1; 12 | }; 13 | 14 | #define KEY_BUF_SIZE 512 15 | 16 | /* This key map is from bochs us-keymap */ 17 | #define KEY_NONE 0x00 18 | #define KEY_PREFIX 0x01 19 | #define KEY_ASCII 0x02 20 | #define KEY_SPECIAL 0x04 21 | 22 | #define KEY_RELEASE_BIT 0x80 23 | #define KEY_E0 0xe0 24 | 25 | /* pause code: e1 1d 45 e1 4d c5 */ 26 | #define KEY_E1 0xe1 27 | 28 | #define KEY_ESC 0x1 29 | #define KEY_1 0x2 30 | #define KEY_2 0x3 31 | #define KEY_3 0x4 32 | #define KEY_4 0x5 33 | #define KEY_5 0x6 34 | #define KEY_6 0x7 35 | #define KEY_7 0x8 36 | #define KEY_8 0x9 37 | #define KEY_9 0xa 38 | #define KEY_0 0xb 39 | #define KEY_MINUS 0xc 40 | #define KEY_EUQAL 0xd 41 | #define KEY_BKSP 0xe 42 | #define KEY_TAB 0xf 43 | #define KEY_Q 0x10 44 | #define KEY_W 0x11 45 | #define KEY_E 0x12 46 | #define KEY_R 0x13 47 | #define KEY_T 0x14 48 | #define KEY_Y 0x15 49 | #define KEY_U 0x16 50 | #define KEY_I 0x17 51 | #define KEY_O 0x18 52 | #define KEY_P 0x19 53 | //#define KEY_[ 0x1a 54 | //#define KEY_] 0x1b 55 | #define KEY_ENTER 0x1c 56 | #define KEY_CTRL 0x1d 57 | #define KEY_A 0x1e 58 | #define KEY_S 0x1f 59 | #define KEY_D 0x20 60 | #define KEY_F 0x21 61 | #define KEY_G 0x22 62 | #define KEY_H 0x23 63 | #define KEY_J 0x24 64 | #define KEY_K 0x25 65 | #define KEY_L 0x26 66 | #define KEY_SEMI 0x27 67 | //#define KEY_' 0x28 68 | //#define KEY_` 0x29 69 | #define KEY_LSHIFT 0x2A 70 | #define KEY_BACKSLASH 0x2B /* \ */ 71 | #define KEY_Z 0x2C 72 | #define KEY_X 0x2D 73 | #define KEY_C 0x2E 74 | #define KEY_V 0x2F 75 | #define KEY_B 0x30 76 | #define KEY_N 0x31 77 | #define KEY_M 0x32 78 | //#define KEY_< 0x33 79 | //#define KEY_> 0x34 80 | #define KEY_SLASH 0x35 /* / ? */ 81 | #define KEY_RSHIFT 0x36 82 | #define KEY_37 83 | #define KEY_ALT 0x38 84 | #define KEY_SPACE 0x39 85 | #define KEY_CAPSLOCK 0x3a 86 | #define KEY_F1 0x3b 87 | #define KEY_F2 0x3c 88 | #define KEY_F3 0x3d 89 | #define KEY_F4 0x3e 90 | #define KEY_F5 0x3f 91 | #define KEY_F6 0x40 92 | #define KEY_F7 0x41 93 | #define KEY_F8 0x42 94 | #define KEY_F9 0x43 95 | #define KEY_F10 0x44 96 | #define KEY_PAUSE 0x45 97 | #define KEY_SCRLK 0x46 98 | #define KEY_HOME 0x47 99 | #define KEY_UP 0x48 100 | #define KEY_PGUP 0x49 101 | #define KEY_4A 102 | #define KEY_LEFT 0x4b 103 | #define KEY_4C 104 | #define KEY_RIGHT 0x4d 105 | #define KEY_4E 106 | #define KEY_END 0x4f 107 | #define KEY_DOWN 0x50 108 | #define KEY_PGDN 0x51 109 | #define KEY_INSERT 0x52 110 | #define KEY_DELETE 0x53 111 | #define KEY_54 112 | #define KEY_55 113 | #define KEY_56 114 | #define KEY_F11 0x57 115 | #define KEY_F12 0x58 116 | #define KEY_59 117 | #define KEY_5A 118 | #define KEY_START 0x5b 119 | #define KEY_5C 120 | #define KEY_BOOK 0x5d 121 | 122 | #endif /* keyboard.h */ 123 | -------------------------------------------------------------------------------- /include/paging.h: -------------------------------------------------------------------------------- 1 | #ifndef __PAGING_H 2 | #define __PAGING_H 3 | 4 | typedef unsigned int pte_t; 5 | typedef unsigned int pde_t; 6 | 7 | #define PTE_PADDR(pte) (((unsigned int)(pte)) & 0xfffff000) 8 | #define PDE_PADDR(pde) PTE_PADDR(pde) 9 | #define PTE(pa, flags) (PTE_PADDR(pa) | (flags)) 10 | #define PDE(pa, flags) PTE(pa, flags) 11 | #define PAGE_PDES 1024 12 | #define PAGE_PTES PAGE_PDES 13 | #define PGD_SHIFT 22 14 | #define PTE_SHIFT 12 15 | #define VA_NPDE(va) (((unsigned int)(va)) >> 22) 16 | #define VA_NPTE(va) ((((unsigned int)(va)) >> 12) & 0x3ff) 17 | #define PDE_FLAGS(pde) ((pde) & 0xfff) 18 | 19 | /* 20 | * Page is writable in these situations(intel manual volume 3A 4-6): 21 | * 1. CR0.WP = 0 22 | * 2. CR0.WP = 1(write protect) 23 | * 1) CPL < 3, PTE_W = 1 24 | * 2) CPL = 3, PTE_W = 1, PTE_U = 1 25 | */ 26 | /* PDE/PTE flags(intel manual volume 3A 4-11) */ 27 | #define PDE_P 0x001 /* present */ 28 | #define PDE_W 0x002 /* writable */ 29 | #define PDE_U 0x004 /* if 0, usermode cannot access the page */ 30 | #define PDE_PWT 0x008 /* page-level write-through */ 31 | #define PDE_PCD 0x010 /* page-level cache disable */ 32 | #define PDE_A 0x020 /* accessed */ 33 | #define PDE_BIT6 0x040 /* bit6 is ignored */ 34 | #define PDE_PS 0x080 /* if CR4.PSE = 1, must be 0*/ 35 | #define PDE_DEFAULT (PDE_P | PDE_W | PDE_U) /* give all priority to pde */ 36 | 37 | #define PTE_P 0x001 38 | #define PTE_W 0x002 39 | #define PTE_U 0x004 /* user readable */ 40 | #define PTE_PWT 0x008 41 | #define PTE_PCD 0x010 42 | #define PTE_A 0x020 /* access */ 43 | #define PTE_D 0x040 /* dirty */ 44 | #define PTE_PAT 0x080 /* PAT supported */ 45 | #define PTE_G 0x100 /* global */ 46 | #define PTE_COW 0x200 /* copy-on-write flag */ 47 | #define PTE_R1 0x400 48 | #define PTE_R2 0x800 49 | #define PTE_SOFT 0xe00 /* These bits are used by software, not hardware. */ 50 | 51 | #define pgpte(p) *(pte_t *)(p)->pg_private 52 | 53 | /* 54 | * Page-Fault Error code: 55 | * P 0 The fault was caused by a non-present page. 56 | * 1 The fault was caused by a page-level protection violation. 57 | * W/R 0 The access causing the fault was a read. 58 | * 1 The access causing the fault was a write. 59 | * U/S 0 The access causing the fault originated when the processor 60 | * was executing in supervisor mode. 61 | * 1 The access causing the fault originated when the processor 62 | * was executing in user mode. 63 | * RSVD 0 The fault was not caused by reserved bit violation. 64 | * 1 The fault was caused by reserved bits set to 1 in a page directory. 65 | * I/D 0 The fault was not caused by an instruction fetch. 66 | * 1 The fault was caused by an instruction fetch. 67 | */ 68 | #define PF_ERROR_P 0x01 69 | #define PF_ERROR_RW 0x02 70 | #define PF_ERROR_US 0x04 71 | #define PF_ERROR_RSVD 0x08 72 | #define PF_ERROR_ID 0x10 73 | #define PF_ERROR_COW (PF_ERROR_P | PF_ERROR_RW) 74 | 75 | extern struct page *map_page(pde_t *pgdir, unsigned int va, unsigned int perm); 76 | extern void pmap_page(pde_t *pgdir, struct page *, unsigned int va, unsigned int perm); 77 | 78 | #endif /* paging.h */ 79 | -------------------------------------------------------------------------------- /kernel/exit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void free_page_table(pde_t *pde) 8 | { 9 | pte_t *pte = (pte_t *)VADDR(PDE_PADDR(*pde)); 10 | struct page *page; 11 | int i; 12 | /* free all physical pages in this page table */ 13 | for (i = 0; i < PAGE_PTES; i++, pte++) { 14 | if (!(*pte & PTE_P)) 15 | continue; 16 | page = ADDR2PG(PTE_PADDR(*pte)); /* physical page */ 17 | if (*pte & PTE_COW) { 18 | /* Cowshare may equal 0 with pte flags: COW ~W. */ 19 | if (page->pg_cowshare > 0) 20 | page->pg_cowshare--; 21 | } 22 | free_page(page); 23 | } 24 | /* free page table */ 25 | put_free_page((void *)VADDR(PDE_PADDR(*pde))); 26 | /* clear page dir entry */ 27 | *pde = 0; 28 | } 29 | 30 | void exit_task_userspace(struct task *task) 31 | { 32 | pde_t *pgdir = task->us.pgdir; 33 | int i; 34 | /* free user address space */ 35 | for (i = 0; i < KBASE_PDE; i++) { 36 | if (pgdir[i] & PDE_P) 37 | free_page_table(&pgdir[i]); 38 | } 39 | } 40 | 41 | void exit_task_fs(struct task *task) 42 | { 43 | inode_close(task->fs.root_dir); 44 | task->fs.root_dir = NULL; 45 | inode_close(task->fs.current_dir); 46 | task->fs.current_dir = NULL; 47 | ft_close(&task->fs.ft); 48 | } 49 | 50 | /* destroy task resources and yield CPU */ 51 | void task_exit(struct task *task) 52 | { 53 | /* Unrunable */ 54 | task->state = TASK_DYING; 55 | exit_task_fs(task); 56 | exit_task_userspace(task); 57 | /* wake up my parent */ 58 | if (task->parent->state == TASK_WAITCHILD) 59 | task->parent->state = TASK_RUNNABLE; 60 | /* 61 | * Why cannot we free total resources of task? 62 | * (Why do we need parent to free task?) 63 | * The current kernel stack is resouce of exiting task! 64 | */ 65 | } 66 | 67 | void sys_exit(int status) 68 | { 69 | ctask->retval = status; 70 | task_exit(ctask); 71 | /* No return */ 72 | schedule(); 73 | if (ctask) 74 | printk("%d ", ctask->pid); 75 | panic("task exiting fails: %d"); 76 | } 77 | 78 | void task_wait_exit(struct task *parent, struct task *task) 79 | { 80 | struct task *child; 81 | list_del(&task->sibling); 82 | /* let @parent to adopt childs of @task */ 83 | if (!list_empty(&task->childs)) { 84 | list_for_each_entry(child, &task->childs, sibling) 85 | child->parent = parent; 86 | list_merge_tail(&parent->childs, &task->childs); 87 | } 88 | put_free_page(task->us.pgdir); 89 | free_task(task); 90 | } 91 | 92 | int task_wait(struct task *parent, int *status) 93 | { 94 | struct task *task; 95 | int cpid = -1; 96 | 97 | if (list_empty(&parent->childs)) 98 | return -1; 99 | 100 | while (1) { 101 | list_for_each_entry(task, &parent->childs, sibling) { 102 | if (task->state == TASK_DYING) { 103 | cpid = task->pid; 104 | goto found; 105 | } 106 | } 107 | /* wait for child exiting */ 108 | ctask->state = TASK_WAITCHILD; 109 | schedule(); 110 | } 111 | found: 112 | if (status) 113 | *status = task->retval; 114 | task_wait_exit(parent, task); 115 | return cpid; 116 | } 117 | 118 | int sys_wait(int *status) 119 | { 120 | return task_wait(ctask, status); 121 | } 122 | -------------------------------------------------------------------------------- /user/libc/syscall.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | u32 usyscall(int num, u32 a1, u32 a2, u32 a3, u32 a4, u32 a5) 5 | { 6 | u32 ret; 7 | asm volatile ( 8 | "int %1;" 9 | : "=a" (ret) 10 | : "i" (INTNO_SYSCALL), 11 | "a" (num), 12 | "b"(a1), 13 | "c"(a2), 14 | "d"(a3), 15 | "D"(a4), 16 | "S"(a5) 17 | : "cc", "memory"); 18 | /* Returning from SYS_fork, it will trigger the page fault here! */ 19 | return ret; 20 | } 21 | 22 | int usys_puts(char *str) 23 | { 24 | return usyscall(SYS_puts, (u32)str, 0, 0, 0, 0); 25 | } 26 | 27 | int usys_gets(char *str, int size) 28 | { 29 | return usyscall(SYS_gets, (u32)str, (u32)size, 0, 0, 0); 30 | } 31 | 32 | int usys_open(char *path, unsigned int flags) 33 | { 34 | return usyscall(SYS_open, (u32)path, (u32)flags, 0, 0, 0); 35 | } 36 | 37 | int usys_close(int fd) 38 | { 39 | return usyscall(SYS_close, (u32)fd, 0, 0, 0, 0); 40 | } 41 | 42 | int usys_fsync(int fd) 43 | { 44 | return usyscall(SYS_fsync, (u32)fd, 0, 0, 0, 0); 45 | } 46 | 47 | int usys_fstat(int fd, struct file_stat *stat) 48 | { 49 | return usyscall(SYS_fstat, (u32)fd, (u32)stat, 0, 0, 0); 50 | } 51 | 52 | int usys_read(int fd, char *buf, size_t size) 53 | { 54 | return usyscall(SYS_read, (u32)fd, (u32)buf, (u32)size, 0, 0); 55 | } 56 | 57 | int usys_write(int fd, char *buf, size_t size) 58 | { 59 | return usyscall(SYS_write, (u32)fd, (u32)buf, (u32)size, 0, 0); 60 | } 61 | 62 | off_t usys_lseek(int fd, off_t offset, unsigned int set) 63 | { 64 | return usyscall(SYS_lseek, (u32)fd, (u32)offset, (u32)set, 0, 0); 65 | } 66 | 67 | int usys_fork(void) 68 | { 69 | return usyscall(SYS_fork, 0, 0, 0, 0, 0); 70 | } 71 | 72 | void usys_yield(void) 73 | { 74 | usyscall(SYS_yield, 0, 0, 0, 0, 0); 75 | } 76 | 77 | int usys_getpid(void) 78 | { 79 | return usyscall(SYS_getpid, 0, 0, 0, 0, 0); 80 | } 81 | 82 | void usys_exit(int status) 83 | { 84 | usyscall(SYS_exit, (u32)status, 0, 0, 0, 0); 85 | } 86 | 87 | int usys_wait(int *status) 88 | { 89 | return usyscall(SYS_wait, (u32)status, 0, 0, 0, 0); 90 | } 91 | 92 | int usys_execute(char *path, int argc, char **argv) 93 | { 94 | return usyscall(SYS_execute, (u32)path, (u32)argc, (u32)argv, 0, 0); 95 | } 96 | 97 | int usys_fchdir(int fd) 98 | { 99 | return usyscall(SYS_fchdir, (u32)fd, 0, 0, 0, 0); 100 | } 101 | 102 | int usys_fgetdir(int fd, int s, int n, struct dir_stat *ds) 103 | { 104 | return usyscall(SYS_fgetdir, (u32)fd, (u32)s, (u32)n, (u32)ds, 0); 105 | } 106 | 107 | int usys_mkdir(char *path, unsigned int mode) 108 | { 109 | return usyscall(SYS_mkdir, (u32)path, (u32)mode, 0, 0, 0); 110 | } 111 | 112 | void usys_sync(void) 113 | { 114 | usyscall(SYS_sync, 0, 0, 0, 0, 0); 115 | } 116 | 117 | int usys_rmdir(char *path) 118 | { 119 | return usyscall(SYS_rmdir, (u32)path, 0, 0, 0, 0); 120 | } 121 | 122 | int usys_rm(char *path) 123 | { 124 | return usyscall(SYS_rm, (u32)path, 0, 0, 0, 0); 125 | } 126 | 127 | int usys_truncate(int fd) 128 | { 129 | return usyscall(SYS_truncate, (u32)fd, 0, 0, 0, 0); 130 | } 131 | 132 | int usys_getcwd(char *buf, size_t size) 133 | { 134 | return usyscall(SYS_getcwd, (u32)buf, (u32)size, 0, 0, 0); 135 | } 136 | -------------------------------------------------------------------------------- /include/int.h: -------------------------------------------------------------------------------- 1 | #ifndef __INT_H 2 | #define __INT_H 3 | 4 | #define NR_IRQS 16 5 | #define INTNO_DE 0 6 | /* Vector 1 is reserved */ 7 | #define INTNO_NMI 2 8 | #define INTNO_BP 3 9 | #define INTNO_OF 4 10 | #define INTNO_BR 5 11 | #define INTNO_UD 6 12 | #define INTNO_NM 7 13 | #define INTNO_DF 8 14 | /* Vector 9 is reserved */ 15 | #define INTNO_TS 10 16 | #define INTNO_NP 11 17 | #define INTNO_SS 12 18 | #define INTNO_GP 13 19 | #define INTNO_PF 14 20 | /* Vector 15 is reserved */ 21 | #define INTNO_MF 16 22 | #define INTNO_AC 17 23 | #define INTNO_MC 18 24 | #define INTNO_XM 19 25 | /* Vector 20-31 are reserved */ 26 | #define INTNO_IRQ0 32 27 | #define INTNO_IRQ1 33 28 | #define INTNO_IRQ2 34 29 | #define INTNO_IRQ3 35 30 | #define INTNO_IRQ4 36 31 | #define INTNO_IRQ5 37 32 | #define INTNO_IRQ6 38 33 | #define INTNO_IRQ7 39 34 | #define INTNO_IRQ8 40 35 | #define INTNO_IRQ9 41 36 | #define INTNO_IRQ10 42 37 | #define INTNO_IRQ11 43 38 | #define INTNO_IRQ12 44 39 | #define INTNO_IRQ13 45 40 | #define INTNO_IRQ14 46 41 | #define INTNO_IRQ15 47 42 | #define INTNO_SYSCALL 48 43 | #define INTNO_MAX INTNO_SYSCALL 44 | #define IDT_SIZE 256 45 | 46 | #define IRQ_TIMER 0 /* Programmable Interrupt Timer Interrupt */ 47 | #define IRQ_KEYBOARD 1 /* Keyboard Interrupt */ 48 | #define IRQ_CASCADE 2 /* Cascade (used internally by the two PICs. never raised) */ 49 | #define IRQ_COM2 3 /* COM2 (if enabled) */ 50 | #define IRQ_COM1 4 /* COM1 (if enabled) */ 51 | #define IRQ_FLOPPY 6 /* Floppy Disk */ 52 | #define IRQ_SPURIOUS 7 /* Unreliable "spurious" interrupt (usually) */ 53 | #define IRQ_CMOS 8 /* CMOS real-time clock (if enabled) */ 54 | #define IRQ_PRI_DISK 14 /* Primary ATA Hard Disk */ 55 | #define IRQ_SEC_DISK 15 /* Secondary ATA Hard Disk */ 56 | 57 | #ifndef __ASM__ 58 | #include 59 | 60 | struct regs { 61 | u32 ds:16, ds_pad:16; 62 | u32 es:16, es_pad:16; 63 | u32 fs:16, fs_pad:16; 64 | u32 gs:16, gs_pad:16; 65 | u32 ebp; 66 | u32 esi; 67 | u32 edi; 68 | u32 edx; 69 | u32 ecx; 70 | u32 ebx; 71 | u32 eax; 72 | u32 error; /* error code */ 73 | u32 eip; 74 | u32 cs:16, cs_pad:16; 75 | u32 eflags; 76 | u32 esp; 77 | u32 ss:16, ss_pad:16; 78 | }; 79 | 80 | extern void de_entry(void); 81 | extern void nmi_entry(void); 82 | extern void bp_entry(void); 83 | extern void of_entry(void); 84 | extern void br_entry(void); 85 | extern void ud_entry(void); 86 | extern void nm_entry(void); 87 | extern void df_entry(void); 88 | extern void ts_entry(void); 89 | extern void np_entry(void); 90 | extern void ss_entry(void); 91 | extern void gp_entry(void); 92 | extern void pf_entry(void); 93 | extern void mf_entry(void); 94 | extern void ac_entry(void); 95 | extern void mc_entry(void); 96 | extern void xm_entry(void); 97 | extern void irq0_entry(void); 98 | extern void irq1_entry(void); 99 | extern void irq2_entry(void); 100 | extern void irq3_entry(void); 101 | extern void irq4_entry(void); 102 | extern void irq5_entry(void); 103 | extern void irq6_entry(void); 104 | extern void irq7_entry(void); 105 | extern void irq8_entry(void); 106 | extern void irq9_entry(void); 107 | extern void irq10_entry(void); 108 | extern void irq11_entry(void); 109 | extern void irq12_entry(void); 110 | extern void irq13_entry(void); 111 | extern void irq14_entry(void); 112 | extern void irq15_entry(void); 113 | extern void syscall_entry(void); 114 | 115 | #endif /* !__ASM__ */ 116 | 117 | #endif /* int.h */ 118 | -------------------------------------------------------------------------------- /kernel/task.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static struct pidset pidmap = { 11 | .bitmap = { 0, }, 12 | .freepids = PIDS, 13 | }; 14 | 15 | static int alloc_pid(void) 16 | { 17 | int pid; 18 | if (pidmap.freepids <= 0) 19 | return -1; 20 | pid = searchzerobit(pidmap.bitmap ,PIDS, 1); 21 | if (pid < 0) 22 | panic("pid bitmap corrupts"); 23 | pidmap.freepids--; 24 | return pid; 25 | } 26 | 27 | static void free_pid(int pid) 28 | { 29 | if (pid >= PIDS) { 30 | printk("try to free unknown pid %d\n", pid); 31 | return; 32 | } 33 | if (clearbit(pidmap.bitmap, pid)) 34 | pidmap.freepids++; 35 | else 36 | printk("try to free free pid\n"); 37 | } 38 | 39 | struct task *ctask; /* current task */ 40 | struct task init_task; 41 | static struct slab *task_slab; 42 | LIST_HEAD(task_list); /* all tasks */ 43 | 44 | /* 45 | * We set tss::limit to 107(the least tss structure), 46 | * excluding I/O Permission Bit Map and set tss::iomapbase 47 | * to zero, in which case the I/O Permission Bit Map is 48 | * not used duiring I/O permissions. 49 | * This makes it easy for us to handle I/O permissions, 50 | * just considering IOPL in Eflags! 51 | * ( For more information, see Section 13.5, "PROTECTED-MODE I/O", 52 | * in the Intel Manual, Volume 1: Basic Architecture ) 53 | */ 54 | struct tss common_tss = { 55 | .prev_tss = 0, /* GDT 0 is reserved! */ 56 | .ss0 = KERN_DATA_SEG, 57 | .ldt = LDT_SEG, 58 | .io_bitmap_addr = 0x8000, 59 | }; 60 | 61 | struct ldt common_ldt; /* Not used */ 62 | 63 | void free_task(struct task *task) 64 | { 65 | list_del(&task->list); 66 | put_free_page(task->kstacktop - PGSIZE); 67 | free_pid(task->pid); 68 | slab_free_object(task_slab, task); 69 | } 70 | 71 | struct task *alloc_task(void) 72 | { 73 | struct task *task; 74 | void *stack; 75 | 76 | /* alloc task */ 77 | task = slab_alloc_object(task_slab); 78 | if (!task) 79 | goto err; 80 | memset(task, 0x0, sizeof(struct task)); 81 | 82 | /* alloc pid */ 83 | task->pid = alloc_pid(); 84 | if (task->pid < 0) 85 | goto err_free_task; 86 | 87 | /* alloc kernel stack */ 88 | stack = get_free_page(); 89 | if (!stack) 90 | goto err_free_pid; 91 | task->kstacktop = stack + PGSIZE; 92 | 93 | /* add to task list */ 94 | list_add(&task->list, &task_list); 95 | list_init(&task->sibling); 96 | list_init(&task->childs); 97 | task->state = TASK_SLEEP; 98 | return task; 99 | 100 | err_free_pid: 101 | free_pid(task->pid); 102 | err_free_task: 103 | slab_free_object(task_slab, task); 104 | err: 105 | return NULL; 106 | } 107 | 108 | extern void *kern_stack_top; 109 | extern pde_t *kern_page_dir; 110 | void task_init(void) 111 | { 112 | /* init task structure allocator */ 113 | task_slab = alloc_slab(sizeof(struct task)); 114 | if (!task_slab) 115 | panic("No memory for task slab"); 116 | /* init first task */ 117 | init_task.kstacktop = kern_stack_top; 118 | init_task.pid = alloc_pid(); 119 | init_task.us.pgdir = kern_page_dir; 120 | init_task.state = TASK_RUNNABLE; 121 | if (init_task.pid != 0) 122 | panic("init task get error pid: %d", init_task.pid); 123 | ctask = &init_task; 124 | /* init tss */ 125 | common_tss.esp0 = (unsigned int)kern_stack_top; 126 | /* init other segments in gdt */ 127 | set_usercode_seg(0, KERNEL_BASE - 1); 128 | set_userdata_seg(0, KERNEL_BASE - 1); 129 | set_tss_desc((unsigned int)&common_tss); 130 | set_ldt_desc((unsigned int)&common_ldt); 131 | lldt(LDT_SEG); 132 | ltr(TSS_SEG); 133 | } 134 | -------------------------------------------------------------------------------- /kernel/fork.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | struct task *clone_task(struct task *parent) 14 | { 15 | struct task *child = alloc_task(); 16 | if (!child) 17 | return NULL; 18 | list_add(&child->sibling, &parent->childs); 19 | child->parent = parent; 20 | return child; 21 | } 22 | 23 | void clone_page_table(pde_t *p, pde_t *c) 24 | { 25 | pte_t *ppte = (pte_t *)VADDR(PDE_PADDR(*p)); 26 | struct page *page; 27 | void *pp; 28 | int i; 29 | /* Read only? */ 30 | if (!(*p & PDE_W)) 31 | panic("Read only page table"); 32 | /* mark copy-on-write flag */ 33 | for (i = 0; i < PAGE_PTES; i++, ppte++) { 34 | if (!(*ppte & PTE_P)) 35 | continue; 36 | page = ADDR2PG(PTE_PADDR(*ppte)); 37 | hold_page(page); 38 | if (*ppte & (PTE_W|PTE_COW)) { 39 | if (!page->pg_cowshare) { 40 | *ppte &= ~PTE_W; 41 | *ppte |= PTE_COW; 42 | } 43 | if (*ppte & PTE_W) 44 | panic("Error for write flag"); 45 | page->pg_cowshare++; 46 | } 47 | } 48 | /* copy page table */ 49 | if (!(pp = get_free_page_pa())) 50 | panic("Cannot get new page for cloned page table"); 51 | memcpy((void *)VADDR(pp), (void *)VADDR(PTE_PADDR(*p)), PGSIZE); 52 | /* copy page dir entry */ 53 | *c = PTE(pp, PDE_FLAGS(*p)); 54 | } 55 | 56 | extern pde_t *kern_page_dir; 57 | void clone_task_userspace(struct task *parent, struct task *child) 58 | { 59 | pde_t *ppgdir, *cpgdir; 60 | int i; 61 | /* alloc new page dir */ 62 | cpgdir = get_free_page(); 63 | if (!cpgdir) 64 | panic("Cannot get child page dir"); 65 | memset(cpgdir, 0x0, PGSIZE); 66 | child->us.pgdir = cpgdir; 67 | /* share the same kernel address space */ 68 | ppgdir = parent->us.pgdir; 69 | memcpy(&cpgdir[KBASE_PDE], &kern_page_dir[KBASE_PDE], KBASE_PDE_SIZE); 70 | /* clone user space */ 71 | for (i = 0; i < KBASE_PDE; i++) { 72 | if (ppgdir[i] & PDE_P) 73 | clone_page_table(&ppgdir[i], &cpgdir[i]); 74 | else 75 | cpgdir[i] = 0; 76 | } 77 | /* flush tlb */ 78 | flush_tlb(); 79 | } 80 | 81 | void clone_task_fdtable(struct fd_table *p, struct fd_table *c) 82 | { 83 | int i; 84 | for (i = 0; i < FD_SIZE; i++) { 85 | if (!p->files[i]) 86 | continue; 87 | c->files[i] = alloc_file(p->files[i]->f_inode, p->files[i]->f_mode); 88 | if (!c->files[i]) 89 | panic("Cannot alloc file"); 90 | get_inode_ref(p->files[i]->f_inode); 91 | } 92 | } 93 | 94 | void clone_task_fs(struct task *parent, struct task *child) 95 | { 96 | child->fs.current_dir = get_inode_ref(parent->fs.current_dir); 97 | child->fs.root_dir = get_inode_ref(parent->fs.root_dir); 98 | clone_task_fdtable(&parent->fs.ft, &child->fs.ft); 99 | } 100 | 101 | void clone_task_context(struct regs *preg, struct task *child) 102 | { 103 | struct regs *creg = (struct regs *)child->kstacktop - 1; 104 | *creg = *preg; 105 | creg->eax = 0; /* Child returns 0 out of fork(). */ 106 | if (!(creg->eflags & EFLAGS_IF)) 107 | panic("has no IF flag"); 108 | child->con.esp = (unsigned int)creg; 109 | child->con.eip = (unsigned int)fork_child_return; 110 | } 111 | 112 | int fork_task(struct task *parent, struct regs *reg) 113 | { 114 | struct task *child; 115 | child = clone_task(parent); 116 | if (!child) 117 | return -1; 118 | clone_task_fs(parent, child); 119 | clone_task_context(reg, child); 120 | clone_task_userspace(parent, child); 121 | child->state = TASK_RUNNABLE; 122 | return child->pid; 123 | } 124 | 125 | int sys_fork(void) 126 | { 127 | return fork_task(ctask, ctask->reg); 128 | } 129 | -------------------------------------------------------------------------------- /kernel/print.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | * Special format: 9 | * "%*s", number, string : print number-width string 10 | */ 11 | int vsprintf(char *buf, char *fmt, va_list args) 12 | { 13 | char *dst = buf; 14 | unsigned int u; /* value for %u/%x */ 15 | int d; /* value for %d */ 16 | char *s; /* value for %s */ 17 | void *p; /* value for %p */ 18 | int zero; /* completion with 0 */ 19 | int width; /* width field */ 20 | int left; /* left aligned */ 21 | int len; /* parsed string length */ 22 | int swidth; /* special format: %*s */ 23 | 24 | while (*fmt) { 25 | if (*fmt != '%') { 26 | *dst++ = *fmt++; 27 | continue; 28 | } 29 | fmt++; /* skip '%' */ 30 | zero = 0; 31 | width = 0; 32 | swidth = 0; 33 | left = 0; 34 | /* handle alignment direction */ 35 | while (*fmt == '+' || *fmt == '-') { 36 | left = (*fmt == '-'); 37 | fmt++; 38 | } 39 | /* handle width */ 40 | while (*fmt == '0') { /* 0 completion */ 41 | zero = 1; 42 | fmt++; 43 | } 44 | if (*fmt >= '1' && *fmt <= '9') 45 | width = strtoi(fmt, &fmt, 10); 46 | /* handle undefinite width of string */ 47 | if (*fmt == '*') { 48 | swidth = va_arg(args, int); 49 | width = 0; /* zero standard width */ 50 | fmt++; 51 | } 52 | /* handle format char */ 53 | switch (*fmt) { 54 | case '%': 55 | *dst = '%'; 56 | len = 1; 57 | break; 58 | case 'c': 59 | *dst = va_arg(args, char); 60 | len = 1; 61 | break; 62 | case 'd': 63 | d = va_arg(args, int); 64 | len = itostr(d, dst, 10); 65 | break; 66 | case 'u': 67 | u = va_arg(args, unsigned int); 68 | len = utostr(u, dst, 10); 69 | break; 70 | case 'x': 71 | u = va_arg(args, unsigned int); 72 | len = utostr(u, dst, 16); 73 | break; 74 | case 'p': 75 | p = va_arg(args, void *); 76 | *dst++ = '0'; 77 | *dst++ = 'x'; 78 | len = utostr((unsigned int)p, dst, 16); 79 | break; 80 | case 's': 81 | s = va_arg(args, char *); 82 | if (swidth > 0) 83 | len = strnncpy(dst, s, swidth); 84 | else 85 | len = strcpy(dst, s); 86 | break; 87 | } 88 | if (width > len) { 89 | if (left) { 90 | memset(dst + len, ' ', width - len); 91 | } else { 92 | memmove(dst + width - len, dst, len); 93 | memset(dst, zero ? '0' : ' ', width - len); 94 | } 95 | len = width; 96 | } 97 | fmt++; 98 | dst += len; 99 | } 100 | *dst = '\0'; 101 | return (dst - buf); 102 | } 103 | 104 | static char kstrbuf[0x1000]; 105 | 106 | int printk(char *format, ...) 107 | { 108 | va_list args; 109 | int i; 110 | va_start(args, format); 111 | i = vsprintf(kstrbuf, format, args); 112 | va_end(args); 113 | return text_nputs(kstrbuf, i); 114 | } 115 | 116 | #define PANIC_PROMPT "Panic: " 117 | #define PANIC_PROMPT_LEN (sizeof(PANIC_PROMPT) - 1) 118 | void panic(char *format, ...) 119 | { 120 | va_list args; 121 | int i; 122 | strcpy(kstrbuf, PANIC_PROMPT); 123 | va_start(args, format); 124 | i = vsprintf(kstrbuf + PANIC_PROMPT_LEN, format, args); 125 | va_end(args); 126 | text_nputs(kstrbuf, i + PANIC_PROMPT_LEN); 127 | /* Close interrupt */ 128 | cli(); 129 | while (1) 130 | hlt(); 131 | } 132 | 133 | void dump_stack(struct regs *reg) 134 | { 135 | printk("----------------[dump stack]----------------\n"); 136 | /* interrupt happens in user mode */ 137 | if (reg->cs & 0x3) 138 | printk("ss: %04x esp: %08x ", reg->ss, reg->esp); 139 | printk( "cs: %04x eip: %08x eflags: %08x\n" 140 | "ds: %04x es: %04x fs: %04x gs: %04x\n" 141 | "ebp: %08x edi: %08x esi: %08x\n" 142 | "eax: %08x ebx: %08x ecx: %08x edx: %08x\n", 143 | reg->cs, reg->eip, reg->eflags, 144 | reg->ds, reg->es, reg->fs, reg->gs, 145 | reg->ebp, reg->edi, reg->esi, 146 | reg->eax, reg->ebx, reg->ecx, reg->edx); 147 | printk("----------------[ end stack]----------------\n"); 148 | } 149 | -------------------------------------------------------------------------------- /fs/file.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct slab *file_slab; 9 | 10 | static void free_file(struct file *file) 11 | { 12 | slab_free_object(file_slab, file); 13 | } 14 | 15 | void put_file(struct file *file) 16 | { 17 | file->f_refcnt--; 18 | if (file->f_refcnt <= 0) 19 | free_file(file); 20 | } 21 | 22 | struct file *get_file(struct file *file) 23 | { 24 | file->f_refcnt++; 25 | return file; 26 | } 27 | 28 | struct file *alloc_file(struct inode *inode, unsigned int mode) 29 | { 30 | struct file *file = slab_alloc_object(file_slab); 31 | memset(file, 0x0, sizeof(file)); 32 | file->f_inode = inode; 33 | file->f_mode = mode; 34 | file->f_refcnt = 1; 35 | return file; 36 | } 37 | 38 | struct file *file_open(char *path, unsigned int mode) 39 | { 40 | struct file *file; 41 | struct inode *inode; 42 | inode = inode_open(path, mode); 43 | if (!inode) 44 | return NULL; 45 | file = alloc_file(inode, mode); 46 | return file; 47 | } 48 | 49 | void file_close(struct file *file) 50 | { 51 | if (file->f_inode) 52 | inode_close(file->f_inode); 53 | else 54 | printk("close file without inode\n"); 55 | file->f_inode = NULL; 56 | put_file(file); 57 | } 58 | 59 | int file_read(struct file *file, char *buf, size_t size) 60 | { 61 | int r = -1; 62 | get_file(file); 63 | if (file->f_inode) { 64 | r = inode_read(file->f_inode, buf, size, file->f_pos); 65 | if (r > 0) 66 | file->f_pos += r; 67 | } 68 | put_file(file); 69 | return r; 70 | } 71 | 72 | int file_write(struct file *file, char *buf, size_t size) 73 | { 74 | int r = -1; 75 | get_file(file); 76 | if (file->f_inode) { 77 | r = inode_write(file->f_inode, buf, size, file->f_pos); 78 | if (r > 0) 79 | file->f_pos += r; 80 | } 81 | put_file(file); 82 | return r; 83 | } 84 | 85 | off_t file_lseek(struct file *file, off_t offset, int whence) 86 | { 87 | off_t off; 88 | get_file(file); 89 | off = file->f_pos; 90 | switch (whence) { 91 | case SEEK_SET: 92 | off = offset; 93 | break; 94 | case SEEK_END: 95 | off = file->f_inode->i_size; 96 | case SEEK_CUR: 97 | off += offset; 98 | break; 99 | default: 100 | off = -1; 101 | break; 102 | } 103 | if (off >= 0) 104 | file->f_pos = off; 105 | else 106 | off = -1; 107 | put_file(file); 108 | return off; 109 | } 110 | 111 | void file_sync(struct file *file) 112 | { 113 | get_file(file); 114 | if (file->f_inode) 115 | inode_sync(file->f_inode); 116 | put_file(file); 117 | } 118 | 119 | int file_stat(struct file *file, struct file_stat *stat) 120 | { 121 | int r = -1; 122 | get_file(file); 123 | if (file->f_inode) { 124 | inode_stat(file->f_inode, stat); 125 | r = 0; 126 | } 127 | put_file(file); 128 | return r; 129 | } 130 | 131 | int file_chdir(struct file *file) 132 | { 133 | int r = -1; 134 | get_file(file); 135 | if (file->f_inode) { 136 | inode_chdir(file->f_inode); 137 | r = 0; 138 | } 139 | put_file(file); 140 | return r; 141 | } 142 | 143 | int file_getdir(struct file *file, int start, int num, struct dir_stat *ds) 144 | { 145 | int r = -1; 146 | get_file(file); 147 | if (file->f_inode) 148 | r = inode_getdir(file->f_inode, start, num, ds); 149 | put_file(file); 150 | return r; 151 | } 152 | 153 | struct file *file_mkdir(char *path, unsigned int mode) 154 | { 155 | struct file *file; 156 | struct inode *inode; 157 | inode = inode_mkdir(path); 158 | if (!inode) 159 | return NULL; 160 | file = alloc_file(inode, mode); 161 | return file; 162 | } 163 | 164 | int file_rmdir(char *path) 165 | { 166 | return inode_rmdir(path); 167 | } 168 | 169 | int file_rm(char *path) 170 | { 171 | return inode_rm(path); 172 | } 173 | 174 | int file_truncate(struct file *file) 175 | { 176 | int r = -1; 177 | get_file(file); 178 | if (file->f_inode) 179 | r = inode_truncate(file->f_inode); 180 | put_file(file); 181 | return r; 182 | 183 | } 184 | -------------------------------------------------------------------------------- /boot/boot.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | .code16 6 | 7 | _ENTRY(boot_start) 8 | /* close interrupt */ 9 | cli 10 | cld 11 | 12 | /* init registers */ 13 | movw $0x07c0, %ax 14 | movw %ax, %ds 15 | movw %ax, %es 16 | movw %ax, %gs 17 | movw %ax, %fs 18 | movw %ax, %ss 19 | movw $0x00, %sp /* set stack top to 0x7c00 */ 20 | 21 | /* 22 | * Enable A20: although there are other methods, this method 23 | * using keyboard controller can work well in any case. 24 | * We can access physical memory above 1MB. 25 | */ 26 | call wait_A20 27 | movb $0xd1, %al /* command: write */ 28 | outb %al, $0x64 29 | call wait_A20 30 | movb $0xdf, %al /* enable */ 31 | outb %al, $0x60 32 | call wait_A20 33 | 34 | /* load second-part boot loader to memory: [0x7e00, 0x8c00) */ 35 | load_drive: 36 | movw $0x0207, %ax /* ah: 02h al: 07h(sectors) */ 37 | movw $0x0002, %cx /* ch: 00h(track) cl: 02h(sector) */ 38 | movw $0x0080, %dx /* dh: 00h(head) cl: 80h(drive: disk) */ 39 | movw $0x0200, %bx /* es:bx (buffer address pointer) */ 40 | int $0x13 41 | jnc load_done /* Carry bit is set for error. */ 42 | reset_drive: 43 | /* reset drive */ 44 | movb $0x00, %ah 45 | movb $0x80, %dl 46 | int $0x13 47 | jc reset_drive 48 | jmp load_drive 49 | 50 | load_done: 51 | jmp boot_next /* jmp to 0x7e00, not changing CS */ 52 | 53 | wait_A20: 54 | inb $0x64, %al 55 | test $0x2, %al 56 | jnz wait_A20 57 | ret 58 | 59 | .org 508 60 | .word 0x0000 /* for sects of kernel image */ 61 | .word 0xaa55 62 | 63 | _ENTRY(boot_next) 64 | /* 65 | * Detecting memory via E820 method 66 | * If this method fails, we dont try other methods, 67 | * just killing the machine. 68 | * E820 entries is saved in [0x8c00, 0x9800). (128 entries:3KB) 69 | * E820 and other parameter are saved in [0x9800, 0x10000) 70 | */ 71 | xorl %ebp, %ebp /* entry number */ 72 | xorl %ebx, %ebx /* ebx must be 0 to start */ 73 | movl $0x1000, %edi /* e820 list(es:edi 0x07c0:0x1000) */ 74 | loop_e820: 75 | movl $SMAP, %edx /* magical number: "SMAP" */ 76 | movl $0xe820, %eax 77 | movl $E820_ENTRY_SIZE, %ecx 78 | int $0x15 79 | jc end_e820 80 | cmpl $SMAP, %eax 81 | jne fail_e820 /* %eax != SMAP for error */ 82 | jcxz next_e820 /* ignore 0-length entry */ 83 | incl %ebp /* increase entry number */ 84 | addl $E820_ENTRY_SIZE, %edi /* %edi points next entry space */ 85 | next_e820: 86 | test %ebx, %ebx /* if ebx equals 0, list ends */ 87 | je end_e820 88 | movl %ebp, %eax 89 | cmpl $E820_MAX, %eax 90 | je fail_e820 /* entry number >= E820_MAX for error */ 91 | jmp loop_e820 92 | end_e820: 93 | movl %ebp, %eax 94 | cmpl $0x01, %eax /* entry number <= 1 for error */ 95 | jbe fail_e820 96 | movl %ebp, (0x1c00) /* save e820 entry number to 0x9800 */ 97 | jmp next_protect_mode 98 | fail_e820: 99 | jmp fail_e820 /* end of boot trap */ 100 | 101 | /* go to protect mode */ 102 | next_protect_mode: 103 | /* Note: we dont load idt, but interrupt has been disabled! */ 104 | /* load gdt: [ds:boot_gdt_desc]*/ 105 | lgdt boot_gdt_desc 106 | /* turn on protected mode */ 107 | movl %cr0, %eax 108 | orl $CR0_PE, %eax 109 | movl %eax, %cr0 110 | ljmp $KERN_CODE_SEG, $BOOT_PADDR(start_protect_mode) 111 | 112 | start_protect_mode: 113 | .code32 114 | movw $KERN_DATA_SEG, %ax 115 | movw %ax, %ds 116 | movw %ax, %es 117 | movw %ax, %fs 118 | movw %ax, %gs 119 | movw %ax, %ss 120 | movl $0x7c00, %esp /* reset stack top to 0x7c00 */ 121 | 122 | call boot_main 123 | 124 | die: /* Should it be here? */ 125 | jmp die 126 | 127 | .align 4 128 | boot_gdt: 129 | /* none seg */ 130 | GDT_SEG_NONE 131 | /* code seg: base 0, limit 4G, execute/read, */ 132 | GDT_SEG(0x0, 0xffffffff, STA_X|STA_R) 133 | /* data seg: base 0, limit 4G, write */ 134 | GDT_SEG(0x0, 0xffffffff, STA_W) 135 | boot_gdt_desc: 136 | .word 0x17 /* gdt limit: gdt size - 1 */ 137 | .long BOOT_PADDR(boot_gdt) /* gdt address */ 138 | 139 | 140 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | MAKEFLAGS += --no-print-directory 2 | 3 | Q = @ 4 | LD = ld 5 | AS = as 6 | CC = gcc 7 | DD = dd 8 | NM = nm 9 | BUILD = tools/build 10 | MKFS = tools/mkfs.minix 11 | CTAGS = ctags 12 | OBJDUMP = objdump 13 | OBJCOPY = objcopy 14 | CFLAGS = -Wall -Werror -fno-builtin -nostdinc -nostdlib -I../include -g -m32 15 | LDFLAGS = -m elf_i386 16 | export Q LD AS CC NM OBJDUMP OBJCOPY CFLAGS LDFLAGS 17 | 18 | KVM = qemu-kvm 19 | KLINK = -T kernel.ld 20 | USER_APPS = user/init user/hello user/sh user/cat user/stat user/ls user/mkdir\ 21 | user/sync user/rmdir user/rm user/cp user/pwd 22 | export USER_APPS 23 | 24 | OBJS = kernel/kernel.o mm/mm.o video/video.o fs/fs.o keyboard/keyboard.o 25 | 26 | all:disk.img user 27 | user:user/init 28 | user/init:user/*.c user/*/*.c user/*/*.S 29 | @make -C user/ all 30 | 31 | disk.img:boot/boot.bin kernel.bin tools/build tools/mkfs.minix 32 | $(Q)$(BUILD) boot/boot.bin kernel.bin 10000 33 | @echo " [BUILD] boot/boot.bin" 34 | $(Q)$(DD) of=$@ if=/dev/zero bs=512 count=10000 2>/dev/null 35 | $(Q)$(DD) of=$@ if=boot/boot.bin conv=notrunc 2>/dev/null 36 | $(Q)$(DD) of=$@ if=kernel.bin conv=notrunc bs=512 seek=8 2>/dev/null 37 | @echo " [DD] $@" 38 | $(Q)$(MKFS) $@ 39 | @echo " [MKFS] $@" 40 | 41 | tools/%:tools/%.c 42 | $(Q)$(CC) $< -o $@ 43 | @echo " [CC] $@" 44 | 45 | kernel.bin:kernel.elf 46 | $(Q)$(OBJCOPY) $< -O binary $@ 47 | @echo " [GEN] $@" 48 | 49 | kernel.elf:$(OBJS) 50 | $(Q)$(LD) $(KLINK) $^ -o $@ 51 | @echo " [LD] $@" 52 | 53 | video/video.o:video/*.c 54 | @make -C video/ 55 | 56 | keyboard/keyboard.o:keyboard/*.c 57 | @make -C keyboard/ 58 | 59 | fs/fs.o:fs/*.c fs/minix/*.c 60 | @make -C fs/ 61 | 62 | mm/mm.o:mm/*.c 63 | @make -C mm/ 64 | 65 | kernel/kernel.o:kernel/*.S kernel/*.c 66 | @make -C kernel/ 67 | 68 | boot/boot.bin:boot/boot.S boot/main.c 69 | @make -C boot/ 70 | 71 | debug:kernel.asm kernel.sym 72 | @make -C boot/ debug 73 | @make -C user/ debug 74 | kernel.asm:kernel.elf 75 | $(Q)$(OBJDUMP) -S $< > $@ 76 | @echo " [DASM] $@" 77 | kernel.sym:kernel.elf 78 | $(Q)$(NM) -n $< > $@ 79 | @echo " [NM] $@" 80 | 81 | # minixdir/dir/[1-100] 82 | MKDIRS = $(shell seq -s ' ' 1 100 | sed 's/\([0-9]\+\)/minixdir\/dir\/\1/g') 83 | RMDIRS = $(shell seq -s ' ' 20 40 | sed 's/\([0-9]\+\)/minixdir\/dir\/\1/g') 84 | # load user environment into bootale disk image 85 | loaduser:disk.img 86 | -mkdir -p minixdir 87 | -sudo losetup /dev/loop0 -o $(shell cat .offset) disk.img 88 | sudo mount -t minix /dev/loop0 minixdir 89 | -sudo cp $(USER_APPS) minixdir/ 90 | -sudo mkdir -p minixdir/dir 91 | -sudo mkdir -p minixdir/dir/dir1 92 | -@sudo mkdir -p $(MKDIRS); echo "Create 100 dirs" 93 | -@sudo rmdir $(RMDIRS); echo "Remove 20 dirs" 94 | -echo "hello wrold" > text1; sudo mv text1 minixdir/ 95 | -echo "RIP Dennis Ritchie" > text2; sudo mv text2 minixdir/dir/ 96 | -sudo umount minixdir 97 | -sudo losetup -d /dev/loop0 98 | -rm -rf minixdir 99 | 100 | kvm:disk.img 101 | $(KVM) -hda disk.img -m 64 102 | bochs:disk.img 103 | bochs -qf tools/bochs.bxrc 104 | # If your bochs installs nogui library, you can run this command. 105 | nbochs:disk.img 106 | bochs -qf tools/bochs.bxrc 'display_library: nogui' 107 | 108 | tag: 109 | $(Q)$(CTAGS) -R * 110 | @echo " [CTAGS]" 111 | 112 | fsck:disk.img 113 | -sudo losetup /dev/loop0 -o $(shell cat .offset) disk.img 114 | -sudo fsck.minix /dev/loop0 115 | -sudo losetup -d /dev/loop0 116 | 117 | 118 | mount:disk.img 119 | mkdir -p minixdir 120 | -sudo losetup /dev/loop0 -o $(shell cat .offset) disk.img 121 | -sudo mount -t minix /dev/loop0 minixdir 122 | 123 | umount: 124 | -sudo umount minixdir 125 | -sudo losetup -d /dev/loop0 126 | rm -rf minixdir 127 | 128 | clean: 129 | @find . -regex ".*\.\(o\|sym\|asm\|elf\|bin\)" -exec rm -f {} ';' 130 | @rm -rf tools/mkfs.minix tools/build tags .offset disk.img 131 | @rm -rf $(USER_APPS) 132 | @echo " [CLEAN]" 133 | 134 | lines: 135 | @echo "code lines:" 136 | @wc -l `find . -name \*.[ch]` | sort -n 137 | 138 | -------------------------------------------------------------------------------- /user/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define iprintf(fmt, args...) printf("/init: " fmt, ##args) 4 | 5 | void test_pit_sched(void) 6 | { 7 | if (fork() == 0) { 8 | if (fork() == 0) { 9 | while (1) { 10 | printf("C"); 11 | yield(); /* test interrupt_level in schedule() */ 12 | } 13 | } else { 14 | while (1) { 15 | printf("X"); 16 | } 17 | } 18 | } else { 19 | while (1) 20 | printf("P"); /* test schedule() in timer interrupt */ 21 | 22 | } 23 | } 24 | 25 | void test_fork(void) 26 | { 27 | int pid; 28 | while (1) { 29 | pid = fork(); 30 | if (pid < 0) { 31 | iprintf("Fork error\n"); 32 | break; 33 | } else if (pid == 0) { 34 | iprintf("I'm child %d\n", getpid()); 35 | break; 36 | } else { 37 | iprintf("Create child %d\n", pid); 38 | } 39 | } 40 | while (1); yield(); 41 | //iprintf("> pid %d <\n", getpid()); 42 | 43 | } 44 | 45 | void test_exit(void) 46 | { 47 | int pid; 48 | int rv; 49 | refork: 50 | pid = fork(); 51 | if (pid < 0) { 52 | iprintf("[%d] Fork error\n", getpid()); 53 | } else if (pid == 0) { 54 | refork_child: 55 | pid = fork(); 56 | if (pid < 0) { 57 | iprintf("[%d] Fork error\n", getpid()); 58 | iprintf("[%d] exit\n", getpid()); 59 | exit(getpid()); 60 | } else if (pid == 0) { 61 | char *as[] = { "/hello", "will exit\n", NULL }; 62 | /* 63 | * This bug is so strange: 64 | * Testing this script, you will get a panic! 65 | * But add "iprintf("EXEC %d\n", pid);" here, 66 | * this bug will disappear! 67 | */ 68 | execute("/hello", 2, as); 69 | while (1) ; 70 | exit(getpid()); 71 | } else { 72 | iprintf("[%d] create %d\n", getpid(), pid); 73 | } 74 | goto refork_child; 75 | } else { 76 | iprintf("[%d] Create child %d and let it run!\n", getpid(), pid); 77 | yield(); 78 | iprintf("[%d] waking up!\n", getpid()); 79 | while ((pid = wait(&rv)) > 0) 80 | iprintf("[p] Child %d exit %d\n", pid, rv); 81 | goto refork; 82 | } 83 | 84 | while (1) ; 85 | 86 | } 87 | 88 | void test_exec(void) 89 | { 90 | char *argvs[] = { "hello", "world", "Haaaa!", NULL }; 91 | int pid; 92 | int r; 93 | refork: 94 | pid = fork(); 95 | if (pid < 0) { 96 | iprintf("fork error\n"); 97 | } else if (pid == 0) { 98 | r = execute("/hello", 3, argvs); 99 | iprintf("error for execute (%d)\n", r); 100 | while (1) ; 101 | } 102 | iprintf("[%d] Create task %d\n", getpid(), pid); 103 | yield(); 104 | pid = wait(&r); 105 | if (pid > 0) 106 | iprintf("[%d] wait child %d return %x\n", getpid(), pid, r); 107 | else 108 | iprintf("[%d] wait error\n"); 109 | goto refork; 110 | } 111 | 112 | void test_open_close(void) 113 | { 114 | int fd; 115 | char buf[4]; 116 | int size, i; 117 | fd = open("/text", 0); 118 | while ((size = read(fd, buf, 4)) > 0) 119 | iprintf("%*s", size, buf); 120 | if (size < 0) { 121 | iprintf("read return %d\n", size); 122 | goto err; 123 | } 124 | iprintf("read ok!\n"); 125 | if (lseek(fd, 0, SEEK_SET) != 0) { 126 | iprintf("lseek error\n"); 127 | goto err; 128 | } 129 | /* (7 + 512 + 1)*1024 */ 130 | i = 832480; 131 | while (i > 0) { 132 | if ((size = write(fd, "123456789\n", 10)) != 10) { 133 | iprintf("write error %d\n", size); 134 | goto err; 135 | } 136 | i -= 10; 137 | } 138 | iprintf("write ok!\n"); 139 | fsync(fd); 140 | iprintf("fsync ok!\n"); 141 | fd = close(fd); 142 | err: 143 | while (1) ; 144 | 145 | } 146 | 147 | void test_gets(void) 148 | { 149 | char buf[64]; 150 | int size; 151 | while ((size = gets(buf, 64)) > 0) 152 | iprintf("[%d]%*s", size, size, buf); 153 | iprintf("ERROR gets return %d\n", size); 154 | while (1) ; 155 | } 156 | 157 | 158 | int main(int argc, char **argv) 159 | { 160 | iprintf("in user mode\n"); 161 | 162 | int pid, rv; 163 | pid = fork(); 164 | if (pid < 0) { 165 | iprintf("Fork error\n"); 166 | } else if (pid == 0) { 167 | char *as[] = { "/sh", NULL }; 168 | execute("/sh", 1, as); 169 | iprintf("execve error\n"); 170 | } else { 171 | pid = wait(&rv); 172 | if (pid > 0) 173 | iprintf("/sh(%d) exit %d\n", pid, rv); 174 | else 175 | iprintf("/sh exit error\n"); 176 | } 177 | 178 | while (1) ; 179 | return 0; 180 | } 181 | -------------------------------------------------------------------------------- /fs/sys.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void ft_close(struct fd_table *ft) 9 | { 10 | int i; 11 | for (i = 0; i < FD_SIZE; i++) { 12 | if (ft->files[i]) 13 | file_close(ft->files[i]); 14 | } 15 | } 16 | 17 | static void fd_save_file(int fd, struct file *file) 18 | { 19 | ctask->fs.ft.files[fd] = file; 20 | } 21 | 22 | static void fd_free(int fd) 23 | { 24 | ctask->fs.ft.files[fd] = NULL; 25 | } 26 | 27 | static int fd_alloc(void) 28 | { 29 | struct fd_table *ft = &ctask->fs.ft; 30 | int fd; 31 | for (fd = 0; fd < FD_SIZE; fd++) 32 | if (!ft->files[fd]) 33 | break; 34 | if (fd < FD_SIZE) 35 | ft->files[fd] = FD_SAVED; 36 | return fd; 37 | } 38 | 39 | struct file *fd_put_file(unsigned int fd) 40 | { 41 | struct file *file = NULL; 42 | if (fd < FD_SIZE) { 43 | file = ctask->fs.ft.files[fd]; 44 | ctask->fs.ft.files[fd] = NULL; 45 | } 46 | return file; 47 | } 48 | 49 | struct file *fd_get_file(unsigned int fd) 50 | { 51 | struct file *file = NULL; 52 | if (fd < FD_SIZE) { 53 | file = ctask->fs.ft.files[fd]; 54 | if (file) 55 | get_file(file); 56 | } 57 | return file; 58 | } 59 | 60 | int sys_read(unsigned int fd, char *buf, size_t size) 61 | { 62 | struct file *file; 63 | int r = -1; 64 | if (size <= 0) 65 | return size; 66 | file = fd_get_file(fd); 67 | if (file) { 68 | r = file_read(file, buf, size); 69 | put_file(file); 70 | } 71 | return r; 72 | } 73 | 74 | int sys_write(unsigned int fd, char *buf, size_t size) 75 | { 76 | struct file *file; 77 | int r = -1; 78 | if (size <= 0) 79 | return size; 80 | file = fd_get_file(fd); 81 | if (file) { 82 | r = file_write(file, buf, size); 83 | put_file(file); 84 | } 85 | return r; 86 | } 87 | 88 | int sys_open(char *name, unsigned int mode) 89 | { 90 | struct file *file; 91 | int fd = fd_alloc(); 92 | if (fd < 0) 93 | goto out; 94 | file = file_open(name, mode); 95 | if (!file) 96 | goto out_free_fd; 97 | fd_save_file(fd, file); 98 | return fd; 99 | out_free_fd: 100 | fd_free(fd); 101 | out: 102 | return -1; 103 | } 104 | 105 | off_t sys_lseek(int fd, off_t offset, int whence) 106 | { 107 | struct file *file = fd_get_file(fd); 108 | if (!file) 109 | return -1; 110 | offset = file_lseek(file, offset, whence); 111 | put_file(file); 112 | return offset; 113 | } 114 | 115 | int sys_fsync(int fd) 116 | { 117 | struct file *file = fd_get_file(fd); 118 | if (!file) 119 | return -1; 120 | file_sync(file); 121 | put_file(file); 122 | return 0; 123 | } 124 | 125 | 126 | int sys_fstat(int fd, struct file_stat *stat) 127 | { 128 | struct file *file = fd_get_file(fd); 129 | int r = -1; 130 | if (!file) 131 | return -1; 132 | r = file_stat(file, stat); 133 | put_file(file); 134 | return r; 135 | } 136 | 137 | int sys_close(int fd) 138 | { 139 | struct file *file = fd_put_file(fd); 140 | if (!file) 141 | return -1; 142 | file_close(file); 143 | return 0; 144 | } 145 | 146 | int sys_fchdir(int fd) 147 | { 148 | struct file *file = fd_get_file(fd); 149 | int r = -1; 150 | if (!file) 151 | return -1; 152 | r = file_chdir(file); 153 | put_file(file); 154 | return r; 155 | } 156 | 157 | /* get dir entry from @fd */ 158 | int sys_fgetdir(int fd, int start, int num, struct dir_stat *ds) 159 | { 160 | struct file *file = fd_get_file(fd); 161 | int r = -1; 162 | if (!file) 163 | return -1; 164 | r = file_getdir(file, start, num, ds); 165 | put_file(file); 166 | return r; 167 | } 168 | 169 | int sys_mkdir(char *path, unsigned int mode) 170 | { 171 | struct file *file; 172 | int fd = fd_alloc(); 173 | if (fd < 0) 174 | goto out; 175 | file = file_mkdir(path, mode); 176 | if (!file) 177 | goto out_free_fd; 178 | fd_save_file(fd, file); 179 | return fd; 180 | out_free_fd: 181 | fd_free(fd); 182 | out: 183 | return -1; 184 | } 185 | 186 | int sys_rmdir(char *path) 187 | { 188 | return file_rmdir(path); 189 | } 190 | 191 | int sys_rm(char *path) 192 | { 193 | return file_rm(path); 194 | } 195 | 196 | int sys_truncate(int fd) 197 | { 198 | struct file *file = fd_get_file(fd); 199 | int r = -1; 200 | if (!file) 201 | return -1; 202 | r = file_truncate(file); 203 | put_file(file); 204 | return r; 205 | } 206 | 207 | int sys_getcwd(char *buf, size_t size) 208 | { 209 | struct inode *inode; 210 | 211 | inode = ctask->fs.current_dir; 212 | if (!inode) 213 | return -1; 214 | 215 | return inode_get_pathname(inode, buf, size); 216 | } 217 | -------------------------------------------------------------------------------- /include/minix_fs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file has definitions for some important minix filesystem 3 | * structures etc. 4 | */ 5 | #ifndef __MINIX_FS_H 6 | #define __MINIX_FS_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | struct block; 13 | 14 | #define MINIX_BLOCK_SHIFT 10 15 | #define MINIX_BLOCK_SIZE (1 << MINIX_BLOCK_SHIFT) 16 | #define MINIX_BLOCK_MASK (MINIX_BLOCK_SIZE - 1) 17 | #define MINIX_BLOCKS(x) ((x) >> MINIX_BLOCK_SHIFT) 18 | #define MINIX_BLOCKS_UP(x) MINIX_BLOCKS((x) + MINIX_BLOCK_MASK) 19 | #define MINIX_BLOCK_OFF(x) ((x) & MINIX_BLOCK_MASK) 20 | 21 | #define MINIX_ZERO_BLOCK ((struct block *)0xffffdead) 22 | #define MINIX_BDATA_BLK(b, blk) (((unsigned short *)(b)->b_data)[blk]) 23 | 24 | #define MINIX_NAME_LEN 14 25 | #define MINIX_ROOT_INO 1 26 | #define MINIX_SUPER_BLK 1 27 | 28 | #define I_MAP_SLOTS 8 29 | #define Z_MAP_SLOTS 8 30 | #define MINIX_SUPER_MAGIC 0x137F 31 | #define MINIX_MAX_SIZE ((7 + 512 + 512 * 512) * MINIX_BLOCK_SIZE) 32 | 33 | #define MINIX_INODE_SIZE (sizeof(struct minix_d_inode)) 34 | #define MINIX_DENTRY_SIZE (sizeof(struct minix_dentry)) 35 | 36 | #define INODES_PER_BLOCK ((MINIX_BLOCK_SIZE) / MINIX_INODE_SIZE) 37 | #define MINIX_DENTRIES_PER_BLOCK ((MINIX_BLOCK_SIZE) / MINIX_DENTRY_SIZE) 38 | #define BITS_PER_BLOCK (8 * MINIX_BLOCK_SIZE) 39 | #define BITS_PER_BLOCK_MASK (BITS_PER_BLOCK - 1) 40 | 41 | /* number of blocks containing inodes */ 42 | #define INODES(sb) DIV_UP((sb)->s_ninodes, INODES_PER_BLOCK) 43 | /* inode-block starting block nr */ 44 | #define INODE_START_BLK(sb) (2 + (sb)->s_imap_blocks + (sb)->s_zmap_blocks) 45 | #define INODE_BLK(sb, ino) (INODE_START_BLK(sb) + (ino) / INODES_PER_BLOCK) 46 | #define INODE_MAP_BLOCKS(sb) DIV_UP((sb)->s_ninodes, BITS_PER_BLOCK) 47 | #define ZONE_MAP_BLOCKS(sb) DIV_UP((sb)->s_nzones - (sb)->s_firstdatazone, BITS_PER_BLOCK) 48 | #define ZONE_MAP_START_BLK(sb) ((sb)->s_imap_blocks + 2) 49 | #define ZONE_MAP_BLK(sb, blk) (ZONE_MAP_START_BLK(sb) + ((((blk) - (sb)->s_firstdatazone + 1)) / BITS_PER_BLOCK)) 50 | #define ZONE_MAP_BLKOFF(sb, blk) (((blk) - (sb)->s_firstdatazone + 1) & BITS_PER_BLOCK_MASK) 51 | #define INODE_MAP_BLK(ino) (2 + (ino) / BITS_PER_BLOCK) 52 | #define BLOCK2INODE(b, i) ((struct minix_d_inode *)(b)->b_data + ((i) - 1) % INODES_PER_BLOCK) 53 | 54 | /* first logic data block nr */ 55 | #define FIRST_ZONE_BLK(sb) \ 56 | (2 + INODES(sb) + (sb)->s_imap_blocks + (sb)->s_zmap_blocks) 57 | 58 | #define minixsuper(s) ((struct minix_d_super_block *)((s)->s_block->b_data)) 59 | #define i2mi(i) ((struct minix_inode *)(i)) 60 | #define i2mdi(i) (i2mi(i)->m_dinode) 61 | #define minix_inode_dirty(i) i2mi(i)->m_iblock->b_dirty = 1 62 | 63 | /* minix inode in device */ 64 | struct minix_d_inode { 65 | unsigned short i_mode; 66 | unsigned short i_uid; 67 | unsigned long i_size; 68 | unsigned long i_time; 69 | unsigned char i_gid; 70 | unsigned char i_nlinks; 71 | unsigned short i_zone[9]; 72 | } __attribute__((packed)); 73 | 74 | struct minix_inode { 75 | struct inode m_inode; 76 | struct minix_d_inode *m_dinode; 77 | struct hlist_node m_hnode; 78 | struct block *m_iblock; /* block containing d_inode */ 79 | } __attribute__((packed)); 80 | 81 | /* super_block in device(disk) */ 82 | struct minix_d_super_block { 83 | unsigned short s_ninodes; 84 | unsigned short s_nzones; /* max disk size is 64MB */ 85 | unsigned short s_imap_blocks; 86 | /* 87 | * zone map stands for logic data block 88 | * *excluding* boot|sb|imap|zmap|inodeblk 89 | */ 90 | unsigned short s_zmap_blocks; 91 | unsigned short s_firstdatazone; 92 | unsigned short s_log_zone_size; 93 | unsigned long s_max_size; 94 | unsigned short s_magic; 95 | } __attribute__((packed)); 96 | 97 | struct minix_dentry { 98 | unsigned short d_ino; 99 | char d_name[MINIX_NAME_LEN]; 100 | } __attribute__((packed)); 101 | 102 | extern struct block *imap_block(struct super_block *, unsigned int); 103 | extern struct inode *minix_get_inode(struct super_block *, unsigned int); 104 | extern struct minix_d_inode *imap_get_inode(struct super_block *, unsigned int, struct block **); 105 | extern struct block *bmap_block(struct inode *, int, int); 106 | extern struct block *minix_get_block(struct super_block *, int); 107 | extern int bmap(struct inode *, int, int); 108 | extern void minix_inode_dirty_block(struct inode *inode, struct block *block); 109 | extern struct minix_d_inode *imap_new_inode(struct super_block *sb, int *rino, struct block **b); 110 | extern struct block *minix_new_block(struct super_block *sb, unsigned short *data); 111 | extern void bmap_put_blocks(struct inode *inode); 112 | extern void imap_put_inode(struct inode *inode); 113 | 114 | #endif /* minix_fs.h */ 115 | -------------------------------------------------------------------------------- /fs/inode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void put_inode(struct inode *inode) 7 | { 8 | inode->i_refcnt--; 9 | if (inode->i_refcnt == 0) { 10 | if (inode->i_ops && inode->i_ops->release) 11 | inode->i_ops->release(inode); 12 | } else if (inode->i_refcnt < 0) { 13 | printk("Free inode too many times(%d)\n", inode->i_refcnt); 14 | } 15 | } 16 | 17 | struct inode *get_inode_ref(struct inode *inode) 18 | { 19 | inode->i_refcnt++; 20 | return inode; 21 | } 22 | 23 | int inode_read(struct inode *inode, char *buf, size_t size, off_t off) 24 | { 25 | /* 26 | * We cannot use min(i_size - off, size) directly here, 27 | * the negative value of (i_size - off) will be changd to 28 | * positive value of `unsigned int` type. 29 | */ 30 | int r = -1; 31 | if (off >= inode->i_size) 32 | return 0; 33 | size = min(inode->i_size - off, size); 34 | if (inode->i_ops && inode->i_ops->read) 35 | r = inode->i_ops->read(inode, buf, size, off); 36 | return r; 37 | } 38 | 39 | void inode_update_size(struct inode *inode, size_t size) 40 | { 41 | inode->i_size = size; 42 | if (inode->i_ops && inode->i_ops->update_size) 43 | inode->i_ops->update_size(inode, size); 44 | } 45 | 46 | int inode_write(struct inode *inode, char *buf, size_t size, off_t off) 47 | { 48 | int r = -1; 49 | if (inode->i_ops && inode->i_ops->write) 50 | r = inode->i_ops->write(inode, buf, size, off); 51 | if ((r > 0) && (r + off > inode->i_size)) 52 | inode_update_size(inode, r + off); 53 | return r; 54 | } 55 | 56 | int inode_truncate(struct inode *inode) 57 | { 58 | int r = -1; 59 | if (S_ISREG(inode->i_mode) && inode->i_ops && inode->i_ops->truncate) { 60 | inode->i_ops->truncate(inode); 61 | r = 0; 62 | } 63 | return r; 64 | } 65 | 66 | struct inode *inode_open(char *path, unsigned int mode) 67 | { 68 | struct inode *dir, *inode; 69 | char *basename; 70 | int len; 71 | dir = path_lookup_dir(path, &basename, &len); 72 | if (!dir) 73 | return NULL; 74 | if (len == 0) { 75 | /* for "/" ,"//", "///", ... */ 76 | if (dir == ctask->fs.root_dir) 77 | return dir; 78 | return NULL; 79 | } 80 | inode = inode_sub_lookup_put(dir, basename, len); 81 | /* Not exist and create it? */ 82 | if (!inode && (mode & O_CREATE)) { 83 | if (dir->i_ops && dir->i_ops->create) 84 | inode = dir->i_ops->create(dir, basename, len); 85 | } 86 | if (inode && (mode & O_TRUNCATE)) 87 | inode_truncate(inode); 88 | return inode; 89 | } 90 | 91 | void inode_close(struct inode *inode) 92 | { 93 | put_inode(inode); 94 | } 95 | 96 | void inode_sync(struct inode *inode) 97 | { 98 | if (inode->i_ops && inode->i_ops->sync) 99 | inode->i_ops->sync(inode); 100 | } 101 | 102 | void inode_stat(struct inode *inode, struct file_stat *stat) 103 | { 104 | stat->size = inode->i_size; 105 | stat->inode = inode->i_ino; 106 | stat->mode = inode->i_mode; 107 | stat->iref = inode->i_refcnt; 108 | if (inode->i_ops && inode->i_ops->stat) 109 | inode->i_ops->stat(inode, stat); 110 | } 111 | 112 | void inode_chdir(struct inode *inode) 113 | { 114 | struct inode *old; 115 | old = ctask->fs.current_dir; 116 | ctask->fs.current_dir = get_inode_ref(inode); 117 | if (old) 118 | put_inode(old); 119 | } 120 | 121 | int inode_getdir(struct inode *inode, int start, int num, struct dir_stat *ds) 122 | { 123 | int r = -1; 124 | if (!S_ISDIR(inode->i_mode)) 125 | return -1; 126 | if (inode->i_ops && inode->i_ops->getdir) 127 | r = inode->i_ops->getdir(inode, start, num, ds); 128 | return r; 129 | } 130 | 131 | struct inode *inode_mkdir(char *path) 132 | { 133 | struct inode *dir, *inode = NULL; 134 | char *basename; 135 | int len; 136 | dir = path_lookup_dir(path, &basename, &len); 137 | if (dir) { 138 | if (len > 0 && dir->i_ops && dir->i_ops->mkdir) 139 | inode = dir->i_ops->mkdir(dir, basename, len); 140 | put_inode(dir); 141 | } 142 | return inode; 143 | } 144 | 145 | int inode_rmdir(char *path) 146 | { 147 | struct inode *dir; 148 | char *basename; 149 | int len, r = -1; 150 | dir = path_lookup_dir(path, &basename, &len); 151 | if (dir) { 152 | if (len > 0 && dir->i_ops && dir->i_ops->rmdir) 153 | r = dir->i_ops->rmdir(dir, basename, len); 154 | put_inode(dir); 155 | } 156 | return r; 157 | } 158 | 159 | int inode_rm(char *path) 160 | { 161 | struct inode *dir; 162 | char *basename; 163 | int len, r = -1; 164 | dir = path_lookup_dir(path, &basename, &len); 165 | if (dir) { 166 | if (len > 0 && dir->i_ops && dir->i_ops->rm) 167 | r = dir->i_ops->rm(dir, basename, len); 168 | put_inode(dir); 169 | } 170 | return r; 171 | } 172 | 173 | int inode_get_pathname(struct inode *inode, char *pathname, size_t len) 174 | { 175 | return inode->i_ops->get_pathname(inode, pathname, len); 176 | } 177 | -------------------------------------------------------------------------------- /kernel/int.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include <8259A.h> 3 | #include 4 | #include 5 | #include 6 | 7 | static void init_8259A(void) 8 | { 9 | /* ICW1: */ 10 | outb_p(PIC_MASTER_CMD, ICW1); 11 | outb_p(PIC_SLAVE_CMD, ICW1); 12 | /* ICW2: remap IRQ number */ 13 | outb_p(PIC_MASTER_DATA, INTNO_IRQ0); 14 | outb_p(PIC_SLAVE_DATA, INTNO_IRQ8); 15 | /* ICW3: */ 16 | outb_p(PIC_MASTER_DATA, ICW3_MASTER); 17 | outb_p(PIC_SLAVE_DATA, ICW3_SLAVE); 18 | /* ICW4: cascaded PIC environment */ 19 | outb_p(PIC_MASTER_DATA, ICW4_MASTER); 20 | outb_p(PIC_SLAVE_DATA, ICW4_SLAVE); 21 | /* disable all interrupts: mask on all bit of IMR */ 22 | outb_p(PIC_MASTER_IMR, 0xff); 23 | outb_p(PIC_SLAVE_IMR, 0xff); 24 | } 25 | 26 | void mask_8259A(int irq) 27 | { 28 | u16 port; 29 | u8 value; 30 | port = (irq < 8) ? PIC_MASTER_IMR : PIC_SLAVE_IMR; 31 | value = inb(port) | (1 << irq); 32 | outb(port, value); 33 | } 34 | 35 | void EOI_8259A(int irq) 36 | { 37 | /* 38 | * If IRQ comes from slave PIC, it is necessary to 39 | * send an EOI to master PIC. 40 | */ 41 | if (irq >= 8) 42 | outb(PIC_SLAVE_CMD, EOI); 43 | outb(PIC_MASTER_CMD, EOI); 44 | } 45 | 46 | void unmask_8259A(int irq) 47 | { 48 | u16 port; 49 | u8 value; 50 | port = (irq < 8) ? PIC_MASTER_IMR : PIC_SLAVE_IMR; 51 | value = inb(port) & (~(1 << irq)); 52 | outb(port, value); 53 | } 54 | 55 | static int interrupt_level; 56 | void first_open_interrupt(void) 57 | { 58 | interrupt_level = 0; 59 | sti(); 60 | } 61 | 62 | void open_interrupt(void) 63 | { 64 | interrupt_level--; 65 | if (interrupt_level == 0) 66 | sti(); 67 | else if (interrupt_level < 0) 68 | panic("interrupt_level = %d", interrupt_level); 69 | } 70 | 71 | void close_interrupt(void) 72 | { 73 | if (interrupt_level == 0) 74 | cli(); 75 | interrupt_level++; 76 | } 77 | 78 | extern void do_page_fault(struct regs *); 79 | extern void do_sys_call(struct regs *); 80 | extern void keyboard_interrupt(struct regs *); 81 | extern void timer_interrupt(struct regs *); 82 | 83 | /* All traps, faults, fatals and hardware interrupt handler */ 84 | void interrupt_handler(int nr, struct regs *reg) 85 | { 86 | if (nr < 0 || nr > INTNO_MAX) { 87 | dump_stack(reg); 88 | panic("Unknown interrupt %d", nr); 89 | } 90 | 91 | interrupt_level++; 92 | 93 | /* 94 | * IRQs are mutually exclusive. 95 | * IRQ can preempt other traps and syscalls. 96 | */ 97 | switch (nr) { 98 | case INTNO_IRQ0: 99 | timer_interrupt(reg); 100 | break; 101 | case INTNO_IRQ1: 102 | keyboard_interrupt(reg); 103 | break; 104 | case INTNO_PF: 105 | do_page_fault(reg); 106 | break; 107 | case INTNO_SYSCALL: 108 | do_sys_call(reg); 109 | break; 110 | default: 111 | dump_stack(reg); 112 | printk("error code: %08x\n", reg->error); 113 | printk("interrupt on %d\n", nr); 114 | panic("interrupt unfinished"); 115 | break; 116 | } 117 | 118 | /* 119 | * send end of interrupt signal to PIC chip (not autoeoi mode) 120 | * (If no EOI is sent, other hardware irq will not be accepted!) 121 | */ 122 | if (nr >= INTNO_IRQ0 && nr <= INTNO_IRQ15) 123 | EOI_8259A(nr - INTNO_IRQ0); 124 | 125 | interrupt_level--; 126 | } 127 | 128 | static struct desc idt[IDT_SIZE]; 129 | static struct table_desc idt_desc = { 130 | .limit = sizeof(idt) - 1, 131 | .base = (u32)idt, /* linear address */ 132 | }; 133 | 134 | void int_init(void) 135 | { 136 | /* Init idt table */ 137 | set_trap_gate(INTNO_DE, de_entry); 138 | /* Vector 1 is reserved */ 139 | set_trap_gate(INTNO_NMI, nmi_entry); 140 | set_trap_gate(INTNO_BP, bp_entry); 141 | set_trap_gate(INTNO_OF, of_entry); 142 | set_trap_gate(INTNO_BR, br_entry); 143 | set_trap_gate(INTNO_UD, ud_entry); 144 | set_trap_gate(INTNO_NM, nm_entry); 145 | set_trap_gate(INTNO_DF, df_entry); 146 | /* Vector 9 is reserved */ 147 | set_trap_gate(INTNO_TS, ts_entry); 148 | set_trap_gate(INTNO_NP, np_entry); 149 | set_trap_gate(INTNO_SS, ss_entry); 150 | set_trap_gate(INTNO_GP, gp_entry); 151 | set_int_gate(INTNO_PF, pf_entry); /* page fault cannot allow interrupt. */ 152 | /* Vector 15 iS reserved */ 153 | set_trap_gate(INTNO_MF, mf_entry); 154 | set_trap_gate(INTNO_AC, ac_entry); 155 | set_trap_gate(INTNO_MC, mc_entry); 156 | set_trap_gate(INTNO_XM, xm_entry); 157 | /* Vector 20-31 are reserved */ 158 | /* Interrupt Gate ensures there is no recursion interrupt. */ 159 | set_int_gate(INTNO_IRQ0, irq0_entry); 160 | set_int_gate(INTNO_IRQ1, irq1_entry); 161 | set_int_gate(INTNO_IRQ2, irq2_entry); 162 | set_int_gate(INTNO_IRQ3, irq3_entry); 163 | set_int_gate(INTNO_IRQ4, irq4_entry); 164 | set_int_gate(INTNO_IRQ5, irq5_entry); 165 | set_int_gate(INTNO_IRQ6, irq6_entry); 166 | set_int_gate(INTNO_IRQ7, irq7_entry); 167 | set_int_gate(INTNO_IRQ8, irq8_entry); 168 | set_int_gate(INTNO_IRQ9, irq9_entry); 169 | set_int_gate(INTNO_IRQ10, irq10_entry); 170 | set_int_gate(INTNO_IRQ11, irq11_entry); 171 | set_int_gate(INTNO_IRQ12, irq12_entry); 172 | set_int_gate(INTNO_IRQ13, irq13_entry); 173 | set_int_gate(INTNO_IRQ14, irq14_entry); 174 | set_int_gate(INTNO_IRQ15, irq15_entry); 175 | set_system_gate(INTNO_SYSCALL, syscall_entry); 176 | 177 | /* load idt table */ 178 | lidt((u32)&idt_desc); 179 | 180 | /* init interrupt processor */ 181 | init_8259A(); 182 | printk("interrupt/trap/fault init!\n"); 183 | } 184 | -------------------------------------------------------------------------------- /mm/buddy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct page_zone zones[PG_ZONES]; 8 | 9 | /* all page descriptors */ 10 | struct page *page_table; 11 | unsigned int npage; 12 | 13 | void zone_debug(int type) 14 | { 15 | struct page_zone *zone = &zones[type]; 16 | struct page_area *area = zone->area; 17 | int i; 18 | printk("zone %2d start %8d free %8x total %8x\n", 19 | type, zone->start, zone->free, zone->total); 20 | printk(" area free list: "); 21 | for (i = 0; i < PG_ORDERS; i++) { 22 | printk("%5d", area->free_num); 23 | area++; 24 | } 25 | printk("\n"); 26 | } 27 | 28 | static void _inline area_del_page(struct page_area *area, struct page *p) 29 | { 30 | area->free_num--; 31 | unsetpagebuddy(p); 32 | list_del_init(&p->pg_list); 33 | } 34 | 35 | static void _inline area_add_page(struct page_area *area, struct page *p) 36 | { 37 | area->free_num++; 38 | setpagebuddy(p); 39 | list_add(&p->pg_list, &area->free_list); 40 | } 41 | 42 | #define PG_ORDER_MASK(order) ((1 << (order)) - 1) 43 | static void free_zone_pages(struct page_zone *zone, struct page *p, int order) 44 | { 45 | struct page_area *area = &zone->area[order]; 46 | struct page *buddy; 47 | unsigned int idx; 48 | 49 | idx = PG2PN(p); 50 | if (idx & PG_ORDER_MASK(order)) 51 | return; 52 | zone->free += (1 << order); 53 | while (order < PG_MAX_ORDER) { 54 | buddy = &page_table[idx ^ (1 << order)]; 55 | /* detect whether @buddy is our real buddy page */ 56 | if (!page_buddy(buddy) || buddy->pg_order != order) 57 | break; 58 | /* pop buddy */ 59 | area_del_page(area, buddy); 60 | buddy->pg_order = PG_NIL_ORDER; 61 | if (area->free_num < 0) { 62 | panic("area %d page %d %s", 63 | area - zone->area, PG2PN(buddy), 64 | page_buddy(buddy)?"buddy":"Unbuddy"); 65 | } 66 | /* for next loop */ 67 | idx &= ~(1 << order); 68 | order++; 69 | area++; 70 | } 71 | /* push buddy */ 72 | p = &page_table[idx]; 73 | area_add_page(area, p); 74 | p->pg_order = order; 75 | } 76 | 77 | void free_pages(struct page *page, int order) 78 | { 79 | if (order < 0 || order > PG_MAX_ORDER || page_reserved(page) || 80 | page_buddy(page) || page->pg_order != PG_NIL_ORDER) { 81 | printk("Free pages error\n"); 82 | return; 83 | } 84 | if (page->pg_refcnt || page->pg_cowshare) 85 | panic("Free in-use pages"); 86 | free_zone_pages(&zones[page->pg_zone], page, order); 87 | } 88 | 89 | static struct page *alloc_zone_pages(struct page_zone *zone, int order) 90 | { 91 | struct page_area *area = &zone->area[order]; 92 | struct page *p; 93 | int alloc_order = order; 94 | /* get minium alloc_order, which is larger than order */ 95 | while (alloc_order < PG_ORDERS) { 96 | if (area->free_num > 0) 97 | break; 98 | area++; 99 | alloc_order++; 100 | } 101 | if (alloc_order >= PG_ORDERS) 102 | return NULL; 103 | p = list_first_entry(&area->free_list, struct page, pg_list); 104 | if (!page_buddy(p)) 105 | panic("Unbuddy?"); 106 | 107 | area_del_page(area, p); 108 | p->pg_order = PG_NIL_ORDER; 109 | /* We always alloc last pages! */ 110 | while (alloc_order > order) { 111 | alloc_order--; 112 | area--; 113 | area_add_page(area, p); 114 | p->pg_order = alloc_order; 115 | p += (1 << alloc_order); 116 | } 117 | zone->free -= 1 << order; 118 | if (page_buddy(p)) 119 | panic("Buddy?"); 120 | return p; 121 | } 122 | 123 | struct page *alloc_pages(int zone, int order) 124 | { 125 | if (order < 0 || order > PG_MAX_ORDER || 126 | zone > PG_ZONE_HIGH || zone < PG_ZONE_LOW) { 127 | printk("Alloc pages error: zone %d order %d\n", zone, order); 128 | return NULL; 129 | } 130 | return alloc_zone_pages(&zones[zone], order); 131 | } 132 | 133 | static void zone_init(int type, int start, int end) 134 | { 135 | struct page_zone *zone = &zones[type]; 136 | struct page_area *area = zone->area; 137 | struct page *p = &page_table[start]; 138 | int i; 139 | 140 | zone->free = 0; 141 | zone->total = max(end - start + 1, 0); 142 | zone->start = zone->total > 0 ? start : -1; 143 | /* init area */ 144 | for (i = 0; i < PG_ORDERS; i++) { 145 | list_init(&area->free_list); 146 | area->free_num = 0; 147 | area++; 148 | } 149 | /* init zone pages */ 150 | for (i = start; i <= end; i++) { 151 | setpagezone(p, type); 152 | p->pg_order = PG_NIL_ORDER; 153 | if (!page_reserved(p)) 154 | free_pages(p, 0); 155 | p++; 156 | } 157 | } 158 | 159 | extern void *boot_memory_exit(void); 160 | extern void e820_memory_reserved(void); 161 | void pages_init(void) 162 | { 163 | int i, n; 164 | page_table = boot_alloc(sizeof(struct page), npage); 165 | memset(page_table, 0x0, npage * sizeof(struct page)); 166 | /* reserve e820 map reserved memory */ 167 | e820_memory_reserved(); 168 | /* reserve alloced boot memory */ 169 | n = PN(boot_memory_exit()); 170 | for (i = NOR_MEM_PN; i < n; i++) 171 | setpagereserved(&page_table[i]); 172 | printk("Normal free memory start from %dth page\n", n); 173 | /* init low memory */ 174 | zone_init(PG_ZONE_LOW, LOW_MEM_PN, NOR_MEM_PN - 1); 175 | zone_init(PG_ZONE_NOR, NOR_MEM_PN, min(npage, HIGH_MEM_PN) - 1); 176 | zone_init(PG_ZONE_HIGH, HIGH_MEM_PN, npage - 1); 177 | 178 | zone_debug(PG_ZONE_LOW); 179 | zone_debug(PG_ZONE_NOR); 180 | zone_debug(PG_ZONE_HIGH); 181 | #ifdef DEBUG_LOW_MEM 182 | while (alloc_pages(0, 0) != NULL); 183 | zone_debug(PG_ZONE_LOW); 184 | for (i = 0; i < NOR_MEM_PN; i++) 185 | free_pages(page_table+i, 0); 186 | zone_debug(PG_ZONE_LOW); 187 | #endif 188 | } 189 | -------------------------------------------------------------------------------- /include/list.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIST_H 2 | #define __LIST_H 3 | 4 | #include 5 | #include 6 | 7 | #define list_entry(ptr, type, member) container_of(ptr, type, member) 8 | #define list_first_entry(ptr, type, member) list_entry((ptr)->next, type, member) 9 | 10 | struct list_head { 11 | struct list_head *prev; 12 | struct list_head *next; 13 | }; 14 | 15 | #define LIST_HEAD(name) struct list_head name = INIT_LIST_HEAD(name) 16 | #define INIT_LIST_HEAD(head) { &(head), &(head) } 17 | #define HOLE_LIST ((struct list_head *)0xffffffff) 18 | #define list_empty(l) ((l)->next == (l)) 19 | 20 | static _inline void list_init(struct list_head *head) 21 | { 22 | head->prev = head->next = head; 23 | } 24 | 25 | static _inline void __list_add(struct list_head *list, struct list_head *prev, 26 | struct list_head *next) 27 | { 28 | prev->next = list; 29 | list->prev = prev; 30 | list->next = next; 31 | next->prev = list; 32 | } 33 | 34 | static _inline void list_add(struct list_head *list, struct list_head *head) 35 | { 36 | __list_add(list, head, head->next); 37 | } 38 | 39 | static _inline void list_add_tail(struct list_head *list, struct list_head *head) 40 | { 41 | __list_add(list, head->prev, head); 42 | } 43 | 44 | static _inline void __list_del(struct list_head *prev, struct list_head *next) 45 | { 46 | prev->next = next; 47 | next->prev = prev; 48 | } 49 | 50 | static _inline void list_del(struct list_head *list) 51 | { 52 | __list_del(list->prev, list->next); 53 | list->prev = list->next = HOLE_LIST; 54 | } 55 | 56 | static _inline void list_del_init(struct list_head *list) 57 | { 58 | __list_del(list->prev, list->next); 59 | list->prev = list->next = list; 60 | } 61 | 62 | static _inline void list_move(struct list_head *list, struct list_head *head) 63 | { 64 | __list_del(list->prev, list->next); 65 | __list_add(list, head, head->next); 66 | } 67 | 68 | /* merge result: dprev <-> (shead <-> ... <-> stail) <-> dnext */ 69 | static _inline void __list_merge(struct list_head *dprev, struct list_head *shead, 70 | struct list_head *stail, struct list_head *dnext) 71 | { 72 | dprev->next = shead; 73 | shead->prev= dprev; 74 | stail->next = dnext; 75 | dnext->prev = stail; 76 | } 77 | 78 | static _inline void list_merge(struct list_head *dest, struct list_head *src) 79 | { 80 | __list_merge(dest, src->next, src->prev, dest->next); 81 | } 82 | 83 | static _inline void list_merge_tail(struct list_head *dest, struct list_head *src) 84 | { 85 | __list_merge(dest->prev, src->next, src->prev, dest); 86 | } 87 | 88 | #define list_for_each(head, list)\ 89 | for (list = (head)->next; list != (head); list = list->next) 90 | 91 | #define list_for_each_entry(entry, head, member) \ 92 | for (entry = list_entry((head)->next, typeof(*entry), member);\ 93 | &(entry->member) != (head);\ 94 | entry = list_entry(entry->member.next, typeof(*entry), member)) 95 | 96 | #define list_for_each_entry_safe(entry, head, member, n) \ 97 | for (entry = list_entry((head)->next, typeof(*entry), member),\ 98 | n = entry->member.next;\ 99 | &entry->member != (head);\ 100 | entry = list_entry(n, typeof(*entry), member),\ 101 | n = entry->member.next) 102 | 103 | /* 104 | * Hash list 105 | */ 106 | /* hash list head */ 107 | struct hlist_head { 108 | struct hlist_node *first; 109 | }; 110 | 111 | struct hlist_node { 112 | struct hlist_node *next; 113 | struct hlist_node **pprev; 114 | }; 115 | 116 | static _inline int hlist_unhashed(struct hlist_node *node) 117 | { 118 | return !node->pprev; 119 | } 120 | 121 | static _inline int hlist_empty(struct hlist_head *head) 122 | { 123 | return !head->first; 124 | } 125 | 126 | static _inline void hlist_head_init(struct hlist_head *head) 127 | { 128 | head->first = NULL; 129 | } 130 | 131 | static _inline void hlist_node_init(struct hlist_node *node) 132 | { 133 | node->next = NULL; 134 | node->pprev = NULL; 135 | } 136 | 137 | static _inline void __hlist_del(struct hlist_node *n) 138 | { 139 | *n->pprev = n->next; 140 | if (n->next) 141 | n->next->pprev = n->pprev; 142 | } 143 | 144 | static _inline void hlist_del(struct hlist_node *n) 145 | { 146 | __hlist_del(n); 147 | n->next = NULL; 148 | n->pprev = NULL; 149 | } 150 | 151 | static _inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) 152 | { 153 | n->next = h->first; 154 | n->pprev = &h->first; 155 | if (h->first) 156 | h->first->pprev = &n->next; 157 | h->first = n; 158 | } 159 | 160 | /* add @n before @next */ 161 | static _inline void hlist_add_before(struct hlist_node *n, struct hlist_node *next) 162 | { 163 | n->next = next; 164 | n->pprev = next->pprev; 165 | *next->pprev = n; 166 | next->pprev = &n->next; 167 | } 168 | 169 | /* add @next after @n */ 170 | static _inline void hlist_add_after(struct hlist_node *n, struct hlist_node *next) 171 | { 172 | next->next = n->next; 173 | next->pprev = &n->next; 174 | if (n->next) 175 | n->next->pprev = &next->next; 176 | n->next = next; 177 | } 178 | 179 | #define hlist_entry(ptr, type, member) list_entry(ptr, type, member) 180 | /* non-node implementation */ 181 | #define hlist_for_each_entry2(entry, head, member)\ 182 | for (entry = ((head)->first) ? hlist_entry((head)->first, typeof(*entry), member) : NULL;\ 183 | entry;\ 184 | entry = (entry->member.next) ? hlist_entry(entry->member.next, typeof(*entry), member) : NULL) 185 | 186 | #define hlist_for_each_entry(entry, node, head, member)\ 187 | for (node = (head)->first;\ 188 | node && (entry = hlist_entry(node, typeof(*entry), member));\ 189 | node = node->next) 190 | 191 | #endif /* list.h */ 192 | -------------------------------------------------------------------------------- /user/libc/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int searchzerobit(void *src, int bits, int set) 4 | { 5 | unsigned int bit32; 6 | int i, k, off; 7 | off = bits & 31; 8 | bits /= 32; 9 | for (i = 0; i < bits; i++) { 10 | bit32 = *((unsigned int *)src); 11 | for (k = 0; k < 32; k++) { 12 | if (!(bit32 & 1)) 13 | goto found; 14 | bit32 >>= 1; 15 | } 16 | src += 4; 17 | } 18 | bit32 = *((unsigned int *)src); 19 | for (k = 0; k < off; k++) { 20 | if (!(bit32 & 1)) 21 | goto found; 22 | bit32 >>= 1; 23 | } 24 | return -1; 25 | found: 26 | if (set) 27 | ((unsigned char *)src)[k >> 3] |= (1 << (k & 7)); 28 | return i * 32 + k; 29 | } 30 | 31 | int testbit(void *src, int bits) 32 | { 33 | u32 bit32; 34 | bit32 = ((u32 *)src)[bits / 32]; 35 | return bit32 & (1 << (bits & 31)); 36 | } 37 | 38 | int setbit(void *src, int bits) 39 | { 40 | u8 *bit8, r; 41 | bit8 = (u8 *)src + (bits / 8); 42 | r = *bit8 & 1 << (bits & 7); 43 | *bit8 = (*bit8) | (1 << (bits & 7)); 44 | return !!r; 45 | } 46 | 47 | int clearbit(void *src, int bits) 48 | { 49 | u8 *bit8, r; 50 | bit8 = (u8 *)src + (bits / 8); 51 | r = *bit8 & (1 << (bits & 7)); 52 | *bit8 = (*bit8) & ~(1 << (bits & 7)); 53 | return !!r; 54 | } 55 | 56 | void memmove(void *dst, void *src, int n) 57 | { 58 | /* safe copy */ 59 | if (src + n > dst && src <= dst) { 60 | while (--n >= 0) 61 | *((u8 *)dst + n) = *((u8 *)src + n); 62 | } else { 63 | int i; 64 | for (i = 0; i < n; i++) 65 | *((u8 *)dst + i) = *((u8 *)src + i); 66 | } 67 | } 68 | 69 | void memcpy(void *dst, void *src, int n) 70 | { 71 | int i; 72 | for (i = 0; i < n; i++) 73 | *((u8 *)dst + i) = *((u8 *)src + i); 74 | } 75 | 76 | void memset(void *dst, int c, int n) 77 | { 78 | int i; 79 | for (i = 0; i < n; i++) 80 | *((u8 *)dst + i) = c; 81 | } 82 | 83 | void wmemset(void *dst, int c, int n) 84 | { 85 | int i; 86 | for (i = 0; i < n; i++) 87 | *((u16 *)dst + i) = c; 88 | } 89 | 90 | int strcpy(char *dst, char *src) 91 | { 92 | char *ret = dst; 93 | while (*src) 94 | *dst++ = *src++; 95 | *dst = '\0'; 96 | return dst - ret; 97 | } 98 | 99 | /* return number of copied bytes */ 100 | int strncpy(char *dst, char *src, int n) 101 | { 102 | int i = 0; 103 | while (*src && n > 0) { 104 | *dst++ = *src++; 105 | n--; 106 | i++; 107 | } 108 | while (n > 0) { 109 | *dst++ = '\0'; 110 | n--; 111 | } 112 | return i; 113 | } 114 | 115 | int strnncpy(char *dst, char *src, int n) 116 | { 117 | int i = 0; 118 | while (*src && n > 0) { 119 | *dst++ = *src++; 120 | n--; 121 | i++; 122 | } 123 | /* 124 | * Dont pad the remainder of dest with null 125 | * if the length of src is less than n 126 | */ 127 | return i; 128 | } 129 | 130 | int strcmp(char *s1, char *s2) 131 | { 132 | while (*s1 && *s1 == *s2) { 133 | s1++; 134 | s2++; 135 | } 136 | return *s1 - *s2; 137 | } 138 | 139 | int strncmp(char *s1, char *s2, unsigned int n) 140 | { 141 | while (n > 0 && *s1 && *s1 == *s2) { 142 | s1++; 143 | s2++; 144 | n--; 145 | } 146 | return (n > 0) ? (*s1 - *s2) : 0; 147 | } 148 | 149 | #define BASEMAX ('z' - 'a' + 11) 150 | #define BASESTR "0123456789abcdefghijklmnopqrstuvwxyz" 151 | 152 | /* return the lenth of number string */ 153 | int utostr(unsigned int n, char *nptr, int base) 154 | { 155 | int i; 156 | char *p = nptr; 157 | /* base check */ 158 | if (base < 2 || base > BASEMAX) 159 | return 0; 160 | /* fast process */ 161 | if (n == 0) { 162 | nptr[0] = '0'; 163 | nptr[1] = '\0'; 164 | return 1; 165 | } 166 | /* transform number to string */ 167 | while (n) { 168 | i = n % base; 169 | n /= base; 170 | *p++ = BASESTR[i]; 171 | } 172 | /* save number string lenth */ 173 | n = p - nptr; 174 | *p-- = '\0'; 175 | /* reverse number string */ 176 | while (nptr < p) { 177 | i = *p; 178 | *p = *nptr; 179 | *nptr = i; 180 | nptr++; 181 | p--; 182 | } 183 | return n; 184 | } 185 | 186 | /* return the lenth of number string */ 187 | int itostr(int n, char *nptr, int base) 188 | { 189 | int i; 190 | char *p = nptr; 191 | /* base check */ 192 | if (base < 2 || base > BASEMAX) 193 | return 0; 194 | /* fast process */ 195 | if (n == 0) { 196 | nptr[0] = '0'; 197 | nptr[1] = '\0'; 198 | return 1; 199 | } 200 | /* If n is mininum of integer, */ 201 | if (n < 0) { 202 | /* 203 | * Integer overflow: 204 | * Cant transform mininum integer to postive number 205 | */ 206 | if (n == MIN_INT) 207 | return 0; 208 | n = -n; 209 | *p++ = '-'; 210 | } 211 | /* transform number to string */ 212 | while (n) { 213 | i = n % base; 214 | n /= base; 215 | *p++ = BASESTR[i]; 216 | } 217 | /* save number string lenth */ 218 | n = p - nptr; 219 | *p-- = '\0'; 220 | if (*nptr == '-') 221 | nptr++; 222 | /* reverse number string */ 223 | while (nptr < p) { 224 | i = *p; 225 | *p = *nptr; 226 | *nptr = i; 227 | nptr++; 228 | p--; 229 | } 230 | return n; 231 | } 232 | 233 | /* 234 | * transform string to integer 235 | * only support base: 16 236 | */ 237 | int strtoi(char *nptr, char **endptr, int base) 238 | { 239 | int num = 0; 240 | int n; 241 | 242 | if (base < 2 || base > BASEMAX) 243 | return 0; 244 | 245 | while (*nptr) { 246 | n = *nptr; 247 | if (n >= '0' && n <= '9') 248 | n -= '0'; 249 | else if (n >= 'A' && n <= 'Z') 250 | n -= ('A' - 10); 251 | else if (n >= 'a' && n <= 'z') 252 | n -= ('a' - 10); 253 | else 254 | n = base; 255 | if (n >= base) 256 | break; 257 | num = num * base + n; 258 | nptr++; 259 | } 260 | if (endptr) 261 | *endptr = nptr; 262 | return num; 263 | } 264 | 265 | int log2(int n) 266 | { 267 | int i = -1; 268 | while (n > 0) { 269 | n >>= 1; 270 | i++; 271 | } 272 | return i; 273 | } 274 | 275 | int log2up(int n) 276 | { 277 | int i = 0; 278 | if (n <= 0) 279 | return -1; 280 | n--; 281 | while (n > 0) { 282 | n >>= 1; 283 | i++; 284 | } 285 | return i; 286 | } 287 | -------------------------------------------------------------------------------- /video/text.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* Text Parameters */ 9 | #define TEXT_BASE 0xb8000 10 | #define TEXT_VBASE ((void *)VADDR(TEXT_BASE)) 11 | #define TEXT_END (TEXT_BASE + TEXT_SCREENS * TEXT_SCR_SIZE) 12 | #define TEXT_VEND ((void *)VADDR(TEXT_END)) 13 | #define TEXT_SIZE (0xc0000 - 0xb8000) 14 | #define TEXT_LINES 25 15 | #define TEXT_ROWS 80 16 | #define TEXT_CHR_SIZE 2 17 | #define TEXT_LINE_SIZE (TEXT_ROWS * TEXT_CHR_SIZE) 18 | #define TEXT_SCR_CHRS (TEXT_ROWS * TEXT_LINES) 19 | #define TEXT_SCR_SIZE (TEXT_SCR_CHRS * TEXT_CHR_SIZE) 20 | /* reserve one blank line for scrolling down last screen */ 21 | #define TEXT_SCREENS ((TEXT_SIZE - TEXT_LINE_SIZE) / TEXT_SCR_SIZE) 22 | /* I/O Port */ 23 | #define TEXT_REG_INDEX 0x3d4 24 | #define TEXT_REG_VALUE 0x3d5 25 | /* Function index */ 26 | #define INDEX_SCREEN_HIGH 0x0c 27 | #define INDEX_SCREEN_LOW 0x0d 28 | #define INDEX_CURSOR_HIGH 0x0e 29 | #define INDEX_CURSOR_LOW 0x0f 30 | /* Special Chars */ 31 | #define TEXT_TAB_SIZE (8 * TEXT_CHR_SIZE) 32 | /* Text Char Mode */ 33 | #define TEXT_BLACK_CHRMODE 0x00 34 | #define TEXT_BLUE_CHRMODE 0x01 35 | #define TEXT_GREEN_CHRMODE 0x02 36 | #define TEXT_CYAN_CHRMODE 0x03 37 | #define TEXT_RED_CHRMODE 0x04 38 | #define TEXT_MAGENTA_CHRMODE 0x05 39 | #define TEXT_BROWN_CHRMODE 0x06 40 | #define TEXT_LIGHTGRAY_CHRMODE 0x07 41 | #define TEXT_DARKGRAY_CHRMODE 0x08 42 | #define TEXT_LIGHTBLUE_CHRMODE 0x09 43 | #define TEXT_LIGHTGREEN_CHRMODE 0x0a 44 | #define TEXT_LIGHTCYAN_CHRMODE 0x0b 45 | #define TEXT_LIGHTRED_CHRMODE 0x0c 46 | #define TEXT_LIGHTMAGENTA_CHRMODE 0x0d 47 | #define TEXT_YELLOW_CHRMODE 0x0e 48 | #define TEXT_WHITE_CHRMODE 0x0f 49 | #define TEXT_DEF_CHRMODE TEXT_WHITE_CHRMODE 50 | 51 | /* 52 | * Text Screen Buffer Memory: 53 | * 54 | * .-----total screen buffer------. 55 | * | | 56 | * | .-current screen-. | 57 | * | | | | 58 | * | .-offset-. | | 59 | * | | | | | 60 | * +------+--------+-------+------+ 61 | * | | | 62 | * base screen cursor 63 | * 64 | */ 65 | static void *text_base; /* base address of total text memory */ 66 | static void *text_screen; /* base address of screen memory */ 67 | static void *text_cursor; 68 | 69 | static _inline void set_cursor(u32 offset) 70 | { 71 | outb_p(TEXT_REG_INDEX, INDEX_CURSOR_LOW); 72 | outb_p(TEXT_REG_VALUE, (u16)(offset & 0xff)); 73 | outb_p(TEXT_REG_INDEX, INDEX_CURSOR_HIGH); 74 | outb_p(TEXT_REG_VALUE, (u16)((offset >> 8) & 0xff)); 75 | } 76 | 77 | static void update_cursor(void) 78 | { 79 | set_cursor((text_cursor - text_base) / TEXT_CHR_SIZE); 80 | } 81 | 82 | static _inline void text_set_screen(u32 offset) 83 | { 84 | outb_p(TEXT_REG_INDEX, INDEX_SCREEN_LOW); 85 | outb_p(TEXT_REG_VALUE, (u16)(offset & 0xff)); 86 | outb_p(TEXT_REG_INDEX, INDEX_SCREEN_HIGH); 87 | outb_p(TEXT_REG_VALUE, (u16)((offset >> 8) & 0xff)); 88 | } 89 | 90 | static void update_screen(void) 91 | { 92 | text_set_screen((text_screen - text_base) / TEXT_CHR_SIZE); 93 | } 94 | 95 | static _inline void clear_vmem(void *src, int chars) 96 | { 97 | u16 mode_char; 98 | mode_char = (TEXT_DEF_CHRMODE << 8) | ' '; 99 | wmemset(src, mode_char, chars); 100 | } 101 | 102 | /* clear current screen without altering cursor */ 103 | static void clear_screen(void) 104 | { 105 | clear_vmem(text_screen, TEXT_SCR_CHRS); 106 | } 107 | 108 | static void text_scroll_down(void) 109 | { 110 | if (text_cursor >= TEXT_VEND) { 111 | /* 112 | * We have reserved one blank line after TEXT_END, 113 | * the blank line is copied to last line of new screen. 114 | * So we dont need to clear the last line manually. 115 | */ 116 | text_screen += TEXT_LINE_SIZE; 117 | memcpy(text_base, text_screen, TEXT_SCR_SIZE); 118 | text_cursor -= (text_screen - text_base); 119 | text_screen = text_base; 120 | /* But we should clear other screens. */ 121 | clear_vmem(text_base + TEXT_SCR_SIZE, TEXT_SCR_CHRS * (TEXT_SCREENS - 1)); 122 | } else { 123 | text_screen += TEXT_LINE_SIZE; 124 | } 125 | update_screen(); 126 | update_cursor(); 127 | } 128 | 129 | static _inline void text_put_char(char c) 130 | { 131 | ((char *)text_cursor)[0] = c; 132 | ((char *)text_cursor)[1] = TEXT_DEF_CHRMODE; 133 | } 134 | 135 | static void text_handle_char(char c) 136 | { 137 | switch (c) { 138 | case '\b': 139 | if (text_cursor > text_screen) { 140 | text_cursor -= TEXT_CHR_SIZE; 141 | text_put_char(' '); 142 | } 143 | break; 144 | case '\t': 145 | text_cursor = ALIGN_UP(text_cursor + TEXT_CHR_SIZE, 146 | TEXT_TAB_SIZE); 147 | break; 148 | case '\n': 149 | text_cursor += TEXT_LINE_SIZE; 150 | text_cursor -= (text_cursor - TEXT_VBASE) % TEXT_LINE_SIZE; 151 | break; 152 | case '\r': 153 | text_cursor += TEXT_LINE_SIZE; 154 | break; 155 | default: 156 | text_put_char(c); 157 | text_cursor += TEXT_CHR_SIZE; 158 | break; 159 | } 160 | if (text_cursor >= text_screen + TEXT_SCR_SIZE) 161 | text_scroll_down(); 162 | } 163 | 164 | void text_putc(char c) 165 | { 166 | text_handle_char(c); 167 | update_cursor(); 168 | } 169 | 170 | int text_nputs(char *s, int n) 171 | { 172 | int i = 0; 173 | while (*s && i < n) { 174 | text_handle_char(*s); 175 | s++; 176 | i++; 177 | } 178 | update_cursor(); 179 | return i; 180 | } 181 | 182 | int text_puts(char *s) 183 | { 184 | int i = 0; 185 | while (*s) { 186 | text_handle_char(*s++); 187 | i++; 188 | } 189 | update_cursor(); 190 | return i; 191 | } 192 | 193 | void text_init(void) 194 | { 195 | /* 196 | * This is a simple initialization: 197 | * Some configure is default according to BIOS initialization. 198 | * For robustness, we should detect and set VGA mode manually. 199 | * But it can work well now. 200 | */ 201 | text_base = TEXT_VBASE; 202 | text_screen = text_base; 203 | text_cursor = text_base; 204 | update_cursor(); 205 | clear_screen(); 206 | printk("Video: init text mode\n"); 207 | } 208 | -------------------------------------------------------------------------------- /kernel/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int searchzerobit(void *src, int bits, int set) 5 | { 6 | unsigned int bit32; 7 | int i, k, off; 8 | off = bits & 31; 9 | bits /= 32; 10 | for (i = 0; i < bits; i++) { 11 | bit32 = *((unsigned int *)src); 12 | for (k = 0; k < 32; k++) { 13 | if (!(bit32 & 1)) 14 | goto found; 15 | bit32 >>= 1; 16 | } 17 | src += 4; 18 | } 19 | bit32 = *((unsigned int *)src); 20 | for (k = 0; k < off; k++) { 21 | if (!(bit32 & 1)) 22 | goto found; 23 | bit32 >>= 1; 24 | } 25 | return -1; 26 | found: 27 | if (set) 28 | ((unsigned char *)src)[k >> 3] |= (1 << (k & 7)); 29 | return i * 32 + k; 30 | } 31 | 32 | int testbit(void *src, int bits) 33 | { 34 | u32 bit32; 35 | bit32 = ((u32 *)src)[bits / 32]; 36 | return bit32 & (1 << (bits & 31)); 37 | } 38 | 39 | int setbit(void *src, int bits) 40 | { 41 | u8 *bit8, r; 42 | bit8 = (u8 *)src + (bits / 8); 43 | r = *bit8 & 1 << (bits & 7); 44 | *bit8 = (*bit8) | (1 << (bits & 7)); 45 | return !!r; 46 | } 47 | 48 | int clearbit(void *src, int bits) 49 | { 50 | u8 *bit8, r; 51 | bit8 = (u8 *)src + (bits / 8); 52 | r = (*bit8) & (1 << (bits & 7)); 53 | *bit8 = (*bit8) & ~(1 << (bits & 7)); 54 | return !!r; 55 | } 56 | 57 | void memmove(void *dst, void *src, int n) 58 | { 59 | /* safe copy */ 60 | if (src + n > dst && src <= dst) { 61 | while (--n >= 0) 62 | *((u8 *)dst + n) = *((u8 *)src + n); 63 | } else { 64 | int i; 65 | for (i = 0; i < n; i++) 66 | *((u8 *)dst + i) = *((u8 *)src + i); 67 | } 68 | } 69 | 70 | void memcpy(void *dst, void *src, int n) 71 | { 72 | int i; 73 | for (i = 0; i < n; i++) 74 | *((u8 *)dst + i) = *((u8 *)src + i); 75 | } 76 | 77 | void memset(void *dst, int c, int n) 78 | { 79 | int i; 80 | for (i = 0; i < n; i++) 81 | *((u8 *)dst + i) = c; 82 | } 83 | 84 | void wmemset(void *dst, int c, int n) 85 | { 86 | int i; 87 | for (i = 0; i < n; i++) 88 | *((u16 *)dst + i) = c; 89 | } 90 | 91 | int strlen(char *str) 92 | { 93 | int len = 0; 94 | while (*str) { 95 | len++; 96 | str++; 97 | } 98 | return len; 99 | } 100 | 101 | int strcpy(char *dst, char *src) 102 | { 103 | char *ret = dst; 104 | while (*src) 105 | *dst++ = *src++; 106 | *dst = '\0'; 107 | return dst - ret; 108 | } 109 | 110 | /* return number of copied bytes */ 111 | int strncpy(char *dst, char *src, int n) 112 | { 113 | int i = 0; 114 | while (*src && n > 0) { 115 | *dst++ = *src++; 116 | n--; 117 | i++; 118 | } 119 | while (n > 0) { 120 | *dst++ = '\0'; 121 | n--; 122 | } 123 | return i; 124 | } 125 | 126 | int strnncpy(char *dst, char *src, int n) 127 | { 128 | int i = 0; 129 | while (*src && n > 0) { 130 | *dst++ = *src++; 131 | n--; 132 | i++; 133 | } 134 | /* 135 | * Dont pad the remainder of dest with null 136 | * if the length of src is less than n 137 | */ 138 | return i; 139 | } 140 | 141 | int strcmp(char *s1, char *s2) 142 | { 143 | while (*s1 && *s1 == *s2) { 144 | s1++; 145 | s2++; 146 | } 147 | return *s1 - *s2; 148 | } 149 | 150 | int strncmp(char *s1, char *s2, unsigned int n) 151 | { 152 | while (n > 0 && *s1 && *s1 == *s2) { 153 | s1++; 154 | s2++; 155 | n--; 156 | } 157 | return (n > 0) ? (*s1 - *s2) : 0; 158 | } 159 | 160 | #define BASEMAX ('z' - 'a' + 11) 161 | #define BASESTR "0123456789abcdefghijklmnopqrstuvwxyz" 162 | 163 | /* return the lenth of number string */ 164 | int utostr(unsigned int n, char *nptr, int base) 165 | { 166 | int i; 167 | char *p = nptr; 168 | /* base check */ 169 | if (base < 2 || base > BASEMAX) 170 | return 0; 171 | /* fast process */ 172 | if (n == 0) { 173 | nptr[0] = '0'; 174 | nptr[1] = '\0'; 175 | return 1; 176 | } 177 | /* transform number to string */ 178 | while (n) { 179 | i = n % base; 180 | n /= base; 181 | *p++ = BASESTR[i]; 182 | } 183 | /* save number string lenth */ 184 | n = p - nptr; 185 | *p-- = '\0'; 186 | /* reverse number string */ 187 | while (nptr < p) { 188 | i = *p; 189 | *p = *nptr; 190 | *nptr = i; 191 | nptr++; 192 | p--; 193 | } 194 | return n; 195 | } 196 | 197 | /* return the lenth of number string */ 198 | int itostr(int n, char *nptr, int base) 199 | { 200 | int i; 201 | char *p = nptr; 202 | /* base check */ 203 | if (base < 2 || base > BASEMAX) 204 | return 0; 205 | /* fast process */ 206 | if (n == 0) { 207 | nptr[0] = '0'; 208 | nptr[1] = '\0'; 209 | return 1; 210 | } 211 | /* If n is mininum of integer, */ 212 | if (n < 0) { 213 | /* 214 | * Integer overflow: 215 | * Cant transform mininum integer to postive number 216 | */ 217 | if (n == MIN_INT) 218 | return 0; 219 | n = -n; 220 | *p++ = '-'; 221 | } 222 | /* transform number to string */ 223 | while (n) { 224 | i = n % base; 225 | n /= base; 226 | *p++ = BASESTR[i]; 227 | } 228 | /* save number string lenth */ 229 | n = p - nptr; 230 | *p-- = '\0'; 231 | if (*nptr == '-') 232 | nptr++; 233 | /* reverse number string */ 234 | while (nptr < p) { 235 | i = *p; 236 | *p = *nptr; 237 | *nptr = i; 238 | nptr++; 239 | p--; 240 | } 241 | return n; 242 | } 243 | 244 | /* 245 | * transform string to integer 246 | * only support base: 16 247 | */ 248 | int strtoi(char *nptr, char **endptr, int base) 249 | { 250 | int num = 0; 251 | int n; 252 | 253 | if (base < 2 || base > BASEMAX) 254 | return 0; 255 | 256 | while (*nptr) { 257 | n = *nptr; 258 | if (n >= '0' && n <= '9') 259 | n -= '0'; 260 | else if (n >= 'A' && n <= 'Z') 261 | n -= ('A' - 10); 262 | else if (n >= 'a' && n <= 'z') 263 | n -= ('a' - 10); 264 | else 265 | n = base; 266 | if (n >= base) 267 | break; 268 | num = num * base + n; 269 | nptr++; 270 | } 271 | if (endptr) 272 | *endptr = nptr; 273 | return num; 274 | } 275 | 276 | int log2(int n) 277 | { 278 | int i = -1; 279 | while (n > 0) { 280 | n >>= 1; 281 | i++; 282 | } 283 | return i; 284 | } 285 | 286 | int log2up(int n) 287 | { 288 | int i = 0; 289 | if (n <= 0) 290 | return -1; 291 | n--; 292 | while (n > 0) { 293 | n >>= 1; 294 | i++; 295 | } 296 | return i; 297 | } 298 | -------------------------------------------------------------------------------- /fs/block.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static struct slab *block_slab; 7 | 8 | #define BLOCK_HASH_SHIFT 4 9 | #define BLOCK_HASH_SIZE (1 << BLOCK_HASH_SHIFT) 10 | #define BLOCK_HASH_MASK (BLOCK_HASH_SIZE - 1) 11 | static struct hlist_head block_htable[BLOCK_HASH_SIZE]; 12 | static LIST_HEAD(block_buffer_list); 13 | 14 | static _inline struct block *get_block_ref(struct block *block) 15 | { 16 | block->b_refcnt++; 17 | return block; 18 | } 19 | 20 | static int bdev_hash(int bdevno, int blk) 21 | { 22 | return ((blk >> bdevno) + (blk ^ bdevno)); 23 | } 24 | 25 | static struct block *lookup_hash_block(struct block_device *bdev, int blk) 26 | { 27 | struct block *block; 28 | struct hlist_node *node; 29 | struct hlist_head *head; 30 | int hash; 31 | 32 | hash = bdev_hash(bdev->no, blk) & BLOCK_HASH_MASK; 33 | head = &block_htable[hash]; 34 | hlist_for_each_entry(block, node, head, b_hnode) { 35 | if (block->b_dev == bdev && block->b_nr == blk) 36 | goto found; 37 | } 38 | return NULL; 39 | found: 40 | /* Lucky! We get a cached one. */ 41 | if (block->b_buffer) { 42 | block->b_refcnt = 0; 43 | block->b_buffer = 0; 44 | list_move(&block->b_list, &bdev->block_list); 45 | } 46 | return get_block_ref(block); 47 | } 48 | 49 | static void block_unhash(struct block *block) 50 | { 51 | if (!hlist_unhashed(&block->b_hnode)) 52 | hlist_del(&block->b_hnode); 53 | } 54 | 55 | static void block_hash(struct block_device *bdev, struct block *block) 56 | { 57 | struct hlist_head *head; 58 | int hash; 59 | hash = bdev_hash(bdev->no, block->b_nr) & BLOCK_HASH_MASK; 60 | head = &block_htable[hash]; 61 | hlist_add_head(&block->b_hnode, head); 62 | } 63 | 64 | void free_block(struct block *block) 65 | { 66 | list_del(&block->b_list); 67 | block_unhash(block); 68 | kfree(block->b_data); 69 | slab_free_object(block_slab, block); 70 | } 71 | 72 | struct block *alloc_block(struct block_device *bdev, int blk) 73 | { 74 | struct block *block = slab_alloc_object(block_slab); 75 | if (!block) 76 | return NULL; 77 | block->b_data = kmalloc(bdev->size); 78 | if (!block->b_data) { 79 | slab_free_object(block_slab, block); 80 | return NULL; 81 | } 82 | block->b_nr = blk; 83 | block->b_size = bdev->size; 84 | block->b_sects = bdev->size / SECT_SIZE; /* Ramdisk will not use. */ 85 | block->b_refcnt = 1; 86 | block->b_dev = bdev; 87 | block->b_dirty = 0; 88 | block->b_read = 0; 89 | block->b_buffer = 0; 90 | block_hash(bdev, block); 91 | list_add(&block->b_list, &bdev->block_list); 92 | return block; 93 | } 94 | 95 | int write_block(struct block *block) 96 | { 97 | struct block_device *bdev = block->b_dev; 98 | int r = -1; 99 | if (bdev && bdev->ops) 100 | r = bdev->ops->write(block); 101 | if (r == 0) 102 | block->b_dirty = 0; 103 | return r; 104 | } 105 | 106 | void put_block(struct block *block) 107 | { 108 | block->b_refcnt--; 109 | if (block->b_refcnt == 0) { 110 | /* We dont free block memory or sync block, just caching it. */ 111 | list_move(&block->b_list, &block_buffer_list); 112 | block->b_buffer = 1; 113 | } else if (block->b_refcnt < 0) { 114 | printk("Free block too many times(%d)\n", block->b_nr); 115 | } 116 | } 117 | 118 | int read_block(struct block *block) 119 | { 120 | struct block_device *bdev = block->b_dev; 121 | int r = -1; 122 | if (bdev && bdev->ops) 123 | r = bdev->ops->read(block); 124 | if (r == 0) 125 | block->b_read = 1; 126 | return r; 127 | } 128 | 129 | struct block *get_block(struct block_device *bdev, int blk) 130 | { 131 | struct block *block; 132 | if (blk >= bdev->blocks) 133 | return NULL; 134 | /* lookup it in hash table */ 135 | block = lookup_hash_block(bdev, blk); 136 | /* We dont cache block, kmalloc(BLOCK_SIZE) will cache it! */ 137 | /* if it isnt in hash table, we alloc a new one. */ 138 | if (!block) { 139 | block = alloc_block(bdev, blk); 140 | if (!block) 141 | return NULL; 142 | } 143 | if (!block->b_read) 144 | read_block(block); 145 | return block; 146 | } 147 | 148 | /* Called when there is no enough free memory. */ 149 | void flush_block_buffer(void) 150 | { 151 | struct block *block; 152 | while (!list_empty(&block_buffer_list)) { 153 | block = list_first_entry(&block_buffer_list, struct block, b_list); 154 | flush_block(block); 155 | free_block(block); 156 | } 157 | } 158 | 159 | void sync_blocks(void) 160 | { 161 | struct hlist_head *head = block_htable; 162 | int i = BLOCK_HASH_SIZE; 163 | struct hlist_node *node; 164 | struct block *block; 165 | while (i > 0) { 166 | hlist_for_each_entry(block, node, head, b_hnode) 167 | flush_block(block); 168 | head++; 169 | i--; 170 | } 171 | } 172 | 173 | int set_block_size(struct block_device *bdev, int size) 174 | { 175 | int r = -1; 176 | if (bdev->ops && bdev->ops->set_block_size) 177 | r = bdev->ops->set_block_size(bdev, size); 178 | return r; 179 | } 180 | 181 | void sys_sync(void) 182 | { 183 | sync_blocks(); 184 | } 185 | 186 | #ifdef DEBUG_BLOCK 187 | extern struct block_device hd_bdev; 188 | void block_test(void) 189 | { 190 | struct block *block; 191 | unsigned char *p; 192 | int i; 193 | block = get_block(&hd_bdev, 0); 194 | if (!block) 195 | panic("Cannot get block"); 196 | if (block != get_block(&hd_bdev, 0)) 197 | panic("Cannot get hash block"); 198 | put_block(block); 199 | p = (unsigned char *)block->b_data; 200 | if (p[510] != 0x55 || p[511] != 0xaa) 201 | panic("ERROR 0x55aa"); 202 | p[0] = 'h'; 203 | p[1] = 'k'; 204 | block->b_dirty = 1; 205 | put_block(block); 206 | block = get_block(&hd_bdev, 0); 207 | p = (unsigned char *)block->b_data; 208 | if (p[0] != 'h' || p[1] != 'k') 209 | panic("block WRITE or READ error"); 210 | for (i = 0; i < 512; i++) 211 | p[i] = 0xff; 212 | block->b_dirty = 1; 213 | put_block(block); 214 | printk("flush buffer\n"); 215 | flush_block_buffer(); 216 | block = get_block(&hd_bdev, 0); 217 | printk("test block ok\n"); 218 | } 219 | #else 220 | #define block_test() 221 | #endif /* !DEBUG_BLOCK */ 222 | 223 | extern void hd_init(void); 224 | void block_init(void) 225 | { 226 | int i; 227 | /* init block buffer allocator */ 228 | block_slab = alloc_slab(sizeof(struct block)); 229 | if (!block_slab) 230 | panic("No memory for block slab"); 231 | /* init block buffer hash table */ 232 | for (i = 0; i < BLOCK_HASH_SIZE; i++) 233 | hlist_head_init(&block_htable[i]); 234 | hd_init(); 235 | block_test(); 236 | } 237 | -------------------------------------------------------------------------------- /tools/mkfs.minix.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "fs.h" 9 | 10 | #if DEBUG 11 | #define warning(fmt, ...) fprintf(stderr, "WARNING: "fmt"\n", __VA_ARGS__) 12 | #define DEBUG_SB(sb) \ 13 | do { \ 14 | fprintf(stderr, "----------super block:-------------\n" \ 15 | "s_inodes: %d\ns_nzones: %d\ns_imap_blocks: %d\n" \ 16 | "s_zmap_blocks: %d\ns_firstdatazone: %d\n" \ 17 | "s_log_zone_size: %u\ns_max_size: %u\n" \ 18 | "s_magic: 0x%x\n-----------------------------------\n", \ 19 | (sb)->s_ninodes, (sb)->s_nzones, (sb)->s_imap_blocks, \ 20 | (sb)->s_zmap_blocks, (sb)->s_firstdatazone, \ 21 | (sb)->s_log_zone_size, (sb)->s_max_size, (sb)->s_magic);\ 22 | } while (0) 23 | #else 24 | #define DEBUG_SB(sb) 25 | #define warning(fmt, ...) 26 | #endif 27 | 28 | #define CLEAN_BLOCK_BUFFER() memset(block_buffer, 0x0, BLOCK_SIZE) 29 | #define CLEAN_SUPER_BLOCK() memset(super_block, 0x0, BLOCK_SIZE) 30 | 31 | #define WRITE_BLOCK(blknr, blk, str) \ 32 | do { \ 33 | if (lseek(devfd, (blknr) * BLOCK_SIZE, SEEK_SET) == -1) \ 34 | per_exit("lseek"); \ 35 | if (BLOCK_SIZE != write(devfd, blk, BLOCK_SIZE)) { \ 36 | per_exit("write: "str); \ 37 | } \ 38 | } while (0) 39 | 40 | #define WRITE_SUPER_BLOCK(blknr, str) WRITE_BLOCK((blknr) + blkoff, super_block, str) 41 | #define WRITE_BLOCK_BUFFER(blknr, str) WRITE_BLOCK((blknr) + blkoff, block_buffer, str) 42 | 43 | static int devfd = -1; 44 | static char *program = NULL; 45 | static char *devfile = NULL; 46 | static unsigned int blocks = 0; 47 | static int blkoff = 0; 48 | 49 | /* 50 | * used by boot/sb/imap/zmap/inodeblk/datablk repeatedly 51 | * Although it is ugly to do it, it is simply enough:P 52 | */ 53 | static unsigned char block_buffer[BLOCK_SIZE]; 54 | static unsigned char super_block[BLOCK_SIZE]; 55 | static struct d_super_block *sb = (struct d_super_block *)super_block; 56 | static unsigned char *map_blk = block_buffer; 57 | static unsigned char *inode_blk = block_buffer; 58 | 59 | void per_exit(char *str) 60 | { 61 | if (errno) 62 | perror(str); 63 | else 64 | fprintf(stderr, "ERROR: %s\n", str); 65 | exit(EXIT_FAILURE); 66 | } 67 | 68 | 69 | void open_set_param(void) 70 | { 71 | struct stat sbuf; 72 | unsigned long size; 73 | 74 | /* get total blocks number of disk image */ 75 | devfd = open(devfile, O_RDWR); 76 | if (devfd == -1) 77 | per_exit("open devfile"); 78 | if (fstat(devfd, &sbuf) == -1) 79 | per_exit("fstat"); 80 | if (!S_ISBLK(sbuf.st_mode)) { 81 | warning("file:%s is not block device", devfile); 82 | blocks = sbuf.st_size / BLOCK_SIZE; 83 | } else { 84 | if (ioctl(devfd, BLKGETSIZE, &size) == -1) 85 | per_exit("ioctl"); 86 | blocks = size / (BLOCK_SIZE / 512); 87 | } 88 | /* get filesystem block offset */ 89 | if (lseek(devfd, 506, SEEK_SET) != 506) 90 | per_exit("lseek"); 91 | if (read(devfd, &blkoff, 2) != 2) 92 | per_exit("read"); 93 | blocks -= blkoff; 94 | printf(" \n", 95 | blkoff, blocks); 96 | /* check */ 97 | if (blocks < 10 || blocks > 65535) 98 | per_exit("invalid block number"); 99 | } 100 | 101 | void clean_boot(void) 102 | { 103 | CLEAN_BLOCK_BUFFER(); 104 | WRITE_BLOCK_BUFFER(0, "boot block"); 105 | } 106 | 107 | void write_super_block(void) 108 | { 109 | 110 | CLEAN_SUPER_BLOCK(); 111 | /* init 'static' data */ 112 | sb->s_log_zone_size = 0; 113 | sb->s_max_size = (7 + 512 + 512 * 512) * BLOCK_SIZE; 114 | sb->s_magic = MINIX_SUPER_MAGIC; 115 | 116 | /* init 'dynamic' data, which need to be caculated */ 117 | sb->s_ninodes = blocks / 3; 118 | sb->s_nzones = blocks; 119 | sb->s_imap_blocks = ALIGN_UP(sb->s_ninodes - 1, 8 * BLOCK_SIZE); 120 | 121 | /* up and down algrithm */ 122 | sb->s_zmap_blocks = 0; /* bits: all blocks - boot/sb/imap/zmap/inodeblk */ 123 | while (sb->s_zmap_blocks != ALIGN_UP(blocks - FIRST_ZONE_BLK(sb), 8 * BLOCK_SIZE)) 124 | sb->s_zmap_blocks = ALIGN_UP(blocks - FIRST_ZONE_BLK(sb), 8 * BLOCK_SIZE); 125 | 126 | /* start from 0, which is boot block number */ 127 | sb->s_firstdatazone = FIRST_ZONE_BLK(sb); 128 | 129 | WRITE_SUPER_BLOCK(1, "super block"); 130 | 131 | warning("write super block: blocks %d\n first data block %d\n", 132 | blocks, sb->s_firstdatazone); 133 | 134 | DEBUG_SB(sb); 135 | } 136 | 137 | void write_maps(void) 138 | { 139 | int i; 140 | 141 | CLEAN_BLOCK_BUFFER(); 142 | 143 | if (lseek(devfd, (2 + blkoff) * BLOCK_SIZE, SEEK_SET) == -1) 144 | per_exit("lseek"); 145 | /* zone map bits only stand for [data block](|boot|sb|imap|zmap|inodeblk|[data block]|)*/ 146 | for (i = 0; i < sb->s_imap_blocks + sb->s_zmap_blocks; i++) 147 | if (BLOCK_SIZE != write(devfd, map_blk, BLOCK_SIZE)) 148 | per_exit("write map_blks"); 149 | } 150 | 151 | void write_root(void) 152 | { 153 | int i; 154 | struct d_inode *root; 155 | 156 | inode_blk = (unsigned char *)block_buffer; 157 | CLEAN_BLOCK_BUFFER(); 158 | /* mark inode map */ 159 | map_blk[0] = 0x03; /* 0-reserved 1-ROOT_INO */ 160 | WRITE_BLOCK_BUFFER(2, "root inode map"); 161 | 162 | /* 163 | * mark zone map 164 | * 0-reserved 165 | * 1-first data block containing dentry:"." and ".." 166 | */ 167 | map_blk[0] = 0x03; 168 | WRITE_BLOCK_BUFFER(2 + sb->s_imap_blocks, "root inode map"); 169 | 170 | #define dentry2 "\x1\x0.\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0"\ 171 | "\x1\x0..\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 172 | #define d2len (2 * sizeof(struct dir_entry)) 173 | /* write inode */ 174 | root = (struct d_inode *)inode_blk; 175 | root->i_mode = S_IFDIR | 0755; 176 | root->i_size = d2len; 177 | root->i_time = time(NULL); 178 | root->i_zone[0] = sb->s_firstdatazone; 179 | root->i_nlinks = 2; 180 | WRITE_BLOCK_BUFFER(INODE_BLK(sb), "root inode"); 181 | 182 | /* write block(dentry:"." and "..") */ 183 | CLEAN_BLOCK_BUFFER(); 184 | memcpy(block_buffer, dentry2, d2len); 185 | WRITE_BLOCK_BUFFER(sb->s_firstdatazone, "root data block(dentry)"); 186 | } 187 | 188 | void usage(void) 189 | { 190 | fprintf(stderr, "Usage %s devfile\n", program); 191 | exit(EXIT_FAILURE); 192 | } 193 | 194 | int main(int argc, char **argv) 195 | { 196 | program = argv[0]; 197 | if (argc != 2) 198 | usage(); 199 | devfile = argv[1]; 200 | open_set_param(); 201 | /* 202 | * It is *not* necessary to clean boot block. 203 | * But I do it to avoid extra troublesome ;-) 204 | */ 205 | clean_boot(); 206 | 207 | write_super_block(); 208 | write_maps(); 209 | write_root(); 210 | return 0; 211 | } 212 | --------------------------------------------------------------------------------