Merge branch 'riscv' into riscv

This commit is contained in:
Frans Kaashoek 2020-08-10 13:05:17 -04:00 committed by GitHub
commit c31d35d803
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 1074 additions and 251 deletions

View file

@ -28,7 +28,8 @@ struct {
struct buf buf[NBUF];
// Linked list of all buffers, through prev/next.
// head.next is most recently used.
// Sorted by how recently the buffer was used.
// head.next is most recent, head.prev is least.
struct buf head;
} bcache;
@ -71,7 +72,8 @@ bget(uint dev, uint blockno)
}
}
// Not cached; recycle an unused buffer.
// Not cached.
// Recycle the least recently used (LRU) unused buffer.
for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
if(b->refcnt == 0) {
b->dev = dev;
@ -110,7 +112,7 @@ bwrite(struct buf *b)
}
// Release a locked buffer.
// Move to the head of the MRU list.
// Move to the head of the most-recently-used list.
void
brelse(struct buf *b)
{

View file

@ -7,7 +7,6 @@ struct buf {
uint refcnt;
struct buf *prev; // LRU cache list
struct buf *next;
struct buf *qnext; // disk queue
uchar data[BSIZE];
};

View file

@ -27,6 +27,8 @@
//
// send one character to the uart.
// called by printf, and to echo input characters,
// but not from write().
//
void
consputc(int c)
@ -40,9 +42,9 @@ consputc(int c)
if(c == BACKSPACE){
// if the user typed backspace, overwrite with a space.
uartputc('\b'); uartputc(' '); uartputc('\b');
uartputc_sync('\b'); uartputc_sync(' '); uartputc_sync('\b');
} else {
uartputc(c);
uartputc_sync(c);
}
}
@ -70,11 +72,11 @@ consolewrite(int user_src, uint64 src, int n)
char c;
if(either_copyin(&c, user_src, src+i, 1) == -1)
break;
consputc(c);
uartputc(c);
}
release(&cons.lock);
return n;
return i;
}
//

View file

@ -52,6 +52,7 @@ 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);
@ -149,6 +150,7 @@ void usertrapret(void);
void uartinit(void);
void uartintr(void);
void uartputc(int);
void uartputc_sync(int);
int uartgetc(void);
// vm.c
@ -173,7 +175,6 @@ int copyinstr(pagetable_t, char *, uint64, uint64);
// plic.c
void plicinit(void);
void plicinithart(void);
uint64 plic_pending(void);
int plic_claim(void);
void plic_complete(int);

View file

@ -97,7 +97,7 @@ exec(char *path, char **argv)
// arguments to user main(argc, argv)
// argc is returned via the system call return
// value, which goes in a0.
p->tf->a1 = sp;
p->trapframe->a1 = sp;
// Save program name for debugging.
for(last=s=path; *s; s++)
@ -109,9 +109,10 @@ exec(char *path, char **argv)
oldpagetable = p->pagetable;
p->pagetable = pagetable;
p->sz = sz;
p->tf->epc = elf.entry; // initial program counter = main
p->tf->sp = sp; // initial stack pointer
p->trapframe->epc = elf.entry; // initial program counter = main
p->trapframe->sp = sp; // initial stack pointer
proc_freepagetable(oldpagetable, oldsz);
return argc; // this ends up in a0, the first argument to main(argc, argv)
bad:

View file

@ -2,3 +2,4 @@
#define O_WRONLY 0x001
#define O_RDWR 0x002
#define O_CREATE 0x200
#define O_TRUNC 0x400

View file

@ -22,7 +22,6 @@
#include "file.h"
#define min(a, b) ((a) < (b) ? (a) : (b))
static void itrunc(struct inode*);
// there should be one superblock per disk device, but we run with
// only one device
struct superblock sb;
@ -406,11 +405,8 @@ bmap(struct inode *ip, uint bn)
}
// Truncate inode (discard contents).
// Only called when the inode has no links
// to it (no directory entries referring to it)
// and has no in-memory reference to it (is
// not an open file or current directory).
static void
// Caller must hold ip->lock.
void
itrunc(struct inode *ip)
{
int i, j;
@ -463,7 +459,7 @@ readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n)
struct buf *bp;
if(off > ip->size || off + n < off)
return -1;
return 0;
if(off + n > ip->size)
n = ip->size - off;
@ -476,7 +472,7 @@ readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n)
}
brelse(bp);
}
return n;
return tot;
}
// Write data to inode.

