diff --git a/Makefile b/Makefile index 1424d7c..6c3df2b 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,14 @@ OBJS = \ trampoline.o \ trap.o \ syscall.o \ - sysproc.o + sysproc.o \ + bio.o \ + fs.o \ + log.o \ + sleeplock.o \ + file.o \ + pipe.o \ + ramdisk.o XXXOBJS = \ bio.o\ @@ -83,15 +90,15 @@ endif LDFLAGS = -z max-page-size=4096 -kernel: $(OBJS) entry.o kernel.ld +kernel: $(OBJS) entry.o kernel.ld initcode $(LD) $(LDFLAGS) -T kernel.ld -o kernel entry.o $(OBJS) $(OBJDUMP) -S kernel > kernel.asm $(OBJDUMP) -t kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernel.sym initcode: initcode.S $(CC) $(CFLAGS) -nostdinc -I. -c initcode.S - #$(LD) $(LDFLAGS) -N -e start -Ttext 0 -o initcode.out initcode.o - #$(OBJCOPY) -S -O binary initcode.out initcode + $(LD) $(LDFLAGS) -N -e start -Ttext 0 -o initcode.out initcode.o + $(OBJCOPY) -S -O binary initcode.out initcode $(OBJDUMP) -S initcode.o > initcode.asm tags: $(OBJS) entryother.S _init @@ -107,6 +114,9 @@ _%: %.o $(ULIB) $(OBJDUMP) -S $@ > $*.asm $(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym +usys.S : usys.pl + perl ./usys.pl > usys.S + _forktest: forktest.o $(ULIB) # forktest has less library code linked in - needs to be small # in order to be able to max out the proc table. @@ -171,7 +181,7 @@ ifndef CPUS CPUS := 1 endif QEMUOPTS = -machine virt -kernel kernel -m 3G -smp $(CPUS) -nographic -#QEMUOPTS += -initrd fs.img +QEMUOPTS += -initrd fs.img qemu: kernel $(QEMU) $(QEMUOPTS) diff --git a/bio.c b/bio.c index a45ff3e..90f9af9 100644 --- a/bio.c +++ b/bio.c @@ -19,10 +19,11 @@ // and needs to be written to disk. #include "types.h" -#include "defs.h" #include "param.h" #include "spinlock.h" #include "sleeplock.h" +#include "riscv.h" +#include "defs.h" #include "fs.h" #include "buf.h" @@ -100,7 +101,7 @@ bread(uint dev, uint blockno) b = bget(dev, blockno); if((b->flags & B_VALID) == 0) { - iderw(b); + ramdiskrw(b); } return b; } @@ -112,7 +113,7 @@ bwrite(struct buf *b) if(!holdingsleep(&b->lock)) panic("bwrite"); b->flags |= B_DIRTY; - iderw(b); + ramdiskrw(b); } // Release a locked buffer. diff --git a/defs.h b/defs.h index d86e495..efffc33 100644 --- a/defs.h +++ b/defs.h @@ -54,10 +54,10 @@ int readi(struct inode*, char*, uint, uint); void stati(struct inode*, struct stat*); int writei(struct inode*, char*, uint, uint); -// ide.c -void ideinit(void); -void ideintr(void); -void iderw(struct buf*); +// ramdisk.c +void ramdiskinit(void); +void ramdiskintr(void); +void ramdiskrw(struct buf*); // ioapic.c void ioapicenable(int irq, int cpu); diff --git a/file.c b/file.c index 24b32c2..6d3ffb3 100644 --- a/file.c +++ b/file.c @@ -3,6 +3,7 @@ // #include "types.h" +#include "riscv.h" #include "defs.h" #include "param.h" #include "fs.h" diff --git a/fs.c b/fs.c index feb59fe..ae96567 100644 --- a/fs.c +++ b/fs.c @@ -10,10 +10,10 @@ // are in sysfile.c. #include "types.h" +#include "riscv.h" #include "defs.h" #include "param.h" #include "stat.h" -#include "mmu.h" #include "proc.h" #include "spinlock.h" #include "sleeplock.h" @@ -180,7 +180,7 @@ iinit(int dev) } readsb(dev, &sb); - cprintf("sb: size %d nblocks %d ninodes %d nlog %d logstart %d\ + printf("sb: size %d nblocks %d ninodes %d nlog %d logstart %d\ inodestart %d bmap start %d\n", sb.size, sb.nblocks, sb.ninodes, sb.nlog, sb.logstart, sb.inodestart, sb.bmapstart); diff --git a/ide.c b/ide.c deleted file mode 100644 index b4c0b1f..0000000 --- a/ide.c +++ /dev/null @@ -1,168 +0,0 @@ -// Simple PIO-based (non-DMA) IDE driver code. - -#include "types.h" -#include "defs.h" -#include "param.h" -#include "memlayout.h" -#include "mmu.h" -#include "proc.h" -#include "x86.h" -#include "traps.h" -#include "spinlock.h" -#include "sleeplock.h" -#include "fs.h" -#include "buf.h" - -#define SECTOR_SIZE 512 -#define IDE_BSY 0x80 -#define IDE_DRDY 0x40 -#define IDE_DF 0x20 -#define IDE_ERR 0x01 - -#define IDE_CMD_READ 0x20 -#define IDE_CMD_WRITE 0x30 -#define IDE_CMD_RDMUL 0xc4 -#define IDE_CMD_WRMUL 0xc5 - -// idequeue points to the buf now being read/written to the disk. -// idequeue->qnext points to the next buf to be processed. -// You must hold idelock while manipulating queue. - -static struct spinlock idelock; -static struct buf *idequeue; - -static int havedisk1; -static void idestart(struct buf*); - -// Wait for IDE disk to become ready. -static int -idewait(int checkerr) -{ - int r; - - while(((r = inb(0x1f7)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY) - ; - if(checkerr && (r & (IDE_DF|IDE_ERR)) != 0) - return -1; - return 0; -} - -void -ideinit(void) -{ - int i; - - initlock(&idelock, "ide"); - ioapicenable(IRQ_IDE, ncpu - 1); - idewait(0); - - // Check if disk 1 is present - outb(0x1f6, 0xe0 | (1<<4)); - for(i=0; i<1000; i++){ - if(inb(0x1f7) != 0){ - havedisk1 = 1; - break; - } - } - - // Switch back to disk 0. - outb(0x1f6, 0xe0 | (0<<4)); -} - -// Start the request for b. Caller must hold idelock. -static void -idestart(struct buf *b) -{ - if(b == 0) - panic("idestart"); - if(b->blockno >= FSSIZE) - panic("incorrect blockno"); - int sector_per_block = BSIZE/SECTOR_SIZE; - int sector = b->blockno * sector_per_block; - int read_cmd = (sector_per_block == 1) ? IDE_CMD_READ : IDE_CMD_RDMUL; - int write_cmd = (sector_per_block == 1) ? IDE_CMD_WRITE : IDE_CMD_WRMUL; - - if (sector_per_block > 7) panic("idestart"); - - idewait(0); - outb(0x3f6, 0); // generate interrupt - outb(0x1f2, sector_per_block); // number of sectors - outb(0x1f3, sector & 0xff); - outb(0x1f4, (sector >> 8) & 0xff); - outb(0x1f5, (sector >> 16) & 0xff); - outb(0x1f6, 0xe0 | ((b->dev&1)<<4) | ((sector>>24)&0x0f)); - if(b->flags & B_DIRTY){ - outb(0x1f7, write_cmd); - outsl(0x1f0, b->data, BSIZE/4); - } else { - outb(0x1f7, read_cmd); - } -} - -// Interrupt handler. -void -ideintr(void) -{ - struct buf *b; - - // First queued buffer is the active request. - acquire(&idelock); - - if((b = idequeue) == 0){ - release(&idelock); - return; - } - idequeue = b->qnext; - - // Read data if needed. - if(!(b->flags & B_DIRTY) && idewait(1) >= 0) - insl(0x1f0, b->data, BSIZE/4); - - // Wake process waiting for this buf. - b->flags |= B_VALID; - b->flags &= ~B_DIRTY; - wakeup(b); - - // Start disk on next buf in queue. - if(idequeue != 0) - idestart(idequeue); - - release(&idelock); -} - -//PAGEBREAK! -// Sync buf with disk. -// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID. -// Else if B_VALID is not set, read buf from disk, set B_VALID. -void -iderw(struct buf *b) -{ - struct buf **pp; - - if(!holdingsleep(&b->lock)) - panic("iderw: buf not locked"); - if((b->flags & (B_VALID|B_DIRTY)) == B_VALID) - panic("iderw: nothing to do"); - if(b->dev != 0 && !havedisk1) - panic("iderw: ide disk 1 not present"); - - acquire(&idelock); //DOC:acquire-lock - - // Append b to idequeue. - b->qnext = 0; - for(pp=&idequeue; *pp; pp=&(*pp)->qnext) //DOC:insert-queue - ; - *pp = b; - - // Start disk if necessary. - if(idequeue == b) - idestart(b); - - // Wait for request to finish. - while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){ - sleep(b, &idelock); - } - - - release(&idelock); -} diff --git a/kalloc.c b/kalloc.c index c943e5e..cfbbae4 100644 --- a/kalloc.c +++ b/kalloc.c @@ -27,6 +27,8 @@ void kinit() { initlock(&kmem.lock, "kmem"); + if(PHYSTOP > RAMDISK) + panic("kinit"); freerange(end, (void*)PHYSTOP); } diff --git a/log.c b/log.c index a64c0f6..c8f7e62 100644 --- a/log.c +++ b/log.c @@ -1,4 +1,5 @@ #include "types.h" +#include "riscv.h" #include "defs.h" #include "param.h" #include "spinlock.h" diff --git a/main.c b/main.c index 04e822a..d4a30f0 100644 --- a/main.c +++ b/main.c @@ -17,11 +17,9 @@ main() kvminit(); // kernel page table procinit(); // process table trapinit(); // trap vectors -#if 0 binit(); // buffer cache fileinit(); // file table - ideinit(); // disk -#endif + ramdiskinit(); // disk userinit(); // first user process scheduler(); diff --git a/memlayout.h b/memlayout.h index 798621e..9bc9c5d 100644 --- a/memlayout.h +++ b/memlayout.h @@ -4,6 +4,8 @@ // 00001000 -- boot ROM, provided by qemu // 10000000 -- uart0 registers // 80000000 -- boot ROM jumps here in machine mode +// -kernel loads the kernel here +// 88000000 -- -initrd fs.img ramdisk image. // unused RAM after 80000000. // the kernel uses physical memory thus: @@ -14,6 +16,8 @@ // registers start here in physical memory. #define UART0 0x10000000L +#define RAMDISK 0x88000000 + // the kernel expects there to be RAM // for use by the kernel and user pages // from physical address 0x80000000 to PHYSTOP. diff --git a/pipe.c b/pipe.c index e9abe7f..1274a3a 100644 --- a/pipe.c +++ b/pipe.c @@ -1,7 +1,7 @@ #include "types.h" +#include "riscv.h" #include "defs.h" #include "param.h" -#include "mmu.h" #include "proc.h" #include "fs.h" #include "spinlock.h" diff --git a/proc.c b/proc.c index e574db0..a099e98 100644 --- a/proc.c +++ b/proc.c @@ -116,16 +116,13 @@ found: return p; } -// XXX hack because I don't know how to incorporate initcode -// into the kernel binary. just the exec system call, no arguments. -// manually copied from initcode.asm. +// a user program that calls exec("/init") +// od -t xC initcode unsigned char initcode[] = { - 0x85, 0x48, // li a7, 1 -- SYS_fork - 0x73, 0x00, 0x00, 0x00, // ecall - 0x8d, 0x48, // li a7, 3 -- SYS_wait - 0x73, 0x00, 0x00, 0x00, // ecall - 0x89, 0x48, // li a7, 2 -- SYS_exit - 0x73, 0x00, 0x00, 0x00, // ecall + 0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x05, 0x02, 0x97, 0x05, 0x00, 0x00, 0x93, 0x85, 0x05, 0x02, + 0x9d, 0x48, 0x73, 0x00, 0x00, 0x00, 0x89, 0x48, 0x73, 0x00, 0x00, 0x00, 0xef, 0xf0, 0xbf, 0xff, + 0x2f, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 }; //PAGEBREAK: 32 @@ -146,8 +143,7 @@ userinit(void) p->tf->sp = PGSIZE; safestrcpy(p->name, "initcode", sizeof(p->name)); - // XXX riscv - //p->cwd = namei("/"); + p->cwd = namei("/"); // this assignment to p->state lets other cores // run this process. the acquire forces the above @@ -210,13 +206,11 @@ fork(void) // Cause fork to return 0 in the child. np->tf->a0 = 0; -#if 0 // XXX riscv // increment reference counts on open file descriptors. for(i = 0; i < NOFILE; i++) if(p->ofile[i]) np->ofile[i] = filedup(p->ofile[i]); np->cwd = idup(p->cwd); -#endif safestrcpy(np->name, p->name, sizeof(p->name)); @@ -244,7 +238,6 @@ exit(void) if(p == initproc) panic("init exiting"); -#if 0 // XXX riscv // Close all open files. for(fd = 0; fd < NOFILE; fd++){ if(p->ofile[fd]){ @@ -256,7 +249,6 @@ exit(void) begin_op(); iput(p->cwd); end_op(); -#endif p->cwd = 0; acquire(&ptable.lock); @@ -423,9 +415,8 @@ forkret(void) // of a regular process (e.g., they call sleep), and thus cannot // be run from main(). first = 0; - // XXX riscv - //iinit(ROOTDEV); - //initlog(ROOTDEV); + iinit(ROOTDEV); + initlog(ROOTDEV); } usertrapret(); diff --git a/ramdisk.c b/ramdisk.c new file mode 100644 index 0000000..9901294 --- /dev/null +++ b/ramdisk.c @@ -0,0 +1,45 @@ +// +// ramdisk that uses the disk image loaded by qemu -rdinit fs.img +// + +#include "types.h" +#include "riscv.h" +#include "defs.h" +#include "param.h" +#include "memlayout.h" +#include "spinlock.h" +#include "sleeplock.h" +#include "fs.h" +#include "buf.h" + +void +ramdiskinit(void) +{ +} + +// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID. +// Else if B_VALID is not set, read buf from disk, set B_VALID. +void +ramdiskrw(struct buf *b) +{ + if(!holdingsleep(&b->lock)) + panic("ramdiskrw: buf not locked"); + if((b->flags & (B_VALID|B_DIRTY)) == B_VALID) + panic("ramdiskrw: nothing to do"); + + if(b->blockno >= FSSIZE) + panic("ramdiskrw: blockno too big"); + + uint64 diskaddr = b->blockno * BSIZE; + char *addr = (char *)RAMDISK + diskaddr; + + if(b->flags & B_DIRTY){ + // write + memmove(addr, b->data, BSIZE); + b->flags &= ~B_DIRTY; + } else { + // read + memmove(b->data, addr, BSIZE); + b->flags |= B_VALID; + } +} diff --git a/sleeplock.c b/sleeplock.c index e0750ea..b490370 100644 --- a/sleeplock.c +++ b/sleeplock.c @@ -1,11 +1,10 @@ // Sleeping locks #include "types.h" +#include "riscv.h" #include "defs.h" #include "param.h" -#include "x86.h" #include "memlayout.h" -#include "mmu.h" #include "proc.h" #include "spinlock.h" #include "sleeplock.h" diff --git a/trapasm.S b/trapasm.S deleted file mode 100644 index 6b6b567..0000000 --- a/trapasm.S +++ /dev/null @@ -1,132 +0,0 @@ -#include "param.h" -#include "x86.h" -#include "mmu.h" - -# the offset of cs in trapframe (i.e., tf->cs - tf) -#define CSOFF 144 - -# vectors.S sends all traps here. -.globl alltraps -alltraps: - # Build trap frame. - push %r15 - push %r14 - push %r13 - push %r12 - push %r11 - push %r10 - push %r9 - push %r8 - push %rdi - push %rsi - push %rbp - push %rdx - push %rcx - push %rbx - push %rax - - cmpw $SEG_KCODE, CSOFF(%rsp) # compare to saved cs - jz 1f - swapgs - -1:mov %rsp, %rdi # frame in arg1 - call trap - -# Return falls through to trapret... -.globl trapret -trapret: - cli - cmpw $SEG_KCODE, CSOFF(%rsp) # compare to saved cs - jz 1f - swapgs - -1:pop %rax - pop %rbx - pop %rcx - pop %rdx - pop %rbp - pop %rsi - pop %rdi - pop %r8 - pop %r9 - pop %r10 - pop %r11 - pop %r12 - pop %r13 - pop %r14 - pop %r15 - - add $16, %rsp # discard trapnum and errorcode - iretq - -#PAGEBREAK! - -# syscall jumps here after syscall instruction -.globl sysentry -sysentry: # Build syscall frame. - // load kernel stack address - swapgs - movq %rax, %gs:0 // save %rax in syscallno of cpu entry - movq %rsp, %gs:8 // user sp - movq %gs:16, %rax // proc entry - - movq %ss:0(%rax), %rax // load kstack from proc - addq $(KSTACKSIZE), %rax - - movq %rax, %rsp - movq %gs:0, %rax // restore rax - - push %gs:8 - push %rcx - push %r11 - push %rax - - push %rbp - push %rbx - push %r12 - push %r13 - push %r14 - push %r15 - - push %r9 - push %r8 - push %r10 - push %rdx - push %rsi - push %rdi - - mov %rsp, %rdi # frame in arg1 - - call syscall - # fall through to sysexit - -.globl sysexit -sysexit: - # to make sure we don't get any interrupts on the user stack while in - # supervisor mode. insufficient? (see vunerability reports for sysret) - cli - - pop %rdi - pop %rsi - pop %rdx - pop %r10 - pop %r8 - pop %r9 - - pop %r15 - pop %r14 - pop %r13 - pop %r12 - pop %rbx - pop %rbp - - pop %rax - pop %r11 - pop %rcx - - mov (%rsp),%rsp # switch to the user stack - # there are two more values on the stack, but we don't care about them - swapgs - - sysretq - diff --git a/ulib.c b/ulib.c index 8e1e1a2..532fe42 100644 --- a/ulib.c +++ b/ulib.c @@ -2,7 +2,6 @@ #include "stat.h" #include "fcntl.h" #include "user.h" -#include "x86.h" char* strcpy(char *s, const char *t) @@ -36,7 +35,11 @@ strlen(const char *s) void* memset(void *dst, int c, uint n) { - stosb(dst, c, n); + char *cdst = (char *) dst; + int i; + for(i = 0; i < n; i++){ + cdst[i] = c; + } return dst; } diff --git a/usertests.c b/usertests.c index 3cd8b34..292319e 100644 --- a/usertests.c +++ b/usertests.c @@ -5,7 +5,6 @@ #include "fs.h" #include "fcntl.h" #include "syscall.h" -#include "traps.h" #include "memlayout.h" char buf[8192]; @@ -1713,35 +1712,6 @@ fsfull() printf(1, "fsfull test finished\n"); } -void -uio() -{ - #define RTC_ADDR 0x70 - #define RTC_DATA 0x71 - - ushort port = 0; - uchar val = 0; - int pid; - - printf(1, "uio test\n"); - pid = fork(); - if(pid == 0){ - port = RTC_ADDR; - val = 0x09; /* year */ - /* http://wiki.osdev.org/Inline_Assembly/Examples */ - asm volatile("outb %0,%1"::"a"(val), "d" (port)); - port = RTC_DATA; - asm volatile("inb %1,%0" : "=a" (val) : "d" (port)); - printf(1, "uio: uio succeeded; test FAILED\n"); - exit(); - } else if(pid < 0){ - printf (1, "fork failed\n"); - exit(); - } - wait(); - printf(1, "uio test done\n"); -} - void argptest() { int fd; @@ -1813,8 +1783,6 @@ main(int argc, char *argv[]) forktest(); bigdir(); // slow - uio(); - exectest(); exit(); diff --git a/usys.S b/usys.S deleted file mode 100644 index 69935e7..0000000 --- a/usys.S +++ /dev/null @@ -1,31 +0,0 @@ -#include "syscall.h" -#include "traps.h" - -#define SYSCALL(name) \ - .globl name; \ - name: \ - mov $SYS_ ## name, %rax; \ - syscall; \ - ret - -SYSCALL(fork) -SYSCALL(exit) -SYSCALL(wait) -SYSCALL(pipe) -SYSCALL(read) -SYSCALL(write) -SYSCALL(close) -SYSCALL(kill) -SYSCALL(exec) -SYSCALL(open) -SYSCALL(mknod) -SYSCALL(unlink) -SYSCALL(fstat) -SYSCALL(link) -SYSCALL(mkdir) -SYSCALL(chdir) -SYSCALL(dup) -SYSCALL(getpid) -SYSCALL(sbrk) -SYSCALL(sleep) -SYSCALL(uptime) diff --git a/usys.pl b/usys.pl new file mode 100755 index 0000000..f8d47d5 --- /dev/null +++ b/usys.pl @@ -0,0 +1,38 @@ +#!/usr/bin/perl -w + +# Generate usys.S, the stubs for syscalls. + +print "# generated by usys.pl - do not edit\n"; + +print "#include \"syscall.h\"\n"; + +sub entry { + my $name = shift; + print ".global $name\n"; + print "${name}:\n"; + print " li a7, SYS_${name}\n"; + print " ecall\n"; + print " ret\n"; +} + +entry("fork"); +entry("exit"); +entry("wait"); +entry("pipe"); +entry("read"); +entry("write"); +entry("close"); +entry("kill"); +entry("exec"); +entry("open"); +entry("mknod"); +entry("unlink"); +entry("fstat"); +entry("link"); +entry("mkdir"); +entry("chdir"); +entry("dup"); +entry("getpid"); +entry("sbrk"); +entry("sleep"); +entry("uptime"); diff --git a/vm.c b/vm.c index 8c2ccb3..a0d6569 100644 --- a/vm.c +++ b/vm.c @@ -4,6 +4,7 @@ #include "elf.h" #include "riscv.h" #include "defs.h" +#include "fs.h" /* * the kernel's page table. @@ -37,6 +38,10 @@ kvminit() mappages(kernel_pagetable, (uint64)etext, PHYSTOP-(uint64)etext, (uint64)etext, PTE_R | PTE_W); + // map the qemu -initrd fs.img ramdisk + mappages(kernel_pagetable, RAMDISK, FSSIZE * BSIZE, + RAMDISK, PTE_R | PTE_W); + // map the trampoline for trap entry/exit to // the highest virtual address in the kernel. mappages(kernel_pagetable, TRAMPOLINE, PGSIZE,