mirror of
https://github.com/drasko/codezero.git
synced 2026-01-12 10:53:16 +01:00
We still have to have the pager structs because they possess intermediate data during boot up such as for transferring of capability lists to boot stack one-by-one, and then to newly generated ktcbs.
199 lines
4.9 KiB
C
199 lines
4.9 KiB
C
/*
|
|
* Containers defined for current build.
|
|
*
|
|
* Copyright (C) 2009 Bahadir Balban
|
|
*/
|
|
#include <l4/generic/container.h>
|
|
#include <l4/generic/resource.h>
|
|
#include <l4/generic/capability.h>
|
|
#include <l4/generic/cap-types.h>
|
|
#include <l4/generic/bootmem.h>
|
|
#include <l4/api/errno.h>
|
|
#include INC_GLUE(memory.h)
|
|
#include INC_SUBARCH(mm.h)
|
|
#include INC_ARCH(linker.h)
|
|
|
|
int container_init(struct container *c)
|
|
{
|
|
/* Allocate new container id */
|
|
c->cid = id_new(&kernel_resources.container_ids);
|
|
|
|
/* Init data structures */
|
|
link_init(&c->pager_list);
|
|
init_address_space_list(&c->space_list);
|
|
init_ktcb_list(&c->ktcb_list);
|
|
init_mutex_queue_head(&c->mutex_queue_head);
|
|
cap_list_init(&c->cap_list);
|
|
|
|
/* Init pager structs */
|
|
c->pager = alloc_bootmem(sizeof(c->pager[0]) *
|
|
CONFIG_MAX_PAGERS_USED, 0);
|
|
for (int i = 0; i < CONFIG_MAX_PAGERS_USED; i++)
|
|
cap_list_init(&c->pager[i].cap_list);
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct container *container_create(void)
|
|
{
|
|
struct container *c = alloc_container();
|
|
|
|
container_init(c);
|
|
|
|
return c;
|
|
}
|
|
|
|
void kres_insert_container(struct container *c,
|
|
struct kernel_resources *kres)
|
|
{
|
|
list_insert(&c->list, &kres->containers.list);
|
|
kres->containers.ncont++;
|
|
}
|
|
|
|
/*
|
|
* TODO:
|
|
*
|
|
* Create a purer address_space_create that takes
|
|
* flags for extra ops such as copying kernel tables,
|
|
* user tables of an existing pgd etc.
|
|
*/
|
|
|
|
/*
|
|
* Inspects pager parameters defined in the container,
|
|
* and sets up an execution environment for the pager.
|
|
*
|
|
* This involves setting up pager's ktcb, space, utcb,
|
|
* all ids, registers, and mapping its (perhaps) first
|
|
* few pages in order to make it runnable.
|
|
*
|
|
* The first pager initialization is a special-case
|
|
* since it uses the current kernel pgd.
|
|
*/
|
|
int init_pager(struct pager *pager,
|
|
struct container *cont,
|
|
pgd_table_t *current_pgd)
|
|
{
|
|
struct ktcb *task;
|
|
struct address_space *space;
|
|
int first = !!current_pgd;
|
|
struct capability *cap;
|
|
|
|
/*
|
|
* Set up dummy current cap_list so that cap accounting
|
|
* can be done to this pager. Note, that we're still on
|
|
* bootstack.
|
|
*/
|
|
cap_list_move(¤t->cap_list, &pager->cap_list);
|
|
|
|
/* New ktcb allocation is needed */
|
|
task = tcb_alloc_init();
|
|
|
|
/* If first, manually allocate/initalize space */
|
|
if (first) {
|
|
if (!(space = alloc_space())) {
|
|
return -ENOMEM;
|
|
}
|
|
/* Set up space id */
|
|
space->spid = id_new(&kernel_resources.space_ids);
|
|
|
|
/* Initialize space structure */
|
|
link_init(&space->list);
|
|
mutex_init(&space->lock);
|
|
cap_list_init(&space->cap_list);
|
|
space->pgd = current_pgd;
|
|
address_space_attach(task, space);
|
|
} else {
|
|
/* Otherwise allocate conventionally */
|
|
space = address_space_create(0);
|
|
address_space_attach(task, space);
|
|
}
|
|
|
|
/* Initialize ktcb */
|
|
task_init_registers(task, pager->start_address);
|
|
|
|
/* Initialize container/pager relationships */
|
|
task->pagerid = task->tid;
|
|
task->tgid = task->tid;
|
|
task->container = cont;
|
|
|
|
/*
|
|
* Setup dummy container pointer so that curcont works,
|
|
* and add the address space to container space list
|
|
*/
|
|
current->container = cont;
|
|
address_space_add(task->space);
|
|
|
|
/* Initialize uninitialized capability fields while on dummy */
|
|
list_foreach_struct(cap, ¤t->cap_list.caps, list) {
|
|
/* Initialize owner */
|
|
cap->owner = task->tid;
|
|
|
|
/*
|
|
* Initialize resource id, if possible.
|
|
* Currently this is a temporary hack where
|
|
* we allow only container ids and _assume_
|
|
* that container is pager's own container.
|
|
*
|
|
* See capability resource ids for info
|
|
*/
|
|
if (cap_rtype(cap) == CAP_RTYPE_CONTAINER)
|
|
cap->resid = task->container->cid;
|
|
else
|
|
cap->resid = CAP_RESID_NONE;
|
|
}
|
|
|
|
printk("%s: Mapping 0x%lx bytes (0x%lx pages) from 0x%lx to 0x%lx for %s\n",
|
|
__KERNELNAME__, pager->memsize,
|
|
__pfn(page_align_up(pager->memsize)),
|
|
pager->start_lma, pager->start_vma, cont->name);
|
|
|
|
/* Map the task's space */
|
|
add_mapping_pgd(pager->start_lma, pager->start_vma,
|
|
page_align_up(pager->memsize),
|
|
MAP_USR_DEFAULT_FLAGS, TASK_PGD(task));
|
|
|
|
/* Move capability list from dummy to task's space cap list */
|
|
cap_list_move(&task->space->cap_list, ¤t->cap_list);
|
|
|
|
/* Initialize task scheduler parameters */
|
|
sched_init_task(task, TASK_PRIO_PAGER);
|
|
|
|
/* Give it a kick-start tick and make runnable */
|
|
task->ticks_left = 1;
|
|
sched_resume_async(task);
|
|
|
|
/* Container list that keeps all tasks */
|
|
tcb_add(task);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Initialize all containers with their initial set of tasks,
|
|
* spaces, scheduler parameters such that they can be started.
|
|
*/
|
|
int container_init_pagers(struct kernel_resources *kres,
|
|
pgd_table_t *current_pgd)
|
|
{
|
|
struct container *cont;
|
|
struct pager *pager;
|
|
int first = 1;
|
|
|
|
list_foreach_struct(cont, &kres->containers.list, list) {
|
|
for (int i = 0; i < cont->npagers; i++) {
|
|
pager = &cont->pager[i];
|
|
|
|
/* First pager initializes specially */
|
|
if (first) {
|
|
init_pager(pager, cont, current_pgd);
|
|
first = 0;
|
|
} else {
|
|
init_pager(pager, cont, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|