View file

@ -8,25 +8,37 @@ SECTIONS
* where qemu's -kernel jumps.
*/
. = 0x80000000;
.text :
{
*(.text)
.text : {
*(.text .text.*)
. = ALIGN(0x1000);
_trampoline = .;
*(trampsec)
. = ALIGN(0x1000);
ASSERT(. - _trampoline == 0x1000, "error: trampoline larger than one page");
PROVIDE(etext = .);
}
. = ALIGN(0x1000);
PROVIDE(etext = .);
.rodata : {
. = ALIGN(16);
*(.srodata .srodata.*) /* do not need to distinguish this from .rodata */
. = ALIGN(16);
*(.rodata .rodata.*)
}
/*
* make sure end is after data and bss.
*/
.data : {
*(.data)
. = ALIGN(16);
*(.sdata .sdata.*) /* do not need to distinguish this from .data */
. = ALIGN(16);
*(.data .data.*)
}
.bss : {
*(.bss)
*(.sbss*)
PROVIDE(end = .);
. = ALIGN(16);
*(.sbss .sbss.*) /* do not need to distinguish this from .bss */
. = ALIGN(16);
*(.bss .bss.*)
}
PROVIDE(end = .);
}

View file

@ -62,6 +62,6 @@
// fixed-size stack
// expandable heap
// ...
// TRAPFRAME (p->tf, used by the trampoline)
// TRAPFRAME (p->trapframe, used by the trampoline)
// TRAMPOLINE (the same page as in the kernel)
#define TRAPFRAME (TRAMPOLINE - PGSIZE)

View file

