mirror of
https://github.com/drasko/codezero.git
synced 2026-04-27 06:09:03 +02: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
|
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
|
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
|
rigorously simple design the same microkernel can be used to design completely
|
||||||
different operating systems. In terms of other features, the microkernel is
|
different operating systems.
|
||||||
preemptive, and smp-ready. Currently only synchronous communication is
|
|
||||||
implemented, but this will change in the near future.
|
|
||||||
|
|
||||||
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
|
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.
|
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
|
It is designed to serve file requests from MM0. Since it abstracts the low-level
|
||||||
to port a new filesystem to be used under FS0.
|
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:
|
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
|
uses, but consequently embedded platforms don't always get enough emphasis. Also
|
||||||
such well established, mature systems tend to oppose major design overhauls,
|
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
|
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.
|
big, that it gets more and more difficult to understand how their internals
|
||||||
Usually much of the code is irrelevant to the problem, in case of embedded
|
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
|
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.
|
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
|
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
|
literature and provide the opportunity to incorporate the latest ideas in OS
|
||||||
technology.
|
technology.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -66,15 +66,12 @@ int memfs_format_filesystem(void *buffer)
|
|||||||
INIT_LIST_HEAD(&sb->inode_cache_list);
|
INIT_LIST_HEAD(&sb->inode_cache_list);
|
||||||
memfs_init_caches(sb);
|
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 */
|
/* We allocate and fix a root inode so the sb is ready for mount */
|
||||||
sb->root = memfs_create_inode(sb);
|
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;
|
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)
|
int sys_close(l4id_t sender, int fd)
|
||||||
{
|
{
|
||||||
struct vnode *v;
|
return 0;
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int sys_mkdir(l4id_t sender, const char *pathname, unsigned int mode)
|
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;
|
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 */
|
/* Pagers */
|
||||||
extern struct vm_pager default_file_pager;
|
extern struct vm_pager default_file_pager;
|
||||||
extern struct vm_pager boot_file_pager;
|
extern struct vm_pager boot_file_pager;
|
||||||
|
|||||||
@@ -20,13 +20,6 @@
|
|||||||
#include <syscalls.h>
|
#include <syscalls.h>
|
||||||
#include <file.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)
|
void handle_requests(void)
|
||||||
{
|
{
|
||||||
/* Generic ipc data */
|
/* 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 */
|
/* Add the page to it's owner's list of in-memory pages */
|
||||||
BUG_ON(!list_empty(&page->list));
|
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);
|
spin_unlock(&page->lock);
|
||||||
//printf("%s: Mapped new page @ 0x%x to task: %d\n", __TASKNAME__,
|
//printf("%s: Mapped new page @ 0x%x to task: %d\n", __TASKNAME__,
|
||||||
// fault->address, fault->task->tid);
|
// 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 */
|
/* Add the page to it's owner's list of in-memory pages */
|
||||||
BUG_ON(!list_empty(&page->list));
|
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);
|
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 */
|
/* Add the page to it's owner's list of in-memory pages */
|
||||||
BUG_ON(!list_empty(&page->list));
|
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);
|
spin_unlock(&page->lock);
|
||||||
} else
|
} else
|
||||||
BUG();
|
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 */
|
/* Add the page to it's owner's list of in-memory pages */
|
||||||
BUG_ON(!list_empty(&page->list));
|
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 */
|
/* The offset of this page in its owner file */
|
||||||
page->f_offset = __pfn(fault->address)
|
page->f_offset = __pfn(fault->address)
|
||||||
@@ -391,15 +391,15 @@ int do_page_fault(struct fault_data *fault)
|
|||||||
|
|
||||||
/* vma flags show no access */
|
/* vma flags show no access */
|
||||||
if (vma_flags & VM_NONE) {
|
if (vma_flags & VM_NONE) {
|
||||||
printf("Illegal access, tid: %d, address: %x\n",
|
printf("Illegal access, tid: %d, address: 0x%x, PC @ 0x%x,\n",
|
||||||
fault->task->tid, fault->address);
|
fault->task->tid, fault->address, fault->kdata->faulty_pc);
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The access reason is not included in the vma's listed flags */
|
/* The access reason is not included in the vma's listed flags */
|
||||||
if (!(reason & vma_flags)) {
|
if (!(reason & vma_flags)) {
|
||||||
printf("Illegal access, tid: %d, address: %x\n",
|
printf("Illegal access, tid: %d, address: 0x%x, PC @ 0x%x\n",
|
||||||
fault->task->tid, fault->address);
|
fault->task->tid, fault->address, fault->kdata->faulty_pc);
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -132,18 +132,55 @@ int vfs_receive_sys_open(l4id_t sender, l4id_t opener, int fd,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Implement this */
|
|
||||||
struct page *find_page(struct vm_file *f, unsigned long pfn)
|
struct page *find_page(struct vm_file *f, unsigned long pfn)
|
||||||
{
|
{
|
||||||
struct page *p;
|
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)
|
if (p->f_offset == pfn)
|
||||||
return p;
|
return p;
|
||||||
}
|
|
||||||
return 0;
|
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
|
* 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.
|
* 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 */
|
/* Add the page to owner's list of in-memory pages */
|
||||||
BUG_ON(!list_empty(&page->list));
|
BUG_ON(!list_empty(&page->list));
|
||||||
list_add(&page->list, &vmfile->page_cache_list);
|
insert_page_olist(page, vmfile);
|
||||||
spin_unlock(&page->lock);
|
spin_unlock(&page->lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,11 +225,49 @@ int read_file_pages(struct vm_file *vmfile, unsigned long pfn_start,
|
|||||||
return 0;
|
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)
|
int sys_read(l4id_t sender, int fd, void *buf, int count)
|
||||||
{
|
{
|
||||||
unsigned long foff_pfn_start, foff_pfn_end;
|
unsigned long foff_pfn_start, foff_pfn_end;
|
||||||
|
unsigned long cursor, first_pgoff;
|
||||||
struct vm_file *vmfile;
|
struct vm_file *vmfile;
|
||||||
unsigned long cursor;
|
|
||||||
struct tcb *t;
|
struct tcb *t;
|
||||||
int err;
|
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_start = __pfn(cursor);
|
||||||
foff_pfn_end = __pfn(page_align_up(cursor + count));
|
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))
|
if ((err = read_file_pages(vmfile, foff_pfn_start, foff_pfn_end) < 0))
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
/*
|
/* The offset of cursor on first page */
|
||||||
* FIXME: If vmfiles are mapped contiguously on mm0, then these reads
|
first_pgoff = PAGE_MASK & cursor;
|
||||||
* can be implemented as a straightforward copy as below.
|
|
||||||
*
|
/* Read it into the user buffer from the cache */
|
||||||
* The problem is that in-memory file pages are usually non-contiguous.
|
if ((err = read_cache_pages(vmfile, buf, foff_pfn_start, foff_pfn_end,
|
||||||
* memcpy(buf, (void *)(vmfile->base + cursor), count);
|
first_pgoff, count)) < 0)
|
||||||
*/
|
return err;
|
||||||
|
|
||||||
|
/* Update cursor on success */
|
||||||
|
t->fd[fd].cursor += count;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sys_write(l4id_t sender, int fd, void *buf, int count)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,9 +127,9 @@ int start_boot_tasks(struct initdata *initdata, struct tcb_head *tcbs)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mmap each task's stack as single page anonymous memory. */
|
/* mmap each task's stack as 4-page anonymous memory. */
|
||||||
if ((err = do_mmap(0, 0, task, USER_AREA_END - PAGE_SIZE,
|
if ((err = do_mmap(0, 0, task, USER_AREA_END - PAGE_SIZE * 4,
|
||||||
VM_READ | VM_WRITE | VMA_ANON, 1) < 0)) {
|
VM_READ | VM_WRITE | VMA_ANON, 4) < 0)) {
|
||||||
printf("do_mmap: Mapping stack failed with %d.\n", err);
|
printf("do_mmap: Mapping stack failed with %d.\n", err);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,9 +26,12 @@ void main(void)
|
|||||||
{
|
{
|
||||||
printf("\n%s: Started with tid %d.\n", __TASKNAME__, self_tid());
|
printf("\n%s: Started with tid %d.\n", __TASKNAME__, self_tid());
|
||||||
/* Sync with pager */
|
/* Sync with pager */
|
||||||
|
wait_pager(0);
|
||||||
|
|
||||||
|
dirtest();
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
wait_pager(0);
|
wait_pager(0);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* Check mmap/munmap */
|
/* Check mmap/munmap */
|
||||||
mmaptest();
|
mmaptest();
|
||||||
|
|||||||
Reference in New Issue
Block a user