pagetable lab initialized

This commit is contained in:
2025-05-06 11:20:36 +08:00
parent 0e751d690f
commit 38997cbef6
42 changed files with 1963 additions and 1154 deletions

View File

@@ -1,3 +1,7 @@
#ifdef LAB_MMAP
typedef unsigned long size_t;
typedef long int off_t;
#endif
struct buf;
struct context;
struct file;
@@ -10,183 +14,226 @@ struct stat;
struct superblock;
// bio.c
void binit(void);
struct buf *bread(uint, uint);
void brelse(struct buf *);
void bwrite(struct buf *);
void bpin(struct buf *);
void bunpin(struct buf *);
void binit(void);
struct buf* bread(uint, uint);
void brelse(struct buf*);
void bwrite(struct buf*);
void bpin(struct buf*);
void bunpin(struct buf*);
// console.c
void consoleinit(void);
void consoleintr(int);
void consputc(int);
void consoleinit(void);
void consoleintr(int);
void consputc(int);
// exec.c
int exec(char *, char **);
int exec(char*, char**);
// file.c
struct file *filealloc(void);
void fileclose(struct file *);
struct file *filedup(struct file *);
void fileinit(void);
int fileread(struct file *, uint64, int n);
int filestat(struct file *, uint64 addr);
int filewrite(struct file *, uint64, int n);
struct file* filealloc(void);
void fileclose(struct file*);
struct file* filedup(struct file*);
void fileinit(void);
int fileread(struct file*, uint64, int n);
int filestat(struct file*, uint64 addr);
int filewrite(struct file*, uint64, int n);
// fs.c
void fsinit(int);
int dirlink(struct inode *, char *, uint);
struct inode *dirlookup(struct inode *, char *, uint *);
struct inode *ialloc(uint, short);
struct inode *idup(struct inode *);
void iinit();
void ilock(struct inode *);
void iput(struct inode *);
void iunlock(struct inode *);
void iunlockput(struct inode *);
void iupdate(struct inode *);
int namecmp(const char *, const char *);
struct inode *namei(char *);
struct inode *nameiparent(char *, char *);
int readi(struct inode *, int, uint64, uint, uint);
void stati(struct inode *, struct stat *);
int writei(struct inode *, int, uint64, uint, uint);
void itrunc(struct inode *);
void fsinit(int);
int dirlink(struct inode*, char*, uint);
struct inode* dirlookup(struct inode*, char*, uint*);
struct inode* ialloc(uint, short);
struct inode* idup(struct inode*);
void iinit();
void ilock(struct inode*);
void iput(struct inode*);
void iunlock(struct inode*);
void iunlockput(struct inode*);
void iupdate(struct inode*);
int namecmp(const char*, const char*);
struct inode* namei(char*);
struct inode* nameiparent(char*, char*);
int readi(struct inode*, int, uint64, uint, uint);
void stati(struct inode*, struct stat*);
int writei(struct inode*, int, uint64, uint, uint);
void itrunc(struct inode*);
// ramdisk.c
void ramdiskinit(void);
void ramdiskintr(void);
void ramdiskrw(struct buf *);
void ramdiskinit(void);
void ramdiskintr(void);
void ramdiskrw(struct buf*);
// kalloc.c
void *kalloc(void);
void kfree(void *);
void kinit(void);
int freemem(void);
void* kalloc(void);
void kfree(void *);
void kinit(void);
// log.c
void initlog(int, struct superblock *);
void log_write(struct buf *);
void begin_op(void);
void end_op(void);
void initlog(int, struct superblock*);
void log_write(struct buf*);
void begin_op(void);
void end_op(void);
// pipe.c
int pipealloc(struct file **, struct file **);
void pipeclose(struct pipe *, int);
int piperead(struct pipe *, uint64, int);
int pipewrite(struct pipe *, uint64, int);
int pipealloc(struct file**, struct file**);
void pipeclose(struct pipe*, int);
int piperead(struct pipe*, uint64, int);
int pipewrite(struct pipe*, uint64, int);
// printf.c
void printf(char *, ...);
void panic(char *) __attribute__((noreturn));
void printfinit(void);
int printf(char*, ...) __attribute__ ((format (printf, 1, 2)));
void panic(char*) __attribute__((noreturn));
void printfinit(void);
// proc.c
int cpuid(void);
void exit(int);
int fork(void);
int growproc(int);
void proc_mapstacks(pagetable_t);
pagetable_t proc_pagetable(struct proc *);
void proc_freepagetable(pagetable_t, uint64);
int kill(int);
int killed(struct proc *);
void setkilled(struct proc *);
struct cpu *mycpu(void);
struct cpu *getmycpu(void);
struct proc *myproc();
void procinit(void);
void scheduler(void) __attribute__((noreturn));
void sched(void);
void sleep(void *, struct spinlock *);
void userinit(void);
int wait(uint64);
void wakeup(void *);
void yield(void);
int either_copyout(int user_dst, uint64 dst, void *src, uint64 len);
int either_copyin(void *dst, int user_src, uint64 src, uint64 len);
void procdump(void);
int proc_size(void);
int update_load(void);
int cpuid(void);
void exit(int);
int fork(void);
int growproc(int);
void proc_mapstacks(pagetable_t);
pagetable_t proc_pagetable(struct proc *);
void proc_freepagetable(pagetable_t, uint64);
int kill(int);
int killed(struct proc*);
void setkilled(struct proc*);
struct cpu* mycpu(void);
struct cpu* getmycpu(void);
struct proc* myproc();
void procinit(void);
void scheduler(void) __attribute__((noreturn));
void sched(void);
void sleep(void*, struct spinlock*);
void userinit(void);
int wait(uint64);
void wakeup(void*);
void yield(void);
int either_copyout(int user_dst, uint64 dst, void *src, uint64 len);
int either_copyin(void *dst, int user_src, uint64 src, uint64 len);
void procdump(void);
// swtch.S
void swtch(struct context *, struct context *);
void swtch(struct context*, struct context*);
// spinlock.c
void acquire(struct spinlock *);
int holding(struct spinlock *);
void initlock(struct spinlock *, char *);
void release(struct spinlock *);
void push_off(void);
void pop_off(void);
void acquire(struct spinlock*);
int holding(struct spinlock*);
void initlock(struct spinlock*, char*);
void release(struct spinlock*);
void push_off(void);
void pop_off(void);
int atomic_read4(int *addr);
#ifdef LAB_LOCK
void freelock(struct spinlock*);
#endif
// sleeplock.c
void acquiresleep(struct sleeplock *);
void releasesleep(struct sleeplock *);
int holdingsleep(struct sleeplock *);
void initsleeplock(struct sleeplock *, char *);
void acquiresleep(struct sleeplock*);
void releasesleep(struct sleeplock*);
int holdingsleep(struct sleeplock*);
void initsleeplock(struct sleeplock*, char*);
// string.c
int memcmp(const void *, const void *, uint);
void *memmove(void *, const void *, uint);
void *memset(void *, int, uint);
char *safestrcpy(char *, const char *, int);
int strlen(const char *);
int strncmp(const char *, const char *, uint);
char *strncpy(char *, const char *, int);
int memcmp(const void*, const void*, uint);
void* memmove(void*, const void*, uint);
void* memset(void*, int, uint);
char* safestrcpy(char*, const char*, int);
int strlen(const char*);
int strncmp(const char*, const char*, uint);
char* strncpy(char*, const char*, int);
// syscall.c
void argint(int, int *);
int argstr(int, char *, int);
void argaddr(int, uint64 *);
int fetchstr(uint64, char *, int);
int fetchaddr(uint64, uint64 *);
void syscall();
void argint(int, int*);
int argstr(int, char*, int);
void argaddr(int, uint64 *);
int fetchstr(uint64, char*, int);
int fetchaddr(uint64, uint64*);
void syscall();
// trap.c
extern uint ticks;
void trapinit(void);
void trapinithart(void);
extern uint ticks;
void trapinit(void);
void trapinithart(void);
extern struct spinlock tickslock;
void usertrapret(void);
void usertrapret(void);
// uart.c
void uartinit(void);
void uartintr(void);
void uartputc(int);
void uartputc_sync(int);
int uartgetc(void);
void uartinit(void);
void uartintr(void);
void uartputc(int);
void uartputc_sync(int);
int uartgetc(void);
// vm.c
void kvminit(void);
void kvminithart(void);
void kvmmap(pagetable_t, uint64, uint64, uint64, int);
int mappages(pagetable_t, uint64, uint64, uint64, int);
pagetable_t uvmcreate(void);
void uvmfirst(pagetable_t, uchar *, uint);
uint64 uvmalloc(pagetable_t, uint64, uint64, int);
uint64 uvmdealloc(pagetable_t, uint64, uint64);
int uvmcopy(pagetable_t, pagetable_t, uint64);
void uvmfree(pagetable_t, uint64);
void uvmunmap(pagetable_t, uint64, uint64, int);
void uvmclear(pagetable_t, uint64);
pte_t *walk(pagetable_t, uint64, int);
uint64 walkaddr(pagetable_t, uint64);
int copyout(pagetable_t, uint64, char *, uint64);
int copyin(pagetable_t, char *, uint64, uint64);
int copyinstr(pagetable_t, char *, uint64, uint64);
void kvminit(void);
void kvminithart(void);
void kvmmap(pagetable_t, uint64, uint64, uint64, int);
int mappages(pagetable_t, uint64, uint64, uint64, int);
pagetable_t uvmcreate(void);
void uvmfirst(pagetable_t, uchar *, uint);
uint64 uvmalloc(pagetable_t, uint64, uint64, int);
uint64 uvmdealloc(pagetable_t, uint64, uint64);
int uvmcopy(pagetable_t, pagetable_t, uint64);
void uvmfree(pagetable_t, uint64);
void uvmunmap(pagetable_t, uint64, uint64, int);
void uvmclear(pagetable_t, uint64);
pte_t * walk(pagetable_t, uint64, int);
uint64 walkaddr(pagetable_t, uint64);
int copyout(pagetable_t, uint64, char *, uint64);
int copyin(pagetable_t, char *, uint64, uint64);
int copyinstr(pagetable_t, char *, uint64, uint64);
#if defined(LAB_PGTBL) || defined(SOL_MMAP)
void vmprint(pagetable_t);
#endif
#ifdef LAB_PGTBL
pte_t* pgpte(pagetable_t, uint64);
#endif
// plic.c
void plicinit(void);
void plicinithart(void);
int plic_claim(void);
void plic_complete(int);
void plicinit(void);
void plicinithart(void);
int plic_claim(void);
void plic_complete(int);
// virtio_disk.c
void virtio_disk_init(void);
void virtio_disk_rw(struct buf *, int);
void virtio_disk_intr(void);
void virtio_disk_init(void);
void virtio_disk_rw(struct buf *, int);
void virtio_disk_intr(void);
// number of elements in fixed-size array
#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
#ifdef LAB_PGTBL
// vmcopyin.c
int copyin_new(pagetable_t, char *, uint64, uint64);
int copyinstr_new(pagetable_t, char *, uint64, uint64);
#endif
#ifdef LAB_LOCK
// stats.c
void statsinit(void);
void statsinc(void);
// sprintf.c
int snprintf(char*, unsigned long, const char*, ...);
#endif
#ifdef KCSAN
void kcsaninit();
#endif
#ifdef LAB_NET
// pci.c
void pci_init();
// e1000.c
void e1000_init(uint32 *);
void e1000_intr(void);
int e1000_transmit(char *, int);
// net.c
void netinit(void);
void net_rx(char *buf, int len);
#endif

