aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md17
-rw-r--r--src/kernel/core/kmain.c12
-rw-r--r--src/kernel/core/thread.c4
-rw-r--r--src/kernel/include/process.h18
-rw-r--r--src/kernel/include/thread.h5
-rw-r--r--src/kernel/include/vfs.h13
-rw-r--r--src/kernel/user/nullfs.c3
-rw-r--r--src/kernel/user/process.c35
-rw-r--r--src/kernel/user/vfs.c12
9 files changed, 84 insertions, 35 deletions
diff --git a/README.md b/README.md
index 282054c..b74eeef 100644
--- a/README.md
+++ b/README.md
@@ -93,7 +93,22 @@ running the tests):
### Things to design
-* Cache architecture
+* Cache architecture :
+ - A RAM file is basically a bunch of pages that contain the data (rather than a segment of
+ malloc()'ed memory)
+ - A framebuffer device is basically a bunch of pages at a fixed hardware location, that cannot
+ grow
+ - In the two previous cases, the pages are never freed : they are not a cache, they are the
+ data itself.
+ - In the case of an on-disk file, the pages are a copy of the file's data that is originally
+ on-disk, and we might want to free these pages even while a process is using them, because
+ we can always reload them from the disk.
+ - An on-disk file with a page cache must be aware of all the places where the page is mapped,
+ so that it can unmap it when reclaiming pages.
+ - Simpler model : cached pages cannot be freed while the file is open with `FM_MMAP`
+* Reclaiming physical memory :
+ - Freeing some cached stuff, ie swapping pages from mmap regions
+ - Swapping pages from processes non-mmap regions (ie real data regions)
* IPC
* How does a process exit, what does it do, how do processes synchronize ?
* Have several threads in a single process
diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c
index 219bab1..fa5d69c 100644
--- a/src/kernel/core/kmain.c
+++ b/src/kernel/core/kmain.c
@@ -124,14 +124,6 @@ void kernel_init_stage2(void* data) {
// Launch some worker threads
start_workers(2);
- // test sleep()
- dbg_printf("Testing sleep() : ");
- for (int i = 0; i < 20; i++) {
- usleep(50000);
- dbg_printf(".");
- }
- dbg_printf("\n");
-
TEST_PLACEHOLDER_AFTER_TASKING;
// Create devfs
@@ -167,13 +159,13 @@ void kernel_init_stage2(void* data) {
ASSERT(nullfs_add_ram_file(devfs, name,
(char*)mods[i].mod_start,
- len, false, FM_READ | FM_MMAP));
+ len, false, FM_READ));
}
TEST_PLACEHOLDER_AFTER_DEVFS;
// Launch INIT
- fs_handle_t *init_bin = fs_open(devfs, "/mod/init.bin", FM_READ | FM_MMAP);
+ fs_handle_t *init_bin = fs_open(devfs, "/mod/init.bin", FM_READ);
if (init_bin == 0) PANIC("No init.bin module provided!");
if (!is_elf(init_bin)) PANIC("init.bin is not valid ELF32 binary");
diff --git a/src/kernel/core/thread.c b/src/kernel/core/thread.c
index 7f9f25e..60dccde 100644
--- a/src/kernel/core/thread.c
+++ b/src/kernel/core/thread.c
@@ -7,6 +7,7 @@
#include <frame.h>
#include <paging.h>
#include <worker.h>
+#include <process.h>
void save_context_and_enter_scheduler(saved_context_t *ctx);
void resume_context(saved_context_t *ctx);
@@ -84,6 +85,8 @@ void run_scheduler() {
// This function is expected NEVER TO RETURN
if (current_thread != 0 && current_thread->state == T_STATE_RUNNING) {
+ current_thread->last_ran = worker_get_time();
+ if (current_thread->proc) current_thread->proc->last_ran = current_thread->last_ran;
enqueue_thread(current_thread, true);
}
@@ -141,6 +144,7 @@ thread_t *new_thread(entry_t entry, void* data) {
t->ctx.eip = (void(*)())run_thread;
t->state = T_STATE_PAUSED;
+ t->last_ran = 0;
t->current_pd_d = get_kernel_pagedir();
diff --git a/src/kernel/include/process.h b/src/kernel/include/process.h
index 07cc14e..6e287e1 100644
--- a/src/kernel/include/process.h
+++ b/src/kernel/include/process.h
@@ -21,7 +21,22 @@
#define USERSTACK_ADDR 0xB8000000
#define USERSTACK_SIZE 0x00020000 // 32 KB
-struct user_region;
+typedef struct process process_t;
+
+typedef struct user_region {
+ process_t *proc;
+
+ void* addr;
+ size_t size;
+
+ int mode;
+
+ fs_handle_t *file; // null if not mmaped-file
+ size_t file_offset;
+
+ struct user_region *next;
+} user_region_t;
+
typedef struct process {
pagedir_t *pd;
struct user_region *regions;
@@ -32,6 +47,7 @@ typedef struct process {
int next_fd;
thread_t *thread;
+ uint64_t last_ran;
int pid;
struct process *parent;
diff --git a/src/kernel/include/thread.h b/src/kernel/include/thread.h
index 8ffbb3d..fa7dc6f 100644
--- a/src/kernel/include/thread.h
+++ b/src/kernel/include/thread.h
@@ -18,16 +18,17 @@ typedef struct saved_context {
void (*eip)();
} saved_context_t;
-struct process;
+typedef struct process process_t;
typedef struct thread {
saved_context_t ctx;
pagedir_t *current_pd_d;
uint32_t state;
+ uint64_t last_ran;
region_info_t *stack_region;
- struct process *proc;
+ process_t *proc;
isr_handler_t user_ex_handler; // page fault in kernel memory accessed by user code (violation)
struct thread *next_in_queue;
diff --git a/src/kernel/include/vfs.h b/src/kernel/include/vfs.h
index cca4952..82b02f4 100644
--- a/src/kernel/include/vfs.h
+++ b/src/kernel/include/vfs.h
@@ -41,15 +41,21 @@ struct fs;
struct fs_node;
struct fs_handle;
+typedef struct user_region user_region_t;
+
// -------------------------------------------
// Structure defining a handle to an open file
typedef struct {
+ // Standard read-write architecture
size_t (*read)(fs_handle_ptr f, size_t offset, size_t len, char* buf);
size_t (*write)(fs_handle_ptr f, size_t offset, size_t len, const char* buf);
bool (*readdir)(fs_handle_ptr f, dirent_t *d);
int (*ioctl)(fs_handle_ptr f, int command, void* data);
void (*close)(fs_handle_ptr f);
+ // Page cache architecture, must be implemented by all files opened with FM_MMAP
+ uint32_t (*get_page)(fs_handle_ptr f, size_t offset);
+ void (*commit_page)(fs_handle_ptr f, size_t offset, uint64_t time); // notifies change
} fs_handle_ops_t;
typedef struct fs_handle {
@@ -165,11 +171,16 @@ bool fs_stat(fs_t *fs, const char* file, stat_t *st);
fs_handle_t* fs_open(fs_t *fs, const char* file, int mode);
void ref_file(fs_handle_t *file);
void unref_file(fs_handle_t *file);
+
int file_get_mode(fs_handle_t *f);
+bool file_stat(fs_handle_t *f, stat_t *st);
+
size_t file_read(fs_handle_t *f, size_t offset, size_t len, char* buf);
size_t file_write(fs_handle_t *f, size_t offset, size_t len, const char* buf);
-bool file_stat(fs_handle_t *f, stat_t *st);
int file_ioctl(fs_handle_t *f, int command, void* data);
bool file_readdir(fs_handle_t *f, dirent_t *d);
+uint32_t file_get_page(fs_handle_t *f, size_t offset);
+void file_commit_page(fs_handle_t *f, size_t offset, uint64_t time);
+
/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/kernel/user/nullfs.c b/src/kernel/user/nullfs.c
index 0ca0073..a925ab5 100644
--- a/src/kernel/user/nullfs.c
+++ b/src/kernel/user/nullfs.c
@@ -218,7 +218,8 @@ bool nullfs_add_ram_file(fs_t *fs, const char* name, char* data, size_t init_sz,
f->data = data;
f->own_data = false;
}
- f->ok_modes = ok_modes;
+ f->ok_modes = ok_modes &
+ (FM_TRUNC | FM_READ | FM_WRITE); // no MMAP support
f->lock = MUTEX_UNLOCKED;
bool add_ok = nullfs_add_node(fs, name, f, &nullfs_f_ops);
diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c
index 3ee78a7..c2eb413 100644
--- a/src/kernel/user/process.c
+++ b/src/kernel/user/process.c
@@ -5,17 +5,6 @@
#include <frame.h>
#include <process.h>
-typedef struct user_region {
- void* addr;
- size_t size;
-
- int mode;
-
- fs_handle_t *file; // null if not mmaped-file
- size_t file_offset;
-
- struct user_region *next;
-} user_region_t;
static int next_pid = 1;
@@ -47,6 +36,7 @@ process_t *new_process(process_t *parent) {
proc->pd = create_pagedir(proc_usermem_pf, proc);
if (proc->pd == 0) goto error;
+ proc->last_ran = 0;
proc->regions = 0;
proc->thread = 0;
proc->pid = (next_pid++);
@@ -207,6 +197,7 @@ bool mmap_file(process_t *proc, fs_handle_t *h, size_t offset, void* addr, size_
if (find_user_region(proc, addr) != 0) return false;
if ((uint32_t)addr & (~PAGE_MASK)) return false;
+ if ((uint32_t)offset & (~PAGE_MASK)) return false;
int fmode = file_get_mode(h);
if (!(fmode & FM_MMAP) || !(fmode & FM_READ)) return false;
@@ -247,6 +238,9 @@ bool mchmap(process_t *proc, void* addr, int mode) {
if (r == 0) return false;
+ if (r->file != 0) {
+ if ((mode & MM_WRITE) && !(file_get_mode(r->file) & FM_WRITE)) return false;
+ }
r->mode = mode;
// change mode on already mapped pages
@@ -295,10 +289,13 @@ bool munmap(process_t *proc, void* addr) {
if (ent & PTE_PRESENT) {
if ((ent & PTE_DIRTY) && (r->mode & MM_WRITE) && r->file != 0) {
- file_write(r->file, it - r->addr + r->file_offset, PAGE_SIZE, it);
+ file_commit_page(r->file, it - r->addr + r->file_offset, proc->last_ran);
}
pd_unmap_page(it);
- frame_free(frame, 1);
+ if (r->file != 0) {
+ // frame is owned by process
+ frame_free(frame, 1);
+ }
}
}
switch_pagedir(save_pd);
@@ -342,7 +339,11 @@ static void proc_usermem_pf(void* p, registers_t *regs, void* addr) {
uint32_t frame;
do {
- frame = frame_alloc(1);
+ if (r->file == 0) {
+ frame = frame_alloc(1);
+ } else {
+ frame = file_get_page(r->file, addr - r->addr + r->file_offset);
+ }
if (frame == 0) {
dbg_printf("OOM for process %d ; yielding and waiting for someone to free some RAM.\n", proc->pid);
yield();
@@ -354,11 +355,7 @@ static void proc_usermem_pf(void* p, registers_t *regs, void* addr) {
yield();
}
- memset(addr, 0, PAGE_SIZE); // zero out
-
- if (r->file != 0) {
- file_read(r->file, addr - r->addr + r->file_offset, PAGE_SIZE, addr);
- }
+ if (r->file == 0) memset(addr, 0, PAGE_SIZE); // zero out
}
void probe_for_read(const void* addr, size_t len) {
diff --git a/src/kernel/user/vfs.c b/src/kernel/user/vfs.c
index a5f03ca..c20caa0 100644
--- a/src/kernel/user/vfs.c
+++ b/src/kernel/user/vfs.c
@@ -445,4 +445,16 @@ bool file_readdir(fs_handle_t *f, dirent_t *d) {
return f->ops->readdir && f->ops->readdir(f->data, d);
}
+uint32_t file_get_page(fs_handle_t *f, size_t offset) {
+ if (!(f->mode & FM_MMAP)) return 0;
+ ASSERT(f->ops->get_page != 0);
+ return f->ops->get_page(f->data, offset);
+}
+
+void file_commit_page(fs_handle_t *f, size_t offset, uint64_t time) {
+ if (!(f->mode & FM_MMAP)) return;
+ ASSERT(f->ops->commit_page != 0);
+ f->ops->commit_page(f->data, offset, time);
+}
+
/* vim: set ts=4 sw=4 tw=0 noet :*/