drivers: implement memory device driver

The first and only memory device mounted at /dev/null discards all data
written to it and always returns 0 bytes when read.
This commit is contained in:
Florian Fischer
2024-01-03 14:02:50 +01:00
parent 7b6076b612
commit 3bf6119030
4 changed files with 197 additions and 0 deletions
+1
View File
@@ -31,6 +31,7 @@ set(KERNEL_SOURCES
${CMAKE_SOURCE_DIR}/mentos/src/devices/pci.c
${CMAKE_SOURCE_DIR}/mentos/src/devices/fpu.c
${CMAKE_SOURCE_DIR}/mentos/src/drivers/ata.c
${CMAKE_SOURCE_DIR}/mentos/src/drivers/mem.c
${CMAKE_SOURCE_DIR}/mentos/src/drivers/rtc.c
${CMAKE_SOURCE_DIR}/mentos/src/drivers/fdc.c
${CMAKE_SOURCE_DIR}/mentos/src/drivers/mouse.c
+18
View File
@@ -0,0 +1,18 @@
/// @file mem.h
/// @brief Drivers for memory devices
/// @copyright (c) 2024 This file is distributed under the MIT License.
/// See LICENSE.md for details.
/// @addtogroup drivers Device Drivers
/// @{
/// @addtogroup mem Memory devices
/// @brief Drivers for memory devices.
/// @{
#pragma once
/// @brief Initializes the memory devices.
/// @return 0 on success, 1 on error.
int mem_devs_initialize(void);
/// @}
/// @}
+167
View File
@@ -0,0 +1,167 @@
/// @file mem.c
/// @brief Memory devices.
/// @copyright (c) 2024 This file is distributed under the MIT License.
/// See LICENSE.md for details.
// Include the kernel log levels.
#include "sys/kernel_levels.h"
/// Change the header.
#define __DEBUG_HEADER__ "[MEMDEV ]"
/// Set the log level.
#define __DEBUG_LEVEL__ GLOBAL_LOGLEVEL
#include "assert.h"
#include "drivers/mem.h"
#include "io/debug.h"
#include "fs/vfs.h"
#include "string.h"
#include "sys/errno.h"
#include "system/syscall.h"
struct memdev;
struct memdev {
vfs_file_t *file;
struct memdev *next;
};
static struct memdev *devices;
static void add_device(struct memdev *device) {
struct memdev *dit = devices;
for (;dit != NULL; dit = dit->next);
if (dit == NULL) {
devices = device;
} else {
dit->next = device;
}
}
static vfs_file_t* find_device_file(const char *path) {
for(struct memdev *dev = devices; dev != NULL; dev = dev->next) {
if (strcmp(dev->file->name, path) == 0) {
return dev->file;
}
}
return NULL;
}
static int mem_stat(const char* path, stat_t *stat);
static vfs_sys_operations_t mem_sys_operations = {
.mkdir_f = NULL,
.rmdir_f = NULL,
.stat_f = mem_stat,
};
static vfs_file_t *null_open(const char *path, int flags, mode_t mode);
static int null_close(vfs_file_t * file);
static ssize_t null_write(vfs_file_t * file, const void *buffer, off_t offset, size_t size);
static ssize_t null_read(vfs_file_t * file, char *buffer, off_t offset, size_t size);
static int null_fstat(vfs_file_t * file, stat_t *stat);
static vfs_file_operations_t null_fs_operations = {
.open_f = null_open,
.unlink_f = NULL,
.close_f = null_close,
.read_f = null_read,
.write_f = null_write,
.lseek_f = NULL,
.stat_f = null_fstat,
.ioctl_f = NULL,
.getdents_f = NULL
};
static struct memdev *null_device_create(const char* name) {
// Create the device.
struct memdev *dev = kmalloc(sizeof(struct memdev));
dev->next = NULL;
// Create the file.
vfs_file_t *file = kmem_cache_alloc(vfs_file_cache, GFP_KERNEL);
if (file == NULL) {
pr_err("Failed to create null device.\n");
return NULL;
}
dev->file = file;
// Set the device name.
strncpy(file->name, name, NAME_MAX);
file->count = 0;
file->uid = 0;
file->gid = 0;
file->mask = 0x2000 | 0666;
file->atime = sys_time(NULL);
file->mtime = sys_time(NULL);
file->ctime = sys_time(NULL);
file->length = 0;
// Set the operations.
file->sys_operations = &mem_sys_operations;
file->fs_operations = &null_fs_operations;
return dev;
}
static vfs_file_t* null_open(const char *path, int flags, mode_t mode) {
vfs_file_t* file = find_device_file(path);
if (file) {
file->count++;
}
// TODO: check permissions
return file;
}
static int null_close(vfs_file_t * file) {
assert(file && "Received null file.");
file->count--;
return 0;
}
static ssize_t null_write(vfs_file_t * file, const void *buffer, off_t offset, size_t size) {
return size;
}
static ssize_t null_read(vfs_file_t * file, char *buffer, off_t offset, size_t size) {
return 0;
}
static int null_fstat(vfs_file_t * file, stat_t *stat)
{
pr_debug("null_fstat(%s, %p)\n", file->name, stat);
stat->st_dev = 0;
stat->st_ino = 0;
stat->st_mode = file->mask;
stat->st_uid = file->uid;
stat->st_gid = file->gid;
stat->st_atime = file->atime;
stat->st_mtime = file->mtime;
stat->st_ctime = file->ctime;
stat->st_size = file->length;
return 0;
}
static int mem_stat(const char *path, stat_t *stat) {
vfs_file_t* file = find_device_file(path);
if (file) {
return file->fs_operations->stat_f(file, stat);
}
return -ENOENT;
}
int mem_devs_initialize(void)
{
struct memdev *devnull = null_device_create("/dev/null");
if (!devnull) {
pr_err("Failed to create devnull");
return -ENODEV;
}
if (!vfs_mount("/dev/null", devnull->file)) {
pr_err("Failed to mount /dev/null");
return 1;
}
add_device(devnull);
return 0;
}
+11
View File
@@ -18,6 +18,7 @@
#include "drivers/keyboard/keymap.h"
#include "drivers/ps2.h"
#include "drivers/rtc.h"
#include "drivers/mem.h"
#include "fs/ext2.h"
#include "fs/procfs.h"
#include "fs/vfs.h"
@@ -238,6 +239,16 @@ int kmain(boot_info_t *boot_informations)
}
print_ok();
//==========================================================================
pr_notice(" Initialize memory devices...\n");
printf(" Initialize memory devices...");
if (mem_devs_initialize()) {
print_fail();
pr_emerg("Failed to initialize memory devices!\n");
return 1;
}
print_ok();
//==========================================================================
pr_notice(" Initialize 'procfs'...\n");
printf(" Initialize 'procfs'...");