@ -83,7 +83,7 @@ pipewrite(struct pipe *pi, uint64 addr, int n)
acquire(&pi->lock);
for(i = 0; i < n; i++){
while(pi->nwrite == pi->nread + PIPESIZE){ //DOC: pipewrite-full
if(pi->readopen == 0 || myproc()->killed){
if(pi->readopen == 0 || pr->killed){
release(&pi->lock);
return -1;
}
@ -96,7 +96,7 @@ pipewrite(struct pipe *pi, uint64 addr, int n)
}
wakeup(&pi->nread);
release(&pi->lock);
return n;
return i;
}
int
@ -108,7 +108,7 @@ piperead(struct pipe *pi, uint64 addr, int n)
acquire(&pi->lock);
while(pi->nread == pi->nwrite && pi->writeopen){ //DOC: pipe-empty
if(myproc()->killed){
if(pr->killed){
release(&pi->lock);
return -1;
}

View file

@ -28,26 +28,11 @@ plicinithart(void)
*(uint32*)PLIC_SPRIORITY(hart) = 0;
}
// return a bitmap of which IRQs are waiting
// to be served.
uint64
plic_pending(void)
{
uint64 mask;
//mask = *(uint32*)(PLIC + 0x1000);
//mask |= (uint64)*(uint32*)(PLIC + 0x1004) << 32;
mask = *(uint64*)PLIC_PENDING;
return mask;
}
// ask the PLIC what interrupt we should serve.
int
plic_claim(void)
{
int hart = cpuid();
//int irq = *(uint32*)(PLIC + 0x201004);
int irq = *(uint32*)PLIC_SCLAIM(hart);
return irq;
}
@ -57,6 +42,5 @@ void
plic_complete(int irq)
{
int hart = cpuid();
//*(uint32*)(PLIC + 0x201004) = irq;
*(uint32*)PLIC_SCLAIM(hart) = irq;
}

View file

@ -20,6 +20,7 @@ static void wakeup1(struct proc *chan);
extern char trampoline[]; // trampoline.S
// initialize the proc table at boot time.
void
procinit(void)
{
@ -106,7 +107,7 @@ found:
p->pid = allocpid();
// Allocate a trapframe page.
if((p->tf = (struct trapframe *)kalloc()) == 0){
if((p->trapframe = (struct trapframe *)kalloc()) == 0){
release(&p->lock);
return 0;
}
@ -116,7 +117,7 @@ found:
// Set up new context to start executing at forkret,
// which returns to user space.
memset(&p->context, 0, sizeof p->context);
memset(&p->context, 0, sizeof(p->context));
p->context.ra = (uint64)forkret;
p->context.sp = p->kstack + PGSIZE;
@ -129,9 +130,9 @@ found:
static void
freeproc(struct proc *p)
{
if(p->tf)
kfree((void*)p->tf);
p->tf = 0;
if(p->trapframe)
kfree((void*)p->trapframe);
p->trapframe = 0;
if(p->pagetable)
proc_freepagetable(p->pagetable, p->sz);
p->pagetable = 0;
@ -145,8 +146,8 @@ freeproc(struct proc *p)
p->state = UNUSED;
}
// Create a page table for a given process,
// with no user pages, but with trampoline pages.
// Create a user page table for a given process,
// with no user memory, but with trampoline pages.
pagetable_t
proc_pagetable(struct proc *p)
{
@ -164,7 +165,7 @@ proc_pagetable(struct proc *p)
// map the trapframe just below TRAMPOLINE, for trampoline.S.
mappages(pagetable, TRAPFRAME, PGSIZE,
(uint64)(p->tf), PTE_R | PTE_W);
(uint64)(p->trapframe), PTE_R | PTE_W);
return pagetable;
}
@ -176,8 +177,7 @@ proc_freepagetable(pagetable_t pagetable, uint64 sz)
{
uvmunmap(pagetable, TRAMPOLINE, PGSIZE, 0);
uvmunmap(pagetable, TRAPFRAME, PGSIZE, 0);
if(sz > 0)
uvmfree(pagetable, sz);
uvmfree(pagetable, sz);
}
// a user program that calls exec("/init")
@ -207,8 +207,8 @@ userinit(void)
p->sz = PGSIZE;
// prepare for the very first "return" from kernel to user.
p->tf->epc = 0; // user program counter
p->tf->sp = PGSIZE; // user stack pointer
p->trapframe->epc = 0; // user program counter
p->trapframe->sp = PGSIZE; // user stack pointer
safestrcpy(p->name, "initcode", sizeof(p->name));
p->cwd = namei("/");
@ -263,10 +263,10 @@ fork(void)
np->parent = p;
// copy saved user registers.
*(np->tf) = *(p->tf);
*(np->trapframe) = *(p->trapframe);
// Cause fork to return 0 in the child.
np->tf->a0 = 0;
np->trapframe->a0 = 0;
// increment reference counts on open file descriptors.
for(i = 0; i < NOFILE; i++)
@ -457,7 +457,7 @@ scheduler(void)
// before jumping back to us.
p->state = RUNNING;
c->proc = p;
swtch(&c->scheduler, &p->context);
swtch(&c->context, &p->context);
// Process is done running for now.
// It should have changed its p->state before coming back.
@ -491,7 +491,7 @@ sched(void)
panic("sched interruptible");
intena = mycpu()->intena;
swtch(&p->context, &mycpu()->scheduler);
swtch(&p->context, &mycpu()->context);
mycpu()->intena = intena;
}

View file

@ -21,7 +21,7 @@ struct context {
// Per-CPU state.
struct cpu {
struct proc *proc; // The process running on this cpu, or null.
struct context scheduler; // swtch() here to enter scheduler().
struct context context; // swtch() here to enter scheduler().
int noff; // Depth of push_off() nesting.
int intena; // Were interrupts enabled before push_off()?
};
@ -95,10 +95,10 @@ struct proc {
int pid; // Process ID
// these are private to the process, so p->lock need not be held.
uint64 kstack; // Bottom of kernel stack for this process
uint64 kstack; // Virtual address of kernel stack
uint64 sz; // Size of process memory (bytes)
pagetable_t pagetable; // Page table
struct trapframe *tf; // data page for trampoline.S
pagetable_t pagetable; // User page table
struct trapframe *trapframe; // data page for trampoline.S
struct context context; // swtch() here to run process
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory

View file

@ -261,7 +261,6 @@ r_time()
static inline void
intr_on()
{
w_sie(r_sie() | SIE_SEIE | SIE_STIE | SIE_SSIE);
w_sstatus(r_sstatus() | SSTATUS_SIE);
}

View file

@ -34,7 +34,8 @@ acquire(struct spinlock *lk)
// Tell the C compiler and the processor to not move loads or stores
// past this point, to ensure that the critical section's memory
// references happen after the lock is acquired.
// references happen strictly after the lock is acquired.
// On RISC-V, this emits a fence instruction.
__sync_synchronize();
// Record info about lock acquisition for holding() and debugging.
@ -52,8 +53,10 @@ release(struct spinlock *lk)
// Tell the C compiler and the CPU to not move loads or stores
// past this point, to ensure that all the stores in the critical
// section are visible to other CPUs before the lock is released.
// On RISC-V, this turns into a fence instruction.
// section are visible to other CPUs before the lock is released,
// and that loads in the critical section occur strictly before
// the lock is released.
// On RISC-V, this emits a fence instruction.
__sync_synchronize();
// Release the lock, equivalent to lk->locked = 0.
@ -69,13 +72,12 @@ release(struct spinlock *lk)
}
// Check whether this cpu is holding the lock.
// Interrupts must be off.
int
holding(struct spinlock *lk)
{
int r;
push_off();
r = (lk->locked && lk->cpu == mycpu());
pop_off();
return r;
}
@ -100,9 +102,9 @@ pop_off(void)
struct cpu *c = mycpu();
if(intr_get())
panic("pop_off - interruptible");
c->noff -= 1;
if(c->noff < 0)
if(c->noff < 1)
panic("pop_off");
c->noff -= 1;
if(c->noff == 0 && c->intena)
intr_on();
}

View file

@ -36,6 +36,7 @@ start()
// delegate all interrupts and exceptions to supervisor mode.
w_medeleg(0xffff);
w_mideleg(0xffff);
w_sie(r_sie() | SIE_SEIE | SIE_STIE | SIE_SSIE);
// ask for clock interrupts.
timerinit();

View file

@ -37,17 +37,17 @@ argraw(int n)
struct proc *p = myproc();
switch (n) {
case 0:
return p->tf->a0;
return p->trapframe->a0;
case 1:
return p->tf->a1;
return p->trapframe->a1;
case 2:
return p->tf->a2;
return p->trapframe->a2;
case 3:
return p->tf->a3;
return p->trapframe->a3;
case 4:
return p->tf->a4;
return p->trapframe->a4;
case 5:
return p->tf->a5;
return p->trapframe->a5;
}
panic("argraw");
return -1;
@ -135,12 +135,12 @@ syscall(void)
int num;
struct proc *p = myproc();
num = p->tf->a7;
num = p->trapframe->a7;
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
p->tf->a0 = syscalls[num]();
p->trapframe->a0 = syscalls[num]();
} else {
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);
p->tf->a0 = -1;
p->trapframe->a0 = -1;
}
}

