Skip to content

Commit 5956a26

Browse files
committed
New KOS-specific file /dev/void
writes are no-ops, reads return undefined data
1 parent 7a0dea3 commit 5956a26

File tree

4 files changed

+210
-11
lines changed

4 files changed

+210
-11
lines changed

kos/src/kernel/core/filesys/null.c

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
#include <sched/group.h>
4242
#include <sched/tsc.h>
4343

44+
#include <hybrid/align.h>
45+
4446
#include <sys/filio.h>
4547
#include <sys/io.h>
4648
#include <sys/param.h> /* NBBY */
@@ -350,6 +352,134 @@ PRIVATE struct mfile_stream_ops const devzero_stream_ops = {
350352

351353

352354

355+
/************************************************************************/
356+
/* General-purpose, write-discard file (/dev/void) */
357+
/* KOS-specific: writes are no-ops, reads return undefined data */
358+
/************************************************************************/
359+
360+
#ifndef CONFIG_DEVVOID_PAGE_COUNT
361+
#define CONFIG_DEVVOID_PAGE_COUNT 16
362+
#endif /* !CONFIG_DEVVOID_PAGE_COUNT */
363+
364+
PRIVATE physpage_t devvoid_page_addr = PHYSPAGE_INVALID;
365+
PRIVATE physpage_t KCALL get_devvoid_page_addr(void) {
366+
physpage_t result = atomic_read(&devvoid_page_addr);
367+
if (result == PHYSPAGE_INVALID) {
368+
physpage_t old;
369+
/* XXX: Why actually allocate memory here? Instead of doing that,
370+
* we could also just find some large range of physical memory
371+
* that doesn't map to anything...
372+
* (but then we'd run the risk of some of the CPU pins not being
373+
* connected and the seemingly unused memory range actually aliasing
374+
* some other **used** range) */
375+
result = page_malloc(CONFIG_DEVVOID_PAGE_COUNT);
376+
if unlikely(result == PHYSPAGE_INVALID)
377+
THROW(E_BADALLOC_INSUFFICIENT_PHYSICAL_MEMORY, CONFIG_DEVVOID_PAGE_COUNT * PAGESIZE);
378+
old = atomic_cmpxch_val(&devvoid_page_addr, PHYSPAGE_INVALID, result);
379+
if unlikely(old != PHYSPAGE_INVALID) {
380+
page_ccfree(result, CONFIG_DEVVOID_PAGE_COUNT);
381+
result = old;
382+
}
383+
}
384+
return result;
385+
}
386+
387+
/* Construct a new mmap-able mem-part for /dev/void */
388+
PRIVATE ATTR_RETNONNULL NONNULL((1)) REF struct mpart *KCALL
389+
devvoid_v_newpart(struct mfile *__restrict UNUSED(self),
390+
PAGEDIR_PAGEALIGNED pos_t UNUSED(minaddr),
391+
PAGEDIR_PAGEALIGNED size_t num_bytes) {
392+
REF struct mpart *result;
393+
size_t pages = num_bytes >> PAGESHIFT;
394+
result = (REF struct mpart *)kmalloc(sizeof(struct mpart), GFP_LOCKED | GFP_PREFLT);
395+
/* (re-)configure the part to point to static, physical memory. */
396+
result->mp_flags = MPART_F_MLOCK | MPART_F_MLOCK_FROZEN | MPART_F_NOFREE;
397+
result->mp_blkst_ptr = NULL; /* Disable block status (thus having the system act like all
398+
* blocks were using `MPART_BLOCK_ST_CHNG' as their status) */
399+
result->mp_meta = NULL;
400+
401+
/* Have all chunks of the mem-part map to the same portion of physical
402+
* memory, which gets used as a system-wide void scratch-memory area. */
403+
TRY {
404+
physpage_t page = get_devvoid_page_addr();
405+
size_t chunks = CEILDIV(pages, CONFIG_DEVVOID_PAGE_COUNT);
406+
assert(chunks >= 1);
407+
if (chunks == 1) {
408+
result->mp_state = MPART_ST_MEM;
409+
result->mp_mem.mc_start = page;
410+
result->mp_mem.mc_size = pages;
411+
} else {
412+
size_t i;
413+
struct mchunk *vec;
414+
vec = (struct mchunk *)kmalloc(chunks * sizeof(struct mchunk),
415+
GFP_LOCKED | GFP_PREFLT);
416+
for (i = 0; i < chunks; ++i) {
417+
vec[i].mc_start = page;
418+
vec[i].mc_size = CONFIG_DEVVOID_PAGE_COUNT;
419+
}
420+
vec[i].mc_size = pages - (i * CONFIG_DEVVOID_PAGE_COUNT);
421+
result->mp_state = MPART_ST_MEM_SC;
422+
result->mp_mem_sc.ms_v = vec;
423+
result->mp_mem_sc.ms_c = chunks;
424+
}
425+
} EXCEPT {
426+
kfree(result);
427+
RETHROW();
428+
}
429+
return result;
430+
}
431+
432+
PRIVATE WUNUSED NONNULL((1)) size_t KCALL
433+
devvoid_v_read(struct mfile *__restrict UNUSED(self), NCX void *UNUSED(dst),
434+
size_t num_bytes, iomode_t UNUSED(mode)) THROWS(...) {
435+
/* Note how we don't actually initialize "dst" ;)
436+
* That's because our file's whole point is that
437+
* anything read from it is **UNDEFINED** */
438+
return num_bytes;
439+
}
440+
441+
PRIVATE WUNUSED NONNULL((1, 2)) size_t KCALL
442+
devvoid_v_readv(struct mfile *__restrict UNUSED(self),
443+
struct iov_buffer *__restrict UNUSED(dst),
444+
size_t num_bytes, iomode_t UNUSED(mode)) THROWS(...) {
445+
return num_bytes;
446+
}
447+
448+
PRIVATE WUNUSED NONNULL((1)) size_t KCALL
449+
devvoid_v_pread(struct mfile *__restrict UNUSED(self), NCX void *UNUSED(dst),
450+
size_t num_bytes, pos_t UNUSED(addr), iomode_t UNUSED(mode)) THROWS(...) {
451+
return num_bytes;
452+
}
453+
454+
PRIVATE WUNUSED NONNULL((1, 2)) size_t KCALL
455+
devvoid_v_preadv(struct mfile *__restrict UNUSED(self), struct iov_buffer *__restrict UNUSED(dst),
456+
size_t num_bytes, pos_t UNUSED(addr), iomode_t UNUSED(mode)) THROWS(...) {
457+
return num_bytes;
458+
}
459+
460+
/* Explicit writes are simply ignored here */
461+
#define devvoid_v_write devnull_v_write
462+
#define devvoid_v_writev devnull_v_writev
463+
#define devvoid_v_pwrite devnull_v_pwrite
464+
#define devvoid_v_pwritev devnull_v_pwritev
465+
#define devvoid_v_seek devnull_v_seek
466+
PRIVATE struct mfile_stream_ops const devvoid_stream_ops = {
467+
.mso_read = &devvoid_v_read,
468+
.mso_readv = &devvoid_v_readv,
469+
.mso_write = &devvoid_v_write,
470+
.mso_writev = &devvoid_v_writev,
471+
.mso_pread = &devvoid_v_pread,
472+
.mso_preadv = &devvoid_v_preadv,
473+
.mso_pwrite = &devvoid_v_pwrite,
474+
.mso_pwritev = &devvoid_v_pwritev,
475+
.mso_seek = &devvoid_v_seek,
476+
.mso_stat = &nullfile_v_stat,
477+
.mso_ioctl = &chrdev_v_ioctl,
478+
};
479+
480+
481+
482+
353483

354484
/************************************************************************/
355485
/* General-purpose, always-full file (/dev/full) */
@@ -1191,6 +1321,7 @@ INTERN_CONST struct chrdev_ops const dev_mem_ops = DEVICE_OPS_INIT(&devmem_v
11911321
INTERN_CONST struct chrdev_ops const dev_kmem_ops = DEVICE_OPS_INIT(NULL, NULL, &devkmem_stream_ops, &devkmem_vio_ops);
11921322
INTERN_CONST struct chrdev_ops const dev_null_ops = DEVICE_OPS_INIT(NULL, &devnull_v_loadpages, &devnull_stream_ops, NULL);
11931323
INTERN_CONST struct chrdev_ops const dev_zero_ops = DEVICE_OPS_INIT(NULL, &devzero_v_loadpages, &devzero_stream_ops, NULL);
1324+
INTERN_CONST struct chrdev_ops const dev_void_ops = DEVICE_OPS_INIT(&devvoid_v_newpart, NULL, &devvoid_stream_ops, NULL);
11941325
INTERN_CONST struct chrdev_ops const dev_full_ops = DEVICE_OPS_INIT(NULL, &devfull_v_loadpages, &devfull_stream_ops, NULL);
11951326
INTERN_CONST struct chrdev_ops const dev_random_ops = DEVICE_OPS_INIT(NULL, NULL, &devrandom_stream_ops, &devrandom_vio_ops);
11961327
INTERN_CONST struct chrdev_ops const dev_urandom_ops = DEVICE_OPS_INIT(NULL, NULL, &devurandom_stream_ops, &devurandom_vio_ops);

kos/src/kernel/core/filesys/nulldefs.c

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ local DEVICE_EXTFLAGS = {
109109
"random": "NO_USER_IO_WITHOUT_VIO",
110110
"urandom": "NO_USER_IO_WITHOUT_VIO",
111111
"kmsg": "MFILE_F_NOUSRMMAP | MFILE_F_NOUSRIO", // mmap() isn't allowed, and I/O has special behavior
112+
"void": none,
112113
"tty": "MFILE_F_NOUSRMMAP | MFILE_F_NOUSRIO", // It's a TTY, so no mmap() or "normal" I/O
113114
};
114115
@@ -122,6 +123,7 @@ local DEVICE_SIZES = {
122123
"random": "0", // Has a custom stat function
123124
"urandom": "(uint64_t)-1",
124125
"kmsg": "0",
126+
"void": "0",
125127
"tty": "0", // Has a custom stat function
126128
};
127129
@@ -135,6 +137,7 @@ local DEVICES = {
135137
("random", 0666 | __S_IFCHR, makedev(1, 8)),
136138
("urandom", 0666 | __S_IFCHR, makedev(1, 9)),
137139
("kmsg", 0644 | __S_IFCHR, makedev(1, 11)),
140+
("void", 0666 | __S_IFCHR, makedev(1, 999)), // KOS-specific: writes are no-ops, reads return undefined data
138141
("tty", 0666 | __S_IFCHR, makedev(5, 0)),
139142
};
140143
local STMODE_MAP = { __S_IFCHR: "S_IFCHR", __S_IFBLK: "S_IFBLK" };
@@ -294,6 +297,7 @@ static_assert(devfs_devnode_makeino(S_IFCHR, makedev(1, 7)) == (__ino_t)_SELECT_
294297
static_assert(devfs_devnode_makeino(S_IFCHR, makedev(1, 8)) == (__ino_t)_SELECT_INO(UINT32_C(0x800047), UINT64_C(0x800047)));
295298
static_assert(devfs_devnode_makeino(S_IFCHR, makedev(1, 9)) == (__ino_t)_SELECT_INO(UINT32_C(0x80004f), UINT64_C(0x80004f)));
296299
static_assert(devfs_devnode_makeino(S_IFCHR, makedev(1, 11)) == (__ino_t)_SELECT_INO(UINT32_C(0x80005f), UINT64_C(0x80005f)));
300+
static_assert(devfs_devnode_makeino(S_IFCHR, makedev(1, 999)) == (__ino_t)_SELECT_INO(UINT32_C(0x801f3f), UINT64_C(0x801f3f)));
297301
static_assert(devfs_devnode_makeino(S_IFCHR, makedev(5, 0)) == (__ino_t)_SELECT_INO(UINT32_C(0x2800007), UINT64_C(0x2800007)));
298302
#undef __CCAST
299303
#define __CCAST
@@ -405,6 +409,18 @@ PRIVATE struct devdirent dirent_dev_kmsg = {
405409
.fd_name = "kmsg"
406410
}
407411
};
412+
PRIVATE struct devdirent dirent_dev_void = {
413+
.dd_dev = AWREF_INIT(&dev_void),
414+
.dd_dirent = {
415+
.fd_refcnt = 2, /* +1: dirent_dev_void, +1: dev_void.dv_dirent */
416+
.fd_ops = &devdirent_ops,
417+
.fd_ino = (ino_t)_SELECT_INO(UINT32_C(0x801f3f), UINT64_C(0x801f3f)),
418+
.fd_hash = FDIRENT_HASH_INIT(0x87b4eb26, 0x64696f76, 0x29eab484, 0x64696f76),
419+
.fd_namelen = 4,
420+
.fd_type = IFTODT(S_IFCHR),
421+
.fd_name = "void"
422+
}
423+
};
408424
PRIVATE struct devdirent dirent_dev_tty = {
409425
.dd_dev = AWREF_INIT(&dev_tty),
410426
.dd_dirent = {
@@ -417,8 +433,8 @@ PRIVATE struct devdirent dirent_dev_tty = {
417433
.fd_name = "tty"
418434
}
419435
};
420-
_SELECT_INO(DEFINE_INTERN_ALIAS(_devfs__fs_nodes__INIT, dev_port),
421-
DEFINE_INTERN_ALIAS(_devfs__fs_nodes__INIT, dev_port));
436+
_SELECT_INO(DEFINE_INTERN_ALIAS(_devfs__fs_nodes__INIT, dev_urandom),
437+
DEFINE_INTERN_ALIAS(_devfs__fs_nodes__INIT, dev_urandom));
422438
DEFINE_INTERN_ALIAS(_devfs_byname_tree__INIT, dev_port);
423439
INTDEF struct chrdev_ops const dev_mem_ops;
424440
INTDEF struct chrdev_ops const dev_kmem_ops;
@@ -429,6 +445,7 @@ INTDEF struct chrdev_ops const dev_full_ops;
429445
INTDEF struct chrdev_ops const dev_random_ops;
430446
INTDEF struct chrdev_ops const dev_urandom_ops;
431447
INTDEF struct chrdev_ops const dev_kmsg_ops;
448+
INTDEF struct chrdev_ops const dev_void_ops;
432449
INTDEF struct chrdev_ops const dev_tty_ops;
433450

434451
/* Device: `/dev/mem' */
@@ -598,7 +615,7 @@ PUBLIC struct device dev_port = {
598615
MFILE_F_NOATIME | MFILE_F_NOMTIME |
599616
MFILE_F_FIXEDFILESIZE |
600617
NO_USER_IO_WITHOUT_VIO |
601-
_SELECT_INO(0, 0)),
618+
_SELECT_INO(_MFILE_FN__RBRED, _MFILE_FN__RBRED)),
602619
MFILE_INIT_mf_trunclock,
603620
MFILE_INIT_mf_filesize((uint64_t)(port_t)-1),
604621
MFILE_INIT_mf_atime(0, 0),
@@ -616,7 +633,7 @@ PUBLIC struct device dev_port = {
616633
FNODE_INIT_fn_changed,
617634
.fn_supent = {
618635
.rb_lhs = _SELECT_INO(&dev_kmem.dv_devnode.dn_node, &dev_kmem.dv_devnode.dn_node),
619-
.rb_rhs = _SELECT_INO(&dev_urandom.dv_devnode.dn_node, &dev_urandom.dv_devnode.dn_node),
636+
.rb_rhs = _SELECT_INO(&dev_full.dv_devnode.dn_node, &dev_full.dv_devnode.dn_node),
620637
},
621638
FNODE_INIT_fn_allnodes,
622639
},
@@ -675,7 +692,7 @@ PUBLIC struct device dev_zero = {
675692
.dv_dirent = &dirent_dev_zero,
676693
.dv_byname_node = {
677694
.rb_par = &dev_urandom,
678-
.rb_lhs = NULL,
695+
.rb_lhs = &dev_void,
679696
.rb_rhs = NULL
680697
}
681698
};
@@ -698,7 +715,7 @@ PUBLIC struct device dev_full = {
698715
MFILE_F_FIXEDFILESIZE |
699716
MFILE_F_NOUSRMMAP | MFILE_F_NOUSRIO |
700717
_MFILE_DEVFS_BYNAME_RED |
701-
_SELECT_INO(_MFILE_FN__RBRED, _MFILE_FN__RBRED)),
718+
_SELECT_INO(0, 0)),
702719
MFILE_INIT_mf_trunclock,
703720
MFILE_INIT_mf_filesize(0),
704721
MFILE_INIT_mf_atime(0, 0),
@@ -816,8 +833,8 @@ PUBLIC struct device dev_urandom = {
816833
.fn_super = &devfs.rs_sup,
817834
FNODE_INIT_fn_changed,
818835
.fn_supent = {
819-
.rb_lhs = _SELECT_INO(&dev_full.dv_devnode.dn_node, &dev_full.dv_devnode.dn_node),
820-
.rb_rhs = _SELECT_INO(&dev_tty.dv_devnode.dn_node, &dev_tty.dv_devnode.dn_node),
836+
.rb_lhs = _SELECT_INO(&dev_port.dv_devnode.dn_node, &dev_port.dv_devnode.dn_node),
837+
.rb_rhs = _SELECT_INO(&dev_void.dv_devnode.dn_node, &dev_void.dv_devnode.dn_node),
821838
},
822839
FNODE_INIT_fn_allnodes,
823840
},
@@ -850,7 +867,7 @@ PUBLIC struct device dev_kmsg = {
850867
MFILE_F_FIXEDFILESIZE |
851868
MFILE_F_NOUSRMMAP | MFILE_F_NOUSRIO |
852869
_MFILE_DEVFS_BYNAME_RED |
853-
_SELECT_INO(_MFILE_FN__RBRED, _MFILE_FN__RBRED)),
870+
_SELECT_INO(0, 0)),
854871
MFILE_INIT_mf_trunclock,
855872
MFILE_INIT_mf_filesize(0),
856873
MFILE_INIT_mf_atime(0, 0),
@@ -883,6 +900,56 @@ PUBLIC struct device dev_kmsg = {
883900
}
884901
};
885902

