Files
2026-10-25 18:45:38 +01:00

103 lines
3.1 KiB
C

// SPDX-License-Identifier: ISC
#include <zinnia/assert.h>
#include <zinnia/chardev.h>
#include <zinnia/random.h>
#include <zinnia/utils.h>
constexpr size_t MEMFILE_CHUNK = 64;
static const uint8_t zero_chunk[MEMFILE_CHUNK];
static errno_t memfile_discard(struct vfs_file* file, iovec_iter_t* buffer, uint64_t offset, ssize_t* out_written) {
*out_written = iovec_iter_len(buffer);
return 0;
}
static errno_t memfile_read_zero(struct vfs_file* file, iovec_iter_t* buffer, uint64_t offset, ssize_t* out_read) {
size_t total = 0;
errno_t status = 0;
while (iovec_iter_len(buffer)) {
size_t copied;
status = iovec_iter_copy_to(buffer, zero_chunk, MIN(iovec_iter_len(buffer), MEMFILE_CHUNK), &copied);
total += copied;
if (status)
break;
}
*out_read = total;
return status;
}
static errno_t null_read(struct vfs_file* file, iovec_iter_t* buffer, uint64_t offset, ssize_t* out_read) {
*out_read = 0;
return 0;
}
static const struct vfs_file_ops null_file_ops = {
.read = null_read,
.write = memfile_discard,
};
static const struct vfs_file_ops zero_file_ops = {
.read = memfile_read_zero,
.write = memfile_discard,
};
static errno_t full_write(struct vfs_file* file, iovec_iter_t* buffer, uint64_t offset, ssize_t* out_written) {
*out_written = 0;
return ENOSPC;
}
static const struct vfs_file_ops full_file_ops = {
.read = memfile_read_zero,
.write = full_write,
};
static errno_t random_read(struct vfs_file* file, iovec_iter_t* buffer, uint64_t offset, ssize_t* out_read) {
uint8_t chunk[MEMFILE_CHUNK];
size_t total = 0;
errno_t status = 0;
while (iovec_iter_len(buffer)) {
const size_t len = MIN(iovec_iter_len(buffer), sizeof(chunk));
// TODO: This function sucks and is probably not useful for cryptography.
random_fill(chunk, len);
size_t copied;
status = iovec_iter_copy_to(buffer, chunk, len, &copied);
total += copied;
if (status)
break;
}
*out_read = total;
return status;
}
static const struct vfs_file_ops random_file_ops = {
.read = random_read,
.write = memfile_discard,
};
static struct chardev null_dev;
static struct chardev zero_dev;
static struct chardev full_dev;
static struct chardev random_dev;
static struct chardev urandom_dev;
static void memfiles_add(const char* name, struct chardev* dev, const struct vfs_file_ops* ops, uint32_t minor) {
chardev_init(dev, nullptr, ops, 1, minor);
errno_t status = devtmpfs_add_chardev(name, dev, 0666);
assert(status == 0, "Unable to create /dev/%s (%i)", name, status);
}
static void memfiles_stage_init(struct boot_info* info) {
memfiles_add("null", &null_dev, &null_file_ops, 3);
memfiles_add("zero", &zero_dev, &zero_file_ops, 5);
memfiles_add("full", &full_dev, &full_file_ops, 7);
memfiles_add("random", &random_dev, &random_file_ops, 8);
memfiles_add("urandom", &urandom_dev, &random_file_ops, 9);
}
INIT_TASK(memfiles_stage, "dev.memfiles", memfiles_stage_init);
INIT_DEPENDS(memfiles_stage, devtmpfs_stage, random_stage);