init commit of lab5_3

lab5_3_hostdevice
Zhiyuan Shao 1 year ago
parent 6151bee3cd
commit da9a3e456f

@ -68,7 +68,7 @@ USER_CPPS := user/*.c
USER_CPPS := $(wildcard $(USER_CPPS)) USER_CPPS := $(wildcard $(USER_CPPS))
USER_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_CPPS))) USER_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_CPPS)))
USER_TARGET := $(OBJ_DIR)/app_PLIC USER_TARGET := $(OBJ_DIR)/app_host_device
#------------------------targets------------------------ #------------------------targets------------------------
$(OBJ_DIR): $(OBJ_DIR):
@-mkdir -p $(OBJ_DIR) @-mkdir -p $(OBJ_DIR)

@ -1,5 +1,5 @@
/* /*
* routines that scan and load a (host) Executable and Linkable Format (ELF) file * Utility routines that scan and load a (host) Executable and Linkable Format (ELF) file
* into the (emulated) memory. * into the (emulated) memory.
*/ */
@ -9,6 +9,7 @@
#include "vmm.h" #include "vmm.h"
#include "pmm.h" #include "pmm.h"
#include "spike_interface/spike_utils.h" #include "spike_interface/spike_utils.h"
#include "util/functions.h"
typedef struct elf_info_t { typedef struct elf_info_t {
spike_file_t *f; spike_file_t *f;
@ -21,8 +22,6 @@ typedef struct elf_info_t {
// //
static void *elf_alloc_mb(elf_ctx *ctx, uint64 elf_pa, uint64 elf_va, uint64 size) { static void *elf_alloc_mb(elf_ctx *ctx, uint64 elf_pa, uint64 elf_va, uint64 size) {
elf_info *msg = (elf_info *)ctx->info; elf_info *msg = (elf_info *)ctx->info;
// we assume that size of proram segment is smaller than a page.
kassert(size < PGSIZE);
void *pa = alloc_page(); void *pa = alloc_page();
if (pa == 0) panic("uvmalloc mem alloc falied\n"); if (pa == 0) panic("uvmalloc mem alloc falied\n");
@ -77,11 +76,21 @@ elf_status elf_load(elf_ctx *ctx) {
if (ph_addr.vaddr + ph_addr.memsz < ph_addr.vaddr) return EL_ERR; if (ph_addr.vaddr + ph_addr.memsz < ph_addr.vaddr) return EL_ERR;
// allocate memory block before elf loading // allocate memory block before elf loading
void *dest = elf_alloc_mb(ctx, ph_addr.vaddr, ph_addr.vaddr, ph_addr.memsz); int npage = ph_addr.memsz / PGSIZE;
if (ph_addr.memsz % PGSIZE > 0)
// actual loading npage++;
if (elf_fpread(ctx, dest, ph_addr.memsz, ph_addr.off) != ph_addr.memsz) int page;
return EL_EIO; uint64 vaddr = ph_addr.vaddr;
uint64 ph_addr_off = ph_addr.off;
for(page=0; page<npage; page++) {
uint64 load_size = (page!=npage-1)?PGSIZE:(ph_addr.memsz % PGSIZE);
void* dest = elf_alloc_mb(ctx, vaddr, vaddr,load_size);
vaddr += PGSIZE;
// actual loading
if (elf_fpread(ctx, dest, load_size, ph_addr.off + page * PGSIZE) != load_size)
return EL_EIO;
}
// record the vm region in proc->mapped_info. added @lab3_1 // record the vm region in proc->mapped_info. added @lab3_1
int j; int j;
@ -89,7 +98,7 @@ elf_status elf_load(elf_ctx *ctx) {
if( (process*)(((elf_info*)(ctx->info))->p)->mapped_info[j].va == 0x0 ) break; if( (process*)(((elf_info*)(ctx->info))->p)->mapped_info[j].va == 0x0 ) break;
((process*)(((elf_info*)(ctx->info))->p))->mapped_info[j].va = ph_addr.vaddr; ((process*)(((elf_info*)(ctx->info))->p))->mapped_info[j].va = ph_addr.vaddr;
((process*)(((elf_info*)(ctx->info))->p))->mapped_info[j].npages = 1; ((process*)(((elf_info*)(ctx->info))->p))->mapped_info[j].npages = npage;
// SEGMENT_READABLE, SEGMENT_EXECUTABLE, SEGMENT_WRITABLE are defined in kernel/elf.h // SEGMENT_READABLE, SEGMENT_EXECUTABLE, SEGMENT_WRITABLE are defined in kernel/elf.h
if( ph_addr.flags == (SEGMENT_READABLE|SEGMENT_EXECUTABLE) ){ if( ph_addr.flags == (SEGMENT_READABLE|SEGMENT_EXECUTABLE) ){
@ -98,6 +107,11 @@ elf_status elf_load(elf_ctx *ctx) {
}else if ( ph_addr.flags == (SEGMENT_READABLE|SEGMENT_WRITABLE) ){ }else if ( ph_addr.flags == (SEGMENT_READABLE|SEGMENT_WRITABLE) ){
((process*)(((elf_info*)(ctx->info))->p))->mapped_info[j].seg_type = DATA_SEGMENT; ((process*)(((elf_info*)(ctx->info))->p))->mapped_info[j].seg_type = DATA_SEGMENT;
sprint( "DATA_SEGMENT added at mapped info offset:%d\n", j ); sprint( "DATA_SEGMENT added at mapped info offset:%d\n", j );
}else if ( (ph_addr.flags & SEGMENT_WRITABLE) &&
(ph_addr.flags & SEGMENT_READABLE) &&
(ph_addr.flags & SEGMENT_EXECUTABLE) ){
((process*)(((elf_info*)(ctx->info))->p))->mapped_info[j].seg_type = WRE_SEGMENT;
sprint( "WRE_SEGMENT added at mapped info offset:%d\n", j );
}else }else
panic( "unknown program segment encountered, segment flag:%d.\n", ph_addr.flags ); panic( "unknown program segment encountered, segment flag:%d.\n", ph_addr.flags );

@ -17,6 +17,10 @@ const struct vinode_ops hostfs_i_ops = {
.viop_create = hostfs_create, .viop_create = hostfs_create,
.viop_lseek = hostfs_lseek, .viop_lseek = hostfs_lseek,
.viop_lookup = hostfs_lookup, .viop_lookup = hostfs_lookup,
.viop_ioctl = hostfs_ioctl,
.viop_mmap = hostfs_mmap,
.viop_munmap = hostfs_munmap,
.viop_read_mmap = hostfs_read_mmap,
.viop_hook_open = hostfs_hook_open, .viop_hook_open = hostfs_hook_open,
.viop_hook_close = hostfs_hook_close, .viop_hook_close = hostfs_hook_close,
@ -51,7 +55,10 @@ int register_hostfs() {
// //
// append new device under "name" to vfs_dev_list. // append new device under "name" to vfs_dev_list.
// //
struct device *init_host_device(char *name) { struct device *init_host_device(char *name, char *hostfs_root) {
if (hostfs_num >= MAX_HOSTFS_NUM)
panic("init_host_device: Too many hostfs devices!\n");
// find rfs in registered fs list // find rfs in registered fs list
struct file_system_type *fs_type = NULL; struct file_system_type *fs_type = NULL;
for (int i = 0; i < MAX_SUPPORTED_FS; i++) { for (int i = 0; i < MAX_SUPPORTED_FS; i++) {
@ -67,8 +74,12 @@ struct device *init_host_device(char *name) {
struct device *device = (struct device *)alloc_page(); struct device *device = (struct device *)alloc_page();
// set the device name and index // set the device name and index
strcpy(device->dev_name, name); strcpy(device->dev_name, name);
// we only support one host-fs device
device->dev_id = 0; // set the device id and root dir
device->dev_id = hostfs_num;
strcpy(host_root_dirs[hostfs_num], hostfs_root);
hostfs_num++;
device->fs_type = fs_type; device->fs_type = fs_type;
// add the device to the vfs device list // add the device to the vfs device list
@ -86,9 +97,12 @@ struct device *init_host_device(char *name) {
// recursive call to assemble a path. // recursive call to assemble a path.
// //
void path_backtrack(char *path, struct dentry *dentry) { void path_backtrack(char *path, struct dentry *dentry) {
if (dentry->parent == NULL) { if (dentry->sb->s_root == vfs_root_dentry
&& dentry->parent == NULL) // mount as root
return;
else if (dentry->sb->s_root != vfs_root_dentry
&& dentry->parent->parent == NULL) // mount as sub dir
return; return;
}
path_backtrack(path, dentry->parent); path_backtrack(path, dentry->parent);
strcat(path, "/"); strcat(path, "/");
strcat(path, dentry->name); strcat(path, dentry->name);
@ -98,7 +112,7 @@ void path_backtrack(char *path, struct dentry *dentry) {
// obtain the absolute path for "dentry", from root to file. // obtain the absolute path for "dentry", from root to file.
// //
void get_path_string(char *path, struct dentry *dentry) { void get_path_string(char *path, struct dentry *dentry) {
strcpy(path, H_ROOT_DIR); strcpy(path, host_root_dirs[dentry->sb->s_dev->dev_id]);
path_backtrack(path, dentry); path_backtrack(path, dentry);
} }
@ -133,7 +147,9 @@ int hostfs_update_vinode(struct vinode *vinode) {
vinode->nlinks = stat.st_nlink; vinode->nlinks = stat.st_nlink;
vinode->blocks = stat.st_blocks; vinode->blocks = stat.st_blocks;
if (S_ISDIR(stat.st_mode)) { if (S_ISCHR(stat.st_mode)) {
vinode->type = H_FILE;
} else if (S_ISDIR(stat.st_mode)) {
vinode->type = H_DIR; vinode->type = H_DIR;
} else if (S_ISREG(stat.st_mode)) { } else if (S_ISREG(stat.st_mode)) {
vinode->type = H_FILE; vinode->type = H_FILE;
@ -196,6 +212,36 @@ struct vinode *hostfs_lookup(struct vinode *parent, struct dentry *sub_dentry) {
return child_inode; return child_inode;
} }
int hostfs_ioctl(struct vinode *f_inode, uint64 request, char *data) {
spike_file_t *pf = (spike_file_t *)f_inode->i_fs_info;
if (pf < 0) {
sprint("hostfs_write: invalid file handle!\n");
return -1;
}
panic( "You need to call host's ioctl by frontend_syscall in lab5_3.\n" );
}
int64 hostfs_mmap(struct vinode *f_node, char *addr, uint64 length, int prot,
int flags, int64 offset) {
spike_file_t *pf = (spike_file_t *)f_node->i_fs_info;
if (pf < 0) {
sprint("hostfs_mmap: invalid file handle!\n");
return -1;
}
return frontend_syscall(HTIFSYS_mmap, (uint64)addr, length, prot, flags,
pf->kfd, offset, 0);
}
int hostfs_read_mmap(struct vinode *node, uint64 num, char *base_addr, char *read_addr,
uint64 length, char *buf) {
return frontend_syscall(HTIFSYS_readmmap, num, (uint64)read_addr - (uint64)base_addr, length,
(uint64)buf, 0, 0, 0);
}
int hostfs_munmap(struct vinode *node, uint64 num, uint64 length) {
return frontend_syscall(HTIFSYS_munmap, num, length, 0, 0, 0, 0, 0);
}
// //
// creates a hostfs file, and establish its vfs inode. // creates a hostfs file, and establish its vfs inode.
// //
@ -294,7 +340,12 @@ struct super_block *hostfs_get_superblock(struct device *dev) {
root_inode->type = H_DIR; root_inode->type = H_DIR;
struct dentry *root_dentry = alloc_vfs_dentry("/", root_inode, NULL); struct dentry *root_dentry = alloc_vfs_dentry("/", root_inode, NULL);
root_dentry->sb = sb;
sb->s_root = root_dentry; sb->s_root = root_dentry;
return sb; return sb;
} }
// host root directory
char host_root_dirs[MAX_HOSTFS_NUM][MAX_PATH_LEN];
int hostfs_num = 0;

@ -8,12 +8,11 @@
#define H_FILE FILE_I #define H_FILE FILE_I
#define H_DIR DIR_I #define H_DIR DIR_I
// root directory #define MAX_HOSTFS_NUM 4
#define H_ROOT_DIR "./hostfs_root"
// hostfs utility functin declarations // hostfs utility functin declarations
int register_hostfs(); int register_hostfs();
struct device *init_host_device(char *name); struct device *init_host_device(char *name, char *hostfs_root);
void get_path_string(char *path, struct dentry *dentry); void get_path_string(char *path, struct dentry *dentry);
struct vinode *hostfs_alloc_vinode(struct super_block *sb); struct vinode *hostfs_alloc_vinode(struct super_block *sb);
int hostfs_write_back_vinode(struct vinode *vinode); int hostfs_write_back_vinode(struct vinode *vinode);
@ -30,6 +29,13 @@ int hostfs_lseek(struct vinode *f_inode, ssize_t new_offset, int whence,
int *offset); int *offset);
int hostfs_link(struct vinode *parent, struct dentry *sub_dentry, struct vinode *link_node); int hostfs_link(struct vinode *parent, struct dentry *sub_dentry, struct vinode *link_node);
int hostfs_unlink(struct vinode *parent, struct dentry *sub_dentry, struct vinode *unlink_node); int hostfs_unlink(struct vinode *parent, struct dentry *sub_dentry, struct vinode *unlink_node);
int hostfs_ioctl(struct vinode *f_inode, uint64 request, char *data);
int64 hostfs_mmap(struct vinode *f_node, char *addr, uint64 length, int prot,
int flags, int64 offset);
int hostfs_read_mmap(struct vinode *node, uint64 num, char *base_addr, char *read_addr,
uint64 length, char *buf);
int hostfs_munmap(struct vinode *node, uint64 num, uint64 length);
int hostfs_hook_open(struct vinode *f_inode, struct dentry *f_dentry); int hostfs_hook_open(struct vinode *f_inode, struct dentry *f_dentry);
int hostfs_hook_close(struct vinode *f_inode, struct dentry *dentry); int hostfs_hook_close(struct vinode *f_inode, struct dentry *dentry);
int hostfs_readdir(struct vinode *dir_vinode, struct dir *dir, int *offset); int hostfs_readdir(struct vinode *dir_vinode, struct dir *dir, int *offset);
@ -37,5 +43,7 @@ struct vinode *hostfs_mkdir(struct vinode *parent, struct dentry *sub_dentry);
struct super_block *hostfs_get_superblock(struct device *dev); struct super_block *hostfs_get_superblock(struct device *dev);
extern const struct vinode_ops hostfs_node_ops; extern const struct vinode_ops hostfs_node_ops;
// root directory
extern char host_root_dirs[MAX_HOSTFS_NUM][MAX_PATH_LEN];
extern int hostfs_num;
#endif #endif

@ -17,4 +17,10 @@
// start virtual address (4MB) of our simple heap. added @lab2_2 // start virtual address (4MB) of our simple heap. added @lab2_2
#define USER_FREE_ADDRESS_START 0x00000000 + PGSIZE * 1024 #define USER_FREE_ADDRESS_START 0x00000000 + PGSIZE * 1024
// start virtual address (8MB) of our shared memory. added @lab5_3
#define USER_SHARE_MEMORY_START 0x00000000 + PGSIZE * 1024 * 2
// start virtual address (12MB) of our mmap memory. added @lab5_3
#define USER_MMAP_MEMORY_START 0x00000000 + PGSIZE * 1024 * 3
#endif #endif

@ -22,11 +22,15 @@ void fs_init(void) {
// initialize the vfs // initialize the vfs
vfs_init(); vfs_init();
// register hostfs and mount it as the root // register hostfs-file and mount it as the root
if( register_hostfs() < 0 ) panic( "fs_init: cannot register hostfs.\n" ); if( register_hostfs() < 0 ) panic( "fs_init: cannot register hostfs.\n" );
struct device *hostdev = init_host_device("HOSTDEV"); struct device *hostdev = init_host_device("HOSTDEV", "./hostfs_root");
vfs_mount("HOSTDEV", MOUNT_AS_ROOT); vfs_mount("HOSTDEV", MOUNT_AS_ROOT);
// register hostfs-dev and mount it as /dev
struct device *hostdev_dev = init_host_device("dev", "/dev");
vfs_mount("dev", MOUNT_DEFAULT);
// register and mount rfs // register and mount rfs
if( register_rfs() < 0 ) panic( "fs_init: cannot register rfs.\n" ); if( register_rfs() < 0 ) panic( "fs_init: cannot register rfs.\n" );
struct device *ramdisk0 = init_rfs_device("RAMDISK0"); struct device *ramdisk0 = init_rfs_device("RAMDISK0");
@ -153,6 +157,67 @@ int do_disk_stat(int fd, struct istat *istat) {
return vfs_disk_stat(pfile, istat); return vfs_disk_stat(pfile, istat);
} }
//
// call ioctl
//
int do_ioctl(int fd, uint64 request, char *data) {
struct file *pfile = get_opened_file(fd);
return vfs_ioctl(pfile, request, data);
}
//
// mmap file or device into memory
//
char *do_mmap(char *addr, uint64 length, int prot, int flags, int fd, int64 offset) {
struct file *pfile = get_opened_file(fd);
for (int i = 0; i < MMAP_MEM_SIZE; i++) {
if (current->mmap_mem[i].length == 0) {
int64 r = vfs_mmap(pfile, addr, length, prot, flags, offset);
if (r >= 0) {
current->mmap_mem[i].addr = current->mmap_memory_top;
current->mmap_memory_top += ROUNDUP(length, PGSIZE);
current->mmap_mem[i].length = length;
current->mmap_mem[i].num = r;
current->mmap_mem[i].fd = fd;
return (char *)current->mmap_mem[i].addr;
} else return (char *)-1;
}
}
return (char *)-1;
}
//
// read from mmaped memory
//
int do_read_mmap(char *addr, int length, char *buf) {
for (int i = 0; i < MMAP_MEM_SIZE; i++) {
if ((uint64)addr >= current->mmap_mem[i].addr
&& (uint64)addr + length <=
current->mmap_mem[i].addr + current->mmap_mem[i].length) {
struct file *pfile = get_opened_file(current->mmap_mem[i].fd);
return vfs_read_mmap(pfile, current->mmap_mem[i].num, (char *)current->mmap_mem[i].addr,
addr, length, buf);
}
}
return -1;
}
//
// unmap file or device into memory
//
int do_munmap(char *addr, uint64 length) {
for (int i = 0; i < MMAP_MEM_SIZE; i++) {
if (current->mmap_mem[i].addr == (uint64)addr &&
current->mmap_mem[i].length == length) {
struct file *pfile = get_opened_file(current->mmap_mem[i].fd);
int r = vfs_munmap(pfile, current->mmap_mem[i].num, length);
if (r >= 0) current->mmap_mem[i].length = 0;
return r;
}
}
return -1;
}
// //
// close a file // close a file
// //

@ -14,6 +14,10 @@ int do_write(int fd, char *buf, uint64 count);
int do_lseek(int fd, int offset, int whence); int do_lseek(int fd, int offset, int whence);
int do_stat(int fd, struct istat *istat); int do_stat(int fd, struct istat *istat);
int do_disk_stat(int fd, struct istat *istat); int do_disk_stat(int fd, struct istat *istat);
int do_ioctl(int fd, uint64 request, char *data);
char *do_mmap(char *addr, uint64 length, int prot, int flags, int fd, int64 offset);
int do_read_mmap(char *addr, int length, char *buf);
int do_munmap(char *addr, uint64 length);
int do_close(int fd); int do_close(int fd);
int do_opendir(char *pathname); int do_opendir(char *pathname);

@ -149,7 +149,19 @@ process* alloc_process() {
procs[i].mapped_info[HEAP_SEGMENT].npages = 0; // no pages are mapped to heap yet. procs[i].mapped_info[HEAP_SEGMENT].npages = 0; // no pages are mapped to heap yet.
procs[i].mapped_info[HEAP_SEGMENT].seg_type = HEAP_SEGMENT; procs[i].mapped_info[HEAP_SEGMENT].seg_type = HEAP_SEGMENT;
procs[i].total_mapped_region = 4; // initialize the process's shared memory starting address
procs[i].share_memory_top = USER_SHARE_MEMORY_START;
// map user share memory in userspace
procs[i].mapped_info[SHARE_SEGMENT].va = USER_SHARE_MEMORY_START;
procs[i].mapped_info[SHARE_SEGMENT].npages = 0;
procs[i].mapped_info[SHARE_SEGMENT].seg_type = SHARE_SEGMENT;
procs[i].total_mapped_region = 5;
// initialize the process's mmap memory starting address
procs[i].mmap_memory_top = USER_MMAP_MEMORY_START;
memset(procs[i].mmap_mem, 0, MMAP_MEM_SIZE * sizeof(mmap_t));
// initialize files_struct // initialize files_struct
procs[i].pfiles = init_proc_file_management(); procs[i].pfiles = init_proc_file_management();
@ -244,6 +256,47 @@ int do_fork( process* parent)
child->mapped_info[child->total_mapped_region].seg_type = CODE_SEGMENT; child->mapped_info[child->total_mapped_region].seg_type = CODE_SEGMENT;
child->total_mapped_region++; child->total_mapped_region++;
break; break;
case DATA_SEGMENT:
for( int j=0; j<parent->mapped_info[i].npages; j++ ){
uint64 addr = lookup_pa(parent->pagetable, parent->mapped_info[i].va+j*PGSIZE);
char *newaddr = alloc_page(); memcpy(newaddr, (void *)addr, PGSIZE);
map_pages(child->pagetable, parent->mapped_info[i].va+j*PGSIZE, PGSIZE,
(uint64)newaddr, prot_to_type(PROT_WRITE | PROT_READ, 1));
}
// after mapping, register the vm region (do not delete codes below!)
child->mapped_info[child->total_mapped_region].va = parent->mapped_info[i].va;
child->mapped_info[child->total_mapped_region].npages =
parent->mapped_info[i].npages;
child->mapped_info[child->total_mapped_region].seg_type = DATA_SEGMENT;
child->total_mapped_region++;
break;
case WRE_SEGMENT:
for( int j=0; j<parent->mapped_info[i].npages; j++ ){
uint64 addr = lookup_pa(parent->pagetable, parent->mapped_info[i].va+j*PGSIZE);
char *newaddr = alloc_page(); memcpy(newaddr, (void *)addr, PGSIZE);
map_pages(child->pagetable, parent->mapped_info[i].va+j*PGSIZE, PGSIZE,
(uint64)newaddr, prot_to_type(PROT_WRITE | PROT_READ | PROT_EXEC, 1));
}
// after mapping, register the vm region (do not delete codes below!)
child->mapped_info[child->total_mapped_region].va = parent->mapped_info[i].va;
child->mapped_info[child->total_mapped_region].npages =
parent->mapped_info[i].npages;
child->mapped_info[child->total_mapped_region].seg_type = WRE_SEGMENT;
child->total_mapped_region++;
break;
case SHARE_SEGMENT:
for (uint64 share_block = parent->mapped_info[SHARE_SEGMENT].va;
share_block < parent->share_memory_top; share_block += PGSIZE) {
uint64 pa = lookup_pa(parent->pagetable, share_block);
map_pages(child->pagetable, share_block, PGSIZE,
pa, prot_to_type(PROT_WRITE | PROT_READ, 1));
}
child->mapped_info[SHARE_SEGMENT].npages = parent->mapped_info[i].npages;
child->share_memory_top = parent->share_memory_top;
break;
} }
} }

@ -23,6 +23,8 @@ typedef struct trapframe_t {
#define NPROC 32 #define NPROC 32
// maximum number of pages in a process's heap // maximum number of pages in a process's heap
#define MAX_HEAP_PAGES 32 #define MAX_HEAP_PAGES 32
// maximum number of memory map regions in a process
#define MMAP_MEM_SIZE 2
// possible status of a process // possible status of a process
enum proc_status { enum proc_status {
@ -39,8 +41,10 @@ enum segment_type {
CONTEXT_SEGMENT, // trapframe segment CONTEXT_SEGMENT, // trapframe segment
SYSTEM_SEGMENT, // system segment SYSTEM_SEGMENT, // system segment
HEAP_SEGMENT, // runtime heap segment HEAP_SEGMENT, // runtime heap segment
SHARE_SEGMENT, // shared segment
CODE_SEGMENT, // ELF segment CODE_SEGMENT, // ELF segment
DATA_SEGMENT, // ELF segment DATA_SEGMENT, // ELF segment
WRE_SEGMENT, // ELF segment
}; };
// the VM regions mapped to a user process // the VM regions mapped to a user process
@ -62,6 +66,11 @@ typedef struct process_heap_manager {
uint32 free_pages_count; uint32 free_pages_count;
}process_heap_manager; }process_heap_manager;
typedef struct mmap_t{
uint64 addr, length, num;
int fd;
}mmap_t;
// the extremely simple definition of process, used for begining labs of PKE // the extremely simple definition of process, used for begining labs of PKE
typedef struct process_t { typedef struct process_t {
// pointing to the stack used in trap handling. // pointing to the stack used in trap handling.
@ -98,6 +107,13 @@ typedef struct process_t {
// it will be called when process is waken up. // it will be called when process is waken up.
void (*wake_callback)(void *); void (*wake_callback)(void *);
void *wake_callback_arg; void *wake_callback_arg;
// shared memory. added @lab5_3
uint64 share_memory_top;
// mmap memory. added @lab5_3
uint64 mmap_memory_top;
mmap_t mmap_mem[MMAP_MEM_SIZE];
}process; }process;
// switch to run user app // switch to run user app

@ -28,6 +28,10 @@ const struct vinode_ops rfs_i_ops = {
.viop_link = rfs_link, .viop_link = rfs_link,
.viop_unlink = rfs_unlink, .viop_unlink = rfs_unlink,
.viop_lookup = rfs_lookup, .viop_lookup = rfs_lookup,
.viop_ioctl = rfs_ioctl,
.viop_mmap = rfs_mmap,
.viop_munmap = rfs_munmap,
.viop_read_mmap = rfs_read_mmap,
.viop_readdir = rfs_readdir, .viop_readdir = rfs_readdir,
.viop_mkdir = rfs_mkdir, .viop_mkdir = rfs_mkdir,
@ -712,6 +716,26 @@ int rfs_unlink(struct vinode *parent, struct dentry *sub_dentry, struct vinode *
return 0; return 0;
} }
int rfs_ioctl(struct vinode *node, uint64 request, char *data) {
panic("rfs_ioctl not implemented!\n");
return -1;
}
int64 rfs_mmap(struct vinode *node, char *addr, uint64 length, int prot,
int flags, int64 offset) {
panic("rfs_mmap not implemented!\n");
return -1;
}
int rfs_read_mmap(struct vinode *node, uint64 num, char *base_addr, char *read_addr,
uint64 length, char *buf) {
panic("rfs_read_mmap not implemented!\n");
}
int rfs_munmap(struct vinode *node, uint64 num, uint64 length) {
panic("rfs_munmap not implemented!\n");
}
// //
// when a directory is opened, the contents of the directory file are read // when a directory is opened, the contents of the directory file are read
// into the memory for directory read operations // into the memory for directory read operations

@ -81,6 +81,12 @@ int rfs_lseek(struct vinode *f_inode, ssize_t new_offset, int whence, int *offse
int rfs_disk_stat(struct vinode *vinode, struct istat *istat); int rfs_disk_stat(struct vinode *vinode, struct istat *istat);
int rfs_link(struct vinode *parent, struct dentry *sub_dentry, struct vinode *link_node); int rfs_link(struct vinode *parent, struct dentry *sub_dentry, struct vinode *link_node);
int rfs_unlink(struct vinode *parent, struct dentry *sub_dentry, struct vinode *unlink_vinode); int rfs_unlink(struct vinode *parent, struct dentry *sub_dentry, struct vinode *unlink_vinode);
int rfs_ioctl(struct vinode *node, uint64 request, char *data);
int64 rfs_mmap(struct vinode *node, char *addr, uint64 length, int prot,
int flags, int64 offset);
int rfs_read_mmap(struct vinode *node, uint64 num, char *base_addr, char *read_addr,
uint64 length, char *buf);
int rfs_munmap(struct vinode *node, uint64 num, uint64 length);
int rfs_hook_opendir(struct vinode *dir_vinode, struct dentry *dentry); int rfs_hook_opendir(struct vinode *dir_vinode, struct dentry *dentry);
int rfs_hook_closedir(struct vinode *dir_vinode, struct dentry *dentry); int rfs_hook_closedir(struct vinode *dir_vinode, struct dentry *dentry);

@ -74,6 +74,20 @@ uint64 sys_user_free_page(uint64 va) {
return 0; return 0;
} }
//
// parent and child process share memory.
//
uint64 sys_user_allocate_share_page() {
void* pa = alloc_page();
memset((void *)pa, 0, PGSIZE);
uint64 va = current->share_memory_top;
current->share_memory_top += PGSIZE;
user_vm_map((pagetable_t)current->pagetable, va, PGSIZE, (uint64)pa,
prot_to_type(PROT_WRITE | PROT_READ, 1));
current->mapped_info[SHARE_SEGMENT].npages++;
return va;
}
// //
// kerenl entry point of naive_fork // kerenl entry point of naive_fork
// //
@ -223,7 +237,7 @@ void sys_user_uart_putchar(uint8 ch) {
*tx = ch; *tx = ch;
} }
// added @lab5_1. Sets the return value of the uart_getchar system call, which should be called // added @lab5_2. Sets the return value of the uart_getchar system call, which should be called
// when waking up the process. For ctx, there needs to be the process number that initiates // when waking up the process. For ctx, there needs to be the process number that initiates
// the system call and the data obtained from the uart device. // the system call and the data obtained from the uart device.
void update_uartvalue(void *ctx) { void update_uartvalue(void *ctx) {
@ -257,6 +271,34 @@ void sys_user_uart2_putchar(uint8 ch) {
*tx = ch; *tx = ch;
} }
ssize_t sys_user_ioctl(int fd, uint64 request, char *datava) {
char* datapa = (char*)user_va_to_pa((pagetable_t)(current->pagetable), datava);
return do_ioctl(fd, request, datapa);
}
ssize_t sys_user_mmap(char *addr, uint64 length, int prot, int flags, int fd, int64 offset) {
return (ssize_t)do_mmap(NULL, length, prot, flags, fd, offset);
}
ssize_t sys_user_munmap(char *addr, uint64 length) {
return do_munmap(addr, length);
}
ssize_t sys_user_readmmap(char *dstva, char *src, uint64 count) {
int i = 0;
while (i < count) {
uint64 addr = (uint64)dstva + i;
uint64 pa = lookup_pa((pagetable_t)current->pagetable, addr);
uint64 off = addr - ROUNDDOWN(addr, PGSIZE);
uint64 len = count - i < PGSIZE - off ? count - i : PGSIZE - off;
int r = do_read_mmap(src, len, (char *)pa + off);
if (r < 0) return -1; else {
i += len; src += len;
}
}
return count;
}
// //
// [a0]: the syscall number; [a1] ... [a7]: arguments to the syscalls. // [a0]: the syscall number; [a1] ... [a7]: arguments to the syscalls.
// returns the code of success, (e.g., 0 means success, fail for otherwise) // returns the code of success, (e.g., 0 means success, fail for otherwise)
@ -312,6 +354,16 @@ long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long a6, l
return sys_user_uart_getchar(); return sys_user_uart_getchar();
case SYS_user_uart2_putchar: case SYS_user_uart2_putchar:
sys_user_uart2_putchar(a1);return 1; sys_user_uart2_putchar(a1);return 1;
case SYS_user_ioctl:
return sys_user_ioctl(a1, a2, (char *)a3);
case SYS_user_mmap:
return sys_user_mmap((char *)a1, a2, a3, a4, a5, a6);
case SYS_user_munmap:
return sys_user_munmap((char *)a1, a2);
case SYS_user_readmmap:
return sys_user_readmmap((char *)a1, (char *)a2, a3);
case SYS_user_allocate_share_page:
return sys_user_allocate_share_page();
default: default:
panic("Unknown syscall %ld \n", a0); panic("Unknown syscall %ld \n", a0);
} }

@ -34,6 +34,13 @@
#define SYS_user_uart_putchar (SYS_user_base + 30) #define SYS_user_uart_putchar (SYS_user_base + 30)
#define SYS_user_uart_getchar (SYS_user_base + 31) #define SYS_user_uart_getchar (SYS_user_base + 31)
#define SYS_user_uart2_putchar (SYS_user_base + 32) #define SYS_user_uart2_putchar (SYS_user_base + 32)
// added @lab5_3
#define SYS_user_ioctl (SYS_user_base + 33)
#define SYS_user_mmap (SYS_user_base + 34)
#define SYS_user_munmap (SYS_user_base + 35)
#define SYS_user_readmmap (SYS_user_base + 36)
#define SYS_user_allocate_share_page (SYS_user_base + 37)
long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7); long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7);
#endif #endif

@ -9,6 +9,7 @@
#include "util/string.h" #include "util/string.h"
#include "util/types.h" #include "util/types.h"
#include "util/hash_table.h" #include "util/hash_table.h"
#include "kernel/process.h"
struct dentry *vfs_root_dentry; // system root direntry struct dentry *vfs_root_dentry; // system root direntry
struct super_block *vfs_sb_list[MAX_MOUNTS]; // system superblock list struct super_block *vfs_sb_list[MAX_MOUNTS]; // system superblock list
@ -354,6 +355,37 @@ int vfs_unlink(const char *path) {
return 0; return 0;
} }
//
// call the ioctl function.
//
int vfs_ioctl(struct file *file, uint64 request, char *data) {
return viop_ioctl(file->f_dentry->dentry_inode, request, data);
}
//
// mmap a file at vfs layer.
//
int64 vfs_mmap(struct file *file, char *addr, uint64 length, int prot,
int flags, int64 offset) {
return viop_mmap(file->f_dentry->dentry_inode, addr, length, prot, flags,
offset);
}
//
// read a mmap file at vfs layer.
//
int vfs_read_mmap(struct file *file, uint64 num, char *base_addr, char *read_addr,
uint64 length, char *buf) {
return viop_read_mmap(file->f_dentry->dentry_inode, num, base_addr, read_addr, length, buf);
}
//
// unmap a mmap file at vfs layer.
//
int vfs_munmap(struct file *file, uint64 num, uint64 length) {
return viop_munmap(file->f_dentry->dentry_inode, num, length);
}
// //
// close a file at vfs layer. // close a file at vfs layer.
// //
@ -604,6 +636,11 @@ struct dentry *alloc_vfs_dentry(const char *name, struct vinode *inode,
dentry->parent = parent; dentry->parent = parent;
dentry->d_ref = 0; dentry->d_ref = 0;
if (parent)
dentry->sb = parent->sb;
else
dentry->sb = NULL;
return dentry; return dentry;
} }

@ -30,6 +30,12 @@ int vfs_stat(struct file *file, struct istat *istat);
int vfs_disk_stat(struct file *file, struct istat *istat); int vfs_disk_stat(struct file *file, struct istat *istat);
int vfs_link(const char *oldpath, const char *newpath); int vfs_link(const char *oldpath, const char *newpath);
int vfs_unlink(const char *path); int vfs_unlink(const char *path);
int vfs_ioctl(struct file *file, uint64 request, char *data);
int64 vfs_mmap(struct file *file, char *addr, uint64 length, int prot,
int flags, int64 offset);
int vfs_read_mmap(struct file *file, uint64 num, char *base_addr, char *read_addr,
uint64 length, char *buf);
int vfs_munmap(struct file *file, uint64 num, uint64 length);
int vfs_close(struct file *file); int vfs_close(struct file *file);
// directory interfaces // directory interfaces
@ -117,6 +123,7 @@ struct super_block {
struct dentry *s_root; // root dentry of inode struct dentry *s_root; // root dentry of inode
struct device *s_dev; // device of the superblock struct device *s_dev; // device of the superblock
void *s_fs_info; // filesystem-specific info. for rfs, it points bitmap void *s_fs_info; // filesystem-specific info. for rfs, it points bitmap
const struct sb_ops *s_ops; // vfs super block operations
}; };
// abstract vfs inode // abstract vfs inode
@ -148,6 +155,14 @@ struct vinode_ops {
struct vinode *unlink_node); struct vinode *unlink_node);
struct vinode *(*viop_lookup)(struct vinode *parent, struct vinode *(*viop_lookup)(struct vinode *parent,
struct dentry *sub_dentry); struct dentry *sub_dentry);
// added @lab5_3
int (*viop_ioctl)(struct vinode *node, uint64 request, char *data);
int64 (*viop_mmap)(struct vinode *node, char *addr, uint64 length, int prot,
int flags, int64 offset);
int (*viop_read_mmap)(struct vinode *node, uint64 num, char *base_addr,
char *read_addr, uint64 length, char *buf);
int (*viop_munmap)(struct vinode *node, uint64 num, uint64 length);
// directory operations // directory operations
int (*viop_readdir)(struct vinode *dir_vinode, struct dir *dir, int *offset); int (*viop_readdir)(struct vinode *dir_vinode, struct dir *dir, int *offset);
@ -180,6 +195,10 @@ struct vinode_ops {
#define viop_link(node, name, link_node) (node->i_ops->viop_link(node, name, link_node)) #define viop_link(node, name, link_node) (node->i_ops->viop_link(node, name, link_node))
#define viop_unlink(node, name, unlink_node) (node->i_ops->viop_unlink(node, name, unlink_node)) #define viop_unlink(node, name, unlink_node) (node->i_ops->viop_unlink(node, name, unlink_node))
#define viop_lookup(parent, sub_dentry) (parent->i_ops->viop_lookup(parent, sub_dentry)) #define viop_lookup(parent, sub_dentry) (parent->i_ops->viop_lookup(parent, sub_dentry))
#define viop_ioctl(node, request, data) (node->i_ops->viop_ioctl(node, request, data))
#define viop_mmap(node, addr, length, prot, flags, offset) (node->i_ops->viop_mmap(node, addr, length, prot, flags, offset))
#define viop_read_mmap(node, num, base_addr, read_addr, length, buf) (node->i_ops->viop_read_mmap(node, num, base_addr, read_addr, length, buf))
#define viop_munmap(node, num, length) (node->i_ops->viop_munmap(node, num, length))
#define viop_readdir(dir_vinode, dir, offset) (dir_vinode->i_ops->viop_readdir(dir_vinode, dir, offset)) #define viop_readdir(dir_vinode, dir, offset) (dir_vinode->i_ops->viop_readdir(dir_vinode, dir, offset))
#define viop_mkdir(dir, sub_dentry) (dir->i_ops->viop_mkdir(dir, sub_dentry)) #define viop_mkdir(dir, sub_dentry) (dir->i_ops->viop_mkdir(dir, sub_dentry))
#define viop_write_back_vinode(node) (node->i_ops->viop_write_back_vinode(node)) #define viop_write_back_vinode(node) (node->i_ops->viop_write_back_vinode(node))

@ -85,6 +85,7 @@
#define HTIFSYS_lstat 1039 #define HTIFSYS_lstat 1039
#define HTIFSYS_time 1062 #define HTIFSYS_time 1062
#define HTIFSYS_readmmap 2001
#define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-4096) #define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-4096)
#define ERR_PTR(x) ((void*)(long)(x)) #define ERR_PTR(x) ((void*)(long)(x))
#define PTR_ERR(x) ((long)(x)) #define PTR_ERR(x) ((long)(x))

@ -1,43 +0,0 @@
/*
* Below is the given application for lab5_2.
* The goal of this app is to control the car via Bluetooth.
*/
#include "user_lib.h"
#include "util/types.h"
void delay(unsigned int time){
unsigned int a = 0xfffff ,b = time;
volatile unsigned int i,j;
for(i = 0; i < a; ++i){
for(j = 0; j < b; ++j){
;
}
}
}
int main(void) {
printu("Hello world!\n");
int i;
int pid = fork();
if(pid == 0)
{
while (1)
{
delay(3);
printu("waiting for you!\n");
}
}
else
{
while(1)
{
char temp = (char)uartgetchar();
if(temp == 'q')
break;
car_control(temp);
}
}
exit(0);
return 0;
}

@ -0,0 +1,87 @@
#pragma pack(4)
#define _SYS__TIMEVAL_H_
struct timeval {
unsigned int tv_sec;
unsigned int tv_usec;
};
#include "user_lib.h"
#include "videodev2.h"
#define DARK 64
#define RATIO 7 / 10
int main() {
char *info = allocate_share_page();
int pid = fork();
if (pid == 0) {
int f = open_u("/dev/video0", O_RDWR), r;
struct v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.width = 320;
fmt.fmt.pix.height = 180;
fmt.fmt.pix.field = V4L2_FIELD_NONE;
r = ioctl_u(f, VIDIOC_S_FMT, &fmt);
printu("Pass format: %d\n", r);
struct v4l2_requestbuffers req;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.count = 1; req.memory = V4L2_MEMORY_MMAP;
r = ioctl_u(f, VIDIOC_REQBUFS, &req);
printu("Pass request: %d\n", r);
struct v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP; buf.index = 0;
r = ioctl_u(f, VIDIOC_QUERYBUF, &buf);
printu("Pass buffer: %d\n", r);
int length = buf.length;
char *img = mmap_u(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, f, buf.m.offset);
unsigned int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
r = ioctl_u(f, VIDIOC_STREAMON, &type);
printu("Open stream: %d\n", r);
char *img_data = naive_malloc();
for (int i = 0; i < (length + 4095) / 4096 - 1; i++)
naive_malloc();
yield();
for (;;) {
if (*info == '1') {
r = ioctl_u(f, VIDIOC_QBUF, &buf);
printu("Buffer enqueue: %d\n", r);
r = ioctl_u(f, VIDIOC_DQBUF, &buf);
printu("Buffer dequeue: %d\n", r);
r = read_mmap_u(img_data, img, length);
int num = 0;
for (int i = 0; i < length; i += 2)
if (img_data[i] < DARK) num++;
printu("Dark num: %d > %d\n", num, length / 2 * RATIO);
if (num > length / 2 * RATIO) {
*info = '0'; car_control('0');
}
} else if (*info == 'q') break;
}
for (char *i = img_data; i - img_data < length; i += 4096)
naive_free(i);
r = ioctl_u(f, VIDIOC_STREAMOFF, &type);
printu("Close stream: %d\n", r);
munmap_u(img, length);
close(f);
exit(0);
} else {
yield();
while(1)
{
char temp = (char)uartgetchar();
*info = temp;
if(temp == 'q')
break;
car_control(temp);
}
}
return 0;
}

@ -13,13 +13,13 @@
uint64 do_user_call(uint64 sysnum, uint64 a1, uint64 a2, uint64 a3, uint64 a4, uint64 a5, uint64 a6, uint64 do_user_call(uint64 sysnum, uint64 a1, uint64 a2, uint64 a3, uint64 a4, uint64 a5, uint64 a6,
uint64 a7) { uint64 a7) {
int ret; uint64 ret;
// before invoking the syscall, arguments of do_user_call are already loaded into the argument // before invoking the syscall, arguments of do_user_call are already loaded into the argument
// registers (a0-a7) of our (emulated) risc-v machine. // registers (a0-a7) of our (emulated) risc-v machine.
asm volatile( asm volatile(
"ecall\n" "ecall\n"
"sw a0, %0" // returns a 32-bit value "sd a0, %0"
: "=m"(ret) : "=m"(ret)
: :
: "memory"); : "memory");
@ -81,7 +81,7 @@ void yield() {
// //
// lib call to open // lib call to open
// //
int open(const char *pathname, int flags) { int open_u(const char *pathname, int flags) {
return do_user_call(SYS_user_open, (uint64)pathname, flags, 0, 0, 0, 0, 0); return do_user_call(SYS_user_open, (uint64)pathname, flags, 0, 0, 0, 0, 0);
} }
@ -208,3 +208,23 @@ void car_control(char val) {
for(i = 0; i < strlen(cmd); i++) for(i = 0; i < strlen(cmd); i++)
uart2putchar(cmd[i]); uart2putchar(cmd[i]);
} }
char *allocate_share_page() {
return (char *)do_user_call(SYS_user_allocate_share_page, 0, 0, 0, 0, 0, 0, 0);
}
int ioctl_u(int fd, uint64 request, void *data) {
return do_user_call(SYS_user_ioctl, fd, request, (uint64)data, 0, 0, 0, 0);
}
void *mmap_u(void *addr, uint64 length, int prot, int flags, int fd, int64 offset) {
return (void *)do_user_call(SYS_user_mmap, (uint64)addr, length, prot, flags, fd, offset, 0);
}
int munmap_u(void *addr, uint64 length) {
return do_user_call(SYS_user_munmap, (uint64)addr, length, 0, 0, 0, 0, 0);
}
int read_mmap_u(char *dstva, char *src, uint64 count) {
return do_user_call(SYS_user_readmmap, (uint64)dstva, (uint64)src, count, 0, 0, 0, 0);
}

@ -7,6 +7,10 @@
#include "util/types.h" #include "util/types.h"
#include "kernel/proc_file.h" #include "kernel/proc_file.h"
#include "unistd.h"
#include "fcntl.h"
#include "util/types.h"
int printu(const char *s, ...); int printu(const char *s, ...);
int exit(int code); int exit(int code);
void* naive_malloc(); void* naive_malloc();
@ -15,7 +19,7 @@ int fork();
void yield(); void yield();
// added @ lab4_1 // added @ lab4_1
int open(const char *pathname, int flags); int open_u(const char *pathname, int flags);
int read_u(int fd, void *buf, uint64 count); int read_u(int fd, void *buf, uint64 count);
int write_u(int fd, void *buf, uint64 count); int write_u(int fd, void *buf, uint64 count);
int lseek_u(int fd, int offset, int whence); int lseek_u(int fd, int offset, int whence);
@ -39,4 +43,25 @@ int uartgetchar();
int uart2putchar(char ch); int uart2putchar(char ch);
void car_control(char val); void car_control(char val);
// added @lab5_3
#define PROT_READ 0x1 // Page can be read.
#define PROT_WRITE 0x2 // Page can be written.
#define PROT_EXEC 0x4 // Page can be executed.
#define PROT_NONE 0x0 // Page can not be accessed.
#define PROT_GROWSDOWN 0x01000000 // Extend change to start of growsdown vma (mprotect only).
#define PROT_GROWSUP 0x02000000 // Extend change to start of growsup vma (mprotect only).
/* Sharing types (must choose one and only one of these). */
#define MAP_SHARED 0x01 // Share changes.
#define MAP_PRIVATE 0x02 // Changes are private.
# define MAP_SHARED_VALIDATE 0x03 // Share changes and validate extension flags.
# define MAP_TYPE 0x0f // Mask for type of mapping.
char *allocate_share_page();
int ioctl_u(int fd, uint64 request, void *data);
void *mmap_u(void *addr, uint64 length, int prot, int flags, int fd, int64 offset);
int munmap_u(void *addr, uint64 length);
int read_mmap_u(char *dstva, char *src, uint64 count);
#endif #endif

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save