View file

@ -341,6 +341,10 @@ sys_open(void)
f->readable = !(omode & O_WRONLY);
f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
if((omode & O_TRUNC) && ip->type == T_FILE){
itrunc(ip);
}
iunlock(ip);
end_op();

View file

@ -20,7 +20,7 @@ uservec:
# in supervisor mode, but with a
# user page table.
#
# sscratch points to where the process's p->tf is
# sscratch points to where the process's p->trapframe is
# mapped into user space, at TRAPFRAME.
#
@ -60,20 +60,20 @@ uservec:
sd t5, 272(a0)
sd t6, 280(a0)
# save the user a0 in p->tf->a0
# save the user a0 in p->trapframe->a0
csrr t0, sscratch
sd t0, 112(a0)
# restore kernel stack pointer from p->tf->kernel_sp
# restore kernel stack pointer from p->trapframe->kernel_sp
ld sp, 8(a0)
# make tp hold the current hartid, from p->tf->kernel_hartid
# make tp hold the current hartid, from p->trapframe->kernel_hartid
ld tp, 32(a0)
# load the address of usertrap(), p->tf->kernel_trap
# load the address of usertrap(), p->trapframe->kernel_trap
ld t0, 16(a0)
# restore kernel page table from p->tf->kernel_satp
# restore kernel page table from p->trapframe->kernel_satp
ld t1, 0(a0)
csrw satp, t1
sfence.vma zero, zero

View file

