diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-03-26 22:18:47 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-03-26 22:18:47 -0600 |
commit | 6ab74d74ee6dc1663b66d0a9a0471f63ade5659a (patch) | |
tree | b579303cc5df38191ee9e8ad63793fbe4c867c02 | |
parent | 9f2e2e96321f14da97adda618a7e4721cbb9791c (diff) | |
parent | 865bb702f828784a0225b5eae9ed8803094140d5 (diff) |
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | HACKING.md | 2 | ||||
-rw-r--r-- | cmd/sbc_harness/CMakeLists.txt | 2 | ||||
-rw-r--r-- | lib9p/include/lib9p/srv.h | 145 | ||||
-rw-r--r-- | lib9p/srv.c | 122 | ||||
-rw-r--r-- | lib9p/tests/test_server/CMakeLists.txt | 2 | ||||
-rw-r--r-- | lib9p/tests/test_server/main.c | 27 | ||||
-rw-r--r-- | lib9p_util/static.c | 63 | ||||
-rw-r--r-- | libcr_ipc/CMakeLists.txt | 9 | ||||
-rw-r--r-- | libhw/CMakeLists.txt | 38 | ||||
-rw-r--r-- | libhw_cr/CMakeLists.txt | 43 | ||||
-rw-r--r-- | libhw_cr/alarmclock.c | 23 | ||||
-rw-r--r-- | libhw_cr/host_alarmclock.c (renamed from libhw/host_alarmclock.c) | 2 | ||||
-rw-r--r-- | libhw_cr/host_include/libhw/host_alarmclock.h (renamed from libhw/host_include/libhw/host_alarmclock.h) | 0 | ||||
-rw-r--r-- | libhw_cr/host_include/libhw/host_net.h (renamed from libhw/host_include/libhw/host_net.h) | 0 | ||||
-rw-r--r-- | libhw_cr/host_net.c (renamed from libhw/host_net.c) | 2 | ||||
-rw-r--r-- | libhw_cr/host_util.c (renamed from libhw/host_util.c) | 2 | ||||
-rw-r--r-- | libhw_cr/host_util.h (renamed from libhw/host_util.h) | 8 | ||||
-rw-r--r-- | libhw_cr/rp2040_dma.c (renamed from libhw/rp2040_dma.c) | 2 | ||||
-rw-r--r-- | libhw_cr/rp2040_dma.h (renamed from libhw/rp2040_dma.h) | 8 | ||||
-rw-r--r-- | libhw_cr/rp2040_gpioirq.c (renamed from libhw/rp2040_gpioirq.c) | 2 | ||||
-rw-r--r-- | libhw_cr/rp2040_gpioirq.h (renamed from libhw/rp2040_gpioirq.h) | 8 | ||||
-rw-r--r-- | libhw_cr/rp2040_hwspi.c (renamed from libhw/rp2040_hwspi.c) | 10 | ||||
-rw-r--r-- | libhw_cr/rp2040_hwtimer.c (renamed from libhw/rp2040_hwtimer.c) | 2 | ||||
-rw-r--r-- | libhw_cr/rp2040_include/libhw/rp2040_hwspi.h (renamed from libhw/rp2040_include/libhw/rp2040_hwspi.h) | 2 | ||||
-rw-r--r-- | libhw_cr/rp2040_include/libhw/rp2040_hwtimer.h (renamed from libhw/rp2040_include/libhw/rp2040_hwtimer.h) | 0 | ||||
-rw-r--r-- | libhw_cr/rp2040_include/libhw/w5500.h (renamed from libhw/rp2040_include/libhw/w5500.h) | 0 | ||||
-rw-r--r-- | libhw_cr/w5500.c (renamed from libhw/w5500.c) | 2 | ||||
-rw-r--r-- | libhw_cr/w5500_ll.h (renamed from libhw/w5500_ll.h) | 71 | ||||
-rw-r--r-- | libhw_generic/CMakeLists.txt | 4 | ||||
-rw-r--r-- | libhw_generic/alarmclock.c | 18 | ||||
-rw-r--r-- | libhw_generic/include/libhw/generic/io.h | 28 | ||||
-rw-r--r-- | libhw_generic/io.c | 98 | ||||
l--------- | libhw_generic/tests/test.h | 1 | ||||
-rw-r--r-- | libhw_generic/tests/test_io.c | 57 |
35 files changed, 550 insertions, 256 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 386b13c..b379a8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,6 +98,7 @@ function(add_lib_test arg_libname arg_testname) if (ENABLE_TESTS) add_executable("${arg_testname}" "tests/${arg_testname}.c") target_link_libraries("${arg_testname}" "${arg_libname}") + target_include_directories("${arg_testname}" PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests) add_test( NAME "${arg_libname}/${arg_testname}" COMMAND valgrind --error-exitcode=2 "./${arg_testname}" @@ -139,7 +140,7 @@ add_subdirectory(libobj) add_subdirectory(libcr) add_subdirectory(libcr_ipc) add_subdirectory(libhw_generic) -add_subdirectory(libhw) +add_subdirectory(libhw_cr) add_subdirectory(libdhcp) add_subdirectory(libusb) add_subdirectory(lib9p) @@ -18,8 +18,8 @@ Our own tiny cooperative-multitasking OS: - `libcr/`: The kernel (a simple coroutine library) - `libcr_ipc/`: IPC primatives (semaphores, mutexes, channels, ...) for libcr - - `libhw/`: The hardware drivers - `libhw_generic/`: The hardware abstraction layer + - `libhw_cr/`: The hardware drivers Libraries for generic parts of what the harness is doing: diff --git a/cmd/sbc_harness/CMakeLists.txt b/cmd/sbc_harness/CMakeLists.txt index d7923c2..fa42b47 100644 --- a/cmd/sbc_harness/CMakeLists.txt +++ b/cmd/sbc_harness/CMakeLists.txt @@ -24,7 +24,7 @@ target_link_libraries(sbc_harness_objs libmisc libusb libdhcp - libhw + libhw_cr lib9p lib9p_util ) diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h index 83aabc0..ff5ebdc 100644 --- a/lib9p/include/lib9p/srv.h +++ b/lib9p/include/lib9p/srv.h @@ -37,53 +37,98 @@ int lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx); /* interface definitions ******************************************************/ -#define lib9p_srv_file_LO_IFACE \ - /* all - resource management */ \ - LO_FUNC(void , free ) /* must not error */ \ - LO_FUNC(struct lib9p_qid , qid ) /* must not error */ \ - LO_FUNC(uint32_t , chio , struct lib9p_srv_ctx *, \ - bool rd, bool wr, \ - bool trunc) \ - \ - /* all - syscalls */ \ - LO_FUNC(struct lib9p_stat , stat , struct lib9p_srv_ctx *) \ - LO_FUNC(void , wstat , struct lib9p_srv_ctx *, \ - struct lib9p_stat new) \ - LO_FUNC(void , remove , struct lib9p_srv_ctx *) \ - \ - /* directories - base */ \ - LO_FUNC(lo_interface lib9p_srv_file, dopen , struct lib9p_srv_ctx *, \ - struct lib9p_s childname) \ - LO_FUNC(lo_interface lib9p_srv_file, dcreate, struct lib9p_srv_ctx *, \ - struct lib9p_s childname, \ - lib9p_dm_t perm, \ - lib9p_o_t flags) \ - \ - /* directories - once opened */ \ - LO_FUNC(size_t /* <- obj cnt */ , dread , struct lib9p_srv_ctx *, \ - uint8_t *buf, \ - /* num bytes -> */ uint32_t byte_count, \ - /* starting at this object -> */ size_t obj_offset) \ - \ - /* non-directories - once opened */ \ - LO_FUNC(uint32_t , pread , struct lib9p_srv_ctx *, \ - void *buf, \ - uint32_t byte_count, \ - uint64_t byte_offset) \ - LO_FUNC(uint32_t , pwrite , struct lib9p_srv_ctx *, \ - void *buf, \ - uint32_t byte_count, \ +lo_interface lib9p_srv_fio; +lo_interface lib9p_srv_dio; + +/* FIXME: I don't like that the pointers returned by stat() and + * pread() have to remain live after they return. Perhaps a + * `respond()`-callback? But that just reads as gross in C. + * + * FIXME: It would be nice if pread() could return more than 1 iovec. + */ +#define lib9p_srv_file_LO_IFACE \ + /* resource management **********************************************/ \ + \ + /** \ + * free() is be called when all FIDs associated with the file are \ + * clunked. \ + * \ + * free() MUST NOT error. \ + */ \ + LO_FUNC(void , free ) \ + \ + /** \ + * qid() is called frequently and returns the current QID of the file. \ + * The .path field MUST never change, the .type field may change in \ + * response to wstat() calls (but the QT_DIR bit MUST NOT change), and \ + * the .vers field may change frequently in response to any number of \ + * things (wstat(), write(), or non-9P events). \ + * \ + * qid() MUST NOT error. \ + */ \ + LO_FUNC(struct lib9p_qid , qid ) \ + \ + /* non-"opened" generic I/O *****************************************/ \ + \ + LO_FUNC(struct lib9p_stat , stat , struct lib9p_srv_ctx *) \ + LO_FUNC(void , wstat , struct lib9p_srv_ctx *, \ + struct lib9p_stat new) \ + LO_FUNC(void , remove , struct lib9p_srv_ctx *) \ + \ + /* non-"opened" directory I/O ***************************************/ \ + \ + LO_FUNC(lo_interface lib9p_srv_file, dwalk , struct lib9p_srv_ctx *, \ + struct lib9p_s childname) \ + LO_FUNC(lo_interface lib9p_srv_file, dcreate, struct lib9p_srv_ctx *, \ + struct lib9p_s childname, \ + lib9p_dm_t perm, \ + lib9p_o_t flags) \ + \ + /* open() for I/O ***************************************************/ \ + \ + LO_FUNC(lo_interface lib9p_srv_fio , fopen , struct lib9p_srv_ctx *, \ + bool rd, bool wr, \ + bool trunc) \ + LO_FUNC(lo_interface lib9p_srv_dio , dopen , struct lib9p_srv_ctx *) +LO_INTERFACE(lib9p_srv_file); + +#define lib9p_srv_fio_LO_IFACE \ + LO_FUNC(struct lib9p_qid , qid ) \ + LO_FUNC(void , iofree ) \ + LO_FUNC(uint32_t , iounit ) \ + LO_FUNC(void , pread , struct lib9p_srv_ctx *, \ + uint32_t byte_count, \ + uint64_t byte_offset, \ + struct iovec *ret) \ + LO_FUNC(uint32_t , pwrite , struct lib9p_srv_ctx *, \ + void *buf, \ + uint32_t byte_count, \ uint64_t byte_offset) -LO_INTERFACE(lib9p_srv_file) +LO_INTERFACE(lib9p_srv_fio); + +/* FIXME: The dio interface just feels clunky. I'm not in a rush to + * change it because util9p_static_dir is already implemented and I + * don't anticipate the sbc-harness needing another dio + * implementation. But if I wanted lib9p to be used outside of + * sbc-harness, this is one of the first things that I'd want to + * change. + */ +#define lib9p_srv_dio_LO_IFACE \ + LO_FUNC(struct lib9p_qid , qid ) \ + LO_FUNC(void , iofree ) \ + LO_FUNC(size_t /* <- obj cnt */ , dread , struct lib9p_srv_ctx *, \ + uint8_t *buf, \ + /* num bytes -> */ uint32_t byte_count, \ + /* starting at this object -> */ size_t obj_offset) +LO_INTERFACE(lib9p_srv_dio); #define LIB9P_SRV_NOTDIR(TYP, NAM) \ - static lo_interface lib9p_srv_file NAM##_dopen (TYP *, struct lib9p_srv_ctx *, struct lib9p_s) { assert_notreached("not a directory"); } \ + static lo_interface lib9p_srv_file NAM##_dwalk (TYP *, struct lib9p_srv_ctx *, struct lib9p_s) { assert_notreached("not a directory"); } \ static lo_interface lib9p_srv_file NAM##_dcreate(TYP *, struct lib9p_srv_ctx *, struct lib9p_s, lib9p_dm_t, lib9p_o_t) { assert_notreached("not a directory"); } \ - static size_t NAM##_dread (TYP *, struct lib9p_srv_ctx *, uint8_t *, uint32_t, size_t) { assert_notreached("not a directory"); } + static lo_interface lib9p_srv_dio NAM##_dopen (TYP *, struct lib9p_srv_ctx *) { assert_notreached("not a directory"); } #define LIB9P_SRV_NOTFILE(TYP, NAM) \ - static uint32_t NAM##_pread (TYP *, struct lib9p_srv_ctx *, void *, uint32_t, uint64_t) { assert_notreached("not a file"); } \ - static uint32_t NAM##_pwrite(TYP *, struct lib9p_srv_ctx *, void *, uint32_t, uint64_t) { assert_notreached("not a file"); } + static lo_interface lib9p_srv_fio NAM##_fopen (TYP *, struct lib9p_srv_ctx *, bool, bool, bool) { assert_notreached("not a file"); } /* main server entrypoints ****************************************************/ @@ -103,16 +148,32 @@ struct lib9p_srv { }; /** + * In an infinite loop, accept a connection and read messages from it until + * close; dispatching requests to a pool of lib9p_srv_write_cr() coroutines + * with the same `srv`. + * * Will just close the connection if a T-message has a size[4] <7. * + * @param srv: The server configuration and state; has an associated pool of + * lib9p_srv_write_cr() coroutines. + * @param listener: The listener object to accept connections from. + * * @errno LINUX_EMSGSIZE T-message has size[4] bigger than max_msg_size * @errno LINUX_EDOM Tversion specified an impossibly small max_msg_size * @errno LINUX_EOPNOTSUPP T-message has an R-message type, or an unrecognized T-message type * @errno LINUX_EBADMSG T-message has wrong size[4] for its content, or has invalid UTF-8 * @errno LINUX_ERANGE R-message does not fit into max_msg_size */ - [[noreturn]] void lib9p_srv_read_cr(struct lib9p_srv *srv, lo_interface net_stream_listener listener); + +/** + * Service requests to the `struct lib9p_srv *srv` argument that have been + * read by lib9p_srv_read_cr(). + * + * @param struct lib9p_srv *srv: The server configuration and state; has an + * associated pool of lib9p_srv_read_cr() + * coroutines. + */ COROUTINE lib9p_srv_write_cr(void *_srv); #endif /* _LIB9P_SRV_H_ */ diff --git a/lib9p/srv.c b/lib9p/srv.c index 2475baf..50d0b78 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -60,8 +60,7 @@ struct srv_pathinfo { * from FIDs. */ unsigned int gc_refcount; /* References from fids with FIDFLAG_OPEN_R/FIDFLAG_OPEN_W. */ - unsigned int rd_refcount; - unsigned int wr_refcount; + unsigned int io_refcount; }; #define NAME pathmap @@ -77,11 +76,18 @@ struct srv_pathinfo { #define FIDFLAG_OPEN (FIDFLAG_OPEN_R|FIDFLAG_OPEN_W) struct _srv_fidinfo { - srv_path_t path; - uint8_t flags; - uint32_t iounit; - size_t dir_idx; - uint64_t dir_off; + srv_path_t path; + uint8_t flags; + union { + struct { + lo_interface lib9p_srv_fio io; + } file; + struct { + lo_interface lib9p_srv_dio io; + size_t idx; + uint64_t off; + } dir; + }; }; #define NAME fidmap @@ -122,9 +128,9 @@ struct _srv_sess { /* mutable */ bool initialized; bool closing; - struct pathmap paths; - struct reqmap reqs; - struct fidmap fids; + struct pathmap paths; /* srv_path_t => lib9p_srv_file + metadata */ + struct fidmap fids; /* lib9p_fid_t => lib9p_srv_{fio,dio} + metadata */ + struct reqmap reqs; /* lib9p_tag_t => *_lib9p_srv_req */ }; struct _lib9p_srv_req { @@ -463,8 +469,7 @@ static inline struct srv_pathinfo *srv_util_pathsave(struct _lib9p_srv_req *ctx, .file = file, .parent_dir = parent_path, .gc_refcount = 0, - .rd_refcount = 0, - .wr_refcount = 0, + .io_refcount = 0, }); assert(pathinfo); if (parent_path != qid.path) { @@ -515,6 +520,12 @@ static inline struct _srv_fidinfo *srv_util_fidsave(struct _lib9p_srv_req *ctx, struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, fid); if (fidinfo) { if (overwrite) { + struct srv_pathinfo *old_pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path); + assert(old_pathinfo); + if (srv_util_pathisdir(old_pathinfo)) + LO_CALL(fidinfo->dir.io, iofree); + else + LO_CALL(fidinfo->file.io, iofree); srv_util_pathfree(ctx, fidinfo->path); } else { lib9p_error(&ctx->ctx.basectx, @@ -748,7 +759,7 @@ static void handle_Twalk(struct _lib9p_srv_req *ctx, break; } - lo_interface lib9p_srv_file member_file = LO_CALL(pathinfo->file, dopen, &ctx->ctx, req->wname[resp->nwqid]); + lo_interface lib9p_srv_file member_file = LO_CALL(pathinfo->file, dwalk, &ctx->ctx, req->wname[resp->nwqid]); assert(LO_IS_NULL(member_file) == lib9p_ctx_has_error(&ctx->ctx.basectx)); if (lib9p_ctx_has_error(&ctx->ctx.basectx)) break; @@ -774,6 +785,13 @@ static void handle_Twalk(struct _lib9p_srv_req *ctx, pathinfo = new_pathinfo; } if (resp->nwqid == req->nwname) { + if (req->newfid == req->fid) { + if (srv_util_pathisdir(pathinfo)) + LO_CALL(fidinfo->dir.io, iofree); + else + LO_CALL(fidinfo->file.io, iofree); + fidinfo->flags = 0; + } if (!srv_util_fidsave(ctx, req->newfid, pathinfo, req->newfid == req->fid)) srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path); } else { @@ -816,7 +834,6 @@ static void handle_Topen(struct _lib9p_srv_req *ctx, /* Variables. */ lib9p_o_t reqmode = req->mode; uint8_t fidflags = fidinfo->flags; - uint32_t iounit = fidinfo->iounit; /* Check permissions. */ if (reqmode & LIB9P_O_RCLOSE) { @@ -831,13 +848,13 @@ static void handle_Topen(struct _lib9p_srv_req *ctx, LINUX_EACCES, "permission denied to remove-on-close"); return; } - fidflags = fidflags | FIDFLAG_RCLOSE; + fidflags |= FIDFLAG_RCLOSE; } struct lib9p_stat stat = LO_CALL(pathinfo->file, stat, &ctx->ctx); if (lib9p_ctx_has_error(&ctx->ctx.basectx)) return; lib9p_stat_assert(stat); - if ((stat.file_mode & LIB9P_DM_EXCL) && (pathinfo->rd_refcount || pathinfo->wr_refcount)) { + if ((stat.file_mode & LIB9P_DM_EXCL) && pathinfo->io_refcount) { lib9p_error(&ctx->ctx.basectx, LINUX_EEXIST, "exclusive file is already opened"); return; @@ -870,26 +887,36 @@ static void handle_Topen(struct _lib9p_srv_req *ctx, } /* Actually make the call. */ - if ((reqmode & LIB9P_O_TRUNC) || (rd && !pathinfo->rd_refcount) || (wr && !pathinfo->wr_refcount) ) { - iounit = LO_CALL(pathinfo->file, chio, &ctx->ctx, - fidflags & FIDFLAG_OPEN_R, - fidflags & FIDFLAG_OPEN_W, - reqmode & LIB9P_O_TRUNC); + uint32_t iounit; + struct lib9p_qid qid; + if (srv_util_pathisdir(pathinfo)) { + fidinfo->dir.io = LO_CALL(pathinfo->file, dopen, &ctx->ctx); + assert(LO_IS_NULL(fidinfo->dir.io) == lib9p_ctx_has_error(&ctx->ctx.basectx)); + if (lib9p_ctx_has_error(&ctx->ctx.basectx)) + return; + fidinfo->dir.idx = 0; + fidinfo->dir.off = 0; + qid = LO_CALL(fidinfo->dir.io, qid); + iounit = 0; + } else { + fidinfo->file.io = LO_CALL(pathinfo->file, fopen, &ctx->ctx, + rd, wr, + reqmode & LIB9P_O_TRUNC); + assert(LO_IS_NULL(fidinfo->file.io) == lib9p_ctx_has_error(&ctx->ctx.basectx)); if (lib9p_ctx_has_error(&ctx->ctx.basectx)) return; + qid = LO_CALL(fidinfo->file.io, qid); + iounit = LO_CALL(fidinfo->file.io, iounit); } /* Success. */ - if (rd) { - fidflags = fidflags | FIDFLAG_OPEN_R; - pathinfo->rd_refcount++; - } - if (wr) { - fidflags = fidflags | FIDFLAG_OPEN_W; - pathinfo->wr_refcount++; - } + if (rd) + fidflags |= FIDFLAG_OPEN_R; + if (wr) + fidflags |= FIDFLAG_OPEN_W; + pathinfo->io_refcount++; fidinfo->flags = fidflags; - resp->qid = stat.file_qid; + resp->qid = qid; resp->iounit = iounit; } @@ -923,7 +950,6 @@ static void handle_Tread(struct _lib9p_srv_req *ctx, /* Variables. */ struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path); assert(pathinfo); - resp->data = (char *)(&resp[1]); /* Do it. */ if (srv_util_pathisdir(pathinfo)) { @@ -931,16 +957,17 @@ static void handle_Tread(struct _lib9p_srv_req *ctx, size_t idx; if (req->offset == 0) idx = 0; - else if (req->offset == fidinfo->dir_off) - idx = fidinfo->dir_idx; + else if (req->offset == fidinfo->dir.off) + idx = fidinfo->dir.idx; else { lib9p_errorf(&ctx->ctx.basectx, LINUX_EINVAL, "invalid offset (must be 0 or %"PRIu64"): %"PRIu64, - fidinfo->dir_off, req->offset); + fidinfo->dir.off, req->offset); return; } /* Do it. */ - size_t num = LO_CALL(pathinfo->file, dread, &ctx->ctx, (uint8_t *)resp->data, req->count, idx); + resp->data = (char *)(&resp[1]); + size_t num = LO_CALL(fidinfo->dir.io, dread, &ctx->ctx, (uint8_t *)resp->data, req->count, idx); /* Translate object-count back to byte-count. */ uint32_t len = 0; for (size_t i = 0; i < num; i++) { @@ -950,10 +977,18 @@ static void handle_Tread(struct _lib9p_srv_req *ctx, } resp->count = len; /* Remember. */ - fidinfo->dir_idx = idx+num; - fidinfo->dir_off = req->offset + len; - } else - resp->count = LO_CALL(pathinfo->file, pread, &ctx->ctx, resp->data, req->count, req->offset); + fidinfo->dir.idx = idx+num; + fidinfo->dir.off = req->offset + len; + } else { + struct iovec iov; + LO_CALL(fidinfo->file.io, pread, &ctx->ctx, req->count, req->offset, &iov); + if (!lib9p_ctx_has_error(&ctx->ctx.basectx)) { + resp->count = iov.iov_len; + resp->data = iov.iov_base; + if (resp->count > req->count) + resp->count = req->count; + } + } } static void handle_Twrite(struct _lib9p_srv_req *ctx, @@ -979,7 +1014,7 @@ static void handle_Twrite(struct _lib9p_srv_req *ctx, assert(pathinfo); /* Do it. */ - resp->count = LO_CALL(pathinfo->file, pwrite, &ctx->ctx, req->data, req->count, req->offset); + resp->count = LO_CALL(fidinfo->file.io, pwrite, &ctx->ctx, req->data, req->count, req->offset); } static void clunkremove(struct _lib9p_srv_req *ctx, lib9p_fid_t fid, bool remove) { @@ -1012,6 +1047,13 @@ static void clunkremove(struct _lib9p_srv_req *ctx, lib9p_fid_t fid, bool remove } clunk: + if (fidinfo->flags & FIDFLAG_OPEN) { + if (srv_util_pathisdir(pathinfo)) + LO_CALL(fidinfo->dir.io, iofree); + else + LO_CALL(fidinfo->file.io, iofree); + pathinfo->io_refcount--; + } srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path); fidmap_del(&ctx->parent_sess->fids, fid); } diff --git a/lib9p/tests/test_server/CMakeLists.txt b/lib9p/tests/test_server/CMakeLists.txt index 74a759d..5313917 100644 --- a/lib9p/tests/test_server/CMakeLists.txt +++ b/lib9p/tests/test_server/CMakeLists.txt @@ -18,7 +18,7 @@ target_link_libraries(test_server_objs libmisc lib9p lib9p_util - libhw + libhw_cr ) # Analyze the stack ############################################################ diff --git a/lib9p/tests/test_server/main.c b/lib9p/tests/test_server/main.c index 074dbe7..c759029 100644 --- a/lib9p/tests/test_server/main.c +++ b/lib9p/tests/test_server/main.c @@ -48,7 +48,10 @@ struct api_file { uint64_t pathnum; }; LO_IMPLEMENTATION_H(lib9p_srv_file, struct api_file, api) +LO_IMPLEMENTATION_H(lib9p_srv_fio, struct api_file, api) + LO_IMPLEMENTATION_C(lib9p_srv_file, struct api_file, api, static) +LO_IMPLEMENTATION_C(lib9p_srv_fio, struct api_file, api, static) static void api_free(struct api_file *self) { assert(self); @@ -61,11 +64,6 @@ static struct lib9p_qid api_qid(struct api_file *self) { .path = self->pathnum, }; } -static uint32_t api_chio(struct api_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) { - assert(self); - assert(ctx); - return 0; -} static struct lib9p_stat api_stat(struct api_file *self, struct lib9p_srv_ctx *ctx) { assert(self); @@ -101,6 +99,21 @@ static void api_remove(struct api_file *self, struct lib9p_srv_ctx *ctx) { LIB9P_SRV_NOTDIR(struct api_file, api) +static lo_interface lib9p_srv_fio api_fopen(struct api_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) { + assert(self); + assert(ctx); + return lo_box_api_as_lib9p_srv_fio(self); +} + +static void api_iofree(struct api_file *self) { + assert(self); +} + +static uint32_t api_iounit(struct api_file *self) { + assert(self); + return 0; +} + static uint32_t api_pwrite(struct api_file *self, struct lib9p_srv_ctx *ctx, void *buf, uint32_t byte_count, uint64_t LM_UNUSED(offset)) { assert(self); assert(ctx); @@ -111,7 +124,9 @@ static uint32_t api_pwrite(struct api_file *self, struct lib9p_srv_ctx *ctx, voi LO_CALL(lo_box_hostnet_tcplist_as_net_stream_listener(&globals.listeners[i]), close); return byte_count; } -static uint32_t api_pread(struct api_file *, struct lib9p_srv_ctx *, void *, uint32_t, uint64_t) { +static void api_pread(struct api_file *LM_UNUSED(self), struct lib9p_srv_ctx *LM_UNUSED(ctx), + uint32_t LM_UNUSED(byte_count), uint64_t LM_UNUSED(byte_offset), + struct iovec *LM_UNUSED(ret)) { assert_notreached("not readable"); } diff --git a/lib9p_util/static.c b/lib9p_util/static.c index a6ea8f6..7f1e6b7 100644 --- a/lib9p_util/static.c +++ b/lib9p_util/static.c @@ -12,6 +12,12 @@ LO_IMPLEMENTATION_C(lib9p_srv_file, struct util9p_static_dir, util9p_static_dir, static); LO_IMPLEMENTATION_C(lib9p_srv_file, struct util9p_static_file, util9p_static_file, static); +LO_IMPLEMENTATION_H(lib9p_srv_dio, struct util9p_static_dir, util9p_static_dir); +LO_IMPLEMENTATION_C(lib9p_srv_dio, struct util9p_static_dir, util9p_static_dir, static); + +LO_IMPLEMENTATION_H(lib9p_srv_fio, struct util9p_static_file, util9p_static_file); +LO_IMPLEMENTATION_C(lib9p_srv_fio, struct util9p_static_file, util9p_static_file, static); + /* dir ************************************************************************/ static void util9p_static_dir_free(struct util9p_static_dir *self) { @@ -26,11 +32,6 @@ static struct lib9p_qid util9p_static_dir_qid(struct util9p_static_dir *self) { .path = self->pathnum, }; } -static uint32_t util9p_static_dir_chio(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) { - assert(self); - assert(ctx); - return 0; -} static struct lib9p_stat util9p_static_dir_stat(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) { assert(self); @@ -68,7 +69,7 @@ static void util9p_static_dir_remove(struct util9p_static_dir *self, struct lib9 lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem"); } -static lo_interface lib9p_srv_file util9p_static_dir_dopen(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, +static lo_interface lib9p_srv_file util9p_static_dir_dwalk(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, struct lib9p_s childname) { assert(self); assert(ctx); @@ -97,6 +98,16 @@ static lo_interface lib9p_srv_file util9p_static_dir_dcreate(struct util9p_stati return LO_NULL(lib9p_srv_file); } +LIB9P_SRV_NOTFILE(struct util9p_static_dir, util9p_static_dir); + +static lo_interface lib9p_srv_dio util9p_static_dir_dopen(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) { + assert(self); + assert(ctx); + return lo_box_util9p_static_dir_as_lib9p_srv_dio(self); +} +static void util9p_static_dir_iofree(struct util9p_static_dir *self) { + assert(self); +} static size_t util9p_static_dir_dread(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, uint8_t *buf, uint32_t byte_count, @@ -126,8 +137,6 @@ static size_t util9p_static_dir_dread(struct util9p_static_dir *self, struct lib return obj_offset - _obj_offset; } -LIB9P_SRV_NOTFILE(struct util9p_static_dir, util9p_static_dir) - /* file ***********************************************************************/ static void util9p_static_file_free(struct util9p_static_file *self) { @@ -142,11 +151,6 @@ static struct lib9p_qid util9p_static_file_qid(struct util9p_static_file *self) .path = self->pathnum, }; } -static uint32_t util9p_static_file_chio(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) { - assert(self); - assert(ctx); - return 0; -} static inline size_t util9p_static_file_size(struct util9p_static_file *file) { assert(file); @@ -196,31 +200,46 @@ static void util9p_static_file_remove(struct util9p_static_file *self, struct li lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem"); } -LIB9P_SRV_NOTDIR(struct util9p_static_file, util9p_static_file) +LIB9P_SRV_NOTDIR(struct util9p_static_file, util9p_static_file); -static uint32_t util9p_static_file_pread(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx, - void *buf, - uint32_t byte_count, - uint64_t byte_offset) { +static lo_interface lib9p_srv_fio util9p_static_file_fopen(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx, + bool rd, bool wr, bool trunc) { assert(self); assert(ctx); + assert(rd); + assert(!wr); + assert(!trunc); + return lo_box_util9p_static_file_as_lib9p_srv_fio(self); +} +static void util9p_static_file_iofree(struct util9p_static_file *self) { + assert(self); +} +static uint32_t util9p_static_file_iounit(struct util9p_static_file *self) { + assert(self); + return 0; +} +static void util9p_static_file_pread(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx, + uint32_t byte_count, uint64_t byte_offset, + struct iovec *ret) { + assert(self); + assert(ctx); + assert(ret); size_t data_size = util9p_static_file_size(self); if (byte_offset > (uint64_t)data_size) { lib9p_error(&ctx->basectx, LINUX_EINVAL, "offset is past end-of-file length"); - return 0; + return; } size_t beg_off = (size_t)byte_offset; size_t end_off = beg_off + (size_t)byte_count; if (end_off > data_size) end_off = data_size; - memcpy(buf, &self->data_start[beg_off], end_off-beg_off); - return (uint32_t)(end_off-beg_off); + ret->iov_base = &self->data_start[beg_off]; + ret->iov_len = end_off-beg_off; } - static uint32_t util9p_static_file_pwrite(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx, void *LM_UNUSED(buf), uint32_t LM_UNUSED(byte_count), diff --git a/libcr_ipc/CMakeLists.txt b/libcr_ipc/CMakeLists.txt index 4590bdd..3746584 100644 --- a/libcr_ipc/CMakeLists.txt +++ b/libcr_ipc/CMakeLists.txt @@ -21,9 +21,6 @@ set(ipc_tests rpc sema ) -if (ENABLE_TESTS) - foreach(test IN LISTS ipc_tests) - add_lib_test(libcr_ipc "test_${test}") - target_include_directories("test_${test}" PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/tests) - endforeach() -endif() +foreach(test IN LISTS ipc_tests) + add_lib_test(libcr_ipc "test_${test}") +endforeach() diff --git a/libhw/CMakeLists.txt b/libhw/CMakeLists.txt deleted file mode 100644 index 242a3fa..0000000 --- a/libhw/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -# libhw/CMakeLists.txt - Device drivers -# -# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> -# SPDX-License-Identifier: AGPL-3.0-or-later - -add_library(libhw INTERFACE) -target_link_libraries(libhw INTERFACE - libhw_generic -) - -if (PICO_PLATFORM STREQUAL "rp2040") - target_include_directories(libhw SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/rp2040_include) - target_link_libraries(libhw INTERFACE - libcr_ipc - ) - target_sources(libhw INTERFACE - rp2040_dma.c - rp2040_gpioirq.c - rp2040_hwspi.c - rp2040_hwtimer.c - w5500.c - ) - target_link_libraries(libhw INTERFACE - hardware_gpio - hardware_irq - hardware_spi - hardware_timer - ) -endif() - -if (PICO_PLATFORM STREQUAL "host") - target_include_directories(libhw SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/host_include) - target_sources(libhw INTERFACE - host_util.c - host_alarmclock.c - host_net.c - ) -endif() diff --git a/libhw_cr/CMakeLists.txt b/libhw_cr/CMakeLists.txt new file mode 100644 index 0000000..caeac21 --- /dev/null +++ b/libhw_cr/CMakeLists.txt @@ -0,0 +1,43 @@ +# libhw_cr/CMakeLists.txt - Device drivers for libcr +# +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +add_library(libhw_cr INTERFACE) +target_link_libraries(libhw_cr INTERFACE + libhw_generic + libcr +) + +target_sources(libhw_cr INTERFACE + alarmclock.c +) + +if (PICO_PLATFORM STREQUAL "rp2040") + target_include_directories(libhw_cr SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/rp2040_include) + target_link_libraries(libhw_cr INTERFACE + libcr_ipc + ) + target_sources(libhw_cr INTERFACE + rp2040_dma.c + rp2040_gpioirq.c + rp2040_hwspi.c + rp2040_hwtimer.c + w5500.c + ) + target_link_libraries(libhw_cr INTERFACE + hardware_gpio + hardware_irq + hardware_spi + hardware_timer + ) +endif() + +if (PICO_PLATFORM STREQUAL "host") + target_include_directories(libhw_cr SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/host_include) + target_sources(libhw_cr INTERFACE + host_util.c + host_alarmclock.c + host_net.c + ) +endif() diff --git a/libhw_cr/alarmclock.c b/libhw_cr/alarmclock.c new file mode 100644 index 0000000..6eec52b --- /dev/null +++ b/libhw_cr/alarmclock.c @@ -0,0 +1,23 @@ +/* libhw_cr/alarmclock.c - sleep() implementation for libcr + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libcr/coroutine.h> + +#include <libhw/generic/alarmclock.h> + +static void alarmclock_sleep_intrhandler(void *_arg) { + cid_t cid = *(cid_t *)_arg; + cr_unpause_from_intrhandler(cid); +} + +void alarmclock_sleep_until_ns(lo_interface alarmclock clock, uint64_t abstime_ns) { + bool saved = cr_save_and_disable_interrupts(); + cid_t cid = cr_getcid(); + struct alarmclock_trigger trigger; + LO_CALL(clock, add_trigger, &trigger, abstime_ns, alarmclock_sleep_intrhandler, &cid); + cr_pause_and_yield(); + cr_restore_interrupts(saved); +} diff --git a/libhw/host_alarmclock.c b/libhw_cr/host_alarmclock.c index 19ece7c..2f255e0 100644 --- a/libhw/host_alarmclock.c +++ b/libhw_cr/host_alarmclock.c @@ -1,4 +1,4 @@ -/* libhw/host_alarmclock.c - <libhw/generic/alarmclock.h> implementation for POSIX hosts +/* libhw_cr/host_alarmclock.c - <libhw/generic/alarmclock.h> implementation for POSIX hosts * * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/libhw/host_include/libhw/host_alarmclock.h b/libhw_cr/host_include/libhw/host_alarmclock.h index 89df68a..89df68a 100644 --- a/libhw/host_include/libhw/host_alarmclock.h +++ b/libhw_cr/host_include/libhw/host_alarmclock.h diff --git a/libhw/host_include/libhw/host_net.h b/libhw_cr/host_include/libhw/host_net.h index fced229..fced229 100644 --- a/libhw/host_include/libhw/host_net.h +++ b/libhw_cr/host_include/libhw/host_net.h diff --git a/libhw/host_net.c b/libhw_cr/host_net.c index e89cd66..f1c988c 100644 --- a/libhw/host_net.c +++ b/libhw_cr/host_net.c @@ -1,4 +1,4 @@ -/* libhw/host_net.c - <libhw/generic/net.h> implementation for hosted glibc +/* libhw_cr/host_net.c - <libhw/generic/net.h> implementation for hosted glibc * * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/libhw/host_util.c b/libhw_cr/host_util.c index b862e39..958ed9c 100644 --- a/libhw/host_util.c +++ b/libhw_cr/host_util.c @@ -1,4 +1,4 @@ -/* libhw/host_util.c - Utilities for GNU/Linux hosts +/* libhw_cr/host_util.c - Utilities for GNU/Linux hosts * * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/libhw/host_util.h b/libhw_cr/host_util.h index f3ef6b4..8c53fab 100644 --- a/libhw/host_util.h +++ b/libhw_cr/host_util.h @@ -1,11 +1,11 @@ -/* libhw/host_util.h - Utilities for GNU/Linux hosts +/* libhw_cr/host_util.h - Utilities for GNU/Linux hosts * * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ -#ifndef _LIBHW_HOST_UTIL_H_ -#define _LIBHW_HOST_UTIL_H_ +#ifndef _LIBHW_CR_HOST_UTIL_H_ +#define _LIBHW_CR_HOST_UTIL_H_ #include <time.h> /* for struct timespec */ #include <sys/time.h> /* for struct timeval */ @@ -44,4 +44,4 @@ static inline uint64_t ns_from_host_ns_time(host_ns_time_t host_time) { ((uint64_t)host_time.tv_nsec); } -#endif /* _LIBHW_HOST_UTIL_H_ */ +#endif /* _LIBHW_CR_HOST_UTIL_H_ */ diff --git a/libhw/rp2040_dma.c b/libhw_cr/rp2040_dma.c index dfbf136..69116bf 100644 --- a/libhw/rp2040_dma.c +++ b/libhw_cr/rp2040_dma.c @@ -1,4 +1,4 @@ -/* libhw/rp2040_dma.c - Utilities for sharing the DMA IRQs +/* libhw_cr/rp2040_dma.c - Utilities for sharing the DMA IRQs * * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/libhw/rp2040_dma.h b/libhw_cr/rp2040_dma.h index c8d69b1..e295adf 100644 --- a/libhw/rp2040_dma.h +++ b/libhw_cr/rp2040_dma.h @@ -1,4 +1,4 @@ -/* libhw/rp2040_dma.h - Utilities for using DMA on the RP2040 (replaces <hardware/dma.h>) +/* libhw_cr/rp2040_dma.h - Utilities for using DMA on the RP2040 (replaces <hardware/dma.h>) * * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. * SPDX-License-Identifier: BSD-3-Clause @@ -7,8 +7,8 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -#ifndef _LIBHW_RP2040_DMA_H_ -#define _LIBHW_RP2040_DMA_H_ +#ifndef _LIBHW_CR_RP2040_DMA_H_ +#define _LIBHW_CR_RP2040_DMA_H_ #include <assert.h> #include <stdint.h> /* for uint32_t */ @@ -125,4 +125,4 @@ struct dma_alias3_short3 { READ_ADDR ; }; #define _DMA_TRIGGER_trans_count struct dma_alias1 #define _DMA_TRIGGER_ctrl struct dma_alias0 -#endif /* _LIBHW_RP2040_DMA_H_ */ +#endif /* _LIBHW_CR_RP2040_DMA_H_ */ diff --git a/libhw/rp2040_gpioirq.c b/libhw_cr/rp2040_gpioirq.c index 2f0ceac..1ae74f9 100644 --- a/libhw/rp2040_gpioirq.c +++ b/libhw_cr/rp2040_gpioirq.c @@ -1,4 +1,4 @@ -/* libhw/rp2040_gpioirq.c - Utilities for sharing the GPIO IRQ (IO_IRQ_BANK0) +/* libhw_cr/rp2040_gpioirq.c - Utilities for sharing the GPIO IRQ (IO_IRQ_BANK0) * * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/libhw/rp2040_gpioirq.h b/libhw_cr/rp2040_gpioirq.h index 06041c9..75a264f 100644 --- a/libhw/rp2040_gpioirq.h +++ b/libhw_cr/rp2040_gpioirq.h @@ -1,11 +1,11 @@ -/* libhw/rp2040_gpioirq.h - Utilities for sharing the GPIO IRQ (IO_IRQ_BANK0) +/* libhw_cr/rp2040_gpioirq.h - Utilities for sharing the GPIO IRQ (IO_IRQ_BANK0) * * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ -#ifndef _LIBHW_RP2040_GPIOIRQ_H_ -#define _LIBHW_RP2040_GPIOIRQ_H_ +#ifndef _LIBHW_CR_RP2040_GPIOIRQ_H_ +#define _LIBHW_CR_RP2040_GPIOIRQ_H_ #include <hardware/gpio.h> /* for enum gpio_irq_level */ @@ -30,4 +30,4 @@ typedef void (*gpioirq_handler_t)(void *arg, uint gpio, enum gpio_irq_level even */ void gpioirq_set_and_enable_exclusive_handler(uint gpio, enum gpio_irq_level event, gpioirq_handler_t fn, void *arg); -#endif /* _LIBHW_RP2040_GPIOIRQ_H_ */ +#endif /* _LIBHW_CR_RP2040_GPIOIRQ_H_ */ diff --git a/libhw/rp2040_hwspi.c b/libhw_cr/rp2040_hwspi.c index f747b1e..d4adb11 100644 --- a/libhw/rp2040_hwspi.c +++ b/libhw_cr/rp2040_hwspi.c @@ -1,4 +1,4 @@ -/* libhw/rp2040_hwspi.c - <libhw/generic/spi.h> implementation for the RP2040's ARM Primecell SSP (PL022) +/* libhw_cr/rp2040_hwspi.c - <libhw/generic/spi.h> implementation for the RP2040's ARM Primecell SSP (PL022) * * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later @@ -185,23 +185,23 @@ static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct dupl if (!iov[i].iov_len) continue; tx_data_blocks[j] = (typeof(tx_data_blocks[0])){ - .read_addr = iov[i].iov_write_src ?: &self->bogus_data, + .read_addr = (iov[i].iov_write_from != IOVEC_DISCARD) ? iov[i].iov_write_from : &self->bogus_data, .write_addr = &spi_get_hw(self->inst)->dr, .trans_count = iov[i].iov_len, .ctrl = (DMA_CTRL_ENABLE | DMA_CTRL_DATA_SIZE(DMA_SIZE_8) - | (iov[i].iov_write_src ? DMA_CTRL_INCR_READ : 0) + | ((iov[i].iov_write_from != IOVEC_DISCARD) ? DMA_CTRL_INCR_READ : 0) | DMA_CTRL_CHAIN_TO(self->dma_tx_ctrl) | DMA_CTRL_TREQ_SEL(SPI_DREQ_NUM(self->inst, true)) | DMA_CTRL_IRQ_QUIET), }; rx_data_blocks[j] = (typeof(rx_data_blocks[0])){ .read_addr = &spi_get_hw(self->inst)->dr, - .write_addr = iov[i].iov_read_dst ?: &bogus_rx_dst, + .write_addr = (iov[i].iov_read_to != IOVEC_DISCARD) ? iov[i].iov_read_to : &bogus_rx_dst, .trans_count = iov[i].iov_len, .ctrl = (DMA_CTRL_ENABLE | DMA_CTRL_DATA_SIZE(DMA_SIZE_8) - | (iov[i].iov_read_dst ? DMA_CTRL_INCR_WRITE : 0) + | ((iov[i].iov_read_to != IOVEC_DISCARD) ? DMA_CTRL_INCR_WRITE : 0) | DMA_CTRL_CHAIN_TO(self->dma_rx_ctrl) | DMA_CTRL_TREQ_SEL(SPI_DREQ_NUM(self->inst, false)) | DMA_CTRL_IRQ_QUIET), diff --git a/libhw/rp2040_hwtimer.c b/libhw_cr/rp2040_hwtimer.c index ada6246..8227abb 100644 --- a/libhw/rp2040_hwtimer.c +++ b/libhw_cr/rp2040_hwtimer.c @@ -1,4 +1,4 @@ -/* libhw/rp2040_hwtimer.c - <libhw/generic/alarmclock.h> implementation for the RP2040's hardware timer +/* libhw_cr/rp2040_hwtimer.c - <libhw/generic/alarmclock.h> implementation for the RP2040's hardware timer * * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/libhw/rp2040_include/libhw/rp2040_hwspi.h b/libhw_cr/rp2040_include/libhw/rp2040_hwspi.h index eb54cdc..9d99f7b 100644 --- a/libhw/rp2040_include/libhw/rp2040_hwspi.h +++ b/libhw_cr/rp2040_include/libhw/rp2040_hwspi.h @@ -48,7 +48,7 @@ LO_IMPLEMENTATION_H(spi, struct rp2040_hwspi, rp2040_hwspi) * @param mode : enum spi_mode : the SPI mode; SPI_MODE_{0..3} * @param baudrate_hz : uint : baudrate in Hz * @param min_delay_ns: uint64_t : minimum time for pin_cs to be high between messages - * @param bogus_data : uint8_t : bogus data to write when .iov_write_src is NULL + * @param bogus_data : uint8_t : bogus data to write when .iov_write_from is IOVEC_DISCARD * @param pin_miso : uint : pin number; 0, 4, 16, or 20 for _HWSPI_0; 8, 12, 24, or 28 for _HWSPI_1 * @param pin_mosi : uint : pin number; 3, 7, 19, or 23 for _HWSPI_0; 11, 15, or 27 for _HWSPI_1 * @param pin_clk : uint : pin number; 2, 6, 18, or 22 for _HWSPI_0; 10, 14, or 26 for _HWSPI_1 diff --git a/libhw/rp2040_include/libhw/rp2040_hwtimer.h b/libhw_cr/rp2040_include/libhw/rp2040_hwtimer.h index 40e4172..40e4172 100644 --- a/libhw/rp2040_include/libhw/rp2040_hwtimer.h +++ b/libhw_cr/rp2040_include/libhw/rp2040_hwtimer.h diff --git a/libhw/rp2040_include/libhw/w5500.h b/libhw_cr/rp2040_include/libhw/w5500.h index 51effba..51effba 100644 --- a/libhw/rp2040_include/libhw/w5500.h +++ b/libhw_cr/rp2040_include/libhw/w5500.h diff --git a/libhw/w5500.c b/libhw_cr/w5500.c index c4d36f3..295add2 100644 --- a/libhw/w5500.c +++ b/libhw_cr/w5500.c @@ -1,4 +1,4 @@ -/* libhw/w5500.c - <libhw/generic/net.h> implementation for the WIZnet W5500 chip +/* libhw_cr/w5500.c - <libhw/generic/net.h> implementation for the WIZnet W5500 chip * * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/libhw/w5500_ll.h b/libhw_cr/w5500_ll.h index 3822ad4..2506cd2 100644 --- a/libhw/w5500_ll.h +++ b/libhw_cr/w5500_ll.h @@ -1,4 +1,4 @@ -/* libhw/w5500_ll.h - Low-level header library for the WIZnet W5500 chip +/* libhw_cr/w5500_ll.h - Low-level header library for the WIZnet W5500 chip * * Based entirely on the W5500 datasheet, v1.1.0. * https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf @@ -7,8 +7,8 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -#ifndef _LIBHW_W5500_LL_H_ -#define _LIBHW_W5500_LL_H_ +#ifndef _LIBHW_CR_W5500_LL_H_ +#define _LIBHW_CR_W5500_LL_H_ #include <alloca.h> /* for alloca() */ #include <stdint.h> /* for uint{n}_t */ @@ -93,39 +93,15 @@ w5500ll_writev( (uint8_t)(addr & 0xFF), (block & CTL_MASK_BLOCK) | CTL_W | CTL_OM_VDM, }; - struct duplex_iovec *inner = alloca(sizeof(struct duplex_iovec)*(iovcnt+1)); + int inner_cnt = 1+io_slice_cnt(iov, iovcnt, skip, max); + struct duplex_iovec *inner = alloca(sizeof(struct duplex_iovec)*inner_cnt); inner[0] = (struct duplex_iovec){ - .iov_read_dst = NULL, - .iov_write_src = header, - .iov_len = sizeof(header), + .iov_read_to = IOVEC_DISCARD, + .iov_write_from = header, + .iov_len = sizeof(header), }; - int j = 1; - size_t skipped = 0, done = 0; - for (int i = 0; i < iovcnt && (max == 0 || done < max); i++) { - if (skipped < skip) { - if (skip - skipped >= iov[i].iov_len) { - skipped += iov[i].iov_len; - continue; - } - inner[j] = (struct duplex_iovec){ - .iov_read_dst = NULL, - .iov_write_src = iov[i].iov_base+(skip-skipped), - .iov_len = iov[i].iov_len-(skip-skipped), - }; - skipped = skip; - } else { - inner[j] = (struct duplex_iovec){ - .iov_read_dst = NULL, - .iov_write_src = iov[i].iov_base, - .iov_len = iov[i].iov_len, - }; - } - done += inner[j].iov_len; - if (max > 0 && done > max) - inner[j].iov_len -= done - max; - j++; - }; - LO_CALL(spidev, readwritev, inner, j); + io_slice_wr_to_duplex(&inner[1], iov, iovcnt, skip, max); + LO_CALL(spidev, readwritev, inner, inner_cnt); } static inline void @@ -154,26 +130,15 @@ w5500ll_readv( (uint8_t)(addr & 0xFF), (block & CTL_MASK_BLOCK) | CTL_R | CTL_OM_VDM, }; - struct duplex_iovec *inner = alloca(sizeof(struct duplex_iovec)*(iovcnt+1)); + int inner_cnt = 1+io_slice_cnt(iov, iovcnt, 0, max); + struct duplex_iovec *inner = alloca(sizeof(struct duplex_iovec)*inner_cnt); inner[0] = (struct duplex_iovec){ - .iov_read_dst = NULL, - .iov_write_src = header, - .iov_len = sizeof(header), - }; - int j = 1; - size_t done = 0; - for (int i = 0; i < iovcnt && (max == 0 || done < max); i++) { - inner[j] = (struct duplex_iovec){ - .iov_read_dst = iov[i].iov_base, - .iov_write_src = NULL, - .iov_len = iov[i].iov_len, - }; - done += inner[j].iov_len; - if (max > 0 && done > max) - inner[j].iov_len -= done - max; - j++; + .iov_read_to = IOVEC_DISCARD, + .iov_write_from = header, + .iov_len = sizeof(header), }; - LO_CALL(spidev, readwritev, inner, j); + io_slice_rd_to_duplex(&inner[1], iov, iovcnt, 0, max); + LO_CALL(spidev, readwritev, inner, inner_cnt); } /* Common chip-wide registers. ***********************************************/ @@ -458,4 +423,4 @@ static_assert(sizeof(struct w5500ll_block_sock_reg) == 0x30); val; \ }) -#endif /* _LIBHW_W5500_LL_H_ */ +#endif /* _LIBHW_CR_W5500_LL_H_ */ diff --git a/libhw_generic/CMakeLists.txt b/libhw_generic/CMakeLists.txt index e38fbe9..5a6014b 100644 --- a/libhw_generic/CMakeLists.txt +++ b/libhw_generic/CMakeLists.txt @@ -8,10 +8,12 @@ target_include_directories(libhw_generic SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE target_link_libraries(libhw_generic INTERFACE libmisc libobj - libcr ) target_sources(libhw_generic INTERFACE alarmclock.c + io.c net.c ) + +add_lib_test(libhw_generic test_io) diff --git a/libhw_generic/alarmclock.c b/libhw_generic/alarmclock.c index 7fd049e..31fbbaf 100644 --- a/libhw_generic/alarmclock.c +++ b/libhw_generic/alarmclock.c @@ -1,25 +1,9 @@ -/* libhw_generic/alarmclock.c - Device-independent <libhw/generic/alarmclock.h> utilities +/* libhw_generic/alarmclock.c - Device-independent <libhw/generic/alarmclock.h> storage * * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ -#include <libcr/coroutine.h> - #include <libhw/generic/alarmclock.h> lo_interface alarmclock bootclock = {0}; - -static void alarmclock_sleep_intrhandler(void *_arg) { - cid_t cid = *(cid_t *)_arg; - cr_unpause_from_intrhandler(cid); -} - -void alarmclock_sleep_until_ns(lo_interface alarmclock clock, uint64_t abstime_ns) { - bool saved = cr_save_and_disable_interrupts(); - cid_t cid = cr_getcid(); - struct alarmclock_trigger trigger; - LO_CALL(clock, add_trigger, &trigger, abstime_ns, alarmclock_sleep_intrhandler, &cid); - cr_pause_and_yield(); - cr_restore_interrupts(saved); -} diff --git a/libhw_generic/include/libhw/generic/io.h b/libhw_generic/include/libhw/generic/io.h index a7f7378..7825c9f 100644 --- a/libhw_generic/include/libhw/generic/io.h +++ b/libhw_generic/include/libhw/generic/io.h @@ -8,6 +8,7 @@ #define _LIBHW_GENERIC_IO_H_ #include <stddef.h> /* for size_t */ +#include <stdint.h> /* for uintptr_t */ #include <sys/types.h> /* for ssize_t */ #include <libobj/obj.h> @@ -23,12 +24,35 @@ struct iovec { }; #endif +#define IOVEC_DISCARD ((void*)(~((uintptr_t)0))) + struct duplex_iovec { - void *iov_read_dst; - void *iov_write_src; + /** + * NULL is a valid pointer value in iov_read_to and + * iov_write_from. To skip a read or write, use the special + * value IOVEC_DISCARD. + */ + void *iov_read_to; + void *iov_write_from; size_t iov_len; }; +/* utilities ******************************************************************/ + +/* slice iovec lists */ +int io_slice_cnt ( const struct iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt); +void io_slice (struct iovec *dst, const struct iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt); +int io_duplex_slice_cnt( const struct duplex_iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt); +void io_duplex_slice (struct duplex_iovec *dst, const struct duplex_iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt); + +/* convert iovec lists */ +void io_rd_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int iovcnt); +void io_wr_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int iovcnt); + +/* slice and convert in one go */ +void io_slice_rd_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt); +void io_slice_wr_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt); + /* basic interfaces ***********************************************************/ /** diff --git a/libhw_generic/io.c b/libhw_generic/io.c new file mode 100644 index 0000000..4ebff10 --- /dev/null +++ b/libhw_generic/io.c @@ -0,0 +1,98 @@ +/* libhw_generic/io.c - Utilities for device-independent I/O definitions + * + * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libmisc/assert.h> + +#include <libhw/generic/io.h> + +#define IOV_ITER(ACTION) \ + assert(src_cnt >= 0); \ + assert(src_cnt == 0 || src); \ + \ + const size_t byte_end = byte_beg + byte_max_cnt; \ + int j = 0; \ + size_t byte_pos = 0; \ + for (int i = 0; \ + i < src_cnt && (byte_max_cnt == 0 || byte_pos < byte_end); \ + i++) { \ + size_t off = 0, len; \ + if (byte_pos < byte_beg) { \ + if (byte_beg - byte_pos >= src[i].iov_len) { \ + byte_pos += src[i].iov_len; \ + continue; \ + } \ + off = byte_beg-byte_pos; \ + len = src[i].iov_len-off; \ + byte_pos = byte_beg; \ + } else { \ + len = src[i].iov_len; \ + } \ + if (byte_max_cnt && byte_end - byte_pos < len) \ + len = byte_end - byte_pos; \ + do { ACTION } while (0); \ + byte_pos += len; \ + j++; \ + } + +int io_slice_cnt(const struct iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) { + IOV_ITER(); + return j; +} + +int io_duplex_slice_cnt(const struct duplex_iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) { + IOV_ITER(); + return j; +} + +void io_slice(struct iovec *dst, const struct iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) { + assert(src_cnt == 0 || dst); + IOV_ITER( + dst[j] = ((struct iovec){ + .iov_base = src[i].iov_base+off, + .iov_len = len, + }); + ); +} +void io_slice_duplex(struct duplex_iovec *dst, const struct duplex_iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) { + assert(src_cnt == 0 || dst); + IOV_ITER( + dst[j] = ((struct duplex_iovec){ + .iov_read_to = src[i].iov_read_to+off, + .iov_write_from = src[i].iov_write_from+off, + .iov_len = len, + }); + ); +} + +void io_slice_rd_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) { + assert(src_cnt == 0 || dst); + IOV_ITER( + dst[j] = ((struct duplex_iovec){ + .iov_read_to = src[i].iov_base+off, + .iov_write_from = IOVEC_DISCARD, + .iov_len = len, + }); + ); +} + +void io_slice_wr_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) { + assert(src_cnt == 0 || dst); + IOV_ITER( + dst[j] = ((struct duplex_iovec){ + .iov_read_to = IOVEC_DISCARD, + .iov_write_from = src[i].iov_base+off, + .iov_len = len, + }); + ); +} + +void io_rd_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int iovcnt) { + io_slice_rd_to_duplex(dst, src, iovcnt, 0, 0); +} + +void io_wr_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int iovcnt) { + io_slice_wr_to_duplex(dst, src, iovcnt, 0, 0); +} diff --git a/libhw_generic/tests/test.h b/libhw_generic/tests/test.h new file mode 120000 index 0000000..2fb1bd5 --- /dev/null +++ b/libhw_generic/tests/test.h @@ -0,0 +1 @@ +../../libmisc/tests/test.h
\ No newline at end of file diff --git a/libhw_generic/tests/test_io.c b/libhw_generic/tests/test_io.c new file mode 100644 index 0000000..0d6df11 --- /dev/null +++ b/libhw_generic/tests/test_io.c @@ -0,0 +1,57 @@ +/* libhw_generic/tests/test_io.c - Tests for <libmisc/io.h> + * + * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <string.h> + +#include <libhw/generic/io.h> + +#include "test.h" + +int main() { + char data[] = "abcdefghijklmnopqrstuvwxyz"; + struct iovec src[] = { + {.iov_base = &data[1], .iov_len=3}, /* "bcd" */ + {.iov_base = &data[20], .iov_len=4}, /* "uvwx" */ + }; + const int src_cnt = sizeof(src)/sizeof(src[0]); + + struct duplex_iovec dst[2]; + +#define TC(start, max, ...) do { \ + char *exp[] = {__VA_ARGS__}; \ + int exp_cnt = sizeof(exp)/sizeof(exp[0]); \ + int act_cnt = io_slice_cnt(src, src_cnt, start, max); \ + test_assert(act_cnt == exp_cnt); \ + memset(dst, 0, sizeof(dst)); \ + io_slice_wr_to_duplex(dst, src, src_cnt, start, max); \ + for (int i = 0; i < act_cnt; i++) { \ + test_assert(dst[i].iov_read_to == IOVEC_DISCARD); \ + test_assert(dst[i].iov_write_from != IOVEC_DISCARD); \ + test_assert(dst[i].iov_len == strlen(exp[i])); \ + test_assert(memcmp(dst[i].iov_write_from, exp[i], dst[i].iov_len) == 0); \ + } \ + } while (0) + + TC(0, 0, /* => */ "bcd", "uvwx"); + TC(1, 0, /* => */ "cd", "uvwx"); + TC(2, 0, /* => */ "d", "uvwx"); + TC(3, 0, /* => */ "uvwx"); + TC(4, 0, /* => */ "vwx"); + TC(5, 0, /* => */ "wx"); + TC(6, 0, /* => */ "x"); + TC(7, 0, /* => */ ); + + TC(0, 2, /* => */ "bc"); + TC(1, 2, /* => */ "cd"); + TC(2, 2, /* => */ "d", "u"); + TC(3, 2, /* => */ "uv"); + TC(4, 2, /* => */ "vw"); + TC(5, 2, /* => */ "wx"); + TC(6, 2, /* => */ "x"); + TC(7, 2, /* => */ ); + + return 0; +} |