Beispiel #1
0
//pmm_init - setup a pmm to manage physical memory, build PDT&PT to setup paging mechanism 
//         - check the correctness of pmm & paging mechanism, print PDT&PT
void
pmm_init(void) {
	init_pmm_manager ();
	page_init ();
	
#ifndef NOCHECK
    //check_alloc_page();
#endif

	boot_pgdir = boot_alloc_page ();
	memset (boot_pgdir, 0, PGSIZE);
	boot_pgdir_pa = PADDR (boot_pgdir);
	current_pgdir_pa = boot_pgdir_pa;

#ifndef NOCHECK
	//check_pgdir ();
#endif

	static_assert(KERNBASE % PTSIZE == 0 && KERNTOP % PTSIZE == 0);

	boot_pgdir[PDX(VPT)] = PADDR(boot_pgdir) | PTE_P | PTE_SPR_R | PTE_SPR_W | PTE_A | PTE_D;
    boot_map_segment(boot_pgdir, KERNBASE, RAM_SIZE, 0, PTE_SPR_R | PTE_SPR_W | PTE_A | PTE_D);

	enable_paging ();
#ifndef NOCHECK
	//check_boot_pgdir ();
#endif
	
    print_pgdir (kprintf);

	slab_init ();
}
Beispiel #2
0
void start_process(volatile process *p) {
    //////print("~~~~ Process started with id = %d and CR3 is %x ~~~~",p->pid,p->cr3);
    enable_paging(p->cr3);
    current_running_process = p;
    p->state = TASK_RUNNING;
    //////print("Process started suckaaaaa %d",p->pid);
}
Beispiel #3
0
static void switch_to_higher_half()
{
    uint32_t i, entries;

    /* zero out paging structure */
    memset((void *) _BSP_PD, 0, sizeof(_BSP_PD));

    /* entries count required to map the kernel */
    entries = ((uint32_t)(&kernel_end) + KERNEL_HEAP_SIZE + TABLE_MASK) / TABLE_SIZE;

    uint32_t *_BSP_PT = (uint32_t *) scratch; //init_heap_alloc(entries * PAGE_SIZE, PAGE_SIZE);

    /* identity map pages */
    for (i = 0; i < entries * 1024; ++i)
        _BSP_PT[i] = (i * PAGE_SIZE) | P | RW;

    /* map the lower-half */
    for (i = 0; i < entries; ++i)
        _BSP_PD[i] = ((uint32_t) _BSP_PT + i * PAGE_SIZE) | P | RW;

    /* map the upper-half */
    for (i = 0; i < entries; ++i)
        _BSP_PD[768 + i] = ((uint32_t) _BSP_PT + i * PAGE_SIZE) | P | RW;

    /* Enable paging using Bootstrap Processor Page Directory */
    enable_paging((uint32_t) _BSP_PD);
}
Beispiel #4
0
/*
 * init_page_directory
 *   DESCRIPTION: Initializes page_directory entries to not present, then fills first  
 * 				  entry with 4mb of 1024 4kb pages. Then fills next entry with just one
 *				  4mb page for the kernal. 
 *   INPUTS: none
 *   OUTPUTS: none
 *   RETURN VALUE: none
 *   SIDE EFFECTS: Enables paging once it sets the page directory/table
 */ 
void init_page_directory(uint32_t address){
	int i,j=0; // for iterations
	// calculate index from vidmap address
	uint16_t page_dir_index = (VIDMAP & PD_INDEX_MASK) >> 22;
	// initialize page directory to not present
	for (i=0;i<INDEX_SIZE;i++){
		page_directory[i] = NOT_PRESENT_WRITE; // initialize page directory to read/write but not present
	}
	// initialize all pages to not present when creating new page table
	for (i=0;i<INDEX_SIZE;i++){
		page_table_vidmap[i] = j | NOT_PRESENT_WRITE; // initialize to supervisor, read/write, not present
		j = j + SIZE_OF_PAGE; // increment by one 4kb page
	}
	// map a 4kb page for the first terminal
	page_table_vidmap[0] = VIDEO_ADDR | PRESENT_USER; // initialize passed flags
	// map a 4kb page for the second terminal
	page_table_vidmap[1] = (VIDMAP + SIZE_OF_PAGE) | PRESENT_USER; // initialize passed flags
	// map a 4kb page for the third terminal
	page_table_vidmap[2] = (VIDMAP + 2*SIZE_OF_PAGE) | PRESENT_USER; // initialize passed flags
	// set constructed page table to correct index of page directory
	page_directory[page_dir_index] = (uint32_t)page_table_vidmap | PRESENT_USER;
	// map first 4mb with 1024 4kb pages
	map_4kb_page(VIDEO_ADDR, PRESENT_WRITE);
	// map second 4mb with one 4mb page
	map_4mb_page(FOUR_MEGABYTES, KERNEL_FLAGS);
	// enable paging by setting the control registers in "paging_control.S"
	enable_paging(page_directory);
	return;
}
Beispiel #5
0
//pmm_init - setup a pmm to manage physical memory, build PDT&PT to setup paging mechanism 
//         - check the correctness of pmm & paging mechanism, print PDT&PT
void
pmm_init(void) {
    //We need to alloc/free the physical memory (granularity is 4KB or other size). 
    //So a framework of physical memory manager (struct pmm_manager)is defined in pmm.h
    //First we should init a physical memory manager(pmm) based on the framework.
    //Then pmm can alloc/free the physical memory. 
    //Now the first_fit/best_fit/worst_fit/buddy_system pmm are available.
    init_pmm_manager();

    // detect physical memory space, reserve already used memory,
    // then use pmm->init_memmap to create free page list
    page_init();

    //use pmm->check to verify the correctness of the alloc/free function in a pmm
    check_alloc_page();

    // create boot_pgdir, an initial page directory(Page Directory Table, PDT)
    boot_pgdir = boot_alloc_page();
    memset(boot_pgdir, 0, PGSIZE);
    boot_cr3 = PADDR(boot_pgdir);

    check_pgdir();


    static_assert(KERNBASE % PTSIZE == 0 && KERNTOP % PTSIZE == 0);

    // recursively insert boot_pgdir in itself
    // to form a virtual page table at virtual address VPT
 //   cprintf("haah1\n");
    // map all physical memory to linear memory with base linear addr KERNBASE
    //linear_addr KERNBASE~KERNBASE+KMEMSIZE = phy_addr 0~KMEMSIZE
    //But shouldn't use this map until enable_paging() & gdt_init() finished.
    boot_map_segment(boot_pgdir, 0, KMEMSIZE, 0, PTE_TYPE_URWX_SRWX | PTE_R | PTE_V);
    boot_pgdir[PDX(VPT)] = PADDR(boot_pgdir) | PTE_TYPE_TABLE | PTE_R | PTE_V;
   // pgdir_alloc_page(boot_pgdir, USTACKTOP-PGSIZE , PTE_TYPE_URW_SRW);
    //cprintf("haha2\n");
    //temporary map: 
    //virtual_addr 3G~3G+4M = linear_addr 0~4M = linear_addr 3G~3G+4M = phy_addr 0~4M     
    //boot_pgdir[0] = boot_pgdir[PDX(KERNBASE)];
    //cprintf("OK!\n");
    enable_paging();
//    cprintf("haah\n");
    //reload gdt(third time,the last time) to map all physical memory
    //virtual_addr 0~4G=liear_addr 0~4G
    //then set kernel stack(ss:esp) in TSS, setup TSS in gdt, load TSS
    //gdt_init();

    //disable the map of virtual_addr 0~4M
    //boot_pgdir[0] = 0;

    //now the basic virtual memory map(see memalyout.h) is established.
    //check the correctness of the basic virtual memory map.
    check_boot_pgdir();

    print_pgdir();

    kmalloc_init();

}
Beispiel #6
0
/*------------------------------------------------------------------------
 *  nulluser  -- initialize system and become the null process (id==0)
 *------------------------------------------------------------------------
 */