View File

@@ -75,17 +75,17 @@ exec(char *path, char **argv)
p = myproc();
uint64 oldsz = p->sz;
// Allocate two pages at the next page boundary.
// Allocate some pages at the next page boundary.
// Make the first inaccessible as a stack guard.
// Use the second as the user stack.
// Use the rest as the user stack.
sz = PGROUNDUP(sz);
uint64 sz1;
if((sz1 = uvmalloc(pagetable, sz, sz + 2*PGSIZE, PTE_W)) == 0)
if((sz1 = uvmalloc(pagetable, sz, sz + (USERSTACK+1)*PGSIZE, PTE_W)) == 0)
goto bad;
sz = sz1;
uvmclear(pagetable, sz-2*PGSIZE);
uvmclear(pagetable, sz-(USERSTACK+1)*PGSIZE);
sp = sz;
stackbase = sp - PGSIZE;
stackbase = sp - USERSTACK*PGSIZE;
// Push argument strings, prepare rest of stack in ustack.
for(argc = 0; argv[argc]; argc++) {

View File

@@ -1,9 +1,9 @@
// On-disk file system format.
// Both the kernel and user programs use this header file.
#include "kernel/types.h"
#define ROOTINO 1 // root i-number
#define BSIZE 1024 // block size
#define ROOTINO 1 // root i-number
#define BSIZE 1024 // block size
// Disk layout:
// [ boot block | super block | log | inode blocks |
@@ -12,14 +12,14 @@
// mkfs computes the super block and builds an initial file system. The
// super block describes the disk layout:
struct superblock {
uint magic; // Must be FSMAGIC
uint size; // Size of file system image (blocks)
uint nblocks; // Number of data blocks
uint ninodes; // Number of inodes.
uint nlog; // Number of log blocks
uint logstart; // Block number of first log block
uint inodestart; // Block number of first inode block
uint bmapstart; // Block number of first free map block
uint magic; // Must be FSMAGIC
uint size; // Size of file system image (blocks)
uint nblocks; // Number of data blocks
uint ninodes; // Number of inodes.
uint nlog; // Number of log blocks
uint logstart; // Block number of first log block
uint inodestart; // Block number of first inode block
uint bmapstart; // Block number of first free map block
};
#define FSMAGIC 0x10203040
@@ -30,25 +30,25 @@ struct superblock {
// On-disk inode structure
struct dinode {
short type; // File type
short major; // Major device number (T_DEVICE only)
short minor; // Minor device number (T_DEVICE only)
short nlink; // Number of links to inode in file system
uint size; // Size of file (bytes)
uint addrs[NDIRECT + 1]; // Data block addresses
short type; // File type
short major; // Major device number (T_DEVICE only)
short minor; // Minor device number (T_DEVICE only)
short nlink; // Number of links to inode in file system
uint size; // Size of file (bytes)
uint addrs[NDIRECT+1]; // Data block addresses
};
// Inodes per block.
#define IPB (BSIZE / sizeof(struct dinode))
#define IPB (BSIZE / sizeof(struct dinode))
// Block containing inode i
#define IBLOCK(i, sb) ((i) / IPB + sb.inodestart)
#define IBLOCK(i, sb) ((i) / IPB + sb.inodestart)
// Bitmap bits per block
#define BPB (BSIZE * 8)
#define BPB (BSIZE*8)
// Block of free map containing bit for block b
#define BBLOCK(b, sb) ((b) / BPB + sb.bmapstart)
#define BBLOCK(b, sb) ((b)/BPB + sb.bmapstart)
// Directory is a file containing a sequence of dirent structures.
#define DIRSIZ 14
@@ -57,3 +57,4 @@ struct dirent {
ushort inum;
char name[DIRSIZ];
};

View File

@@ -7,7 +7,6 @@
#include "memlayout.h"
#include "spinlock.h"
#include "riscv.h"
#include "proc.h"
#include "defs.h"
void freerange(void *pa_start, void *pa_end);
@@ -81,17 +80,3 @@ kalloc(void)
memset((char*)r, 5, PGSIZE); // fill with junk
return (void*)r;
}
int
freemem(void)
{
struct run* p = kmem.freelist;
uint64 num = 0;
while (p) {
num += 1;
p = p->next;
}
return num * PGSIZE;
}

View File

@@ -3,7 +3,7 @@
# mode come here.
#
# the current stack is a kernel stack.
# push all registers, call kerneltrap().
# push registers, call kerneltrap().
# when kerneltrap() returns, restore registers, return.
#
.globl kerneltrap
@@ -13,7 +13,7 @@ kernelvec:
# make room to save registers.
addi sp, sp, -256
# save the registers.
# save caller-saved registers.
sd ra, 0(sp)
sd sp, 8(sp)
sd gp, 16(sp)
@@ -21,8 +21,6 @@ kernelvec:
sd t0, 32(sp)
sd t1, 40(sp)
sd t2, 48(sp)
sd s0, 56(sp)
sd s1, 64(sp)
sd a0, 72(sp)
sd a1, 80(sp)
sd a2, 88(sp)
@@ -31,16 +29,6 @@ kernelvec:
sd a5, 112(sp)
sd a6, 120(sp)
sd a7, 128(sp)
sd s2, 136(sp)
sd s3, 144(sp)
sd s4, 152(sp)
sd s5, 160(sp)
sd s6, 168(sp)
sd s7, 176(sp)
sd s8, 184(sp)
sd s9, 192(sp)
sd s10, 200(sp)
sd s11, 208(sp)
sd t3, 216(sp)
sd t4, 224(sp)
sd t5, 232(sp)
@@ -57,8 +45,6 @@ kernelvec:
ld t0, 32(sp)
ld t1, 40(sp)
ld t2, 48(sp)
ld s0, 56(sp)
ld s1, 64(sp)
ld a0, 72(sp)
ld a1, 80(sp)
ld a2, 88(sp)
@@ -67,16 +53,6 @@ kernelvec:
ld a5, 112(sp)
ld a6, 120(sp)
ld a7, 128(sp)
ld s2, 136(sp)
ld s3, 144(sp)
ld s4, 152(sp)
ld s5, 160(sp)
ld s6, 168(sp)
ld s7, 176(sp)
ld s8, 184(sp)
ld s9, 192(sp)
ld s10, 200(sp)
ld s11, 208(sp)
ld t3, 216(sp)
ld t4, 224(sp)
ld t5, 232(sp)
@@ -86,39 +62,3 @@ kernelvec:
# return to whatever we were doing in the kernel.
sret
#
# machine-mode timer interrupt.
#
.globl timervec
.align 4
timervec:
# start.c has set up the memory that mscratch points to:
# scratch[0,8,16] : register save area.
# scratch[24] : address of CLINT's MTIMECMP register.
# scratch[32] : desired interval between interrupts.
csrrw a0, mscratch, a0
sd a1, 0(a0)
sd a2, 8(a0)
sd a3, 16(a0)
# schedule the next timer interrupt
# by adding interval to mtimecmp.
ld a1, 24(a0) # CLINT_MTIMECMP(hart)
ld a2, 32(a0) # interval
ld a3, 0(a1)
add a3, a3, a2
sd a3, 0(a1)
# arrange for a supervisor software interrupt
# after this handler returns.
li a1, 2
csrw sip, a1
ld a3, 16(a0)
ld a2, 8(a0)
ld a1, 0(a0)
csrrw a0, mscratch, a0
mret

View File

@@ -25,10 +25,9 @@
#define VIRTIO0 0x10001000
#define VIRTIO0_IRQ 1
// core local interruptor (CLINT), which contains the timer.
#define CLINT 0x2000000L
#define CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 8*(hartid))
#define CLINT_MTIME (CLINT + 0xBFF8) // cycles since boot.
#ifdef LAB_NET
#define E1000_IRQ 33
#endif
// qemu puts platform-level interrupt controller (PLIC) here.
#define PLIC 0x0c000000L
@@ -50,7 +49,7 @@
// map kernel stacks beneath the trampoline,
// each surrounded by invalid guard pages.
#define KSTACK(p) (TRAMPOLINE - ((p)+1)* 2*PGSIZE)
#define KSTACK(p) (TRAMPOLINE - (p)*2*PGSIZE - 3*PGSIZE)
// User memory layout.
// Address zero first:
@@ -59,6 +58,14 @@
// fixed-size stack
// expandable heap
// ...
// USYSCALL (shared with kernel)
// TRAPFRAME (p->trapframe, used by the trampoline)
// TRAMPOLINE (the same page as in the kernel)
#define TRAPFRAME (TRAMPOLINE - PGSIZE)
#ifdef LAB_PGTBL
#define USYSCALL (TRAPFRAME - PGSIZE)
struct usyscall {
int pid; // Process ID
};
#endif

View File

@@ -11,3 +11,5 @@
#define NBUF (MAXOPBLOCKS*3) // size of disk block cache
#define FSSIZE 2000 // size of file system in blocks
#define MAXPATH 128 // maximum file path name
#define USERSTACK 1 // user stack pages

View File

@@ -26,13 +26,13 @@ static struct {
static char digits[] = "0123456789abcdef";
static void
printint(int xx, int base, int sign)
printint(long long xx, int base, int sign)
{
char buf[16];
int i;
uint x;
unsigned long long x;
if(sign && (sign = xx < 0))
if(sign && (sign = (xx < 0)))
x = -xx;
else
x = xx;
@@ -59,30 +59,71 @@ printptr(uint64 x)
consputc(digits[x >> (sizeof(uint64) * 8 - 4)]);
}
// Print to the console. only understands %d, %x, %p, %s.
void
// Print to the console.
int
printf(char *fmt, ...)
{
va_list ap;
int i, c, locking;
int i, cx, c0, c1, c2, locking;
char *s;
locking = pr.locking;
if(locking)
acquire(&pr.lock);
if (fmt == 0)
panic("null fmt");
va_start(ap, fmt);
for(i = 0; (c = fmt[i] & 0xff) != 0; i++){
if(c != '%'){
consputc(c);
for(i = 0; (cx = fmt[i] & 0xff) != 0; i++){
if(cx != '%'){
consputc(cx);
continue;
}
c = fmt[++i] & 0xff;
if(c == 0)
i++;
c0 = fmt[i+0] & 0xff;
c1 = c2 = 0;
if(c0) c1 = fmt[i+1] & 0xff;
if(c1) c2 = fmt[i+2] & 0xff;
if(c0 == 'd'){
printint(va_arg(ap, int), 10, 1);
} else if(c0 == 'l' && c1 == 'd'){
printint(va_arg(ap, uint64), 10, 1);
i += 1;
} else if(c0 == 'l' && c1 == 'l' && c2 == 'd'){
printint(va_arg(ap, uint64), 10, 1);
i += 2;
} else if(c0 == 'u'){
printint(va_arg(ap, int), 10, 0);
} else if(c0 == 'l' && c1 == 'u'){
printint(va_arg(ap, uint64), 10, 0);
i += 1;
} else if(c0 == 'l' && c1 == 'l' && c2 == 'u'){
printint(va_arg(ap, uint64), 10, 0);
i += 2;
} else if(c0 == 'x'){
printint(va_arg(ap, int), 16, 0);
} else if(c0 == 'l' && c1 == 'x'){
printint(va_arg(ap, uint64), 16, 0);
i += 1;
} else if(c0 == 'l' && c1 == 'l' && c2 == 'x'){
printint(va_arg(ap, uint64), 16, 0);
i += 2;
} else if(c0 == 'p'){
printptr(va_arg(ap, uint64));
} else if(c0 == 's'){
if((s = va_arg(ap, char*)) == 0)
s = "(null)";
for(; *s; s++)
consputc(*s);
} else if(c0 == '%'){
consputc('%');
} else if(c0 == 0){
break;
} else {
// Print unknown % sequence to draw attention.
consputc('%');
consputc(c0);
}
#if 0
switch(c){
case 'd':
printint(va_arg(ap, int), 10, 1);
@@ -108,11 +149,14 @@ printf(char *fmt, ...)
consputc(c);
break;
}
#endif
}
va_end(ap);
if(locking)
release(&pr.lock);
return 0;
}
void
@@ -120,8 +164,7 @@ panic(char *s)
{
pr.locking = 0;
printf("panic: ");
printf(s);
printf("\n");
printf("%s\n", s);
panicked = 1; // freeze uart output from other CPUs
for(;;)
;

View File

@@ -5,9 +5,6 @@
#include "spinlock.h"
#include "proc.h"
#include "defs.h"
#include "sysinfo.h"
uint64 current_load = 0;
struct cpu cpus[NCPU];
@@ -149,9 +146,6 @@ found:
p->context.ra = (uint64)forkret;
p->context.sp = p->kstack + PGSIZE;
// 初始化计数器
memset(p->syscall_counts, 0, sizeof(p->syscall_counts));
return p;
}
@@ -316,8 +310,6 @@ fork(void)
safestrcpy(np->name, p->name, sizeof(p->name));
// 复制掩码
np->tracemask = p->tracemask;
pid = np->pid;
release(&np->lock);
@@ -454,7 +446,6 @@ scheduler(void)
{
struct proc *p;
struct cpu *c = mycpu();
/*update_load_avg();*/
c->proc = 0;
for(;;){
@@ -463,6 +454,7 @@ scheduler(void)
// processes are waiting.
intr_on();
int found = 0;
for(p = proc; p < &proc[NPROC]; p++) {
acquire(&p->lock);
if(p->state == RUNNABLE) {
@@ -471,15 +463,20 @@ scheduler(void)
// before jumping back to us.
p->state = RUNNING;
c->proc = p;
current_load += 1;
swtch(&c->context, &p->context);
// Process is done running for now.
// It should have changed its p->state before coming back.
c->proc = 0;
found = 1;
}
release(&p->lock);
}
if(found == 0) {
// nothing to run; stop running on this core until an interrupt.
intr_on();
asm volatile("wfi");
}
}
}
@@ -696,18 +693,3 @@ procdump(void)
printf("\n");
}
}
int
proc_size()
{
int i =0, n = 0;
for (; i < NPROC; ++i) {
if (proc[i].state != UNUSED) n += 1;
}
return n;
}
int
update_load() {
return current_load;
}

View File

@@ -1,5 +1,3 @@
#include "defs.h"
// Saved registers for kernel context switches.
struct context {
uint64 ra;
@@ -93,7 +91,6 @@ struct proc {
int killed; // If non-zero, have been killed
int xstate; // Exit status to be returned to parent's wait
int pid; // Process ID
int tracemask; // Trace Mask
// wait_lock must be held when using this:
struct proc *parent; // Parent process
@@ -107,5 +104,4 @@ struct proc {
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
char name[16]; // Process name (debugging)
int syscall_counts[24]; // 每个系统调用的调用次数
};

View File

@@ -96,9 +96,7 @@ w_sie(uint64 x)
}
// Machine-mode Interrupt Enable
#define MIE_MEIE (1L << 11) // external
#define MIE_MTIE (1L << 7) // timer
#define MIE_MSIE (1L << 3) // software
#define MIE_STIE (1L << 5) // supervisor timer
static inline uint64
r_mie()
{
@@ -176,11 +174,38 @@ r_stvec()
return x;
}
// Machine-mode interrupt vector
static inline void
w_mtvec(uint64 x)
// Supervisor Timer Comparison Register
static inline uint64
r_stimecmp()
{
asm volatile("csrw mtvec, %0" : : "r" (x));
uint64 x;
// asm volatile("csrr %0, stimecmp" : "=r" (x) );
asm volatile("csrr %0, 0x14d" : "=r" (x) );
return x;
}
static inline void
w_stimecmp(uint64 x)
{
// asm volatile("csrw stimecmp, %0" : : "r" (x));
asm volatile("csrw 0x14d, %0" : : "r" (x));
}
// Machine Environment Configuration Register
static inline uint64
r_menvcfg()
{
uint64 x;
// asm volatile("csrr %0, menvcfg" : "=r" (x) );
asm volatile("csrr %0, 0x30a" : "=r" (x) );
return x;
}
static inline void
w_menvcfg(uint64 x)
{
//asm volatile("csrw menvcfg, %0" : : "r" (x));
asm volatile("csrw 0x30a, %0" : : "r" (x));
}
// Physical Memory Protection
@@ -217,12 +242,6 @@ r_satp()
return x;
}
static inline void
w_mscratch(uint64 x)
{
asm volatile("csrw mscratch, %0" : : "r" (x));
}
// Supervisor Trap Cause
static inline uint64
r_scause()
@@ -295,6 +314,14 @@ r_sp()
return x;
}
static inline uint64
r_fp()
{
uint64 x;
asm volatile("mv %0, s0" : "=r" (x) );
return x;
}
// read and write tp, the thread pointer, which xv6 uses to hold
// this core's hartid (core number), the index into cpus[].
static inline uint64
@@ -335,6 +362,11 @@ typedef uint64 *pagetable_t; // 512 PTEs
#define PGSIZE 4096 // bytes per page
#define PGSHIFT 12 // bits of offset within a page
#ifdef LAB_PGTBL
#define SUPERPGSIZE (2 * (1 << 20)) // bytes per page
#define SUPERPGROUNDUP(sz) (((sz)+SUPERPGSIZE-1) & ~(SUPERPGSIZE-1))
#endif
#define PGROUNDUP(sz) (((sz)+PGSIZE-1) & ~(PGSIZE-1))
#define PGROUNDDOWN(a) (((a)) & ~(PGSIZE-1))
@@ -344,6 +376,12 @@ typedef uint64 *pagetable_t; // 512 PTEs
#define PTE_X (1L << 3)
#define PTE_U (1L << 4) // user can access
#if defined(LAB_MMAP) || defined(LAB_PGTBL)
#define PTE_LEAF(pte) (((pte) & PTE_R) | ((pte) & PTE_W) | ((pte) & PTE_X))
#endif
// shift a physical address to the right place for a PTE.
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)

