-initrd fs.img, ramdisk.c, file system

This commit is contained in:
Robert Morris 2019-05-31 11:45:42 -04:00
parent 2ec1959fd1
commit 5d34fa2a48
20 changed files with 138 additions and 403 deletions

View file

@ -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)

7
bio.c
View file

@ -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.

8
defs.h
View file

@ -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);

1
file.c
View file

@ -3,6 +3,7 @@
//
#include "types.h"
#include "riscv.h"
#include "defs.h"
#include "param.h"
#include "fs.h"

4
fs.c
View file

@ -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);

168
ide.c
View file

@ -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);
}

View file

@ -27,6 +27,8 @@ void
kinit()
{
initlock(&kmem.lock, "kmem");
if(PHYSTOP > RAMDISK)
panic("kinit");
freerange(end, (void*)PHYSTOP);
}

1
log.c
View file

@ -1,4 +1,5 @@
#include "types.h"
#include "riscv.h"
#include "defs.h"
#include "param.h"
#include "spinlock.h"

4
main.c
View file

@ -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();

View file

@ -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.

2
pipe.c
View file

@ -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"

27
proc.c
View file

@ -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();

45
ramdisk.c Normal file
View file

@ -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;
}
}

View file

@ -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"

132
trapasm.S
View file

@ -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

7
ulib.c
View file

@ -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;
}

View file

@ -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();

31
usys.S
View file

@ -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)

38
usys.pl Executable file
View file

@ -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");

5
vm.c
View file

@ -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,