nulluser()				/* babysit CPU when no one is home */
{
        int userpid;

	console_dev = SERIAL0;		/* set console to COM0 */

	initevec();

	kprintf("system running up!\n");
	sysinit();

	/* create a process to execute the user's main program */
	/*****************************/

	enable();		/* enable interrupts */

	sprintf(vers, "PC Xinu %s", VERSION);
	kprintf("\n\n%s\n", vers);
	if (reboot++ < 1)
		kprintf("\n");
	else
		kprintf("   (reboot %d)\n", reboot);


	kprintf("%d bytes real mem\n",
		(unsigned long) maxaddr+1);
#ifdef DETAIL	
	kprintf("    %d", (unsigned long) 0);
	kprintf(" to %d\n", (unsigned long) (maxaddr) );
#endif	

	kprintf("%d bytes Xinu code\n",
		(unsigned long) ((unsigned long) &end - (unsigned long) start));
#ifdef DETAIL	
	kprintf("    %d", (unsigned long) start);
	kprintf(" to %d\n", (unsigned long) &end );
#endif

#ifdef DETAIL	
	kprintf("%d bytes user stack/heap space\n",
		(unsigned long) ((unsigned long) maxaddr - (unsigned long) &end));
	kprintf("    %d", (unsigned long) &end);
	kprintf(" to %d\n", (unsigned long) maxaddr);
#endif	
	
	kprintf("clock %sabled\n", clkruns == 1?"en":"dis");

	userpid = create(main, INITSTK, INITPRIO, INITNAME, INITARGS);


	enable_paging((proctab[NULLPROC].pd->frm_num) * NBPG);
	enable();
	resume(userpid);

	/* create a process to execute the user's main program */

	while (TRUE)
		/* empty */;
}
Beispiel #7
0
void setup_pdt_enable_paging() {
	uint16_t i = 0;

	while(i < 1024) {
		PDT[i].address = i * 0x400000;
		PDT[i].page_size = 1;
		PDT[i].rw = 1;
		PDT[i].present = 1;

		i++;
	}

	enable_paging((uint32_t) &PDT);
}
Beispiel #8
0
static page_frame_t kernel_page_table_install(struct multiboot_info *mb) {
    // Certain very important things already exist in physical memory. They
    // need to be marked as present so that the allocator doesn't grab them by
    // accident.
    // After they are marked as present they can safely be mapped with
    // map_page.

    // Iterate over the multiboot memory map table and mark certain addresses
    // as unusable.
    klogf("Marking unusable!\n");
    multiboot_memory_map_t *mm_last = (multiboot_memory_map_t*)(mb->mmap_addr +
        mb->mmap_length);
    for (multiboot_memory_map_t *mm = (multiboot_memory_map_t*)mb->mmap_addr;
         mm < mm_last;
         mm = (multiboot_memory_map_t*)((uintptr_t)mm +
                                        mm->size + sizeof(mm->size))) {
        // If the memory is not available
        if (mm->type != MULTIBOOT_MEMORY_AVAILABLE) {
            klogf("Unusable physical address %p of type %p and length %p\n",
                    mm->addr, mm->type, mm->len);
            for (uint64_t page = PAGE_ALIGN(mm->addr);
                 page < NEXT_PAGE(mm->addr+mm->len); page += PAGE_SIZE) {
                use_frame(page);
            }
        }
    }
    klogf("mm_addr table %p\n", mb->mmap_addr);
    klogf("apm table %p\n", mb->apm_table);
    klogf("fb table %p\n", mb->framebuffer_addr);
    klogf("vbe int off %p\n", mb->vbe_interface_off);

    // Catch NULL pointer dereferences
    use_frame(0);

    // Mark all the pages the kernel sits on as used
    use_range(KERNEL_START, KERNEL_END);

    // Mark the kernel heap as in use
    use_frame(KHEAP_PHYS_ROOT);
    // Mark video memory as in use
    use_range(VGA_BEGIN, VGA_END);

    // Mark the paging directory as in use
    use_frame(PAGE_DIRECTORY);
    page_frame_t page_dir = bootstrap_kernel_page_table();

    enable_paging(page_dir);
    return page_dir;
}
Beispiel #9
0
void init_paging()
{
	size_t sz;
	uint32_t i;
	uint32_t mem_end_page;

	DPRINTK("paging...\t\t");

	mem_end_page = 0x1000000;
	nframes = mem_end_page / PAGE_SIZ;

	sz = INDEX_FROM_BIT(nframes);
	frames = (uint32_t *)kmalloc(sz);
	memset(frames, 0, sz);

	kernel_directory = (struct page_directory *)
		kmalloc_a(sizeof(struct page_directory));
	memset(kernel_directory, 0, sizeof(struct page_directory));

	// don't do this...
	current_directory = kernel_directory;

	// do this instead...
	kernel_directory->physical_addr = (uint32_t)kernel_directory->tables_physical;

	for (i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += PAGE_SIZ)
		get_page(i, 1, kernel_directory);

	i = 0;
	while (i < placement_addr + PAGE_SIZ) {
		alloc_frame(get_page(i, 1, kernel_directory), 0, 0);
		i += PAGE_SIZ;
	}

	for (i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += PAGE_SIZ)
		alloc_frame(get_page(i, 1, kernel_directory), 0, 0);

	// register_interrupt_handler(14, page_fault);

	switch_page_directory(kernel_directory);
	enable_paging();

	kheap = create_heap(KHEAP_START, KHEAP_START + KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0);

	current_directory = clone_directory(kernel_directory);
        switch_page_directory(current_directory);

	DPRINTK("done!\n");
}
Beispiel #10
0
Datei: vm.c Projekt: joao29a/boot
void paging_init(void) {

    memset(page_directory, 0, sizeof(unsigned long) * 1024);
    memset(page_table, 0, sizeof(unsigned long) * 1024);
    
    
    int i;
    for(i=0;i<1024;i++){
        page_table[i] = (i*4096) | flagsPTE;	
	page_directory[i] = 0;
    }
 
    page_directory[0] = (unsigned long) page_table | flagsPDE;
    
    enable_paging((unsigned long)page_directory);
}
Beispiel #11
0
Datei: vm.c Projekt: YuKill/boot
void paging_init(void) {

    memset(kpage_directory, 0, sizeof(unsigned long) * 1024);
    memset(kpage_tables, 0,
          sizeof(unsigned long) * 1024 * page_directory_size);

    int i,j,address = 0;
    for(j=0;j<page_directory_size;j++){

      for(i=0;i<1024;i++){
           kpage_tables[j].entry[i] = address | flagsPTE;
           address = address + 4096;
      }

      kpage_directory[j] = (unsigned long) &kpage_tables[j] | flagsPDE;
    }
    enable_paging((unsigned long)kpage_directory);
}
Beispiel #12
0
/* initPaging: initialize system page table.  Everything is mapped flat, 
 * and private memory is cached. */
