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_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_CPPS)))
USER_TARGET := $(OBJ_DIR)/app_PLIC
USER_TARGET := $(OBJ_DIR)/app_host_device
#------------------------targets------------------------
$(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.
*/
@ -9,6 +9,7 @@
#include "vmm.h"
#include "pmm.h"
#include "spike_interface/spike_utils.h"
#include "util/functions.h"
typedef struct elf_info_t {
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) {
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();
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;
// allocate memory block before elf loading
void *dest = elf_alloc_mb(ctx, ph_addr.vaddr, ph_addr.vaddr, ph_addr.memsz);
// actual loading
if (elf_fpread(ctx, dest, ph_addr.memsz, ph_addr.off) != ph_addr.memsz)
return EL_EIO;
int npage = ph_addr.memsz / PGSIZE;
if (ph_addr.memsz % PGSIZE > 0)
npage++;
int page;
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
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;
((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
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) ){
((process*)(((elf_info*)(ctx->info))->p))->mapped_info[j].seg_type = DATA_SEGMENT;
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
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_lseek = hostfs_lseek,
.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_close = hostfs_hook_close,
@ -51,7 +55,10 @@ int register_hostfs() {
//
// 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
struct file_system_type *fs_type = NULL;
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();
// set the device name and index
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;
// 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.
//
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;
}
path_backtrack(path, dentry->parent);
strcat(path, "/");
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.
//
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);
}
@ -133,7 +147,9 @@ int hostfs_update_vinode(struct vinode *vinode) {
vinode->nlinks = stat.st_nlink;
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;
} else if (S_ISREG(stat.st_mode)) {
vinode->type = H_FILE;
@ -196,6 +212,36 @@ struct vinode *hostfs_lookup(struct vinode *parent, struct dentry *sub_dentry) {
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.
//
@ -294,7 +340,12 @@ struct super_block *hostfs_get_superblock(struct device *dev) {
root_inode->type = H_DIR;
struct dentry *root_dentry = alloc_vfs_dentry("/", root_inode, NULL);
root_dentry->sb = sb;
sb->s_root = root_dentry;
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_DIR DIR_I
// root directory
#define H_ROOT_DIR "./hostfs_root"
#define MAX_HOSTFS_NUM 4
// hostfs utility functin declarations
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);
struct vinode *hostfs_alloc_vinode(struct super_block *sb);
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 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_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_close(struct vinode *f_inode, struct dentry *dentry);
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);
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

@ -17,4 +17,10 @@
// start virtual address (4MB) of our simple heap. added @lab2_2
#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

@ -22,11 +22,15 @@ void fs_init(void) {
// initialize the vfs
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" );
struct device *hostdev = init_host_device("HOSTDEV");
struct device *hostdev = init_host_device("HOSTDEV", "./hostfs_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
if( register_rfs() < 0 ) panic( "fs_init: cannot register rfs.\n" );
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);
}
//
// 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
//

@ -14,6 +14,10 @@ int do_write(int fd, char *buf, uint64 count);
int do_lseek(int fd, int offset, int whence);
int do_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_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].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
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->total_mapped_region++;
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
// maximum number of pages in a process's heap
#define MAX_HEAP_PAGES 32
// maximum number of memory map regions in a process
#define MMAP_MEM_SIZE 2
// possible status of a process
enum proc_status {
@ -39,8 +41,10 @@ enum segment_type {
CONTEXT_SEGMENT, // trapframe segment
SYSTEM_SEGMENT, // system segment
HEAP_SEGMENT, // runtime heap segment
SHARE_SEGMENT, // shared segment
CODE_SEGMENT, // ELF segment
DATA_SEGMENT, // ELF segment
WRE_SEGMENT, // ELF segment
};
// the VM regions mapped to a user process
@ -62,6 +66,11 @@ typedef struct process_heap_manager {
uint32 free_pages_count;
}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
typedef struct process_t {
// 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.
void (*wake_callback)(void *);
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;
// switch to run user app

@ -28,6 +28,10 @@ const struct vinode_ops rfs_i_ops = {
.viop_link = rfs_link,
.viop_unlink = rfs_unlink,
.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_mkdir = rfs_mkdir,
@ -712,6 +716,26 @@ int rfs_unlink(struct vinode *parent, struct dentry *sub_dentry, struct vinode *
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
// 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_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_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_closedir(struct vinode *dir_vinode, struct dentry *dentry);

@ -74,6 +74,20 @@ uint64 sys_user_free_page(uint64 va) {
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
//
@ -223,7 +237,7 @@ void sys_user_uart_putchar(uint8 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
// the system call and the data obtained from the uart device.
void update_uartvalue(void *ctx) {
@ -257,6 +271,34 @@ void sys_user_uart2_putchar(uint8 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.
// 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();
case SYS_user_uart2_putchar:
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:
panic("Unknown syscall %ld \n", a0);
}

@ -34,6 +34,13 @@
#define SYS_user_uart_putchar (SYS_user_base + 30)
#define SYS_user_uart_getchar (SYS_user_base + 31)
#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);
#endif

@ -9,6 +9,7 @@
#include "util/string.h"
#include "util/types.h"
#include "util/hash_table.h"
#include "kernel/process.h"
struct dentry *vfs_root_dentry; // system root direntry
struct super_block *vfs_sb_list[MAX_MOUNTS]; // system superblock list
@ -354,6 +355,37 @@ int vfs_unlink(const char *path) {
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.
//
@ -604,6 +636,11 @@ struct dentry *alloc_vfs_dentry(const char *name, struct vinode *inode,
dentry->parent = parent;
dentry->d_ref = 0;
if (parent)
dentry->sb = parent->sb;
else
dentry->sb = NULL;
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_link(const char *oldpath, const char *newpath);
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);
// directory interfaces
@ -117,6 +123,7 @@ struct super_block {
struct dentry *s_root; // root dentry of inode
struct device *s_dev; // device of the superblock
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
@ -148,6 +155,14 @@ struct vinode_ops {
struct vinode *unlink_node);
struct vinode *(*viop_lookup)(struct vinode *parent,
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
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_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_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_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))

@ -85,6 +85,7 @@
#define HTIFSYS_lstat 1039
#define HTIFSYS_time 1062
#define HTIFSYS_readmmap 2001
#define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-4096)
#define ERR_PTR(x) ((void*)(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 a7) {
int ret;
uint64 ret;
// before invoking the syscall, arguments of do_user_call are already loaded into the argument
// registers (a0-a7) of our (emulated) risc-v machine.
asm volatile(
"ecall\n"
"sw a0, %0" // returns a 32-bit value
"sd a0, %0"
: "=m"(ret)
:
: "memory");
@ -81,7 +81,7 @@ void yield() {
//
// 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);
}
@ -208,3 +208,23 @@ void car_control(char val) {
for(i = 0; i < strlen(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 "kernel/proc_file.h"
#include "unistd.h"
#include "fcntl.h"
#include "util/types.h"
int printu(const char *s, ...);
int exit(int code);
void* naive_malloc();
@ -15,7 +19,7 @@ int fork();
void yield();
// 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 write_u(int fd, void *buf, uint64 count);
int lseek_u(int fd, int offset, int whence);
@ -39,4 +43,25 @@ int uartgetchar();
int uart2putchar(char ch);
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

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