View File

@@ -10,12 +10,6 @@ void timerinit();
// entry.S needs one stack per CPU.
__attribute__ ((aligned (16))) char stack0[4096 * NCPU];
// a scratch area per CPU for machine-mode timer interrupts.
uint64 timer_scratch[NCPU][5];
// assembly code in kernelvec.S for machine-mode timer interrupt.
extern void timervec();
// entry.S jumps here in machine mode on stack0.
void
start()
@@ -54,36 +48,19 @@ start()
asm volatile("mret");
}
// arrange to receive timer interrupts.
// they will arrive in machine mode at
// at timervec in kernelvec.S,
// which turns them into software interrupts for
// devintr() in trap.c.
// ask each hart to generate timer interrupts.
void
timerinit()
{
// each CPU has a separate source of timer interrupts.
int id = r_mhartid();
// ask the CLINT for a timer interrupt.
int interval = 1000000; // cycles; about 1/10th second in qemu.
*(uint64*)CLINT_MTIMECMP(id) = *(uint64*)CLINT_MTIME + interval;
// prepare information in scratch[] for timervec.
// scratch[0..2] : space for timervec to save registers.
// scratch[3] : address of CLINT MTIMECMP register.
// scratch[4] : desired interval (in cycles) between timer interrupts.
uint64 *scratch = &timer_scratch[id][0];
scratch[3] = CLINT_MTIMECMP(id);
scratch[4] = interval;
w_mscratch((uint64)scratch);
// set the machine-mode trap handler.
w_mtvec((uint64)timervec);
// enable machine-mode interrupts.
w_mstatus(r_mstatus() | MSTATUS_MIE);
// enable machine-mode timer interrupts.
w_mie(r_mie() | MIE_MTIE);
// enable supervisor-mode timer interrupts.
w_mie(r_mie() | MIE_STIE);
// enable the sstc extension (i.e. stimecmp).
w_menvcfg(r_menvcfg() | (1L << 63));
// allow supervisor to use stimecmp and time.
w_mcounteren(r_mcounteren() | 2);
// ask for the very first timer interrupt.
w_stimecmp(r_time() + 1000000);
}

