xv6: formatting, cleanup, rev5 (take 2)
This commit is contained in:
		
							parent
							
								
									9c4fe7ba10
								
							
						
					
					
						commit
						cf4b1ad90b
					
				
					 17 changed files with 193 additions and 197 deletions
				
			
		
							
								
								
									
										20
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										29
									
								
								bootasm.S
									
										
									
									
									
								
							
							
						
						
									
										29
									
								
								bootasm.S
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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.
 | 
			
		||||
//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
 | 
			
		||||
 | 
			
		||||
# tell the assembler to generate 0x66 prefixes for 16-bit
 | 
			
		||||
# instructions like movw, and to generate 32-bit immediate
 | 
			
		||||
# addresses.
 | 
			
		||||
.code32
 | 
			
		||||
 | 
			
		||||
.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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										23
									
								
								data.S
									
										
									
									
									
								
							
							
						
						
									
										23
									
								
								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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										56
									
								
								exec.c
									
										
									
									
									
								
							
							
						
						
									
										56
									
								
								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++)
 | 
			
		||||
    ;
 | 
			
		||||
  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);
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
  freevm(oldpgdir);
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								fs.h
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								ide.c
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										7
									
								
								main.c
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								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.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								mp.c
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										76
									
								
								proc.c
									
										
									
									
									
								
							
							
						
						
									
										76
									
								
								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");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										26
									
								
								runoff.spec
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								runoff1
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										6
									
								
								toc.ftr
									
										
									
									
									
								
							
							
						
						
									
										6
									
								
								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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								trap.c
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								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();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										113
									
								
								vm.c
									
										
									
									
									
								
							
							
						
						
									
										113
									
								
								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;
 | 
			
		||||
  struct kmap *k;
 | 
			
		||||
 | 
			
		||||
  rwstart = PGROUNDDOWN(etext);
 | 
			
		||||
  rwlen = (uint)rwstart - 0x100000;
 | 
			
		||||
 | 
			
		||||
  // 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)
 | 
			
		||||
  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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue