OpenCores
URL https://opencores.org/ocsvn/c0or1k/c0or1k/trunk

Subversion Repositories c0or1k

[/] [c0or1k/] [trunk/] [conts/] [posix/] [mm0/] [mm/] [init.c] - Rev 7

Go to most recent revision | Compare with Previous | Blame | View Log

/*
 * Initialise the system.
 *
 * Copyright (C) 2007 - 2009 Bahadir Balban
 */
#include L4LIB_INC_ARCH(syscalls.h)
#include L4LIB_INC_ARCH(syslib.h)
#include __INC_ARCH(debug.h)
#include <l4lib/utcb.h>
#include <l4lib/exregs.h>
#include <l4/lib/list.h>
#include <l4/generic/cap-types.h>	/* TODO: Move this to API */
#include <l4/api/capability.h>
 
#include <stdio.h>
#include <string.h>
#include <mm/alloc_page.h>
#include <malloc/malloc.h>
#include <lib/bit.h>
 
#include <task.h>
#include <shm.h>
#include <file.h>
#include <init.h>
#include <test.h>
#include <utcb.h>
#include <bootm.h>
#include <vfs.h>
#include <init.h>
#include <memory.h>
#include <capability.h>
#include <linker.h>
#include <mmap.h>
#include <file.h>
#include <syscalls.h>
#include <linker.h>
 
/* Kernel data acquired during initialisation */
__initdata struct initdata initdata;
 
 
/* Physical memory descriptors */
struct memdesc physmem;		/* Initial, primitive memory descriptor */
struct membank membank[1];	/* The memory bank */
struct page *page_array;	/* The physical page array based on mem bank */
 
/* Memory region capabilities */
struct container_memory_regions cont_mem_regions;
 
void print_pfn_range(int pfn, int size)
{
	unsigned int addr = pfn << PAGE_BITS;
	unsigned int end = (pfn + size) << PAGE_BITS;
	printf("Used: 0x%x - 0x%x\n", addr, end);
}
 
/*
 * This sets up the mm0 task struct and memory environment but omits
 * bits that are already done such as creating a new thread, setting
 * registers.
 */
int pager_setup_task(void)
{
	struct tcb *task;
	struct task_ids ids;
	struct exregs_data exregs;
	void *mapped;
	int err;
 
	/*
	 * The thread itself is already known by the kernel,
	 * so we just allocate a local task structure.
	 */
	if (IS_ERR(task = tcb_alloc_init(TCB_NO_SHARING))) {
		printf("FATAL: "
		       "Could not allocate tcb for pager.\n");
		BUG();
	}
 
	/* Set up own ids */
	l4_getid(&ids);
	task->tid = ids.tid;
	task->spid = ids.spid;
	task->tgid = ids.tgid;
 
	/* Initialise vfs specific fields. */
	task->fs_data->rootdir = vfs_root.pivot;
	task->fs_data->curdir = vfs_root.pivot;
 
	/* Text markers */
	task->text_start = (unsigned long)__start_text;
	task->text_end = (unsigned long)__end_rodata;
 
	/* Data markers */
	task->stack_end = (unsigned long)__stack;
	task->stack_start = (unsigned long)__start_stack;
 
	/* Stack markers */
	task->data_start = (unsigned long)__start_data;
	task->data_end = (unsigned long)__end_data;
 
	/* BSS markers */
	task->bss_start = (unsigned long)__start_bss;
	task->bss_end = (unsigned long)__end_bss;
 
	/* Task's region available for mmap as  */
	task->map_start = PAGER_MMAP_START;
	task->map_end = PAGER_MMAP_END;
 
	/* Task's total map boundaries */
	task->start = __pfn_to_addr(cont_mem_regions.pager->start);
	task->end = __pfn_to_addr(cont_mem_regions.pager->end);
 
	/*
	 * Map all regions as anonymous (since no real
	 * file could back) All already-mapped areas
	 * are mapped at once.
	 */
	if (IS_ERR(mapped =
		   do_mmap(0, 0, task, task->start,
			   VMA_ANONYMOUS | VM_READ | VMA_FIXED |
			   VM_WRITE | VM_EXEC | VMA_PRIVATE,
			   __pfn(page_align_up(task->map_start) -
				 task->start)))) {
		printf("FATAL: do_mmap: failed with %d.\n", (int)mapped);
		BUG();
	}
 
 
	/* Set pager as child and parent of itself */
	list_insert(&task->child_ref, &task->children);
	task->parent = task;
 
	/* Allocate and set own utcb */
	task_setup_utcb(task);
	memset(&exregs, 0, sizeof(exregs));
	exregs_set_utcb(&exregs, task->utcb_address);
	if ((err = l4_exchange_registers(&exregs, task->tid)) < 0) {
		printf("FATAL: Pager could not set own utcb. "
		       "UTCB address: 0x%lx, error: %d\n",
		       task->utcb_address, err);
		BUG();
	}
 
	/* Pager must prefault its utcb */
	task_prefault_page(task, task->utcb_address, VM_READ | VM_WRITE);
 
	/* Add the task to the global task list */
	global_add_task(task);
 
	return 0;
}
 
/*
 * Copy all necessary data from initmem to real memory,
 * release initdata and any init memory used
 */
void release_initdata()
{
	/* Free and unmap init memory:
	 *
	 * FIXME: We can and do safely unmap the boot
	 * memory here, but because we don't utilize it yet,
	 * it remains as if it is a used block
	 */
 
	l4_unmap(__start_init,
		 __pfn(page_align_up(__end_init - __start_init)),
		 self_tid());
}
 
static void init_page_map(struct page_bitmap *pmap,
			  unsigned long pfn_start,
			  unsigned long pfn_end)
{
	pmap->pfn_start = pfn_start;
	pmap->pfn_end = pfn_end;
	set_page_map(pmap, pfn_start,
		     pfn_end - pfn_start, 0);
}
 
/*
 * Marks pages in the global page_map as used or unused.
 *
 * @start = start page address to set, inclusive.
 * @numpages = number of pages to set.
 */
int set_page_map(struct page_bitmap *page_map,
		 unsigned long pfn_start,
		 int numpages, int val)
{
	unsigned long pfn_end = pfn_start + numpages;
	unsigned long pfn_err = 0;
 
	if (page_map->pfn_start > pfn_start ||
	    page_map->pfn_end < pfn_start) {
		pfn_err = pfn_start;
		goto error;
	}
	if (page_map->pfn_end < pfn_end ||
	    page_map->pfn_start > pfn_end) {
		pfn_err = pfn_end;
		goto error;
	}
 
	/* Adjust bases so words get set from index 0 */
	pfn_start -= page_map->pfn_start;
	pfn_end -= page_map->pfn_start;
 
	if (val)
		for (int i = pfn_start; i < pfn_end; i++)
			page_map->map[BITWISE_GETWORD(i)] |= BITWISE_GETBIT(i);
	else
		for (int i = pfn_start; i < pfn_end; i++)
			page_map->map[BITWISE_GETWORD(i)] &= ~BITWISE_GETBIT(i);
 
	return 0;
 
error:
	BUG_MSG("Given page area is out of system page_map range: 0x%lx\n",
		pfn_err << PAGE_BITS);
	return -1;
}
 
/*
 * Allocates page descriptors and
 * initialises them using page_map information
 */
void init_physmem_secondary(struct membank *membank)
{
	struct page_bitmap *pmap = initdata.page_map;
	int npages = pmap->pfn_end - pmap->pfn_start;
	void *virtual_start;
	int err;
 
	/*
	 * Allocation marks for the struct
	 * page array; npages, start, end
	 */
	int pg_npages, pg_spfn, pg_epfn;
	unsigned long ffree_addr;
 
	membank[0].start = __pfn_to_addr(pmap->pfn_start);
	membank[0].end = __pfn_to_addr(pmap->pfn_end);
 
	/* First find the first free page after last used page */
	for (int i = 0; i < npages; i++)
		if ((pmap->map[BITWISE_GETWORD(i)] & BITWISE_GETBIT(i)))
			membank[0].free = membank[0].start + (i + 1) * PAGE_SIZE;
	BUG_ON(membank[0].free >= membank[0].end);
 
	/*
	 * One struct page for every physical page.
	 * Calculate how many pages needed for page
	 * structs, start and end pfn marks.
	 */
	pg_npages = __pfn(page_align_up((sizeof(struct page) * npages)));
 
	pg_spfn = __pfn(membank[0].free);
	pg_epfn = pg_spfn + pg_npages;
 
	/*
	 * Use free pages from the bank as
	 * the space for struct page array
	 */
	if (IS_ERR(membank[0].page_array =
		   l4_map_helper((void *)membank[0].free,
				 pg_npages))) {
		printf("FATAL: Page array mapping failed. err=%d\n",
		       (int)membank[0].page_array);
		BUG();
	}
 
	/* Update free memory left */
	membank[0].free += pg_npages * PAGE_SIZE;
 
	/* Update page bitmap for the pages used for the page array */
	set_page_map(pmap, pg_spfn, pg_epfn - pg_spfn, 1);
 
	/* Initialise the page array */
	for (int i = 0; i < npages; i++) {
		link_init(&membank[0].page_array[i].list);
 
		/*
		 * Set use counts for pages the
		 * kernel has already used up
		 */
		if (!(pmap->map[BITWISE_GETWORD(i)]
		      & BITWISE_GETBIT(i)))
			membank[0].page_array[i].refcnt = -1;
		else	/* Last page used +1 is free */
			ffree_addr = membank[0].start + (i + 1) * PAGE_SIZE;
	}
 
	/*
	 * First free address must
	 * come up the same for both
	 */
	BUG_ON(ffree_addr != membank[0].free);
 
	/* Set global page array to this bank's array */
	page_array = membank[0].page_array;
 
	/* Test that page/phys macros work */
	BUG_ON(phys_to_page(page_to_phys(&page_array[5]))
			    != &page_array[5]);
 
	/* Now map all physical pages to virtual correspondents */
	virtual_start = (void *)PAGER_VIRTUAL_START;
	if ((err = l4_map((void *)membank[0].start,
			  virtual_start,
			  __pfn(membank[0].end - membank[0].start),
			  MAP_USR_RW, self_tid())) < 0) {
		printk("FATAL: Could not map all physical pages to "
		       "virtual. err=%d\n", err);
		BUG();
	}
 
#if 0
	printf("Virtual offset: %p\n", virtual_start);
	printf("Physical page offset: 0x%lx\n", membank[0].start);
	printf("page address: 0x%lx\n", (unsigned long)&page_array[5]);
	printf("page_to_virt: %p\n", page_to_virt(&page_array[5]));
	printf("virt_to_phys, virtual_start: %p\n", virt_to_phys(virtual_start));
	printf("page_to_virt_to_phys: %p\n", virt_to_phys(page_to_virt(&page_array[5])));
	printf("page_to_phys: 0x%lx\n", page_to_phys(&page_array[5]));
#endif
 
	/* Now test that virt/phys macros work */
	BUG_ON(virt_to_phys(page_to_virt(&page_array[5]))
	       != (void *)page_to_phys(&page_array[5]));
	BUG_ON(virt_to_page(page_to_virt(&page_array[5]))
	       != &page_array[5]);
}
 
 
/* Fills in the physmem structure with free physical memory information */
void init_physmem_primary()
{
	unsigned long pfn_start, pfn_end, pfn_images_end = 0;
	struct bootdesc *bootdesc = initdata.bootdesc;
 
	/* Allocate page map structure */
	initdata.page_map =
		alloc_bootmem(sizeof(struct page_bitmap) +
			      ((cont_mem_regions.physmem->end -
			        cont_mem_regions.physmem->start)
			       >> 5) + 1, 0);
 
	/* Initialise page map from physmem capability */
	init_page_map(initdata.page_map,
		      cont_mem_regions.physmem->start,
		      cont_mem_regions.physmem->end);
 
	/* Mark pager and other boot task areas as used */
	for (int i = 0; i < bootdesc->total_images; i++) {
		pfn_start =
			__pfn(page_align_up(bootdesc->images[i].phys_start));
		pfn_end =
			__pfn(page_align_up(bootdesc->images[i].phys_end));
 
		if (pfn_end > pfn_images_end)
			pfn_images_end = pfn_end;
		set_page_map(initdata.page_map, pfn_start,
			     pfn_end - pfn_start, 1);
	}
 
	physmem.start = cont_mem_regions.physmem->start;
	physmem.end = cont_mem_regions.physmem->end;
 
	physmem.free_cur = pfn_images_end;
	physmem.free_end = physmem.end;
	physmem.numpages = physmem.end - physmem.start;
}
 
 
void init_physmem(void)
{
	init_physmem_primary();
 
	init_physmem_secondary(membank);
 
	init_page_allocator(membank[0].free, membank[0].end);
}
 