@ -48,7 +48,7 @@ usertrap(void)
struct proc *p = myproc();
// save user program counter.
p->tf->epc = r_sepc();
p->trapframe->epc = r_sepc();
if(r_scause() == 8){
// system call
@ -58,7 +58,7 @@ usertrap(void)
// sepc points to the ecall instruction,
// but we want to return to the next instruction.
p->tf->epc += 4;
p->trapframe->epc += 4;
// an interrupt will change sstatus &c registers,
// so don't enable until done with those registers.
@ -91,8 +91,9 @@ usertrapret(void)
{
struct proc *p = myproc();
// turn off interrupts, since we're switching
// now from kerneltrap() to usertrap().
// we're about to switch the destination of traps from
// kerneltrap() to usertrap(), so turn off interrupts until
// we're back in user space, where usertrap() is correct.
intr_off();
// send syscalls, interrupts, and exceptions to trampoline.S
@ -100,10 +101,10 @@ usertrapret(void)
// set up trapframe values that uservec will need when
// the process next re-enters the kernel.
p->tf->kernel_satp = r_satp(); // kernel page table
p->tf->kernel_sp = p->kstack + PGSIZE; // process's kernel stack
p->tf->kernel_trap = (uint64)usertrap;
p->tf->kernel_hartid = r_tp(); // hartid for cpuid()
p->trapframe->kernel_satp = r_satp(); // kernel page table
p->trapframe->kernel_sp = p->kstack + PGSIZE; // process's kernel stack
p->trapframe->kernel_trap = (uint64)usertrap;
p->trapframe->kernel_hartid = r_tp(); // hartid for cpuid()
// set up the registers that trampoline.S's sret will use
// to get to user space.
@ -115,7 +116,7 @@ usertrapret(void)
w_sstatus(x);
// set S Exception Program Counter to the saved user pc.
w_sepc(p->tf->epc);
w_sepc(p->trapframe->epc);
// tell trampoline.S the user page table to switch to.
uint64 satp = MAKE_SATP(p->pagetable);
@ -129,7 +130,6 @@ usertrapret(void)
// interrupts and exceptions from kernel code go here via kernelvec,
// on whatever the current kernel stack is.
// must be 4-byte aligned to fit in stvec.
void
kerneltrap()
{
@ -189,9 +189,16 @@ devintr()
uartintr();
} else if(irq == VIRTIO0_IRQ){
virtio_disk_intr();
} else if(irq){
printf("unexpected interrupt irq=%d\n", irq);
}
plic_complete(irq);
// the PLIC allows each device to raise at most one
// interrupt at a time; tell the PLIC the device is
// now allowed to interrupt again.
if(irq)
plic_complete(irq);
return 1;
} else if(scause == 0x8000000000000001L){
// software interrupt from a machine-mode timer interrupt,

View file

@ -18,18 +18,35 @@
// the UART control registers.
// some have different meanings for
// read vs write.
// http://byterunner.com/16550.html
#define RHR 0 // receive holding register (for input bytes)
#define THR 0 // transmit holding register (for output bytes)
#define IER 1 // interrupt enable register
#define FCR 2 // FIFO control register
#define ISR 2 // interrupt status register
#define LCR 3 // line control register
#define LSR 5 // line status register
// see http://byterunner.com/16550.html
#define RHR 0 // receive holding register (for input bytes)
#define THR 0 // transmit holding register (for output bytes)
#define IER 1 // interrupt enable register
#define IER_TX_ENABLE (1<<0)
#define IER_RX_ENABLE (1<<1)
#define FCR 2 // FIFO control register
#define FCR_FIFO_ENABLE (1<<0)
#define FCR_FIFO_CLEAR (3<<1) // clear the content of the two FIFOs
#define ISR 2 // interrupt status register
#define LCR 3 // line control register
#define LCR_EIGHT_BITS (3<<0)
#define LCR_BAUD_LATCH (1<<7) // special mode to set baud rate
#define LSR 5 // line status register
#define LSR_RX_READY (1<<0) // input is waiting to be read from RHR
#define LSR_TX_IDLE (1<<5) // THR can accept another character to send
#define ReadReg(reg) (*(Reg(reg)))
#define WriteReg(reg, v) (*(Reg(reg)) = (v))
// the transmit output buffer.
struct spinlock uart_tx_lock;
#define UART_TX_BUF_SIZE 32
char uart_tx_buf[UART_TX_BUF_SIZE];
int uart_tx_w; // write next to uart_tx_buf[uart_tx_w++]
int uart_tx_r; // read next from uart_tx_buf[uar_tx_r++]
void uartstart();
void
uartinit(void)
{
@ -37,7 +54,7 @@ uartinit(void)
WriteReg(IER, 0x00);
// special mode to set baud rate.
WriteReg(LCR, 0x80);
WriteReg(LCR, LCR_BAUD_LATCH);
// LSB for baud rate of 38.4K.
WriteReg(0, 0x03);
@ -47,23 +64,87 @@ uartinit(void)
// leave set-baud mode,
// and set word length to 8 bits, no parity.
WriteReg(LCR, 0x03);
WriteReg(LCR, LCR_EIGHT_BITS);
// reset and enable FIFOs.
WriteReg(FCR, 0x07);
WriteReg(FCR, FCR_FIFO_ENABLE | FCR_FIFO_CLEAR);
// enable receive interrupts.
WriteReg(IER, 0x01);
// enable transmit and receive interrupts.
WriteReg(IER, IER_TX_ENABLE | IER_RX_ENABLE);
initlock(&uart_tx_lock, "uart");
}
// write one output character to the UART.
// add a character to the output buffer and tell the
// UART to start sending if it isn't already.
// blocks if the output buffer is full.
// because it may block, it can't be called
// from interrupts; it's only suitable for use
// by write().
void
uartputc(int c)
{
acquire(&uart_tx_lock);
while(1){
if(((uart_tx_w + 1) % UART_TX_BUF_SIZE) == uart_tx_r){
// buffer is full.
// wait for uartstart() to open up space in the buffer.
sleep(&uart_tx_r, &uart_tx_lock);
} else {
uart_tx_buf[uart_tx_w] = c;
uart_tx_w = (uart_tx_w + 1) % UART_TX_BUF_SIZE;
uartstart();
release(&uart_tx_lock);
return;
}
}
}
// alternate version of uartputc() that doesn't
// use interrupts, for use by kernel printf() and
// to echo characters. it spins waiting for the uart's
// output register to be empty.
void
uartputc_sync(int c)
{
push_off();
// wait for Transmit Holding Empty to be set in LSR.
while((ReadReg(LSR) & (1 << 5)) == 0)
while((ReadReg(LSR) & LSR_TX_IDLE) == 0)
;
WriteReg(THR, c);
pop_off();
}
// if the UART is idle, and a character is waiting
// in the transmit buffer, send it.
// caller must hold uart_tx_lock.
// called from both the top- and bottom-half.
void
uartstart()
{
while(1){
if(uart_tx_w == uart_tx_r){
// transmit buffer is empty.
return;
}
if((ReadReg(LSR) & LSR_TX_IDLE) == 0){
// the UART transmit holding register is full,
// so we cannot give it another byte.
// it will interrupt when it's ready for a new byte.
return;
}
int c = uart_tx_buf[uart_tx_r];
uart_tx_r = (uart_tx_r + 1) % UART_TX_BUF_SIZE;
// maybe uartputc() is waiting for space in the buffer.
wakeup(&uart_tx_r);
WriteReg(THR, c);
}
}
// read one input character from the UART.
@ -79,14 +160,22 @@ uartgetc(void)
}
}
// trap.c calls here when the uart interrupts.
// handle a uart interrupt, raised because input has
// arrived, or the uart is ready for more output, or
// both. called from trap.c.
void
uartintr(void)
{
// read and process incoming characters.
while(1){
int c = uartgetc();
if(c == -1)
break;
consoleintr(c);
}
// send buffered characters.
acquire(&uart_tx_lock);
uartstart();
release(&uart_tx_lock);
}

View file

@ -16,9 +16,7 @@ extern char etext[]; // kernel.ld sets this to end of kernel code.
extern char trampoline[]; // trampoline.S
/*
* create a direct-map page table for the kernel and
* turn on paging. called early, in supervisor mode.
* the page allocator is already initialized.
* create a direct-map page table for the kernel.
*/
void
kvminit()
@ -70,7 +68,7 @@ kvminithart()
// 21..29 -- 9 bits of level-1 index.
// 12..20 -- 9 bits of level-0 index.
// 0..11 -- 12 bits of byte offset within the page.
static pte_t *
pte_t *
walk(pagetable_t pagetable, uint64 va, int alloc)
{
if(va >= MAXVA)
@ -278,7 +276,7 @@ uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz)
// Recursively free page-table pages.
// All leaf mappings must already have been removed.
static void
void
freewalk(pagetable_t pagetable)
{
// there are 2^9 = 512 PTEs in a page table.
@ -301,7 +299,8 @@ freewalk(pagetable_t pagetable)
void
uvmfree(pagetable_t pagetable, uint64 sz)
{
uvmunmap(pagetable, 0, sz, 1);
if(sz > 0)
uvmunmap(pagetable, 0, sz, 1);
freewalk(pagetable);
}