update name of code to labcodes
This commit is contained in:
167
labcodes/lab8/kern/fs/devs/dev.c
Normal file
167
labcodes/lab8/kern/fs/devs/dev.c
Normal file
@@ -0,0 +1,167 @@
|
||||
#include <defs.h>
|
||||
#include <string.h>
|
||||
#include <stat.h>
|
||||
#include <dev.h>
|
||||
#include <inode.h>
|
||||
#include <unistd.h>
|
||||
#include <error.h>
|
||||
|
||||
/*
|
||||
* dev_open - Called for each open().
|
||||
*/
|
||||
static int
|
||||
dev_open(struct inode *node, uint32_t open_flags) {
|
||||
if (open_flags & (O_CREAT | O_TRUNC | O_EXCL | O_APPEND)) {
|
||||
return -E_INVAL;
|
||||
}
|
||||
struct device *dev = vop_info(node, device);
|
||||
return dop_open(dev, open_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* dev_close - Called on the last close(). Just pass through.
|
||||
*/
|
||||
static int
|
||||
dev_close(struct inode *node) {
|
||||
struct device *dev = vop_info(node, device);
|
||||
return dop_close(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* dev_read -Called for read. Hand off to iobuf.
|
||||
*/
|
||||
static int
|
||||
dev_read(struct inode *node, struct iobuf *iob) {
|
||||
struct device *dev = vop_info(node, device);
|
||||
return dop_io(dev, iob, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* dev_write -Called for write. Hand off to iobuf.
|
||||
*/
|
||||
static int
|
||||
dev_write(struct inode *node, struct iobuf *iob) {
|
||||
struct device *dev = vop_info(node, device);
|
||||
return dop_io(dev, iob, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* dev_ioctl - Called for ioctl(). Just pass through.
|
||||
*/
|
||||
static int
|
||||
dev_ioctl(struct inode *node, int op, void *data) {
|
||||
struct device *dev = vop_info(node, device);
|
||||
return dop_ioctl(dev, op, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* dev_fstat - Called for stat().
|
||||
* Set the type and the size (block devices only).
|
||||
* The link count for a device is always 1.
|
||||
*/
|
||||
static int
|
||||
dev_fstat(struct inode *node, struct stat *stat) {
|
||||
int ret;
|
||||
memset(stat, 0, sizeof(struct stat));
|
||||
if ((ret = vop_gettype(node, &(stat->st_mode))) != 0) {
|
||||
return ret;
|
||||
}
|
||||
struct device *dev = vop_info(node, device);
|
||||
stat->st_nlinks = 1;
|
||||
stat->st_blocks = dev->d_blocks;
|
||||
stat->st_size = stat->st_blocks * dev->d_blocksize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* dev_gettype - Return the type. A device is a "block device" if it has a known
|
||||
* length. A device that generates data in a stream is a "character
|
||||
* device".
|
||||
*/
|
||||
static int
|
||||
dev_gettype(struct inode *node, uint32_t *type_store) {
|
||||
struct device *dev = vop_info(node, device);
|
||||
*type_store = (dev->d_blocks > 0) ? S_IFBLK : S_IFCHR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* dev_tryseek - Attempt a seek.
|
||||
* For block devices, require block alignment.
|
||||
* For character devices, prohibit seeking entirely.
|
||||
*/
|
||||
static int
|
||||
dev_tryseek(struct inode *node, off_t pos) {
|
||||
struct device *dev = vop_info(node, device);
|
||||
if (dev->d_blocks > 0) {
|
||||
if ((pos % dev->d_blocksize) == 0) {
|
||||
if (pos >= 0 && pos < dev->d_blocks * dev->d_blocksize) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -E_INVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* dev_lookup - Name lookup.
|
||||
*
|
||||
* One interesting feature of device:name pathname syntax is that you
|
||||
* can implement pathnames on arbitrary devices. For instance, if you
|
||||
* had a graphics device that supported multiple resolutions (which we
|
||||
* don't), you might arrange things so that you could open it with
|
||||
* pathnames like "video:800x600/24bpp" in order to select the operating
|
||||
* mode.
|
||||
*
|
||||
* However, we have no support for this in the base system.
|
||||
*/
|
||||
static int
|
||||
dev_lookup(struct inode *node, char *path, struct inode **node_store) {
|
||||
if (*path != '\0') {
|
||||
return -E_NOENT;
|
||||
}
|
||||
vop_ref_inc(node);
|
||||
*node_store = node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function table for device inodes.
|
||||
*/
|
||||
static const struct inode_ops dev_node_ops = {
|
||||
.vop_magic = VOP_MAGIC,
|
||||
.vop_open = dev_open,
|
||||
.vop_close = dev_close,
|
||||
.vop_read = dev_read,
|
||||
.vop_write = dev_write,
|
||||
.vop_fstat = dev_fstat,
|
||||
.vop_ioctl = dev_ioctl,
|
||||
.vop_gettype = dev_gettype,
|
||||
.vop_tryseek = dev_tryseek,
|
||||
.vop_lookup = dev_lookup,
|
||||
};
|
||||
|
||||
#define init_device(x) \
|
||||
do { \
|
||||
extern void dev_init_##x(void); \
|
||||
dev_init_##x(); \
|
||||
} while (0)
|
||||
|
||||
/* dev_init - Initialization functions for builtin vfs-level devices. */
|
||||
void
|
||||
dev_init(void) {
|
||||
// init_device(null);
|
||||
init_device(stdin);
|
||||
init_device(stdout);
|
||||
init_device(disk0);
|
||||
}
|
||||
/* dev_create_inode - Create inode for a vfs-level device. */
|
||||
struct inode *
|
||||
dev_create_inode(void) {
|
||||
struct inode *node;
|
||||
if ((node = alloc_inode(device)) != NULL) {
|
||||
vop_init(node, &dev_node_ops, NULL);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
31
labcodes/lab8/kern/fs/devs/dev.h
Normal file
31
labcodes/lab8/kern/fs/devs/dev.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef __KERN_FS_DEVS_DEV_H__
|
||||
#define __KERN_FS_DEVS_DEV_H__
|
||||
|
||||
#include <defs.h>
|
||||
|
||||
struct inode;
|
||||
struct iobuf;
|
||||
|
||||
/*
|
||||
* Filesystem-namespace-accessible device.
|
||||
* d_io is for both reads and writes; the iobuf will indicates the direction.
|
||||
*/
|
||||
struct device {
|
||||
size_t d_blocks;
|
||||
size_t d_blocksize;
|
||||
int (*d_open)(struct device *dev, uint32_t open_flags);
|
||||
int (*d_close)(struct device *dev);
|
||||
int (*d_io)(struct device *dev, struct iobuf *iob, bool write);
|
||||
int (*d_ioctl)(struct device *dev, int op, void *data);
|
||||
};
|
||||
|
||||
#define dop_open(dev, open_flags) ((dev)->d_open(dev, open_flags))
|
||||
#define dop_close(dev) ((dev)->d_close(dev))
|
||||
#define dop_io(dev, iob, write) ((dev)->d_io(dev, iob, write))
|
||||
#define dop_ioctl(dev, op, data) ((dev)->d_ioctl(dev, op, data))
|
||||
|
||||
void dev_init(void);
|
||||
struct inode *dev_create_inode(void);
|
||||
|
||||
#endif /* !__KERN_FS_DEVS_DEV_H__ */
|
||||
|
||||
144
labcodes/lab8/kern/fs/devs/dev_disk0.c
Normal file
144
labcodes/lab8/kern/fs/devs/dev_disk0.c
Normal file
@@ -0,0 +1,144 @@
|
||||
#include <defs.h>
|
||||
#include <mmu.h>
|
||||
#include <sem.h>
|
||||
#include <ide.h>
|
||||
#include <inode.h>
|
||||
#include <kmalloc.h>
|
||||
#include <dev.h>
|
||||
#include <vfs.h>
|
||||
#include <iobuf.h>
|
||||
#include <error.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define DISK0_BLKSIZE PGSIZE
|
||||
#define DISK0_BUFSIZE (4 * DISK0_BLKSIZE)
|
||||
#define DISK0_BLK_NSECT (DISK0_BLKSIZE / SECTSIZE)
|
||||
|
||||
static char *disk0_buffer;
|
||||
static semaphore_t disk0_sem;
|
||||
|
||||
static void
|
||||
lock_disk0(void) {
|
||||
down(&(disk0_sem));
|
||||
}
|
||||
|
||||
static void
|
||||
unlock_disk0(void) {
|
||||
up(&(disk0_sem));
|
||||
}
|
||||
|
||||
static int
|
||||
disk0_open(struct device *dev, uint32_t open_flags) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
disk0_close(struct device *dev) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
disk0_read_blks_nolock(uint32_t blkno, uint32_t nblks) {
|
||||
int ret;
|
||||
uint32_t sectno = blkno * DISK0_BLK_NSECT, nsecs = nblks * DISK0_BLK_NSECT;
|
||||
if ((ret = ide_read_secs(DISK0_DEV_NO, sectno, disk0_buffer, nsecs)) != 0) {
|
||||
panic("disk0: read blkno = %d (sectno = %d), nblks = %d (nsecs = %d): 0x%08x.\n",
|
||||
blkno, sectno, nblks, nsecs, ret);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
disk0_write_blks_nolock(uint32_t blkno, uint32_t nblks) {
|
||||
int ret;
|
||||
uint32_t sectno = blkno * DISK0_BLK_NSECT, nsecs = nblks * DISK0_BLK_NSECT;
|
||||
if ((ret = ide_write_secs(DISK0_DEV_NO, sectno, disk0_buffer, nsecs)) != 0) {
|
||||
panic("disk0: write blkno = %d (sectno = %d), nblks = %d (nsecs = %d): 0x%08x.\n",
|
||||
blkno, sectno, nblks, nsecs, ret);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
disk0_io(struct device *dev, struct iobuf *iob, bool write) {
|
||||
off_t offset = iob->io_offset;
|
||||
size_t resid = iob->io_resid;
|
||||
uint32_t blkno = offset / DISK0_BLKSIZE;
|
||||
uint32_t nblks = resid / DISK0_BLKSIZE;
|
||||
|
||||
/* don't allow I/O that isn't block-aligned */
|
||||
if ((offset % DISK0_BLKSIZE) != 0 || (resid % DISK0_BLKSIZE) != 0) {
|
||||
return -E_INVAL;
|
||||
}
|
||||
|
||||
/* don't allow I/O past the end of disk0 */
|
||||
if (blkno + nblks > dev->d_blocks) {
|
||||
return -E_INVAL;
|
||||
}
|
||||
|
||||
/* read/write nothing ? */
|
||||
if (nblks == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock_disk0();
|
||||
while (resid != 0) {
|
||||
size_t copied, alen = DISK0_BUFSIZE;
|
||||
if (write) {
|
||||
iobuf_move(iob, disk0_buffer, alen, 0, &copied);
|
||||
assert(copied != 0 && copied <= resid && copied % DISK0_BLKSIZE == 0);
|
||||
nblks = copied / DISK0_BLKSIZE;
|
||||
disk0_write_blks_nolock(blkno, nblks);
|
||||
}
|
||||
else {
|
||||
if (alen > resid) {
|
||||
alen = resid;
|
||||
}
|
||||
nblks = alen / DISK0_BLKSIZE;
|
||||
disk0_read_blks_nolock(blkno, nblks);
|
||||
iobuf_move(iob, disk0_buffer, alen, 1, &copied);
|
||||
assert(copied == alen && copied % DISK0_BLKSIZE == 0);
|
||||
}
|
||||
resid -= copied, blkno += nblks;
|
||||
}
|
||||
unlock_disk0();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
disk0_ioctl(struct device *dev, int op, void *data) {
|
||||
return -E_UNIMP;
|
||||
}
|
||||
|
||||
static void
|
||||
disk0_device_init(struct device *dev) {
|
||||
static_assert(DISK0_BLKSIZE % SECTSIZE == 0);
|
||||
if (!ide_device_valid(DISK0_DEV_NO)) {
|
||||
panic("disk0 device isn't available.\n");
|
||||
}
|
||||
dev->d_blocks = ide_device_size(DISK0_DEV_NO) / DISK0_BLK_NSECT;
|
||||
dev->d_blocksize = DISK0_BLKSIZE;
|
||||
dev->d_open = disk0_open;
|
||||
dev->d_close = disk0_close;
|
||||
dev->d_io = disk0_io;
|
||||
dev->d_ioctl = disk0_ioctl;
|
||||
sem_init(&(disk0_sem), 1);
|
||||
|
||||
static_assert(DISK0_BUFSIZE % DISK0_BLKSIZE == 0);
|
||||
if ((disk0_buffer = kmalloc(DISK0_BUFSIZE)) == NULL) {
|
||||
panic("disk0 alloc buffer failed.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dev_init_disk0(void) {
|
||||
struct inode *node;
|
||||
if ((node = dev_create_inode()) == NULL) {
|
||||
panic("disk0: dev_create_node.\n");
|
||||
}
|
||||
disk0_device_init(vop_info(node, device));
|
||||
|
||||
int ret;
|
||||
if ((ret = vfs_add_dev("disk0", node, 1)) != 0) {
|
||||
panic("disk0: vfs_add_dev: %e.\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
126
labcodes/lab8/kern/fs/devs/dev_stdin.c
Normal file
126
labcodes/lab8/kern/fs/devs/dev_stdin.c
Normal file
@@ -0,0 +1,126 @@
|
||||
#include <defs.h>
|
||||
#include <stdio.h>
|
||||
#include <wait.h>
|
||||
#include <sync.h>
|
||||
#include <proc.h>
|
||||
#include <sched.h>
|
||||
#include <dev.h>
|
||||
#include <vfs.h>
|
||||
#include <iobuf.h>
|
||||
#include <inode.h>
|
||||
#include <unistd.h>
|
||||
#include <error.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define STDIN_BUFSIZE 4096
|
||||
|
||||
static char stdin_buffer[STDIN_BUFSIZE];
|
||||
static off_t p_rpos, p_wpos;
|
||||
static wait_queue_t __wait_queue, *wait_queue = &__wait_queue;
|
||||
|
||||
void
|
||||
dev_stdin_write(char c) {
|
||||
bool intr_flag;
|
||||
if (c != '\0') {
|
||||
local_intr_save(intr_flag);
|
||||
{
|
||||
stdin_buffer[p_wpos % STDIN_BUFSIZE] = c;
|
||||
if (p_wpos - p_rpos < STDIN_BUFSIZE) {
|
||||
p_wpos ++;
|
||||
}
|
||||
if (!wait_queue_empty(wait_queue)) {
|
||||
wakeup_queue(wait_queue, WT_KBD, 1);
|
||||
}
|
||||
}
|
||||
local_intr_restore(intr_flag);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
dev_stdin_read(char *buf, size_t len) {
|
||||
int ret = 0;
|
||||
bool intr_flag;
|
||||
local_intr_save(intr_flag);
|
||||
{
|
||||
for (; ret < len; ret ++, p_rpos ++) {
|
||||
try_again:
|
||||
if (p_rpos < p_wpos) {
|
||||
*buf ++ = stdin_buffer[p_rpos % STDIN_BUFSIZE];
|
||||
}
|
||||
else {
|
||||
wait_t __wait, *wait = &__wait;
|
||||
wait_current_set(wait_queue, wait, WT_KBD);
|
||||
local_intr_restore(intr_flag);
|
||||
|
||||
schedule();
|
||||
|
||||
local_intr_save(intr_flag);
|
||||
wait_current_del(wait_queue, wait);
|
||||
if (wait->wakeup_flags == WT_KBD) {
|
||||
goto try_again;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
local_intr_restore(intr_flag);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
stdin_open(struct device *dev, uint32_t open_flags) {
|
||||
if (open_flags != O_RDONLY) {
|
||||
return -E_INVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
stdin_close(struct device *dev) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
stdin_io(struct device *dev, struct iobuf *iob, bool write) {
|
||||
if (!write) {
|
||||
int ret;
|
||||
if ((ret = dev_stdin_read(iob->io_base, iob->io_resid)) > 0) {
|
||||
iob->io_resid -= ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return -E_INVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
stdin_ioctl(struct device *dev, int op, void *data) {
|
||||
return -E_INVAL;
|
||||
}
|
||||
|
||||
static void
|
||||
stdin_device_init(struct device *dev) {
|
||||
dev->d_blocks = 0;
|
||||
dev->d_blocksize = 1;
|
||||
dev->d_open = stdin_open;
|
||||
dev->d_close = stdin_close;
|
||||
dev->d_io = stdin_io;
|
||||
dev->d_ioctl = stdin_ioctl;
|
||||
|
||||
p_rpos = p_wpos = 0;
|
||||
wait_queue_init(wait_queue);
|
||||
}
|
||||
|
||||
void
|
||||
dev_init_stdin(void) {
|
||||
struct inode *node;
|
||||
if ((node = dev_create_inode()) == NULL) {
|
||||
panic("stdin: dev_create_node.\n");
|
||||
}
|
||||
stdin_device_init(vop_info(node, device));
|
||||
|
||||
int ret;
|
||||
if ((ret = vfs_add_dev("stdin", node, 0)) != 0) {
|
||||
panic("stdin: vfs_add_dev: %e.\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
64
labcodes/lab8/kern/fs/devs/dev_stdout.c
Normal file
64
labcodes/lab8/kern/fs/devs/dev_stdout.c
Normal file
@@ -0,0 +1,64 @@
|
||||
#include <defs.h>
|
||||
#include <stdio.h>
|
||||
#include <dev.h>
|
||||
#include <vfs.h>
|
||||
#include <iobuf.h>
|
||||
#include <inode.h>
|
||||
#include <unistd.h>
|
||||
#include <error.h>
|
||||
#include <assert.h>
|
||||
|
||||
static int
|
||||
stdout_open(struct device *dev, uint32_t open_flags) {
|
||||
if (open_flags != O_WRONLY) {
|
||||
return -E_INVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
stdout_close(struct device *dev) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
stdout_io(struct device *dev, struct iobuf *iob, bool write) {
|
||||
if (write) {
|
||||
char *data = iob->io_base;
|
||||
for (; iob->io_resid != 0; iob->io_resid --) {
|
||||
cputchar(*data ++);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -E_INVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
stdout_ioctl(struct device *dev, int op, void *data) {
|
||||
return -E_INVAL;
|
||||
}
|
||||
|
||||
static void
|
||||
stdout_device_init(struct device *dev) {
|
||||
dev->d_blocks = 0;
|
||||
dev->d_blocksize = 1;
|
||||
dev->d_open = stdout_open;
|
||||
dev->d_close = stdout_close;
|
||||
dev->d_io = stdout_io;
|
||||
dev->d_ioctl = stdout_ioctl;
|
||||
}
|
||||
|
||||
void
|
||||
dev_init_stdout(void) {
|
||||
struct inode *node;
|
||||
if ((node = dev_create_inode()) == NULL) {
|
||||
panic("stdout: dev_create_node.\n");
|
||||
}
|
||||
stdout_device_init(vop_info(node, device));
|
||||
|
||||
int ret;
|
||||
if ((ret = vfs_add_dev("stdout", node, 0)) != 0) {
|
||||
panic("stdout: vfs_add_dev: %e.\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user