mirror of
https://github.com/drasko/codezero.git
synced 2026-01-12 02:43:15 +01:00
Adds reading pages into page-cache in an ordered manner.
Added reading pages from the page cache into user buffer for sys_read. Increases stack sizes to 4 pages. Updated README to include more details about multi-pager environments.
This commit is contained in:
40
README
40
README
@@ -38,17 +38,35 @@ Codezero. These system calls provide purely mechanism; threads and address
|
||||
spaces, and the methods of inter-process communication between them. Anything
|
||||
beyond these are policy and they are implemented in the userspace. Due to this
|
||||
rigorously simple design the same microkernel can be used to design completely
|
||||
different operating systems. In terms of other features, the microkernel is
|
||||
preemptive, and smp-ready. Currently only synchronous communication is
|
||||
implemented, but this will change in the near future.
|
||||
different operating systems.
|
||||
|
||||
MM0 is the systm task that implements memory management. It contains memory and
|
||||
In terms of other features, the microkernel is preemptive, and smp-ready.
|
||||
Currently only synchronous communication is implemented, but this will change in
|
||||
the near future.
|
||||
|
||||
MM0 is the system task that implements memory management. It contains memory and
|
||||
page allocators. It implements demand paging by managing page faults, physical
|
||||
pages and their file/task associations.
|
||||
pages and their file/task associations. It provides the default paging mechanism
|
||||
on Codezero.
|
||||
|
||||
FS0 is the system task that implements a simple, modern virtual filesystem layer.
|
||||
Since it abstracts the low-level filesystem details, it is a relatively easy job
|
||||
to port a new filesystem to be used under FS0.
|
||||
It is designed to serve file requests from MM0. Since it abstracts the low-level
|
||||
filesystem details, it is a relatively easy job to port a new filesystem to be
|
||||
used under FS0.
|
||||
|
||||
MM0 and FS0 both reside in the userspace, and they are not mandatory services.
|
||||
For example the virtual and physical memory resources can be partitioned by
|
||||
Codezero among pagers, and a third-party pager can override Codezero's MM0
|
||||
pager on the same run-time, and implement an independent paging behaviour
|
||||
for its own memory partition. This feature provides the option of having an
|
||||
adjustable mixture of generalisation and specialisation at the same run-time, by
|
||||
using a combination of Codezero's abstract posix-like page/file management
|
||||
services and an application-specific pager that depends on its own paging
|
||||
abilities. For example a critical task could both use posix-like files
|
||||
benefiting from the abstraction and simplification that it brings, but at the
|
||||
same time rely on its own page-fault handling for its critical data so that even
|
||||
though it handles its memory in a specialised way, it does not depend on another
|
||||
pager's grace for correct, stable operation.
|
||||
|
||||
|
||||
License:
|
||||
@@ -75,8 +93,8 @@ code. Linux is well established, and targets a broad range of platforms and
|
||||
uses, but consequently embedded platforms don't always get enough emphasis. Also
|
||||
such well established, mature systems tend to oppose major design overhauls,
|
||||
which limits innovation to a certain extent. In addition, their code base is so
|
||||
big, that it gets more and more difficult to understand how the system works.
|
||||
Usually much of the code is irrelevant to the problem, in case of embedded
|
||||
big, that it gets more and more difficult to understand how their internals
|
||||
work. Usually much of the code is irrelevant to the problem, in case of embedded
|
||||
systems. Codezero is written from scratch to solely target embedded systems and
|
||||
as such the source code is %100 relevant. It is small and free from legacy code.
|
||||
Finally monolithic kernels may have issues with dependability due to much of the
|
||||
@@ -99,3 +117,7 @@ development methodologies, Codezero project aims to keep up with the latest OS
|
||||
literature and provide the opportunity to incorporate the latest ideas in OS
|
||||
technology.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -66,15 +66,12 @@ int memfs_format_filesystem(void *buffer)
|
||||
INIT_LIST_HEAD(&sb->inode_cache_list);
|
||||
memfs_init_caches(sb);
|
||||
|
||||
/*
|
||||
* TODO: Make sure root vnode has a vnode number of 0 !!!.
|
||||
* This is used in early root lookup.
|
||||
*/
|
||||
BUG();
|
||||
|
||||
/* We allocate and fix a root inode so the sb is ready for mount */
|
||||
sb->root = memfs_create_inode(sb);
|
||||
|
||||
/* Some early-init code relies on root having inode number 0 */
|
||||
BUG_ON(sb->root->inum != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,15 +113,7 @@ int sys_open(l4id_t sender, const char *pathname, int flags, unsigned int mode)
|
||||
|
||||
int sys_close(l4id_t sender, int fd)
|
||||
{
|
||||
struct vnode *v;
|
||||
|
||||
/* Get the task */
|
||||
BUG_ON(!(task = find_task(sender)));
|
||||
|
||||
/* Lookup vnode */
|
||||
if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
|
||||
return -EINVAL; /* No such vnode */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_mkdir(l4id_t sender, const char *pathname, unsigned int mode)
|
||||
|
||||
@@ -112,6 +112,9 @@ static inline struct vm_area *find_vma(unsigned long addr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Adds a page to its vmfile's page cache in order of offset. */
|
||||
int insert_page_olist(struct page *this, struct vm_file *f);
|
||||
|
||||
/* Pagers */
|
||||
extern struct vm_pager default_file_pager;
|
||||
extern struct vm_pager boot_file_pager;
|
||||
|
||||
@@ -20,13 +20,6 @@
|
||||
#include <syscalls.h>
|
||||
#include <file.h>
|
||||
|
||||
/* FIXME:LOCKING:FIXME:LOCKING:FIXME:LOCKING
|
||||
* NOTE: For multithreadded MM0, not suprisingly, we need locking on
|
||||
* vmas, vm_files, and all global variables. Also at times, the per-task
|
||||
* lists of items (e.g. vmas) must be entirely locked. Pages already have
|
||||
* locking.
|
||||
*/
|
||||
|
||||
void handle_requests(void)
|
||||
{
|
||||
/* Generic ipc data */
|
||||
|
||||
@@ -130,7 +130,7 @@ int do_file_page(struct fault_data *fault)
|
||||
|
||||
/* Add the page to it's owner's list of in-memory pages */
|
||||
BUG_ON(!list_empty(&page->list));
|
||||
list_add(&page->list, &page->owner->page_cache_list);
|
||||
insert_page_olist(page, page->owner);
|
||||
spin_unlock(&page->lock);
|
||||
//printf("%s: Mapped new page @ 0x%x to task: %d\n", __TASKNAME__,
|
||||
// fault->address, fault->task->tid);
|
||||
@@ -184,7 +184,7 @@ int do_file_page(struct fault_data *fault)
|
||||
|
||||
/* Add the page to it's owner's list of in-memory pages */
|
||||
BUG_ON(!list_empty(&page->list));
|
||||
list_add(&page->list, &page->owner->page_cache_list);
|
||||
insert_page_olist(page, page->owner);
|
||||
spin_unlock(&page->lock);
|
||||
|
||||
/*
|
||||
@@ -244,7 +244,7 @@ int do_file_page(struct fault_data *fault)
|
||||
|
||||
/* Add the page to it's owner's list of in-memory pages */
|
||||
BUG_ON(!list_empty(&page->list));
|
||||
list_add(&page->list, &page->owner->page_cache_list);
|
||||
insert_page_olist(page, page->owner);
|
||||
spin_unlock(&page->lock);
|
||||
} else
|
||||
BUG();
|
||||
@@ -333,7 +333,7 @@ int do_anon_page(struct fault_data *fault)
|
||||
|
||||
/* Add the page to it's owner's list of in-memory pages */
|
||||
BUG_ON(!list_empty(&page->list));
|
||||
list_add(&page->list, &page->owner->page_cache_list);
|
||||
insert_page_olist(page, page->owner);
|
||||
|
||||
/* The offset of this page in its owner file */
|
||||
page->f_offset = __pfn(fault->address)
|
||||
@@ -391,15 +391,15 @@ int do_page_fault(struct fault_data *fault)
|
||||
|
||||
/* vma flags show no access */
|
||||
if (vma_flags & VM_NONE) {
|
||||
printf("Illegal access, tid: %d, address: %x\n",
|
||||
fault->task->tid, fault->address);
|
||||
printf("Illegal access, tid: %d, address: 0x%x, PC @ 0x%x,\n",
|
||||
fault->task->tid, fault->address, fault->kdata->faulty_pc);
|
||||
BUG();
|
||||
}
|
||||
|
||||
/* The access reason is not included in the vma's listed flags */
|
||||
if (!(reason & vma_flags)) {
|
||||
printf("Illegal access, tid: %d, address: %x\n",
|
||||
fault->task->tid, fault->address);
|
||||
printf("Illegal access, tid: %d, address: 0x%x, PC @ 0x%x\n",
|
||||
fault->task->tid, fault->address, fault->kdata->faulty_pc);
|
||||
BUG();
|
||||
}
|
||||
|
||||
|
||||
@@ -132,18 +132,55 @@ int vfs_receive_sys_open(l4id_t sender, l4id_t opener, int fd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: Implement this */
|
||||
struct page *find_page(struct vm_file *f, unsigned long pfn)
|
||||
{
|
||||
struct page *p;
|
||||
|
||||
list_for_each_entry(p, &f->page_cache_list, list) {
|
||||
list_for_each_entry(p, &f->page_cache_list, list)
|
||||
if (p->f_offset == pfn)
|
||||
return p;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inserts the page to vmfile's list in order of page frame offset.
|
||||
* We use an ordered list instead of a radix or btree for now.
|
||||
*/
|
||||
int insert_page_olist(struct page *this, struct vm_file *f)
|
||||
{
|
||||
struct page *before, *after;
|
||||
|
||||
/* Add if list is empty */
|
||||
if (list_empty(&f->page_cache_list)) {
|
||||
list_add_tail(&this->list, &f->page_cache_list);
|
||||
return 0;
|
||||
}
|
||||
/* Else find the right interval */
|
||||
list_for_each_entry(before, &f->page_cache_list, list) {
|
||||
after = list_entry(before->list.next, struct page, list);
|
||||
|
||||
/* If there's only one in list */
|
||||
if (before->list.next == &f->page_cache_list) {
|
||||
/* Add to end if greater */
|
||||
if (this->f_offset > before->f_offset)
|
||||
list_add_tail(&this->list, &before->list);
|
||||
/* Add to beginning if smaller */
|
||||
else if (this->f_offset < before->f_offset)
|
||||
list_add(&this->list, &before->list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If this page is in-between two other, insert it there */
|
||||
if (before->f_offset < this->f_offset &&
|
||||
after->f_offset > this->f_offset) {
|
||||
list_add_tail(&this->list, &before->list);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
BUG();
|
||||
}
|
||||
|
||||
/*
|
||||
* This reads-in a range of pages from a file and populates the page cache
|
||||
* just like a page fault, but its not in the page fault path.
|
||||
@@ -180,7 +217,7 @@ int read_file_pages(struct vm_file *vmfile, unsigned long pfn_start,
|
||||
|
||||
/* Add the page to owner's list of in-memory pages */
|
||||
BUG_ON(!list_empty(&page->list));
|
||||
list_add(&page->list, &vmfile->page_cache_list);
|
||||
insert_page_olist(page, vmfile);
|
||||
spin_unlock(&page->lock);
|
||||
}
|
||||
}
|
||||
@@ -188,11 +225,49 @@ int read_file_pages(struct vm_file *vmfile, unsigned long pfn_start,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reads a page range from an ordered list of pages into buffer */
|
||||
int read_cache_pages(struct vm_file *vmfile, void *buf, unsigned long pfn_start,
|
||||
unsigned long pfn_end, unsigned long offset,
|
||||
int count)
|
||||
{
|
||||
struct page *head, *next;
|
||||
int copysize, left;
|
||||
|
||||
list_for_each_entry(head, &vmfile->page_cache_list, list)
|
||||
if (head->f_offset == pfn_start)
|
||||
goto copy;
|
||||
BUG();
|
||||
|
||||
copy:
|
||||
left = count;
|
||||
|
||||
/* Copy the first page */
|
||||
copysize = (left <= PAGE_SIZE) ? left : PAGE_SIZE;
|
||||
memcpy(buf, (void *)phys_to_virt((void *)page_to_phys(head)) + offset,
|
||||
copysize);
|
||||
left -= copysize;
|
||||
|
||||
/* Copy the rest. Urgh, lots of arithmetic here. */
|
||||
list_for_each_entry(next, &head->list, list) {
|
||||
if (left == 0 || next->f_offset == pfn_end)
|
||||
break;
|
||||
copysize = (left <= PAGE_SIZE) ? left : PAGE_SIZE;
|
||||
memcpy(buf + count - left,
|
||||
(void *)phys_to_virt((void *)page_to_phys(next)),
|
||||
copysize);
|
||||
left -= copysize;
|
||||
}
|
||||
BUG_ON(left != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int sys_read(l4id_t sender, int fd, void *buf, int count)
|
||||
{
|
||||
unsigned long foff_pfn_start, foff_pfn_end;
|
||||
unsigned long cursor, first_pgoff;
|
||||
struct vm_file *vmfile;
|
||||
unsigned long cursor;
|
||||
struct tcb *t;
|
||||
int err;
|
||||
|
||||
@@ -208,43 +283,26 @@ int sys_read(l4id_t sender, int fd, void *buf, int count)
|
||||
foff_pfn_start = __pfn(cursor);
|
||||
foff_pfn_end = __pfn(page_align_up(cursor + count));
|
||||
|
||||
/* Read the page range into the cache from file */
|
||||
if ((err = read_file_pages(vmfile, foff_pfn_start, foff_pfn_end) < 0))
|
||||
return err;
|
||||
|
||||
/*
|
||||
* FIXME: If vmfiles are mapped contiguously on mm0, then these reads
|
||||
* can be implemented as a straightforward copy as below.
|
||||
*
|
||||
* The problem is that in-memory file pages are usually non-contiguous.
|
||||
* memcpy(buf, (void *)(vmfile->base + cursor), count);
|
||||
*/
|
||||
/* The offset of cursor on first page */
|
||||
first_pgoff = PAGE_MASK & cursor;
|
||||
|
||||
/* Read it into the user buffer from the cache */
|
||||
if ((err = read_cache_pages(vmfile, buf, foff_pfn_start, foff_pfn_end,
|
||||
first_pgoff, count)) < 0)
|
||||
return err;
|
||||
|
||||
/* Update cursor on success */
|
||||
t->fd[fd].cursor += count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_write(l4id_t sender, int fd, void *buf, int count)
|
||||
{
|
||||
unsigned long foff_pfn_start, foff_pfn_end;
|
||||
struct vm_file *vmfile;
|
||||
unsigned long cursor;
|
||||
struct tcb *t;
|
||||
int err;
|
||||
|
||||
BUG_ON(!(t = find_task(sender)));
|
||||
|
||||
/* TODO: Check user buffer and count validity */
|
||||
if (fd < 0 || fd > TASK_OFILES_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
vmfile = t->fd[fd].vmfile;
|
||||
cursor = t->fd[fd].cursor;
|
||||
|
||||
foff_pfn_start = __pfn(cursor);
|
||||
foff_pfn_end = __pfn(page_align_up(cursor + count));
|
||||
|
||||
if ((err = write_file_pages(vmfile, foff_pfn_start, foff_pfn_end) < 0))
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -127,9 +127,9 @@ int start_boot_tasks(struct initdata *initdata, struct tcb_head *tcbs)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* mmap each task's stack as single page anonymous memory. */
|
||||
if ((err = do_mmap(0, 0, task, USER_AREA_END - PAGE_SIZE,
|
||||
VM_READ | VM_WRITE | VMA_ANON, 1) < 0)) {
|
||||
/* mmap each task's stack as 4-page anonymous memory. */
|
||||
if ((err = do_mmap(0, 0, task, USER_AREA_END - PAGE_SIZE * 4,
|
||||
VM_READ | VM_WRITE | VMA_ANON, 4) < 0)) {
|
||||
printf("do_mmap: Mapping stack failed with %d.\n", err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -26,9 +26,12 @@ void main(void)
|
||||
{
|
||||
printf("\n%s: Started with tid %d.\n", __TASKNAME__, self_tid());
|
||||
/* Sync with pager */
|
||||
wait_pager(0);
|
||||
|
||||
dirtest();
|
||||
|
||||
while (1)
|
||||
wait_pager(0);
|
||||
|
||||
#if 0
|
||||
/* Check mmap/munmap */
|
||||
mmaptest();
|
||||
|
||||
Reference in New Issue
Block a user