summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile20
-rw-r--r--bootasm.S33
-rw-r--r--bootother.S2
-rw-r--r--data.S23
-rw-r--r--exec.c62
-rw-r--r--fs.h1
-rw-r--r--ide.c2
-rw-r--r--main.c7
-rw-r--r--mp.c2
-rw-r--r--proc.c76
-rw-r--r--runoff.list4
-rw-r--r--runoff.spec26
-rwxr-xr-xrunoff12
-rw-r--r--toc.ftr6
-rw-r--r--trap.c3
-rw-r--r--usertests.c6
-rw-r--r--vm.c115
17 files changed, 193 insertions, 197 deletions
diff --git a/Makefile b/Makefile
index 980543a..7000fac 100644
--- a/Makefile
+++ b/Makefile
@@ -107,8 +107,8 @@ initcode: initcode.S
$(OBJCOPY) -S -O binary initcode.out initcode
$(OBJDUMP) -S initcode.o > initcode.asm
-kernel: $(OBJS) multiboot.o bootother initcode
- $(LD) $(LDFLAGS) -Ttext 0x100000 -e main -o kernel multiboot.o $(OBJS) -b binary initcode bootother fs.img
+kernel: $(OBJS) multiboot.o data.o bootother initcode
+ $(LD) $(LDFLAGS) -Ttext 0x100000 -e main -o kernel multiboot.o data.o $(OBJS) -b binary initcode bootother
$(OBJDUMP) -S kernel > kernel.asm
$(OBJDUMP) -t kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernel.sym
@@ -119,8 +119,8 @@ kernel: $(OBJS) multiboot.o bootother initcode
# great for testing the kernel on real hardware without
# needing a scratch disk.
MEMFSOBJS = $(filter-out ide.o,$(OBJS)) memide.o
-kernelmemfs: $(MEMFSOBJS) multiboot.o bootother initcode fs.img
- $(LD) $(LDFLAGS) -Ttext 0x100000 -e main -o kernelmemfs multiboot.o $(MEMFSOBJS) -b binary initcode bootother fs.img
+kernelmemfs: $(MEMFSOBJS) multiboot.o data.o bootother initcode fs.img
+ $(LD) $(LDFLAGS) -Ttext 0x100000 -e main -o kernelmemfs multiboot.o data.o $(MEMFSOBJS) -b binary initcode bootother fs.img
$(OBJDUMP) -S kernelmemfs > kernelmemfs.asm
$(OBJDUMP) -t kernelmemfs | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernelmemfs.sym
@@ -251,14 +251,16 @@ dist-test:
rm -rf dist-test
mkdir dist-test
cp dist/* dist-test
- cd dist-test; ../m print
- cd dist-test; ../m bochs || true
- cd dist-test; ../m qemu
+ cd dist-test; $(MAKE) print
+ cd dist-test; $(MAKE) bochs || true
+ cd dist-test; $(MAKE) qemu
-# update this rule (change rev1) when it is time to
+# update this rule (change rev#) when it is time to
# make a new revision.
tar:
rm -rf /tmp/xv6
mkdir -p /tmp/xv6
cp dist/* dist/.gdbinit.tmpl /tmp/xv6
- (cd /tmp; tar cf - xv6) | gzip >xv6-rev4.tar.gz
+ (cd /tmp; tar cf - xv6) | gzip >xv6-rev5.tar.gz
+
+.PHONY: dist-test dist
diff --git a/bootasm.S b/bootasm.S
index f5d1678..3cc23e7 100644
--- a/bootasm.S
+++ b/bootasm.S
@@ -13,7 +13,7 @@
.code16 # Assemble for 16-bit mode
.globl start
start:
- cli # BIOS enabled interrupts ; disable
+ cli # BIOS enabled interrupts; disable
# Set up the important data segment registers (DS, ES, SS).
xorw %ax,%ax # Segment number zero
@@ -21,10 +21,8 @@ start:
movw %ax,%es # -> Extra Segment
movw %ax,%ss # -> Stack Segment
- # Enable A20:
- # For backwards compatibility with the earliest PCs, physical
- # address line 20 is tied low, so that addresses higher than
- # 1MB wrap around to zero by default. This code undoes this.
+ # Physical address line A20 is tied to zero so that the first PCs
+ # with 2 MB would run software that assumed 1 MB. Undo that.
seta20.1:
inb $0x64,%al # Wait for not busy
testb $0x2,%al
@@ -41,28 +39,21 @@ seta20.2:
movb $0xdf,%al # 0xdf -> port 0x60
outb %al,$0x60
-//PAGEBREAK!
- # Switch from real to protected mode, using a bootstrap GDT
- # and segment translation that makes virtual addresses
- # identical to physical addresses, so that the
- # effective memory map does not change after subsequent
- # loads of segment registers.
+ # Switch from real to protected mode. Use a bootstrap GDT that makes
+ # virtual addresses map dierctly to physical addresses so that the
+ # effective memory map doesn't change during the transition.
lgdt gdtdesc
movl %cr0, %eax
orl $CR0_PE, %eax
movl %eax, %cr0
-
- # This ljmp is how you load the CS (Code Segment) register.
- # SEG_ASM produces segment descriptors with the 32-bit mode
- # flag set (the D flag), so addresses and word operands will
- # default to 32 bits after this jump.
- ljmp $(SEG_KCODE<<3), $start32
-# tell the assembler to generate 0x66 prefixes for 16-bit
-# instructions like movw, and to generate 32-bit immediate
-# addresses.
-.code32
+//PAGEBREAK!
+ # Complete transition to 32-bit protected mode by using long jmp
+ # to reload %cs and %eip. The segment registers are set up with no
+ # translation, so that the mapping is still the identity mapping.
+ ljmp $(SEG_KCODE<<3), $start32
+.code32 # Tell assembler to generate 32-bit code now.
start32:
# Set up the protected-mode data segment registers
movw $(SEG_KDATA<<3), %ax # Our data segment selector
diff --git a/bootother.S b/bootother.S
index 186873e..37b899b 100644
--- a/bootother.S
+++ b/bootother.S
@@ -34,12 +34,12 @@ start:
movw %ax,%es
movw %ax,%ss
-//PAGEBREAK!
lgdt gdtdesc
movl %cr0, %eax
orl $CR0_PE, %eax
movl %eax, %cr0
+//PAGEBREAK!
ljmp $(SEG_KCODE<<3), $start32
.code32
diff --git a/data.S b/data.S
index 47f05b3..c0eb55b 100644
--- a/data.S
+++ b/data.S
@@ -1,5 +1,24 @@
-# Define "data" symbol to mark beginning of data segment.
-# Must be linked before any other data on ld command line.
+// The kernel layout is:
+//
+// text
+// rodata
+// data
+// bss
+//
+// Conventionally, Unix linkers provide pseudo-symbols
+// etext, edata, and end, at the end of the text, data, and bss.
+// For the kernel mapping, we need the address at the beginning
+// of the data section, but that's not one of the conventional
+// symbols, because the convention started before there was a
+// read-only rodata section between text and data.
+//
+// To get the address of the data section, we define a symbol
+// named data and make sure this is the first object passed to
+// the linker, so that it will be the first symbol in the data section.
+//
+// Alternative approaches would be to parse our own ELF header
+// or to write a linker script, but this is simplest.
+
.data
.globl data
data:
diff --git a/exec.c b/exec.c
index 209bc79..05f80f8 100644
--- a/exec.c
+++ b/exec.c
@@ -10,8 +10,8 @@ int
exec(char *path, char **argv)
{
char *s, *last;
- int i, off, argc;
- uint sz, sp, strings[MAXARG];
+ int i, off;
+ uint argc, sz, sp, ustack[3+MAXARG+1];
struct elfhdr elf;
struct inode *ip;
struct proghdr ph;
@@ -53,49 +53,25 @@ exec(char *path, char **argv)
if((sz = allocuvm(pgdir, sz, sz + PGSIZE)) == 0)
goto bad;
- // initialize stack content:
-
- // "argumentN" -- nul-terminated string
- // ...
- // "argument0"
- // 0 -- argv[argc]
- // address of argumentN
- // ...
- // address of argument0 -- argv[0]
- // address of address of argument0 -- argv argument to main()
- // argc -- argc argument to main()
- // ffffffff -- return PC for main() call
-
+ // Push argument strings, prepare rest of stack in ustack.
sp = sz;
-
- // count arguments
- for(argc = 0; argv[argc]; argc++)
- ;
- if(argc >= MAXARG)
- goto bad;
-
- // push strings and remember where they are
- for(i = argc - 1; i >= 0; --i){
- sp -= strlen(argv[i]) + 1;
- strings[i] = sp;
- copyout(pgdir, sp, argv[i], strlen(argv[i]) + 1);
+ for(argc = 0; argv[argc]; argc++) {
+ if(argc >= MAXARG)
+ goto bad;
+ sp -= strlen(argv[argc]) + 1;
+ sp &= ~3;
+ if(copyout(pgdir, sp, argv[argc], strlen(argv[argc]) + 1) < 0)
+ goto bad;
+ ustack[3+argc] = sp;
}
+ ustack[3+argc] = 0;
-#define PUSH(x){ int xx = (int)(x); sp -= 4; copyout(pgdir, sp, &xx, 4); }
+ ustack[0] = 0xffffffff; // fake return PC
+ ustack[1] = argc;
+ ustack[2] = sp - (argc+1)*4; // argv pointer
- PUSH(0); // argv[argc] is zero
-
- // push argv[] elements
- for(i = argc - 1; i >= 0; --i)
- PUSH(strings[i]);
-
- PUSH(sp); // argv
-
- PUSH(argc);
-
- PUSH(0xffffffff); // in case main tries to return
-
- if(sp < sz - PGSIZE)
+ sp -= (3+argc+1) * 4;
+ if(copyout(pgdir, sp, ustack, (3+argc+1)*4) < 0)
goto bad;
// Save program name for debugging.
@@ -110,9 +86,7 @@ exec(char *path, char **argv)
proc->sz = sz;
proc->tf->eip = elf.entry; // main
proc->tf->esp = sp;
-
- switchuvm(proc);
-
+ switchuvm(proc);
freevm(oldpgdir);
return 0;
diff --git a/fs.h b/fs.h
index 6f92592..1e6137b 100644
--- a/fs.h
+++ b/fs.h
@@ -41,7 +41,6 @@ struct dinode {
// Block containing bit for block b
#define BBLOCK(b, ninodes) (b/BPB + (ninodes)/IPB + 3)
-// PAGEBREAK: 10
// Directory is a file containing a sequence of dirent structures.
#define DIRSIZ 14
diff --git a/ide.c b/ide.c
index f4bd210..53293a7 100644
--- a/ide.c
+++ b/ide.c
@@ -96,7 +96,7 @@ ideintr(void)
acquire(&idelock);
if((b = idequeue) == 0){
release(&idelock);
- cprintf("Spurious IDE interrupt.\n");
+ // cprintf("spurious IDE interrupt\n");
return;
}
idequeue = b->qnext;
diff --git a/main.c b/main.c
index 8a5f7f1..e6d81f3 100644
--- a/main.c
+++ b/main.c
@@ -89,7 +89,8 @@ bootothers(void)
char *stack;
// Write bootstrap code to unused memory at 0x7000.
- // The linker has placed the image of bootother.S in _binary_bootother_start.
+ // The linker has placed the image of bootother.S in
+ // _binary_bootother_start.
code = (uchar*)0x7000;
memmove(code, _binary_bootother_start, (uint)_binary_bootother_size);
@@ -111,3 +112,7 @@ bootothers(void)
;
}
}
+
+//PAGEBREAK!
+// Blank page.
+
diff --git a/mp.c b/mp.c
index 44ee020..5ab348e 100644
--- a/mp.c
+++ b/mp.c
@@ -39,7 +39,6 @@ mpsearch1(uchar *addr, int len)
{
uchar *e, *p;
- cprintf("mpsearch1 0x%x %d\n", addr, len);
e = addr+len;
for(p = addr; p < e; p += sizeof(struct mp))
if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0)
@@ -113,7 +112,6 @@ mpinit(void)
switch(*p){
case MPPROC:
proc = (struct mpproc*)p;
- cprintf("mpproc %d\n", proc->apicid);
if(ncpu != proc->apicid){
cprintf("mpinit: ncpu=%d apicid=%d\n", ncpu, proc->apicid);
ismp = 0;
diff --git a/proc.c b/proc.c
index e6ccd9d..eb334d0 100644
--- a/proc.c
+++ b/proc.c
@@ -25,44 +25,6 @@ pinit(void)
initlock(&ptable.lock, "ptable");
}
-//PAGEBREAK: 36
-// Print a process listing to console. For debugging.
-// Runs when user types ^P on console.
-// No lock to avoid wedging a stuck machine further.
-void
-procdump(void)
-{
- static char *states[] = {
- [UNUSED] "unused",
- [EMBRYO] "embryo",
- [SLEEPING] "sleep ",
- [RUNNABLE] "runble",
- [RUNNING] "run ",
- [ZOMBIE] "zombie"
- };
- int i;
- struct proc *p;
- char *state;
- uint pc[10];
-
- for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
- if(p->state == UNUSED)
- continue;
- if(p->state >= 0 && p->state < NELEM(states) && states[p->state])
- state = states[p->state];
- else
- state = "???";
- cprintf("%d %s %s", p->pid, state, p->name);
- if(p->state == SLEEPING){
- getcallerpcs((uint*)p->context->ebp+2, pc);
- for(i=0; i<10 && pc[i] != 0; i++)
- cprintf(" %p", pc[i]);
- }
- cprintf("\n");
- }
-}
-
-
//PAGEBREAK: 32
// Look in the process table for an UNUSED proc.
// If found, change state to EMBRYO and initialize
@@ -447,3 +409,41 @@ kill(int pid)
return -1;
}
+//PAGEBREAK: 36
+// Print a process listing to console. For debugging.
+// Runs when user types ^P on console.
+// No lock to avoid wedging a stuck machine further.
+void
+procdump(void)
+{
+ static char *states[] = {
+ [UNUSED] "unused",
+ [EMBRYO] "embryo",
+ [SLEEPING] "sleep ",
+ [RUNNABLE] "runble",
+ [RUNNING] "run ",
+ [ZOMBIE] "zombie"
+ };
+ int i;
+ struct proc *p;
+ char *state;
+ uint pc[10];
+
+ for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
+ if(p->state == UNUSED)
+ continue;
+ if(p->state >= 0 && p->state < NELEM(states) && states[p->state])
+ state = states[p->state];
+ else
+ state = "???";
+ cprintf("%d %s %s", p->pid, state, p->name);
+ if(p->state == SLEEPING){
+ getcallerpcs((uint*)p->context->ebp+2, pc);
+ for(i=0; i<10 && pc[i] != 0; i++)
+ cprintf(" %p", pc[i]);
+ }
+ cprintf("\n");
+ }
+}
+
+
diff --git a/runoff.list b/runoff.list
index 01147ea..f0edaf0 100644
--- a/runoff.list
+++ b/runoff.list
@@ -22,6 +22,7 @@ proc.h
proc.c
swtch.S
kalloc.c
+data.S
vm.c
# system calls
traps.h
@@ -48,6 +49,7 @@ exec.c
# pipes
pipe.c
+
# string operations
string.c
@@ -62,6 +64,7 @@ kbd.c
console.c
timer.c
uart.c
+multiboot.S
# user-level
initcode.S
@@ -72,3 +75,4 @@ sh.c
+
diff --git a/runoff.spec b/runoff.spec
index 8a2b5c9..4d00038 100644
--- a/runoff.spec
+++ b/runoff.spec
@@ -6,8 +6,8 @@ sheet1: left
# pages. The file may start in either column.
#
# "even" and "odd" specify which column a file must start on. "even"
-# means it must start in the left of the two columns. "odd" means it
-# must start in the right of the two columns.
+# means it must start in the left of the two columns (00). "odd" means it
+# must start in the right of the two columns (50).
#
# You'd think these would be the other way around.
@@ -33,23 +33,23 @@ left: spinlock.h # mild preference
even: spinlock.h # mild preference
# This gets struct proc and allocproc on the same spread
-right: proc.h
-odd: proc.h
+left: proc.h
+even: proc.h
# goal is to have two action-packed 2-page spreads,
# one with
# userinit growproc fork exit wait
# and another with
# scheduler sched yield forkret sleep wakeup1 wakeup
-left: proc.c # VERY important
-odd: proc.c # VERY important
+right: proc.c # VERY important
+even: proc.c # VERY important
# A few more action packed spreads
# page table creation and process loading
# walkpgdir mappages setupkvm vmenable switch[ku]vm inituvm loaduvm
# process memory management
# allocuvm deallocuvm freevm
-right: vm.c
+left: vm.c
odd: vm.c
# kalloc.c either
@@ -69,17 +69,25 @@ odd: vm.c
# file.h either
# fs.h either
# fsvar.h either
-left: ide.c
+# left: ide.c # mild preference
even: ide.c
# odd: bio.c
+
+# with fs.c starting on 2nd column of a left page, we get these 2-page spreads:
+# ialloc iupdate iget idup ilock iunlock iput iunlockput
+# bmap itrunc stati readi writei
+# namecmp dirlookup dirlink skipelem namex namei
+# fielinit filealloc filedup fileclose filestat fileread filewrite
+# starting on 2nd column of a right page is not terrible either
odd: fs.c # VERY important
+left: fs.c # mild preference
# file.c either
# exec.c either
# sysfile.c either
# even: pipe.c # mild preference
# string.c either
-left: kbd.h
+# left: kbd.h # mild preference
even: kbd.h
even: console.c
odd: sh.c
diff --git a/runoff1 b/runoff1
index ba42e8f..532f844 100755
--- a/runoff1
+++ b/runoff1
@@ -33,7 +33,7 @@ for($i=0; $i<@lines; ){
last if $i>=@lines;
# If the rest of the file fits, use the whole thing.
- if(@lines <= $i+50){
+ if(@lines <= $i+50 && !grep { /PAGEBREAK/ } @lines){
$breakbefore = @lines;
}else{
# Find a good next page break;
diff --git a/toc.ftr b/toc.ftr
index 3ed8593..5e15911 100644
--- a/toc.ftr
+++ b/toc.ftr
@@ -6,8 +6,8 @@ on the same line as the name, the line number (or, in a few cases, numbers)
where the name is defined. Successive lines in an entry list the line
numbers where the name is used. For example, this entry:
- swtch 2308
- 0317 2128 2166 2307 2308
+ swtch 2358
+ 0317 2128 2166 2357 2358
-indicates that swtch is defined on line 2308 and is mentioned on five lines
+indicates that swtch is defined on line 2358 and is mentioned on five lines
on sheets 03, 21, and 23.
diff --git a/trap.c b/trap.c
index b2b2ebb..6651f8e 100644
--- a/trap.c
+++ b/trap.c
@@ -59,6 +59,9 @@ trap(struct trapframe *tf)
ideintr();
lapiceoi();
break;
+ case T_IRQ0 + IRQ_IDE+1:
+ // Bochs generates spurious IDE1 interrupts.
+ break;
case T_IRQ0 + IRQ_KBD:
kbdintr();
lapiceoi();
diff --git a/usertests.c b/usertests.c
index 9a83591..296731a 100644
--- a/usertests.c
+++ b/usertests.c
@@ -1445,11 +1445,11 @@ bigargtest(void)
ppid = getpid();
pid = fork();
if(pid == 0){
- char *args[32];
+ char *args[32+1];
int i;
- for(i = 0; i < 32-1; i++)
+ for(i = 0; i < 32; i++)
args[i] = "bigargs test: failed\n ";
- args[32-1] = 0;
+ args[32] = 0;
printf(stdout, "bigarg test\n");
exec("echo", args);
printf(stdout, "bigarg test ok\n");
diff --git a/vm.c b/vm.c
index bfc0845..1fe64d2 100644
--- a/vm.c
+++ b/vm.c
@@ -6,8 +6,18 @@
#include "proc.h"
#include "elf.h"
+extern char data[]; // defined in data.S
+
static pde_t *kpgdir; // for use in scheduler()
+// Allocate one page table for the machine for the kernel address
+// space for scheduler processes.
+void
+kvmalloc(void)
+{
+ kpgdir = setupkvm();
+}
+
// Set up CPU's kernel segment descriptors.
// Run once at boot time on each CPU.
void
@@ -72,7 +82,6 @@ mappages(pde_t *pgdir, void *la, uint size, uint pa, int perm)
a = PGROUNDDOWN(la);
last = PGROUNDDOWN(la + size - 1);
-
for(;;){
pte = walkpgdir(pgdir, a, 1);
if(pte == 0)
@@ -110,40 +119,32 @@ mappages(pde_t *pgdir, void *la, uint size, uint pa, int perm)
// range from 0 till 640KB (USERTOP), which where the I/O hole starts
// (both in physical memory and in the kernel's virtual address
// space).
-
-// Allocate one page table for the machine for the kernel address
-// space for scheduler processes.
-void
-kvmalloc(void)
-{
- kpgdir = setupkvm();
-}
+static struct kmap {
+ void *p;
+ void *e;
+ int perm;
+} kmap[] = {
+ {(void*)USERTOP, (void*)0x100000, PTE_W}, // I/O space
+ {(void*)0x100000, data, 0 }, // kernel text, rodata
+ {data, (void*)PHYSTOP, PTE_W}, // kernel data, memory
+ {(void*)0xFE000000, 0, PTE_W}, // device mappings
+};
// Set up kernel part of a page table.
pde_t*
setupkvm(void)
{
- extern char etext[];
- char *rwstart;
pde_t *pgdir;
- uint rwlen;
-
- rwstart = PGROUNDDOWN(etext);
- rwlen = (uint)rwstart - 0x100000;
+ struct kmap *k;
- // Allocate page directory
if((pgdir = (pde_t*)kalloc()) == 0)
return 0;
memset(pgdir, 0, PGSIZE);
- if(// Map IO space from 640K to 1Mbyte
- mappages(pgdir, (void*)USERTOP, 0x60000, USERTOP, PTE_W) < 0 ||
- // Map kernel instructions
- mappages(pgdir, (void*)0x100000, rwlen, 0x100000, 0) < 0 ||
- // Map kernel data and free memory pool
- mappages(pgdir, rwstart, PHYSTOP-(uint)rwstart, (uint)rwstart, PTE_W) < 0 ||
- // Map devices such as ioapic, lapic, ...
- mappages(pgdir, (void*)0xFE000000, 0x2000000, 0xFE000000, PTE_W) < 0)
- return 0;
+ k = kmap;
+ for(k = kmap; k < &kmap[NELEM(kmap)]; k++)
+ if(mappages(pgdir, k->p, k->e - k->p, (uint)k->p, k->perm) < 0)
+ return 0;
+
return pgdir;
}
@@ -162,48 +163,27 @@ vmenable(void)
// Switch h/w page table register to the kernel-only page table,
// for when no process is running.
void
-switchkvm()
+switchkvm(void)
{
lcr3(PADDR(kpgdir)); // switch to the kernel page table
}
-// Switch h/w page table and TSS registers to point to process p.
+// Switch TSS and h/w page table to correspond to process p.
void
switchuvm(struct proc *p)
{
pushcli();
-
- // Setup TSS
cpu->gdt[SEG_TSS] = SEG16(STS_T32A, &cpu->ts, sizeof(cpu->ts)-1, 0);
cpu->gdt[SEG_TSS].s = 0;
cpu->ts.ss0 = SEG_KDATA << 3;
cpu->ts.esp0 = (uint)proc->kstack + KSTACKSIZE;
ltr(SEG_TSS << 3);
-
if(p->pgdir == 0)
- panic("switchuvm: no pgdir\n");
-
+ panic("switchuvm: no pgdir");
lcr3(PADDR(p->pgdir)); // switch to new address space
popcli();
}
-// Return the physical address that a given user address
-// maps to. The result is also a kernel logical address,
-// since the kernel maps the physical memory allocated to user
-// processes directly.
-char*
-uva2ka(pde_t *pgdir, char *uva)
-{
- pte_t *pte;
-
- pte = walkpgdir(pgdir, uva, 0);
- if((*pte & PTE_P) == 0)
- return 0;
- if((*pte & PTE_U) == 0)
- return 0;
- return (char*)PTE_ADDR(*pte);
-}
-
// Load the initcode into address 0 of pgdir.
// sz must be less than a page.
void
@@ -228,10 +208,10 @@ loaduvm(pde_t *pgdir, char *addr, struct inode *ip, uint offset, uint sz)
pte_t *pte;
if((uint)addr % PGSIZE != 0)
- panic("loaduvm: addr must be page aligned\n");
+ panic("loaduvm: addr must be page aligned");
for(i = 0; i < sz; i += PGSIZE){
if((pte = walkpgdir(pgdir, addr+i, 0)) == 0)
- panic("loaduvm: address should exist\n");
+ panic("loaduvm: address should exist");
pa = PTE_ADDR(*pte);
if(sz - i < PGSIZE)
n = sz - i;
@@ -243,10 +223,8 @@ loaduvm(pde_t *pgdir, char *addr, struct inode *ip, uint offset, uint sz)
return 0;
}
-// Allocate memory to the process to bring its size from oldsz to
-// newsz. Allocates physical memory and page table entries. oldsz and
-// newsz need not be page-aligned, nor does newsz have to be larger
-// than oldsz. Returns the new process size or 0 on error.
+// Allocate page tables and physical memory to grow process from oldsz to
+// newsz, which need not be page aligned. Returns new size or 0 on error.
int
allocuvm(pde_t *pgdir, uint oldsz, uint newsz)
{
@@ -330,9 +308,9 @@ copyuvm(pde_t *pgdir, uint sz)
return 0;
for(i = 0; i < sz; i += PGSIZE){
if((pte = walkpgdir(pgdir, (void*)i, 0)) == 0)
- panic("copyuvm: pte should exist\n");
+ panic("copyuvm: pte should exist");
if(!(*pte & PTE_P))
- panic("copyuvm: page not present\n");
+ panic("copyuvm: page not present");
pa = PTE_ADDR(*pte);
if((mem = kalloc()) == 0)
goto bad;
@@ -347,16 +325,31 @@ bad:
return 0;
}
-// copy some data to user address va in page table pgdir.
-// most useful when pgdir is not the current page table.
+//PAGEBREAK!
+// Map user virtual address to kernel physical address.
+char*
+uva2ka(pde_t *pgdir, char *uva)
+{
+ pte_t *pte;
+
+ pte = walkpgdir(pgdir, uva, 0);
+ if((*pte & PTE_P) == 0)
+ return 0;
+ if((*pte & PTE_U) == 0)
+ return 0;
+ return (char*)PTE_ADDR(*pte);
+}
+
+// Copy len bytes from p to user address va in page table pgdir.
+// Most useful when pgdir is not the current page table.
// uva2ka ensures this only works for PTE_U pages.
int
-copyout(pde_t *pgdir, uint va, void *xbuf, uint len)
+copyout(pde_t *pgdir, uint va, void *p, uint len)
{
char *buf, *pa0;
uint n, va0;
- buf = (char*)xbuf;
+ buf = (char*)p;
while(len > 0){
va0 = (uint)PGROUNDDOWN(va);
pa0 = uva2ka(pgdir, (char*)va0);