View File

@@ -1,7 +1,6 @@
#define T_DIR 1 // Directory
#define T_FILE 2 // File
#define T_DEVICE 3 // Device
#include "types.h"
#define T_DIR 1 // Directory
#define T_FILE 2 // File
#define T_DEVICE 3 // Device
struct stat {
int dev; // File system's disk device

View File

@@ -7,11 +7,6 @@
#include "syscall.h"
#include "defs.h"
// 保留系统调用别名
char* syscalls_name[25] = {"", "fork", "exit", "wait", "pipe", "read", "kill", "exec",
"fstat", "chdir", "dup", "getpid", "sbrk", "sleep", "uptime",
"open", "write", "mknod", "unlink", "link", "mkdir", "close", "trace", "sysinfo"};
// Fetch the uint64 at addr from the current process.
int
fetchaddr(uint64 addr, uint64 *ip)
@@ -106,8 +101,17 @@ extern uint64 sys_unlink(void);
extern uint64 sys_link(void);
extern uint64 sys_mkdir(void);
extern uint64 sys_close(void);
extern uint64 sys_trace(void);
extern uint64 sys_sysinfo(void);
#ifdef LAB_NET
extern uint64 sys_bind(void);
extern uint64 sys_unbind(void);
extern uint64 sys_send(void);
extern uint64 sys_recv(void);
#endif
#ifdef LAB_PGTBL
extern uint64 sys_pgpte(void);
extern uint64 sys_kpgtbl(void);
#endif
// An array mapping syscall numbers from syscall.h
// to the function that handles the system call.
@@ -133,10 +137,20 @@ static uint64 (*syscalls[])(void) = {
[SYS_link] sys_link,
[SYS_mkdir] sys_mkdir,
[SYS_close] sys_close,
[SYS_trace] sys_trace,
[SYS_sysinfo] sys_sysinfo,
#ifdef LAB_NET
[SYS_bind] sys_bind,
[SYS_unbind] sys_unbind,
[SYS_send] sys_send,
[SYS_recv] sys_recv,
#endif
#ifdef LAB_PGTBL
[SYS_pgpte] sys_pgpte,
[SYS_kpgtbl] sys_kpgtbl,
#endif
};
void
syscall(void)
{
@@ -148,12 +162,6 @@ syscall(void)
// Use num to lookup the system call function for num, call it,
// and store its return value in p->trapframe->a0
p->trapframe->a0 = syscalls[num]();
if (p->tracemask & (1 << num)) {
p->syscall_counts[num]++;
printf("%d: syscall %s(trace counts: %d) -> %d\n",
p->pid, syscalls_name[num], p->syscall_counts[num], p->trapframe->a0);
printf("a1:%d a2:%d a3:%d a4:%d a5:%d a6:%d a7:%d\n",p->trapframe->a1,p->trapframe->a2,p->trapframe->a3,p->trapframe->a4,p->trapframe->a5,p->trapframe->a6,p->trapframe->a7);
}
} else {
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);

View File

@@ -20,5 +20,19 @@
#define SYS_link 19
#define SYS_mkdir 20
#define SYS_close 21
#define SYS_trace 22
#define SYS_sysinfo 23
// System calls for labs
#define SYS_trace 22
#define SYS_sysinfo 23
#define SYS_sigalarm 24
#define SYS_sigreturn 25
#define SYS_symlink 26
#define SYS_mmap 27
#define SYS_munmap 28
#define SYS_bind 29
#define SYS_unbind 30
#define SYS_send 31
#define SYS_recv 32
#define SYS_pgpte 33
#define SYS_kpgtbl 34
#define SYS_pgaccess 35

View File

@@ -1,11 +1,10 @@
#include "types.h"
#include "riscv.h"
#include "defs.h"
#include "param.h"
#include "defs.h"
#include "memlayout.h"
#include "spinlock.h"
#include "proc.h"
#include "sysinfo.h"
uint64
sys_exit(void)
@@ -55,6 +54,7 @@ sys_sleep(void)
int n;
uint ticks0;
argint(0, &n);
if(n < 0)
n = 0;
@@ -71,6 +71,37 @@ sys_sleep(void)
return 0;
}
#ifdef LAB_PGTBL
int
sys_pgpte(void)
{
uint64 va;
struct proc *p;
p = myproc();
argaddr(0, &va);
pte_t *pte = pgpte(p->pagetable, va);
if(pte != 0) {
return (uint64) *pte;
}
return 0;
}
#endif
#ifdef LAB_PGTBL
int
sys_kpgtbl(void)
{
struct proc *p;
p = myproc();
vmprint(p->pagetable);
return 0;
}
#endif
uint64
sys_kill(void)
{
@@ -92,30 +123,3 @@ sys_uptime(void)
release(&tickslock);
return xticks;
}
uint64
sys_trace(void)
{
int n;
argint(0, &n);
if(n<0) return -1;
myproc()->tracemask = n;
return 0;
}
uint64
sys_sysinfo(void)
{
struct sysinfo info;
uint64 addr;
argaddr(0, &addr);
if (addr < 0) return -1;
struct proc* p = myproc();
info.nproc = proc_size();
info.freemem = freemem();
info.unused_proc_num = NPROC - info.nproc;
info.load_avg = update_load() * 100 / sys_uptime();
if (copyout(p->pagetable, addr, (char*)&info, sizeof(info)) < 0)
return -1;
return 0;
}