903+
/* Device: `/dev/void' */
904+
PUBLIC struct device dev_void = {
905+
.dv_devnode = {
906+
.dn_node = {
907+
.fn_file = {
908+
MFILE_INIT_mf_refcnt(1), /* +1: dev_void */
909+
MFILE_INIT_mf_ops(&dev_void_ops.cdo_dev.do_node.dvno_node.no_file),
910+
MFILE_INIT_mf_lock,
911+
MFILE_INIT_mf_parts(MFILE_PARTS_ANONYMOUS),
912+
MFILE_INIT_mf_initdone,
913+
MFILE_INIT_mf_changed(MFILE_PARTS_ANONYMOUS),
914+
MFILE_INIT_mf_blockshift(PAGESHIFT, PAGESHIFT),
915+
MFILE_INIT_mf_meta,
916+
MFILE_INIT_mf_flags(MFILE_F_ATTRCHANGED | MFILE_F_CHANGED |
917+
MFILE_F_NOATIME | MFILE_F_NOMTIME |
918+
MFILE_F_FIXEDFILESIZE |
919+
_MFILE_DEVFS_BYNAME_RED |
920+
_SELECT_INO(0, 0)),
921+
MFILE_INIT_mf_trunclock,
922+
MFILE_INIT_mf_filesize(0),
923+
MFILE_INIT_mf_atime(0, 0),
924+
MFILE_INIT_mf_mtime(0, 0),
925+
MFILE_INIT_mf_ctime(0, 0),
926+
MFILE_INIT_mf_btime(0, 0),
927+
MFILE_INIT_mf_msalign(NULL)
928+
},
929+
.fn_nlink = 1,
930+
.fn_mode = 0666 | S_IFCHR,
931+
.fn_uid = 0,
932+
.fn_gid = 0,
933+
.fn_ino = (ino_t)_SELECT_INO(UINT32_C(0x801f3f), UINT64_C(0x801f3f)),
934+
.fn_super = &devfs.rs_sup,
935+
FNODE_INIT_fn_changed,
936+
.fn_supent = {
937+
.rb_lhs = _SELECT_INO(&dev_kmsg.dv_devnode.dn_node, &dev_kmsg.dv_devnode.dn_node),
938+
.rb_rhs = _SELECT_INO(&dev_tty.dv_devnode.dn_node, &dev_tty.dv_devnode.dn_node),
939+
},
940+
FNODE_INIT_fn_allnodes,
941+
},
942+
.dn_devno = makedev(1, 999)
943+
},
944+
.dv_driver = &drv_self,
945+
.dv_dirent = &dirent_dev_void,
946+
.dv_byname_node = {
947+
.rb_par = &dev_zero,
948+
.rb_lhs = NULL,
949+
.rb_rhs = NULL
950+
}
951+
};
952+
886953
/* Device: `/dev/tty' */
887954
PUBLIC struct device dev_tty = {
888955
.dv_devnode = {
@@ -918,7 +985,7 @@ PUBLIC struct device dev_tty = {
918985
.fn_super = &devfs.rs_sup,
919986
FNODE_INIT_fn_changed,
920987
.fn_supent = {
921-
.rb_lhs = _SELECT_INO(&dev_kmsg.dv_devnode.dn_node, &dev_kmsg.dv_devnode.dn_node),
988+
.rb_lhs = _SELECT_INO(NULL, NULL),
922989
.rb_rhs = _SELECT_INO(NULL, NULL),
923990
},
924991
FNODE_INIT_fn_allnodes,

kos/src/kernel/include/kernel/fs/null.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ DATDEF struct device dev_full; /* /dev/full */
3939
DATDEF struct device dev_random; /* /dev/random */
4040
DATDEF struct device dev_urandom; /* /dev/urandom */
4141
DATDEF struct device dev_kmsg; /* /dev/kmsg */
42+
DATDEF struct device dev_void; /* /dev/void (KOS-specific: writes are no-ops, reads return undefined data) */
4243
DATDEF struct device dev_tty; /* /dev/tty */
4344

4445
DECL_END

kos/src/kernel/include/kernel/memory.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ NOTHROW(FCALL page_getzone)(physpage_t ptr) {
203203

204204
/* Allocate `num_pages' continuous pages of physical memory and return their page number.
205205
* WARNING: Physical memory cannot be dereferenced prior to being mapped.
206-
* @return: * : The starting page number of the newly allocated memory range.
206+
* @return: * : The starting page number of the newly allocated memory range.
207207
* @return: PHYSPAGE_INVALID: The allocation failed. */
208208
FUNDEF WUNUSED physpage_t NOTHROW(FCALL page_mallocone)(void);
209209
FUNDEF NOBLOCK WUNUSED physpage_t NOTHROW(FCALL page_mallocone_nocc)(void);

0 commit comments

Comments
 (0)