├── .dir-locals.el ├── .gdbinit.tmpl ├── .gitignore ├── CODING ├── GNUmakefile ├── README.md ├── boot ├── Makefrag ├── boot.S ├── main.c └── sign.pl ├── conf ├── env.mk └── lab.mk ├── fs ├── Makefrag ├── bc.c ├── fs.c ├── fs.h ├── fsformat.c ├── ide.c ├── lorem ├── motd ├── newmotd ├── script ├── serv.c ├── test.c ├── testshell.key └── testshell.sh ├── grade-lab1 ├── grade-lab2 ├── grade-lab3 ├── grade-lab4 ├── grade-lab5 ├── gradelib.py ├── inc ├── COPYRIGHT ├── args.h ├── assert.h ├── elf.h ├── env.h ├── error.h ├── fd.h ├── fs.h ├── kbdreg.h ├── lib.h ├── memlayout.h ├── mmu.h ├── partition.h ├── stab.h ├── stdarg.h ├── stdio.h ├── string.h ├── syscall.h ├── trap.h ├── types.h └── x86.h ├── kern ├── COPYRIGHT ├── Makefrag ├── console.c ├── console.h ├── cpu.h ├── entry.S ├── entrypgdir.c ├── env.c ├── env.h ├── init.c ├── kclock.c ├── kclock.h ├── kdebug.c ├── kdebug.h ├── kernel.ld ├── lapic.c ├── monitor.c ├── monitor.h ├── mpconfig.c ├── mpentry.S ├── picirq.c ├── picirq.h ├── pmap.c ├── pmap.h ├── printf.c ├── sched.c ├── sched.h ├── spinlock.c ├── spinlock.h ├── syscall.c ├── syscall.h ├── trap.c ├── trap.h └── trapentry.S ├── lib ├── Makefrag ├── args.c ├── console.c ├── entry.S ├── exit.c ├── fd.c ├── file.c ├── fork.c ├── fprintf.c ├── ipc.c ├── libmain.c ├── pageref.c ├── panic.c ├── pfentry.S ├── pgfault.c ├── pipe.c ├── printf.c ├── printfmt.c ├── readline.c ├── spawn.c ├── string.c ├── syscall.c └── wait.c ├── mergedep.pl ├── reports ├── Lab1.md ├── Lab2.md ├── Lab3.md ├── Lab4.md ├── Lab5.md └── img │ └── lab1-challenge.png └── user ├── Makefrag ├── badsegment.c ├── breakpoint.c ├── buggyhello.c ├── buggyhello2.c ├── cat.c ├── divzero.c ├── dumbfork.c ├── echo.c ├── evilhello.c ├── fairness.c ├── faultalloc.c ├── faultallocbad.c ├── faultbadhandler.c ├── faultdie.c ├── faultevilhandler.c ├── faultio.c ├── faultnostack.c ├── faultread.c ├── faultreadkernel.c ├── faultregs.c ├── faultwrite.c ├── faultwritekernel.c ├── forktree.c ├── hello.c ├── icode.c ├── idle.c ├── init.c ├── initsh.c ├── ls.c ├── lsfd.c ├── num.c ├── pingpong.c ├── pingpongs.c ├── primes.c ├── primespipe.c ├── priority.c ├── sendpage.c ├── sh.c ├── softint.c ├── spawnfaultio.c ├── spawnhello.c ├── spawninit.c ├── spin.c ├── stresssched.c ├── testbss.c ├── testfdsharing.c ├── testfile.c ├── testkbd.c ├── testmalloc.c ├── testpipe.c ├── testpiperace.c ├── testpiperace2.c ├── testptelibrary.c ├── testpteshare.c ├── testshell.c ├── user.ld ├── writemotd.c └── yield.c /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil 2 | (indent-tabs-mode . t) 3 | (tab-width . 8)) 4 | (c-mode 5 | (c-file-style . "bsd") 6 | (c-basic-offset . 8)) 7 | (shell-mode 8 | (sh-basic-offset . 8) 9 | (sh-indentation . 8)) 10 | (python-mode 11 | (indent-tabs-mode . nil)) 12 | ) 13 | -------------------------------------------------------------------------------- /.gdbinit.tmpl: -------------------------------------------------------------------------------- 1 | set $lastcs = -1 2 | 3 | define hook-stop 4 | # There doesn't seem to be a good way to detect if we're in 16- or 5 | # 32-bit mode, but we always run with CS == 8 in 32-bit mode. 6 | if $cs == 8 || $cs == 27 7 | if $lastcs != 8 && $lastcs != 27 8 | set architecture i386 9 | end 10 | x/i $pc 11 | else 12 | if $lastcs == -1 || $lastcs == 8 || $lastcs == 27 13 | set architecture i8086 14 | end 15 | # Translate the segment:offset into a physical address 16 | printf "[%4x:%4x] ", $cs, $eip 17 | x/i $cs*16+$eip 18 | end 19 | set $lastcs = $cs 20 | end 21 | 22 | echo + target remote localhost:1234\n 23 | target remote localhost:1234 24 | 25 | # If this fails, it's probably because your GDB doesn't support ELF. 26 | # Look at the tools page at 27 | # http://pdos.csail.mit.edu/6.828/2009/tools.html 28 | # for instructions on building GDB with ELF support. 29 | echo + symbol-file obj/kern/kernel\n 30 | symbol-file obj/kern/kernel 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /obj 2 | /jos.in 3 | /jos.log 4 | /jos.out 5 | /jos.out.* 6 | /jos.cmd 7 | /.gdbinit 8 | /wget.log 9 | /qemu.pcap 10 | /qemu.pcap.* 11 | /qemu.out 12 | /qemu.log 13 | /gradelib.pyc 14 | /lab*-handin.tar.gz 15 | /lab?/ 16 | /sol?/ 17 | /myapi.key 18 | /.suf 19 | .vscode/ 20 | -------------------------------------------------------------------------------- /CODING: -------------------------------------------------------------------------------- 1 | JOS CODING STANDARDS 2 | 3 | It's easier on everyone if all authors working on a shared 4 | code base are consistent in the way they write their programs. 5 | We have the following conventions in our code: 6 | 7 | * No space after the name of a function in a call 8 | For example, printf("hello") not printf ("hello"). 9 | 10 | * One space after keywords "if", "for", "while", "switch". 11 | For example, if (x) not if(x). 12 | 13 | * Space before braces. 14 | For example, if (x) { not if (x){. 15 | 16 | * Function names are all lower-case separated by underscores. 17 | 18 | * Beginning-of-line indentation via tabs, not spaces. 19 | 20 | * Preprocessor macros are always UPPERCASE. 21 | There are a few grandfathered exceptions: assert, panic, 22 | static_assert, offsetof. 23 | 24 | * Pointer types have spaces: (uint16_t *) not (uint16_t*). 25 | 26 | * Multi-word names are lower_case_with_underscores. 27 | 28 | * Comments in imported code are usually C /* ... */ comments. 29 | Comments in new code are C++ style //. 30 | 31 | * In a function definition, the function name starts a new line. 32 | Then you can grep -n '^foo' */*.c to find the definition of foo. 33 | 34 | * Functions that take no arguments are declared f(void) not f(). 35 | 36 | The included .dir-locals.el file will automatically set up the basic 37 | indentation style in Emacs. 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MIT6.828Labs-JOS 2 | 3 | This repository contains my solution to MIT6.828 Operating System Engineering Fall 2018 Lab 1-5. You can refer to the `report/` folder for my reports of each Lab. 4 | 5 | WARNING: DO NOT COPY THIS REPOSITORY AS YOUR SOLUTION IF YOU ARE TAKING COURSES THAT USE THESE LABS AS ASSIGNMENTS!!! 6 | 7 | ## Challenges 8 | 9 | Most of the solutions on the Internet are missing challenges, but I have done some challenges in Lab 2-5, which might be useful for you. The challenges I solved are the following, you can refer to my reports and code for how I solved them. 10 | 11 | ### Lab 1 - Colored Output to Console 12 | 13 | > **Challenge.** Enhance the console to allow text to be printed in different colors. The traditional way to do this is to make it interpret [ANSI escape sequences](http://rrbrandt.dee.ufcg.edu.br/en/docs/ansi/) embedded in the text strings printed to the console, but you may use any mechanism you like. There is plenty of information on [the 6.828 reference page](https://pdos.csail.mit.edu/6.828/2018/reference.html) and elsewhere on the web on programming the VGA display hardware. If you're feeling really adventurous, you could try switching the VGA hardware into a graphics mode and making the console draw text onto the graphical frame buffer. 14 | 15 | ### Lab 2 - More Useful JOS Monitor Commands 16 | 17 | > **Challenge!** Extend the JOS kernel monitor with commands to: 18 | > 19 | > Display in a useful and easy-to-read format all of the physical page mappings (or lack thereof) that apply to a particular range of virtual/linear addresses in the currently active address space. For example, you might enter 'showmappings 0x3000 0x5000' to display the physical page mappings and corresponding permission bits that apply to the pages at virtual addresses 0x3000, 0x4000, and 0x5000. 20 | > 21 | > Explicitly set, clear, or change the permissions of any mapping in the current address space. 22 | > 23 | > Dump the contents of a range of memory given either a virtual or physical address range. Be sure the dump code behaves correctly when the range extends across page boundaries! 24 | > 25 | > Do anything else that you think might be useful later for debugging the kernel. (There's a good chance it will be!) 26 | 27 | ### Lab 3 - Breakpoints and Single Stepping 28 | 29 | > **Challenge!** Modify the JOS kernel monitor so that you can 'continue' execution from the current location (e.g., after the int3, if the kernel monitor was invoked via the breakpoint exception), and so that you can single-step one instruction at a time. You will need to understand certain bits of the EFLAGS register in order to implement single-stepping. 30 | 31 | ### Lab 4 - Fixed Priority Scheduling 32 | 33 | > **Challenge!** Add a less trivial scheduling policy to the kernel, such as a fixed-priority scheduler that allows each environment to be assigned a priority and ensures that higher-priority environments are always chosen in preference to lower-priority environments. 34 | 35 | ### Lab 5 - FIFO Disk Block Cache 36 | 37 | > **Challenge!** The block cache has no eviction policy. Once a block gets faulted in to it, it never gets removed and will remain in memory forevermore. Add eviction to the buffer cache. Using the PTE_A "accessed" bits in the page tables, which the hardware sets on any access to a page, you can track approximate usage of disk blocks without the need to modify every place in the code that accesses the disk map region. Be careful with dirty blocks. 38 | -------------------------------------------------------------------------------- /boot/Makefrag: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile fragment for the JOS kernel. 3 | # This is NOT a complete makefile; 4 | # you must run GNU make in the top-level directory 5 | # where the GNUmakefile is located. 6 | # 7 | 8 | OBJDIRS += boot 9 | 10 | BOOT_OBJS := $(OBJDIR)/boot/boot.o $(OBJDIR)/boot/main.o 11 | 12 | $(OBJDIR)/boot/%.o: boot/%.c 13 | @echo + cc -Os $< 14 | @mkdir -p $(@D) 15 | $(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $@ $< 16 | 17 | $(OBJDIR)/boot/%.o: boot/%.S 18 | @echo + as $< 19 | @mkdir -p $(@D) 20 | $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $< 21 | 22 | $(OBJDIR)/boot/main.o: boot/main.c 23 | @echo + cc -Os $< 24 | $(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $(OBJDIR)/boot/main.o boot/main.c 25 | 26 | $(OBJDIR)/boot/boot: $(BOOT_OBJS) 27 | @echo + ld boot/boot 28 | $(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 -o $@.out $^ 29 | $(V)$(OBJDUMP) -S $@.out >$@.asm 30 | $(V)$(OBJCOPY) -S -O binary -j .text $@.out $@ 31 | $(V)perl boot/sign.pl $(OBJDIR)/boot/boot 32 | 33 | -------------------------------------------------------------------------------- /boot/boot.S: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | # Start the CPU: switch to 32-bit protected mode, jump into C. 4 | # The BIOS loads this code from the first sector of the hard disk into 5 | # memory at physical address 0x7c00 and starts executing in real mode 6 | # with %cs=0 %ip=7c00. 7 | 8 | .set PROT_MODE_CSEG, 0x8 # kernel code segment selector 9 | .set PROT_MODE_DSEG, 0x10 # kernel data segment selector 10 | .set CR0_PE_ON, 0x1 # protected mode enable flag 11 | 12 | .globl start 13 | start: 14 | .code16 # Assemble for 16-bit mode 15 | cli # Disable interrupts 16 | cld # String operations increment 17 | 18 | # Set up the important data segment registers (DS, ES, SS). 19 | xorw %ax,%ax # Segment number zero 20 | movw %ax,%ds # -> Data Segment 21 | movw %ax,%es # -> Extra Segment 22 | movw %ax,%ss # -> Stack Segment 23 | 24 | # Enable A20: 25 | # For backwards compatibility with the earliest PCs, physical 26 | # address line 20 is tied low, so that addresses higher than 27 | # 1MB wrap around to zero by default. This code undoes this. 28 | seta20.1: 29 | inb $0x64,%al # Wait for not busy 30 | testb $0x2,%al 31 | jnz seta20.1 32 | 33 | movb $0xd1,%al # 0xd1 -> port 0x64 34 | outb %al,$0x64 35 | 36 | seta20.2: 37 | inb $0x64,%al # Wait for not busy 38 | testb $0x2,%al 39 | jnz seta20.2 40 | 41 | movb $0xdf,%al # 0xdf -> port 0x60 42 | outb %al,$0x60 43 | 44 | # Switch from real to protected mode, using a bootstrap GDT 45 | # and segment translation that makes virtual addresses 46 | # identical to their physical addresses, so that the 47 | # effective memory map does not change during the switch. 48 | lgdt gdtdesc 49 | movl %cr0, %eax 50 | orl $CR0_PE_ON, %eax 51 | movl %eax, %cr0 52 | 53 | # Jump to next instruction, but in 32-bit code segment. 54 | # Switches processor into 32-bit mode. 55 | ljmp $PROT_MODE_CSEG, $protcseg 56 | 57 | .code32 # Assemble for 32-bit mode 58 | protcseg: 59 | # Set up the protected-mode data segment registers 60 | movw $PROT_MODE_DSEG, %ax # Our data segment selector 61 | movw %ax, %ds # -> DS: Data Segment 62 | movw %ax, %es # -> ES: Extra Segment 63 | movw %ax, %fs # -> FS 64 | movw %ax, %gs # -> GS 65 | movw %ax, %ss # -> SS: Stack Segment 66 | 67 | # Set up the stack pointer and call into C. 68 | movl $start, %esp 69 | call bootmain 70 | 71 | # If bootmain returns (it shouldn't), loop. 72 | spin: 73 | jmp spin 74 | 75 | # Bootstrap GDT 76 | .p2align 2 # force 4 byte alignment 77 | gdt: 78 | SEG_NULL # null seg 79 | SEG(STA_X|STA_R, 0x0, 0xffffffff) # code seg 80 | SEG(STA_W, 0x0, 0xffffffff) # data seg 81 | 82 | gdtdesc: 83 | .word 0x17 # sizeof(gdt) - 1 84 | .long gdt # address gdt 85 | 86 | -------------------------------------------------------------------------------- /boot/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /********************************************************************** 5 | * This a dirt simple boot loader, whose sole job is to boot 6 | * an ELF kernel image from the first IDE hard disk. 7 | * 8 | * DISK LAYOUT 9 | * * This program(boot.S and main.c) is the bootloader. It should 10 | * be stored in the first sector of the disk. 11 | * 12 | * * The 2nd sector onward holds the kernel image. 13 | * 14 | * * The kernel image must be in ELF format. 15 | * 16 | * BOOT UP STEPS 17 | * * when the CPU boots it loads the BIOS into memory and executes it 18 | * 19 | * * the BIOS intializes devices, sets of the interrupt routines, and 20 | * reads the first sector of the boot device(e.g., hard-drive) 21 | * into memory and jumps to it. 22 | * 23 | * * Assuming this boot loader is stored in the first sector of the 24 | * hard-drive, this code takes over... 25 | * 26 | * * control starts in boot.S -- which sets up protected mode, 27 | * and a stack so C code then run, then calls bootmain() 28 | * 29 | * * bootmain() in this file takes over, reads in the kernel and jumps to it. 30 | **********************************************************************/ 31 | 32 | #define SECTSIZE 512 33 | #define ELFHDR ((struct Elf *) 0x10000) // scratch space 34 | 35 | void readsect(void*, uint32_t); 36 | void readseg(uint32_t, uint32_t, uint32_t); 37 | 38 | void 39 | bootmain(void) 40 | { 41 | struct Proghdr *ph, *eph; 42 | int i; 43 | 44 | // read 1st page off disk 45 | readseg((uint32_t) ELFHDR, SECTSIZE*8, 0); 46 | 47 | // is this a valid ELF? 48 | if (ELFHDR->e_magic != ELF_MAGIC) 49 | goto bad; 50 | 51 | // load each program segment (ignores ph flags) 52 | ph = (struct Proghdr *) ((uint8_t *) ELFHDR + ELFHDR->e_phoff); 53 | eph = ph + ELFHDR->e_phnum; 54 | for (; ph < eph; ph++) { 55 | // p_pa is the load address of this segment (as well 56 | // as the physical address) 57 | readseg(ph->p_pa, ph->p_memsz, ph->p_offset); 58 | for (i = 0; i < ph->p_memsz - ph->p_filesz; i++) { 59 | *((char *) ph->p_pa + ph->p_filesz + i) = 0; 60 | } 61 | } 62 | 63 | // call the entry point from the ELF header 64 | // note: does not return! 65 | ((void (*)(void)) (ELFHDR->e_entry))(); 66 | 67 | bad: 68 | outw(0x8A00, 0x8A00); 69 | outw(0x8A00, 0x8E00); 70 | while (1) 71 | /* do nothing */; 72 | } 73 | 74 | // Read 'count' bytes at 'offset' from kernel into physical address 'pa'. 75 | // Might copy more than asked 76 | void 77 | readseg(uint32_t pa, uint32_t count, uint32_t offset) 78 | { 79 | uint32_t end_pa; 80 | 81 | end_pa = pa + count; 82 | 83 | // round down to sector boundary 84 | pa &= ~(SECTSIZE - 1); 85 | 86 | // translate from bytes to sectors, and kernel starts at sector 1 87 | offset = (offset / SECTSIZE) + 1; 88 | 89 | // If this is too slow, we could read lots of sectors at a time. 90 | // We'd write more to memory than asked, but it doesn't matter -- 91 | // we load in increasing order. 92 | while (pa < end_pa) { 93 | // Since we haven't enabled paging yet and we're using 94 | // an identity segment mapping (see boot.S), we can 95 | // use physical addresses directly. This won't be the 96 | // case once JOS enables the MMU. 97 | readsect((uint8_t*) pa, offset); 98 | pa += SECTSIZE; 99 | offset++; 100 | } 101 | } 102 | 103 | void 104 | waitdisk(void) 105 | { 106 | // wait for disk reaady 107 | while ((inb(0x1F7) & 0xC0) != 0x40) 108 | /* do nothing */; 109 | } 110 | 111 | void 112 | readsect(void *dst, uint32_t offset) 113 | { 114 | // wait for disk to be ready 115 | waitdisk(); 116 | 117 | outb(0x1F2, 1); // count = 1 118 | outb(0x1F3, offset); 119 | outb(0x1F4, offset >> 8); 120 | outb(0x1F5, offset >> 16); 121 | outb(0x1F6, (offset >> 24) | 0xE0); 122 | outb(0x1F7, 0x20); // cmd 0x20 - read sectors 123 | 124 | // wait for disk to be ready 125 | waitdisk(); 126 | 127 | // read a sector 128 | insl(0x1F0, dst, SECTSIZE/4); 129 | } 130 | 131 | -------------------------------------------------------------------------------- /boot/sign.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | open(BB, $ARGV[0]) || die "open $ARGV[0]: $!"; 4 | 5 | binmode BB; 6 | my $buf; 7 | read(BB, $buf, 1000); 8 | $n = length($buf); 9 | 10 | if($n > 510){ 11 | print STDERR "boot block too large: $n bytes (max 510)\n"; 12 | exit 1; 13 | } 14 | 15 | print STDERR "boot block is $n bytes (max 510)\n"; 16 | 17 | $buf .= "\0" x (510-$n); 18 | $buf .= "\x55\xAA"; 19 | 20 | open(BB, ">$ARGV[0]") || die "open >$ARGV[0]: $!"; 21 | binmode BB; 22 | print BB $buf; 23 | close BB; 24 | -------------------------------------------------------------------------------- /conf/env.mk: -------------------------------------------------------------------------------- 1 | # env.mk - configuration variables for the JOS lab 2 | 3 | # '$(V)' controls whether the lab makefiles print verbose commands (the 4 | # actual shell commands run by Make), as well as the "overview" commands 5 | # (such as '+ cc lib/readline.c'). 6 | # 7 | # For overview commands only, the line should read 'V = @'. 8 | # For overview and verbose commands, the line should read 'V ='. 9 | V = @ 10 | 11 | # If your system-standard GNU toolchain is ELF-compatible, then comment 12 | # out the following line to use those tools (as opposed to the i386-jos-elf 13 | # tools that the 6.828 make system looks for by default). 14 | # 15 | # GCCPREFIX='' 16 | 17 | # If the makefile cannot find your QEMU binary, uncomment the 18 | # following line and set it to the full path to QEMU. 19 | # 20 | # QEMU= 21 | -------------------------------------------------------------------------------- /conf/lab.mk: -------------------------------------------------------------------------------- 1 | LAB=5 2 | PACKAGEDATE=Wed Oct 24 20:44:37 EDT 2018 3 | -------------------------------------------------------------------------------- /fs/Makefrag: -------------------------------------------------------------------------------- 1 | 2 | OBJDIRS += fs 3 | 4 | FSOFILES := $(OBJDIR)/fs/ide.o \ 5 | $(OBJDIR)/fs/bc.o \ 6 | $(OBJDIR)/fs/fs.o \ 7 | $(OBJDIR)/fs/serv.o \ 8 | $(OBJDIR)/fs/test.o \ 9 | 10 | USERAPPS := $(OBJDIR)/user/init 11 | 12 | FSIMGTXTFILES := fs/newmotd \ 13 | fs/motd 14 | 15 | 16 | USERAPPS := $(USERAPPS) \ 17 | $(OBJDIR)/user/cat \ 18 | $(OBJDIR)/user/echo \ 19 | $(OBJDIR)/user/init \ 20 | $(OBJDIR)/user/ls \ 21 | $(OBJDIR)/user/lsfd \ 22 | $(OBJDIR)/user/num \ 23 | $(OBJDIR)/user/forktree \ 24 | $(OBJDIR)/user/primes \ 25 | $(OBJDIR)/user/primespipe \ 26 | $(OBJDIR)/user/sh \ 27 | $(OBJDIR)/user/testfdsharing \ 28 | $(OBJDIR)/user/testkbd \ 29 | $(OBJDIR)/user/testpipe \ 30 | $(OBJDIR)/user/testpteshare \ 31 | $(OBJDIR)/user/testshell \ 32 | $(OBJDIR)/user/hello \ 33 | $(OBJDIR)/user/faultio \ 34 | 35 | FSIMGTXTFILES := $(FSIMGTXTFILES) \ 36 | fs/lorem \ 37 | fs/script \ 38 | fs/testshell.key \ 39 | fs/testshell.sh 40 | 41 | 42 | FSIMGFILES := $(FSIMGTXTFILES) $(USERAPPS) 43 | 44 | $(OBJDIR)/fs/%.o: fs/%.c fs/fs.h inc/lib.h $(OBJDIR)/.vars.USER_CFLAGS 45 | @echo + cc[USER] $< 46 | @mkdir -p $(@D) 47 | $(V)$(CC) -nostdinc $(USER_CFLAGS) -c -o $@ $< 48 | 49 | $(OBJDIR)/fs/fs: $(FSOFILES) $(OBJDIR)/lib/entry.o $(OBJDIR)/lib/libjos.a user/user.ld 50 | @echo + ld $@ 51 | $(V)mkdir -p $(@D) 52 | $(V)$(LD) -o $@ $(ULDFLAGS) $(LDFLAGS) -nostdlib \ 53 | $(OBJDIR)/lib/entry.o $(FSOFILES) \ 54 | -L$(OBJDIR)/lib -ljos $(GCC_LIB) 55 | $(V)$(OBJDUMP) -S $@ >$@.asm 56 | 57 | # How to build the file system image 58 | $(OBJDIR)/fs/fsformat: fs/fsformat.c 59 | @echo + mk $(OBJDIR)/fs/fsformat 60 | $(V)mkdir -p $(@D) 61 | $(V)$(NCC) $(NATIVE_CFLAGS) -o $(OBJDIR)/fs/fsformat fs/fsformat.c 62 | 63 | $(OBJDIR)/fs/clean-fs.img: $(OBJDIR)/fs/fsformat $(FSIMGFILES) 64 | @echo + mk $(OBJDIR)/fs/clean-fs.img 65 | $(V)mkdir -p $(@D) 66 | $(V)$(OBJDIR)/fs/fsformat $(OBJDIR)/fs/clean-fs.img 1024 $(FSIMGFILES) 67 | 68 | $(OBJDIR)/fs/fs.img: $(OBJDIR)/fs/clean-fs.img 69 | @echo + cp $(OBJDIR)/fs/clean-fs.img $@ 70 | $(V)cp $(OBJDIR)/fs/clean-fs.img $@ 71 | 72 | all: $(OBJDIR)/fs/fs.img 73 | 74 | #all: $(addsuffix .sym, $(USERAPPS)) 75 | 76 | #all: $(addsuffix .asm, $(USERAPPS)) 77 | 78 | -------------------------------------------------------------------------------- /fs/fs.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define SECTSIZE 512 // bytes per disk sector 5 | #define BLKSECTS (BLKSIZE / SECTSIZE) // sectors per block 6 | 7 | /* Disk block n, when in memory, is mapped into the file system 8 | * server's address space at DISKMAP + (n*BLKSIZE). */ 9 | #define DISKMAP 0x10000000 10 | 11 | /* Maximum disk size we can handle (3GB) */ 12 | #define DISKSIZE 0xC0000000 13 | 14 | struct Super *super; // superblock 15 | uint32_t *bitmap; // bitmap blocks mapped in memory 16 | 17 | /* ide.c */ 18 | bool ide_probe_disk1(void); 19 | void ide_set_disk(int diskno); 20 | void ide_set_partition(uint32_t first_sect, uint32_t nsect); 21 | int ide_read(uint32_t secno, void *dst, size_t nsecs); 22 | int ide_write(uint32_t secno, const void *src, size_t nsecs); 23 | 24 | /* bc.c */ 25 | void* diskaddr(uint32_t blockno); 26 | bool va_is_mapped(void *va); 27 | bool va_is_dirty(void *va); 28 | void flush_block(void *addr); 29 | void bc_init(void); 30 | 31 | /* fs.c */ 32 | void fs_init(void); 33 | int file_get_block(struct File *f, uint32_t file_blockno, char **pblk); 34 | int file_create(const char *path, struct File **f); 35 | int file_open(const char *path, struct File **f); 36 | ssize_t file_read(struct File *f, void *buf, size_t count, off_t offset); 37 | int file_write(struct File *f, const void *buf, size_t count, off_t offset); 38 | int file_set_size(struct File *f, off_t newsize); 39 | void file_flush(struct File *f); 40 | int file_remove(const char *path); 41 | void fs_sync(void); 42 | 43 | /* int map_block(uint32_t); */ 44 | bool block_is_free(uint32_t blockno); 45 | int alloc_block(void); 46 | 47 | /* test.c */ 48 | void fs_test(void); 49 | 50 | -------------------------------------------------------------------------------- /fs/ide.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Minimal PIO-based (non-interrupt-driven) IDE driver code. 3 | * For information about what all this IDE/ATA magic means, 4 | * see the materials available on the class references page. 5 | */ 6 | 7 | #include "fs.h" 8 | #include 9 | 10 | #define IDE_BSY 0x80 11 | #define IDE_DRDY 0x40 12 | #define IDE_DF 0x20 13 | #define IDE_ERR 0x01 14 | 15 | static int diskno = 1; 16 | 17 | static int 18 | ide_wait_ready(bool check_error) 19 | { 20 | int r; 21 | 22 | while (((r = inb(0x1F7)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY) 23 | /* do nothing */; 24 | 25 | if (check_error && (r & (IDE_DF|IDE_ERR)) != 0) 26 | return -1; 27 | return 0; 28 | } 29 | 30 | bool 31 | ide_probe_disk1(void) 32 | { 33 | int r, x; 34 | 35 | // wait for Device 0 to be ready 36 | ide_wait_ready(0); 37 | 38 | // switch to Device 1 39 | outb(0x1F6, 0xE0 | (1<<4)); 40 | 41 | // check for Device 1 to be ready for a while 42 | for (x = 0; 43 | x < 1000 && ((r = inb(0x1F7)) & (IDE_BSY|IDE_DF|IDE_ERR)) != 0; 44 | x++) 45 | /* do nothing */; 46 | 47 | // switch back to Device 0 48 | outb(0x1F6, 0xE0 | (0<<4)); 49 | 50 | cprintf("Device 1 presence: %d\n", (x < 1000)); 51 | return (x < 1000); 52 | } 53 | 54 | void 55 | ide_set_disk(int d) 56 | { 57 | if (d != 0 && d != 1) 58 | panic("bad disk number"); 59 | diskno = d; 60 | } 61 | 62 | 63 | int 64 | ide_read(uint32_t secno, void *dst, size_t nsecs) 65 | { 66 | int r; 67 | 68 | assert(nsecs <= 256); 69 | 70 | ide_wait_ready(0); 71 | 72 | outb(0x1F2, nsecs); 73 | outb(0x1F3, secno & 0xFF); 74 | outb(0x1F4, (secno >> 8) & 0xFF); 75 | outb(0x1F5, (secno >> 16) & 0xFF); 76 | outb(0x1F6, 0xE0 | ((diskno&1)<<4) | ((secno>>24)&0x0F)); 77 | outb(0x1F7, 0x20); // CMD 0x20 means read sector 78 | 79 | for (; nsecs > 0; nsecs--, dst += SECTSIZE) { 80 | if ((r = ide_wait_ready(1)) < 0) 81 | return r; 82 | insl(0x1F0, dst, SECTSIZE/4); 83 | } 84 | 85 | return 0; 86 | } 87 | 88 | int 89 | ide_write(uint32_t secno, const void *src, size_t nsecs) 90 | { 91 | int r; 92 | 93 | assert(nsecs <= 256); 94 | 95 | ide_wait_ready(0); 96 | 97 | outb(0x1F2, nsecs); 98 | outb(0x1F3, secno & 0xFF); 99 | outb(0x1F4, (secno >> 8) & 0xFF); 100 | outb(0x1F5, (secno >> 16) & 0xFF); 101 | outb(0x1F6, 0xE0 | ((diskno&1)<<4) | ((secno>>24)&0x0F)); 102 | outb(0x1F7, 0x30); // CMD 0x30 means write sector 103 | 104 | for (; nsecs > 0; nsecs--, src += SECTSIZE) { 105 | if ((r = ide_wait_ready(1)) < 0) 106 | return r; 107 | outsl(0x1F0, src, SECTSIZE/4); 108 | } 109 | 110 | return 0; 111 | } 112 | 113 | -------------------------------------------------------------------------------- /fs/lorem: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur 2 | adipisicing elit, sed do eiusmod tempor 3 | incididunt ut labore et dolore magna 4 | aliqua. Ut enim ad minim veniam, quis 5 | nostrud exercitation ullamco laboris 6 | nisi ut aliquip ex ea commodo consequat. 7 | Duis aute irure dolor in reprehenderit 8 | in voluptate velit esse cillum dolore eu 9 | fugiat nulla pariatur. Excepteur sint 10 | occaecat cupidatat non proident, sunt in 11 | culpa qui officia deserunt mollit anim 12 | id est laborum. 13 | -------------------------------------------------------------------------------- /fs/motd: -------------------------------------------------------------------------------- 1 | This is /motd, the message of the day. 2 | 3 | Welcome to the JOS kernel, now with a file system! 4 | 5 | -------------------------------------------------------------------------------- /fs/newmotd: -------------------------------------------------------------------------------- 1 | This is the NEW message of the day! 2 | 3 | -------------------------------------------------------------------------------- /fs/script: -------------------------------------------------------------------------------- 1 | echo This is from the script. 2 | cat lorem | num | cat 3 | echo These are my file descriptors. 4 | lsfd -1 5 | echo This is the end of the script. 6 | -------------------------------------------------------------------------------- /fs/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "fs.h" 5 | 6 | static char *msg = "This is the NEW message of the day!\n\n"; 7 | 8 | void 9 | fs_test(void) 10 | { 11 | struct File *f; 12 | int r; 13 | char *blk; 14 | uint32_t *bits; 15 | 16 | // back up bitmap 17 | if ((r = sys_page_alloc(0, (void*) PGSIZE, PTE_P|PTE_U|PTE_W)) < 0) 18 | panic("sys_page_alloc: %e", r); 19 | bits = (uint32_t*) PGSIZE; 20 | memmove(bits, bitmap, PGSIZE); 21 | // allocate block 22 | if ((r = alloc_block()) < 0) 23 | panic("alloc_block: %e", r); 24 | // check that block was free 25 | assert(bits[r/32] & (1 << (r%32))); 26 | // and is not free any more 27 | assert(!(bitmap[r/32] & (1 << (r%32)))); 28 | cprintf("alloc_block is good\n"); 29 | 30 | if ((r = file_open("/not-found", &f)) < 0 && r != -E_NOT_FOUND) 31 | panic("file_open /not-found: %e", r); 32 | else if (r == 0) 33 | panic("file_open /not-found succeeded!"); 34 | if ((r = file_open("/newmotd", &f)) < 0) 35 | panic("file_open /newmotd: %e", r); 36 | cprintf("file_open is good\n"); 37 | 38 | if ((r = file_get_block(f, 0, &blk)) < 0) 39 | panic("file_get_block: %e", r); 40 | if (strcmp(blk, msg) != 0) 41 | panic("file_get_block returned wrong data"); 42 | cprintf("file_get_block is good\n"); 43 | 44 | *(volatile char*)blk = *(volatile char*)blk; 45 | assert((uvpt[PGNUM(blk)] & PTE_D)); 46 | file_flush(f); 47 | assert(!(uvpt[PGNUM(blk)] & PTE_D)); 48 | cprintf("file_flush is good\n"); 49 | 50 | if ((r = file_set_size(f, 0)) < 0) 51 | panic("file_set_size: %e", r); 52 | assert(f->f_direct[0] == 0); 53 | assert(!(uvpt[PGNUM(f)] & PTE_D)); 54 | cprintf("file_truncate is good\n"); 55 | 56 | if ((r = file_set_size(f, strlen(msg))) < 0) 57 | panic("file_set_size 2: %e", r); 58 | assert(!(uvpt[PGNUM(f)] & PTE_D)); 59 | if ((r = file_get_block(f, 0, &blk)) < 0) 60 | panic("file_get_block 2: %e", r); 61 | strcpy(blk, msg); 62 | assert((uvpt[PGNUM(blk)] & PTE_D)); 63 | file_flush(f); 64 | assert(!(uvpt[PGNUM(blk)] & PTE_D)); 65 | assert(!(uvpt[PGNUM(f)] & PTE_D)); 66 | cprintf("file rewrite is good\n"); 67 | } 68 | -------------------------------------------------------------------------------- /fs/testshell.key: -------------------------------------------------------------------------------- 1 | # echo hello world | cat 2 | hello world 3 | # cat lorem 4 | Lorem ipsum dolor sit amet, consectetur 5 | adipisicing elit, sed do eiusmod tempor 6 | incididunt ut labore et dolore magna 7 | aliqua. Ut enim ad minim veniam, quis 8 | nostrud exercitation ullamco laboris 9 | nisi ut aliquip ex ea commodo consequat. 10 | Duis aute irure dolor in reprehenderit 11 | in voluptate velit esse cillum dolore eu 12 | fugiat nulla pariatur. Excepteur sint 13 | occaecat cupidatat non proident, sunt in 14 | culpa qui officia deserunt mollit anim 15 | id est laborum. 16 | # cat lorem |num 17 | 1 Lorem ipsum dolor sit amet, consectetur 18 | 2 adipisicing elit, sed do eiusmod tempor 19 | 3 incididunt ut labore et dolore magna 20 | 4 aliqua. Ut enim ad minim veniam, quis 21 | 5 nostrud exercitation ullamco laboris 22 | 6 nisi ut aliquip ex ea commodo consequat. 23 | 7 Duis aute irure dolor in reprehenderit 24 | 8 in voluptate velit esse cillum dolore eu 25 | 9 fugiat nulla pariatur. Excepteur sint 26 | 10 occaecat cupidatat non proident, sunt in 27 | 11 culpa qui officia deserunt mollit anim 28 | 12 id est laborum. 29 | # cat lorem |num |num |num |num |num 30 | 1 1 1 1 1 Lorem ipsum dolor sit amet, consectetur 31 | 2 2 2 2 2 adipisicing elit, sed do eiusmod tempor 32 | 3 3 3 3 3 incididunt ut labore et dolore magna 33 | 4 4 4 4 4 aliqua. Ut enim ad minim veniam, quis 34 | 5 5 5 5 5 nostrud exercitation ullamco laboris 35 | 6 6 6 6 6 nisi ut aliquip ex ea commodo consequat. 36 | 7 7 7 7 7 Duis aute irure dolor in reprehenderit 37 | 8 8 8 8 8 in voluptate velit esse cillum dolore eu 38 | 9 9 9 9 9 fugiat nulla pariatur. Excepteur sint 39 | 10 10 10 10 10 occaecat cupidatat non proident, sunt in 40 | 11 11 11 11 11 culpa qui officia deserunt mollit anim 41 | 12 12 12 12 12 id est laborum. 42 | # lsfd -1 43 | fd 0: name testshell.sh isdir 0 size 113 dev file 44 | fd 1: name isdir 0 size 32 dev pipe 45 | fd 3: name isdir 0 size 32 dev pipe 46 | # cat script 47 | echo This is from the script. 48 | cat lorem | num | cat 49 | echo These are my file descriptors. 50 | lsfd -1 51 | echo This is the end of the script. 52 | # sh