View File

@@ -68,8 +68,8 @@ usertrap(void)
} else if((which_dev = devintr()) != 0){
// ok
} else {
printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
printf(" sepc=%p stval=%p\n", r_sepc(), r_stval());
printf("usertrap(): unexpected scause 0x%lx pid=%d\n", r_scause(), p->pid);
printf(" sepc=0x%lx stval=0x%lx\n", r_sepc(), r_stval());
setkilled(p);
}
@@ -145,13 +145,13 @@ kerneltrap()
panic("kerneltrap: interrupts enabled");
if((which_dev = devintr()) == 0){
printf("scause %p\n", scause);
printf("sepc=%p stval=%p\n", r_sepc(), r_stval());
// interrupt or trap from an unknown source
printf("scause=0x%lx sepc=0x%lx stval=0x%lx\n", scause, r_sepc(), r_stval());
panic("kerneltrap");
}
// give up the CPU if this is a timer interrupt.
if(which_dev == 2 && myproc() != 0 && myproc()->state == RUNNING)
if(which_dev == 2 && myproc() != 0)
yield();
// the yield() may have caused some traps to occur,
@@ -163,10 +163,17 @@ kerneltrap()
void
clockintr()
{
acquire(&tickslock);
ticks++;
wakeup(&ticks);
release(&tickslock);
if(cpuid() == 0){
acquire(&tickslock);
ticks++;
wakeup(&ticks);
release(&tickslock);
}
// ask for the next timer interrupt. this also clears
// the interrupt request. 1000000 is about a tenth
// of a second.
w_stimecmp(r_time() + 1000000);
}
// check if it's an external interrupt or software interrupt,
@@ -179,8 +186,7 @@ devintr()
{
uint64 scause = r_scause();
if((scause & 0x8000000000000000L) &&
(scause & 0xff) == 9){
if(scause == 0x8000000000000009L){
// this is a supervisor external interrupt, via PLIC.
// irq indicates which device interrupted.
@@ -201,18 +207,9 @@ devintr()
plic_complete(irq);
return 1;
} else if(scause == 0x8000000000000001L){
// software interrupt from a machine-mode timer interrupt,
// forwarded by timervec in kernelvec.S.
if(cpuid() == 0){
clockintr();
}
// acknowledge the software interrupt by clearing
// the SSIP bit in sip.
w_sip(r_sip() & ~2);
} else if(scause == 0x8000000000000005L){
// timer interrupt.
clockintr();
return 2;
} else {
return 0;

View File

@@ -1,10 +1,10 @@
typedef unsigned int uint;
typedef unsigned int uint;
typedef unsigned short ushort;
typedef unsigned char uchar;
typedef unsigned char uchar;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned int uint32;
typedef unsigned long uint64;
typedef uint64 pde_t;

View File

@@ -13,7 +13,7 @@
// the UART control registers are memory-mapped
// at address UART0. this macro returns the
// address of one of the registers.
#define Reg(reg) ((volatile unsigned char *)(UART0 + reg))
#define Reg(reg) ((volatile unsigned char *)(UART0 + (reg)))
// the UART control registers.
// some have different meanings for
@@ -136,6 +136,7 @@ uartstart()
while(1){
if(uart_tx_w == uart_tx_r){
// transmit buffer is empty.
ReadReg(ISR);
return;
}

View File

@@ -4,6 +4,8 @@
#include "elf.h"
#include "riscv.h"
#include "defs.h"
#include "spinlock.h"
#include "proc.h"
#include "fs.h"
/*
@@ -30,8 +32,16 @@ kvmmake(void)
// virtio mmio disk interface
kvmmap(kpgtbl, VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W);
#ifdef LAB_NET
// PCI-E ECAM (configuration space), for pci.c
kvmmap(kpgtbl, 0x30000000L, 0x30000000L, 0x10000000, PTE_R | PTE_W);
// pci.c maps the e1000's registers here.
kvmmap(kpgtbl, 0x40000000L, 0x40000000L, 0x20000, PTE_R | PTE_W);
#endif
// PLIC
kvmmap(kpgtbl, PLIC, PLIC, 0x400000, PTE_R | PTE_W);
kvmmap(kpgtbl, PLIC, PLIC, 0x4000000, PTE_R | PTE_W);
// map kernel text executable and read-only.
kvmmap(kpgtbl, KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X);
@@ -92,6 +102,11 @@ walk(pagetable_t pagetable, uint64 va, int alloc)
pte_t *pte = &pagetable[PX(level, va)];
if(*pte & PTE_V) {
pagetable = (pagetable_t)PTE2PA(*pte);
#ifdef LAB_PGTBL
if(PTE_LEAF(*pte)) {
return pte;
}
#endif
} else {
if(!alloc || (pagetable = (pde_t*)kalloc()) == 0)
return 0;
@@ -125,6 +140,7 @@ walkaddr(pagetable_t pagetable, uint64 va)
return pa;
}
// add a mapping to the kernel page table.
// only used when booting.
// does not flush TLB or enable paging.
@@ -179,15 +195,19 @@ uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
{
uint64 a;
pte_t *pte;
int sz;
if((va % PGSIZE) != 0)
panic("uvmunmap: not aligned");
for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
for(a = va; a < va + npages*PGSIZE; a += sz){
sz = PGSIZE;
if((pte = walk(pagetable, a, 0)) == 0)
panic("uvmunmap: walk");
if((*pte & PTE_V) == 0)
if((*pte & PTE_V) == 0) {
printf("va=%ld pte=%ld\n", a, *pte);
panic("uvmunmap: not mapped");
}
if(PTE_FLAGS(*pte) == PTE_V)
panic("uvmunmap: not a leaf");
if(do_free){
@@ -227,6 +247,7 @@ uvmfirst(pagetable_t pagetable, uchar *src, uint sz)
memmove(mem, src, sz);
}
// Allocate PTEs and physical memory to grow process from oldsz to
// newsz, which need not be page aligned. Returns new size or 0 on error.
uint64
@@ -234,19 +255,23 @@ uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz, int xperm)
{
char *mem;
uint64 a;
int sz;
if(newsz < oldsz)
return oldsz;
oldsz = PGROUNDUP(oldsz);
for(a = oldsz; a < newsz; a += PGSIZE){
for(a = oldsz; a < newsz; a += sz){
sz = PGSIZE;
mem = kalloc();
if(mem == 0){
uvmdealloc(pagetable, a, oldsz);
return 0;
}
memset(mem, 0, PGSIZE);
if(mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_R|PTE_U|xperm) != 0){
#ifndef LAB_SYSCALL
memset(mem, 0, sz);
#endif
if(mappages(pagetable, a, sz, (uint64)mem, PTE_R|PTE_U|xperm) != 0){
kfree(mem);
uvmdealloc(pagetable, a, oldsz);
return 0;
@@ -316,8 +341,11 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
uint64 pa, i;
uint flags;
char *mem;
int szinc;
for(i = 0; i < sz; i += PGSIZE){
for(i = 0; i < sz; i += szinc){
szinc = PGSIZE;
szinc = PGSIZE;
if((pte = walk(old, i, 0)) == 0)
panic("uvmcopy: pte should exist");
if((*pte & PTE_V) == 0)
@@ -363,13 +391,21 @@ copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
while(len > 0){
va0 = PGROUNDDOWN(dstva);
if(va0 >= MAXVA)
if (va0 >= MAXVA)
return -1;
pte = walk(pagetable, va0, 0);
if(pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0 ||
(*pte & PTE_W) == 0)
if((pte = walk(pagetable, va0, 0)) == 0) {
// printf("copyout: pte should exist 0x%x %d\n", dstva, len);
return -1;
}
// forbid copyout over read-only user text pages.
if((*pte & PTE_W) == 0)
return -1;
pa0 = walkaddr(pagetable, va0);
if(pa0 == 0)
return -1;
pa0 = PTE2PA(*pte);
n = PGSIZE - (dstva - va0);
if(n > len)
n = len;
@@ -389,7 +425,7 @@ int
copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)
{
uint64 n, va0, pa0;
while(len > 0){
va0 = PGROUNDDOWN(srcva);
pa0 = walkaddr(pagetable, va0);
@@ -449,3 +485,20 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
return -1;
}
}
#ifdef LAB_PGTBL
void
vmprint(pagetable_t pagetable) {
// your code here
}
#endif
#ifdef LAB_PGTBL
pte_t*
pgpte(pagetable_t pagetable, uint64 va) {
return walk(pagetable, va, 0);
}
#endif