void initPaging()
{
	unsigned long addrMap, mloc;

	// Zero out the page tables
	void _asm_bzero(unsigned long base, unsigned long count);
	_asm_bzero(PTBASE, 1024*1024*4);

	// Fill in PD entries
	addrMap = PTBASE;
	for (mloc = 0; mloc < 1023*4; mloc+=4)
	{
		*(unsigned long *)mloc = addrMap | PTE_P | PTE_RW;
		addrMap += 0x1000;
	}

	// Last PD entry points to the PD itself.
	*(unsigned long *)mloc = PAGEDIRLOC | PTE_P | PTE_RW;

#define MAP(virt, phys, vlimit, flags) \
	addrMap = (phys); \
	for (mloc = (virt)/0x400+PTBASE; mloc < (vlimit)/0x400+PTBASE; mloc+=4) \
	{ \
		*(unsigned long *)mloc = addrMap | (flags); \
		addrMap += 0x1000; \
	}

	// Fill in PT entries
	// Private mem (0x0 -> same; < 0x29000000)
	MAP(0, 0, 0x29000000, PTE_P | PTE_RW);
	// SHM (0x80000000 -> same; < 0x84000000)
	MAP(0x80000000, 0x80000000, 0x84000000, PTE_P | PTE_RW | PTE_CD);
	// MPB (0xc0000000 -> same; < 0xd9000000)
	MAP(0xc0000000, 0xc0000000, 0xd9000000, PTE_P | PTE_RW | PTE_PMB);
	// CRB, FPGA, MCPC TCP/IP IF, and VRC (0xe0000000 -> same; < 0xfc000000)
	MAP(0xe0000000, 0xe0000000, 0xfc000000, PTE_P | PTE_RW | PTE_CD);
	// APIC and upper private mem (0xfee00000 -> same; < 0xffc00000)
	MAP(0xfee00000, 0xfee00000, 0xffc00000, PTE_P | PTE_RW | PTE_CD);

	enable_paging(PAGEDIRLOC);
}
Beispiel #13
0
/* To init paging, we identity map the first 4MB of memory to the kernel's 
 * page table.  Then we set bit 31 of cr0. */
int init_paging()
{
  uint32 i, j, pdes, error;
  void* addr = 0;
  word_t *p;

  kern_page_dir = (word_t)PD_BASE;
  /* This division will have MOD of 0.  If not, there is an awkward ammount
   * of memory (not 4K divisable) and we just ignore the leftover. */
  pdes = frame_count/PT_ENTRIES;    /* Number of required page directory 
                                       entires to map all physical frames. */

  /* Zero out the page table. */
  bzero( (void*)kern_page_dir, FRAME_LEN );

  /* Map all of physical memory to the kernel page table. */
  for( i = 0; i < pdes; i++ ) {
    p = (word_t*)MEMMAN_ALLOC_KERN_FRAME( &error );
    if( error == 1 ) { 
      kprintf( "Error allocating kernel frame for PT.\n" );
      return RET_FAILURE;
    }

    for( j = 0; j < PT_ENTRIES; j++ ) {
      p[j] = frame_to_pte_user( (word_t)addr );
      addr += FRAME_LEN;
    }

    ((word_t*)kern_page_dir)[i] = frame_to_pde_user( (word_t)p );
  }

  /* Load the page directory into cr3. */
  __asm__ __volatile( "movl %0, %%eax; \
                       movl %%eax, %%cr3" : : "r" (kern_page_dir) ); 

  /* Enable paging. */
  enable_paging();

  return RET_SUCCESS;
}
Beispiel #14
0
void
procB(void)
{
    int rc = EMPTY;
    int vpage = 8000;
    int npages = 100;
    int bs_id = 5;
    char *x;
    char temp;

    rc = get_bs(bs_id, npages);
    kprintf("get_bs in %s.. %d\n", __func__, rc);

    rc = xmmap(vpage, bs_id, npages);
    kprintf("xmmap in %s.. %d\n", rc);

    x = (char *) (vpage * NBPG);
    kprintf("%s trying to access vaddr 0x%08x\n", __func__, x);
    temp = *x;
    kprintf("value of temp in %s.. %c\n", __func__, temp);

    sleep(1);

    enable_paging();
    *x =  's';
    temp = *x;
    kprintf("value of temp in %s.. %c\n", __func__, temp);

    rc = xmunmap(vpage);
    kprintf("xmunmap in %s.. %d\n", __func__, rc);

    /* Try to access VM after unmapping it. The process should be killed. */
    kprintf("value of temp in %s.. %c\n", __func__, *x);
    kprintf("This line should never be printed!\n");

    rc = release_bs(bs_id);
    kprintf("release_bs in %s.. %d\n", __func__, rc);
    
    return;
}
void
init()
{
	struct ext_mem_format *ptr_exts; // structure-pointer to structure
	struct ext_mem_format temp_struc; // temporary structure
	struct inode ino_kern;
	struct ext_mem_format ext_mem_strucs[50]; // 386 usable RAM list format

	usec_t ino_sec;
	ubyte_t num_servs; // number of servers to read to memory
	uint_t tot_mem, counter, counter1; // counters
	byte *ptr_mem=(byte *)ext_mem_strucs; // byte-pointer to structure

	/* 
	 * Get absolute sector for first ivector.
	 * It is stored in a global variable.
	 */
	sosfs_ivec_first();

	/* read kernel's and server's inode sector */
	ino_sec = sosfs_iget("/boot/kernel");
	/* if error */
	if (ino_sec == -1) {
		low_putstr("Inode not found\n"); 
		while (1);
	}
	/* read kernel's inode */
	sosfs_read_raw(ino_sec, &ino_kern);

	/* zero out the vector */
	for (tot_mem=0; tot_mem<512; tot_mem++)
		buffer[tot_mem]=0;

	/* 
	 * Copy arguments from real-mode to protected-mode.
	 * The monitor program wishes to pass the arguments to the kernel.
	 * This is done by a little hack that uses an interrupt instruction
	 * passing a buffer to copy from real-mode to protected-mode using
	 * BIOS.
	 */
	kargs_init();

	/* 
	 * Get total amount of RAM.
	 * The most reliable way to know the system's memory-mapping
	 * is by using the BIOS; we use int $0x15 function 0xe820.
	 */
	low_tot_ram(ext_mem_strucs);

	/* point to memory-map vector */
	ptr_exts=ext_mem_strucs;
	/* 
	 * Traverse the structures until magic number found.
	 * Our interrupt handler set a magic number after the last
	 * entry returned by the BIOS handler.
	 */
	kprintf("\n");
	kprintf("BIOS-provided physical-memory mappings\n");
	kprintf("======================================================\n");
	while (ptr_exts->acpi_ext != 0x12345) {
		/* if we must ignore the entry, so we do */
		if (ptr_exts->reg_len == 0)
			continue;
		/* print type of memory to terminal */
		switch (ptr_exts->reg_type) {
			case 1:
				kprintf("Usable RAM at ");
				if (ptr_exts->base_addr[0] != 0) {
					zero_mem(ptr_exts);
					put_list(ptr_exts);
				}
				break;
			case 2:
				kprintf("Reserved/unusable RAM at ");
				break;
			case 3:
			case 4:
			case 5:
				kprintf("ACPI RAM at ");
				break;
		}
		/*
		 * Create a temporary structure and copy the entire structure
		 * to it.
		 * Print the address range.
		 */
		temp_struc = *ptr_exts; // copy structure
		temp_struc.reg_len[0] += temp_struc.base_addr[0];
		kprintf("%x-", &temp_struc);
		kprintf("%x", temp_struc.reg_len);
		kprintf("\n");
		for (tot_mem=0; tot_mem<512; tot_mem++)
			buffer[tot_mem]=0;
		ptr_exts++; // advance one structure
	}
	kprintf("======================================================\n");

	/* 
	 * Set up initial memory mappings.
	 * Load user-level servers to predefined physical memory and
	 * identically map them. Map the monitor program and the kernel
	 * also to identical physical addresses. Also map those programs'
	 * heaps.
	 */
	load_init();
	heap_init();
	/* list returned by BIOS might be unsorted */
	sort_free_list();
	/* machine-dependent format to machine-independent format */
	dep_2_indep_list(ptr_list);
	mmap_init();
	enable_paging();
	SOS_init();
}
Beispiel #16
0
/*
 * syscall_execve
 * 
 * Implements the execve system call. This effectively does a "brain transplant"
 * on a process by arranging for it to run a different program to what it was
 * previously. This is achieved by loading the new program from the file system,
 * placing a copy in the process's text segment, and changing the instruction
 * pointer of the process to point to the first instruction of the loaded
 * executable file.
 * 
 * In addition to loading a new program, this call is also responsible for passing
 * command line arguments to the new program. This is done by using the memory
 * at the bottom of the stack (actually the highest address, since the stack grows
 * downwards), in which the array of strings corresponding to argv is placed. The
 * argv and argc values are placed at the top of the stack, so that the main
 * function will be able to access them as arguments.
 */
int
syscall_execve(const char *filename, char *const argv[],
	       char *const envp[], regs * r)
{
	process *proc = current_process;

	/*
	 * Verify that the filename and all of the pointers within argc arg valid
	 * (i.e. completely reside in the process's address space) 
	 */
	if (!valid_string(filename))
		return -EFAULT;

	unsigned int argno = 0;
	if (NULL != argv) {
		while (1) {
			if (!valid_pointer(argv, (argno + 1) * sizeof(char *)))
				return -EFAULT;
			if (NULL == argv[argno])
				break;
			if (!valid_string(argv[argno]))
				return -EFAULT;
			argno++;
		}
	}

	/*
	 * Check that the specified executable file actually exists, and find out its
	 * location within the file system 
	 */
	directory_entry *entry;
	int res;
	if (0 > (res = get_directory_entry(filesystem, filename, &entry)))
		return res;
	if (TYPE_DIR == entry->type)
		return -EISDIR;

	/*
	 * Calculate number of arguments and amount of space needed to store them 
	 */
	unsigned int argc = 0;
	unsigned int argslen = 0;
	for (argc = 0; argv && argv[argc]; argc++)
		argslen += strlen(argv[argc]) + 1;

	/*
	 * Allocate a temporary buffer in which to store the argument data. This will
	 * later be copied to the process's stack. The reason we can't do this
	 * in-place is that doing so would risk overwriting some of the data we are
	 * copying from. 
	 */
	unsigned int argdata_size =
	    argslen + argc * sizeof(char *) + 2 * sizeof(int);
	char *argdata = kmalloc(argdata_size);
	char **newargv = (char **)(argdata + 8);

	/*
	 * Work backwards through the allocated buffer, copying in the strings one-
	 * by-one 
	 */
	unsigned int pos = argdata_size;
	for (argno = 0; argno < argc; argno++) {
		unsigned int nbytes = strlen(argv[argno]) + 1;
		pos -= nbytes;
		memmove(&argdata[pos], argv[argno], nbytes);
		newargv[argno] =
		    (char *)(PROCESS_STACK_BASE - argdata_size + pos);
	}

	/*
	 * Set argc and argv as the top two words on the stack. These are the values
	 * that main will see passed in as its parameters. 
	 */
	*(unsigned int *)(argdata + 0) = argc;
	*(unsigned int *)(argdata + 4) = PROCESS_STACK_BASE - argdata_size + 8;

	/*
	 * Unmap the existing text segment 
	 */
	disable_paging();
	unsigned int addr;
	for (addr = proc->text_start; addr < proc->text_end; addr += PAGE_SIZE)
		unmap_and_free_page(proc->pdir, addr);
	for (addr = proc->data_start; addr < proc->data_end; addr += PAGE_SIZE)
		unmap_and_free_page(proc->pdir, addr);

	/*
	 * Resize text and data segments to 0 bytes each 
	 */
	proc->text_start = PROCESS_TEXT_BASE;
	proc->text_end = PROCESS_TEXT_BASE;
	proc->data_start = PROCESS_DATA_BASE;
	proc->data_end = PROCESS_DATA_BASE;

	/*
	 * Load in the text segment from the executable file 
	 */
	char *data = filesystem + entry->location;
	for (pos = 0; pos < entry->size; pos += PAGE_SIZE) {
		proc->text_end = proc->text_start + pos;
		void *page = alloc_page();
		if (PAGE_SIZE <= entry->size - pos)
			memmove(page, &data[pos], PAGE_SIZE);
		else
			memmove(page, &data[pos], entry->size - pos);
		map_page(proc->pdir, proc->text_end, (unsigned int)page,
			 PAGE_USER, PAGE_READ_WRITE);
	}
	proc->text_end = proc->text_start + pos;
	enable_paging(current_process->pdir);

	/*
	 * Copy the command line argument data we set up above to the process's
	 * stack 
	 */
	memmove((void *)(PROCESS_STACK_BASE - argdata_size), argdata,
		argdata_size);
	kfree(argdata);

	/*
	 * Set up the process's saved register state so that when it resumes
	 * execution, it will start from the beginning of the loaded code. 
	 */
	init_regs(r, PROCESS_STACK_BASE - argdata_size,
		  (void *)current_process->text_start);

	return 0;
}
Beispiel #17
0
/*******************************************************************************
 * Name:    pf_handler 
 *
 * Desc:    High level page fault handling code. The low level page fault
 *          interrupt handler is written in assembly. It'll setup the required
 *          registers (faulted address in CR2) and the stack frame with the 
 *          error code. This routine is responsible for the following:
 *          1. Read the faulted address and lookup BS to find if this address is
 *              mapped. If so, get the BS id and the offset within the BS. If 
 *              not, this is an illegal access - kill the process and move on.
 *          2. Actual paging starts here. Lookup the proctab to find the pid's
 *              pdir base. From the faulted address, we can get the pdir offset.
 *              Using these two, check if a page table exist for the faulted
 *              address. If not create one.
 *          3. If the page table is presnet, get the ptbl offset from the 
 *              faulted vaddr. This points to the location of the page table
 *              entry. Now, check if the frame assoicated with this page is
 *              already present in the memory (shared pages). If so, update the
 *              page table's 'pres' bit to reflect this and increment the 
 *              frame's refcount. If not, allocate a new frame and update the
 *              page table entry to reflect that the frame is present.
 *          4. Processor caches the paging entries (TLB) maintained by software
 *              and uses them whenever possible. When a pgt entry's 'pres' bit
 *              is cleared, we need to flush the entry from the processor 
 *              cache so that the proceessor would use the updated software
 *              data. This is described in detail in section 4.8 of Intel IA32 
 *              software developer manual (vol 3). There are many ways to force
 *              the processor to use the software tables, than hardware cache.
 *              One such way is to reload teh CR0 register. So, if any of the
 *              'pres' bits are modified, we reload the CR0 register.
 *
 * Params:  None.
 *
 * Returns: SYSCALL
 *  OK      - on success
 *  SYSERR  - on error
 ******************************************************************************/
SYSCALL
pf_handler(void)
{
    int bs_id = EMPTY;
    int bs_offset = EMPTY;
    int fr_id = EMPTY;
    uint32_t pdir_offset = 0;
    uint32_t ptbl_offset = 0;
    uint32_t page_offset = 0;
    uint32_t fault_addr = 0;
    pd_t *pdir = NULL;
    pt_t *ptbl = NULL;
    frm_map_t *frptr = NULL;
    frm_map_t *pt_frptr = NULL;
    virt_addr_t  *fault_vaddr = NULL;
    STATWORD ps; 

    disable(ps);
    DTRACE_START;

    DTRACE("DBG$ %d %s> inside high-level page fault handler\n",    \
            currpid, __func__);

    /* vaddr   : pdir_offset : ptbl_offset : page_offset
     * 32 bits : 10 bits     : 10 bits     : 12 bits
     */
    fault_addr = read_cr2();

    /* The virtual address is 32-bits. So, we directly read the required set of 
     * bits by assigining it to a strcutre with appropriate bit-fields.
     */
    fault_vaddr = (virt_addr_t *) (&fault_addr);
    pdir_offset = (uint32_t) fault_vaddr->pd_offset;
    ptbl_offset = (uint32_t) fault_vaddr->pt_offset;
    page_offset = (uint32_t) fault_vaddr->pg_offset;
    DTRACE("DBG$ %d %s> faulted vaddr 0x%08x, vpage %d\n",  \
            currpid, __func__, fault_addr, VADDR_TO_VPAGE(fault_addr));
    DTRACE("DBG$ %d %s> pd %d, pt %d, pg %d\n",  \
            currpid, __func__, pdir_offset, ptbl_offset, page_offset);


    /* Check the BS for a mapping for the faulted vaddr and the pid. If present,
     * record the BS id and the offset within the BS. If not present, it's
     * illeagal memory access. Kill the process and return.
     */
    if (SYSERR == bsm_lookup(currpid, fault_addr, &bs_id, &bs_offset, 
                                NULL, NULL)) {
        DTRACE("DBG$ %d %s> bsm_lookup() failed\n", currpid, __func__);
        DTRACE("DBG$ %d %s> pid %d will be killed\n",   \
                currpid, __func__, currpid);
        kprintf("\n\n");
        kprintf("FATAL ERROR: Process '%s' with pid '%d' is trying to access " \
                "virtual memory out of its range! \nThe process will be "      \
                "terminated.\n", P_GET_PNAME(currpid), currpid);
        kprintf("\n\n");
        sleep(9);
        DTRACE_END;
        restore(ps);
        kill(currpid);
        goto RESTORE_AND_RETURN_ERROR;
    }   

    /* Get the currpid's page directory and index to the appropriate pgt. If pgt
     * isn't present, create one.
     */
    pdir = P_GET_PDIR(currpid);
    if (FALSE == PD_GET_PRES(pdir, pdir_offset)) {
        DTRACE("DBG$ %d %s> pgt not present for pid %d, pd offset %d, "     \
                "pt offset %d, pg offset %d, vaddr 0x%08x\n", currpid,      \
                __func__, currpid, pdir_offset, ptbl_offset, page_offset,   \
                fault_addr);
        ptbl = new_pgt();
        if (NULL == ptbl) {
            DTRACE("DBG$ %d %s> new_pgt() failed\n", currpid, __func__);
            goto RESTORE_AND_RETURN_ERROR;
        }

        /* Fill-in few meta-data for the pgt frame just created. */
        pt_frptr = FR_GET_FPTR(FR_PA_TO_ID(ptbl));
        pt_frptr->fr_pid = currpid;

        /* Set the 'pres' and 'write' bits alone. Rest would've been zeroed
         * out by new_pgt(). Also, set the base of the new page table.
         */
        pdir[pdir_offset].pd_pres = 1;
        pdir[pdir_offset].pd_write = 1;
        pdir[pdir_offset].pd_base = VADDR_TO_VPAGE((unsigned) ptbl);
    } else {
        DTRACE("DBG$ %d %s> ptbl already present at 0x%08x, fr id %d\n",  \
            currpid, __func__, VPAGE_TO_VADDR(PD_GET_BASE(pdir, pdir_offset)),\
            FR_PA_TO_ID(VPAGE_TO_VADDR(PD_GET_BASE(pdir, pdir_offset))));
    }
    ptbl = (pt_t *) VPAGE_TO_VADDR(PD_GET_BASE(pdir, pdir_offset));
    DTRACE("DBG$ %d %s> ptbl present at 0x%08x, fr id %d\n",  \
            currpid, __func__, ptbl, FR_PA_TO_ID(ptbl));

    /* Find if a frame representing the same BS id and offset is present in the
     * memory (shared pages). If so, just update the page table entry and
     * increment teh refcount.
     */
    if (EMPTY == (fr_id = is_frm_present(bs_id, bs_offset))) {
        DTRACE("DBG$ %d %s> frame not present.. creating a new frame\n",    \
                currpid, __func__);

        frptr = get_frm(FR_PAGE);
        if (NULL == frptr) {
            DTRACE("DBG$ %d %s> get_frm() failed\n", currpid, __func__);
            goto RESTORE_AND_RETURN_ERROR;
        }
        fr_id = frptr->fr_id;
        frm_pidmap_oper(fr_id, getpid(), FR_OP_PMAP_SET);
        frm_record_details(fr_id, getpid(), VADDR_TO_VPAGE(fault_addr));

        /* Read the appropriate page from BS onto the new frame. */
        if (SYSERR == read_bs((char *) FR_ID_TO_PA(fr_id), bs_id, bs_offset)) {
            DTRACE("DBG$ %d %s> read_bs() failed for fr id %d, bs %d, "     \
                    "offset %d\n", currpid, __func__, fr_id, bs_id, bs_offset);
            goto RESTORE_AND_RETURN_ERROR;
        } else {
            DTRACE("DBG$ %d %s> reading for fr id %d, bs %d, offset %d\n",  \
                    currpid, __func__, fr_id, bs_id, bs_offset);
        }

        /* Fill-in the new BS details in the frame. */
        frptr->fr_type = FR_PAGE;
        frptr->fr_bs = bs_id;
        frptr->fr_bsoffset = bs_offset;
        inc_frm_refcount(fr_id);
#ifdef DBG_ON
        print_frm_id(fr_id);
#endif
    } else {
        /* A frame representing the same BS and offset is already present in the 
         * memory. So, just increment the refcount of the frame.
         */
        frm_pidmap_oper(fr_id, getpid(), FR_OP_PMAP_SET);
        frm_record_details(fr_id, getpid(), VADDR_TO_VPAGE(fault_addr));
        inc_frm_refcount(fr_id);
    }

    /* In both cases (frame present and frame not present), we need to update
     * the page table entry as at this point, the frame is loaded onto the
     * memory. Do the following w.r.t. the pgt frame:
     *      1. Set the 'pres' bit in the page table entry corresponding to the
     *          newly loaded page to reflect that the page is present in the
     *          memory. 
     *      2. Set the 'write' bit (as given in PA3 description). 
     *      3. Update the 'base' of the page entry corresponding to the newly 
     *          created page to point to the frame.
     *      4. Increment the refcount of the pgt frame. Unlike data frames, where
     *          refocunt denotes the # of processes that map to the actual
     *          physical frame, pgt frame's refcount reflects the # of pages
     *          (that are part of this pgt) that are present in the memory. 
     *          This will be decremented when a frame is paged out and the 
     *          pgt frame will be freed when the refcount reaches zero.
     */
    ptbl[ptbl_offset].pt_pres = 1;
    ptbl[ptbl_offset].pt_write = 1;
    ptbl[ptbl_offset].pt_base = FR_ID_TO_VPAGE(fr_id);
    inc_frm_refcount(FR_PA_TO_ID(ptbl));

    /* Reload the CR0 register would force the processor to flush the tables
     * that the processor maintains in hardware cache and to use the updated
     * software tables.
     */
    enable_paging();

    DTRACE("DBG$ %d %s> returning OK\n", currpid, __func__);
    DTRACE_END;
    restore(ps);
    return OK;

RESTORE_AND_RETURN_ERROR:
    DTRACE("DBG$ %d %s> returning SYSERR\n", currpid, __func__);
    DTRACE_END;
    restore(ps);
    return SYSERR;
}
Beispiel #18
0
/*******************************************************************************
 * Name:    pgt_update_for_pid
 *
 * Desc:    Called when a frame is freed. This routine:
 *          1. Goes over all the pgts of the given process and clears the 
 *              'pres' bit of the page table entry as the frame is about to 
 *              be freed, eventually.
 *          2. As it goes over the page tables of the process, it records
 *              the dirty bit value of the page table. This will be 
 *              returned to the caller so that caller can write-off the frame
 *              to the BS. 
 *          3. If all the frames of the page table frame are freed, the page
 *              table frame itself can be freed. In this case, we need to 
 *              update the 'pres' bit of the corrsponding entry in the page 
 *              directory (outer page table) of the process.
 *          4. Processor caches the paging entries (TLB) maintained by software
 *              and uses them whenever possible. When a pgt entry's 'pres' bit
 *              is cleared, we need to flush the entry from the processor 
 *              cache so that the proceessor would use the updated software
 *              data. This is described in detail in section 4.8 of Intel IA32 
 *              software developer manual (vol 3). There are many ways to force
 *              the processor to use the software tables, than hardware cache.
 *              One such way is to reload teh CR0 register. So, if any of the
 *              'pres' bits are modified, we reload the CR0 register.
 *
 * Params:  
 *  fr_id   - frame id of the frame being paged out/removed
 *  pid     - pid of the proc whose page table is to be updated (optional)
 *              passing EMPTY would update all pid page tables
 *
 * Returns: int
 *  TRUE    - if the dirty bit is set for at least one proc
 *  FALSE   - if the dirty bit is not set for any of the procs
 *  EMPTY   - oops! something went wrong..
 ******************************************************************************/
int
pgt_update_for_pid(int fr_id, int pid)
{
    int rc = FALSE;
    frm_map_t *frptr = NULL;
    STATWORD ps;

    disable(ps);
    DTRACE_START;

    if (FALSE == FR_IS_ID_VALID(fr_id)) {
        DTRACE("DBG$ %d %s> bad fr id %d\n", currpid, __func__, fr_id);
        rc = EMPTY;
        goto RESTORE_AND_RETURN;
    }

    /* If the given frame is free, the required pgt's would have been updated
     * earlier. Just return.
     */
    if (FR_FREE == FR_GET_STATUS(fr_id)) {
        DTRACE("DBG$ %d %s> fr id %d is free\n",    \
                currpid, __func__, fr_id, FR_GET_STATUS(fr_id));
        rc = FALSE;
        goto RESTORE_AND_RETURN;
    }

    /* This routine is only to update the page tables when a frame is removed
     * or a proc unmaps the frame. So, we only have to bother about data pages.
     */
    if (FR_PAGE != FR_GET_TYPE(fr_id)) {
        DTRACE("DBG$ %d %s> fr id %d isn't a data frame.. type %d\n",   \
                currpid, __func__, fr_id, FR_GET_TYPE(fr_id));
        rc = FALSE;
        goto RESTORE_AND_RETURN;
    }

    if (isbadpid(pid)) {
        DTRACE("DBG$ %d %s> bad pid %d\n", currpid, __func__, pid);
        rc = EMPTY;
        goto RESTORE_AND_RETURN;
    }

    if (PRFREE == P_GET_PSTATE(pid)) {
        DTRACE("DBG$ %d %s> pid %d is in free state\n", \
                currpid, __func__, pid);
        rc = EMPTY;
        goto RESTORE_AND_RETURN;
    }

    /* If the pid doesn't use the given frame, return FALSE. */
    if (FALSE == frm_pidmap_oper(fr_id, pid, FR_OP_PMAP_CHK)) {
        DTRACE("DBG$ %d %s> fr id %d is not used by pid %d\n",
                currpid, __func__, fr_id, pid);
        rc = FALSE;
        goto RESTORE_AND_RETURN;
    }

    /* If we are here, we are good to go. Update the page table by doing the
     * following:
     *  1. Record the dirty bit value.
     *  2. Clear the 'pres' bit for the page in the page table.
     *  3. Decrement the refcount of the page table.
     *  4. If the refcount of the frame containing the page table reaches 0,
     *      free the frame.
     *  5. If the frame containing the page table is freed, clear the 'pres'
     *      bit of the page directory entry of the process containing the just
     *      freed frame.
     */
    frptr = FR_GET_FPTR(fr_id);
    rc = pgt_oper(fr_id, pid, frptr->fr_vpage[pid], PT_OP_FREE_FRM);

RESTORE_AND_RETURN:
    /* Reload the CR0 register would force the processor to flush the tables
     * that the processor maintains in hardware cache and to use the updated
     * software tables.
     */
    enable_paging();
    DTRACE_END;
    restore(ps);
    return rc;
}
Beispiel #19
0
/*
 * syscall_fork
 * 
 * Implements the fork system call, which makes a copy of an existing process.
 * After this call has completed, the two processes will have exactly the same
 * state, with the exception of their process ids and the return value from the
 * fork call. The return value that the parent process sees will be the (non-zero)
 * process id of the child. The child will see a return value of 0. Based on this,
 * each of the two processes can go their separate ways, with the child process
 * typically taking completely different code
 * path, such as a call to exec.
 * 
 * This call is an alternative to start_process. fork is the standard way to create
 * processes under UNIX, and in most cases is the *only* way for new processes to
 * be started, at least from user-space.
 * 
 * The *full* state of a process must be copied here, including all fields of the
 * process object, and all of the memory associated with the process in its various
 * segments (text, data, and stack).
 */
pid_t syscall_fork(regs * r)
{
	/*
	 * Find a free process identifier 
	 */
	pid_t child_pid = get_free_pid();
	if (0 > child_pid)
		return -EAGAIN;

	process *parent = current_process;
	process *child = &processes[child_pid];
	memset(child, 0, sizeof(process));
	child->pid = child_pid;
	child->parent_pid = parent->pid;
	child->exists = 1;

	/*
	 * Create a page directory for the new process, and set the segment ranges.
	 * Note that we have to temporarily disable paging here, because we need to
	 * deal with physical memory when allocating a page directory and setting up
	 * the mappings. 
	 */
	disable_paging();
	child->pdir = (page_dir) alloc_page();

	child->text_start = parent->text_start;
	child->text_end = parent->text_end;
	child->data_start = parent->data_start;
	child->data_end = parent->data_end;
	child->stack_start = parent->stack_start;
	child->stack_end = parent->stack_end;

	/*
	 * Identity map memory 0-6Mb 
	 */
	unsigned int addr;
	for (addr = 0 * MB; addr < 6 * MB; addr += PAGE_SIZE)
		map_page(child->pdir, addr, addr, PAGE_USER, PAGE_READ_ONLY);

	/*
	 * Copy parent's text, data, and stack segments to child 
	 */
	map_and_copy(parent->pdir, child->pdir, child->text_start,
		     child->text_end);
	map_and_copy(parent->pdir, child->pdir, child->data_start,
		     child->data_end);
	map_and_copy(parent->pdir, child->pdir, child->stack_start,
		     child->stack_end);

	enable_paging(current_process->pdir);

	/*
	 * Copy file handles. The reference count is increased on each of them, so
	 * that we can keep track of how many file descriptors refere to each file
	 * handle. This information is needed so we know when to destroy a file handle
	 * (i.e. when its reference count reaches 0). 
	 */
	int i;
	for (i = 0; i < MAX_FDS; i++) {
		if (NULL != parent->filedesc[i]) {
			child->filedesc[i] = parent->filedesc[i];
			child->filedesc[i]->refcount++;
		}
	}
	/*
	 * Copy the saved CPU registers of the current process, which determines its
	 * execution state (instruction pointer, stack pointer etc.) 
	 */
	child->saved_regs = *r;
	child->saved_regs.eax = 0;	/* child's return value from fork */

	memmove(child->cwd, parent->cwd, PATH_MAX);

	/*
	 * Place the process on the ready list, so that it can begin execution on a
	 * subsequent context switch 
	 */
	child->ready = 1;
	list_add(&ready, child);

	/*
	 * Return the child's process id... note that this value will only go to the
	 * parent, since we set the child's return value from fork above 
	 */
	return child_pid;
}
Beispiel #20
0
/**
 * Initializes the page structures,
 * move to the page structure # 0 (kernel).
 * and turn on the paging.
 */
void paging_init(unsigned int mbi_addr)
{
	pdir_init_kern(mbi_addr);
	set_pdir_base(0);
	enable_paging();
}
Beispiel #21
0
void init_paging (u32_t upper_mem_kb, u32_t img_phys_end_addr)
{
    u32_t tmp1 = 0xA000;
    u32_t tmp2 = PAGE_OFFSET;

    u32_t phys_end_of_kernel = kernel_phys_end_addr ( upper_mem_kb, img_phys_end_addr);


    /* Setup the page directory entry for the region 0-4 MB  */
    insert_pg_dir_entry ( 0,
                          (u32_t *) phys_addr ( (u32_t) kernel_pg_dir),
                          phys_addr ( (u32_t) pg_table2),
                          PRESENT | RW | ACCESSED);

    /* Identity map the video memory */
    while ( tmp1 <= 0xFF000) {
        insert_pg_table_entry ( tmp1,
                                (u32_t *) phys_addr ( (u32_t) pg_table2),
                                tmp1,
                                PRESENT | RW | CACHE_DISABLE | ACCESSED);

        tmp1 += PAGE_SIZE_BYTES;
    }

    tmp1 = (u32_t) __kernel_load_addr;

    /* Identity map the kernel */
    while ( tmp1 < phys_end_of_kernel) {
        insert_pg_table_entry ( tmp1,
                                (u32_t *) phys_addr ( (u32_t) pg_table2),
                                tmp1,
                                PRESENT | RW | GLOBAL | ACCESSED);

        tmp1 += PAGE_SIZE_BYTES;
    }


    /* Set the page directory entry for the 4 MB starting at
     * virtual address 0xC0000000 */
    insert_pg_dir_entry (PAGE_OFFSET,
                         (u32_t *) phys_addr ( (u32_t) kernel_pg_dir),
                         phys_addr ( (u32_t) pg_table1),
                         PRESENT | RW | GLOBAL | ACCESSED);


    tmp1 = (u32_t) __kernel_load_addr;
    tmp2 = PAGE_OFFSET;
    /* Map the virtual kernel address space onto the physical
     * pages */
    while ( tmp1 < phys_end_of_kernel) {
        insert_pg_table_entry ( tmp2,
                                (u32_t *) phys_addr ( (u32_t) pg_table1),
                                tmp1,
                                PRESENT | RW | GLOBAL | ACCESSED);

        tmp1 += PAGE_SIZE_BYTES;
        tmp2 += PAGE_SIZE_BYTES;
    }


    /* Map the page directory onto itself in the upper 4 MB of the
     * virual address space. This is needed for mapping physical
     * pages into the virtual address space */
    kernel_pg_dir [1023] = (u32_t) kernel_pg_dir | PRESENT | RW | ACCESSED;

    /* Let the CPU know where the page directory is */
    set_pg_dir ( phys_addr ( (u32_t) kernel_pg_dir));

    /* Lets get the show on the road :) */
    enable_paging();

}
Beispiel #22
0
/*------------------------------------------------------------------------
 *  nulluser  -- initialize system and become the null process (id==0)
 *------------------------------------------------------------------------
 */
nulluser()				/* babysit CPU when no one is home */
{
        int userpid;
	unsigned long temp;

	console_dev = SERIAL0;		/* set console to COM0 */

	initevec();

	kprintf("system running up!\n");
	sysinit();

	enable();		/* enable interrupts */

	sprintf(vers, "PC Xinu %s", VERSION);
	kprintf("\n\n%s\n", vers);
	if (reboot++ < 1)
		kprintf("\n");
	else
		kprintf("   (reboot %d)\n", reboot);


	kprintf("%d bytes real mem\n",
		(unsigned long) maxaddr+1);
#ifdef DETAIL	
	kprintf("    %d", (unsigned long) 0);
	kprintf(" to %d\n", (unsigned long) (maxaddr) );
#endif	

	kprintf("%d bytes Xinu code\n",
		(unsigned long) ((unsigned long) &end - (unsigned long) start));
#ifdef DETAIL	
	kprintf("    %d", (unsigned long) start);
	kprintf(" to %d\n", (unsigned long) &end );
#endif

#ifdef DETAIL	
	kprintf("%d bytes user stack/heap space\n",
		(unsigned long) ((unsigned long) maxaddr - (unsigned long) &end));
	kprintf("    %d", (unsigned long) &end);
	kprintf(" to %d\n", (unsigned long) maxaddr);
#endif	
	
	kprintf("clock %sabled\n", clkruns == 1?"en":"dis");
/*
initialize_pagedirectory();
initialize_pagetable();
get_frame(1,FR_DIR,0);
get_frame(1,FR_TBL,0);
get_frame(1,FR_TBL,0);
get_frame(1,FR_TBL,0);
get_frame(1,FR_TBL,0);
*/

	init_frm();
	init_bsm();

	temp = create_ps() ;
	write_cr3(0x400000);
	set_evec(14,pfintr);
    
	proctab[currpid].pdbr = temp;
//	pageq.next= &pageq;	//Always points to head
	myheadq = NULL;		//actual pointer used by page replacement policyi
	currq = NULL;
	pcurrq = NULL;
    

    /* create a process to execute the user's main program */
	userpid = create(main,INITSTK,INITPRIO,INITNAME,INITARGS);
	enable_paging();
	resume(userpid);

	while (TRUE)
		/* empty */;
}
Beispiel #23
0
/*------------------------------------------------------------------------
 *  nulluser  -- initialize system and become the null process (id==0)
 *------------------------------------------------------------------------
 */
nulluser()				/* babysit CPU when no one is home */
{
        int userpid;
        //OS proj 3 modify
    int i;
    unsigned long nullproc_PDBR, main_PDBR;
    //int free_fr1,free_fr2,free_fr3,free_fr4;

	console_dev = SERIAL0;		/* set console to COM0 */

	initevec();

	kprintf("system running up!\n");
	sysinit();

	enable();		/* enable interrupts */

	sprintf(vers, "PC Xinu %s", VERSION);
	kprintf("\n\n%s\n", vers);
	if (reboot++ < 1)
		kprintf("\n");
	else
		kprintf("   (reboot %d)\n", reboot);


	kprintf("%d bytes real mem\n",
		(unsigned long) maxaddr+1);
#ifdef DETAIL	
	kprintf("    %d", (unsigned long) 0);
	kprintf(" to %d\n", (unsigned long) (maxaddr) );
#endif	

	kprintf("%d bytes Xinu code\n",
		(unsigned long) ((unsigned long) &end - (unsigned long) start));
#ifdef DETAIL	
	kprintf("    %d", (unsigned long) start);
	kprintf(" to %d\n", (unsigned long) &end );
#endif

#ifdef DETAIL	
	kprintf("%d bytes user stack/heap space\n",
		(unsigned long) ((unsigned long) maxaddr - (unsigned long) &end));
	kprintf("    %d", (unsigned long) &end);
	kprintf(" to %d\n", (unsigned long) maxaddr);
#endif	

	//OS proj 3 modify
	/*Create new page table for null process:
- create page directory (outer page table)
- initialize 1:1 mapping for the first 4096 pages
- allocate 4 page tables (4x1024 pages)
- assign each page table entry to the address starting
from page number 0 to 1023
- this page tables should be shared between processes*/
	nullproc_PDBR = init_pagedir(currpid); //func in frame.c
	write_cr3(nullproc_PDBR);
	proctab[currpid].pdbr = nullproc_PDBR;
	//create global frames to map 4096 
	/*All memory below page 4096 will be "global". That is, it is usable and visible by all processes and
accessible by simply using its actual physical addresses. As a result, the first four page tables for every
process will be the same, and thus should be shared.*/
	for(i = 0; i < 4; ++i)
	{
		global_pagetable_fr[i] = get_frm();
		global_pagetable_addr[i] = 0x00400000 + (unsigned long) global_pagetable_fr[i] * NBPG;
		map_frame_to_proc_virtpage(global_pagetable_fr[i], currpid, global_pagetable_addr[i] >> 12, FR_TBL);
		/*
		frm_tab[global_pagetable_fr[i]].fr_status = FRM_MAPPED;
		frm_tab[global_pagetable_fr[i]].fr_type = FR_TBL;
		frm_tab[global_pagetable_fr[i]].fr_dirty = 1;
		frm_tab[global_pagetable_fr[i]].fr_loadtime = ctr1000;
		*/
	}

	share_global_tables(nullproc_PDBR); //implement get_frm()
	enable_paging();
	
	kprintf("clock %sabled\n", clkruns == 1?"en":"dis");


	/* create a process to execute the user's main program */
	userpid = create(main,INITSTK,INITPRIO,INITNAME,INITARGS);
	//OS proj 3 modify
	main_PDBR = init_pagedir(userpid);
	proctab[userpid].pdbr = main_PDBR;
	share_global_tables(main_PDBR);

	resume(userpid);

	while (TRUE)
		/* empty */;
}
Beispiel #24
0
int free_frame(frame_t * frame)
{
	intmask mask;
	mask = disable();
	//LOG("Freeing");
	//print_frame(frame);
	if(frame->id <5)
	{
		LOG(" WHAT THE F**K %d %d", frame->id, frame->type);
		restore(mask);
		return OK;
	}
	//kprintf("id %d type %d ", frame->id, frame->type);
	//print_fifo_list();
	//kprintf("\n");
	if(frame == NULL)
	{
		restore(mask);
		return SYSERR;
	}
	else if(!FRAMEID_IS_VALID(frame->id))
	{
		restore(mask);
		return SYSERR;
	}
	else if(frame->type == FREE)
	{
		restore(mask);
		return OK;
	}
	else if(frame->type == PAGE){

		//print_fifo_list();
		//LOG("Got here 0.5");
		//3. Using the inverted page table, get vp, the virtual page number of the page to be replaced.
		uint32 vp = frame->vp_no;
		//4. Let a be vp*4096 (the first virtual address on page vp).

		hook_pswap_out(vp, frame->id + FRAME0);
		uint32 a = vp*PAGE_SIZE;

		virtual_addr * virt = (virtual_addr *) &a;

		//5. Let p be the high 10 bits of a. Let q be bits [21:12] of a.
		uint32 p = virt->page_directory_offset;
		uint32 q = virt->page_table_offset;

		//6. Let pid be the process id of the process owning vp.
		pid32 pid = frame->pid;


		//7. Let pd point to the page directory of process pid.
		struct	procent	*prptr;		/* Ptr to process table entry	*/
		prptr = &proctab[pid];
		pd_t * pd = prptr->pagedir;

		if( pd == NULL)
		{
			LOG(" pd doesn't exist ");
			restore(mask);
			return SYSERR;
		}
		bool8 pt_pres = FALSE;
		pt_pres = (bool8) pd[p].pd_pres;

		bool8 pg_pres = FALSE;
		bool8 dirty = FALSE;
		if(pt_pres)
		{	//8. Let pt point to the pid's p_th page table.
			pt_t * pt = (pt_t *) ((pd[p].pd_base) * PAGE_SIZE);
			pg_pres = (bool8) pt[q].pt_pres;
			uint32 pg_base = (uint32) pt[q].pt_base;
			if(pg_pres){
				if((uint32)FRAMEID_TO_VPAGE(frame->id) == pg_base)
				{
					pg_pres = TRUE;
					dirty  = pt[q].pt_dirty;
				}
				else
				{
					pg_pres = FALSE;
				}
			}




		}
		if(pg_pres)
		{
			frame_t * pt_frame = &frames[(pd[p].pd_base) - FRAME0];
			pt_t * pt = (pt_t *) ((pd[p].pd_base) * PAGE_SIZE);
			//9. Mark the appropriate entry of pt as not present.
			pt[q].pt_pres = 0;
			if(pt_frame->type == VPTBL){
				decr_frame_refcount(pt_frame);
				if(pt_frame->refcount == 0){
					pd[p].pd_pres = 0;
					free_frame(pt_frame);

				}


				bzero((char *)&pt[q], sizeof(pt_t));
			}
			else if(pt_frame->type == GPTBL)
			{
			//	kprintf(" Uh  OH");
			}
			// If the reference count has reached zero, you should mark the appropriate entry in pd as "not present."
			// This conserves frames by keeping only page tables which are necessary.
			//LOG("Got here 1.5");

			//If the dirty bit for page vp was set in its page table, you must do the following:
			//a)	Using the backing store map, find the store and page offset within the store, given pid and a.
			//		If the lookup fails, something is wrong. Print an error message and kill the process with id pid.
			//b)	Write the page back to the backing store.

			//LOG("Got here 2");

			if(dirty){
				bsd_t bs_store_id;
				int bs_store_page_offset;
				if(SYSERR == bs_map_check(pid, vp, &bs_store_id, &bs_store_page_offset))
				{
						kprintf("FATAL :Can't find the bs_map");
						restore(mask);
						kill(currpid);
						return SYSERR;
				}
				//print_frame(frame);
				if(BACKSTORE_ID_IS_VALID(frame->backstore) && BACKSTORE_OFFSET_IS_VALID(frame->backstore_offset) && frame->backstore == bs_store_id && frame->backstore_offset == bs_store_page_offset)
				{
					//LOG("Frame %d was dirty", frame->id);
					open_bs(frame->backstore);
					write_bs(FRAMEID_TO_PHYSICALADDR(frame->id), frame->backstore, frame->backstore_offset);
					close_bs(frame->backstore);
				}
				//else
				//{
				//	print_frame(frame);
				//	kprintf("Fatal error: Cannot locate backstore for vpage %d to swap out page for pid %d ", vp, pid);
				//	kill(pid);
				//	initialize_frame(frame);
				//	restore(mask);
				//	return SYSERR;
				//}
			}

			else{
				//print_frame(frame);
			}
		}



		//LOG("Got here 1");
		//10. If the page being removed belongs to the current process,
		// invalidate the TLB entry for the page vp, using the invlpg instruction (see Intel Manual, volumes II and III for more details on this instruction).
		// 11. In the inverted page table, decrement the reference count of the frame occupied by pt.


		//LOG(" Free frame");
		//print_frame(frame);
		enable_paging();
		initialize_frame(frame);
		// Update page table entries associated with this frame
		// set the frame to be free
	}
	else if(frame->type == VPTBL)
	{
		evict_from_fifo_list(frame);
		hook_ptable_delete(frame->id + FRAME0);
		enable_paging();
		initialize_frame(frame);
	}
	else if(frame->type == DIR)
	{
		struct procent * prptrNULL = &proctab[NULLPROC];
		pd_t * null_pg_dir = prptrNULL->pagedir;
		struct	procent	*prptr;		/* Ptr to process table entry	*/
		prptr = &proctab[currpid];
		if(prptr->pagedir!= null_pg_dir)
		{
			evict_from_fifo_list(frame);
			prptr->pagedir = prptrNULL->pagedir;
			switch_page_directory(prptr->pagedir);
			enable_paging();
			initialize_frame(frame);

		}
	}
	restore(mask);
	return OK;

}
Beispiel #25
0
Datei: mmu.c Projekt: Kloniks/muk
int mmu_initialize(void)
{
  enable_paging();
  return -1;
}