/*
 * To be removed later: This file copies in-memory elf image to the
 * initialized and formatted in-memory memfs filesystem.
 */
void copy_init_process(void)
{
	int fd;
	struct svc_image *init_img;
	unsigned long img_size;
	void *init_img_start, *init_img_end;
	struct tcb *self = find_task(self_tid());
	void *mapped;
	int err;
 
	/* Measure performance, if enabled */
	perfmon_reset_start_cyccnt();
 
	if ((fd = sys_open(self, "/test0", O_TRUNC |
			   O_RDWR | O_CREAT, 0)) < 0) {
		printf("FATAL: Could not open file "
		       "to write initial task.\n");
		BUG();
	}
 
	debug_record_cycles("sys_open");
 
	init_img = bootdesc_get_image_byname("test0");
	img_size = page_align_up(init_img->phys_end) -
				 page_align(init_img->phys_start);
 
	init_img_start = l4_map_helper((void *)init_img->phys_start,
				       __pfn(img_size));
	init_img_end = init_img_start + img_size;
 
	/*
	 * Map an anonymous region and prefault it.
	 * Its got to be from __end, because we haven't
	 * unmapped .init section yet (where map_start normally lies).
	 */
	if (IS_ERR(mapped =
		   do_mmap(0, 0, self, page_align_up(__end),
			   VMA_ANONYMOUS | VM_READ | VMA_FIXED |
			   VM_WRITE | VM_EXEC | VMA_PRIVATE,
			   __pfn(img_size)))) {
		printf("FATAL: do_mmap: failed with %d.\n",
		       (int)mapped);
		BUG();
	}
 
	debug_record_cycles("Until after do_mmap");
 
	 /* Prefault it */
	if ((err = task_prefault_range(self, (unsigned long)mapped,
				       img_size, VM_READ | VM_WRITE))
				       < 0) {
		printf("FATAL: Prefaulting init image failed.\n");
		BUG();
	}
 
 
	/* Copy the raw image to anon region */
	memcpy(mapped, init_img_start, img_size);
 
 
	debug_record_cycles("memcpy image");
 
 
	/* Write it to real file from anon region */
	sys_write(find_task(self_tid()), fd, mapped, img_size);
 
	debug_record_cycles("sys_write");
 
	/* Close file */
	sys_close(find_task(self_tid()), fd);
 
 
	debug_record_cycles("sys_close");
 
	/* Unmap anon region */
	do_munmap(self, (unsigned long)mapped, __pfn(img_size));
 
	/* Unmap raw virtual range for image memory */
	l4_unmap_helper(init_img_start,__pfn(img_size));
 
	debug_record_cycles("Final do_munmap/l4_unmap");
 
}
 
void start_init_process(void)
{
 
	copy_init_process();
 
	init_execve("/test0");
}
 
void init(void)
{
	setup_caps();
 
	pager_address_pool_init();
 
	read_boot_params();
 
	init_physmem();
 
	init_devzero();
 
	shm_pool_init();
 
	utcb_pool_init();
 
	vfs_init();
 
	pager_setup_task();
 
	start_init_process();
 
	release_initdata();
 
	mm0_test_global_vm_integrity();
}
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.