diff options
56 files changed, 7254 insertions, 5176 deletions
diff --git a/.editorconfig b/.editorconfig index af47cbe..f907b33 100644 --- a/.editorconfig +++ b/.editorconfig @@ -30,13 +30,13 @@ _mode = markdown [*.9p{,.wip}] _mode = 9p -[{lib9p/tests/test_server/static.h.gen,build-aux/embed-sources.h.gen,build-aux/lint-{generic,unknown}}] +[{lib9p/tests/test_server/static.h.gen,build-aux/embed-sources.h.gen,build-aux/lint-{generic,unknown},lib9p/tests/test_compile.c.gen}] _mode = sh [{build-aux/lint-h,build-aux/lint-bin,build-aux/get-dscname,build-aux/linux-errno.txt.gen,libusb/include/libusb/tusb_helpers.h.gen,lib9p/tests/runtest}] _mode = bash -[{lib9p/idl.gen,lib9p/include/lib9p/linux-errno.h.gen,build-aux/stack.c.gen}] +[{lib9p/proto.gen,lib9p/include/lib9p/linux-errno.h.gen,build-aux/stack.c.gen}] _mode = python3 indent_style = space indent_size = 4 @@ -46,7 +46,13 @@ _mode = python3 indent_style = space indent_size = 4 -[{.editorconfig,.gitmodules}] +[requirements.txt] +_mode = pip + +[**/Documentation/**.txt] +_mode = man-cat + +[{.editorconfig,.gitmodules,.pylintrc}] _mode = ini [.gitignore] diff --git a/.gitmodules b/.gitmodules index d8d8265..8a4c874 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,8 +1,8 @@ # .gitmodules - Were to get some 3rd-party sources # -# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later [submodule "3rd-party/pico-sdk"] path = 3rd-party/pico-sdk - url = https://github.com/raspberrypi/pico-sdk + url = https://github.com/LukeShu/pico-sdk diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..944973f --- /dev/null +++ b/.pylintrc @@ -0,0 +1,40 @@ +# .pylintrc - Configuration for Pylint +# +# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +[MAIN] +analyse-fallback-blocks=yes +enable-all-extensions=yes +fail-on=all +#init-hook='sys.path.insert(0, os.path.normpath(os.path.join(__file__, "..")))' + +[MESSAGES CONTROL] + +disable=missing-module-docstring, + missing-class-docstring, + missing-function-docstring, + fixme, + line-too-long, + unused-argument, + too-few-public-methods, + invalid-name, + too-many-lines, + too-many-locals, + too-many-statements, + too-many-nested-blocks, + too-many-branches, + too-many-instance-attributes, + too-many-arguments, + too-many-positional-arguments, + too-many-return-statements, + global-statement, + import-outside-toplevel + +[REPORTS] +reports=no +score=no + +[VARIABLES] +allow-global-unused-variables=no +init-import=yes diff --git a/GNUmakefile b/GNUmakefile index 1311b6e..2d11c8b 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -42,9 +42,13 @@ lib9p/include/lib9p/linux-errno.h: %: %.gen 3rd-party/linux-errno.txt $^ >$@ generate/files += lib9p/9p.generated.c lib9p/include/lib9p/9p.generated.h -lib9p/9p.generated.c lib9p/include/lib9p/9p.generated.h &: lib9p/idl.gen lib9p/idl/__init__.py lib9p/idl lib9p/idl/*.9p +lib9p/9p.generated.c lib9p/include/lib9p/9p.generated.h &: lib9p/proto.gen lib9p/idl/__init__.py lib9p/protogen lib9p/protogen/*.py lib9p/idl lib9p/idl/*.9p $< $(filter %.9p,$^) +generate/files += lib9p/tests/test_compile.c +lib9p/tests/test_compile.c: %: %.gen lib9p/include/lib9p/9p.generated.h + $^ $@ + generate/files += libusb/include/libusb/tusb_helpers.h 3rd-party/MS-LCID.pdf 3rd-party/MS-LCID.txt libusb/include/libusb/tusb_helpers.h 3rd-party/MS-LCID.pdf 3rd-party/MS-LCID.txt &: libusb/include/libusb/tusb_helpers.h.gen $^ @@ -74,6 +78,9 @@ generate-clean: platforms := rp2040 host # $(shell sed -nE 's/if *\(PICO_PLATFORM STREQUAL "(.*)"\)/\1/p' cmd/*/CMakeLists.txt) build_types = Debug Release RelWithDebInfo MinSizeRel +export CTEST_PARALLEL_LEVEL = 0 +export CTEST_OUTPUT_ON_FAILURE = 1 + build: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build)) .PHONY: build @@ -89,7 +96,7 @@ check: build .PHONY: check $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check)): build/%/check: build/%/Makefile - CTEST_OUTPUT_ON_FAILURE=1 $(MAKE) -C $(<D) test + $(MAKE) -C $(<D) test .PHONY: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check)) # `lint` and `format` ########################################################## @@ -115,10 +122,11 @@ lint/python3: lint/%: build-aux/venv ./build-aux/venv/bin/mypy --strict --scripts-are-modules $(sources_$*) ./build-aux/venv/bin/black --check $(sources_$*) ./build-aux/venv/bin/isort --check $(sources_$*) - ! grep -nh 'SPECIAL$$' -- lib9p/idl.gen + ./build-aux/venv/bin/pylint $(sources_$*) + ! grep -nh 'SPECIAL$$' -- lib9p/proto.gen lib9p/protogen/*.py lint/c: lint/%: build-aux/lint-h build-aux/get-dscname ./build-aux/lint-h $(filter %.h,$(sources_$*)) -lint/make lint/cmake lint/gitignore lint/ini lint/9p lint/markdown: lint/%: +lint/make lint/cmake lint/gitignore lint/ini lint/9p lint/markdown lint/pip lint/man-cat: lint/%: @: lint/unknown: lint/%: build-aux/lint-unknown ./build-aux/lint-unknown $(sources_$*) @@ -136,7 +144,7 @@ format/sh format/bash: format/% @: format/c: format/%: @: TODO: Adopt a C code-formatter -format/make format/cmake format/gitignore format/ini format/9p format/markdown: format/%: +format/make format/cmake format/gitignore format/ini format/9p format/markdown format/pip format/man-cat: format/%: @: format/unknown: format/%: @: diff --git a/build-aux/lint-bin b/build-aux/lint-bin index 0b955de..78ed19f 100755 --- a/build-aux/lint-bin +++ b/build-aux/lint-bin @@ -25,7 +25,7 @@ RESET=$(tput sgr0) err() { printf "${RED}%s${RESET}: %s\n" "$1" "$2" >&2 - #r=1 + r=1 } # Input is `ld --print-map` format. @@ -104,7 +104,22 @@ lint_stack() { done < <( comm -3 \ <(sed -En 's/^included: (.*:)?//p' "${in_elffile%.elf}_stack.c" | sort -u) \ - <(readelf_funcs "$in_elffile" | sed 's/\.part\.[0-9]*$//' | sort -u)) + <(readelf_funcs "$in_elffile" | sed -E -e 's/\.part\.[0-9]*$//' -e 's/^__(.*)_veneer$/\1/' | sort -u)) +} + +lint_func_blocklist() { + local in_elffile + in_elffile=$1 + + local blocklist=( + gpio_default_irq_handler + ) + + while read -r func; do + err "$in_elffile" "Contains blocklisted function: ${func}" + done < <(readelf --syms --wide -- "$in_elffile" | + awk '$4 == "FUNC" { print $8 }' | + grep -Fx "${blocklist[@]/#/-e}") } main() { @@ -116,7 +131,8 @@ main() { echo 'Global variables:' lint_globals "${elf}.map" | sed 's/^/ /' } > "${elf%.elf}.lint.globals" - lint_stack "$elf" &> "${elf%.elf}.lint.stack" + (lint_stack "$elf") &> "${elf%.elf}.lint.stack" + lint_func_blocklist "$elf" done return $r diff --git a/build-aux/lint-unknown b/build-aux/lint-unknown index 3c2e91b..dda9541 100755 --- a/build-aux/lint-unknown +++ b/build-aux/lint-unknown @@ -7,4 +7,18 @@ RED=$(tput setaf 1) RESET=$(tput sgr0) -printf "${RED}%s${RESET}: cannot lint unknown file type\n" "$@" >&2 +err() { + printf "${RED}%s${RESET}: %s\n" "$1" "$2" >&2 + r=1 +} + +r=0 +for filename in "$@"; do + if ! { [ -f "$filename" ] && ! [ -h "$filename" ]; }; then + # Ignore non-files + continue + fi + + err "$filename" 'cannot lint unknown file type' +done +exit $r diff --git a/build-aux/requirements.txt b/build-aux/requirements.txt index 43a13be..fb76559 100644 --- a/build-aux/requirements.txt +++ b/build-aux/requirements.txt @@ -1,9 +1,10 @@ # build-aux/requirements.txt - List of Python dev requirements # -# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later mypy types-gdb>=15.0.0.20241204 # https://github.com/python/typeshed/pull/13169 black isort +pylint diff --git a/build-aux/stack.c.gen b/build-aux/stack.c.gen index edc7bae..a8e2149 100755 --- a/build-aux/stack.c.gen +++ b/build-aux/stack.c.gen @@ -71,7 +71,7 @@ def parse_vcg(reader: typing.TextIO) -> typing.Iterator[VCGElem]: k = m.group(1) v = m.group(2) if k in elem.attrs: - _raise(f"duplicate key: {repr(k)}") + _raise(f"duplicate key: {k!r}") if v.startswith('"'): def unesc(esc: re.Match[str]) -> str: @@ -83,12 +83,16 @@ def parse_vcg(reader: typing.TextIO) -> typing.Iterator[VCGElem]: case "\\": return "\\" case _: - _raise(f"invalid escape code {repr(esc.group(0))}") + _raise(f"invalid escape code {esc.group(0)!r}") v = re_esc.sub(unesc, v[1:-1]) elem.attrs[k] = v pos = m.end() + del _raise + del pos + del line + del lineno yield elem @@ -98,11 +102,58 @@ def parse_vcg(reader: typing.TextIO) -> typing.Iterator[VCGElem]: UsageKind: typing.TypeAlias = typing.Literal["static", "dynamic", "dynamic,bounded"] +class BaseName: + _content: str + + def __init__(self, content: str) -> None: + if ":" in content: + raise ValueError(f"invalid non-qualified name: {content!r}") + self._content = content + + def __str__(self) -> str: + return self._content + + def __eq__(self, other: typing.Any) -> bool: + assert isinstance(other, BaseName) + return self._content == other._content + + def __lt__(self, other: "BaseName") -> bool: + return self._content < other._content + + def __hash__(self) -> int: + return hash(self._content) + + +class QName: + _content: str + + def __init__(self, content: str) -> None: + self._content = content + + def __str__(self) -> str: + return self._content + + def __eq__(self, other: typing.Any) -> bool: + assert isinstance( + other, QName + ), f"comparing QName with {other.__class__.__name__}" + return self._content == other._content + + def __lt__(self, other: "QName") -> bool: + return self._content < other._content + + def __hash__(self) -> int: + return hash(self._content) + + def base(self) -> BaseName: + return BaseName(str(self).rsplit(":", 1)[-1].split(".", 1)[0]) + + class Node: # from .title (`static` and `__weak` functions are prefixed with # the compilation unit .c file. For static functions that's fine, # but we'll have to handle it specially for __weak.). - funcname: str + funcname: QName # .label is "{funcname}\n{location}\n{nstatic} bytes (static}\n{ndynamic} dynamic objects" location: str usage_kind: UsageKind @@ -111,51 +162,55 @@ class Node: # edges with .sourcename set to this node, val is if it's # OK/expected that the function be missing. - calls: dict[str, bool] + calls: dict[QName, bool] def synthetic_node( - name: str, nstatic: int, calls: typing.Collection[str] = set() + name: str, nstatic: int, calls: typing.Collection[str] = frozenset() ) -> Node: n = Node() - n.funcname = name + n.funcname = QName(name) n.location = "<synthetic>" n.usage_kind = "static" n.nstatic = nstatic n.ndynamic = 0 - n.calls = dict((c, False) for c in calls) + n.calls = dict((QName(c), False) for c in calls) return n +class AnalyzeResultVal(typing.NamedTuple): + nstatic: int + cnt: int + + class AnalyzeResultGroup(typing.NamedTuple): - rows: dict[str, int] - nmax: int - nsum: int + rows: dict[QName, AnalyzeResultVal] class AnalyzeResult(typing.NamedTuple): groups: dict[str, AnalyzeResultGroup] - missing: set[str] - dynamic: set[str] + missing: set[QName] + dynamic: set[QName] - included_funcs: set[str] + included_funcs: set[QName] class Application(typing.Protocol): def extra_nodes(self) -> typing.Collection[Node]: ... - def location_xform(self, loc: str) -> str: ... - def indirect_callees(self, elem: VCGElem) -> tuple[list[str], bool]: ... - def skip_call(self, chain: list[str], funcname: str) -> bool: ... + def indirect_callees( + self, elem: VCGElem + ) -> tuple[typing.Collection[QName], bool]: ... + def skip_call(self, chain: typing.Sequence[QName], funcname: QName) -> bool: ... def analyze( *, ci_fnames: typing.Collection[str], - app_func_filters: dict[str, typing.Callable[[str], int]], + app_func_filters: dict[str, typing.Callable[[QName], tuple[int, bool]]], app: Application, cfg_max_call_depth: int, ) -> AnalyzeResult: @@ -168,8 +223,8 @@ def analyze( flags=re.MULTILINE, ) - graph: dict[str, Node] = dict() - qualified: dict[str, set[str]] = dict() + graph: dict[QName, Node] = {} + qualified: dict[BaseName, set[QName]] = {} def handle_elem(elem: VCGElem) -> None: match elem.typ: @@ -180,14 +235,12 @@ def analyze( for k, v in elem.attrs.items(): match k: case "title": - node.funcname = v + node.funcname = QName(v) case "label": if elem.attrs.get("shape", "") != "ellipse": m = re_node_label.fullmatch(v) if not m: - raise ValueError( - f"unexpected label value {repr(v)}" - ) + raise ValueError(f"unexpected label value {v!r}") node.location = m.group("location") node.usage_kind = typing.cast( UsageKind, m.group("usage_kind") @@ -196,37 +249,37 @@ def analyze( node.ndynamic = int(m.group("ndynamic")) case "shape": if v != "ellipse": - raise ValueError(f"unexpected shape value {repr(v)}") + raise ValueError(f"unexpected shape value {v!r}") skip = True case _: - raise ValueError(f"unknown edge key {repr(k)}") + raise ValueError(f"unknown edge key {k!r}") if not skip: if node.funcname in graph: - raise ValueError(f"duplicate node {repr(node.funcname)}") + raise ValueError(f"duplicate node {str(node.funcname)!r}") graph[node.funcname] = node - if ":" in node.funcname: - _, shortname = node.funcname.rsplit(":", 1) - if shortname not in qualified: - qualified[shortname] = set() - qualified[shortname].add(node.funcname) + if ":" in str(node.funcname): + basename = node.funcname.base() + if basename not in qualified: + qualified[basename] = set() + qualified[basename].add(node.funcname) case "edge": - caller: str | None = None - callee: str | None = None + caller: QName | None = None + callee: QName | None = None for k, v in elem.attrs.items(): match k: case "sourcename": - caller = v + caller = QName(v) case "targetname": - callee = v + callee = QName(v) case "label": pass case _: - raise ValueError(f"unknown edge key {repr(k)}") + raise ValueError(f"unknown edge key {k!r}") if caller is None or callee is None: - raise ValueError(f"incomplete edge: {repr(elem.attrs)}") + raise ValueError(f"incomplete edge: {elem.attrs!r}") if caller not in graph: raise ValueError(f"unknown caller: {caller}") - if callee == "__indirect_call": + if str(callee) == "__indirect_call": callees, missing_ok = app.indirect_callees(elem) for callee in callees: if callee not in graph[caller].calls: @@ -234,87 +287,100 @@ def analyze( else: graph[caller].calls[callee] = False case _: - raise ValueError(f"unknown elem type {repr(elem.typ)}") + raise ValueError(f"unknown elem type {elem.typ!r}") for ci_fname in ci_fnames: - with open(ci_fname, "r") as fh: + with open(ci_fname, "r", encoding="utf-8") as fh: for elem in parse_vcg(fh): handle_elem(elem) for node in app.extra_nodes(): if node.funcname in graph: - raise ValueError(f"duplicate node {repr(node.funcname)}") + raise ValueError(f"duplicate node {str(node.funcname)!r}") graph[node.funcname] = node - missing: set[str] = set() - dynamic: set[str] = set() - included_funcs: set[str] = set() + missing: set[QName] = set() + dynamic: set[QName] = set() + included_funcs: set[QName] = set() dbg = False - def resolve_funcname(funcname: str) -> str | None: + def resolve_funcname(funcname: QName) -> QName | None: # Handle `ld --wrap` functions - if f"__wrap_{funcname}" in graph: - return f"__wrap_{funcname}" - if funcname.startswith("__real_") and funcname[len("__real_") :] in graph: - funcname = funcname[len("__real_") :] + if QName(f"__wrap_{funcname}") in graph: + return QName(f"__wrap_{funcname}") + if ( + str(funcname).startswith("__real_") + and QName(str(funcname)[len("__real_") :]) in graph + ): + funcname = QName(str(funcname)[len("__real_") :]) # Usual case - if funcname in graph: - return funcname + if QName(str(funcname)) in graph: + return QName(str(funcname)) # Handle `__weak` functions - if funcname in qualified and len(qualified[funcname]) == 1: - return sorted(qualified[funcname])[0] + if ( + ":" not in str(funcname) + and len(qualified.get(BaseName(str(funcname)), set())) == 1 + ): + return sorted(qualified[BaseName(str(funcname))])[0] return None + track_inclusion: bool = True + def nstatic( - orig_funcname: str, chain: list[str] = [], missing_ok: bool = False + orig_funcname: QName, + chain: typing.Sequence[QName] = (), + missing_ok: bool = False, ) -> int: nonlocal dbg + nonlocal track_inclusion funcname = resolve_funcname(orig_funcname) if not funcname: - if app.skip_call(chain, orig_funcname): + if chain and app.skip_call(chain, QName(str(orig_funcname))): + if dbg: + print(f"//dbg: {'- '*len(chain)}{orig_funcname}\tskip missing") return 0 if not missing_ok: missing.add(orig_funcname) + if dbg: + print(f"//dbg: {'- '*len(chain)}{orig_funcname}\tmissing") return 0 - if app.skip_call(chain, funcname): + if chain and app.skip_call(chain, funcname): + if dbg: + print(f"//dbg: {'- '*len(chain)}{orig_funcname}\tskip") return 0 if len(chain) == cfg_max_call_depth: - raise ValueError(f"max call depth exceeded: {chain+[funcname]}") + raise ValueError(f"max call depth exceeded: {[*chain, funcname]}") node = graph[funcname] if dbg: - print(f"//dbg: {funcname}\t{node.nstatic}") + print(f"//dbg: {'- '*len(chain)}{funcname}\t{node.nstatic}") if node.usage_kind == "dynamic" or node.ndynamic > 0: - dynamic.add(app.location_xform(funcname)) - included_funcs.add(funcname) + dynamic.add(funcname) + if track_inclusion: + included_funcs.add(funcname) return node.nstatic + max( [ 0, *[ - nstatic(call, chain + [funcname], missing_ok) + nstatic(call, [*chain, funcname], missing_ok) for call, missing_ok in node.calls.items() ], ] ) - groups: dict[str, AnalyzeResultGroup] = dict() + groups: dict[str, AnalyzeResultGroup] = {} for grp_name, grp_filter in app_func_filters.items(): - nmax = 0 - nsum = 0 - rows: dict[str, int] = {} + rows: dict[QName, AnalyzeResultVal] = {} for funcname in graph: - if cnt := grp_filter(funcname): - n = nstatic(funcname) - rows[app.location_xform(funcname)] = n - if n > nmax: - nmax = n - nsum += cnt * n - groups[grp_name] = AnalyzeResultGroup(rows=rows, nmax=nmax, nsum=nsum) + cnt, track_inclusion = grp_filter(funcname) + if cnt: + rows[funcname] = AnalyzeResultVal(nstatic=nstatic(funcname), cnt=cnt) + groups[grp_name] = AnalyzeResultGroup(rows=rows) return AnalyzeResult( groups=groups, missing=missing, dynamic=dynamic, included_funcs=included_funcs @@ -329,11 +395,11 @@ def read_source(location: str) -> str: re_location = re.compile(r"(?P<filename>.+):(?P<row>[0-9]+):(?P<col>[0-9]+)") m = re_location.fullmatch(location) if not m: - raise ValueError(f"unexpected label value {repr(location)}") + raise ValueError(f"unexpected label value {location!r}") filename = m.group("filename") row = int(m.group("row")) - 1 col = int(m.group("col")) - 1 - with open(m.group("filename"), "r") as fh: + with open(filename, "r", encoding="utf-8") as fh: return fh.readlines()[row][col:].rstrip() @@ -351,12 +417,24 @@ re_call_other = re.compile(r"(?P<func>[^(]+)\(.*") class Plugin(typing.Protocol): - def is_intrhandler(self, name: str) -> bool: ... + def is_intrhandler(self, name: QName) -> bool: ... + + # init_array returns a list of functions that are placed in the + # `.init_array.*` section; AKA functions marked with + # `__attribute__((constructor))`. + def init_array(self) -> typing.Collection[QName]: ... + + # extra_includes returns a list of functions that are never + # called, but are included in the binary anyway. This may because + # it is an unused method in a used vtable. This may be because it + # is an atexit() callback (we never exit). + def extra_includes(self) -> typing.Collection[str]: ... + def extra_nodes(self) -> typing.Collection[Node]: ... def indirect_callees( self, loc: str, line: str - ) -> tuple[list[str], bool] | None: ... - def skip_call(self, chain: list[str], call: str) -> bool: ... + ) -> tuple[typing.Collection[QName], bool] | None: ... + def skip_call(self, chain: typing.Sequence[QName], call: QName) -> bool: ... class PluginApplication: @@ -375,10 +453,7 @@ class PluginApplication: ret.extend(plugin.extra_nodes()) return ret - def location_xform(self, loc: str) -> str: - return self._location_xform(loc) - - def indirect_callees(self, elem: VCGElem) -> tuple[list[str], bool]: + def indirect_callees(self, elem: VCGElem) -> tuple[typing.Collection[QName], bool]: loc = elem.attrs.get("label", "") line = read_source(loc) @@ -390,10 +465,10 @@ class PluginApplication: placeholder = "__indirect_call" if m := re_call_other.fullmatch(line): placeholder += ":" + m.group("func") - placeholder += " at " + self.location_xform(elem.attrs.get("label", "")) - return [placeholder], False + placeholder += " at " + self._location_xform(elem.attrs.get("label", "")) + return [QName(placeholder)], False - def skip_call(self, chain: list[str], funcname: str) -> bool: + def skip_call(self, chain: typing.Sequence[QName], funcname: QName) -> bool: for plugin in self._plugins: if plugin.skip_call(chain, funcname): return True @@ -404,33 +479,36 @@ class PluginApplication: # Application-specific code -class AppPlugin: - def is_intrhandler(self, name: str) -> bool: - return name in [ - "rp2040_hwtimer_intrhandler", - "_cr_gdb_intrhandler", - "hostclock_handle_sig_alarm", - "hostnet_handle_sig_io", - ] +class CmdPlugin: + def is_intrhandler(self, name: QName) -> bool: + return False + + def init_array(self) -> typing.Collection[QName]: + return [] + + def extra_includes(self) -> typing.Collection[str]: + return [] def extra_nodes(self) -> typing.Collection[Node]: return [] - def indirect_callees(self, loc: str, line: str) -> tuple[list[str], bool] | None: + def indirect_callees( + self, loc: str, line: str + ) -> tuple[typing.Collection[QName], bool] | None: if "/3rd-party/" in loc: return None if "srv->auth" in line: return [], False if "srv->rootdir" in line: - return ["get_root"], False + return [QName("get_root")], False return None - def skip_call(self, chain: list[str], call: str) -> bool: + def skip_call(self, chain: typing.Sequence[QName], call: QName) -> bool: return False class LibObjPlugin: - objcalls: dict[str, set[str]] # method_name => {method_impls} + objcalls: dict[str, set[QName]] # method_name => {method_impls} def __init__(self, arg_c_fnames: typing.Collection[str]) -> None: ifaces: dict[str, set[str]] = {} # iface_name => {method_names} @@ -439,7 +517,7 @@ class LibObjPlugin: re_lo_iface = re.compile(r"^\s*#\s*define\s+(?P<name>\S+)_LO_IFACE") re_lo_func = re.compile(r"LO_FUNC *\([^,]*, *(?P<name>[^,) ]+) *[,)]") for fname in arg_c_fnames: - with open(fname, "r") as fh: + with open(fname, "r", encoding="utf-8") as fh: while line := fh.readline(): if m := re_lo_iface.match(line): iface_name = m.group("name") @@ -460,98 +538,174 @@ class LibObjPlugin: r"^LO_IMPLEMENTATION_[HC]\s*\(\s*(?P<iface>[^, ]+)\s*,\s*(?P<impl_typ>[^,]+)\s*,\s*(?P<impl_name>[^, ]+)\s*[,)].*" ) for fname in arg_c_fnames: - with open(fname, "r") as fh: + with open(fname, "r", encoding="utf-8") as fh: for line in fh: line = line.strip() if m := re_lo_implementation.match(line): implementations[m.group("iface")].add(m.group("impl_name")) - objcalls: dict[str, set[str]] = {} # method_name => {method_impls} - for iface_name in ifaces: - for method_name in ifaces[iface_name]: + objcalls: dict[str, set[QName]] = {} # method_name => {method_impls} + for iface_name, iface in ifaces.items(): + for method_name in iface: if method_name not in objcalls: objcalls[method_name] = set() for impl_name in implementations[iface_name]: - objcalls[method_name].add(impl_name + "_" + method_name) + objcalls[method_name].add(QName(impl_name + "_" + method_name)) self.objcalls = objcalls - def is_intrhandler(self, name: str) -> bool: + def is_intrhandler(self, name: QName) -> bool: return False + def init_array(self) -> typing.Collection[QName]: + return [] + + def extra_includes(self) -> typing.Collection[str]: + return [] + def extra_nodes(self) -> typing.Collection[Node]: return [] - def indirect_callees(self, loc: str, line: str) -> tuple[list[str], bool] | None: + def indirect_callees( + self, loc: str, line: str + ) -> tuple[typing.Collection[QName], bool] | None: re_call_objcall = re.compile(r"LO_CALL\((?P<obj>[^,]+), (?P<meth>[^,)]+)[,)].*") if "/3rd-party/" in loc: return None if m := re_call_objcall.fullmatch(line): if m.group("meth") in self.objcalls: - return sorted(self.objcalls[m.group("meth")]), False + return self.objcalls[m.group("meth")], False return [ - f"__indirect_call:{m.group('obj')}.vtable->{m.group('meth')}" + QName(f"__indirect_call:{m.group('obj')}.vtable->{m.group('meth')}") ], False return None - def skip_call(self, chain: list[str], call: str) -> bool: + def skip_call(self, chain: typing.Sequence[QName], call: QName) -> bool: return False class LibHWPlugin: pico_platform: str + libobj: LibObjPlugin - def __init__(self, arg_pico_platform: str) -> None: + def __init__(self, arg_pico_platform: str, libobj: LibObjPlugin) -> None: self.pico_platform = arg_pico_platform + self.libobj = libobj - def is_intrhandler(self, name: str) -> bool: - return False + def is_intrhandler(self, name: QName) -> bool: + return str(name.base()) in [ + "rp2040_hwtimer_intrhandler", + "hostclock_handle_sig_alarm", + "hostnet_handle_sig_io", + "gpioirq_handler", + "dmairq_handler", + ] + + def init_array(self) -> typing.Collection[QName]: + return [] + + def extra_includes(self) -> typing.Collection[str]: + return [] def extra_nodes(self) -> typing.Collection[Node]: return [] - def indirect_callees(self, loc: str, line: str) -> tuple[list[str], bool] | None: + def indirect_callees( + self, loc: str, line: str + ) -> tuple[typing.Collection[QName], bool] | None: if "/3rd-party/" in loc: return None + for fn in ( + "io_readv", + "io_writev", + "io_close", + "io_close_read", + "io_close_write", + "io_readwritev", + ): + if f"{fn}(" in line: + return self.libobj.indirect_callees(loc, f"LO_CALL(x, {fn[3:]})") + if "io_read(" in line: + return self.libobj.indirect_callees(loc, "LO_CALL(x, readv)") + if "io_writev(" in line: + return self.libobj.indirect_callees(loc, "LO_CALL(x, writev)") if "trigger->cb(trigger->cb_arg)" in line: ret = [ - "alarmclock_sleep_intrhandler", + QName("alarmclock_sleep_intrhandler"), ] if self.pico_platform == "rp2040": ret += [ - "w5500_tcp_alarm_handler", - "w5500_udp_alarm_handler", + QName("w5500_tcp_alarm_handler"), + QName("w5500_udp_alarm_handler"), ] return ret, False + if "/rp2040_gpioirq.c:" in loc and "handler->fn" in line: + return [ + QName("w5500_intrhandler"), + ], False + if "/rp2040_dma.c:" in loc and "handler->fn" in line: + return [ + QName("rp2040_hwspi_intrhandler"), + ], False + return None + + def skip_call(self, chain: typing.Sequence[QName], call: QName) -> bool: + return False + + +class LibCRPlugin: + def is_intrhandler(self, name: QName) -> bool: + return str(name.base()) in ("_cr_gdb_intrhandler",) + + def init_array(self) -> typing.Collection[QName]: + return [] + + def extra_includes(self) -> typing.Collection[str]: + return [] + + def extra_nodes(self) -> typing.Collection[Node]: + return [] + + def indirect_callees( + self, loc: str, line: str + ) -> tuple[typing.Collection[QName], bool] | None: return None - def skip_call(self, chain: list[str], call: str) -> bool: + def skip_call(self, chain: typing.Sequence[QName], call: QName) -> bool: return False class LibCRIPCPlugin: - def is_intrhandler(self, name: str) -> bool: + def is_intrhandler(self, name: QName) -> bool: return False + def init_array(self) -> typing.Collection[QName]: + return [] + + def extra_includes(self) -> typing.Collection[str]: + return [] + def extra_nodes(self) -> typing.Collection[Node]: return [] - def indirect_callees(self, loc: str, line: str) -> tuple[list[str], bool] | None: + def indirect_callees( + self, loc: str, line: str + ) -> tuple[typing.Collection[QName], bool] | None: if "/3rd-party/" in loc: return None if "/chan.c:" in loc and "front->dequeue(" in line: return [ - "_cr_chan_dequeue", - "_cr_select_dequeue", + QName("_cr_chan_dequeue"), + QName("_cr_select_dequeue"), ], False return None - def skip_call(self, chain: list[str], call: str) -> bool: + def skip_call(self, chain: typing.Sequence[QName], call: QName) -> bool: return False class Lib9PPlugin: - tmessage_handlers: set[str] | None + tmessage_handlers: set[QName] | None lib9p_msgs: set[str] _CONFIG_9P_NUM_SOCKS: int | None CONFIG_9P_SRV_MAX_REQS: int | None @@ -582,7 +736,7 @@ class Lib9PPlugin: def config_h_get(varname: str) -> int | None: if config_h_fname: - with open(config_h_fname, "r") as fh: + with open(config_h_fname, "r", encoding="utf-8") as fh: for line in fh: line = line.rstrip() if line.startswith("#define"): @@ -597,23 +751,23 @@ class Lib9PPlugin: # Read sources ######################################################### - tmessage_handlers: set[str] | None = None + tmessage_handlers: set[QName] | None = None if lib9p_srv_c_fname: re_tmessage_handler = re.compile( r"^\s*\[LIB9P_TYP_T[^]]+\]\s*=\s*\(tmessage_handler\)\s*(?P<handler>\S+),\s*$" ) tmessage_handlers = set() - with open(lib9p_srv_c_fname, "r") as fh: + with open(lib9p_srv_c_fname, "r", encoding="utf-8") as fh: for line in fh: line = line.rstrip() if m := re_tmessage_handler.fullmatch(line): - tmessage_handlers.add(m.group("handler")) + tmessage_handlers.add(QName(m.group("handler"))) self.tmessage_handlers = tmessage_handlers lib9p_msgs: set[str] = set() if lib9p_generated_c_fname: re_lib9p_msg_entry = re.compile(r"^\s*_MSG_(?:[A-Z]+)\((?P<typ>\S+)\),$") - with open(lib9p_generated_c_fname, "r") as fh: + with open(lib9p_generated_c_fname, "r", encoding="utf-8") as fh: for line in fh: line = line.rstrip() if m := re_lib9p_msg_entry.fullmatch(line): @@ -621,22 +775,30 @@ class Lib9PPlugin: lib9p_msgs.add(typ) self.lib9p_msgs = lib9p_msgs - def thread_count(self, name: str) -> int: + def thread_count(self, name: QName) -> int: assert self._CONFIG_9P_NUM_SOCKS assert self.CONFIG_9P_SRV_MAX_REQS - if "read" in name: + if "read" in str(name.base()): return self._CONFIG_9P_NUM_SOCKS - elif "write" in name: + if "write" in str(name.base()): return self._CONFIG_9P_NUM_SOCKS * self.CONFIG_9P_SRV_MAX_REQS return 1 - def is_intrhandler(self, name: str) -> bool: + def is_intrhandler(self, name: QName) -> bool: return False + def init_array(self) -> typing.Collection[QName]: + return [] + + def extra_includes(self) -> typing.Collection[str]: + return [] + def extra_nodes(self) -> typing.Collection[Node]: return [] - def indirect_callees(self, loc: str, line: str) -> tuple[list[str], bool] | None: + def indirect_callees( + self, loc: str, line: str + ) -> tuple[typing.Collection[QName], bool] | None: if "/3rd-party/" in loc: return None if ( @@ -645,101 +807,171 @@ class Lib9PPlugin: and "tmessage_handlers[typ](" in line ): # Functions for disabled protocol extensions will be missing. - return sorted(self.tmessage_handlers), True + return self.tmessage_handlers, True if self.lib9p_msgs and "/9p.c:" in loc: for meth in ["validate", "unmarshal", "marshal"]: if line.startswith(f"tentry.{meth}("): # Functions for disabled protocol extensions will be missing. - return sorted(f"{meth}_{msg}" for msg in self.lib9p_msgs), True + return [QName(f"{meth}_{msg}") for msg in self.lib9p_msgs], True return None - def skip_call(self, chain: list[str], call: str) -> bool: - if "lib9p/srv.c:srv_util_pathfree" in call: + def skip_call(self, chain: typing.Sequence[QName], call: QName) -> bool: + if "lib9p/srv.c:srv_util_pathfree" in str(call): assert isinstance(self.CONFIG_9P_SRV_MAX_DEPTH, int) if len(chain) >= self.CONFIG_9P_SRV_MAX_DEPTH and all( - ("lib9p/srv.c:srv_util_pathfree" in c) + ("lib9p/srv.c:srv_util_pathfree" in str(c)) for c in chain[-self.CONFIG_9P_SRV_MAX_DEPTH :] ): return True re_msg_meth = re.compile( r"^lib9p_(?P<grp>[TR])msg_(?P<meth>validate|unmarshal|marshal)$" ) - wrapper = next((c for c in chain if re_msg_meth.match(c)), None) + wrapper = next((c for c in chain if re_msg_meth.match(str(c))), None) if wrapper: - m = re_msg_meth.match(wrapper) + m = re_msg_meth.match(str(wrapper)) assert m - deny = ":" + m.group("meth") + "_" + ("R" if m.group("grp") == "T" else "T") - if deny in call: + deny = m.group("meth") + "_" + ("R" if m.group("grp") == "T" else "T") + if str(call.base()).startswith(deny): return True return False class LibMiscPlugin: - def is_intrhandler(self, name: str) -> bool: + def is_intrhandler(self, name: QName) -> bool: return False + def init_array(self) -> typing.Collection[QName]: + return [] + + def extra_includes(self) -> typing.Collection[str]: + return [] + def extra_nodes(self) -> typing.Collection[Node]: return [] - def indirect_callees(self, loc: str, line: str) -> tuple[list[str], bool] | None: + def indirect_callees( + self, loc: str, line: str + ) -> tuple[typing.Collection[QName], bool] | None: return None - def skip_call(self, chain: list[str], call: str) -> bool: + def skip_call(self, chain: typing.Sequence[QName], call: QName) -> bool: if ( len(chain) > 1 - and chain[-1] == "__assert_msg_fail" - and call.endswith(":__lm_printf") - and "__assert_msg_fail" in chain[:-1] + and str(chain[-1].base()) == "__assert_msg_fail" + and str(call.base()) == "__lm_printf" + and any(str(c.base()) == "__assert_msg_fail" for c in chain[:-1]) ): return True return False +class PicoFmtPlugin: + known_out: dict[str, str] + known_fct: dict[str, str] + + def __init__(self) -> None: + self.known_out = { + "": "_out_null", # XXX + "__wrap_sprintf": "_out_buffer", + "__wrap_snprintf": "_out_buffer", + "__wrap_vsnprintf": "_out_buffer", + "vfctprintf": "_out_fct", + } + self.known_fct = { + "stdio_vprintf": "stdio_buffered_printer", + "__wrap_vprintf": "stdio_buffered_printer", + } + + def is_intrhandler(self, name: QName) -> bool: + return False + + def init_array(self) -> typing.Collection[QName]: + return [] + + def extra_includes(self) -> typing.Collection[str]: + return [] + + def extra_nodes(self) -> typing.Collection[Node]: + return [] + + def indirect_callees( + self, loc: str, line: str + ) -> tuple[typing.Collection[QName], bool] | None: + if "/3rd-party/pico-sdk/" not in loc: + return None + if "/printf.c:" in loc: + m = re_call_other.fullmatch(line) + call: str | None = m.group("func") if m else None + if call == "out": + return [QName(x) for x in self.known_out.values()], False + if "->fct" in line: + return [QName(x) for x in self.known_fct.values()], False + return None + + def skip_call(self, chain: typing.Sequence[QName], call: QName) -> bool: + if str(call.base()) in self.known_out.values(): + out = "" + for pcall in chain: + if str(pcall.base()) in self.known_out: + out = self.known_out[str(pcall.base())] + if ( + out == "_out_buffer" and str(call.base()) == "_out_null" + ): # XXX: Gross hack + out = "_out_null" + return str(call.base()) != out + if str(call.base()) in self.known_fct.values(): + fct = "" + for pcall in chain: + if str(pcall.base()) in self.known_fct: + fct = self.known_fct[str(pcall.base())] + return str(call.base()) != fct + return False + + class PicoSDKPlugin: - app_gpio_handlers: typing.Collection[str] - app_init_array: typing.Collection[str] - app_preinit_array: typing.Collection[str] + get_init_array: typing.Callable[[], typing.Collection[QName]] + app_init_array: typing.Collection[QName] | None + app_preinit_array: typing.Collection[QName] def __init__( self, *, - app_gpio_handlers: typing.Collection[str], - app_init_array: typing.Collection[str], + get_init_array: typing.Callable[[], typing.Collection[QName]], ) -> None: - self.app_gpio_handlers = app_gpio_handlers - self.app_init_array = app_init_array + # grep for '__attribute__((constructor))'. + self.get_init_array = get_init_array + self.app_init_array = None # git grep '^PICO_RUNTIME_INIT_FUNC\S*(' self.app_preinit_array = [ - # "runtime_init_mutex", # pico_mutex - # "runtime_init_default_alarm_pool", # pico_time - # "runtime_init_boot_locks_reset", # hardware_boot_lock - "runtime_init_per_core_irq_priorities", # hardware_irq - # "spinlock_set_extexclall", # hardware_sync_spin_lock - "__aeabi_bits_init", # pico_bit_ops - # "runtime_init_bootrom_locking_enable", # pico_bootrom, rp2350-only - # "runtime_init_pre_core_tls_setup", # pico_clib_interface, picolibc-only - # "__aeabi_double_init", # pico_double - # "__aeabi_float_init", # pico_float - "__aeabi_mem_init", # pico_mem_ops - "first_per_core_initializer", # pico_runtime + # QName("runtime_init_mutex"), # pico_mutex + # QName("runtime_init_default_alarm_pool"), # pico_time + # QName("runtime_init_boot_locks_reset"), # hardware_boot_lock + QName("runtime_init_per_core_irq_priorities"), # hardware_irq + # QName("spinlock_set_extexclall"), # hardware_sync_spin_lock + QName("__aeabi_bits_init"), # pico_bit_ops + # QName("runtime_init_bootrom_locking_enable"), # pico_bootrom, rp2350-only + # QName("runtime_init_pre_core_tls_setup"), # pico_clib_interface, picolibc-only + # QName("__aeabi_double_init"), # pico_double + # QName("__aeabi_float_init"), # pico_float + QName("__aeabi_mem_init"), # pico_mem_ops + QName("first_per_core_initializer"), # pico_runtime # pico_runtime_init - # "runtime_init_bootrom_reset", # rp2350-only - # "runtime_init_per_core_bootrom_reset", # rp2350-only - # "runtime_init_per_core_h3_irq_registers", # rp2350-only - "runtime_init_early_resets", - "runtime_init_usb_power_down", - # "runtime_init_per_core_enable_coprocessors", # PICO_RUNTIME_SKIP_INIT_PER_CORE_ENABLE_COPROCESSORS - "runtime_init_clocks", - "runtime_init_post_clock_resets", - "runtime_init_rp2040_gpio_ie_disable", - "runtime_init_spin_locks_reset", - "runtime_init_install_ram_vector_table", + # QName("runtime_init_bootrom_reset"), # rp2350-only + # QName("runtime_init_per_core_bootrom_reset"), # rp2350-only + # QName("runtime_init_per_core_h3_irq_registers"), # rp2350-only + QName("runtime_init_early_resets"), + QName("runtime_init_usb_power_down"), + # QName("runtime_init_per_core_enable_coprocessors"), # PICO_RUNTIME_SKIP_INIT_PER_CORE_ENABLE_COPROCESSORS + QName("runtime_init_clocks"), + QName("runtime_init_post_clock_resets"), + QName("runtime_init_rp2040_gpio_ie_disable"), + QName("runtime_init_spin_locks_reset"), + QName("runtime_init_install_ram_vector_table"), ] - def is_intrhandler(self, name: str) -> bool: - return name in [ - "gpio_default_irq_handler", + def is_intrhandler(self, name: QName) -> bool: + return str(name.base()) in [ "isr_invalid", "isr_nmi", "isr_hardfault", @@ -749,7 +981,15 @@ class PicoSDKPlugin: *[f"isr_irq{n}" for n in range(32)], ] - def indirect_callees(self, loc: str, line: str) -> tuple[list[str], bool] | None: + def init_array(self) -> typing.Collection[QName]: + return [] + + def extra_includes(self) -> typing.Collection[str]: + return [] + + def indirect_callees( + self, loc: str, line: str + ) -> tuple[typing.Collection[QName], bool] | None: if "/3rd-party/pico-sdk/" not in loc or "/3rd-party/pico-sdk/lib/" in loc: return None m = re_call_other.fullmatch(line) @@ -757,65 +997,44 @@ class PicoSDKPlugin: match call: case "connect_internal_flash_func": - return ["rom_func_lookup(ROM_FUNC_CONNECT_INTERNAL_FLASH)"], False + return [ + QName("rom_func_lookup(ROM_FUNC_CONNECT_INTERNAL_FLASH)") + ], False case "flash_exit_xip_func": - return ["rom_func_lookup(ROM_FUNC_FLASH_EXIT_XIP)"], False + return [QName("rom_func_lookup(ROM_FUNC_FLASH_EXIT_XIP)")], False case "flash_range_erase_func": - return ["rom_func_lookup(ROM_FUNC_FLASH_RANGE_ERASE)"], False + return [QName("rom_func_lookup(ROM_FUNC_FLASH_RANGE_ERASE)")], False case "flash_flush_cache_func": - return ["rom_func_lookup(ROM_FUNC_FLASH_FLUSH_CACHE)"], False + return [QName("rom_func_lookup(ROM_FUNC_FLASH_FLUSH_CACHE)")], False case "rom_table_lookup": - return ["rom_hword_as_ptr(BOOTROM_TABLE_LOOKUP_OFFSET)"], False + return [QName("rom_hword_as_ptr(BOOTROM_TABLE_LOOKUP_OFFSET)")], False if "/flash.c:" in loc and "boot2_copyout" in line: - return ["_stage2_boot"], False - if "/gpio.c:" in loc and call == "callback": - return sorted(self.app_gpio_handlers), False - if "/printf.c:" in loc: - if call == "out": - return [ - "_out_buffer", - "_out_null", - "_out_fct", - ], False - if "->fct(" in line: - return ["stdio_buffered_printer"], False + return [QName("_stage2_boot")], False if "/stdio.c:" in loc: if call == "out_func": return [ - "stdio_out_chars_crlf", - "stdio_out_chars_no_crlf", + QName("stdio_out_chars_crlf"), + QName("stdio_out_chars_no_crlf"), ], False if call and (call.startswith("d->") or call.startswith("driver->")): _, meth = call.split("->", 1) match meth: case "out_chars": - return ["stdio_uart_out_chars"], False + return [QName("stdio_uart_out_chars")], False case "out_flush": - return ["stdio_uart_out_flush"], False + return [QName("stdio_uart_out_flush")], False case "in_chars": - return ["stdio_uart_in_chars"], False + return [QName("stdio_uart_in_chars")], False if "/newlib_interface.c:" in loc: if line == "*p)();": - return sorted(self.app_init_array), False + if self.app_init_array is None: + self.app_init_array = self.get_init_array() + return self.app_init_array, False if "/pico_runtime/runtime.c:" in loc: - return sorted(self.app_preinit_array), False + return self.app_preinit_array, False return None - def skip_call(self, chain: list[str], call: str) -> bool: - if call == "_out_buffer" or call == "_out_fct": - last = "" - for pcall in chain: - if pcall in [ - "__wrap_sprintf", - "__wrap_snprintf", - "__wrap_vsnprintf", - "vfctprintf", - ]: - last = pcall - if last == "vfctprintf": - return call != "_out_fct" - else: - return call == "_out_buffer" + def skip_call(self, chain: typing.Sequence[QName], call: QName) -> bool: return False def extra_nodes(self) -> typing.Collection[Node]: @@ -836,7 +1055,8 @@ class PicoSDKPlugin: synthetic_node("isr_svcall", 0, {"__unhandled_user_irq"}), synthetic_node("isr_pendsv", 0, {"__unhandled_user_irq"}), synthetic_node("isr_systick", 0, {"__unhandled_user_irq"}), - synthetic_node(f"__unhandled_user_irq", 0), + synthetic_node("__unhandled_user_irq", 0), + synthetic_node("_entry_point", 0, {"_reset_handler"}), synthetic_node("_reset_handler", 0, {"runtime_init", "main", "exit"}), ] @@ -948,7 +1168,7 @@ class PicoSDKPlugin: class TinyUSBDevicePlugin: - tud_drivers: dict[str, set[str]] + tud_drivers: dict[str, set[QName]] # method_name => {method_impls} def __init__(self, arg_c_fnames: typing.Collection[str]) -> None: usbd_c_fname = get_zero_or_one( @@ -968,7 +1188,7 @@ class TinyUSBDevicePlugin: r"^\s*#\s*define\s+(?P<k>CFG_TUD_(?:\S{3}|AUDIO|VIDEO|MIDI|VENDOR|USBTMC|DFU_RUNTIME|ECM_RNDIS))\s+(?P<v>\S+).*" ) tusb_config: dict[str, bool] = {} - with open(tusb_config_h_fname, "r") as fh: + with open(tusb_config_h_fname, "r", encoding="utf-8") as fh: in_table = False for line in fh: line = line.rstrip() @@ -977,14 +1197,14 @@ class TinyUSBDevicePlugin: v = m.group("v") tusb_config[k] = bool(int(v)) - tud_drivers: dict[str, set[str]] = {} + tud_drivers: dict[str, set[QName]] = {} re_tud_entry = re.compile( r"^\s+\.(?P<meth>\S+)\s*=\s*(?P<impl>[a-zA-Z0-9_]+)(?:,.*)?" ) re_tud_if1 = re.compile(r"^\s*#\s*if (\S+)\s*") re_tud_if2 = re.compile(r"^\s*#\s*if (\S+)\s*\|\|\s*(\S+)\s*") re_tud_endif = re.compile(r"^\s*#\s*endif\s*") - with open(usbd_c_fname, "r") as fh: + with open(usbd_c_fname, "r", encoding="utf-8") as fh: in_table = False enabled = True for line in fh: @@ -1004,20 +1224,28 @@ class TinyUSBDevicePlugin: if meth not in tud_drivers: tud_drivers[meth] = set() if impl != "NULL": - tud_drivers[meth].add(impl) + tud_drivers[meth].add(QName(impl)) if line.startswith("}"): in_table = False elif " _usbd_driver[] = {" in line: in_table = True self.tud_drivers = tud_drivers - def is_intrhandler(self, name: str) -> bool: + def is_intrhandler(self, name: QName) -> bool: return False + def init_array(self) -> typing.Collection[QName]: + return [] + + def extra_includes(self) -> typing.Collection[str]: + return [] + def extra_nodes(self) -> typing.Collection[Node]: return [] - def indirect_callees(self, loc: str, line: str) -> tuple[list[str], bool] | None: + def indirect_callees( + self, loc: str, line: str + ) -> tuple[typing.Collection[QName], bool] | None: if "/tinyusb/" not in loc or "/tinyusb/src/host/" in loc or "_host.c:" in loc: return None m = re_call_other.fullmatch(line) @@ -1026,25 +1254,34 @@ class TinyUSBDevicePlugin: if call == "_ctrl_xfer.complete_cb": return [ # "process_test_mode_cb", - "tud_vendor_control_xfer_cb", + QName("tud_vendor_control_xfer_cb"), *sorted(self.tud_drivers["control_xfer_cb"]), ], False - elif call.startswith("driver->"): + if call.startswith("driver->"): return sorted(self.tud_drivers[call[len("driver->") :]]), False - elif call == "event.func_call.func": + if call == "event.func_call.func": # callback from usb_defer_func() return [], False return None - def skip_call(self, chain: list[str], call: str) -> bool: + def skip_call(self, chain: typing.Sequence[QName], call: QName) -> bool: return False class NewlibPlugin: - def is_intrhandler(self, name: str) -> bool: + def is_intrhandler(self, name: QName) -> bool: return False + def init_array(self) -> typing.Collection[QName]: + return [QName("register_fini")] + + def extra_includes(self) -> typing.Collection[str]: + return [ + # register_fini() calls atexit(__libc_fini_array) + "__libc_fini_array", + ] + def extra_nodes(self) -> typing.Collection[Node]: # This is accurate to # /usr/arm-none-eabi/lib/thumb/v6-m/nofp/libg.a as of @@ -1078,33 +1315,54 @@ class NewlibPlugin: synthetic_node("_getpid_r", 8, {"_getpid"}), synthetic_node("random", 8), synthetic_node("register_fini", 8, {"atexit"}), + synthetic_node("atexit", 8, {"__register_exitproc"}), + synthetic_node( + "__register_exitproc", + 32, + { + "__retarget_lock_acquire_recursive", + "__retarget_lock_release_recursive", + }, + ), + synthetic_node("__libc_fini_array", 16, {"_fini"}), ] - def indirect_callees(self, loc: str, line: str) -> tuple[list[str], bool] | None: + def indirect_callees( + self, loc: str, line: str + ) -> tuple[typing.Collection[QName], bool] | None: return None - def skip_call(self, chain: list[str], call: str) -> bool: + def skip_call(self, chain: typing.Sequence[QName], call: QName) -> bool: return False class LibGCCPlugin: - def is_intrhandler(self, name: str) -> bool: + def is_intrhandler(self, name: QName) -> bool: return False + def init_array(self) -> typing.Collection[QName]: + return [] + + def extra_includes(self) -> typing.Collection[str]: + return [] + def extra_nodes(self) -> typing.Collection[Node]: - # This is accurate to - # /usr/lib/gcc/arm-none-eabi/14.2.0/thumb/v6-m/nofp/libgcc.a - # as of Parabola's arm-none-eabi-gcc 14.2.0-1. + # This is accurate to Parabola's arm-none-eabi-gcc 14.2.0-1. return [ + # /usr/lib/gcc/arm-none-eabi/14.2.0/thumb/v6-m/nofp/libgcc.a synthetic_node("__aeabi_idiv0", 0), synthetic_node("__aeabi_ldiv0", 0), synthetic_node("__aeabi_llsr", 0), + # /usr/lib/gcc/arm-none-eabi/14.2.0/thumb/v6-m/nofp/crti.o + synthetic_node("_fini", 24), ] - def indirect_callees(self, loc: str, line: str) -> tuple[list[str], bool] | None: + def indirect_callees( + self, loc: str, line: str + ) -> tuple[typing.Collection[QName], bool] | None: return None - def skip_call(self, chain: list[str], call: str) -> bool: + def skip_call(self, chain: typing.Sequence[QName], call: QName) -> bool: return False @@ -1122,23 +1380,26 @@ def main( lib9p_plugin = Lib9PPlugin(arg_base_dir, arg_c_fnames) - sbc_gpio_handlers = [ - "w5500_intrhandler", - ] - - def sbc_is_thread(name: str) -> int: - if name.endswith("_cr") and name != "lib9p_srv_read_cr": - if "9p" in name: + def sbc_is_thread(name: QName) -> int: + if str(name).endswith("_cr") and str(name.base()) != "lib9p_srv_read_cr": + if "9p" in str(name.base()) or "lib9p/tests/test_server/main.c:" in str( + name + ): return lib9p_plugin.thread_count(name) return 1 - if name == ("_reset_handler" if arg_pico_platform == "rp2040" else "main"): + if str(name.base()) == ( + "_entry_point" if arg_pico_platform == "rp2040" else "main" + ): return 1 return 0 + libobj_plugin = LibObjPlugin(arg_c_fnames) + plugins += [ - AppPlugin(), - LibObjPlugin(arg_c_fnames), - LibHWPlugin(arg_pico_platform), + CmdPlugin(), + libobj_plugin, + LibHWPlugin(arg_pico_platform, libobj_plugin), + LibCRPlugin(), LibCRIPCPlugin(), lib9p_plugin, LibMiscPlugin(), @@ -1147,10 +1408,17 @@ def main( # pico-sdk ####################################################### if arg_pico_platform == "rp2040": + + def get_init_array() -> typing.Collection[QName]: + ret: list[QName] = [] + for plugin in plugins: + ret.extend(plugin.init_array()) + return ret + plugins += [ + PicoFmtPlugin(), PicoSDKPlugin( - app_gpio_handlers=sbc_gpio_handlers, - app_init_array=["register_fini"], + get_init_array=get_init_array, ), TinyUSBDevicePlugin(arg_c_fnames), NewlibPlugin(), @@ -1159,20 +1427,29 @@ def main( # Tie it all together ############################################ - def thread_filter(name: str) -> int: - return sbc_is_thread(name) + def thread_filter(name: QName) -> tuple[int, bool]: + return sbc_is_thread(name), True - def intrhandler_filter(name: str) -> int: - name = name.rsplit(":", 1)[-1] + def intrhandler_filter(name: QName) -> tuple[int, bool]: for plugin in plugins: if plugin.is_intrhandler(name): - return 1 - return 0 + return 1, True + return 0, False - def misc_filter(name: str) -> int: - if name.endswith(":__lm_printf") or name == "__assert_msg_fail": - return 1 - return 0 + def misc_filter(name: QName) -> tuple[int, bool]: + if str(name.base()) in ["__lm_printf", "__assert_msg_fail"]: + return 1, False + return 0, False + + extra_includes: list[str] = [] + for plugin in plugins: + extra_includes.extend(plugin.extra_includes()) + + def extra_filter(name: QName) -> tuple[int, bool]: + nonlocal extra_includes + if str(name.base()) in extra_includes: + return 1, True + return 0, False def location_xform(loc: str) -> str: if not loc.startswith("/"): @@ -1187,6 +1464,7 @@ def main( "Threads": thread_filter, "Interrupt handlers": intrhandler_filter, "Misc": misc_filter, + "Extra": extra_filter, }, app=PluginApplication(location_xform, plugins), cfg_max_call_depth=100, @@ -1195,21 +1473,30 @@ def main( def print_group(grp_name: str) -> None: grp = result.groups[grp_name] + nsum = sum(v.nstatic * v.cnt for v in grp.rows.values()) + nmax = max(v.nstatic for v in grp.rows.values()) + # Figure sizes. - namelen = max([len(k) for k in grp.rows.keys()] + [len(grp_name) + 4]) - numlen = len(str(grp.nsum)) + namelen = max( + [len(location_xform(str(k))) for k in grp.rows.keys()] + [len(grp_name) + 4] + ) + numlen = len(str(nsum)) sep1 = ("=" * namelen) + " " + "=" * numlen sep2 = ("-" * namelen) + " " + "-" * numlen # Print. print("= " + grp_name + " " + sep1[len(grp_name) + 3 :]) - for name, num in sorted(grp.rows.items()): - if num == 0: + for qname, val in sorted(grp.rows.items()): + name = location_xform(str(qname)) + if val.nstatic == 0: continue - print(f"{name.ljust(namelen)} {str(num).rjust(numlen)}") + print( + f"{name:<{namelen}} {val.nstatic:>{numlen}}" + + (f" * {val.cnt}" if val.cnt != 1 else "") + ) print(sep2) - print(f"{'Total'.ljust(namelen)} {str(grp.nsum).rjust(numlen)}") - print(f"{'Maximum'.ljust(namelen)} {str(grp.nmax).rjust(numlen)}") + print(f"{'Total':<{namelen}} {nsum:>{numlen}}") + print(f"{'Maximum':<{namelen}} {nmax:>{numlen}}") print(sep1) def next_power_of_2(x: int) -> int: @@ -1221,32 +1508,77 @@ def main( print_group("Threads") print_group("Interrupt handlers") print("*/") - overhead = result.groups["Interrupt handlers"].nmax - rows: list[tuple[str, int, int]] = [] - for funcname, base in result.groups["Threads"].rows.items(): - rows.append((funcname.split(":")[-1], base, next_power_of_2(base + overhead))) - namelen = max(len(r[0]) for r in rows) - baselen = max(len(str(r[1])) for r in rows) - sizelen = max(len(str(r[2])) for r in rows) + intrstack = max( + v.nstatic for v in result.groups["Interrupt handlers"].rows.values() + ) + stack_guard_size = 16 * 2 + + class CrRow(typing.NamedTuple): + name: str + cnt: int + base: int + size: int + + rows: list[CrRow] = [] + mainrow: CrRow | None = None + for funcname, val in result.groups["Threads"].rows.items(): + name = str(funcname.base()) + base = val.nstatic + size = base + intrstack + if name in ("main", "_entry_point"): + mainrow = CrRow(name=name, cnt=1, base=base, size=size) + else: + size = next_power_of_2(size + stack_guard_size) - stack_guard_size + rows.append(CrRow(name=name, cnt=val.cnt, base=base, size=size)) + namelen = max(len(r.name) for r in rows) + baselen = max(len(str(r.base)) for r in rows) + sizesum = sum(r.cnt * (r.size + stack_guard_size) for r in rows) + sizelen = len(str(max(sizesum, mainrow.size if mainrow else 0))) + + def print_row(comment: bool, name: str, size: int, eqn: str | None = None) -> None: + prefix = "const size_t CONFIG_COROUTINE_STACK_SIZE_" + if comment: + print(f"/* {name}".ljust(len(prefix) + namelen), end="") + else: + print(f"{prefix}{name:<{namelen}}", end="") + print(f" = {size:>{sizelen}};", end="") + if comment: + print(" */", end="") + elif eqn: + print(" ", end="") + if eqn: + print(f" /* {eqn} */", end="") + print() + for row in sorted(rows): - if row[0] in ("main", "_reset_handler"): - continue - print("const size_t CONFIG_COROUTINE_STACK_SIZE_", end="") - print(f"{row[0].ljust(namelen)} =", end="") - print(f" {str(row[2]).rjust(sizelen)};", end="") - print(f" /* LM_NEXT_POWER_OF_2({str(row[1]).rjust(baselen)}+{overhead}) */") + print_row( + False, + row.name, + row.size, + f"LM_NEXT_POWER_OF_2({row.base:>{baselen}}+{intrstack}+{stack_guard_size})-{stack_guard_size}", + ) + print_row(True, "TOTAL (inc. stack guard)", sizesum) + if mainrow: + print_row( + True, + "MAIN/KERNEL", + mainrow.size, + f" {mainrow.base:>{baselen}}+{intrstack}", + ) print() print("/*") print_group("Misc") for funcname in sorted(result.missing): - print(f"warning: missing: {funcname}") + print(f"warning: missing: {location_xform(str(funcname))}") for funcname in sorted(result.dynamic): - print(f"warning: dynamic-stack-usage: {funcname}") + print(f"warning: dynamic-stack-usage: {location_xform(str(funcname))}") print("*/") print("") print("/*") + if result.groups["Extra"].rows: + print_group("Extra") for funcname in sorted(result.included_funcs): print(f"included: {funcname}") print("*/") @@ -1266,7 +1598,7 @@ if __name__ == "__main__": for obj_fname in obj_fnames: if re_c_obj_suffix.search(obj_fname): ci_fnames.add(re_c_obj_suffix.sub(".c.ci", obj_fname)) - with open(obj_fname + ".d", "r") as fh: + with open(obj_fname + ".d", "r", encoding="utf-8") as fh: c_fnames.update( fh.read().replace("\\\n", " ").split(":")[-1].split() ) diff --git a/cmd/sbc_harness/CMakeLists.txt b/cmd/sbc_harness/CMakeLists.txt index 081a5fc..d7923c2 100644 --- a/cmd/sbc_harness/CMakeLists.txt +++ b/cmd/sbc_harness/CMakeLists.txt @@ -31,6 +31,16 @@ target_link_libraries(sbc_harness_objs pico_minimize_runtime(sbc_harness_objs INCLUDE PRINTF PRINTF_MINIMAL PRINTF_LONG_LONG PRINTF_PTRDIFF_T ) +target_compile_definitions(sbc_harness_objs PRIVATE + #PICO_USE_FASTEST_SUPPORTED_CLOCK=1 + + # Calculated by `./3rd-party/pico-sdk/src/rp2_common/hardware_clocks/scripts/vcocalc.py --cmake-only 170` + PLL_SYS_REFDIV=2 + PLL_SYS_VCO_FREQ_HZ=1530000000 + PLL_SYS_POSTDIV1=3 + PLL_SYS_POSTDIV2=3 + SYS_CLK_HZ=170000000 +) suppress_tinyusb_warnings() diff --git a/cmd/sbc_harness/config/config.h b/cmd/sbc_harness/config/config.h index b569cd5..fd089b1 100644 --- a/cmd/sbc_harness/config/config.h +++ b/cmd/sbc_harness/config/config.h @@ -9,12 +9,11 @@ #include <stddef.h> /* for size_t */ -/* W5500 **********************************************************************/ +/* RP2040 *********************************************************************/ -/** - * How many W5500 chips we have. - */ -#define CONFIG_W5500_NUM 1 +#define CONFIG_RP2040_SPI_DEBUG 1 /* bool */ + +/* W5500 **********************************************************************/ /** * When allocating an arbitrary local port, what range should it be @@ -27,13 +26,12 @@ #define CONFIG_W5500_LOCAL_PORT_MIN 32768 #define CONFIG_W5500_LOCAL_PORT_MAX 60999 -#define CONFIG_W5500_DEBUG 1 /* bool */ - +#define CONFIG_W5500_VALIDATE_SPI 1 /* bool */ +#define CONFIG_W5500_DEBUG 0 /* bool */ #define CONFIG_W5500_LL_DEBUG 0 /* bool */ /* 9P *************************************************************************/ -#define CONFIG_9P_PORT LIB9P_DEFAULT_PORT_9FS /** * This max-msg-size is sized so that a Twrite message can return * 8KiB of data. @@ -106,7 +104,7 @@ extern const size_t CONFIG_COROUTINE_STACK_SIZE_w5500_irq_cr; #define CONFIG_COROUTINE_NUM ( \ 1 /* usb_common */ + \ 1 /* usb_keyboard */ + \ - CONFIG_W5500_NUM /* irq handler */ + \ + 1 /* W5500 irq handler */ + \ _CONFIG_9P_NUM_SOCKS /* 9P accept()+read() */ + \ (CONFIG_9P_SRV_MAX_REQS*_CONFIG_9P_NUM_SOCKS) /* 9P work+write() */ ) diff --git a/cmd/sbc_harness/main.c b/cmd/sbc_harness/main.c index 6f1d0ca..2b2b3f8 100644 --- a/cmd/sbc_harness/main.c +++ b/cmd/sbc_harness/main.c @@ -139,7 +139,7 @@ static COROUTINE read9p_cr(void *) { cr_begin(); lo_interface net_iface iface = lo_box_w5500_if_as_net_iface(&globals.dev_w5500); - lo_interface net_stream_listener listener = LO_CALL(iface, tcp_listen, CONFIG_9P_PORT); + lo_interface net_stream_listener listener = LO_CALL(iface, tcp_listen, LIB9P_DEFAULT_PORT_9FS); lib9p_srv_read_cr(&globals.srv, listener); @@ -168,11 +168,14 @@ COROUTINE init_cr(void *) { rp2040_hwspi_init(&globals.dev_spi, "W5500", RP2040_HWSPI_0, SPI_MODE_0, /* the W5500 supports mode 0 or mode 3 */ - 60*1000*1000, /* as close to the W5500's max rate of 80MHz as we can without hwspi borking */ - 16, /* PIN_MISO */ - 19, /* PIN_MOSI */ - 18, /* PIN_CLK */ - 17); /* PIN_CS */ + 42500000, /* min(w5500, hwspi); w5500=80MHz; hwspi=42.5MHz, see rp2040_hwspi.h for a comment about why this is so low */ + 30, /* W5500 datasheet says min(T_CS = SCSn High Time) = 30ns */ + 0, /* bogus write write data when doing a read */ + 16, /* PIN_MISO */ + 19, /* PIN_MOSI */ + 18, /* PIN_CLK */ + 17, /* PIN_CS */ + 0, 1, 2, 3); /* DMA channels */ w5500_init(&globals.dev_w5500, "W5500", lo_box_rp2040_hwspi_as_spi(&globals.dev_spi), 21, /* PIN_INTR */ diff --git a/gdb-helpers/libcr.py b/gdb-helpers/libcr.py index 3ffafce..fcfd86e 100644 --- a/gdb-helpers/libcr.py +++ b/gdb-helpers/libcr.py @@ -1,17 +1,20 @@ # gdb-helpers/libcr.py - GDB helpers for libcr. # -# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later import contextlib import time import typing -import gdb -import gdb.unwinder +import gdb # pylint: disable=import-error +import gdb.unwinder # pylint: disable=import-error # GDB helpers ################################################################## +# https://sourceware.org/bugzilla/show_bug.cgi?id=32428 +gdb_bug_32428 = True + class _gdb_Locus(typing.Protocol): @property @@ -125,19 +128,19 @@ class CrGlobals: return if self.coroutine_running: if not self.coroutine_running.is_selected(): - if True: # https://sourceware.org/bugzilla/show_bug.cgi?id=32428 + if gdb_bug_32428: print("Must return to running coroutine before continuing.") print("Hit ^C twice then run:") print(f" cr select {self.coroutine_running.id}") while True: time.sleep(1) - assert self.coroutine_running._cont_env - gdb_longjmp(self.coroutine_running._cont_env) + assert self.coroutine_running.cont_env + gdb_longjmp(self.coroutine_running.cont_env) for cr in self.coroutines: - cr._cont_env = None + cr.cont_env = None def is_valid_cid(self, cid: int) -> bool: - return 0 < cid and cid <= len(self.coroutines) + return 0 < cid <= len(self.coroutines) @property def coroutine_running(self) -> "CrCoroutine | None": @@ -211,6 +214,8 @@ class CrBreakpoint(gdb.Breakpoint): @enabled.setter def enabled(self, value: bool) -> None: self._unwinder.enabled = value + # Use a dunder-call to avoid an infinite loop. + # pylint: disable=unnecessary-dunder-call gdb.Breakpoint.enabled.__set__(self, value) # type: ignore def stop(self) -> bool: @@ -243,12 +248,12 @@ def cr_select_top_frame() -> None: class CrCoroutine: cr_globals: CrGlobals cid: int - _cont_env: gdb_JmpBuf | None + cont_env: gdb_JmpBuf | None def __init__(self, cr_globals: CrGlobals, cid: int) -> None: self.cr_globals = cr_globals self.cid = cid - self._cont_env = None + self.cont_env = None @property def id(self) -> int: @@ -269,18 +274,18 @@ class CrCoroutine: sp = int(gdb.parse_and_eval("$sp")) lo = int(gdb.parse_and_eval(f"coroutine_table[{self.id-1}].stack")) hi = lo + int(gdb.parse_and_eval(f"coroutine_table[{self.id-1}].stack_size")) - return lo <= sp and sp < hi + return lo <= sp < hi def select(self, level: int = -1) -> None: if self.cr_globals.coroutine_selected: - self.cr_globals.coroutine_selected._cont_env = gdb_setjmp() + self.cr_globals.coroutine_selected.cont_env = gdb_setjmp() - if self._cont_env: - gdb_longjmp(self._cont_env) + if self.cont_env: + gdb_longjmp(self.cont_env) else: env: gdb_JmpBuf if self == self.cr_globals.coroutine_running: - assert False # self._cont_env should have been set + assert False # self.cont_env should have been set elif self.state == self.cr_globals.CR_RUNNING: env = self.cr_globals.readjmp("&coroutine_add_env") else: @@ -332,7 +337,7 @@ class CrListCommand(gdb.Command): def invoke(self, arg: str, from_tty: bool) -> None: argv = gdb.string_to_argv(arg) if len(argv) != 0: - raise gdb.GdbError(f"Usage: cr list") + raise gdb.GdbError("Usage: cr list") rows: list[tuple[str, str, str, str, str]] = [ ("", "Id", "Name", "State", "Frame") @@ -384,7 +389,7 @@ class CrListCommand(gdb.Command): cr_select_top_frame() full = gdb.execute("frame", from_tty=from_tty, to_string=True) gdb.execute(f"select-frame level {saved_level}") - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught full = "#0 err: " + str(e) line = full.split("\n", maxsplit=1)[0] return line.split(maxsplit=1)[1] @@ -423,32 +428,32 @@ class CrSelectCommand(gdb.Command): crs += [cr] match len(crs): case 0: - raise gdb.GdbError(f"No such coroutine: {repr(name)}") + raise gdb.GdbError(f"No such coroutine: {name!r}") case 1: return crs[0] case _: - raise gdb.GdbError(f"Ambiguous name, must use Id: {repr(name)}") + raise gdb.GdbError(f"Ambiguous name, must use Id: {name!r}") # Wire it all in ############################################################### -cr_globals: CrGlobals | None = None +_cr_globals: CrGlobals | None = None def cr_initialize() -> None: - global cr_globals - if cr_globals: - old = cr_globals + global _cr_globals + if _cr_globals: + old = _cr_globals new = CrGlobals() for i in range(min(len(old.coroutines), len(new.coroutines))): - new.coroutines[i]._cont_env = old.coroutines[i]._cont_env + new.coroutines[i].cont_env = old.coroutines[i].cont_env old.delete() - cr_globals = new + _cr_globals = new else: - cr_globals = CrGlobals() - CrCommand(cr_globals) - CrListCommand(cr_globals) - CrSelectCommand(cr_globals) + _cr_globals = CrGlobals() + CrCommand(_cr_globals) + CrListCommand(_cr_globals) + CrSelectCommand(_cr_globals) def cr_on_new_objfile(event: gdb.Event) -> None: @@ -460,7 +465,7 @@ def cr_on_new_objfile(event: gdb.Event) -> None: gdb.events.new_objfile.disconnect(cr_on_new_objfile) -if cr_globals: +if _cr_globals: cr_initialize() else: gdb.events.new_objfile.connect(cr_on_new_objfile) diff --git a/gdb-helpers/rp2040.py b/gdb-helpers/rp2040.py index 30a936a..087974d 100644 --- a/gdb-helpers/rp2040.py +++ b/gdb-helpers/rp2040.py @@ -1,9 +1,11 @@ # gdb-helpers/rp2040.py - GDB helpers for the RP2040 CPU. # -# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later -import gdb +import typing + +import gdb # pylint: disable=import-error def read_mmreg(addr: int) -> int: @@ -18,6 +20,23 @@ def fmt32(x: int) -> str: return "0b" + bin(x)[2:].rjust(32, "0") +def box(title: str, content: str) -> str: + width = 80 + + lines = content.split("\n") + while len(lines) and lines[0] == "": + lines = lines[1:] + while len(lines) and lines[-1] == "": + lines = lines[:-1] + lines = ["", *lines, ""] + + ret = "โโ[" + title + "]" + ("โ" * (width - len(title) - 5)) + "โ\n" + for line in content.split("\n"): + ret += f"โ {line:<{width-4}} โ\n" + ret += "โ" + ("โ" * (width - 2)) + "โ" + return ret + + def read_prio(addr: int) -> str: prios: list[int] = 32 * [0] for regnum in range(0, 8): @@ -91,27 +110,23 @@ class RP2040ShowInterrupts(gdb.Command): """Show the RP2040's interrupt state.""" def __init__(self) -> None: - super(RP2040ShowInterrupts, self).__init__( - "rp2040-show-interrupts", gdb.COMMAND_USER - ) + super().__init__("rp2040-show-interrupts", gdb.COMMAND_USER) def invoke(self, arg: str, from_tty: bool) -> None: + self.arm_cortex_m0plus_registers() + self.arm_cortex_m0plus_mmregisters() + self.rp2040_dma_mmregisters() + + def arm_cortex_m0plus_mmregisters(self) -> None: base: int = 0xE0000000 icsr = read_mmreg(base + 0xED04) - psr = read_reg("xPSR") - # โโโคโโโคโโคโโโคโโโโคโโโโคโโโโโโโค - # 10987654321098765432109876543210 (dec bitnum) - # 3 2 1 0 - # โโโคโโโคโโคโโโคโโโโคโโโโคโโโโโโโค - # fedcba9876543210fedcba9876543210 (hex bitnum) - # 1 0 print( - f""" -ARM Cortex-M0+ memory-mapped registers: - + box( + "ARM Cortex-M0+ memory-mapped registers", + f""" clocksโ โSIO SPIโ โ โโQSPI - UARTโโ โ โโโbank0 โXIP + UARTโโ โ โโโGPIO โXIP ADCโ โโ โ โโโโDMA โโUSB I2Cโ โ โโ โ โโโโ โPIOโโโPWM RTCโโโโโโคโโโโโคโโโโโโโโโโโโโโโฌtimers @@ -142,22 +157,139 @@ AIRCR : {fmt32(read_mmreg(base+0xed0c)) } Application Interrupt and Reset Co โsleep_deep s_ev_on_pendโ โโsleep_on_exit SCR : {fmt32(read_mmreg(base+0xed10)) } System Control +""", + ) + ) -ARM Cortex-M0+ processor core registers: - + def arm_cortex_m0plus_registers(self) -> None: + psr = read_reg("xPSR") + print( + box( + "ARM Cortex-M0+ processor-core registers", + f""" โpm (0=normal, 1=top priority) PRIMASK : {fmt32(read_reg('primask')) } Priority Mask - [C]arryโโo[V]erflow - [Z]eroโโโ โ[T]humb โrequire [a]lignment - [N]egativeโโโโ โ exec โ โinterrupt - appโซโซโซโข โโโโโโโโโดโโโโโโโขโโโโโโดโโโ + app exec intr + โโดโโ โโโโโโโโโดโโโโโโโโโโโโดโโโโ xPSR : {fmt32(psr) } {{Application,Execution,Interrupt}} Program Status - โโโโโโฌโโโ - โ{psr&0x1FF} ({exception_names[psr&0x1FF]}) + โโโโ โ โโโโโโฌโโโโ + [N]egativeโโโโ โ โ โ{psr&0x1FF} ({exception_names[psr&0x1FF]}) + [Z]eroโโโ โ[T]humb โrequire [a]lignment + [C]arryโโ + o[V]erflowโ +""", + ) + ) -""" + def rp2040_dma_mmregisters(self) -> None: + base: int = 0x50000000 + + def fmt12(x: int) -> str: + s = fmt32(x) + return s[:-12] + "_" + s[-12:] + + print( + box( + "RP2040 DMA memory-mapped registers", + f""" + + 8 4 0 + โโโโดโโโโดโโโโค +INTR : {fmt12(read_mmreg(base + 0x400))} Raw + โ โ โ โ +INTE0: {fmt12(read_mmreg(base + 0x404))} IRQ_DMA_0 Enable +INTF0: {fmt12(read_mmreg(base + 0x408))} IRQ_DMA_0 Force +INTS0: {fmt12(read_mmreg(base + 0x40c))} IRQ_DMA_0 Status + โ โ โ โ +INTE1: {fmt12(read_mmreg(base + 0x414))} IRQ_DMA_1 Enable +INTF1: {fmt12(read_mmreg(base + 0x418))} IRQ_DMA_1 Force +INTS1: {fmt12(read_mmreg(base + 0x41c))} IRQ_DMA_1 Status +""", + ) ) RP2040ShowInterrupts() + + +class RP2040ShowDMA(gdb.Command): + """Show the RP2040's DMA control registers.""" + + def __init__(self) -> None: + super().__init__("rp2040-show-dma", gdb.COMMAND_USER) + + def invoke(self, arg: str, from_tty: bool) -> None: + base: int = 0x50000000 + u32_size: int = 4 + + nchan = read_mmreg(base + 0x448) + + def chreg( + ch: int, + name: typing.Literal[ + "read_addr", + "write_addr", + "trans_count", + "ctrl", + "dbg_ctdreq", + "dbg_tcr", + ], + ) -> int: + fieldcnt: int = 4 * 4 + fieldnum: int + debug = False + match name: + case "read_addr": + fieldnum = 0 + case "write_addr": + fieldnum = 1 + case "trans_count": + fieldnum = 2 + case "ctrl": + fieldnum = 4 + case "dbg_ctdreq": + fieldnum = 0 + debug = True + case "dbg_tcr": + fieldnum = 1 + debug = True + return read_mmreg( + base + + (0x800 if debug else 0) + + (ch * u32_size * fieldcnt) + + (u32_size * fieldnum) + ) + + def ctrl(ch: int) -> str: + s = fmt32(chreg(ch, "ctrl")) + return s[:10] + "_" + s[10:] + + def chaddr(ch: int, name: typing.Literal["read", "write"]) -> str: + val = chreg(ch, name + "_addr") # type: ignore + if val == 0: + return "NULL " + return f"0x{val:08x}" + + ret = """ + โsniff_enable + โโbswap + โโโirq_quiet + โโโ โtreq_sel + โโโ โ โchain_to + โโโ โ โ โring_sel + โโโ โ โ โ โring_size + โโโ โ โ โ โ โincr_write + busyโ โโโ โ โ โ โ โโincr_read +write_errโ โ โโโ โ โ โ โ โโโdata_size +read_errโโ โ โโโ โ โ โ โ โโโ โhigh_priority +ahb_errโโโ โ โโโ โ โ โ โ โโโ โโenable + โโโ โ โโโ โ โ โ โ โโโ โโ trans_cnt + โโโ โ โโโโโโดโโโโโดโโโโโดโโโโโโโโ read_addr write_addr cur/reload +""" + for ch in range(0, nchan): + ret += f"{ch: 3}: {ctrl(ch)} {chaddr(ch, 'read')} {chaddr(ch, 'write')} {chreg(ch, 'trans_count')}/{chreg(ch, 'dbg_tcr')}\n" + print(box("RP2040 DMA channels", ret)) + + +RP2040ShowDMA() @@ -79,7 +79,7 @@ bool lib9p_ctx_has_error(struct lib9p_ctx *ctx) { return ctx->err_msg[0]; } -int lib9p_error(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *msg) { +int lib9p_error(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *msg) { if (lib9p_ctx_has_error(ctx)) return -1; strncpy(ctx->err_msg, msg, sizeof(ctx->err_msg)); @@ -94,7 +94,7 @@ int lib9p_error(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *msg) { return -1; } -int lib9p_errorf(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *fmt, ...) { +int lib9p_errorf(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *fmt, ...) { int n; va_list args; @@ -123,17 +123,8 @@ ssize_t _lib9p_validate(uint8_t xxx_low_typ_bit, const struct _lib9p_recv_tentry xxx_table[LIB9P_VER_NUM][0x80], struct lib9p_ctx *ctx, uint8_t *net_bytes) { /* Inspect the first 5 bytes ourselves. */ - struct _validate_ctx subctx = { - /* input */ - .ctx = ctx, - .net_size = uint32le_decode(net_bytes), - .net_bytes = net_bytes, - - /* output */ - .net_offset = 0, - .host_extra = 0, - }; - if (subctx.net_size < 5) + uint32_t net_size = uint32le_decode(net_bytes); + if (net_size < 5) return lib9p_error(ctx, LINUX_EBADMSG, "message is impossibly short"); uint8_t typ = net_bytes[4]; if (typ % 2 != xxx_low_typ_bit) @@ -145,18 +136,7 @@ ssize_t _lib9p_validate(uint8_t xxx_low_typ_bit, lib9p_msgtype_str(ctx->version, typ), lib9p_version_str(ctx->version)); /* Now use the message-type-specific tentry to process the whole thing. */ - if (tentry.validate(&subctx)) - return -1; - assert(subctx.net_offset <= subctx.net_size); - if (subctx.net_offset < subctx.net_size) - return lib9p_errorf(ctx, LINUX_EBADMSG, "message has %"PRIu32" extra bytes", - subctx.net_size - subctx.net_offset); - - /* Return. */ - ssize_t ret; - if (__builtin_add_overflow(tentry.basesize, subctx.host_extra, &ret)) - return lib9p_error(ctx, LINUX_EMSGSIZE, "unmarshalled payload overflows SSIZE_MAX"); - return ret; + return tentry.validate(ctx, net_size, net_bytes); } ssize_t lib9p_Tmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) { @@ -177,16 +157,7 @@ void _lib9p_unmarshal(const struct _lib9p_recv_tentry xxx_table[LIB9P_VER_NUM][0 *ret_typ = typ; struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2]; - struct _unmarshal_ctx subctx = { - /* input */ - .ctx = ctx, - .net_bytes = net_bytes, - - /* output */ - .net_offset = 0, - .extra = ret_body + tentry.basesize, - }; - tentry.unmarshal(&subctx, ret_body); + tentry.unmarshal(ctx, net_bytes, ret_body); } void lib9p_Tmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, @@ -205,11 +176,7 @@ static bool _lib9p_marshal(const struct _lib9p_send_tentry xxx_table[LIB9P_VER_NUM][0x80], struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body, size_t *ret_iov_cnt, struct iovec *ret_iov, uint8_t *ret_copied) { - struct _marshal_ctx subctx = { - /* input */ - .ctx = ctx, - - /* ouptut */ + struct _marshal_ret ret = { .net_iov_cnt = 1, .net_iov = ret_iov, .net_copied_size = 0, @@ -217,10 +184,10 @@ bool _lib9p_marshal(const struct _lib9p_send_tentry xxx_table[LIB9P_VER_NUM][0x8 }; struct _lib9p_send_tentry tentry = xxx_table[ctx->version][typ/2]; - bool ret_erred = tentry.marshal(&subctx, body); - if (ret_iov[subctx.net_iov_cnt-1].iov_len == 0) - subctx.net_iov_cnt--; - *ret_iov_cnt = subctx.net_iov_cnt; + bool ret_erred = tentry.marshal(ctx, body, &ret); + if (ret_iov[ret.net_iov_cnt-1].iov_len == 0) + ret.net_iov_cnt--; + *ret_iov_cnt = ret.net_iov_cnt; return ret_erred; } @@ -246,39 +213,17 @@ bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *bo bool lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size, ssize_t *ret_host_size) { - struct _validate_ctx subctx = { - /* input */ - .ctx = ctx, - .net_size = net_size, - .net_bytes = net_bytes, - - /* output */ - .net_offset = 0, - .host_extra = 0, - }; - if (_lib9p_stat_validate(&subctx)) + ssize_t host_size = _lib9p_stat_validate(ctx, net_size, net_bytes, ret_net_size); + if (host_size < 0) return true; - if (ret_net_size) - *ret_net_size = subctx.net_offset; if (ret_host_size) - if (__builtin_add_overflow(sizeof(struct lib9p_stat), subctx.host_extra, ret_host_size)) - return lib9p_error(ctx, LINUX_EMSGSIZE, "unmarshalled stat object overflows SSIZE_MAX"); + *ret_host_size = host_size; return false; } -uint32_t lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, - struct lib9p_stat *ret_obj, void *ret_extra) { - struct _unmarshal_ctx subctx = { - /* input */ - .ctx = ctx, - .net_bytes = net_bytes, - - /* output */ - .net_offset = 0, - .extra = ret_extra, - }; - _lib9p_stat_unmarshal(&subctx, ret_obj); - return subctx.net_offset; +void lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, + struct lib9p_stat *ret) { + _lib9p_stat_unmarshal(ctx, net_bytes, ret); } uint32_t lib9p_stat_marshal(struct lib9p_ctx *ctx, uint32_t max_net_size, struct lib9p_stat *obj, @@ -287,17 +232,13 @@ uint32_t lib9p_stat_marshal(struct lib9p_ctx *ctx, uint32_t max_net_size, struct _ctx.max_msg_size = max_net_size; struct iovec iov = {0}; - struct _marshal_ctx subctx = { - /* input */ - .ctx = &_ctx, - - /* output */ + struct _marshal_ret ret = { .net_iov_cnt = 1, .net_iov = &iov, .net_copied_size = 0, .net_copied = ret_bytes, }; - if (_lib9p_stat_marshal(&subctx, obj)) + if (_lib9p_stat_marshal(&_ctx, obj, &ret)) return 0; - return subctx.net_iov[0].iov_len; + return ret.net_iov[0].iov_len; } diff --git a/lib9p/9p.generated.c b/lib9p/9p.generated.c index fe042e6..6726084 100644 --- a/lib9p/9p.generated.c +++ b/lib9p/9p.generated.c @@ -1,4 +1,4 @@ -/* Generated by `lib9p/idl.gen lib9p/idl/2002-9P2000.9p lib9p/idl/2003-9P2000.p9p.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2010-9P2000.L.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */ +/* Generated by `lib9p/proto.gen lib9p/idl/2002-9P2000.9p lib9p/idl/2003-9P2000.p9p.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2010-9P2000.L.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */ #include <stdbool.h> #include <stddef.h> /* for size_t */ @@ -39,12 +39,12 @@ #endif /** - * is_ver(ctx, ver) is essentially `(ctx->ctx->version == LIB9P_VER_##ver)`, - * but compiles correctly (to `false`) even if `LIB9P_VER_##ver` isn't defined + * is_ver(ctx, ver) is essentially `(ctx->version == LIB9P_VER_##ver)`, but + * compiles correctly (to `false`) even if `LIB9P_VER_##ver` isn't defined * (because `!CONFIG_9P_ENABLE_##ver`). This is useful when `||`ing * several version checks together. */ -#define is_ver(CTX, ver) _is_ver_##ver(CTX->ctx->version) +#define is_ver(ctx, ver) _is_ver_##ver((ctx)->version) /* strings ********************************************************************/ @@ -333,6 +333,38 @@ static const lib9p_o_t o_masks[LIB9P_VER_NUM] = { #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_L +static const lib9p_lo_t lo_masks[LIB9P_VER_NUM] = { +#if CONFIG_9P_ENABLE_9P2000 + [LIB9P_VER_9P2000] = 0b00000000000000000000000000000000, +#endif /* CONFIG_9P_ENABLE_9P2000 */ + [LIB9P_VER_9P2000_L] = 0b00000000000111111111111111000011, +#if CONFIG_9P_ENABLE_9P2000_e + [LIB9P_VER_9P2000_e] = 0b00000000000000000000000000000000, +#endif /* CONFIG_9P_ENABLE_9P2000_e */ +#if CONFIG_9P_ENABLE_9P2000_p9p + [LIB9P_VER_9P2000_p9p] = 0b00000000000000000000000000000000, +#endif /* CONFIG_9P_ENABLE_9P2000_p9p */ +#if CONFIG_9P_ENABLE_9P2000_u + [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000, +#endif /* CONFIG_9P_ENABLE_9P2000_u */ +}; + +static const lib9p_mode_t mode_masks[LIB9P_VER_NUM] = { +#if CONFIG_9P_ENABLE_9P2000 + [LIB9P_VER_9P2000] = 0b00000000000000000000000000000000, +#endif /* CONFIG_9P_ENABLE_9P2000 */ + [LIB9P_VER_9P2000_L] = 0b00000000000000001111111111111111, +#if CONFIG_9P_ENABLE_9P2000_e + [LIB9P_VER_9P2000_e] = 0b00000000000000000000000000000000, +#endif /* CONFIG_9P_ENABLE_9P2000_e */ +#if CONFIG_9P_ENABLE_9P2000_p9p + [LIB9P_VER_9P2000_p9p] = 0b00000000000000000000000000000000, +#endif /* CONFIG_9P_ENABLE_9P2000_p9p */ +#if CONFIG_9P_ENABLE_9P2000_u + [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000, +#endif /* CONFIG_9P_ENABLE_9P2000_u */ +}; + static const lib9p_getattr_t getattr_masks[LIB9P_VER_NUM] = { #if CONFIG_9P_ENABLE_9P2000 [LIB9P_VER_9P2000] = 0b0000000000000000000000000000000000000000000000000000000000000000, @@ -384,2494 +416,2664 @@ static const lib9p_lock_flags_t lock_flags_masks[LIB9P_VER_NUM] = { /* validate_* *****************************************************************/ -LM_ALWAYS_INLINE static bool _validate_size_net(struct _validate_ctx *ctx, uint32_t n) { - if (__builtin_add_overflow(ctx->net_offset, n, &ctx->net_offset)) - /* If needed-net-size overflowed uint32_t, then - * there's no way that actual-net-size will live up to - * that. */ - return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); - if (ctx->net_offset > ctx->net_size) - return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); - return false; -} - -LM_ALWAYS_INLINE static bool _validate_size_host(struct _validate_ctx *ctx, size_t n) { - if (__builtin_add_overflow(ctx->host_extra, n, &ctx->host_extra)) - /* If needed-host-size overflowed size_t, then there's - * no way that actual-net-size will live up to - * that. */ - return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); - return false; -} - -LM_ALWAYS_INLINE static bool _validate_list(struct _validate_ctx *ctx, - size_t cnt, - _validate_fn_t item_fn, size_t item_host_size) { - for (size_t i = 0; i < cnt; i++) - if (_validate_size_host(ctx, item_host_size) || item_fn(ctx)) - return true; - return false; -} - -LM_ALWAYS_INLINE static bool validate_1(struct _validate_ctx *ctx) { return _validate_size_net(ctx, 1); } -LM_ALWAYS_INLINE static bool validate_2(struct _validate_ctx *ctx) { return _validate_size_net(ctx, 2); } -LM_ALWAYS_INLINE static bool validate_4(struct _validate_ctx *ctx) { return _validate_size_net(ctx, 4); } -LM_ALWAYS_INLINE static bool validate_8(struct _validate_ctx *ctx) { return _validate_size_net(ctx, 8); } - -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static bool validate_tag(struct _validate_ctx *ctx) { - return validate_2(ctx); -} - -LM_ALWAYS_INLINE static bool validate_fid(struct _validate_ctx *ctx) { - return validate_4(ctx); -} - -LM_ALWAYS_INLINE static bool validate_s(struct _validate_ctx *ctx) { - uint16_t len; - return false - || (validate_2(ctx) || ({ len = uint16le_decode(&ctx->net_bytes[ctx->net_offset-2]); false; })) - || _validate_size_net(ctx, len) - || ({ (!is_valid_utf8_without_nul(&ctx->net_bytes[ctx->net_offset-len], len)) && lib9p_error(ctx->ctx, LINUX_EBADMSG, "message contains invalid UTF-8"); }) - ; -} +#define VALIDATE_NET_BYTES(n) \ + if (__builtin_add_overflow(net_offset, n, &net_offset)) \ + /* If needed-net-size overflowed uint32_t, then \ + * there's no way that actual-net-size will live up to \ + * that. */ \ + return lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content"); \ + if (net_offset > net_size) \ + return lib9p_errorf(ctx, LINUX_EBADMSG, "message is too short for content (%"PRIu32" > %"PRIu32") @ %d", net_offset, net_size, __LINE__); +#define VALIDATE_NET_UTF8(n) \ + { \ + size_t len = n; \ + VALIDATE_NET_BYTES(len); \ + if (!is_valid_utf8_without_nul(&net_bytes[net_offset-len], len)) \ + return lib9p_error(ctx, LINUX_EBADMSG, "message contains invalid UTF-8"); \ + } +#define RESERVE_HOST_BYTES(n) \ + if (__builtin_add_overflow(host_size, n, &host_size)) \ + /* If needed-host-size overflowed ssize_t, then there's \ + * no way that actual-net-size will live up to \ + * that. */ \ + return lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content"); +#define GET_U8LE(off) (net_bytes[off]) +#define GET_U16LE(off) uint16le_decode(&net_bytes[off]) +#define GET_U32LE(off) uint32le_decode(&net_bytes[off]) +#define GET_U64LE(off) uint64le_decode(&net_bytes[off]) +#define LAST_U8LE() GET_U8LE(net_offset-1) +#define LAST_U16LE() GET_U16LE(net_offset-2) +#define LAST_U32LE() GET_U32LE(net_offset-4) +#define LAST_U64LE() GET_U64LE(net_offset-8) -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static bool validate_dm(struct _validate_ctx *ctx) { - if (validate_4(ctx)) - return true; - lib9p_dm_t mask = dm_masks[ctx->ctx->version]; - lib9p_dm_t val = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); - if (val & ~mask) - return lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#04"PRIx32, val & ~mask); - return false; +static ssize_t validate_stat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_stat); + uint32_t offsetof_stat_size = net_offset + 0; + uint32_t offsetof_kern_type = net_offset + 2; + uint32_t offsetof_file_qid_type = net_offset + 8; + VALIDATE_NET_BYTES(21); + if (GET_U8LE(offsetof_file_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_file_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_file_mode = net_offset + 0; + VALIDATE_NET_BYTES(22); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(12); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_stat_size) != (uint32_t)(offsetof_end - offsetof_kern_type)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "stat->stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_stat_size), (uint32_t)(offsetof_end - offsetof_kern_type)); + if (GET_U32LE(offsetof_file_mode) & ~dm_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32, + GET_U32LE(offsetof_file_mode) & ~dm_masks[ctx->version]); + if (ret_net_size) + *ret_net_size = net_offset; + return (ssize_t)host_size; } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static bool validate_qt(struct _validate_ctx *ctx) { - if (validate_1(ctx)) - return true; - lib9p_qt_t mask = qt_masks[ctx->ctx->version]; - lib9p_qt_t val = ctx->net_bytes[ctx->net_offset-1]; - if (val & ~mask) - return lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#01"PRIx8, val & ~mask); - return false; -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +static ssize_t validate_Tversion(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tversion); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(13); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tversion->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(100)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tversion->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(100)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rversion(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rversion); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(13); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rversion->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(101)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rversion->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(101)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tauth(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tauth); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(13); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static bool validate_nuid(struct _validate_ctx *ctx) { - return validate_4(ctx); -} - + if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) { + VALIDATE_NET_BYTES(4); + } #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static bool validate_o(struct _validate_ctx *ctx) { - if (validate_1(ctx)) - return true; - lib9p_o_t mask = o_masks[ctx->ctx->version]; - lib9p_o_t val = ctx->net_bytes[ctx->net_offset-1]; - if (val & ~mask) - return lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "unknown bits in o bitfield: %#01"PRIx8, val & ~mask); - return false; -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_ALWAYS_INLINE static bool validate_getattr(struct _validate_ctx *ctx) { - if (validate_8(ctx)) - return true; - lib9p_getattr_t mask = getattr_masks[ctx->ctx->version]; - lib9p_getattr_t val = uint64le_decode(&ctx->net_bytes[ctx->net_offset-8]); - if (val & ~mask) - return lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "unknown bits in getattr bitfield: %#08"PRIx64, val & ~mask); - return false; -} - -LM_ALWAYS_INLINE static bool validate_setattr(struct _validate_ctx *ctx) { - if (validate_4(ctx)) - return true; - lib9p_setattr_t mask = setattr_masks[ctx->ctx->version]; - lib9p_setattr_t val = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); - if (val & ~mask) - return lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "unknown bits in setattr bitfield: %#04"PRIx32, val & ~mask); - return false; -} - -LM_ALWAYS_INLINE static bool validate_lock_type(struct _validate_ctx *ctx) { - return validate_1(ctx); -} - -LM_ALWAYS_INLINE static bool validate_lock_flags(struct _validate_ctx *ctx) { - if (validate_4(ctx)) - return true; - lib9p_lock_flags_t mask = lock_flags_masks[ctx->ctx->version]; - lib9p_lock_flags_t val = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); - if (val & ~mask) - return lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "unknown bits in lock_flags bitfield: %#04"PRIx32, val & ~mask); - return false; -} - -LM_ALWAYS_INLINE static bool validate_lock_status(struct _validate_ctx *ctx) { - return validate_1(ctx); -} - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static bool validate_Tflush(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_2(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 108; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rflush(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 109; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rread(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t count; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || (validate_4(ctx) || ({ count = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || _validate_size_net(ctx, count) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 117; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - || ({ uint32_t max = INT32_MAX; (((uint32_t)count) > max) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "count value is too large (%"PRIu32" > %"PRIu32")", count, max); }) - ; -} - -LM_FLATTEN static bool validate_Rwrite(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t count; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || (validate_4(ctx) || ({ count = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 119; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - || ({ uint32_t max = INT32_MAX; (((uint32_t)count) > max) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "count value is too large (%"PRIu32" > %"PRIu32")", count, max); }) - ; -} - -LM_FLATTEN static bool validate_Rclunk(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 121; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rremove(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 123; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tauth->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(102)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tauth->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(102)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rauth(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rauth); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_aqid_type = net_offset + 7; + VALIDATE_NET_BYTES(20); + if (GET_U8LE(offsetof_aqid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_aqid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rauth->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(103)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rauth->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(103)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tattach(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tattach); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(17); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); +#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u + if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) { + VALIDATE_NET_BYTES(4); + } +#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tattach->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(104)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tattach->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(104)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rattach(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rattach); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_qid_type = net_offset + 7; + VALIDATE_NET_BYTES(20); + if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rattach->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(105)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rattach->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(105)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rerror(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rerror); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(9); + VALIDATE_NET_UTF8(LAST_U16LE()); +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + VALIDATE_NET_BYTES(4); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rerror->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(107)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rerror->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(107)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tflush(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tflush); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 9; + VALIDATE_NET_BYTES(9); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tflush->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(108)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tflush->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(108)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rflush(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rflush); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 7; + VALIDATE_NET_BYTES(7); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rflush->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(109)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rflush->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(109)); + return (ssize_t)host_size; +} + +static ssize_t validate_Twalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Twalk); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_nwname = net_offset + 15; + VALIDATE_NET_BYTES(17); + for (uint16_t i = 0, cnt = LAST_U16LE(); i < cnt; i++) { + RESERVE_HOST_BYTES(sizeof(struct lib9p_s)); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); + } + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Twalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(110)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Twalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(110)); + if ((uint16_t)GET_U16LE(offsetof_nwname) > (uint16_t)(16)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Twalk->nwname value is too large: %"PRIu16" > %"PRIu16, + (uint16_t)GET_U16LE(offsetof_nwname), (uint16_t)(16)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rwalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rwalk); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_nwqid = net_offset + 7; + VALIDATE_NET_BYTES(9); + for (uint16_t i = 0, cnt = LAST_U16LE(); i < cnt; i++) { + RESERVE_HOST_BYTES(sizeof(struct lib9p_qid)); + uint32_t offsetof_wqid_type = net_offset + 0; + VALIDATE_NET_BYTES(13); + if (GET_U8LE(offsetof_wqid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_wqid_type) & ~qt_masks[ctx->version]); + } + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(111)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(111)); + if ((uint16_t)GET_U16LE(offsetof_nwqid) > (uint16_t)(16)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwalk->nwqid value is too large: %"PRIu16" > %"PRIu16, + (uint16_t)GET_U16LE(offsetof_nwqid), (uint16_t)(16)); + return (ssize_t)host_size; } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static bool validate_Rwstat(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 127; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; +static ssize_t validate_Topen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Topen); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_mode = net_offset + 11; + uint32_t offsetof_end = net_offset + 12; + VALIDATE_NET_BYTES(12); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Topen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(112)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Topen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(112)); + if (GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8, + GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]); + return (ssize_t)host_size; +} + +static ssize_t validate_Ropen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Ropen); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_qid_type = net_offset + 7; + VALIDATE_NET_BYTES(20); + if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_end = net_offset + 4; + VALIDATE_NET_BYTES(4); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Ropen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(113)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Ropen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(113)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tcreate); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(13); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_perm = net_offset + 0; + uint32_t offsetof_mode = net_offset + 4; + uint32_t offsetof_end = net_offset + 5; + VALIDATE_NET_BYTES(5); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(114)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(114)); + if (GET_U32LE(offsetof_perm) & ~dm_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32, + GET_U32LE(offsetof_perm) & ~dm_masks[ctx->version]); + if (GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8, + GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]); + return (ssize_t)host_size; +} + +static ssize_t validate_Rcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rcreate); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_qid_type = net_offset + 7; + VALIDATE_NET_BYTES(20); + if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_end = net_offset + 4; + VALIDATE_NET_BYTES(4); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(115)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(115)); + return (ssize_t)host_size; } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static bool validate_Rlerror(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_4(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 7; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rstatfs(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_4(ctx) - || validate_4(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_4(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 9; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rrename(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 21; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rsetattr(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 27; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rxattrwalk(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_8(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 31; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rxattrcreate(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 33; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rreaddir(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t count; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || (validate_4(ctx) || ({ count = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || _validate_size_net(ctx, count) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 41; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rfsync(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 51; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rlink(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 71; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rrenameat(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 75; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Runlinkat(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 77; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000_e -LM_FLATTEN static bool validate_Tsession(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_8(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 150; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rsession(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 151; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rsread(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t count; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || (validate_4(ctx) || ({ count = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || _validate_size_net(ctx, count) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 153; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rswrite(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_4(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 155; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000_e */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static bool validate_Tread(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint64_t offset; - uint32_t count; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || (validate_8(ctx) || ({ offset = uint64le_decode(&ctx->net_bytes[ctx->net_offset-8]); false; })) - || (validate_4(ctx) || ({ count = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 116; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - || ({ uint64_t max = INT64_MAX; (((uint64_t)offset) > max) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "offset value is too large (%"PRIu64" > %"PRIu64")", offset, max); }) - || ({ uint32_t max = INT32_MAX; (((uint32_t)count) > max) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "count value is too large (%"PRIu32" > %"PRIu32")", count, max); }) - ; -} - -LM_FLATTEN static bool validate_Twrite(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint64_t offset; - uint32_t count; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || (validate_8(ctx) || ({ offset = uint64le_decode(&ctx->net_bytes[ctx->net_offset-8]); false; })) - || (validate_4(ctx) || ({ count = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || _validate_size_net(ctx, count) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 118; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - || ({ uint64_t max = INT64_MAX; (((uint64_t)offset) > max) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "offset value is too large (%"PRIu64" > %"PRIu64")", offset, max); }) - || ({ uint32_t max = INT32_MAX; (((uint32_t)count) > max) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "count value is too large (%"PRIu32" > %"PRIu32")", count, max); }) - ; -} - -LM_FLATTEN static bool validate_Tclunk(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 120; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Tremove(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 122; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; +static ssize_t validate_Tread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tread); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_offset = net_offset + 11; + uint32_t offsetof_count = net_offset + 19; + uint32_t offsetof_end = net_offset + 23; + VALIDATE_NET_BYTES(23); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(116)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(116)); + if ((uint64_t)GET_U64LE(offsetof_offset) > (uint64_t)(INT64_MAX)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tread->offset value is too large: %"PRIu64" > %"PRIu64, + (uint64_t)GET_U64LE(offsetof_offset), (uint64_t)(INT64_MAX)); + if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tread->count value is too large: %"PRIu32" > %"PRIu32, + (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rread); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_count = net_offset + 7; + VALIDATE_NET_BYTES(11); + VALIDATE_NET_BYTES(LAST_U32LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(117)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(117)); + if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rread->count value is too large: %"PRIu32" > %"PRIu32, + (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX)); + return (ssize_t)host_size; +} + +static ssize_t validate_Twrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Twrite); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_offset = net_offset + 11; + uint32_t offsetof_count = net_offset + 19; + VALIDATE_NET_BYTES(23); + VALIDATE_NET_BYTES(LAST_U32LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Twrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(118)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Twrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(118)); + if ((uint64_t)GET_U64LE(offsetof_offset) > (uint64_t)(INT64_MAX)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Twrite->offset value is too large: %"PRIu64" > %"PRIu64, + (uint64_t)GET_U64LE(offsetof_offset), (uint64_t)(INT64_MAX)); + if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Twrite->count value is too large: %"PRIu32" > %"PRIu32, + (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rwrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rwrite); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_count = net_offset + 7; + uint32_t offsetof_end = net_offset + 11; + VALIDATE_NET_BYTES(11); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(119)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(119)); + if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwrite->count value is too large: %"PRIu32" > %"PRIu32, + (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tclunk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tclunk); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 11; + VALIDATE_NET_BYTES(11); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tclunk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(120)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tclunk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(120)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rclunk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rclunk); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 7; + VALIDATE_NET_BYTES(7); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rclunk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(121)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rclunk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(121)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tremove(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tremove); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 11; + VALIDATE_NET_BYTES(11); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tremove->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(122)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tremove->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(122)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rremove(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rremove); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 7; + VALIDATE_NET_BYTES(7); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rremove->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(123)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rremove->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(123)); + return (ssize_t)host_size; } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static bool validate_Tstat(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 124; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static bool validate_Tstatfs(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 8; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Tlopen(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_4(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 12; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Treadlink(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 22; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Treaddir(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_8(ctx) - || validate_4(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 40; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Tfsync(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_4(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 50; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static bool validate_Tversion(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_4(ctx) - || validate_s(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 100; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rversion(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_4(ctx) - || validate_s(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 101; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rerror(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_s(ctx) +static ssize_t validate_Tstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tstat); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 11; + VALIDATE_NET_BYTES(11); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(124)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(124)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rstat); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_nstat = net_offset + 7; + uint32_t offsetof_stat = net_offset + 9; + uint32_t offsetof_stat_stat_size = net_offset + 9; + uint32_t offsetof_stat_kern_type = net_offset + 11; + uint32_t offsetof_stat_file_qid_type = net_offset + 17; + VALIDATE_NET_BYTES(30); + if (GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_stat_file_mode = net_offset + 0; + VALIDATE_NET_BYTES(22); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); #if CONFIG_9P_ENABLE_9P2000_u - || ( is_ver(ctx, 9P2000_u) && validate_4(ctx) ) + if (is_ver(ctx, 9P2000_u)) { + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(12); + } #endif /* CONFIG_9P_ENABLE_9P2000_u */ - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 107; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Twalk(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint16_t nwname; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_fid(ctx) - || (validate_2(ctx) || ({ nwname = uint16le_decode(&ctx->net_bytes[ctx->net_offset-2]); false; })) - || _validate_list(ctx, nwname, validate_s, sizeof(struct lib9p_s)) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 110; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - || ({ uint16_t max = 16; (((uint16_t)nwname) > max) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "nwname value is too large (%"PRIu16" > %"PRIu16")", nwname, max); }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static bool validate_Trename(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_fid(ctx) - || validate_s(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 20; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rreadlink(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_s(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 23; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Txattrwalk(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_fid(ctx) - || validate_s(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 30; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Txattrcreate(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_s(ctx) - || validate_8(ctx) - || validate_4(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 32; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Tgetlock(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_1(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_4(ctx) - || validate_s(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 54; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rgetlock(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_1(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_4(ctx) - || validate_s(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 55; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Tlink(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_fid(ctx) - || validate_s(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 70; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Trenameat(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_s(ctx) - || validate_fid(ctx) - || validate_s(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 74; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Tunlinkat(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_s(ctx) - || validate_4(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 76; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000_e -LM_FLATTEN static bool validate_Tsread(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint16_t nwname; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_4(ctx) - || (validate_2(ctx) || ({ nwname = uint16le_decode(&ctx->net_bytes[ctx->net_offset-2]); false; })) - || _validate_list(ctx, nwname, validate_s, sizeof(struct lib9p_s)) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 152; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Tswrite(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint16_t nwname; - uint32_t count; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_4(ctx) - || (validate_2(ctx) || ({ nwname = uint16le_decode(&ctx->net_bytes[ctx->net_offset-2]); false; })) - || _validate_list(ctx, nwname, validate_s, sizeof(struct lib9p_s)) - || (validate_4(ctx) || ({ count = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || _validate_size_net(ctx, count) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 154; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000_e */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static bool validate_qid(struct _validate_ctx *ctx) { - return false - || validate_qt(ctx) - || validate_4(ctx) - || validate_8(ctx) - ; -} - -LM_FLATTEN static bool validate_Tauth(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_s(ctx) - || validate_s(ctx) -#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u - || ( ( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) ) && validate_nuid(ctx) ) -#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 102; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Tattach(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_fid(ctx) - || validate_s(ctx) - || validate_s(ctx) -#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u - || ( ( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) ) && validate_nuid(ctx) ) -#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 104; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static bool validate_Tlcreate(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_s(ctx) - || validate_4(ctx) - || validate_4(ctx) - || validate_nuid(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 14; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Tsymlink(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_s(ctx) - || validate_s(ctx) - || validate_nuid(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 16; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Tmknod(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_s(ctx) - || validate_4(ctx) - || validate_4(ctx) - || validate_4(ctx) - || validate_nuid(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 18; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Tmkdir(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_s(ctx) - || validate_4(ctx) - || validate_nuid(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 72; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static bool validate_Topen(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_o(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 112; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Tcreate(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_s(ctx) - || validate_dm(ctx) - || validate_o(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 114; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_p9p -LM_FLATTEN static bool validate_Topenfd(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_o(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 98; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000_p9p */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static bool validate_Tgetattr(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_getattr(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 24; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Tsetattr(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_setattr(ctx) - || validate_4(ctx) - || validate_nuid(ctx) - || validate_nuid(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 26; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Tlock(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || validate_lock_type(ctx) - || validate_lock_flags(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_4(ctx) - || validate_s(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 52; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rlock(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_lock_status(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 53; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static bool validate_stat(struct _validate_ctx *ctx) { - uint16_t stat_size; - uint32_t _kern_type_offset; - return false - || (validate_2(ctx) || ({ stat_size = uint16le_decode(&ctx->net_bytes[ctx->net_offset-2]); false; })) - || ({ _kern_type_offset = ctx->net_offset; validate_2(ctx); }) - || validate_4(ctx) - || validate_qid(ctx) - || validate_dm(ctx) - || validate_4(ctx) - || validate_4(ctx) - || validate_8(ctx) - || validate_s(ctx) - || validate_s(ctx) - || validate_s(ctx) - || validate_s(ctx) + uint32_t offsetof_stat_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_stat_stat_size) != (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstat->stat.stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_stat_stat_size), (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type)); + if (GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32, + GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version]); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(125)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(125)); + if ((uint32_t)GET_U32LE(offsetof_nstat) != (uint32_t)(offsetof_end - offsetof_stat)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstat->nstat value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_nstat), (uint32_t)(offsetof_end - offsetof_stat)); + return (ssize_t)host_size; +} + +static ssize_t validate_Twstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Twstat); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_nstat = net_offset + 11; + uint32_t offsetof_stat = net_offset + 13; + uint32_t offsetof_stat_stat_size = net_offset + 13; + uint32_t offsetof_stat_kern_type = net_offset + 15; + uint32_t offsetof_stat_file_qid_type = net_offset + 21; + VALIDATE_NET_BYTES(34); + if (GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_stat_file_mode = net_offset + 0; + VALIDATE_NET_BYTES(22); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); #if CONFIG_9P_ENABLE_9P2000_u - || ( is_ver(ctx, 9P2000_u) && validate_s(ctx) ) - || ( is_ver(ctx, 9P2000_u) && validate_nuid(ctx) ) - || ( is_ver(ctx, 9P2000_u) && validate_nuid(ctx) ) - || ( is_ver(ctx, 9P2000_u) && validate_nuid(ctx) ) + if (is_ver(ctx, 9P2000_u)) { + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(12); + } #endif /* CONFIG_9P_ENABLE_9P2000_u */ - || ({ uint16_t exp = ctx->net_offset - _kern_type_offset; (((uint16_t)stat_size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "stat_size value is wrong (actual:%"PRIu16" != correct:%"PRIu16")", (uint16_t)stat_size, exp); }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static bool validate_Rauth(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_qid(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 103; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rattach(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_qid(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 105; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rwalk(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint16_t nwqid; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || (validate_2(ctx) || ({ nwqid = uint16le_decode(&ctx->net_bytes[ctx->net_offset-2]); false; })) - || _validate_list(ctx, nwqid, validate_qid, sizeof(struct lib9p_qid)) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 111; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - || ({ uint16_t max = 16; (((uint16_t)nwqid) > max) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "nwqid value is too large (%"PRIu16" > %"PRIu16")", nwqid, max); }) - ; -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static bool validate_Ropen(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_qid(ctx) - || validate_4(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 113; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rcreate(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_qid(ctx) - || validate_4(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 115; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; + uint32_t offsetof_stat_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_stat_stat_size) != (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Twstat->stat.stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_stat_stat_size), (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type)); + if (GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32, + GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version]); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Twstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(126)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Twstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(126)); + if ((uint32_t)GET_U32LE(offsetof_nstat) != (uint32_t)(offsetof_end - offsetof_stat)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Twstat->nstat value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_nstat), (uint32_t)(offsetof_end - offsetof_stat)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rwstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rwstat); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 7; + VALIDATE_NET_BYTES(7); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(127)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(127)); + return (ssize_t)host_size; } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_p9p -LM_FLATTEN static bool validate_Ropenfd(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_qid(ctx) - || validate_4(ctx) - || validate_4(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 99; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; +static ssize_t validate_Topenfd(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Topenfd); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_mode = net_offset + 11; + uint32_t offsetof_end = net_offset + 12; + VALIDATE_NET_BYTES(12); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Topenfd->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(98)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Topenfd->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(98)); + if (GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8, + GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]); + return (ssize_t)host_size; +} + +static ssize_t validate_Ropenfd(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Ropenfd); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_qid_type = net_offset + 7; + VALIDATE_NET_BYTES(20); + if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_end = net_offset + 8; + VALIDATE_NET_BYTES(8); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Ropenfd->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(99)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Ropenfd->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(99)); + return (ssize_t)host_size; } #endif /* CONFIG_9P_ENABLE_9P2000_p9p */ #if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static bool validate_Rlopen(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_qid(ctx) - || validate_4(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 13; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rlcreate(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_qid(ctx) - || validate_4(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 15; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rsymlink(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_qid(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 17; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rmknod(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_qid(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 19; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rgetattr(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_8(ctx) - || validate_qid(ctx) - || validate_4(ctx) - || validate_nuid(ctx) - || validate_nuid(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || validate_8(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 25; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; -} - -LM_FLATTEN static bool validate_Rmkdir(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint32_t _size_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_qid(ctx) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 73; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - ; +static ssize_t validate_Rlerror(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rlerror); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 11; + VALIDATE_NET_BYTES(11); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlerror->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(7)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlerror->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(7)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tstatfs(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tstatfs); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 11; + VALIDATE_NET_BYTES(11); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tstatfs->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(8)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tstatfs->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(8)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rstatfs(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rstatfs); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 67; + VALIDATE_NET_BYTES(67); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstatfs->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(9)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstatfs->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(9)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tlopen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tlopen); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_flags = net_offset + 11; + uint32_t offsetof_end = net_offset + 15; + VALIDATE_NET_BYTES(15); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlopen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(12)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlopen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(12)); + if (GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in lo bitfield: %#08"PRIx32, + GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version]); + return (ssize_t)host_size; +} + +static ssize_t validate_Rlopen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rlopen); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_qid_type = net_offset + 7; + VALIDATE_NET_BYTES(20); + if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_end = net_offset + 4; + VALIDATE_NET_BYTES(4); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlopen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(13)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlopen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(13)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tlcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tlcreate); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(13); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_flags = net_offset + 0; + uint32_t offsetof_mode = net_offset + 4; + uint32_t offsetof_end = net_offset + 12; + VALIDATE_NET_BYTES(12); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(14)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(14)); + if (GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in lo bitfield: %#08"PRIx32, + GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version]); + if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, + GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]); + return (ssize_t)host_size; +} + +static ssize_t validate_Rlcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rlcreate); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_qid_type = net_offset + 7; + VALIDATE_NET_BYTES(20); + if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_end = net_offset + 4; + VALIDATE_NET_BYTES(4); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(15)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(15)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tsymlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tsymlink); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(13); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_end = net_offset + 4; + VALIDATE_NET_BYTES(4); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsymlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(16)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsymlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(16)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rsymlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rsymlink); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_qid_type = net_offset + 7; + VALIDATE_NET_BYTES(20); + if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsymlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(17)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsymlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(17)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tmknod(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tmknod); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(13); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_mode = net_offset + 0; + uint32_t offsetof_end = net_offset + 16; + VALIDATE_NET_BYTES(16); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tmknod->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(18)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tmknod->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(18)); + if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, + GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]); + return (ssize_t)host_size; +} + +static ssize_t validate_Rmknod(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rmknod); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_qid_type = net_offset + 7; + VALIDATE_NET_BYTES(20); + if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rmknod->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(19)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rmknod->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(19)); + return (ssize_t)host_size; +} + +static ssize_t validate_Trename(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Trename); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(17); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Trename->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(20)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Trename->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(20)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rrename(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rrename); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 7; + VALIDATE_NET_BYTES(7); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rrename->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(21)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rrename->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(21)); + return (ssize_t)host_size; +} + +static ssize_t validate_Treadlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Treadlink); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 11; + VALIDATE_NET_BYTES(11); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Treadlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(22)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Treadlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(22)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rreadlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rreadlink); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(9); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rreadlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(23)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rreadlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(23)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tgetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tgetattr); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_request_mask = net_offset + 11; + uint32_t offsetof_end = net_offset + 19; + VALIDATE_NET_BYTES(19); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tgetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(24)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tgetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(24)); + if (GET_U64LE(offsetof_request_mask) & ~getattr_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in getattr bitfield: %#016"PRIx64, + GET_U64LE(offsetof_request_mask) & ~getattr_masks[ctx->version]); + return (ssize_t)host_size; +} + +static ssize_t validate_Rgetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rgetattr); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_valid = net_offset + 7; + uint32_t offsetof_qid_type = net_offset + 15; + VALIDATE_NET_BYTES(28); + if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_mode = net_offset + 0; + uint32_t offsetof_end = net_offset + 132; + VALIDATE_NET_BYTES(132); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rgetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(25)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rgetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(25)); + if (GET_U64LE(offsetof_valid) & ~getattr_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in getattr bitfield: %#016"PRIx64, + GET_U64LE(offsetof_valid) & ~getattr_masks[ctx->version]); + if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, + GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]); + return (ssize_t)host_size; +} + +static ssize_t validate_Tsetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tsetattr); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_valid = net_offset + 11; + uint32_t offsetof_mode = net_offset + 15; + uint32_t offsetof_end = net_offset + 67; + VALIDATE_NET_BYTES(67); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(26)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(26)); + if (GET_U32LE(offsetof_valid) & ~setattr_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in setattr bitfield: %#08"PRIx32, + GET_U32LE(offsetof_valid) & ~setattr_masks[ctx->version]); + if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, + GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]); + return (ssize_t)host_size; +} + +static ssize_t validate_Rsetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rsetattr); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 7; + VALIDATE_NET_BYTES(7); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(27)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(27)); + return (ssize_t)host_size; +} + +static ssize_t validate_Txattrwalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Txattrwalk); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(17); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Txattrwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(30)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Txattrwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(30)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rxattrwalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rxattrwalk); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 15; + VALIDATE_NET_BYTES(15); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rxattrwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(31)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rxattrwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(31)); + return (ssize_t)host_size; +} + +static ssize_t validate_Txattrcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Txattrcreate); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(13); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_end = net_offset + 12; + VALIDATE_NET_BYTES(12); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Txattrcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(32)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Txattrcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(32)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rxattrcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rxattrcreate); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 7; + VALIDATE_NET_BYTES(7); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rxattrcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(33)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rxattrcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(33)); + return (ssize_t)host_size; +} + +static ssize_t validate_Treaddir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Treaddir); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 23; + VALIDATE_NET_BYTES(23); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Treaddir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(40)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Treaddir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(40)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rreaddir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rreaddir); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(11); + VALIDATE_NET_BYTES(LAST_U32LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rreaddir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(41)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rreaddir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(41)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tfsync(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tfsync); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 15; + VALIDATE_NET_BYTES(15); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tfsync->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(50)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tfsync->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(50)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rfsync(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rfsync); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 7; + VALIDATE_NET_BYTES(7); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rfsync->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(51)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rfsync->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(51)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tlock); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_flags = net_offset + 12; + VALIDATE_NET_BYTES(38); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(52)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(52)); + if (GET_U32LE(offsetof_flags) & ~lock_flags_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in lock_flags bitfield: %#08"PRIx32, + GET_U32LE(offsetof_flags) & ~lock_flags_masks[ctx->version]); + return (ssize_t)host_size; +} + +static ssize_t validate_Rlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rlock); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 8; + VALIDATE_NET_BYTES(8); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(53)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(53)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tgetlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tgetlock); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(34); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tgetlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(54)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tgetlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(54)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rgetlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rgetlock); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(30); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rgetlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(55)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rgetlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(55)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tlink); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(17); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(70)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(70)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rlink); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 7; + VALIDATE_NET_BYTES(7); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(71)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(71)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tmkdir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tmkdir); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(13); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_mode = net_offset + 0; + uint32_t offsetof_end = net_offset + 8; + VALIDATE_NET_BYTES(8); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tmkdir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(72)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tmkdir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(72)); + if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, + GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]); + return (ssize_t)host_size; +} + +static ssize_t validate_Rmkdir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rmkdir); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_qid_type = net_offset + 7; + VALIDATE_NET_BYTES(20); + if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rmkdir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(73)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rmkdir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(73)); + return (ssize_t)host_size; +} + +static ssize_t validate_Trenameat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Trenameat); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(13); + VALIDATE_NET_UTF8(LAST_U16LE()); + VALIDATE_NET_BYTES(6); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Trenameat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(74)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Trenameat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(74)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rrenameat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rrenameat); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 7; + VALIDATE_NET_BYTES(7); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rrenameat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(75)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rrenameat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(75)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tunlinkat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tunlinkat); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(13); + VALIDATE_NET_UTF8(LAST_U16LE()); + uint32_t offsetof_end = net_offset + 4; + VALIDATE_NET_BYTES(4); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tunlinkat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(76)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tunlinkat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(76)); + return (ssize_t)host_size; +} + +static ssize_t validate_Runlinkat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Runlinkat); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 7; + VALIDATE_NET_BYTES(7); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Runlinkat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(77)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Runlinkat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(77)); + return (ssize_t)host_size; } #endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static bool validate_Rstat(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint16_t nstat; - uint32_t _size_offset; - uint32_t _stat_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || (validate_2(ctx) || ({ nstat = uint16le_decode(&ctx->net_bytes[ctx->net_offset-2]); false; })) - || ({ _stat_offset = ctx->net_offset; validate_stat(ctx); }) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 125; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - || ({ uint16_t exp = ctx->net_offset - _stat_offset; (((uint16_t)nstat) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "nstat value is wrong (actual:%"PRIu16" != correct:%"PRIu16")", (uint16_t)nstat, exp); }) - ; -} - -LM_FLATTEN static bool validate_Twstat(struct _validate_ctx *ctx) { - uint32_t size; - uint8_t typ; - uint16_t nstat; - uint32_t _size_offset; - uint32_t _stat_offset; - return false - || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = uint32le_decode(&ctx->net_bytes[ctx->net_offset-4]); false; })) - || (validate_1(ctx) || ({ typ = ctx->net_bytes[ctx->net_offset-1]; false; })) - || validate_tag(ctx) - || validate_fid(ctx) - || (validate_2(ctx) || ({ nstat = uint16le_decode(&ctx->net_bytes[ctx->net_offset-2]); false; })) - || ({ _stat_offset = ctx->net_offset; validate_stat(ctx); }) - || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); }) - || ({ uint8_t exp = 126; (((uint8_t)typ) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu8" != correct:%"PRIu8")", (uint8_t)typ, exp); }) - || ({ uint16_t exp = ctx->net_offset - _stat_offset; (((uint16_t)nstat) != exp) && - lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "nstat value is wrong (actual:%"PRIu16" != correct:%"PRIu16")", (uint16_t)nstat, exp); }) - ; +#if CONFIG_9P_ENABLE_9P2000_e +static ssize_t validate_Tsession(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tsession); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 15; + VALIDATE_NET_BYTES(15); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsession->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(150)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsession->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(150)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rsession(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rsession); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 7; + VALIDATE_NET_BYTES(7); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsession->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(151)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsession->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(151)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tsread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tsread); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(13); + for (uint16_t i = 0, cnt = LAST_U16LE(); i < cnt; i++) { + RESERVE_HOST_BYTES(sizeof(struct lib9p_s)); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); + } + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(152)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(152)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rsread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rsread); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(11); + VALIDATE_NET_BYTES(LAST_U32LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(153)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(153)); + return (ssize_t)host_size; +} + +static ssize_t validate_Tswrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Tswrite); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + VALIDATE_NET_BYTES(13); + for (uint16_t i = 0, cnt = LAST_U16LE(); i < cnt; i++) { + RESERVE_HOST_BYTES(sizeof(struct lib9p_s)); + VALIDATE_NET_BYTES(2); + VALIDATE_NET_UTF8(LAST_U16LE()); + } + VALIDATE_NET_BYTES(4); + VALIDATE_NET_BYTES(LAST_U32LE()); + uint32_t offsetof_end = net_offset + 0; + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tswrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(154)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Tswrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(154)); + return (ssize_t)host_size; +} + +static ssize_t validate_Rswrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { + uint32_t net_offset = 0; + ssize_t host_size = sizeof(struct lib9p_msg_Rswrite); + uint32_t offsetof_size = net_offset + 0; + uint32_t offsetof_typ = net_offset + 4; + uint32_t offsetof_end = net_offset + 11; + VALIDATE_NET_BYTES(11); + if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rswrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); + if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(155)) + return lib9p_errorf(ctx, LINUX_EBADMSG, "Rswrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(155)); + return (ssize_t)host_size; } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#endif /* CONFIG_9P_ENABLE_9P2000_e */ /* unmarshal_* ****************************************************************/ -LM_ALWAYS_INLINE static void unmarshal_1(struct _unmarshal_ctx *ctx, uint8_t *out) { - *out = ctx->net_bytes[ctx->net_offset]; - ctx->net_offset += 1; -} - -LM_ALWAYS_INLINE static void unmarshal_2(struct _unmarshal_ctx *ctx, uint16_t *out) { - *out = uint16le_decode(&ctx->net_bytes[ctx->net_offset]); - ctx->net_offset += 2; -} - -LM_ALWAYS_INLINE static void unmarshal_4(struct _unmarshal_ctx *ctx, uint32_t *out) { - *out = uint32le_decode(&ctx->net_bytes[ctx->net_offset]); - ctx->net_offset += 4; -} +#define UNMARSHAL_BYTES(ctx, data_lvalue, len) \ + data_lvalue = (char *)&net_bytes[net_offset]; \ + net_offset += len; +#define UNMARSHAL_U8LE(ctx, val_lvalue) \ + val_lvalue = net_bytes[net_offset]; \ + net_offset += 1; +#define UNMARSHAL_U16LE(ctx, val_lvalue) \ + val_lvalue = uint16le_decode(&net_bytes[net_offset]); \ + net_offset += 2; +#define UNMARSHAL_U32LE(ctx, val_lvalue) \ + val_lvalue = uint32le_decode(&net_bytes[net_offset]); \ + net_offset += 4; +#define UNMARSHAL_U64LE(ctx, val_lvalue) \ + val_lvalue = uint64le_decode(&net_bytes[net_offset]); \ + net_offset += 8; -LM_ALWAYS_INLINE static void unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out) { - *out = uint64le_decode(&ctx->net_bytes[ctx->net_offset]); - ctx->net_offset += 8; -} - -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static void unmarshal_tag(struct _unmarshal_ctx *ctx, lib9p_tag_t *out) { - unmarshal_2(ctx, (uint16_t *)out); -} - -LM_ALWAYS_INLINE static void unmarshal_fid(struct _unmarshal_ctx *ctx, lib9p_fid_t *out) { - unmarshal_4(ctx, (uint32_t *)out); -} - -LM_ALWAYS_INLINE static void unmarshal_s(struct _unmarshal_ctx *ctx, struct lib9p_s *out) { - memset(out, 0, sizeof(*out)); - unmarshal_2(ctx, &out->len); - out->utf8 = (char *)&ctx->net_bytes[ctx->net_offset]; - ctx->net_offset += out->len; -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static void unmarshal_dm(struct _unmarshal_ctx *ctx, lib9p_dm_t *out) { - unmarshal_4(ctx, (uint32_t *)out); +static void unmarshal_stat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_stat *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 2; + UNMARSHAL_U16LE(ctx, out->kern_type); + UNMARSHAL_U32LE(ctx, out->kern_dev); + UNMARSHAL_U8LE(ctx, out->file_qid.type); + UNMARSHAL_U32LE(ctx, out->file_qid.vers); + UNMARSHAL_U64LE(ctx, out->file_qid.path); + UNMARSHAL_U32LE(ctx, out->file_mode); + UNMARSHAL_U32LE(ctx, out->file_atime); + UNMARSHAL_U32LE(ctx, out->file_mtime); + UNMARSHAL_U64LE(ctx, out->file_size); + UNMARSHAL_U16LE(ctx, out->file_name.len); + UNMARSHAL_BYTES(ctx, out->file_name.utf8, out->file_name.len); + UNMARSHAL_U16LE(ctx, out->file_owner_uid.len); + UNMARSHAL_BYTES(ctx, out->file_owner_uid.utf8, out->file_owner_uid.len); + UNMARSHAL_U16LE(ctx, out->file_owner_gid.len); + UNMARSHAL_BYTES(ctx, out->file_owner_gid.utf8, out->file_owner_gid.len); + UNMARSHAL_U16LE(ctx, out->file_last_modified_uid.len); + UNMARSHAL_BYTES(ctx, out->file_last_modified_uid.utf8, out->file_last_modified_uid.len); +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + UNMARSHAL_U16LE(ctx, out->file_extension.len); + UNMARSHAL_BYTES(ctx, out->file_extension.utf8, out->file_extension.len); + UNMARSHAL_U32LE(ctx, out->file_owner_n_uid); + UNMARSHAL_U32LE(ctx, out->file_owner_n_gid); + UNMARSHAL_U32LE(ctx, out->file_last_modified_n_uid); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static void unmarshal_qt(struct _unmarshal_ctx *ctx, lib9p_qt_t *out) { - unmarshal_1(ctx, (uint8_t *)out); -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +static void unmarshal_Tversion([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tversion *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->max_msg_size); + UNMARSHAL_U16LE(ctx, out->version.len); + UNMARSHAL_BYTES(ctx, out->version.utf8, out->version.len); +} + +static void unmarshal_Rversion([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rversion *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->max_msg_size); + UNMARSHAL_U16LE(ctx, out->version.len); + UNMARSHAL_BYTES(ctx, out->version.utf8, out->version.len); +} + +static void unmarshal_Tauth([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tauth *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->afid); + UNMARSHAL_U16LE(ctx, out->uname.len); + UNMARSHAL_BYTES(ctx, out->uname.utf8, out->uname.len); + UNMARSHAL_U16LE(ctx, out->aname.len); + UNMARSHAL_BYTES(ctx, out->aname.utf8, out->aname.len); #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static void unmarshal_nuid(struct _unmarshal_ctx *ctx, lib9p_nuid_t *out) { - unmarshal_4(ctx, (uint32_t *)out); -} - + if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) { + UNMARSHAL_U32LE(ctx, out->n_uid); + } #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static void unmarshal_o(struct _unmarshal_ctx *ctx, lib9p_o_t *out) { - unmarshal_1(ctx, (uint8_t *)out); -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_ALWAYS_INLINE static void unmarshal_getattr(struct _unmarshal_ctx *ctx, lib9p_getattr_t *out) { - unmarshal_8(ctx, (uint64_t *)out); } -LM_ALWAYS_INLINE static void unmarshal_setattr(struct _unmarshal_ctx *ctx, lib9p_setattr_t *out) { - unmarshal_4(ctx, (uint32_t *)out); -} - -LM_ALWAYS_INLINE static void unmarshal_lock_type(struct _unmarshal_ctx *ctx, lib9p_lock_type_t *out) { - unmarshal_1(ctx, (uint8_t *)out); -} - -LM_ALWAYS_INLINE static void unmarshal_lock_flags(struct _unmarshal_ctx *ctx, lib9p_lock_flags_t *out) { - unmarshal_4(ctx, (uint32_t *)out); -} - -LM_ALWAYS_INLINE static void unmarshal_lock_status(struct _unmarshal_ctx *ctx, lib9p_lock_status_t *out) { - unmarshal_1(ctx, (uint8_t *)out); -} - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static void unmarshal_Tflush(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tflush *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_2(ctx, &out->oldtag); -} - -LM_FLATTEN static void unmarshal_Rflush(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rflush *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); -} - -LM_FLATTEN static void unmarshal_Rread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rread *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_4(ctx, &out->count); - out->data = (char *)&ctx->net_bytes[ctx->net_offset]; - ctx->net_offset += out->count; +static void unmarshal_Rauth([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rauth *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U8LE(ctx, out->aqid.type); + UNMARSHAL_U32LE(ctx, out->aqid.vers); + UNMARSHAL_U64LE(ctx, out->aqid.path); +} + +static void unmarshal_Tattach([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tattach *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U32LE(ctx, out->afid); + UNMARSHAL_U16LE(ctx, out->uname.len); + UNMARSHAL_BYTES(ctx, out->uname.utf8, out->uname.len); + UNMARSHAL_U16LE(ctx, out->aname.len); + UNMARSHAL_BYTES(ctx, out->aname.utf8, out->aname.len); +#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u + if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) { + UNMARSHAL_U32LE(ctx, out->n_uid); + } +#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ } -LM_FLATTEN static void unmarshal_Rwrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwrite *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_4(ctx, &out->count); +static void unmarshal_Rattach([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rattach *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U8LE(ctx, out->qid.type); + UNMARSHAL_U32LE(ctx, out->qid.vers); + UNMARSHAL_U64LE(ctx, out->qid.path); +} + +static void unmarshal_Rerror([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rerror *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U16LE(ctx, out->ename.len); + UNMARSHAL_BYTES(ctx, out->ename.utf8, out->ename.len); +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + UNMARSHAL_U32LE(ctx, out->errno); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ } -LM_FLATTEN static void unmarshal_Rclunk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rclunk *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); +static void unmarshal_Tflush([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tflush *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U16LE(ctx, out->oldtag); +} + +static void unmarshal_Rflush([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rflush *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); +} + +static void unmarshal_Twalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Twalk *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U32LE(ctx, out->newfid); + UNMARSHAL_U16LE(ctx, out->nwname); + out->wname = extra; + extra += sizeof(out->wname[0]) * out->nwname; + for (uint16_t i = 0; i < out->nwname; i++) { + UNMARSHAL_U16LE(ctx, out->wname[i].len); + UNMARSHAL_BYTES(ctx, out->wname[i].utf8, out->wname[i].len); + } } -LM_FLATTEN static void unmarshal_Rremove(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rremove *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); +static void unmarshal_Rwalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rwalk *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U16LE(ctx, out->nwqid); + out->wqid = extra; + extra += sizeof(out->wqid[0]) * out->nwqid; + for (uint16_t i = 0; i < out->nwqid; i++) { + UNMARSHAL_U8LE(ctx, out->wqid[i].type); + UNMARSHAL_U32LE(ctx, out->wqid[i].vers); + UNMARSHAL_U64LE(ctx, out->wqid[i].path); + } } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static void unmarshal_Rwstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwstat *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); +static void unmarshal_Topen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Topen *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U8LE(ctx, out->mode); +} + +static void unmarshal_Ropen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Ropen *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U8LE(ctx, out->qid.type); + UNMARSHAL_U32LE(ctx, out->qid.vers); + UNMARSHAL_U64LE(ctx, out->qid.path); + UNMARSHAL_U32LE(ctx, out->iounit); +} + +static void unmarshal_Tcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tcreate *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U16LE(ctx, out->name.len); + UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len); + UNMARSHAL_U32LE(ctx, out->perm); + UNMARSHAL_U8LE(ctx, out->mode); +} + +static void unmarshal_Rcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rcreate *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U8LE(ctx, out->qid.type); + UNMARSHAL_U32LE(ctx, out->qid.vers); + UNMARSHAL_U64LE(ctx, out->qid.path); + UNMARSHAL_U32LE(ctx, out->iounit); } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static void unmarshal_Rlerror(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rlerror *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_4(ctx, &out->ecode); -} - -LM_FLATTEN static void unmarshal_Rstatfs(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rstatfs *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_4(ctx, &out->type); - unmarshal_4(ctx, &out->bsize); - unmarshal_8(ctx, &out->blocks); - unmarshal_8(ctx, &out->bfree); - unmarshal_8(ctx, &out->bavail); - unmarshal_8(ctx, &out->files); - unmarshal_8(ctx, &out->ffree); - unmarshal_8(ctx, &out->fsid); - unmarshal_4(ctx, &out->namelen); -} - -LM_FLATTEN static void unmarshal_Rrename(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rrename *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); -} - -LM_FLATTEN static void unmarshal_Rsetattr(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rsetattr *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); -} - -LM_FLATTEN static void unmarshal_Rxattrwalk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rxattrwalk *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_8(ctx, &out->attr_size); -} - -LM_FLATTEN static void unmarshal_Rxattrcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rxattrcreate *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); -} - -LM_FLATTEN static void unmarshal_Rreaddir(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rreaddir *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_4(ctx, &out->count); - out->data = (char *)&ctx->net_bytes[ctx->net_offset]; - ctx->net_offset += out->count; -} - -LM_FLATTEN static void unmarshal_Rfsync(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rfsync *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); -} - -LM_FLATTEN static void unmarshal_Rlink(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rlink *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); -} - -LM_FLATTEN static void unmarshal_Rrenameat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rrenameat *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); -} - -LM_FLATTEN static void unmarshal_Runlinkat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Runlinkat *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); -} - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000_e -LM_FLATTEN static void unmarshal_Tsession(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tsession *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_8(ctx, &out->key); -} - -LM_FLATTEN static void unmarshal_Rsession(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rsession *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); -} - -LM_FLATTEN static void unmarshal_Rsread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rsread *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_4(ctx, &out->count); - out->data = (char *)&ctx->net_bytes[ctx->net_offset]; - ctx->net_offset += out->count; -} - -LM_FLATTEN static void unmarshal_Rswrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rswrite *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_4(ctx, &out->count); -} - -#endif /* CONFIG_9P_ENABLE_9P2000_e */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static void unmarshal_Tread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tread *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_8(ctx, &out->offset); - unmarshal_4(ctx, &out->count); -} - -LM_FLATTEN static void unmarshal_Twrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twrite *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_8(ctx, &out->offset); - unmarshal_4(ctx, &out->count); - out->data = (char *)&ctx->net_bytes[ctx->net_offset]; - ctx->net_offset += out->count; -} - -LM_FLATTEN static void unmarshal_Tclunk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tclunk *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); -} - -LM_FLATTEN static void unmarshal_Tremove(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tremove *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); +static void unmarshal_Tread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tread *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U64LE(ctx, out->offset); + UNMARSHAL_U32LE(ctx, out->count); +} + +static void unmarshal_Rread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rread *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->count); + UNMARSHAL_BYTES(ctx, out->data, out->count); +} + +static void unmarshal_Twrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Twrite *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U64LE(ctx, out->offset); + UNMARSHAL_U32LE(ctx, out->count); + UNMARSHAL_BYTES(ctx, out->data, out->count); +} + +static void unmarshal_Rwrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rwrite *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->count); +} + +static void unmarshal_Tclunk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tclunk *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); +} + +static void unmarshal_Rclunk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rclunk *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); +} + +static void unmarshal_Tremove([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tremove *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); +} + +static void unmarshal_Rremove([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rremove *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static void unmarshal_Tstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tstat *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static void unmarshal_Tstatfs(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tstatfs *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); -} - -LM_FLATTEN static void unmarshal_Tlopen(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tlopen *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_4(ctx, &out->flags); -} - -LM_FLATTEN static void unmarshal_Treadlink(struct _unmarshal_ctx *ctx, struct lib9p_msg_Treadlink *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); -} - -LM_FLATTEN static void unmarshal_Treaddir(struct _unmarshal_ctx *ctx, struct lib9p_msg_Treaddir *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_8(ctx, &out->offset); - unmarshal_4(ctx, &out->count); -} - -LM_FLATTEN static void unmarshal_Tfsync(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tfsync *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_4(ctx, &out->datasync); -} - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static void unmarshal_Tversion(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tversion *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_4(ctx, &out->max_msg_size); - unmarshal_s(ctx, &out->version); -} - -LM_FLATTEN static void unmarshal_Rversion(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rversion *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_4(ctx, &out->max_msg_size); - unmarshal_s(ctx, &out->version); -} - -LM_FLATTEN static void unmarshal_Rerror(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rerror *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_s(ctx, &out->ename); +static void unmarshal_Tstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tstat *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); +} + +static void unmarshal_Rstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rstat *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + net_offset += 2; + net_offset += 2; + UNMARSHAL_U16LE(ctx, out->stat.kern_type); + UNMARSHAL_U32LE(ctx, out->stat.kern_dev); + UNMARSHAL_U8LE(ctx, out->stat.file_qid.type); + UNMARSHAL_U32LE(ctx, out->stat.file_qid.vers); + UNMARSHAL_U64LE(ctx, out->stat.file_qid.path); + UNMARSHAL_U32LE(ctx, out->stat.file_mode); + UNMARSHAL_U32LE(ctx, out->stat.file_atime); + UNMARSHAL_U32LE(ctx, out->stat.file_mtime); + UNMARSHAL_U64LE(ctx, out->stat.file_size); + UNMARSHAL_U16LE(ctx, out->stat.file_name.len); + UNMARSHAL_BYTES(ctx, out->stat.file_name.utf8, out->stat.file_name.len); + UNMARSHAL_U16LE(ctx, out->stat.file_owner_uid.len); + UNMARSHAL_BYTES(ctx, out->stat.file_owner_uid.utf8, out->stat.file_owner_uid.len); + UNMARSHAL_U16LE(ctx, out->stat.file_owner_gid.len); + UNMARSHAL_BYTES(ctx, out->stat.file_owner_gid.utf8, out->stat.file_owner_gid.len); + UNMARSHAL_U16LE(ctx, out->stat.file_last_modified_uid.len); + UNMARSHAL_BYTES(ctx, out->stat.file_last_modified_uid.utf8, out->stat.file_last_modified_uid.len); #if CONFIG_9P_ENABLE_9P2000_u - if ( is_ver(ctx, 9P2000_u) ) unmarshal_4(ctx, &out->errno); + if (is_ver(ctx, 9P2000_u)) { + UNMARSHAL_U16LE(ctx, out->stat.file_extension.len); + UNMARSHAL_BYTES(ctx, out->stat.file_extension.utf8, out->stat.file_extension.len); + UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_uid); + UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_gid); + UNMARSHAL_U32LE(ctx, out->stat.file_last_modified_n_uid); + } #endif /* CONFIG_9P_ENABLE_9P2000_u */ } -LM_FLATTEN static void unmarshal_Twalk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twalk *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_fid(ctx, &out->newfid); - unmarshal_2(ctx, &out->nwname); - out->wname = ctx->extra; - ctx->extra += sizeof(out->wname[0]) * out->nwname; - for (typeof(out->nwname) i = 0; i < out->nwname; i++) - unmarshal_s(ctx, &out->wname[i]); -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static void unmarshal_Trename(struct _unmarshal_ctx *ctx, struct lib9p_msg_Trename *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_fid(ctx, &out->dfid); - unmarshal_s(ctx, &out->name); -} - -LM_FLATTEN static void unmarshal_Rreadlink(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rreadlink *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_s(ctx, &out->target); -} - -LM_FLATTEN static void unmarshal_Txattrwalk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Txattrwalk *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_fid(ctx, &out->newfid); - unmarshal_s(ctx, &out->name); -} - -LM_FLATTEN static void unmarshal_Txattrcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Txattrcreate *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_s(ctx, &out->name); - unmarshal_8(ctx, &out->attr_size); - unmarshal_4(ctx, &out->flags); -} - -LM_FLATTEN static void unmarshal_Tgetlock(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tgetlock *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_1(ctx, &out->type); - unmarshal_8(ctx, &out->start); - unmarshal_8(ctx, &out->length); - unmarshal_4(ctx, &out->proc_id); - unmarshal_s(ctx, &out->client_id); -} - -LM_FLATTEN static void unmarshal_Rgetlock(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rgetlock *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_1(ctx, &out->type); - unmarshal_8(ctx, &out->start); - unmarshal_8(ctx, &out->length); - unmarshal_4(ctx, &out->proc_id); - unmarshal_s(ctx, &out->client_id); -} - -LM_FLATTEN static void unmarshal_Tlink(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tlink *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->dfid); - unmarshal_fid(ctx, &out->fid); - unmarshal_s(ctx, &out->name); -} - -LM_FLATTEN static void unmarshal_Trenameat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Trenameat *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->olddirfid); - unmarshal_s(ctx, &out->oldname); - unmarshal_fid(ctx, &out->newdirfid); - unmarshal_s(ctx, &out->newname); -} - -LM_FLATTEN static void unmarshal_Tunlinkat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tunlinkat *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->dirfd); - unmarshal_s(ctx, &out->name); - unmarshal_4(ctx, &out->flags); -} - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000_e -LM_FLATTEN static void unmarshal_Tsread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tsread *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_4(ctx, &out->fid); - unmarshal_2(ctx, &out->nwname); - out->wname = ctx->extra; - ctx->extra += sizeof(out->wname[0]) * out->nwname; - for (typeof(out->nwname) i = 0; i < out->nwname; i++) - unmarshal_s(ctx, &out->wname[i]); -} - -LM_FLATTEN static void unmarshal_Tswrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tswrite *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_4(ctx, &out->fid); - unmarshal_2(ctx, &out->nwname); - out->wname = ctx->extra; - ctx->extra += sizeof(out->wname[0]) * out->nwname; - for (typeof(out->nwname) i = 0; i < out->nwname; i++) - unmarshal_s(ctx, &out->wname[i]); - unmarshal_4(ctx, &out->count); - out->data = (char *)&ctx->net_bytes[ctx->net_offset]; - ctx->net_offset += out->count; -} - -#endif /* CONFIG_9P_ENABLE_9P2000_e */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static void unmarshal_qid(struct _unmarshal_ctx *ctx, struct lib9p_qid *out) { - memset(out, 0, sizeof(*out)); - unmarshal_qt(ctx, &out->type); - unmarshal_4(ctx, &out->vers); - unmarshal_8(ctx, &out->path); -} - -LM_FLATTEN static void unmarshal_Tauth(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tauth *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->afid); - unmarshal_s(ctx, &out->uname); - unmarshal_s(ctx, &out->aname); -#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u - if ( ( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) ) ) unmarshal_nuid(ctx, &out->n_uid); -#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ -} - -LM_FLATTEN static void unmarshal_Tattach(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tattach *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_fid(ctx, &out->afid); - unmarshal_s(ctx, &out->uname); - unmarshal_s(ctx, &out->aname); -#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u - if ( ( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) ) ) unmarshal_nuid(ctx, &out->n_uid); -#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ +static void unmarshal_Twstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Twstat *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + net_offset += 2; + net_offset += 2; + UNMARSHAL_U16LE(ctx, out->stat.kern_type); + UNMARSHAL_U32LE(ctx, out->stat.kern_dev); + UNMARSHAL_U8LE(ctx, out->stat.file_qid.type); + UNMARSHAL_U32LE(ctx, out->stat.file_qid.vers); + UNMARSHAL_U64LE(ctx, out->stat.file_qid.path); + UNMARSHAL_U32LE(ctx, out->stat.file_mode); + UNMARSHAL_U32LE(ctx, out->stat.file_atime); + UNMARSHAL_U32LE(ctx, out->stat.file_mtime); + UNMARSHAL_U64LE(ctx, out->stat.file_size); + UNMARSHAL_U16LE(ctx, out->stat.file_name.len); + UNMARSHAL_BYTES(ctx, out->stat.file_name.utf8, out->stat.file_name.len); + UNMARSHAL_U16LE(ctx, out->stat.file_owner_uid.len); + UNMARSHAL_BYTES(ctx, out->stat.file_owner_uid.utf8, out->stat.file_owner_uid.len); + UNMARSHAL_U16LE(ctx, out->stat.file_owner_gid.len); + UNMARSHAL_BYTES(ctx, out->stat.file_owner_gid.utf8, out->stat.file_owner_gid.len); + UNMARSHAL_U16LE(ctx, out->stat.file_last_modified_uid.len); + UNMARSHAL_BYTES(ctx, out->stat.file_last_modified_uid.utf8, out->stat.file_last_modified_uid.len); +#if CONFIG_9P_ENABLE_9P2000_u + if (is_ver(ctx, 9P2000_u)) { + UNMARSHAL_U16LE(ctx, out->stat.file_extension.len); + UNMARSHAL_BYTES(ctx, out->stat.file_extension.utf8, out->stat.file_extension.len); + UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_uid); + UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_gid); + UNMARSHAL_U32LE(ctx, out->stat.file_last_modified_n_uid); + } +#endif /* CONFIG_9P_ENABLE_9P2000_u */ } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static void unmarshal_Tlcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tlcreate *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_s(ctx, &out->name); - unmarshal_4(ctx, &out->flags); - unmarshal_4(ctx, &out->mode); - unmarshal_nuid(ctx, &out->gid); -} - -LM_FLATTEN static void unmarshal_Tsymlink(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tsymlink *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_s(ctx, &out->name); - unmarshal_s(ctx, &out->symtgt); - unmarshal_nuid(ctx, &out->gid); -} - -LM_FLATTEN static void unmarshal_Tmknod(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tmknod *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->dfid); - unmarshal_s(ctx, &out->name); - unmarshal_4(ctx, &out->mode); - unmarshal_4(ctx, &out->major); - unmarshal_4(ctx, &out->minor); - unmarshal_nuid(ctx, &out->gid); -} - -LM_FLATTEN static void unmarshal_Tmkdir(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tmkdir *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->dfid); - unmarshal_s(ctx, &out->name); - unmarshal_4(ctx, &out->mode); - unmarshal_nuid(ctx, &out->gid); -} - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static void unmarshal_Topen(struct _unmarshal_ctx *ctx, struct lib9p_msg_Topen *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_o(ctx, &out->mode); -} - -LM_FLATTEN static void unmarshal_Tcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tcreate *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_s(ctx, &out->name); - unmarshal_dm(ctx, &out->perm); - unmarshal_o(ctx, &out->mode); +static void unmarshal_Rwstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rwstat *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_p9p -LM_FLATTEN static void unmarshal_Topenfd(struct _unmarshal_ctx *ctx, struct lib9p_msg_Topenfd *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_o(ctx, &out->mode); +static void unmarshal_Topenfd([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Topenfd *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U8LE(ctx, out->mode); +} + +static void unmarshal_Ropenfd([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Ropenfd *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U8LE(ctx, out->qid.type); + UNMARSHAL_U32LE(ctx, out->qid.vers); + UNMARSHAL_U64LE(ctx, out->qid.path); + UNMARSHAL_U32LE(ctx, out->iounit); + UNMARSHAL_U32LE(ctx, out->unixfd); } #endif /* CONFIG_9P_ENABLE_9P2000_p9p */ #if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static void unmarshal_Tgetattr(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tgetattr *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_getattr(ctx, &out->request_mask); -} - -LM_FLATTEN static void unmarshal_Tsetattr(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tsetattr *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_setattr(ctx, &out->valid); - unmarshal_4(ctx, &out->mode); - unmarshal_nuid(ctx, &out->uid); - unmarshal_nuid(ctx, &out->gid); - unmarshal_8(ctx, &out->filesize); - unmarshal_8(ctx, &out->atime_sec); - unmarshal_8(ctx, &out->atime_nsec); - unmarshal_8(ctx, &out->mtime_sec); - unmarshal_8(ctx, &out->mtime_nsec); -} - -LM_FLATTEN static void unmarshal_Tlock(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tlock *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - unmarshal_lock_type(ctx, &out->type); - unmarshal_lock_flags(ctx, &out->flags); - unmarshal_8(ctx, &out->start); - unmarshal_8(ctx, &out->length); - unmarshal_4(ctx, &out->proc_id); - unmarshal_s(ctx, &out->client_id); -} - -LM_FLATTEN static void unmarshal_Rlock(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rlock *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_lock_status(ctx, &out->status); +static void unmarshal_Rlerror([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rlerror *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->ecode); +} + +static void unmarshal_Tstatfs([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tstatfs *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); +} + +static void unmarshal_Rstatfs([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rstatfs *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->type); + UNMARSHAL_U32LE(ctx, out->bsize); + UNMARSHAL_U64LE(ctx, out->blocks); + UNMARSHAL_U64LE(ctx, out->bfree); + UNMARSHAL_U64LE(ctx, out->bavail); + UNMARSHAL_U64LE(ctx, out->files); + UNMARSHAL_U64LE(ctx, out->ffree); + UNMARSHAL_U64LE(ctx, out->fsid); + UNMARSHAL_U32LE(ctx, out->namelen); +} + +static void unmarshal_Tlopen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tlopen *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U32LE(ctx, out->flags); +} + +static void unmarshal_Rlopen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rlopen *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U8LE(ctx, out->qid.type); + UNMARSHAL_U32LE(ctx, out->qid.vers); + UNMARSHAL_U64LE(ctx, out->qid.path); + UNMARSHAL_U32LE(ctx, out->iounit); +} + +static void unmarshal_Tlcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tlcreate *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U16LE(ctx, out->name.len); + UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len); + UNMARSHAL_U32LE(ctx, out->flags); + UNMARSHAL_U32LE(ctx, out->mode); + UNMARSHAL_U32LE(ctx, out->gid); +} + +static void unmarshal_Rlcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rlcreate *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U8LE(ctx, out->qid.type); + UNMARSHAL_U32LE(ctx, out->qid.vers); + UNMARSHAL_U64LE(ctx, out->qid.path); + UNMARSHAL_U32LE(ctx, out->iounit); +} + +static void unmarshal_Tsymlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tsymlink *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U16LE(ctx, out->name.len); + UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len); + UNMARSHAL_U16LE(ctx, out->symtgt.len); + UNMARSHAL_BYTES(ctx, out->symtgt.utf8, out->symtgt.len); + UNMARSHAL_U32LE(ctx, out->gid); +} + +static void unmarshal_Rsymlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rsymlink *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U8LE(ctx, out->qid.type); + UNMARSHAL_U32LE(ctx, out->qid.vers); + UNMARSHAL_U64LE(ctx, out->qid.path); +} + +static void unmarshal_Tmknod([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tmknod *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->dfid); + UNMARSHAL_U16LE(ctx, out->name.len); + UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len); + UNMARSHAL_U32LE(ctx, out->mode); + UNMARSHAL_U32LE(ctx, out->major); + UNMARSHAL_U32LE(ctx, out->minor); + UNMARSHAL_U32LE(ctx, out->gid); +} + +static void unmarshal_Rmknod([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rmknod *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U8LE(ctx, out->qid.type); + UNMARSHAL_U32LE(ctx, out->qid.vers); + UNMARSHAL_U64LE(ctx, out->qid.path); +} + +static void unmarshal_Trename([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Trename *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U32LE(ctx, out->dfid); + UNMARSHAL_U16LE(ctx, out->name.len); + UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len); +} + +static void unmarshal_Rrename([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rrename *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); +} + +static void unmarshal_Treadlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Treadlink *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); +} + +static void unmarshal_Rreadlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rreadlink *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U16LE(ctx, out->target.len); + UNMARSHAL_BYTES(ctx, out->target.utf8, out->target.len); +} + +static void unmarshal_Tgetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tgetattr *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U64LE(ctx, out->request_mask); +} + +static void unmarshal_Rgetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rgetattr *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U64LE(ctx, out->valid); + UNMARSHAL_U8LE(ctx, out->qid.type); + UNMARSHAL_U32LE(ctx, out->qid.vers); + UNMARSHAL_U64LE(ctx, out->qid.path); + UNMARSHAL_U32LE(ctx, out->mode); + UNMARSHAL_U32LE(ctx, out->uid); + UNMARSHAL_U32LE(ctx, out->gid); + UNMARSHAL_U64LE(ctx, out->nlink); + UNMARSHAL_U64LE(ctx, out->rdev); + UNMARSHAL_U64LE(ctx, out->filesize); + UNMARSHAL_U64LE(ctx, out->blksize); + UNMARSHAL_U64LE(ctx, out->blocks); + UNMARSHAL_U64LE(ctx, out->atime_sec); + UNMARSHAL_U64LE(ctx, out->atime_nsec); + UNMARSHAL_U64LE(ctx, out->mtime_sec); + UNMARSHAL_U64LE(ctx, out->mtime_nsec); + UNMARSHAL_U64LE(ctx, out->ctime_sec); + UNMARSHAL_U64LE(ctx, out->ctime_nsec); + UNMARSHAL_U64LE(ctx, out->btime_sec); + UNMARSHAL_U64LE(ctx, out->btime_nsec); + UNMARSHAL_U64LE(ctx, out->gen); + UNMARSHAL_U64LE(ctx, out->data_version); +} + +static void unmarshal_Tsetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tsetattr *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U32LE(ctx, out->valid); + UNMARSHAL_U32LE(ctx, out->mode); + UNMARSHAL_U32LE(ctx, out->uid); + UNMARSHAL_U32LE(ctx, out->gid); + UNMARSHAL_U64LE(ctx, out->filesize); + UNMARSHAL_U64LE(ctx, out->atime_sec); + UNMARSHAL_U64LE(ctx, out->atime_nsec); + UNMARSHAL_U64LE(ctx, out->mtime_sec); + UNMARSHAL_U64LE(ctx, out->mtime_nsec); +} + +static void unmarshal_Rsetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rsetattr *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); +} + +static void unmarshal_Txattrwalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Txattrwalk *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U32LE(ctx, out->newfid); + UNMARSHAL_U16LE(ctx, out->name.len); + UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len); +} + +static void unmarshal_Rxattrwalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rxattrwalk *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U64LE(ctx, out->attr_size); +} + +static void unmarshal_Txattrcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Txattrcreate *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U16LE(ctx, out->name.len); + UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len); + UNMARSHAL_U64LE(ctx, out->attr_size); + UNMARSHAL_U32LE(ctx, out->flags); +} + +static void unmarshal_Rxattrcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rxattrcreate *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); +} + +static void unmarshal_Treaddir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Treaddir *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U64LE(ctx, out->offset); + UNMARSHAL_U32LE(ctx, out->count); +} + +static void unmarshal_Rreaddir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rreaddir *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->count); + UNMARSHAL_BYTES(ctx, out->data, out->count); +} + +static void unmarshal_Tfsync([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tfsync *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U32LE(ctx, out->datasync); +} + +static void unmarshal_Rfsync([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rfsync *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); +} + +static void unmarshal_Tlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tlock *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U8LE(ctx, out->type); + UNMARSHAL_U32LE(ctx, out->flags); + UNMARSHAL_U64LE(ctx, out->start); + UNMARSHAL_U64LE(ctx, out->length); + UNMARSHAL_U32LE(ctx, out->proc_id); + UNMARSHAL_U16LE(ctx, out->client_id.len); + UNMARSHAL_BYTES(ctx, out->client_id.utf8, out->client_id.len); +} + +static void unmarshal_Rlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rlock *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U8LE(ctx, out->status); +} + +static void unmarshal_Tgetlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tgetlock *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U8LE(ctx, out->type); + UNMARSHAL_U64LE(ctx, out->start); + UNMARSHAL_U64LE(ctx, out->length); + UNMARSHAL_U32LE(ctx, out->proc_id); + UNMARSHAL_U16LE(ctx, out->client_id.len); + UNMARSHAL_BYTES(ctx, out->client_id.utf8, out->client_id.len); +} + +static void unmarshal_Rgetlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rgetlock *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U8LE(ctx, out->type); + UNMARSHAL_U64LE(ctx, out->start); + UNMARSHAL_U64LE(ctx, out->length); + UNMARSHAL_U32LE(ctx, out->proc_id); + UNMARSHAL_U16LE(ctx, out->client_id.len); + UNMARSHAL_BYTES(ctx, out->client_id.utf8, out->client_id.len); +} + +static void unmarshal_Tlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tlink *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->dfid); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U16LE(ctx, out->name.len); + UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len); +} + +static void unmarshal_Rlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rlink *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); +} + +static void unmarshal_Tmkdir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tmkdir *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->dfid); + UNMARSHAL_U16LE(ctx, out->name.len); + UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len); + UNMARSHAL_U32LE(ctx, out->mode); + UNMARSHAL_U32LE(ctx, out->gid); +} + +static void unmarshal_Rmkdir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rmkdir *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U8LE(ctx, out->qid.type); + UNMARSHAL_U32LE(ctx, out->qid.vers); + UNMARSHAL_U64LE(ctx, out->qid.path); +} + +static void unmarshal_Trenameat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Trenameat *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->olddirfid); + UNMARSHAL_U16LE(ctx, out->oldname.len); + UNMARSHAL_BYTES(ctx, out->oldname.utf8, out->oldname.len); + UNMARSHAL_U32LE(ctx, out->newdirfid); + UNMARSHAL_U16LE(ctx, out->newname.len); + UNMARSHAL_BYTES(ctx, out->newname.utf8, out->newname.len); +} + +static void unmarshal_Rrenameat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rrenameat *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); +} + +static void unmarshal_Tunlinkat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tunlinkat *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->dirfd); + UNMARSHAL_U16LE(ctx, out->name.len); + UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len); + UNMARSHAL_U32LE(ctx, out->flags); +} + +static void unmarshal_Runlinkat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Runlinkat *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); } #endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_ALWAYS_INLINE static void unmarshal_stat(struct _unmarshal_ctx *ctx, struct lib9p_stat *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 2; - unmarshal_2(ctx, &out->kern_type); - unmarshal_4(ctx, &out->kern_dev); - unmarshal_qid(ctx, &out->file_qid); - unmarshal_dm(ctx, &out->file_mode); - unmarshal_4(ctx, &out->file_atime); - unmarshal_4(ctx, &out->file_mtime); - unmarshal_8(ctx, &out->file_size); - unmarshal_s(ctx, &out->file_name); - unmarshal_s(ctx, &out->file_owner_uid); - unmarshal_s(ctx, &out->file_owner_gid); - unmarshal_s(ctx, &out->file_last_modified_uid); -#if CONFIG_9P_ENABLE_9P2000_u - if ( is_ver(ctx, 9P2000_u) ) unmarshal_s(ctx, &out->file_extension); - if ( is_ver(ctx, 9P2000_u) ) unmarshal_nuid(ctx, &out->file_owner_n_uid); - if ( is_ver(ctx, 9P2000_u) ) unmarshal_nuid(ctx, &out->file_owner_n_gid); - if ( is_ver(ctx, 9P2000_u) ) unmarshal_nuid(ctx, &out->file_last_modified_n_uid); -#endif /* CONFIG_9P_ENABLE_9P2000_u */ -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static void unmarshal_Rauth(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rauth *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_qid(ctx, &out->aqid); -} - -LM_FLATTEN static void unmarshal_Rattach(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rattach *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_qid(ctx, &out->qid); -} - -LM_FLATTEN static void unmarshal_Rwalk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwalk *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_2(ctx, &out->nwqid); - out->wqid = ctx->extra; - ctx->extra += sizeof(out->wqid[0]) * out->nwqid; - for (typeof(out->nwqid) i = 0; i < out->nwqid; i++) - unmarshal_qid(ctx, &out->wqid[i]); -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static void unmarshal_Ropen(struct _unmarshal_ctx *ctx, struct lib9p_msg_Ropen *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_qid(ctx, &out->qid); - unmarshal_4(ctx, &out->iounit); -} - -LM_FLATTEN static void unmarshal_Rcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rcreate *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_qid(ctx, &out->qid); - unmarshal_4(ctx, &out->iounit); -} - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_p9p -LM_FLATTEN static void unmarshal_Ropenfd(struct _unmarshal_ctx *ctx, struct lib9p_msg_Ropenfd *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_qid(ctx, &out->qid); - unmarshal_4(ctx, &out->iounit); - unmarshal_4(ctx, &out->unixfd); +#if CONFIG_9P_ENABLE_9P2000_e +static void unmarshal_Tsession([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tsession *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U64LE(ctx, out->key); +} + +static void unmarshal_Rsession([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rsession *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); +} + +static void unmarshal_Tsread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tsread *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U16LE(ctx, out->nwname); + out->wname = extra; + extra += sizeof(out->wname[0]) * out->nwname; + for (uint16_t i = 0; i < out->nwname; i++) { + UNMARSHAL_U16LE(ctx, out->wname[i].len); + UNMARSHAL_BYTES(ctx, out->wname[i].utf8, out->wname[i].len); + } } -#endif /* CONFIG_9P_ENABLE_9P2000_p9p */ -#if CONFIG_9P_ENABLE_9P2000_L -LM_FLATTEN static void unmarshal_Rlopen(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rlopen *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_qid(ctx, &out->qid); - unmarshal_4(ctx, &out->iounit); -} - -LM_FLATTEN static void unmarshal_Rlcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rlcreate *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_qid(ctx, &out->qid); - unmarshal_4(ctx, &out->iounit); -} - -LM_FLATTEN static void unmarshal_Rsymlink(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rsymlink *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_qid(ctx, &out->qid); -} - -LM_FLATTEN static void unmarshal_Rmknod(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rmknod *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_qid(ctx, &out->qid); -} - -LM_FLATTEN static void unmarshal_Rgetattr(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rgetattr *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_8(ctx, &out->valid); - unmarshal_qid(ctx, &out->qid); - unmarshal_4(ctx, &out->mode); - unmarshal_nuid(ctx, &out->uid); - unmarshal_nuid(ctx, &out->gid); - unmarshal_8(ctx, &out->nlink); - unmarshal_8(ctx, &out->rdev); - unmarshal_8(ctx, &out->filesize); - unmarshal_8(ctx, &out->blksize); - unmarshal_8(ctx, &out->blocks); - unmarshal_8(ctx, &out->atime_sec); - unmarshal_8(ctx, &out->atime_nsec); - unmarshal_8(ctx, &out->mtime_sec); - unmarshal_8(ctx, &out->mtime_nsec); - unmarshal_8(ctx, &out->ctime_sec); - unmarshal_8(ctx, &out->ctime_nsec); - unmarshal_8(ctx, &out->btime_sec); - unmarshal_8(ctx, &out->btime_nsec); - unmarshal_8(ctx, &out->gen); - unmarshal_8(ctx, &out->data_version); -} - -LM_FLATTEN static void unmarshal_Rmkdir(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rmkdir *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_qid(ctx, &out->qid); +static void unmarshal_Rsread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rsread *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->count); + UNMARSHAL_BYTES(ctx, out->data, out->count); +} + +static void unmarshal_Tswrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Tswrite *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->fid); + UNMARSHAL_U16LE(ctx, out->nwname); + out->wname = extra; + extra += sizeof(out->wname[0]) * out->nwname; + for (uint16_t i = 0; i < out->nwname; i++) { + UNMARSHAL_U16LE(ctx, out->wname[i].len); + UNMARSHAL_BYTES(ctx, out->wname[i].utf8, out->wname[i].len); + } + UNMARSHAL_U32LE(ctx, out->count); + UNMARSHAL_BYTES(ctx, out->data, out->count); } -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -LM_FLATTEN static void unmarshal_Rstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rstat *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - ctx->net_offset += 2; - unmarshal_stat(ctx, &out->stat); -} - -LM_FLATTEN static void unmarshal_Twstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twstat *out) { - memset(out, 0, sizeof(*out)); - ctx->net_offset += 4; - ctx->net_offset += 1; - unmarshal_tag(ctx, &out->tag); - unmarshal_fid(ctx, &out->fid); - ctx->net_offset += 2; - unmarshal_stat(ctx, &out->stat); +static void unmarshal_Rswrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { + struct lib9p_msg_Rswrite *out = out_buf; + [[gnu::unused]] void *extra = &out[1]; + uint32_t net_offset = 0; + net_offset += 4; + net_offset += 1; + UNMARSHAL_U16LE(ctx, out->tag); + UNMARSHAL_U32LE(ctx, out->count); } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#endif /* CONFIG_9P_ENABLE_9P2000_e */ /* marshal_* ******************************************************************/ -#define MARSHAL_BYTES_ZEROCOPY(ctx, data, len) \ - if (ctx->net_iov[ctx->net_iov_cnt-1].iov_len) \ - ctx->net_iov_cnt++; \ - ctx->net_iov[ctx->net_iov_cnt-1].iov_base = data; \ - ctx->net_iov[ctx->net_iov_cnt-1].iov_len = len; \ - ctx->net_iov_cnt++; -#define MARSHAL_BYTES(ctx, data, len) \ - if (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base) \ - ctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size]; \ - memcpy(&ctx->net_copied[ctx->net_copied_size], data, len); \ - ctx->net_copied_size += len; \ - ctx->net_iov[ctx->net_iov_cnt-1].iov_len += len; -#define MARSHAL_U8LE(ctx, val) \ - if (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base) \ - ctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size]; \ - ctx->net_copied[ctx->net_copied_size] = val; \ - ctx->net_copied_size += 1; \ - ctx->net_iov[ctx->net_iov_cnt-1].iov_len += 1; -#define MARSHAL_U16LE(ctx, val) \ - if (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base) \ - ctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size]; \ - uint16le_encode(&ctx->net_copied[ctx->net_copied_size], val); \ - ctx->net_copied_size += 2; \ - ctx->net_iov[ctx->net_iov_cnt-1].iov_len += 2; -#define MARSHAL_U32LE(ctx, val) \ - if (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base) \ - ctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size]; \ - uint32le_encode(&ctx->net_copied[ctx->net_copied_size], val); \ - ctx->net_copied_size += 4; \ - ctx->net_iov[ctx->net_iov_cnt-1].iov_len += 4; -#define MARSHAL_U64LE(ctx, val) \ - if (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base) \ - ctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size]; \ - uint64le_encode(&ctx->net_copied[ctx->net_copied_size], val); \ - ctx->net_copied_size += 8; \ - ctx->net_iov[ctx->net_iov_cnt-1].iov_len += 8; +#define MARSHAL_BYTES_ZEROCOPY(ctx, data, len) \ + if (ret->net_iov[ret->net_iov_cnt-1].iov_len) \ + ret->net_iov_cnt++; \ + ret->net_iov[ret->net_iov_cnt-1].iov_base = data; \ + ret->net_iov[ret->net_iov_cnt-1].iov_len = len; \ + ret->net_iov_cnt++; +#define MARSHAL_BYTES(ctx, data, len) \ + if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \ + ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \ + memcpy(&ret->net_copied[ret->net_copied_size], data, len); \ + ret->net_copied_size += len; \ + ret->net_iov[ret->net_iov_cnt-1].iov_len += len; +#define MARSHAL_U8LE(ctx, val) \ + if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \ + ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \ + ret->net_copied[ret->net_copied_size] = val; \ + ret->net_copied_size += 1; \ + ret->net_iov[ret->net_iov_cnt-1].iov_len += 1; +#define MARSHAL_U16LE(ctx, val) \ + if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \ + ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \ + uint16le_encode(&ret->net_copied[ret->net_copied_size], val); \ + ret->net_copied_size += 2; \ + ret->net_iov[ret->net_iov_cnt-1].iov_len += 2; +#define MARSHAL_U32LE(ctx, val) \ + if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \ + ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \ + uint32le_encode(&ret->net_copied[ret->net_copied_size], val); \ + ret->net_copied_size += 4; \ + ret->net_iov[ret->net_iov_cnt-1].iov_len += 4; +#define MARSHAL_U64LE(ctx, val) \ + if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \ + ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \ + uint64le_encode(&ret->net_copied[ret->net_copied_size], val); \ + ret->net_copied_size += 8; \ + ret->net_iov[ret->net_iov_cnt-1].iov_len += 8; #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -static bool marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val) { +static bool marshal_stat(struct lib9p_ctx *ctx, struct lib9p_stat *val, struct _marshal_ret *ret) { uint32_t needed_size = 49 + val->file_name.len + val->file_owner_uid.len + val->file_owner_gid.len + val->file_last_modified_uid.len; #if CONFIG_9P_ENABLE_9P2000_u if is_ver(ctx, 9P2000_u) { needed_size += 14 + val->file_extension.len; } #endif /* CONFIG_9P_ENABLE_9P2000_u */ - if (needed_size > ctx->ctx->max_msg_size) { + if (needed_size > ctx->max_msg_size) { return true; } uint32_t offsetof_end = needed_size; @@ -2879,10 +3081,10 @@ static bool marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val) { MARSHAL_U16LE(ctx, offsetof_end - offsetof_kern_type); MARSHAL_U16LE(ctx, val->kern_type); MARSHAL_U32LE(ctx, val->kern_dev); - MARSHAL_U8LE(ctx, val->file_qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->file_qid.type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->file_qid.vers); MARSHAL_U64LE(ctx, val->file_qid.path); - MARSHAL_U32LE(ctx, val->file_mode & dm_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->file_mode & dm_masks[ctx->version]); MARSHAL_U32LE(ctx, val->file_atime); MARSHAL_U32LE(ctx, val->file_mtime); MARSHAL_U64LE(ctx, val->file_size); @@ -2898,20 +3100,8 @@ static bool marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val) { if (is_ver(ctx, 9P2000_u)) { MARSHAL_U16LE(ctx, val->file_extension.len); MARSHAL_BYTES(ctx, val->file_extension.utf8, val->file_extension.len); - } -#endif /* CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_u - if (is_ver(ctx, 9P2000_u)) { MARSHAL_U32LE(ctx, val->file_owner_n_uid); - } -#endif /* CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_u - if (is_ver(ctx, 9P2000_u)) { MARSHAL_U32LE(ctx, val->file_owner_n_gid); - } -#endif /* CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_u - if (is_ver(ctx, 9P2000_u)) { MARSHAL_U32LE(ctx, val->file_last_modified_n_uid); } #endif /* CONFIG_9P_ENABLE_9P2000_u */ @@ -2920,13 +3110,13 @@ static bool marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val) { #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -static bool marshal_Tversion(struct _marshal_ctx *ctx, struct lib9p_msg_Tversion *val) { +static bool marshal_Tversion(struct lib9p_ctx *ctx, struct lib9p_msg_Tversion *val, struct _marshal_ret *ret) { uint32_t needed_size = 13 + val->version.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tversion", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -2940,13 +3130,13 @@ static bool marshal_Tversion(struct _marshal_ctx *ctx, struct lib9p_msg_Tversion return false; } -static bool marshal_Rversion(struct _marshal_ctx *ctx, struct lib9p_msg_Rversion *val) { +static bool marshal_Rversion(struct lib9p_ctx *ctx, struct lib9p_msg_Rversion *val, struct _marshal_ret *ret) { uint32_t needed_size = 13 + val->version.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rversion", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -2960,18 +3150,18 @@ static bool marshal_Rversion(struct _marshal_ctx *ctx, struct lib9p_msg_Rversion return false; } -static bool marshal_Tauth(struct _marshal_ctx *ctx, struct lib9p_msg_Tauth *val) { +static bool marshal_Tauth(struct lib9p_ctx *ctx, struct lib9p_msg_Tauth *val, struct _marshal_ret *ret) { uint32_t needed_size = 15 + val->uname.len + val->aname.len; #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u if ( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) ) { needed_size += 4; } #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tauth", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -2992,13 +3182,13 @@ static bool marshal_Tauth(struct _marshal_ctx *ctx, struct lib9p_msg_Tauth *val) return false; } -static bool marshal_Rauth(struct _marshal_ctx *ctx, struct lib9p_msg_Rauth *val) { +static bool marshal_Rauth(struct lib9p_ctx *ctx, struct lib9p_msg_Rauth *val, struct _marshal_ret *ret) { uint32_t needed_size = 20; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rauth", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3006,24 +3196,24 @@ static bool marshal_Rauth(struct _marshal_ctx *ctx, struct lib9p_msg_Rauth *val) MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); MARSHAL_U8LE(ctx, 103); MARSHAL_U16LE(ctx, val->tag); - MARSHAL_U8LE(ctx, val->aqid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->aqid.type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->aqid.vers); MARSHAL_U64LE(ctx, val->aqid.path); return false; } -static bool marshal_Tattach(struct _marshal_ctx *ctx, struct lib9p_msg_Tattach *val) { +static bool marshal_Tattach(struct lib9p_ctx *ctx, struct lib9p_msg_Tattach *val, struct _marshal_ret *ret) { uint32_t needed_size = 19 + val->uname.len + val->aname.len; #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u if ( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) ) { needed_size += 4; } #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tattach", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3045,13 +3235,13 @@ static bool marshal_Tattach(struct _marshal_ctx *ctx, struct lib9p_msg_Tattach * return false; } -static bool marshal_Rattach(struct _marshal_ctx *ctx, struct lib9p_msg_Rattach *val) { +static bool marshal_Rattach(struct lib9p_ctx *ctx, struct lib9p_msg_Rattach *val, struct _marshal_ret *ret) { uint32_t needed_size = 20; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rattach", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3059,24 +3249,24 @@ static bool marshal_Rattach(struct _marshal_ctx *ctx, struct lib9p_msg_Rattach * MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); MARSHAL_U8LE(ctx, 105); MARSHAL_U16LE(ctx, val->tag); - MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->qid.vers); MARSHAL_U64LE(ctx, val->qid.path); return false; } -static bool marshal_Rerror(struct _marshal_ctx *ctx, struct lib9p_msg_Rerror *val) { +static bool marshal_Rerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rerror *val, struct _marshal_ret *ret) { uint32_t needed_size = 9 + val->ename.len; #if CONFIG_9P_ENABLE_9P2000_u if is_ver(ctx, 9P2000_u) { needed_size += 4; } #endif /* CONFIG_9P_ENABLE_9P2000_u */ - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rerror", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3094,13 +3284,13 @@ static bool marshal_Rerror(struct _marshal_ctx *ctx, struct lib9p_msg_Rerror *va return false; } -static bool marshal_Tflush(struct _marshal_ctx *ctx, struct lib9p_msg_Tflush *val) { +static bool marshal_Tflush(struct lib9p_ctx *ctx, struct lib9p_msg_Tflush *val, struct _marshal_ret *ret) { uint32_t needed_size = 9; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tflush", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3112,13 +3302,13 @@ static bool marshal_Tflush(struct _marshal_ctx *ctx, struct lib9p_msg_Tflush *va return false; } -static bool marshal_Rflush(struct _marshal_ctx *ctx, struct lib9p_msg_Rflush *val) { +static bool marshal_Rflush(struct lib9p_ctx *ctx, struct lib9p_msg_Rflush *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rflush", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3129,16 +3319,16 @@ static bool marshal_Rflush(struct _marshal_ctx *ctx, struct lib9p_msg_Rflush *va return false; } -static bool marshal_Twalk(struct _marshal_ctx *ctx, struct lib9p_msg_Twalk *val) { +static bool marshal_Twalk(struct lib9p_ctx *ctx, struct lib9p_msg_Twalk *val, struct _marshal_ret *ret) { uint32_t needed_size = 17; for (uint16_t i = 0; i < val->nwname; i++) { needed_size += 2 + val->wname[i].len; } - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Twalk", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3156,13 +3346,13 @@ static bool marshal_Twalk(struct _marshal_ctx *ctx, struct lib9p_msg_Twalk *val) return false; } -static bool marshal_Rwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Rwalk *val) { +static bool marshal_Rwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Rwalk *val, struct _marshal_ret *ret) { uint32_t needed_size = 9 + (val->nwqid)*13; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rwalk", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3172,7 +3362,7 @@ static bool marshal_Rwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Rwalk *val) MARSHAL_U16LE(ctx, val->tag); MARSHAL_U16LE(ctx, val->nwqid); for (uint16_t i = 0; i < val->nwqid; i++) { - MARSHAL_U8LE(ctx, val->wqid[i].type & qt_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->wqid[i].type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->wqid[i].vers); MARSHAL_U64LE(ctx, val->wqid[i].path); } @@ -3181,13 +3371,13 @@ static bool marshal_Rwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Rwalk *val) #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -static bool marshal_Topen(struct _marshal_ctx *ctx, struct lib9p_msg_Topen *val) { +static bool marshal_Topen(struct lib9p_ctx *ctx, struct lib9p_msg_Topen *val, struct _marshal_ret *ret) { uint32_t needed_size = 12; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Topen", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3196,17 +3386,17 @@ static bool marshal_Topen(struct _marshal_ctx *ctx, struct lib9p_msg_Topen *val) MARSHAL_U8LE(ctx, 112); MARSHAL_U16LE(ctx, val->tag); MARSHAL_U32LE(ctx, val->fid); - MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->version]); return false; } -static bool marshal_Ropen(struct _marshal_ctx *ctx, struct lib9p_msg_Ropen *val) { +static bool marshal_Ropen(struct lib9p_ctx *ctx, struct lib9p_msg_Ropen *val, struct _marshal_ret *ret) { uint32_t needed_size = 24; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Ropen", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3214,20 +3404,20 @@ static bool marshal_Ropen(struct _marshal_ctx *ctx, struct lib9p_msg_Ropen *val) MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); MARSHAL_U8LE(ctx, 113); MARSHAL_U16LE(ctx, val->tag); - MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->qid.vers); MARSHAL_U64LE(ctx, val->qid.path); MARSHAL_U32LE(ctx, val->iounit); return false; } -static bool marshal_Tcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Tcreate *val) { +static bool marshal_Tcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Tcreate *val, struct _marshal_ret *ret) { uint32_t needed_size = 18 + val->name.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tcreate", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3238,18 +3428,18 @@ static bool marshal_Tcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Tcreate * MARSHAL_U32LE(ctx, val->fid); MARSHAL_U16LE(ctx, val->name.len); MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len); - MARSHAL_U32LE(ctx, val->perm & dm_masks[ctx->ctx->version]); - MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->perm & dm_masks[ctx->version]); + MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->version]); return false; } -static bool marshal_Rcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rcreate *val) { +static bool marshal_Rcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rcreate *val, struct _marshal_ret *ret) { uint32_t needed_size = 24; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rcreate", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3257,7 +3447,7 @@ static bool marshal_Rcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rcreate * MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); MARSHAL_U8LE(ctx, 115); MARSHAL_U16LE(ctx, val->tag); - MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->qid.vers); MARSHAL_U64LE(ctx, val->qid.path); MARSHAL_U32LE(ctx, val->iounit); @@ -3266,13 +3456,13 @@ static bool marshal_Rcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rcreate * #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -static bool marshal_Tread(struct _marshal_ctx *ctx, struct lib9p_msg_Tread *val) { +static bool marshal_Tread(struct lib9p_ctx *ctx, struct lib9p_msg_Tread *val, struct _marshal_ret *ret) { uint32_t needed_size = 23; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tread", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3286,13 +3476,13 @@ static bool marshal_Tread(struct _marshal_ctx *ctx, struct lib9p_msg_Tread *val) return false; } -static bool marshal_Rread(struct _marshal_ctx *ctx, struct lib9p_msg_Rread *val) { +static bool marshal_Rread(struct lib9p_ctx *ctx, struct lib9p_msg_Rread *val, struct _marshal_ret *ret) { uint32_t needed_size = 11 + val->count; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rread", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3305,13 +3495,13 @@ static bool marshal_Rread(struct _marshal_ctx *ctx, struct lib9p_msg_Rread *val) return false; } -static bool marshal_Twrite(struct _marshal_ctx *ctx, struct lib9p_msg_Twrite *val) { +static bool marshal_Twrite(struct lib9p_ctx *ctx, struct lib9p_msg_Twrite *val, struct _marshal_ret *ret) { uint32_t needed_size = 23 + val->count; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Twrite", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3326,13 +3516,13 @@ static bool marshal_Twrite(struct _marshal_ctx *ctx, struct lib9p_msg_Twrite *va return false; } -static bool marshal_Rwrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rwrite *val) { +static bool marshal_Rwrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rwrite *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rwrite", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3344,13 +3534,13 @@ static bool marshal_Rwrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rwrite *va return false; } -static bool marshal_Tclunk(struct _marshal_ctx *ctx, struct lib9p_msg_Tclunk *val) { +static bool marshal_Tclunk(struct lib9p_ctx *ctx, struct lib9p_msg_Tclunk *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tclunk", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3362,13 +3552,13 @@ static bool marshal_Tclunk(struct _marshal_ctx *ctx, struct lib9p_msg_Tclunk *va return false; } -static bool marshal_Rclunk(struct _marshal_ctx *ctx, struct lib9p_msg_Rclunk *val) { +static bool marshal_Rclunk(struct lib9p_ctx *ctx, struct lib9p_msg_Rclunk *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rclunk", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3379,13 +3569,13 @@ static bool marshal_Rclunk(struct _marshal_ctx *ctx, struct lib9p_msg_Rclunk *va return false; } -static bool marshal_Tremove(struct _marshal_ctx *ctx, struct lib9p_msg_Tremove *val) { +static bool marshal_Tremove(struct lib9p_ctx *ctx, struct lib9p_msg_Tremove *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tremove", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3397,13 +3587,13 @@ static bool marshal_Tremove(struct _marshal_ctx *ctx, struct lib9p_msg_Tremove * return false; } -static bool marshal_Rremove(struct _marshal_ctx *ctx, struct lib9p_msg_Rremove *val) { +static bool marshal_Rremove(struct lib9p_ctx *ctx, struct lib9p_msg_Rremove *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rremove", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3416,13 +3606,13 @@ static bool marshal_Rremove(struct _marshal_ctx *ctx, struct lib9p_msg_Rremove * #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -static bool marshal_Tstat(struct _marshal_ctx *ctx, struct lib9p_msg_Tstat *val) { +static bool marshal_Tstat(struct lib9p_ctx *ctx, struct lib9p_msg_Tstat *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tstat", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3434,18 +3624,18 @@ static bool marshal_Tstat(struct _marshal_ctx *ctx, struct lib9p_msg_Tstat *val) return false; } -static bool marshal_Rstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rstat *val) { +static bool marshal_Rstat(struct lib9p_ctx *ctx, struct lib9p_msg_Rstat *val, struct _marshal_ret *ret) { uint32_t needed_size = 58 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len; #if CONFIG_9P_ENABLE_9P2000_u if is_ver(ctx, 9P2000_u) { needed_size += 14 + val->stat.file_extension.len; } #endif /* CONFIG_9P_ENABLE_9P2000_u */ - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rstat", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3465,10 +3655,10 @@ static bool marshal_Rstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rstat *val) MARSHAL_U16LE(ctx, offsetof_stat_end - offsetof_stat_kern_type); MARSHAL_U16LE(ctx, val->stat.kern_type); MARSHAL_U32LE(ctx, val->stat.kern_dev); - MARSHAL_U8LE(ctx, val->stat.file_qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->stat.file_qid.type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->stat.file_qid.vers); MARSHAL_U64LE(ctx, val->stat.file_qid.path); - MARSHAL_U32LE(ctx, val->stat.file_mode & dm_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->stat.file_mode & dm_masks[ctx->version]); MARSHAL_U32LE(ctx, val->stat.file_atime); MARSHAL_U32LE(ctx, val->stat.file_mtime); MARSHAL_U64LE(ctx, val->stat.file_size); @@ -3484,38 +3674,26 @@ static bool marshal_Rstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rstat *val) if (is_ver(ctx, 9P2000_u)) { MARSHAL_U16LE(ctx, val->stat.file_extension.len); MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_extension.utf8, val->stat.file_extension.len); - } -#endif /* CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_u - if (is_ver(ctx, 9P2000_u)) { MARSHAL_U32LE(ctx, val->stat.file_owner_n_uid); - } -#endif /* CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_u - if (is_ver(ctx, 9P2000_u)) { MARSHAL_U32LE(ctx, val->stat.file_owner_n_gid); - } -#endif /* CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_u - if (is_ver(ctx, 9P2000_u)) { MARSHAL_U32LE(ctx, val->stat.file_last_modified_n_uid); } #endif /* CONFIG_9P_ENABLE_9P2000_u */ return false; } -static bool marshal_Twstat(struct _marshal_ctx *ctx, struct lib9p_msg_Twstat *val) { +static bool marshal_Twstat(struct lib9p_ctx *ctx, struct lib9p_msg_Twstat *val, struct _marshal_ret *ret) { uint32_t needed_size = 62 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len; #if CONFIG_9P_ENABLE_9P2000_u if is_ver(ctx, 9P2000_u) { needed_size += 14 + val->stat.file_extension.len; } #endif /* CONFIG_9P_ENABLE_9P2000_u */ - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Twstat", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3536,10 +3714,10 @@ static bool marshal_Twstat(struct _marshal_ctx *ctx, struct lib9p_msg_Twstat *va MARSHAL_U16LE(ctx, offsetof_stat_end - offsetof_stat_kern_type); MARSHAL_U16LE(ctx, val->stat.kern_type); MARSHAL_U32LE(ctx, val->stat.kern_dev); - MARSHAL_U8LE(ctx, val->stat.file_qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->stat.file_qid.type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->stat.file_qid.vers); MARSHAL_U64LE(ctx, val->stat.file_qid.path); - MARSHAL_U32LE(ctx, val->stat.file_mode & dm_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->stat.file_mode & dm_masks[ctx->version]); MARSHAL_U32LE(ctx, val->stat.file_atime); MARSHAL_U32LE(ctx, val->stat.file_mtime); MARSHAL_U64LE(ctx, val->stat.file_size); @@ -3555,33 +3733,21 @@ static bool marshal_Twstat(struct _marshal_ctx *ctx, struct lib9p_msg_Twstat *va if (is_ver(ctx, 9P2000_u)) { MARSHAL_U16LE(ctx, val->stat.file_extension.len); MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_extension.utf8, val->stat.file_extension.len); - } -#endif /* CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_u - if (is_ver(ctx, 9P2000_u)) { MARSHAL_U32LE(ctx, val->stat.file_owner_n_uid); - } -#endif /* CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_u - if (is_ver(ctx, 9P2000_u)) { MARSHAL_U32LE(ctx, val->stat.file_owner_n_gid); - } -#endif /* CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_u - if (is_ver(ctx, 9P2000_u)) { MARSHAL_U32LE(ctx, val->stat.file_last_modified_n_uid); } #endif /* CONFIG_9P_ENABLE_9P2000_u */ return false; } -static bool marshal_Rwstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rwstat *val) { +static bool marshal_Rwstat(struct lib9p_ctx *ctx, struct lib9p_msg_Rwstat *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rwstat", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3594,13 +3760,13 @@ static bool marshal_Rwstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rwstat *va #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_p9p -static bool marshal_Topenfd(struct _marshal_ctx *ctx, struct lib9p_msg_Topenfd *val) { +static bool marshal_Topenfd(struct lib9p_ctx *ctx, struct lib9p_msg_Topenfd *val, struct _marshal_ret *ret) { uint32_t needed_size = 12; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Topenfd", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3609,17 +3775,17 @@ static bool marshal_Topenfd(struct _marshal_ctx *ctx, struct lib9p_msg_Topenfd * MARSHAL_U8LE(ctx, 98); MARSHAL_U16LE(ctx, val->tag); MARSHAL_U32LE(ctx, val->fid); - MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->version]); return false; } -static bool marshal_Ropenfd(struct _marshal_ctx *ctx, struct lib9p_msg_Ropenfd *val) { +static bool marshal_Ropenfd(struct lib9p_ctx *ctx, struct lib9p_msg_Ropenfd *val, struct _marshal_ret *ret) { uint32_t needed_size = 28; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Ropenfd", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3627,7 +3793,7 @@ static bool marshal_Ropenfd(struct _marshal_ctx *ctx, struct lib9p_msg_Ropenfd * MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); MARSHAL_U8LE(ctx, 99); MARSHAL_U16LE(ctx, val->tag); - MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->qid.vers); MARSHAL_U64LE(ctx, val->qid.path); MARSHAL_U32LE(ctx, val->iounit); @@ -3637,13 +3803,13 @@ static bool marshal_Ropenfd(struct _marshal_ctx *ctx, struct lib9p_msg_Ropenfd * #endif /* CONFIG_9P_ENABLE_9P2000_p9p */ #if CONFIG_9P_ENABLE_9P2000_L -static bool marshal_Rlerror(struct _marshal_ctx *ctx, struct lib9p_msg_Rlerror *val) { +static bool marshal_Rlerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rlerror *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rlerror", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3655,13 +3821,13 @@ static bool marshal_Rlerror(struct _marshal_ctx *ctx, struct lib9p_msg_Rlerror * return false; } -static bool marshal_Tstatfs(struct _marshal_ctx *ctx, struct lib9p_msg_Tstatfs *val) { +static bool marshal_Tstatfs(struct lib9p_ctx *ctx, struct lib9p_msg_Tstatfs *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tstatfs", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3673,13 +3839,13 @@ static bool marshal_Tstatfs(struct _marshal_ctx *ctx, struct lib9p_msg_Tstatfs * return false; } -static bool marshal_Rstatfs(struct _marshal_ctx *ctx, struct lib9p_msg_Rstatfs *val) { +static bool marshal_Rstatfs(struct lib9p_ctx *ctx, struct lib9p_msg_Rstatfs *val, struct _marshal_ret *ret) { uint32_t needed_size = 67; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rstatfs", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3699,13 +3865,13 @@ static bool marshal_Rstatfs(struct _marshal_ctx *ctx, struct lib9p_msg_Rstatfs * return false; } -static bool marshal_Tlopen(struct _marshal_ctx *ctx, struct lib9p_msg_Tlopen *val) { +static bool marshal_Tlopen(struct lib9p_ctx *ctx, struct lib9p_msg_Tlopen *val, struct _marshal_ret *ret) { uint32_t needed_size = 15; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tlopen", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3714,17 +3880,17 @@ static bool marshal_Tlopen(struct _marshal_ctx *ctx, struct lib9p_msg_Tlopen *va MARSHAL_U8LE(ctx, 12); MARSHAL_U16LE(ctx, val->tag); MARSHAL_U32LE(ctx, val->fid); - MARSHAL_U32LE(ctx, val->flags); + MARSHAL_U32LE(ctx, val->flags & lo_masks[ctx->version]); return false; } -static bool marshal_Rlopen(struct _marshal_ctx *ctx, struct lib9p_msg_Rlopen *val) { +static bool marshal_Rlopen(struct lib9p_ctx *ctx, struct lib9p_msg_Rlopen *val, struct _marshal_ret *ret) { uint32_t needed_size = 24; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rlopen", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3732,20 +3898,20 @@ static bool marshal_Rlopen(struct _marshal_ctx *ctx, struct lib9p_msg_Rlopen *va MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); MARSHAL_U8LE(ctx, 13); MARSHAL_U16LE(ctx, val->tag); - MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->qid.vers); MARSHAL_U64LE(ctx, val->qid.path); MARSHAL_U32LE(ctx, val->iounit); return false; } -static bool marshal_Tlcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Tlcreate *val) { +static bool marshal_Tlcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Tlcreate *val, struct _marshal_ret *ret) { uint32_t needed_size = 25 + val->name.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tlcreate", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3756,19 +3922,19 @@ static bool marshal_Tlcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Tlcreate MARSHAL_U32LE(ctx, val->fid); MARSHAL_U16LE(ctx, val->name.len); MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len); - MARSHAL_U32LE(ctx, val->flags); - MARSHAL_U32LE(ctx, val->mode); + MARSHAL_U32LE(ctx, val->flags & lo_masks[ctx->version]); + MARSHAL_U32LE(ctx, val->mode & mode_masks[ctx->version]); MARSHAL_U32LE(ctx, val->gid); return false; } -static bool marshal_Rlcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rlcreate *val) { +static bool marshal_Rlcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rlcreate *val, struct _marshal_ret *ret) { uint32_t needed_size = 24; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rlcreate", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3776,20 +3942,20 @@ static bool marshal_Rlcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rlcreate MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); MARSHAL_U8LE(ctx, 15); MARSHAL_U16LE(ctx, val->tag); - MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->qid.vers); MARSHAL_U64LE(ctx, val->qid.path); MARSHAL_U32LE(ctx, val->iounit); return false; } -static bool marshal_Tsymlink(struct _marshal_ctx *ctx, struct lib9p_msg_Tsymlink *val) { +static bool marshal_Tsymlink(struct lib9p_ctx *ctx, struct lib9p_msg_Tsymlink *val, struct _marshal_ret *ret) { uint32_t needed_size = 19 + val->name.len + val->symtgt.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tsymlink", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3806,13 +3972,13 @@ static bool marshal_Tsymlink(struct _marshal_ctx *ctx, struct lib9p_msg_Tsymlink return false; } -static bool marshal_Rsymlink(struct _marshal_ctx *ctx, struct lib9p_msg_Rsymlink *val) { +static bool marshal_Rsymlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rsymlink *val, struct _marshal_ret *ret) { uint32_t needed_size = 20; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rsymlink", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3820,19 +3986,19 @@ static bool marshal_Rsymlink(struct _marshal_ctx *ctx, struct lib9p_msg_Rsymlink MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); MARSHAL_U8LE(ctx, 17); MARSHAL_U16LE(ctx, val->tag); - MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->qid.vers); MARSHAL_U64LE(ctx, val->qid.path); return false; } -static bool marshal_Tmknod(struct _marshal_ctx *ctx, struct lib9p_msg_Tmknod *val) { +static bool marshal_Tmknod(struct lib9p_ctx *ctx, struct lib9p_msg_Tmknod *val, struct _marshal_ret *ret) { uint32_t needed_size = 29 + val->name.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tmknod", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3843,20 +4009,20 @@ static bool marshal_Tmknod(struct _marshal_ctx *ctx, struct lib9p_msg_Tmknod *va MARSHAL_U32LE(ctx, val->dfid); MARSHAL_U16LE(ctx, val->name.len); MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len); - MARSHAL_U32LE(ctx, val->mode); + MARSHAL_U32LE(ctx, val->mode & mode_masks[ctx->version]); MARSHAL_U32LE(ctx, val->major); MARSHAL_U32LE(ctx, val->minor); MARSHAL_U32LE(ctx, val->gid); return false; } -static bool marshal_Rmknod(struct _marshal_ctx *ctx, struct lib9p_msg_Rmknod *val) { +static bool marshal_Rmknod(struct lib9p_ctx *ctx, struct lib9p_msg_Rmknod *val, struct _marshal_ret *ret) { uint32_t needed_size = 20; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rmknod", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3864,19 +4030,19 @@ static bool marshal_Rmknod(struct _marshal_ctx *ctx, struct lib9p_msg_Rmknod *va MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); MARSHAL_U8LE(ctx, 19); MARSHAL_U16LE(ctx, val->tag); - MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->qid.vers); MARSHAL_U64LE(ctx, val->qid.path); return false; } -static bool marshal_Trename(struct _marshal_ctx *ctx, struct lib9p_msg_Trename *val) { +static bool marshal_Trename(struct lib9p_ctx *ctx, struct lib9p_msg_Trename *val, struct _marshal_ret *ret) { uint32_t needed_size = 17 + val->name.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Trename", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3891,13 +4057,13 @@ static bool marshal_Trename(struct _marshal_ctx *ctx, struct lib9p_msg_Trename * return false; } -static bool marshal_Rrename(struct _marshal_ctx *ctx, struct lib9p_msg_Rrename *val) { +static bool marshal_Rrename(struct lib9p_ctx *ctx, struct lib9p_msg_Rrename *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rrename", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3908,13 +4074,13 @@ static bool marshal_Rrename(struct _marshal_ctx *ctx, struct lib9p_msg_Rrename * return false; } -static bool marshal_Treadlink(struct _marshal_ctx *ctx, struct lib9p_msg_Treadlink *val) { +static bool marshal_Treadlink(struct lib9p_ctx *ctx, struct lib9p_msg_Treadlink *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Treadlink", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3926,13 +4092,13 @@ static bool marshal_Treadlink(struct _marshal_ctx *ctx, struct lib9p_msg_Treadli return false; } -static bool marshal_Rreadlink(struct _marshal_ctx *ctx, struct lib9p_msg_Rreadlink *val) { +static bool marshal_Rreadlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rreadlink *val, struct _marshal_ret *ret) { uint32_t needed_size = 9 + val->target.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rreadlink", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3945,13 +4111,13 @@ static bool marshal_Rreadlink(struct _marshal_ctx *ctx, struct lib9p_msg_Rreadli return false; } -static bool marshal_Tgetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Tgetattr *val) { +static bool marshal_Tgetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Tgetattr *val, struct _marshal_ret *ret) { uint32_t needed_size = 19; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tgetattr", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3960,17 +4126,17 @@ static bool marshal_Tgetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Tgetattr MARSHAL_U8LE(ctx, 24); MARSHAL_U16LE(ctx, val->tag); MARSHAL_U32LE(ctx, val->fid); - MARSHAL_U64LE(ctx, val->request_mask & getattr_masks[ctx->ctx->version]); + MARSHAL_U64LE(ctx, val->request_mask & getattr_masks[ctx->version]); return false; } -static bool marshal_Rgetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Rgetattr *val) { +static bool marshal_Rgetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Rgetattr *val, struct _marshal_ret *ret) { uint32_t needed_size = 160; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rgetattr", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -3978,11 +4144,11 @@ static bool marshal_Rgetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Rgetattr MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); MARSHAL_U8LE(ctx, 25); MARSHAL_U16LE(ctx, val->tag); - MARSHAL_U64LE(ctx, val->valid); - MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U64LE(ctx, val->valid & getattr_masks[ctx->version]); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->qid.vers); MARSHAL_U64LE(ctx, val->qid.path); - MARSHAL_U32LE(ctx, val->mode); + MARSHAL_U32LE(ctx, val->mode & mode_masks[ctx->version]); MARSHAL_U32LE(ctx, val->uid); MARSHAL_U32LE(ctx, val->gid); MARSHAL_U64LE(ctx, val->nlink); @@ -4003,13 +4169,13 @@ static bool marshal_Rgetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Rgetattr return false; } -static bool marshal_Tsetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Tsetattr *val) { +static bool marshal_Tsetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Tsetattr *val, struct _marshal_ret *ret) { uint32_t needed_size = 67; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tsetattr", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4018,8 +4184,8 @@ static bool marshal_Tsetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Tsetattr MARSHAL_U8LE(ctx, 26); MARSHAL_U16LE(ctx, val->tag); MARSHAL_U32LE(ctx, val->fid); - MARSHAL_U32LE(ctx, val->valid & setattr_masks[ctx->ctx->version]); - MARSHAL_U32LE(ctx, val->mode); + MARSHAL_U32LE(ctx, val->valid & setattr_masks[ctx->version]); + MARSHAL_U32LE(ctx, val->mode & mode_masks[ctx->version]); MARSHAL_U32LE(ctx, val->uid); MARSHAL_U32LE(ctx, val->gid); MARSHAL_U64LE(ctx, val->filesize); @@ -4030,13 +4196,13 @@ static bool marshal_Tsetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Tsetattr return false; } -static bool marshal_Rsetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Rsetattr *val) { +static bool marshal_Rsetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Rsetattr *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rsetattr", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4047,13 +4213,13 @@ static bool marshal_Rsetattr(struct _marshal_ctx *ctx, struct lib9p_msg_Rsetattr return false; } -static bool marshal_Txattrwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Txattrwalk *val) { +static bool marshal_Txattrwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Txattrwalk *val, struct _marshal_ret *ret) { uint32_t needed_size = 17 + val->name.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Txattrwalk", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4068,13 +4234,13 @@ static bool marshal_Txattrwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Txattr return false; } -static bool marshal_Rxattrwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Rxattrwalk *val) { +static bool marshal_Rxattrwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Rxattrwalk *val, struct _marshal_ret *ret) { uint32_t needed_size = 15; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rxattrwalk", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4086,13 +4252,13 @@ static bool marshal_Rxattrwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Rxattr return false; } -static bool marshal_Txattrcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Txattrcreate *val) { +static bool marshal_Txattrcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Txattrcreate *val, struct _marshal_ret *ret) { uint32_t needed_size = 25 + val->name.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Txattrcreate", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4108,13 +4274,13 @@ static bool marshal_Txattrcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Txat return false; } -static bool marshal_Rxattrcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rxattrcreate *val) { +static bool marshal_Rxattrcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rxattrcreate *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rxattrcreate", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4125,13 +4291,13 @@ static bool marshal_Rxattrcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rxat return false; } -static bool marshal_Treaddir(struct _marshal_ctx *ctx, struct lib9p_msg_Treaddir *val) { +static bool marshal_Treaddir(struct lib9p_ctx *ctx, struct lib9p_msg_Treaddir *val, struct _marshal_ret *ret) { uint32_t needed_size = 23; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Treaddir", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4145,13 +4311,13 @@ static bool marshal_Treaddir(struct _marshal_ctx *ctx, struct lib9p_msg_Treaddir return false; } -static bool marshal_Rreaddir(struct _marshal_ctx *ctx, struct lib9p_msg_Rreaddir *val) { +static bool marshal_Rreaddir(struct lib9p_ctx *ctx, struct lib9p_msg_Rreaddir *val, struct _marshal_ret *ret) { uint64_t needed_size = 11 + val->count; - if (needed_size > (uint64_t)(ctx->ctx->max_msg_size)) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > (uint64_t)(ctx->max_msg_size)) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rreaddir", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = (uint32_t)needed_size; @@ -4164,13 +4330,13 @@ static bool marshal_Rreaddir(struct _marshal_ctx *ctx, struct lib9p_msg_Rreaddir return false; } -static bool marshal_Tfsync(struct _marshal_ctx *ctx, struct lib9p_msg_Tfsync *val) { +static bool marshal_Tfsync(struct lib9p_ctx *ctx, struct lib9p_msg_Tfsync *val, struct _marshal_ret *ret) { uint32_t needed_size = 15; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tfsync", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4183,13 +4349,13 @@ static bool marshal_Tfsync(struct _marshal_ctx *ctx, struct lib9p_msg_Tfsync *va return false; } -static bool marshal_Rfsync(struct _marshal_ctx *ctx, struct lib9p_msg_Rfsync *val) { +static bool marshal_Rfsync(struct lib9p_ctx *ctx, struct lib9p_msg_Rfsync *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rfsync", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4200,13 +4366,13 @@ static bool marshal_Rfsync(struct _marshal_ctx *ctx, struct lib9p_msg_Rfsync *va return false; } -static bool marshal_Tlock(struct _marshal_ctx *ctx, struct lib9p_msg_Tlock *val) { +static bool marshal_Tlock(struct lib9p_ctx *ctx, struct lib9p_msg_Tlock *val, struct _marshal_ret *ret) { uint32_t needed_size = 38 + val->client_id.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tlock", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4216,7 +4382,7 @@ static bool marshal_Tlock(struct _marshal_ctx *ctx, struct lib9p_msg_Tlock *val) MARSHAL_U16LE(ctx, val->tag); MARSHAL_U32LE(ctx, val->fid); MARSHAL_U8LE(ctx, val->type); - MARSHAL_U32LE(ctx, val->flags & lock_flags_masks[ctx->ctx->version]); + MARSHAL_U32LE(ctx, val->flags & lock_flags_masks[ctx->version]); MARSHAL_U64LE(ctx, val->start); MARSHAL_U64LE(ctx, val->length); MARSHAL_U32LE(ctx, val->proc_id); @@ -4225,13 +4391,13 @@ static bool marshal_Tlock(struct _marshal_ctx *ctx, struct lib9p_msg_Tlock *val) return false; } -static bool marshal_Rlock(struct _marshal_ctx *ctx, struct lib9p_msg_Rlock *val) { +static bool marshal_Rlock(struct lib9p_ctx *ctx, struct lib9p_msg_Rlock *val, struct _marshal_ret *ret) { uint32_t needed_size = 8; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rlock", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4243,13 +4409,13 @@ static bool marshal_Rlock(struct _marshal_ctx *ctx, struct lib9p_msg_Rlock *val) return false; } -static bool marshal_Tgetlock(struct _marshal_ctx *ctx, struct lib9p_msg_Tgetlock *val) { +static bool marshal_Tgetlock(struct lib9p_ctx *ctx, struct lib9p_msg_Tgetlock *val, struct _marshal_ret *ret) { uint32_t needed_size = 34 + val->client_id.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tgetlock", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4267,13 +4433,13 @@ static bool marshal_Tgetlock(struct _marshal_ctx *ctx, struct lib9p_msg_Tgetlock return false; } -static bool marshal_Rgetlock(struct _marshal_ctx *ctx, struct lib9p_msg_Rgetlock *val) { +static bool marshal_Rgetlock(struct lib9p_ctx *ctx, struct lib9p_msg_Rgetlock *val, struct _marshal_ret *ret) { uint32_t needed_size = 30 + val->client_id.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rgetlock", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4290,13 +4456,13 @@ static bool marshal_Rgetlock(struct _marshal_ctx *ctx, struct lib9p_msg_Rgetlock return false; } -static bool marshal_Tlink(struct _marshal_ctx *ctx, struct lib9p_msg_Tlink *val) { +static bool marshal_Tlink(struct lib9p_ctx *ctx, struct lib9p_msg_Tlink *val, struct _marshal_ret *ret) { uint32_t needed_size = 17 + val->name.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tlink", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4311,13 +4477,13 @@ static bool marshal_Tlink(struct _marshal_ctx *ctx, struct lib9p_msg_Tlink *val) return false; } -static bool marshal_Rlink(struct _marshal_ctx *ctx, struct lib9p_msg_Rlink *val) { +static bool marshal_Rlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rlink *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rlink", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4328,13 +4494,13 @@ static bool marshal_Rlink(struct _marshal_ctx *ctx, struct lib9p_msg_Rlink *val) return false; } -static bool marshal_Tmkdir(struct _marshal_ctx *ctx, struct lib9p_msg_Tmkdir *val) { +static bool marshal_Tmkdir(struct lib9p_ctx *ctx, struct lib9p_msg_Tmkdir *val, struct _marshal_ret *ret) { uint32_t needed_size = 21 + val->name.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tmkdir", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4345,18 +4511,18 @@ static bool marshal_Tmkdir(struct _marshal_ctx *ctx, struct lib9p_msg_Tmkdir *va MARSHAL_U32LE(ctx, val->dfid); MARSHAL_U16LE(ctx, val->name.len); MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len); - MARSHAL_U32LE(ctx, val->mode); + MARSHAL_U32LE(ctx, val->mode & mode_masks[ctx->version]); MARSHAL_U32LE(ctx, val->gid); return false; } -static bool marshal_Rmkdir(struct _marshal_ctx *ctx, struct lib9p_msg_Rmkdir *val) { +static bool marshal_Rmkdir(struct lib9p_ctx *ctx, struct lib9p_msg_Rmkdir *val, struct _marshal_ret *ret) { uint32_t needed_size = 20; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rmkdir", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4364,19 +4530,19 @@ static bool marshal_Rmkdir(struct _marshal_ctx *ctx, struct lib9p_msg_Rmkdir *va MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); MARSHAL_U8LE(ctx, 73); MARSHAL_U16LE(ctx, val->tag); - MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->ctx->version]); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]); MARSHAL_U32LE(ctx, val->qid.vers); MARSHAL_U64LE(ctx, val->qid.path); return false; } -static bool marshal_Trenameat(struct _marshal_ctx *ctx, struct lib9p_msg_Trenameat *val) { +static bool marshal_Trenameat(struct lib9p_ctx *ctx, struct lib9p_msg_Trenameat *val, struct _marshal_ret *ret) { uint32_t needed_size = 19 + val->oldname.len + val->newname.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Trenameat", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4393,13 +4559,13 @@ static bool marshal_Trenameat(struct _marshal_ctx *ctx, struct lib9p_msg_Trename return false; } -static bool marshal_Rrenameat(struct _marshal_ctx *ctx, struct lib9p_msg_Rrenameat *val) { +static bool marshal_Rrenameat(struct lib9p_ctx *ctx, struct lib9p_msg_Rrenameat *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rrenameat", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4410,13 +4576,13 @@ static bool marshal_Rrenameat(struct _marshal_ctx *ctx, struct lib9p_msg_Rrename return false; } -static bool marshal_Tunlinkat(struct _marshal_ctx *ctx, struct lib9p_msg_Tunlinkat *val) { +static bool marshal_Tunlinkat(struct lib9p_ctx *ctx, struct lib9p_msg_Tunlinkat *val, struct _marshal_ret *ret) { uint32_t needed_size = 17 + val->name.len; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tunlinkat", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4431,13 +4597,13 @@ static bool marshal_Tunlinkat(struct _marshal_ctx *ctx, struct lib9p_msg_Tunlink return false; } -static bool marshal_Runlinkat(struct _marshal_ctx *ctx, struct lib9p_msg_Runlinkat *val) { +static bool marshal_Runlinkat(struct lib9p_ctx *ctx, struct lib9p_msg_Runlinkat *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Runlinkat", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4450,13 +4616,13 @@ static bool marshal_Runlinkat(struct _marshal_ctx *ctx, struct lib9p_msg_Runlink #endif /* CONFIG_9P_ENABLE_9P2000_L */ #if CONFIG_9P_ENABLE_9P2000_e -static bool marshal_Tsession(struct _marshal_ctx *ctx, struct lib9p_msg_Tsession *val) { +static bool marshal_Tsession(struct lib9p_ctx *ctx, struct lib9p_msg_Tsession *val, struct _marshal_ret *ret) { uint32_t needed_size = 15; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tsession", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4468,13 +4634,13 @@ static bool marshal_Tsession(struct _marshal_ctx *ctx, struct lib9p_msg_Tsession return false; } -static bool marshal_Rsession(struct _marshal_ctx *ctx, struct lib9p_msg_Rsession *val) { +static bool marshal_Rsession(struct lib9p_ctx *ctx, struct lib9p_msg_Rsession *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rsession", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4485,16 +4651,16 @@ static bool marshal_Rsession(struct _marshal_ctx *ctx, struct lib9p_msg_Rsession return false; } -static bool marshal_Tsread(struct _marshal_ctx *ctx, struct lib9p_msg_Tsread *val) { +static bool marshal_Tsread(struct lib9p_ctx *ctx, struct lib9p_msg_Tsread *val, struct _marshal_ret *ret) { uint64_t needed_size = 13; for (uint16_t i = 0; i < val->nwname; i++) { needed_size += 2 + val->wname[i].len; } - if (needed_size > (uint64_t)(ctx->ctx->max_msg_size)) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > (uint64_t)(ctx->max_msg_size)) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tsread", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = (uint32_t)needed_size; @@ -4511,13 +4677,13 @@ static bool marshal_Tsread(struct _marshal_ctx *ctx, struct lib9p_msg_Tsread *va return false; } -static bool marshal_Rsread(struct _marshal_ctx *ctx, struct lib9p_msg_Rsread *val) { +static bool marshal_Rsread(struct lib9p_ctx *ctx, struct lib9p_msg_Rsread *val, struct _marshal_ret *ret) { uint64_t needed_size = 11 + val->count; - if (needed_size > (uint64_t)(ctx->ctx->max_msg_size)) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > (uint64_t)(ctx->max_msg_size)) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rsread", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = (uint32_t)needed_size; @@ -4530,16 +4696,16 @@ static bool marshal_Rsread(struct _marshal_ctx *ctx, struct lib9p_msg_Rsread *va return false; } -static bool marshal_Tswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Tswrite *val) { +static bool marshal_Tswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Tswrite *val, struct _marshal_ret *ret) { uint64_t needed_size = 17 + val->count; for (uint16_t i = 0; i < val->nwname; i++) { needed_size += 2 + val->wname[i].len; } - if (needed_size > (uint64_t)(ctx->ctx->max_msg_size)) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > (uint64_t)(ctx->max_msg_size)) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tswrite", - ctx->ctx->version ? "negotiated" : "client", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "client", + ctx->max_msg_size); return true; } uint32_t offsetof_end = (uint32_t)needed_size; @@ -4558,13 +4724,13 @@ static bool marshal_Tswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Tswrite * return false; } -static bool marshal_Rswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rswrite *val) { +static bool marshal_Rswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rswrite *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; - if (needed_size > ctx->ctx->max_msg_size) { - lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)", + if (needed_size > ctx->max_msg_size) { + lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rswrite", - ctx->ctx->version ? "negotiated" : "server", - ctx->ctx->max_msg_size); + ctx->version ? "negotiated" : "server", + ctx->max_msg_size); return true; } uint32_t offsetof_end = needed_size; @@ -4598,13 +4764,13 @@ const uint32_t _lib9p_table_msg_min_size[LIB9P_VER_NUM] = { #endif /* CONFIG_9P_ENABLE_9P2000_u */ }; -#define _MSG_RECV(typ) [LIB9P_TYP_##typ/2] = { \ - .basesize = sizeof(struct lib9p_msg_##typ), \ - .validate = validate_##typ, \ - .unmarshal = (_unmarshal_fn_t)unmarshal_##typ, \ +#define _MSG_RECV(typ) [LIB9P_TYP_##typ/2] = { \ + .basesize = sizeof(struct lib9p_msg_##typ), \ + .validate = validate_##typ, \ + .unmarshal = (_unmarshal_fn_t)unmarshal_##typ, \ } -#define _MSG_SEND(typ) [LIB9P_TYP_##typ/2] = { \ - .marshal = (_marshal_fn_t)marshal_##typ, \ +#define _MSG_SEND(typ) [LIB9P_TYP_##typ/2] = { \ + .marshal = (_marshal_fn_t)marshal_##typ, \ } const struct _lib9p_recv_tentry _lib9p_table_Tmsg_recv[LIB9P_VER_NUM][0x80] = { @@ -5061,12 +5227,12 @@ const struct _lib9p_send_tentry _lib9p_table_Rmsg_send[LIB9P_VER_NUM][0x80] = { #endif /* CONFIG_9P_ENABLE_9P2000_u */ }; -LM_FLATTEN bool _lib9p_stat_validate(struct _validate_ctx *ctx) { - return validate_stat(ctx); +LM_FLATTEN ssize_t _lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) { + return validate_stat(ctx, net_size, net_bytes, ret_net_size); } -LM_FLATTEN void _lib9p_stat_unmarshal(struct _unmarshal_ctx *ctx, struct lib9p_stat *out) { - unmarshal_stat(ctx, out); +LM_FLATTEN void _lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out) { + unmarshal_stat(ctx, net_bytes, out); } -LM_FLATTEN bool _lib9p_stat_marshal(struct _marshal_ctx *ctx, struct lib9p_stat *val) { - return marshal_stat(ctx, val); +LM_FLATTEN bool _lib9p_stat_marshal(struct lib9p_ctx *ctx, struct lib9p_stat *val, struct _marshal_ret *ret) { + return marshal_stat(ctx, val, ret); } diff --git a/lib9p/CMakeLists.txt b/lib9p/CMakeLists.txt index b356288..707308e 100644 --- a/lib9p/CMakeLists.txt +++ b/lib9p/CMakeLists.txt @@ -13,7 +13,7 @@ target_sources(lib9p INTERFACE target_link_libraries(lib9p INTERFACE libcr_ipc libmisc - libhw + libhw_generic ) if (ENABLE_TESTS) @@ -22,4 +22,6 @@ if (ENABLE_TESTS) NAME "lib9p/runtest" COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/tests/runtest" ) + add_lib_test(lib9p test_compile) + target_include_directories(test_compile PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_compile_config) endif() diff --git a/lib9p/idl.gen b/lib9p/idl.gen deleted file mode 100755 index db5f37d..0000000 --- a/lib9p/idl.gen +++ /dev/null @@ -1,1381 +0,0 @@ -#!/usr/bin/env python -# lib9p/idl.gen - Generate C marshalers/unmarshalers for .9p files -# defining 9P protocol variants. -# -# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> -# SPDX-License-Identifier: AGPL-3.0-or-later - -import enum -import graphlib -import os.path -import sys -import typing - -sys.path.insert(0, os.path.normpath(os.path.join(__file__, ".."))) - -import idl - -# This strives to be "general-purpose" in that it just acts on the -# *.9p inputs; but (unfortunately?) there are a few special-cases in -# this script, marked with "SPECIAL". - - -# Utilities #################################################################### - -idprefix = "lib9p_" - -u32max = (1 << 32) - 1 -u64max = (1 << 64) - 1 - - -def tab_ljust(s: str, width: int) -> str: - cur = len(s.expandtabs(tabsize=8)) - if cur >= width: - return s - return s + " " * (width - cur) - - -def add_prefix(p: str, s: str) -> str: - if s.startswith("_"): - return "_" + p + s[1:] - return p + s - - -def c_macro(full: str) -> str: - full = full.rstrip() - assert "\n" in full - lines = [l.rstrip() for l in full.split("\n")] - width = max(len(l.expandtabs(tabsize=8)) for l in lines[:-1]) - lines = [tab_ljust(l, width) for l in lines] - return " \\\n".join(lines).rstrip() + "\n" - - -def c_ver_enum(ver: str) -> str: - return f"{idprefix.upper()}VER_{ver.replace('.', '_')}" - - -def c_ver_ifdef(versions: typing.Collection[str]) -> str: - return " || ".join( - f"CONFIG_9P_ENABLE_{v.replace('.', '_')}" for v in sorted(versions) - ) - - -def c_ver_cond(versions: typing.Collection[str]) -> str: - if len(versions) == 1: - v = next(v for v in versions) - return f"is_ver(ctx, {v.replace('.', '_')})" - return "( " + (" || ".join(c_ver_cond({v}) for v in sorted(versions))) + " )" - - -def c_typename(typ: idl.Type, parent: idl.StructMember | None = None) -> str: - match typ: - case idl.Primitive(): - if typ.value == 1 and parent and parent.cnt: # SPECIAL (string) - return "[[gnu::nonstring]] char" - return f"uint{typ.value*8}_t" - case idl.Number(): - return f"{idprefix}{typ.name}_t" - case idl.Bitfield(): - return f"{idprefix}{typ.name}_t" - case idl.Message(): - return f"struct {idprefix}msg_{typ.name}" - case idl.Struct(): - return f"struct {idprefix}{typ.name}" - case _: - raise ValueError(f"not a type: {typ.__class__.__name__}") - - -def c_expr(expr: idl.Expr, lookup_sym: typing.Callable[[str], str]) -> str: - ret: list[str] = [] - for tok in expr.tokens: - match tok: - case idl.ExprOp(): - ret.append(tok.op) - case idl.ExprLit(): - ret.append(str(tok.val)) - case idl.ExprSym(name="s32_max"): - ret.append("INT32_MAX") - case idl.ExprSym(name="s64_max"): - ret.append("INT64_MAX") - case idl.ExprSym(): - ret.append(lookup_sym(tok.name)) - case _: - assert False - return " ".join(ret) - - -_ifdef_stack: list[str | None] = [] - - -def ifdef_push(n: int, _newval: str) -> str: - # Grow the stack as needed - global _ifdef_stack - while len(_ifdef_stack) < n: - _ifdef_stack.append(None) - - # Set some variables - parentval: str | None = None - for x in _ifdef_stack[:-1]: - if x is not None: - parentval = x - oldval = _ifdef_stack[-1] - newval: str | None = _newval - if newval == parentval: - newval = None - - # Put newval on the stack. - _ifdef_stack[-1] = newval - - # Build output. - ret = "" - if newval != oldval: - if oldval is not None: - ret += f"#endif /* {oldval} */\n" - if newval is not None: - ret += f"#if {newval}\n" - return ret - - -def ifdef_pop(n: int) -> str: - global _ifdef_stack - ret = "" - while len(_ifdef_stack) > n: - if _ifdef_stack[-1] is not None: - ret += f"#endif /* {_ifdef_stack[-1]} */\n" - _ifdef_stack = _ifdef_stack[:-1] - return ret - - -# topo_sorted() ################################################################ - - -def topo_sorted(typs: list[idl.Type]) -> typing.Iterable[idl.Type]: - ts: graphlib.TopologicalSorter[idl.Type] = graphlib.TopologicalSorter() - for typ in typs: - match typ: - case idl.Number(): - ts.add(typ) - case idl.Bitfield(): - ts.add(typ) - case idl.Struct(): # and idl.Message(): - deps = [ - member.typ - for member in typ.members - if not isinstance(member.typ, idl.Primitive) - ] - ts.add(typ, *deps) - return ts.static_order() - - -# walk() ####################################################################### - - -class Path: - root: idl.Type - elems: list[idl.StructMember] - - def __init__( - self, root: idl.Type, elems: list[idl.StructMember] | None = None - ) -> None: - self.root = root - self.elems = elems if elems is not None else [] - - def add(self, elem: idl.StructMember) -> "Path": - return Path(self.root, self.elems + [elem]) - - def parent(self) -> "Path": - return Path(self.root, self.elems[:-1]) - - def c_str(self, base: str, loopdepth: int = 0) -> str: - ret = base - for i, elem in enumerate(self.elems): - if i > 0: - ret += "." - ret += elem.name - if elem.cnt: - ret += f"[{chr(ord('i')+loopdepth)}]" - loopdepth += 1 - return ret - - def __str__(self) -> str: - return self.c_str(self.root.name + "->") - - -class WalkCmd(enum.Enum): - KEEP_GOING = 1 - DONT_RECURSE = 2 - ABORT = 3 - - -type WalkHandler = typing.Callable[ - [Path], tuple[WalkCmd, typing.Callable[[], None] | None] -] - - -def _walk(path: Path, handle: WalkHandler) -> WalkCmd: - typ = path.elems[-1].typ if path.elems else path.root - - ret, atexit = handle(path) - - if isinstance(typ, idl.Struct): - match ret: - case WalkCmd.KEEP_GOING: - for member in typ.members: - if _walk(path.add(member), handle) == WalkCmd.ABORT: - ret = WalkCmd.ABORT - break - case WalkCmd.DONT_RECURSE: - ret = WalkCmd.KEEP_GOING - case WalkCmd.ABORT: - ret = WalkCmd.ABORT - case _: - assert False, f"invalid cmd: {ret}" - - if atexit: - atexit() - return ret - - -def walk(typ: idl.Type, handle: WalkHandler) -> None: - _walk(Path(typ), handle) - - -# get_buffer_size() ############################################################ - - -class BufferSize: - min_size: int # really just here to sanity-check against typ.min_size(version) - exp_size: int # "expected" or max-reasonable size - max_size: int # really just here to sanity-check against typ.max_size(version) - max_copy: int - max_copy_extra: str - max_iov: int - max_iov_extra: str - _starts_with_copy: bool - _ends_with_copy: bool - - def __init__(self) -> None: - self.min_size = 0 - self.exp_size = 0 - self.max_size = 0 - self.max_copy = 0 - self.max_copy_extra = "" - self.max_iov = 0 - self.max_iov_extra = "" - self._starts_with_copy = False - self._ends_with_copy = False - - -def get_buffer_size(typ: idl.Type, version: str) -> BufferSize: - assert isinstance(typ, idl.Primitive) or (version in typ.in_versions) - - ret = BufferSize() - - if not isinstance(typ, idl.Struct): - assert typ.static_size - ret.min_size = typ.static_size - ret.exp_size = typ.static_size - ret.max_size = typ.static_size - ret.max_copy = typ.static_size - ret.max_iov = 1 - ret._starts_with_copy = True - ret._ends_with_copy = True - return ret - - def handle(path: Path) -> tuple[WalkCmd, None]: - nonlocal ret - if path.elems: - child = path.elems[-1] - if version not in child.in_versions: - return WalkCmd.DONT_RECURSE, None - if child.cnt: - if child.typ.static_size == 1: # SPECIAL (zerocopy) - ret.max_iov += 1 - # HEURISTIC: 27 for strings (max-strlen from 9P1), 8KiB for other data - ret.exp_size += 27 if child.name == "utf8" else 8192 - ret.max_size += child.max_cnt - ret._ends_with_copy = False - return WalkCmd.DONT_RECURSE, None - sub = get_buffer_size(child.typ, version) - ret.exp_size += sub.exp_size * 16 # HEURISTIC: MAXWELEM - ret.max_size += sub.max_size * child.max_cnt - if child.name == "wname" and path.root.name in ( - "Tsread", - "Tswrite", - ): # SPECIAL (9P2000.e) - assert ret._ends_with_copy - assert sub._starts_with_copy - assert not sub._ends_with_copy - ret.max_copy_extra = ( - f" + (CONFIG_9P_MAX_9P2000_e_WELEM * {sub.max_copy})" - ) - ret.max_iov_extra = ( - f" + (CONFIG_9P_MAX_9P2000_e_WELEM * {sub.max_iov})" - ) - ret.max_iov -= 1 - else: - ret.max_copy += sub.max_copy * child.max_cnt - if sub.max_iov == 1 and sub._starts_with_copy: # is purely copy - ret.max_iov += 1 - else: # contains zero-copy segments - ret.max_iov += sub.max_iov * child.max_cnt - if ret._ends_with_copy and sub._starts_with_copy: - # we can merge this one - ret.max_iov -= 1 - if ( - sub._ends_with_copy - and sub._starts_with_copy - and sub.max_iov > 1 - ): - # we can merge these - ret.max_iov -= child.max_cnt - 1 - ret._ends_with_copy = sub._ends_with_copy - return WalkCmd.DONT_RECURSE, None - elif not isinstance(child.typ, idl.Struct): - assert child.typ.static_size - if not ret._ends_with_copy: - if ret.max_size == 0: - ret._starts_with_copy = True - ret.max_iov += 1 - ret._ends_with_copy = True - ret.min_size += child.typ.static_size - ret.exp_size += child.typ.static_size - ret.max_size += child.typ.static_size - ret.max_copy += child.typ.static_size - return WalkCmd.KEEP_GOING, None - - walk(typ, handle) - assert ret.min_size == typ.min_size(version) - assert ret.max_size == typ.max_size(version) - return ret - - -# Generate .h ################################################################## - - -def gen_h(versions: set[str], typs: list[idl.Type]) -> str: - global _ifdef_stack - _ifdef_stack = [] - - ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */ - -#ifndef _LIB9P_9P_H_ -\t#error Do not include <lib9p/9p.generated.h> directly; include <lib9p/9p.h> instead -#endif - -#include <stdint.h> /* for uint{{n}}_t types */ - -#include <libhw/generic/net.h> /* for struct iovec */ -""" - - id2typ: dict[int, idl.Message] = {} - for msg in [msg for msg in typs if isinstance(msg, idl.Message)]: - id2typ[msg.msgid] = msg - - ret += f""" -/* config *********************************************************************/ - -#include "config.h" -""" - for ver in sorted(versions): - ret += "\n" - ret += f"#ifndef {c_ver_ifdef({ver})}\n" - ret += f"\t#error config.h must define {c_ver_ifdef({ver})}\n" - if ver == "9P2000.e": # SPECIAL (9P2000.e) - ret += "#else\n" - ret += f"\t#if {c_ver_ifdef({ver})}\n" - ret += "\t\t#ifndef(CONFIG_9P_MAX_9P2000_e_WELEM)\n" - ret += f"\t\t\t#error if {c_ver_ifdef({ver})} then config.h must define CONFIG_9P_MAX_9P2000_e_WELEM\n" - ret += "\t\t#endif\n" - ret += "\t\tstatic_assert(CONFIG_9P_MAX_9P2000_e_WELEM > 0);\n" - ret += "\t#endif\n" - ret += "#endif\n" - - ret += f""" -/* enum version ***************************************************************/ - -enum {idprefix}version {{ -""" - fullversions = ["unknown = 0", *sorted(versions)] - verwidth = max(len(v) for v in fullversions) - for ver in fullversions: - if ver in versions: - ret += ifdef_push(1, c_ver_ifdef({ver})) - ret += f"\t{c_ver_enum(ver)}," - ret += (" " * (verwidth - len(ver))) + ' /* "' + ver.split()[0] + '" */\n' - ret += ifdef_pop(0) - ret += f"\t{c_ver_enum('NUM')},\n" - ret += "};\n" - - ret += """ -/* enum msg_type **************************************************************/ - -""" - ret += f"enum {idprefix}msg_type {{ /* uint8_t */\n" - namewidth = max(len(msg.name) for msg in typs if isinstance(msg, idl.Message)) - for n in range(0x100): - if n not in id2typ: - continue - msg = id2typ[n] - ret += ifdef_push(1, c_ver_ifdef(msg.in_versions)) - ret += f"\t{idprefix.upper()}TYP_{msg.name.ljust(namewidth)} = {msg.msgid},\n" - ret += ifdef_pop(0) - ret += "};\n" - - ret += """ -/* payload types **************************************************************/ -""" - - def per_version_comment( - typ: idl.Type, fn: typing.Callable[[idl.Type, str], str] - ) -> str: - lines: dict[str, str] = {} - for version in sorted(typ.in_versions): - lines[version] = fn(typ, version) - if len(set(lines.values())) == 1: - for _, line in lines.items(): - return f"/* {line} */\n" - assert False - else: - ret = "" - v_width = max(len(c_ver_enum(v)) for v in typ.in_versions) - for version, line in lines.items(): - ret += f"/* {c_ver_enum(version).ljust(v_width)}: {line} */\n" - return ret - - for typ in topo_sorted(typs): - ret += "\n" - ret += ifdef_push(1, c_ver_ifdef(typ.in_versions)) - - def sum_size(typ: idl.Type, version: str) -> str: - sz = get_buffer_size(typ, version) - assert ( - sz.min_size <= sz.exp_size - and sz.exp_size <= sz.max_size - and sz.max_size < u64max - ) - ret = "" - if sz.min_size == sz.max_size: - ret += f"size = {sz.min_size:,}" - else: - ret += f"min_size = {sz.min_size:,} ; exp_size = {sz.exp_size:,} ; max_size = {sz.max_size:,}" - if sz.max_size > u32max: - ret += " (warning: >UINT32_MAX)" - ret += f" ; max_iov = {sz.max_iov:,}{sz.max_iov_extra} ; max_copy = {sz.max_copy:,}{sz.max_copy_extra}" - return ret - - ret += per_version_comment(typ, sum_size) - - match typ: - case idl.Number(): - ret += f"typedef {c_typename(typ.prim)} {c_typename(typ)};\n" - prefix = f"{idprefix.upper()}{typ.name.upper()}_" - namewidth = max(len(name) for name in typ.vals) - for name, val in typ.vals.items(): - ret += f"#define {prefix}{name.ljust(namewidth)} (({c_typename(typ)})UINT{typ.static_size*8}_C({val}))\n" - case idl.Bitfield(): - ret += f"typedef {c_typename(typ.prim)} {c_typename(typ)};\n" - names = [ - typ.bits[n] or f" {n}" for n in reversed(range(0, len(typ.bits))) - ] - if aliases := [k for k in typ.names if k not in typ.bits]: - names.append("") - names.extend(aliases) - prefix = f"{idprefix.upper()}{typ.name.upper()}_" - namewidth = max(len(add_prefix(prefix, name)) for name in names) - - ret += "\n" - for name in names: - if name == "": - ret += "\n" - continue - - if name.startswith(" "): - vers = typ.in_versions - c_name = "" - c_val = f"1<<{name[1:]}" - else: - vers = typ.names[name].in_versions - c_name = add_prefix(prefix, name) - c_val = f"{typ.names[name].val}" - - ret += ifdef_push(2, c_ver_ifdef(vers)) - - # It is important all of the `beg` strings have - # the same length. - end = "" - if name.startswith(" "): - beg = "/* unused" - end = " */" - elif _ifdef_stack[-1]: - beg = "# define" - else: - beg = "#define " - - ret += f"{beg} {c_name.ljust(namewidth)} (({c_typename(typ)})({c_val})){end}\n" - ret += ifdef_pop(1) - case idl.Struct(): # and idl.Message(): - ret += c_typename(typ) + " {" - if not typ.members: - ret += "};\n" - continue - ret += "\n" - - typewidth = max(len(c_typename(m.typ, m)) for m in typ.members) - - for member in typ.members: - if member.val: - continue - ret += ifdef_push(2, c_ver_ifdef(member.in_versions)) - ret += f"\t{c_typename(member.typ, member).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};\n" - ret += ifdef_pop(1) - ret += "};\n" - ret += ifdef_pop(0) - - ret += """ -/* containers *****************************************************************/ -""" - ret += "\n" - ret += f"#define _{idprefix.upper()}MAX(a, b) ((a) > (b)) ? (a) : (b)\n" - - tmsg_max_iov: dict[str, int] = {} - tmsg_max_copy: dict[str, int] = {} - rmsg_max_iov: dict[str, int] = {} - rmsg_max_copy: dict[str, int] = {} - for typ in typs: - if not isinstance(typ, idl.Message): - continue - if typ.name in ("Tsread", "Tswrite"): # SPECIAL (9P2000.e) - continue - max_iov = tmsg_max_iov if typ.msgid % 2 == 0 else rmsg_max_iov - max_copy = tmsg_max_copy if typ.msgid % 2 == 0 else rmsg_max_copy - for version in typ.in_versions: - if version not in max_iov: - max_iov[version] = 0 - max_copy[version] = 0 - sz = get_buffer_size(typ, version) - if sz.max_iov > max_iov[version]: - max_iov[version] = sz.max_iov - if sz.max_copy > max_copy[version]: - max_copy[version] = sz.max_copy - - for name, table in [ - ("tmsg_max_iov", tmsg_max_iov), - ("tmsg_max_copy", tmsg_max_copy), - ("rmsg_max_iov", rmsg_max_iov), - ("rmsg_max_copy", rmsg_max_copy), - ]: - inv: dict[int, set[str]] = {} - for version, maxval in table.items(): - if maxval not in inv: - inv[maxval] = set() - inv[maxval].add(version) - - ret += "\n" - directive = "if" - seen_e = False # SPECIAL (9P2000.e) - for maxval in sorted(inv, reverse=True): - ret += f"#{directive} {c_ver_ifdef(inv[maxval])}\n" - indent = 1 - if name.startswith("tmsg") and not seen_e: # SPECIAL (9P2000.e) - typ = next(typ for typ in typs if typ.name == "Tswrite") - sz = get_buffer_size(typ, "9P2000.e") - match name: - case "tmsg_max_iov": - maxexpr = f"{sz.max_iov}{sz.max_iov_extra}" - case "tmsg_max_copy": - maxexpr = f"{sz.max_copy}{sz.max_copy_extra}" - case _: - assert False - ret += f"\t#if {c_ver_ifdef({"9P2000.e"})}\n" - ret += f"\t\t#define {idprefix.upper()}{name.upper()} _{idprefix.upper()}MAX({maxval}, {maxexpr})\n" - ret += f"\t#else\n" - indent += 1 - ret += f"{'\t'*indent}#define {idprefix.upper()}{name.upper()} {maxval}\n" - if name.startswith("tmsg") and not seen_e: # SPECIAL (9P2000.e) - ret += "\t#endif\n" - if "9P2000.e" in inv[maxval]: - seen_e = True - directive = "elif" - ret += "#endif\n" - - ret += "\n" - ret += f"struct {idprefix}Tmsg_send_buf {{\n" - ret += f"\tsize_t iov_cnt;\n" - ret += f"\tstruct iovec iov[{idprefix.upper()}TMSG_MAX_IOV];\n" - ret += f"\tuint8_t copied[{idprefix.upper()}TMSG_MAX_COPY];\n" - ret += "};\n" - - ret += "\n" - ret += f"struct {idprefix}Rmsg_send_buf {{\n" - ret += f"\tsize_t iov_cnt;\n" - ret += f"\tstruct iovec iov[{idprefix.upper()}RMSG_MAX_IOV];\n" - ret += f"\tuint8_t copied[{idprefix.upper()}RMSG_MAX_COPY];\n" - ret += "};\n" - - return ret - - -# Generate .c ################################################################## - - -def gen_c(versions: set[str], typs: list[idl.Type]) -> str: - global _ifdef_stack - _ifdef_stack = [] - - ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */ - -#include <stdbool.h> -#include <stddef.h> /* for size_t */ -#include <inttypes.h> /* for PRI* macros */ -#include <string.h> /* for memset() */ - -#include <libmisc/assert.h> - -#include <lib9p/9p.h> - -#include "internal.h" -""" - - # utilities ################################################################ - ret += f""" -/* utilities ******************************************************************/ -""" - - def used(arg: str) -> str: - return arg - - def unused(arg: str) -> str: - return f"LM_UNUSED({arg})" - - id2typ: dict[int, idl.Message] = {} - for msg in [msg for msg in typs if isinstance(msg, idl.Message)]: - id2typ[msg.msgid] = msg - - def msg_table(grp: str, meth: str, tentry: str, rng: tuple[int, int, int]) -> str: - ret = f"const {tentry} _{idprefix}table_{grp}_{meth}[{c_ver_enum('NUM')}][{hex(len(range(*rng)))}] = {{\n" - for ver in ["unknown", *sorted(versions)]: - if ver != "unknown": - ret += ifdef_push(1, c_ver_ifdef({ver})) - ret += f"\t[{c_ver_enum(ver)}] = {{\n" - for n in range(*rng): - xmsg: idl.Message | None = id2typ.get(n, None) - if xmsg: - if ver == "unknown": # SPECIAL (initialization) - if xmsg.name not in ["Tversion", "Rversion", "Rerror"]: - xmsg = None - else: - if ver not in xmsg.in_versions: - xmsg = None - if xmsg: - ret += f"\t\t_MSG_{meth.upper()}({xmsg.name}),\n" - ret += "\t},\n" - ret += ifdef_pop(0) - ret += "};\n" - return ret - - for v in sorted(versions): - ret += f"#if CONFIG_9P_ENABLE_{v.replace('.', '_')}\n" - ret += f"\t#define _is_ver_{v.replace('.', '_')}(v) (v == {c_ver_enum(v)})\n" - ret += "#else\n" - ret += f"\t#define _is_ver_{v.replace('.', '_')}(v) false\n" - ret += "#endif\n" - ret += "\n" - ret += "/**\n" - ret += f" * is_ver(ctx, ver) is essentially `(ctx->ctx->version == {idprefix.upper()}VER_##ver)`,\n" - ret += f" * but compiles correctly (to `false`) even if `{idprefix.upper()}VER_##ver` isn't defined\n" - ret += " * (because `!CONFIG_9P_ENABLE_##ver`). This is useful when `||`ing\n" - ret += " * several version checks together.\n" - ret += " */\n" - ret += "#define is_ver(CTX, ver) _is_ver_##ver(CTX->ctx->version)\n" - - # strings ################################################################## - ret += f""" -/* strings ********************************************************************/ - -const char *const _{idprefix}table_ver_name[{c_ver_enum('NUM')}] = {{ -""" - for ver in ["unknown", *sorted(versions)]: - if ver in versions: - ret += ifdef_push(1, c_ver_ifdef({ver})) - ret += f'\t[{c_ver_enum(ver)}] = "{ver}",\n' - ret += ifdef_pop(0) - ret += "};\n" - - ret += "\n" - ret += f"#define _MSG_NAME(typ) [{idprefix.upper()}TYP_##typ] = #typ\n" - ret += msg_table("msg", "name", "char *const", (0, 0x100, 1)) - - # bitmasks ################################################################# - ret += f""" -/* bitmasks *******************************************************************/ -""" - for typ in typs: - if not isinstance(typ, idl.Bitfield): - continue - ret += "\n" - ret += ifdef_push(1, c_ver_ifdef(typ.in_versions)) - ret += f"static const {c_typename(typ)} {typ.name}_masks[{c_ver_enum('NUM')}] = {{\n" - verwidth = max(len(ver) for ver in versions) - for ver in sorted(versions): - ret += ifdef_push(2, c_ver_ifdef({ver})) - ret += ( - f"\t[{c_ver_enum(ver)}]{' '*(verwidth-len(ver))} = 0b" - + "".join( - "1" if typ.bit_is_valid(bitname, ver) else "0" - for bitname in reversed(typ.bits) - ) - + ",\n" - ) - ret += ifdef_pop(1) - ret += "};\n" - ret += ifdef_pop(0) - - # validate_* ############################################################### - ret += """ -/* validate_* *****************************************************************/ - -LM_ALWAYS_INLINE static bool _validate_size_net(struct _validate_ctx *ctx, uint32_t n) { -\tif (__builtin_add_overflow(ctx->net_offset, n, &ctx->net_offset)) -\t\t/* If needed-net-size overflowed uint32_t, then -\t\t * there's no way that actual-net-size will live up to -\t\t * that. */ -\t\treturn lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); -\tif (ctx->net_offset > ctx->net_size) -\t\treturn lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); -\treturn false; -} - -LM_ALWAYS_INLINE static bool _validate_size_host(struct _validate_ctx *ctx, size_t n) { -\tif (__builtin_add_overflow(ctx->host_extra, n, &ctx->host_extra)) -\t\t/* If needed-host-size overflowed size_t, then there's -\t\t * no way that actual-net-size will live up to -\t\t * that. */ -\t\treturn lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); -\treturn false; -} - -LM_ALWAYS_INLINE static bool _validate_list(struct _validate_ctx *ctx, - size_t cnt, - _validate_fn_t item_fn, size_t item_host_size) { -\tfor (size_t i = 0; i < cnt; i++) -\t\tif (_validate_size_host(ctx, item_host_size) || item_fn(ctx)) -\t\t\treturn true; -\treturn false; -} - -LM_ALWAYS_INLINE static bool validate_1(struct _validate_ctx *ctx) { return _validate_size_net(ctx, 1); } -LM_ALWAYS_INLINE static bool validate_2(struct _validate_ctx *ctx) { return _validate_size_net(ctx, 2); } -LM_ALWAYS_INLINE static bool validate_4(struct _validate_ctx *ctx) { return _validate_size_net(ctx, 4); } -LM_ALWAYS_INLINE static bool validate_8(struct _validate_ctx *ctx) { return _validate_size_net(ctx, 8); } -""" - for typ in topo_sorted(typs): - inline = "LM_FLATTEN" if isinstance(typ, idl.Message) else "LM_ALWAYS_INLINE" - argfn = unused if (isinstance(typ, idl.Struct) and not typ.members) else used - ret += "\n" - ret += ifdef_push(1, c_ver_ifdef(typ.in_versions)) - ret += f"{inline} static bool validate_{typ.name}(struct _validate_ctx *{argfn('ctx')}) {{\n" - - match typ: - case idl.Number(): - ret += f"\treturn validate_{typ.prim.name}(ctx);\n" - case idl.Bitfield(): - ret += f"\t if (validate_{typ.static_size}(ctx))\n" - ret += "\t\treturn true;\n" - ret += ( - f"\t{c_typename(typ)} mask = {typ.name}_masks[ctx->ctx->version];\n" - ) - if typ.static_size == 1: - ret += f"\t{c_typename(typ)} val = ctx->net_bytes[ctx->net_offset-1];\n" - else: - ret += f"\t{c_typename(typ)} val = uint{typ.static_size*8}le_decode(&ctx->net_bytes[ctx->net_offset-{typ.static_size}]);\n" - ret += f"\tif (val & ~mask)\n" - ret += f'\t\treturn lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "unknown bits in {typ.name} bitfield: %#0{typ.static_size}"PRIx{typ.static_size*8}, val & ~mask);\n' - ret += "\treturn false;\n" - case idl.Struct(): # and idl.Message() - if len(typ.members) == 0: - ret += "\treturn false;\n" - ret += "}\n" - continue - - def should_save_value(member: idl.StructMember) -> bool: - nonlocal typ - assert isinstance(typ, idl.Struct) - return bool( - member.max - or member.val - or any(m.cnt == member for m in typ.members) - ) - - # Pass 1 - declare value variables - for member in typ.members: - if should_save_value(member): - ret += ifdef_push(2, c_ver_ifdef(member.in_versions)) - ret += f"\t{c_typename(member.typ)} {member.name};\n" - ret += ifdef_pop(1) - - # Pass 2 - declare offset variables - mark_offset: set[str] = set() - for member in typ.members: - for tok in [*member.max.tokens, *member.val.tokens]: - if isinstance(tok, idl.ExprSym) and tok.name.startswith("&"): - if tok.name[1:] not in mark_offset: - ret += f"\tuint32_t _{tok.name[1:]}_offset;\n" - mark_offset.add(tok.name[1:]) - - # Pass 3 - main pass - ret += "\treturn false\n" - for member in typ.members: - ret += ifdef_push(2, c_ver_ifdef(member.in_versions)) - ret += f"\t || " - if member.in_versions != typ.in_versions: - ret += "( " + c_ver_cond(member.in_versions) + " && " - if member.cnt is not None: - if member.typ.static_size == 1: # SPECIAL (zerocopy) - ret += f"_validate_size_net(ctx, {member.cnt.name})" - else: - ret += f"_validate_list(ctx, {member.cnt.name}, validate_{member.typ.name}, sizeof({c_typename(member.typ)}))" - if typ.name == "s": # SPECIAL (string) - ret += f'\n\t || ({{ (!is_valid_utf8_without_nul(&ctx->net_bytes[ctx->net_offset-len], len)) && lib9p_error(ctx->ctx, LINUX_EBADMSG, "message contains invalid UTF-8"); }})' - else: - if should_save_value(member): - ret += "(" - if member.name in mark_offset: - ret += f"({{ _{member.name}_offset = ctx->net_offset; " - ret += f"validate_{member.typ.name}(ctx)" - if member.name in mark_offset: - ret += "; })" - if should_save_value(member): - nbytes = member.static_size - assert nbytes - if nbytes == 1: - ret += f" || ({{ {member.name} = ctx->net_bytes[ctx->net_offset-1]; false; }}))" - else: - ret += f" || ({{ {member.name} = uint{nbytes*8}le_decode(&ctx->net_bytes[ctx->net_offset-{nbytes}]); false; }}))" - if member.in_versions != typ.in_versions: - ret += " )" - ret += "\n" - - # Pass 4 - validate ,max= and ,val= constraints - for member in typ.members: - - def lookup_sym(sym: str) -> str: - match sym: - case "end": - return "ctx->net_offset" - case _: - assert sym.startswith("&") - return f"_{sym[1:]}_offset" - - if member.max: - assert member.static_size - nbits = member.static_size * 8 - ret += ifdef_push(2, c_ver_ifdef(member.in_versions)) - ret += f"\t || ({{ uint{nbits}_t max = {c_expr(member.max, lookup_sym)}; (((uint{nbits}_t){member.name}) > max) &&\n" - ret += f'\t lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "{member.name} value is too large (%"PRIu{nbits}" > %"PRIu{nbits}")", {member.name}, max); }})\n' - if member.val: - assert member.static_size - nbits = member.static_size * 8 - ret += ifdef_push(2, c_ver_ifdef(member.in_versions)) - ret += f"\t || ({{ uint{nbits}_t exp = {c_expr(member.val, lookup_sym)}; (((uint{nbits}_t){member.name}) != exp) &&\n" - ret += f'\t lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "{member.name} value is wrong (actual:%"PRIu{nbits}" != correct:%"PRIu{nbits}")", (uint{nbits}_t){member.name}, exp); }})\n' - - ret += ifdef_pop(1) - ret += "\t ;\n" - ret += "}\n" - ret += ifdef_pop(0) - - # unmarshal_* ############################################################## - ret += """ -/* unmarshal_* ****************************************************************/ - -LM_ALWAYS_INLINE static void unmarshal_1(struct _unmarshal_ctx *ctx, uint8_t *out) { -\t*out = ctx->net_bytes[ctx->net_offset]; -\tctx->net_offset += 1; -} - -LM_ALWAYS_INLINE static void unmarshal_2(struct _unmarshal_ctx *ctx, uint16_t *out) { -\t*out = uint16le_decode(&ctx->net_bytes[ctx->net_offset]); -\tctx->net_offset += 2; -} - -LM_ALWAYS_INLINE static void unmarshal_4(struct _unmarshal_ctx *ctx, uint32_t *out) { -\t*out = uint32le_decode(&ctx->net_bytes[ctx->net_offset]); -\tctx->net_offset += 4; -} - -LM_ALWAYS_INLINE static void unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out) { -\t*out = uint64le_decode(&ctx->net_bytes[ctx->net_offset]); -\tctx->net_offset += 8; -} -""" - for typ in topo_sorted(typs): - inline = "LM_FLATTEN" if isinstance(typ, idl.Message) else "LM_ALWAYS_INLINE" - argfn = unused if (isinstance(typ, idl.Struct) and not typ.members) else used - ret += "\n" - ret += ifdef_push(1, c_ver_ifdef(typ.in_versions)) - ret += f"{inline} static void unmarshal_{typ.name}(struct _unmarshal_ctx *{argfn('ctx')}, {c_typename(typ)} *out) {{\n" - match typ: - case idl.Number(): - ret += f"\tunmarshal_{typ.prim.name}(ctx, ({c_typename(typ.prim)} *)out);\n" - case idl.Bitfield(): - ret += f"\tunmarshal_{typ.prim.name}(ctx, ({c_typename(typ.prim)} *)out);\n" - case idl.Struct(): - ret += "\tmemset(out, 0, sizeof(*out));\n" - - for member in typ.members: - ret += ifdef_push(2, c_ver_ifdef(member.in_versions)) - if member.val: - ret += f"\tctx->net_offset += {member.static_size};\n" - continue - ret += "\t" - - prefix = "\t" - if member.in_versions != typ.in_versions: - ret += "if ( " + c_ver_cond(member.in_versions) + " ) " - prefix = "\t\t" - if member.cnt: - if member.in_versions != typ.in_versions: - ret += "{\n" - ret += prefix - if member.typ.static_size == 1: # SPECIAL (string, zerocopy) - ret += f"out->{member.name} = (char *)&ctx->net_bytes[ctx->net_offset];\n" - ret += ( - f"{prefix}ctx->net_offset += out->{member.cnt.name};\n" - ) - else: - ret += f"out->{member.name} = ctx->extra;\n" - ret += f"{prefix}ctx->extra += sizeof(out->{member.name}[0]) * out->{member.cnt.name};\n" - ret += f"{prefix}for (typeof(out->{member.cnt.name}) i = 0; i < out->{member.cnt.name}; i++)\n" - ret += f"{prefix}\tunmarshal_{member.typ.name}(ctx, &out->{member.name}[i]);\n" - if member.in_versions != typ.in_versions: - ret += "\t}\n" - else: - ret += ( - f"unmarshal_{member.typ.name}(ctx, &out->{member.name});\n" - ) - ret += ifdef_pop(1) - ret += "}\n" - ret += ifdef_pop(0) - - # marshal_* ################################################################ - ret += """ -/* marshal_* ******************************************************************/ - -""" - ret += c_macro( - "#define MARSHAL_BYTES_ZEROCOPY(ctx, data, len)\n" - "\tif (ctx->net_iov[ctx->net_iov_cnt-1].iov_len)\n" - "\t\tctx->net_iov_cnt++;\n" - "\tctx->net_iov[ctx->net_iov_cnt-1].iov_base = data;\n" - "\tctx->net_iov[ctx->net_iov_cnt-1].iov_len = len;\n" - "\tctx->net_iov_cnt++;\n" - ) - ret += c_macro( - "#define MARSHAL_BYTES(ctx, data, len)\n" - "\tif (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base)\n" - "\t\tctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size];\n" - "\tmemcpy(&ctx->net_copied[ctx->net_copied_size], data, len);\n" - "\tctx->net_copied_size += len;\n" - "\tctx->net_iov[ctx->net_iov_cnt-1].iov_len += len;\n" - ) - ret += c_macro( - "#define MARSHAL_U8LE(ctx, val)\n" - "\tif (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base)\n" - "\t\tctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size];\n" - "\tctx->net_copied[ctx->net_copied_size] = val;\n" - "\tctx->net_copied_size += 1;\n" - "\tctx->net_iov[ctx->net_iov_cnt-1].iov_len += 1;\n" - ) - ret += c_macro( - "#define MARSHAL_U16LE(ctx, val)\n" - "\tif (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base)\n" - "\t\tctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size];\n" - "\tuint16le_encode(&ctx->net_copied[ctx->net_copied_size], val);\n" - "\tctx->net_copied_size += 2;\n" - "\tctx->net_iov[ctx->net_iov_cnt-1].iov_len += 2;\n" - ) - ret += c_macro( - "#define MARSHAL_U32LE(ctx, val)\n" - "\tif (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base)\n" - "\t\tctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size];\n" - "\tuint32le_encode(&ctx->net_copied[ctx->net_copied_size], val);\n" - "\tctx->net_copied_size += 4;\n" - "\tctx->net_iov[ctx->net_iov_cnt-1].iov_len += 4;\n" - ) - ret += c_macro( - "#define MARSHAL_U64LE(ctx, val)\n" - "\tif (!ctx->net_iov[ctx->net_iov_cnt-1].iov_base)\n" - "\t\tctx->net_iov[ctx->net_iov_cnt-1].iov_base = &ctx->net_copied[ctx->net_copied_size];\n" - "\tuint64le_encode(&ctx->net_copied[ctx->net_copied_size], val);\n" - "\tctx->net_copied_size += 8;\n" - "\tctx->net_iov[ctx->net_iov_cnt-1].iov_len += 8;\n" - ) - - class OffsetExpr: - static: int - cond: dict[frozenset[str], "OffsetExpr"] - rep: list[tuple[Path, "OffsetExpr"]] - - def __init__(self) -> None: - self.static = 0 - self.rep = [] - self.cond = {} - - def add(self, other: "OffsetExpr") -> None: - self.static += other.static - self.rep += other.rep - for k, v in other.cond.items(): - if k in self.cond: - self.cond[k].add(v) - else: - self.cond[k] = v - - def gen_c( - self, - dsttyp: str, - dstvar: str, - root: str, - indent_depth: int, - loop_depth: int, - ) -> str: - oneline: list[str] = [] - multiline = "" - if self.static: - oneline.append(str(self.static)) - for cnt, sub in self.rep: - if not sub.cond and not sub.rep: - if sub.static == 1: - oneline.append(cnt.c_str(root)) - else: - oneline.append(f"({cnt.c_str(root)})*{sub.static}") - continue - loopvar = chr(ord("i") + loop_depth) - multiline += f"{'\t'*indent_depth}for ({c_typename(cnt.elems[-1].typ)} {loopvar} = 0; {loopvar} < {cnt.c_str(root)}; {loopvar}++) {{\n" - multiline += sub.gen_c( - "", dstvar, root, indent_depth + 1, loop_depth + 1 - ) - multiline += f"{'\t'*indent_depth}}}\n" - for vers, sub in self.cond.items(): - multiline += ifdef_push(indent_depth + 1, c_ver_ifdef(vers)) - multiline += f"{'\t'*indent_depth}if {c_ver_cond(vers)} {{\n" - multiline += sub.gen_c("", dstvar, root, indent_depth + 1, loop_depth) - multiline += f"{'\t'*indent_depth}}}\n" - multiline += ifdef_pop(indent_depth) - if dsttyp: - if not oneline: - oneline.append("0") - ret = f"{'\t'*indent_depth}{dsttyp} {dstvar} = {' + '.join(oneline)};\n" - elif oneline: - ret = f"{'\t'*indent_depth}{dstvar} += {' + '.join(oneline)};\n" - ret += multiline - return ret - - type OffsetExprRecursion = typing.Callable[[Path], WalkCmd] - - def get_offset_expr(typ: idl.Type, recurse: OffsetExprRecursion) -> OffsetExpr: - if not isinstance(typ, idl.Struct): - assert typ.static_size - ret = OffsetExpr() - ret.static = typ.static_size - return ret - - stack: list[tuple[Path, OffsetExpr, typing.Callable[[], None]]] - - def pop_root() -> None: - assert False - - def pop_cond() -> None: - nonlocal stack - key = frozenset(stack[-1][0].elems[-1].in_versions) - if key in stack[-2][1].cond: - stack[-2][1].cond[key].add(stack[-1][1]) - else: - stack[-2][1].cond[key] = stack[-1][1] - stack = stack[:-1] - - def pop_rep() -> None: - nonlocal stack - member_path = stack[-1][0] - member = member_path.elems[-1] - assert member.cnt - cnt_path = member_path.parent().add(member.cnt) - stack[-2][1].rep.append((cnt_path, stack[-1][1])) - stack = stack[:-1] - - def handle(path: Path) -> tuple[WalkCmd, typing.Callable[[], None] | None]: - nonlocal recurse - - ret = recurse(path) - if ret != WalkCmd.KEEP_GOING: - return ret, None - - nonlocal stack - stack_len = len(stack) - - def pop() -> None: - nonlocal stack - nonlocal stack_len - while len(stack) > stack_len: - stack[-1][2]() - - if path.elems: - child = path.elems[-1] - parent = path.elems[-2].typ if len(path.elems) > 1 else path.root - if child.in_versions < parent.in_versions: - stack.append((path, OffsetExpr(), pop_cond)) - if child.cnt: - stack.append((path, OffsetExpr(), pop_rep)) - if not isinstance(child.typ, idl.Struct): - assert child.typ.static_size - stack[-1][1].static += child.typ.static_size - return ret, pop - - stack = [(Path(typ), OffsetExpr(), pop_root)] - walk(typ, handle) - return stack[0][1] - - def go_to_end(path: Path) -> WalkCmd: - return WalkCmd.KEEP_GOING - - def go_to_tok(name: str) -> typing.Callable[[Path], WalkCmd]: - def ret(path: Path) -> WalkCmd: - if len(path.elems) == 1 and path.elems[0].name == name: - return WalkCmd.ABORT - return WalkCmd.KEEP_GOING - - return ret - - for typ in typs: - if not ( - isinstance(typ, idl.Message) or typ.name == "stat" - ): # SPECIAL (include stat) - continue - assert isinstance(typ, idl.Struct) - ret += "\n" - ret += ifdef_push(1, c_ver_ifdef(typ.in_versions)) - ret += f"static bool marshal_{typ.name}(struct _marshal_ctx *ctx, {c_typename(typ)} *val) {{\n" - - # Pass 1 - check size - max_size = max(typ.max_size(v) for v in typ.in_versions) - - if max_size > u32max: # SPECIAL (9P2000.e) - ret += get_offset_expr(typ, go_to_end).gen_c( - "uint64_t", "needed_size", "val->", 1, 0 - ) - ret += "\tif (needed_size > (uint64_t)(ctx->ctx->max_msg_size)) {\n" - else: - ret += get_offset_expr(typ, go_to_end).gen_c( - "uint32_t", "needed_size", "val->", 1, 0 - ) - ret += "\tif (needed_size > ctx->ctx->max_msg_size) {\n" - if isinstance(typ, idl.Message): # SPECIAL (disable for stat) - ret += f'\t\tlib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%PRIu32)",\n' - ret += f'\t\t\t"{typ.name}",\n' - ret += f'\t\t\tctx->ctx->version ? "negotiated" : "{'client' if typ.msgid % 2 == 0 else 'server'}",\n' - ret += "\t\t\tctx->ctx->max_msg_size);\n" - ret += "\t\treturn true;\n" - ret += "\t}\n" - - # Pass 2 - write data - ifdef_depth = 1 - stack: list[tuple[Path, bool]] = [(Path(typ), False)] - - def handle(path: Path) -> tuple[WalkCmd, typing.Callable[[], None]]: - nonlocal ret - nonlocal ifdef_depth - nonlocal stack - stack_len = len(stack) - - def pop() -> None: - nonlocal ret - nonlocal ifdef_depth - nonlocal stack - nonlocal stack_len - while len(stack) > stack_len: - ret += f"{'\t'*(len(stack)-1)}}}\n" - if stack[-1][1]: - ifdef_depth -= 1 - ret += ifdef_pop(ifdef_depth) - stack = stack[:-1] - - loopdepth = sum(1 for elem in path.elems if elem.cnt) - struct = path.elems[-1].typ if path.elems else path.root - if isinstance(struct, idl.Struct): - offsets: list[str] = [] - for member in struct.members: - if not member.val: - continue - for tok in member.val.tokens: - if not isinstance(tok, idl.ExprSym): - continue - if tok.name == "end" or tok.name.startswith("&"): - if tok.name not in offsets: - offsets.append(tok.name) - for name in offsets: - name_prefix = "offsetof_" + "".join( - m.name + "_" for m in path.elems - ) - if name == "end": - if not path.elems: - nonlocal max_size - if max_size > u32max: - ret += f"{'\t'*len(stack)}uint32_t {name_prefix}end = (uint32_t)needed_size;\n" - else: - ret += f"{'\t'*len(stack)}uint32_t {name_prefix}end = needed_size;\n" - continue - recurse: OffsetExprRecursion = go_to_end - else: - assert name.startswith("&") - name = name[1:] - recurse = go_to_tok(name) - expr = get_offset_expr(struct, recurse) - expr_prefix = path.c_str("val->", loopdepth) - if not expr_prefix.endswith(">"): - expr_prefix += "." - ret += expr.gen_c( - "uint32_t", - name_prefix + name, - expr_prefix, - len(stack), - loopdepth, - ) - if path.elems: - child = path.elems[-1] - parent = path.elems[-2].typ if len(path.elems) > 1 else path.root - if child.in_versions < parent.in_versions: - ret += ifdef_push(ifdef_depth + 1, c_ver_ifdef(child.in_versions)) - ifdef_depth += 1 - ret += f"{'\t'*len(stack)}if ({c_ver_cond(child.in_versions)}) {{\n" - stack.append((path, True)) - if child.cnt: - cnt_path = path.parent().add(child.cnt) - if child.typ.static_size == 1: # SPECIAL (zerocopy) - if path.root.name == "stat": # SPECIAL (stat) - ret += f"{'\t'*len(stack)}MARSHAL_BYTES(ctx, {path.c_str('val->')[:-3]}, {cnt_path.c_str('val->')});\n" - else: - ret += f"{'\t'*len(stack)}MARSHAL_BYTES_ZEROCOPY(ctx, {path.c_str('val->')[:-3]}, {cnt_path.c_str('val->')});\n" - return WalkCmd.KEEP_GOING, pop - loopvar = chr(ord("i") + loopdepth - 1) - ret += f"{'\t'*len(stack)}for ({c_typename(child.cnt.typ)} {loopvar} = 0; {loopvar} < {cnt_path.c_str('val->')}; {loopvar}++) {{\n" - stack.append((path, False)) - if not isinstance(child.typ, idl.Struct): - if child.val: - - def lookup_sym(sym: str) -> str: - nonlocal path - if sym.startswith("&"): - sym = sym[1:] - return ( - "offsetof_" - + "".join(m.name + "_" for m in path.elems[:-1]) - + sym - ) - - val = c_expr(child.val, lookup_sym) - else: - val = path.c_str("val->") - if isinstance(child.typ, idl.Bitfield): - val += f" & {child.typ.name}_masks[ctx->ctx->version]" - ret += f"{'\t'*len(stack)}MARSHAL_U{child.typ.static_size*8}LE(ctx, {val});\n" - return WalkCmd.KEEP_GOING, pop - - walk(typ, handle) - - ret += "\treturn false;\n" - ret += "}\n" - ret += ifdef_pop(0) - - # function tables ########################################################## - ret += """ -/* function tables ************************************************************/ -""" - - ret += "\n" - ret += f"const uint32_t _{idprefix}table_msg_min_size[{c_ver_enum('NUM')}] = {{\n" - rerror = next(typ for typ in typs if typ.name == "Rerror") - ret += f"\t[{c_ver_enum('unknown')}] = {rerror.min_size('9P2000')},\n" # SPECIAL (initialization) - for ver in sorted(versions): - ret += ifdef_push(1, c_ver_ifdef({ver})) - ret += f"\t[{c_ver_enum(ver)}] = {rerror.min_size(ver)},\n" - ret += ifdef_pop(0) - ret += "};\n" - - ret += "\n" - ret += c_macro( - f"#define _MSG_RECV(typ) [{idprefix.upper()}TYP_##typ/2] = {{\n" - f"\t\t.basesize = sizeof(struct {idprefix}msg_##typ),\n" - f"\t\t.validate = validate_##typ,\n" - f"\t\t.unmarshal = (_unmarshal_fn_t)unmarshal_##typ,\n" - f"\t}}\n" - ) - ret += c_macro( - f"#define _MSG_SEND(typ) [{idprefix.upper()}TYP_##typ/2] = {{\n" - f"\t\t.marshal = (_marshal_fn_t)marshal_##typ,\n" - f"\t}}\n" - ) - ret += "\n" - ret += msg_table("Tmsg", "recv", f"struct _{idprefix}recv_tentry", (0, 0x100, 2)) - ret += "\n" - ret += msg_table("Rmsg", "recv", f"struct _{idprefix}recv_tentry", (1, 0x100, 2)) - ret += "\n" - ret += msg_table("Tmsg", "send", f"struct _{idprefix}send_tentry", (0, 0x100, 2)) - ret += "\n" - ret += msg_table("Rmsg", "send", f"struct _{idprefix}send_tentry", (1, 0x100, 2)) - - ret += f""" -LM_FLATTEN bool _{idprefix}stat_validate(struct _validate_ctx *ctx) {{ -\treturn validate_stat(ctx); -}} -LM_FLATTEN void _{idprefix}stat_unmarshal(struct _unmarshal_ctx *ctx, struct {idprefix}stat *out) {{ -\tunmarshal_stat(ctx, out); -}} -LM_FLATTEN bool _{idprefix}stat_marshal(struct _marshal_ctx *ctx, struct {idprefix}stat *val) {{ -\treturn marshal_stat(ctx, val); -}} -""" - - ############################################################################ - return ret - - -# Main ######################################################################### - - -if __name__ == "__main__": - import sys - - if typing.TYPE_CHECKING: - - class ANSIColors: - MAGENTA = "\x1b[35m" - RED = "\x1b[31m" - RESET = "\x1b[0m" - - else: - from _colorize import ANSIColors # Present in Python 3.13+ - - if len(sys.argv) < 2: - raise ValueError("requires at least 1 .9p filename") - parser = idl.Parser() - for txtname in sys.argv[1:]: - try: - parser.parse_file(txtname) - except SyntaxError as e: - print( - f"{ANSIColors.RED}{e.filename}{ANSIColors.RESET}:{ANSIColors.MAGENTA}{e.lineno}{ANSIColors.RESET}: {e.msg}", - file=sys.stderr, - ) - assert e.text - print(f"\t{e.text}", file=sys.stderr) - print( - f"\t{ANSIColors.RED}{'~'*len(e.text)}{ANSIColors.RESET}", - file=sys.stderr, - ) - sys.exit(2) - versions, typs = parser.all() - outdir = os.path.normpath(os.path.join(sys.argv[0], "..")) - with open(os.path.join(outdir, "include/lib9p/9p.generated.h"), "w") as fh: - fh.write(gen_h(versions, typs)) - with open(os.path.join(outdir, "9p.generated.c"), "w") as fh: - fh.write(gen_c(versions, typs)) diff --git a/lib9p/idl/0000-README.md b/lib9p/idl/0000-README.md index 036de22..e19a1e8 100644 --- a/lib9p/idl/0000-README.md +++ b/lib9p/idl/0000-README.md @@ -41,6 +41,11 @@ and messages (which are a special-case of structures). msg Tname = "size[4,val=end-&size] typ[1,val=TYP] tag[tag] REST..." +Bitfield bit names may be wrapped in `reserved(...)` or +`subfield(...)`; reserved indicates that the bit is named but is not +allowed to be used, and subfield indicates that the bit is part of a +num/enum that is handled by an alias. + Struct fields that have numeric types (either primitives or `num` types) can add to their type `,val=` and/or `,max=` to specify what the exact value must be and/or what the maximum (inclusive) value is. diff --git a/lib9p/idl/0000-TODO.md b/lib9p/idl/0000-TODO.md index d196ac9..81cafe5 100644 --- a/lib9p/idl/0000-TODO.md +++ b/lib9p/idl/0000-TODO.md @@ -1,6 +1,6 @@ <!-- lib9p/idl/0000-TODO.md - Changes I intend to make to idl/__init__.py - and idl.gen + and proto.gen Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib9p/idl/2002-9P2000.9p b/lib9p/idl/2002-9P2000.9p index 438e02f..2a4f7ed 100644 --- a/lib9p/idl/2002-9P2000.9p +++ b/lib9p/idl/2002-9P2000.9p @@ -42,7 +42,7 @@ bitfield dm = 4 # that the file is mounted by the kernel as a 9P transport; # that the kernel has a lock on doing I/O on it, so userspace # can't do I/O on it. - "28=_PLAN9_MOUNT" + "28=reserved(PLAN9_MOUNT)" "27=AUTH" "26=TMP" #... @@ -63,7 +63,7 @@ bitfield qt = 1 "7=DIR" "6=APPEND" "5=EXCL" - "4=_PLAN9_MOUNT" # See "_PLAN9_MOUNT" in "dm" above. + "4=reserved(PLAN9_MOUNT)" # See "PLAN9_MOUNT" in "dm" above. "3=AUTH" # Fun historical fact: QTTMP was a relatively late addition to # Plan 9, in 2003-12. @@ -107,12 +107,12 @@ struct stat = "stat_size[2,val=end-&kern_type]" # "O"pen flags (flags to pass to Topen and Tcreate) # Unused bits *must* be 0. bitfield o = 1 - "0=mode_0" # low bit of the 2-bit READ/WRITE/RDWR/EXEC enum - "1=mode_1" # high bit of the 2-bit READ/WRITE/RDWR/EXEC enum + "0=subfield(mode)" # low bit of the 2-bit READ/WRITE/RDWR/EXEC enum + "1=subfield(mode)" # high bit of the 2-bit READ/WRITE/RDWR/EXEC enum #"2=unused" #"3=unused" "4=TRUNC" - #"5=_reserved_CEXEC" # close-on-exec + "5=reserved(CEXEC)" # close-on-exec "6=RCLOSE" # remove-on-close #"7=unused" diff --git a/lib9p/idl/2005-9P2000.u.9p b/lib9p/idl/2005-9P2000.u.9p index d96bbce..fefe3e9 100644 --- a/lib9p/idl/2005-9P2000.u.9p +++ b/lib9p/idl/2005-9P2000.u.9p @@ -14,6 +14,9 @@ from ./2002-9P2000.9p import * num nuid = 4 "NONUID = ~0" +num errno = 4 + "NOERROR = 0" + struct stat += "file_extension[s]" "file_owner_n_uid[nuid]" "file_owner_n_gid[nuid]" @@ -22,7 +25,7 @@ struct stat += "file_extension[s]" msg Tauth += "n_uid[nuid]" msg Tattach += "n_uid[nuid]" -msg Rerror += "errno[4]" +msg Rerror += "errno[errno]" bitfield dm += "23=DEVICE" "21=NAMEDPIPE" diff --git a/lib9p/idl/2010-9P2000.L.9p b/lib9p/idl/2010-9P2000.L.9p index e21d411..7ac86a6 100644 --- a/lib9p/idl/2010-9P2000.L.9p +++ b/lib9p/idl/2010-9P2000.L.9p @@ -5,82 +5,206 @@ # "9P2000.L" Linux extension # https://github.com/chaos/diod/blob/master/protocol.md +# https://github.com/chaos/diod/blob/master/src/libnpfs/protocol.h version "9P2000.L" from ./2002-9P2000.9p import tag, fid, s, qt, qid from ./2002-9P2000.9p import Rerror from ./2002-9P2000.9p import Tversion, Rversion, Tflush, Rflush, Twalk, Rwalk, Tread, Rread, Twrite, Rwrite, Tclunk, Rclunk, Tremove, Rremove -from ./2005-9P2000.u.9p import nuid, Tauth, Rauth, Tattach, Rattach +from ./2005-9P2000.u.9p import nuid, errno, Tauth, Rauth, Tattach, Rattach + +#num errno += # TODO + +num super_magic = 4 + # See <linux/magic.h> (linux.git include/uapi/linux/magic.h). + # + # To quote `util-linux.git:include/statfs_magic.h`: + # "Unfortunately, Linux kernel header file <linux/magic.h> is + # incomplete mess and kernel returns by statfs f_type many numbers + # that are nowhere specified (in API)." + # + # util-linux <statfs_magic.h> is also incomplete. As is the + # statfs(2) man-page. + # + # I'm working on a patchset to the kernel to get <linux/magic.h> + # to be complete, but in the mean-time I'm just not going to + # bother with putting a list here. + # + # TODO + "V9FS_MAGIC=0x01021997" + +# "L"inux "O"pen flags (flags to pass to Tlopen and Tlcreate) +# +# The values are not specified in in protocol.md, but are specified in +# protocol.h (and are different than the Linux kernel's values, which +# vary by architecture). +bitfield lo = 4 + "0=subfield(mode)" # low bit of the 2-bit RDONLY/WRONLY/RDWR/NOACCESS enum + "1=subfield(mode)" # high bit of the 2-bit RDONLY/WRONLY/RDWR/NOACCESS enum + #"2=unused" + #"3=unused" + #"4=unused" + #"5=unused" + "6=CREATE" + "7=EXCL" + "8=NOCTTY" + "9=TRUNC" + "10=APPEND" + "11=NONBLOCK" + "12=DSYNC" + "13=BSD_FASYNC" + "14=DIRECT" + "15=LARGEFILE" + "16=DIRECTORY" + "17=NOFOLLOW" + "18=NOATIME" + "19=CLOEXEC" + "20=SYNC" + + "RDONLY = 0" + "WRONLY = 1" + "RDWR = 2" + "NOACCESS = 3" + + "MODE_MASK = 0b000000000000000000011" + "FLAG_MASK = 0b111111111111111000000" + +# "D"irentry "T"ype +# +# These match the Linux kernel's values. +num dt = 1 + "UNKNOWN = 0" + "NAMED_PIPE = 1" + "CHAR_DEV = 2" + "DIRECTORY = 4" + "BLOCK_DEV = 6" + "REGULAR = 8" + "SYMLINK = 10" + "SOCKET = 12" + "WHITEOUT = 14" + +# Mode +# +# These match the Linux kernel's values. Why is this 32-bits wide +# instead of just 16? Who knows? +bitfield mode = 4 + #... + "15=subfield(fmt)" # bit of the 4-bit FMT_ enum + "14=subfield(fmt)" # bit of the 4-bit FMT_ enum + "13=subfield(fmt)" # bit of the 4-bit FMT_ enum + "12=subfield(fmt)" # bit of the 4-bit FMT_ enum + #... + "11=PERM_SETGROUP" + "10=PERM_SETUSER" + "9=PERM_STICKY" + "8=PERM_OWNER_R" + "7=PERM_OWNER_W" + "6=PERM_OWNER_X" + "5=PERM_GROUP_R" + "4=PERM_GROUP_W" + "3=PERM_GROUP_X" + "2=PERM_OTHER_R" + "1=PERM_OTHER_W" + "0=PERM_OTHER_X" + + "FMT_NAMED_PIPE = LIB9P_DT_NAMED_PIPE<<12" + "FMT_CHAR_DEV = LIB9P_DT_CHAR_DEV<<12" + "FMT_DIRECTORY = LIB9P_DT_DIRECTORY<<12" + "FMT_BLOCK_DEV = LIB9P_DT_BLOCK_DEV<<12" + "FMT_REGULAR = LIB9P_DT_REGULAR<<12" + "FMT_SYMLINK = LIB9P_DT_SYMLINK<<12" + "FMT_SOCKET = LIB9P_DT_SOCKET<<12" + + "PERM_MASK = 0000777" # PERM_* + "FMT_MASK = 0170000" # _fmt_* + +# A boolean value that is for some reason 4 bytes wide. +num b4 = 4 + "FALSE=0" + "TRUE=1" + # all other values are true also bitfield getattr = 8 - "0=MODE" - "1=NLINK" - "2=UID" - "3=GID" - "4=RDEV" - "5=ATIME" - "6=MTIME" - "7=CTIME" - "8=INO" - "9=SIZE" - "10=BLOCKS" - - "11=BTIME" - "12=GEN" - "13=DATA_VERSION" - - "BASIC=0x000007ff" # Mask for fields up to BLOCKS - "ALL =0x00003fff" # Mask for All fields above + "0=MODE" + "1=NLINK" + "2=UID" + "3=GID" + "4=RDEV" + "5=ATIME" + "6=MTIME" + "7=CTIME" + "8=INO" + "9=SIZE" + "10=BLOCKS" + + "11=BTIME" + "12=GEN" + "13=DATA_VERSION" + + "BASIC=0x000007ff" # Mask for fields up to BLOCKS + "ALL =0x00003fff" # Mask for All fields above bitfield setattr = 4 - "0=MODE" - "1=UID" - "2=GID" - "3=SIZE" - "4=ATIME" - "5=MTIME" - "6=CTIME" - "7=ATIME_SET" - "8=MTIME_SET" + "0=MODE" + "1=UID" + "2=GID" + "3=SIZE" + "4=ATIME" + "5=MTIME" + "6=CTIME" + "7=ATIME_SET" + "8=MTIME_SET" num lock_type = 1 - "RDLCK=0" - "WRLCK=1" - "UNLCK=2" + "RDLCK=0" + "WRLCK=1" + "UNLCK=2" bitfield lock_flags = 4 - "0=BLOCK" - "1=RECLAIM" + "0=BLOCK" + "1=RECLAIM" num lock_status = 1 - "SUCCESS=0" - "BLOCKED=1" - "ERROR=2" - "GRACE=3" + "SUCCESS=0" + "BLOCKED=1" + "ERROR=2" + "GRACE=3" #msg Tlerror = "size[4,val=end-&size] typ[1,val=6] tag[tag] illegal" # analogous to 106/Terror -msg Rlerror = "size[4,val=end-&size] typ[1,val=7] tag[tag] ecode[4]" # analogous to 107/Rerror +msg Rlerror = "size[4,val=end-&size] typ[1,val=7] tag[tag] ecode[errno]" # analogous to 107/Rerror msg Tstatfs = "size[4,val=end-&size] typ[1,val=8] tag[tag] fid[fid]" -msg Rstatfs = "size[4,val=end-&size] typ[1,val=9] tag[tag] type[4] bsize[4] blocks[8] bfree[8] bavail[8] files[8] ffree[8] fsid[8] namelen[4]" -msg Tlopen = "size[4,val=end-&size] typ[1,val=12] tag[tag] fid[fid] flags[4]" # analogous to 112/Topen +msg Rstatfs = "size[4,val=end-&size] typ[1,val=9] tag[tag]" # Description | statfs | statvfs + "type[super_magic]" # Type of filesystem | f_type | - + "bsize[4]" # Block size in bytes | f_bsize | f_bsize + # - # Fragment size in bytes | f_frsize (since Linux 2.6) | f_frsize + "blocks[8]" # Size of FS in f_frsize units | f_blocks | f_blocks + "bfree[8]" # Number of free blocks | f_bfree | f_bfree + "bavail[8]" # Number of free blocks for unprivileged users | f_bavail | b_avail + "files[8]" # Number of inodes | f_files | f_files + "ffree[8]" # Number of free inodes | f_ffree | f_ffree + # - # Number of free inodes for unprivileged users | - | f_favail + "fsid[8]" # Filesystem instance ID | f_fsid | f_fsid + # - # Mount flags | f_flags (since Linux 2.6.36) | f_flag + "namelen[4]" # Maximum filename length | f_namemax | f_namemax +msg Tlopen = "size[4,val=end-&size] typ[1,val=12] tag[tag] fid[fid] flags[lo]" # analogous to 112/Topen msg Rlopen = "size[4,val=end-&size] typ[1,val=13] tag[tag] qid[qid] iounit[4]" # analogous to 113/Ropen -msg Tlcreate = "size[4,val=end-&size] typ[1,val=14] tag[tag] fid[fid] name[s] flags[4] mode[4] gid[nuid]" # analogous to 114/Tcreate +msg Tlcreate = "size[4,val=end-&size] typ[1,val=14] tag[tag] fid[fid] name[s] flags[lo] mode[mode] gid[nuid]" # analogous to 114/Tcreate msg Rlcreate = "size[4,val=end-&size] typ[1,val=15] tag[tag] qid[qid] iounit[4]" # analogous to 115/Rcreate msg Tsymlink = "size[4,val=end-&size] typ[1,val=16] tag[tag] fid[fid] name[s] symtgt[s] gid[nuid]" msg Rsymlink = "size[4,val=end-&size] typ[1,val=17] tag[tag] qid[qid]" -msg Tmknod = "size[4,val=end-&size] typ[1,val=18] tag[tag] dfid[fid] name[s] mode[4] major[4] minor[4] gid[nuid]" +msg Tmknod = "size[4,val=end-&size] typ[1,val=18] tag[tag] dfid[fid] name[s] mode[mode] major[4] minor[4] gid[nuid]" msg Rmknod = "size[4,val=end-&size] typ[1,val=19] tag[tag] qid[qid]" msg Trename = "size[4,val=end-&size] typ[1,val=20] tag[tag] fid[fid] dfid[fid] name[s]" msg Rrename = "size[4,val=end-&size] typ[1,val=21] tag[tag]" msg Treadlink = "size[4,val=end-&size] typ[1,val=22] tag[tag] fid[fid]" msg Rreadlink = "size[4,val=end-&size] typ[1,val=23] tag[tag] target[s]" msg Tgetattr = "size[4,val=end-&size] typ[1,val=24] tag[tag] fid[fid] request_mask[getattr]" -msg Rgetattr = "size[4,val=end-&size] typ[1,val=25] tag[tag] valid[8] qid[qid] mode[4] uid[nuid] gid[nuid] nlink[8]" +msg Rgetattr = "size[4,val=end-&size] typ[1,val=25] tag[tag] valid[getattr] qid[qid] mode[mode] uid[nuid] gid[nuid] nlink[8]" "rdev[8] filesize[8] blksize[8] blocks[8]" "atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]" "ctime_sec[8] ctime_nsec[8] btime_sec[8] btime_nsec[8]" "gen[8] data_version[8]" -msg Tsetattr = "size[4,val=end-&size] typ[1,val=26] tag[tag] fid[fid] valid[setattr] mode[4] uid[nuid] gid[nuid] filesize[8] atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]" +msg Tsetattr = "size[4,val=end-&size] typ[1,val=26] tag[tag] fid[fid] valid[setattr] mode[mode] uid[nuid] gid[nuid] filesize[8] atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]" msg Rsetattr = "size[4,val=end-&size] typ[1,val=27] tag[tag]" #... msg Txattrwalk = "size[4,val=end-&size] typ[1,val=30] tag[tag] fid[fid] newfid[fid] name[s]" @@ -89,18 +213,18 @@ msg Txattrcreate = "size[4,val=end-&size] typ[1,val=32] tag[tag] fid[fid] name[s msg Rxattrcreate = "size[4,val=end-&size] typ[1,val=33] tag[tag]" #... msg Treaddir = "size[4,val=end-&size] typ[1,val=40] tag[tag] fid[fid] offset[8] count[4]" -msg Rreaddir = "size[4,val=end-&size] typ[1,val=41] tag[tag] count[4] count*(data[1])" # data is "qid[qid] offset[8] type[1] name[s]" +msg Rreaddir = "size[4,val=end-&size] typ[1,val=41] tag[tag] count[4] count*(data[1])" # data is "qid[qid] offset[8] type[dt] name[s]" #... -msg Tfsync = "size[4,val=end-&size] typ[1,val=50] tag[tag] fid[fid] datasync[4]" +msg Tfsync = "size[4,val=end-&size] typ[1,val=50] tag[tag] fid[fid] datasync[b4]" msg Rfsync = "size[4,val=end-&size] typ[1,val=51] tag[tag]" msg Tlock = "size[4,val=end-&size] typ[1,val=52] tag[tag] fid[fid] type[lock_type] flags[lock_flags] start[8] length[8] proc_id[4] client_id[s]" msg Rlock = "size[4,val=end-&size] typ[1,val=53] tag[tag] status[lock_status]" -msg Tgetlock = "size[4,val=end-&size] typ[1,val=54] tag[tag] fid[fid] type[1] start[8] length[8] proc_id[4] client_id[s]" -msg Rgetlock = "size[4,val=end-&size] typ[1,val=55] tag[tag] type[1] start[8] length[8] proc_id[4] client_id[s]" +msg Tgetlock = "size[4,val=end-&size] typ[1,val=54] tag[tag] fid[fid] type[lock_type] start[8] length[8] proc_id[4] client_id[s]" +msg Rgetlock = "size[4,val=end-&size] typ[1,val=55] tag[tag] type[lock_type] start[8] length[8] proc_id[4] client_id[s]" # ... msg Tlink = "size[4,val=end-&size] typ[1,val=70] tag[tag] dfid[fid] fid[fid] name[s]" msg Rlink = "size[4,val=end-&size] typ[1,val=71] tag[tag]" -msg Tmkdir = "size[4,val=end-&size] typ[1,val=72] tag[tag] dfid[fid] name[s] mode[4] gid[nuid]" +msg Tmkdir = "size[4,val=end-&size] typ[1,val=72] tag[tag] dfid[fid] name[s] mode[mode] gid[nuid]" msg Rmkdir = "size[4,val=end-&size] typ[1,val=73] tag[tag] qid[qid]" msg Trenameat = "size[4,val=end-&size] typ[1,val=74] tag[tag] olddirfid[fid] oldname[s] newdirfid[fid] newname[s]" msg Rrenameat = "size[4,val=end-&size] typ[1,val=75] tag[tag]" diff --git a/lib9p/idl/__init__.py b/lib9p/idl/__init__.py index a01c38f..e7b3670 100644 --- a/lib9p/idl/__init__.py +++ b/lib9p/idl/__init__.py @@ -6,8 +6,9 @@ import enum import os.path import re -from typing import Callable, Literal, TypeVar, cast +import typing +# pylint: disable=unused-variable __all__ = [ # entrypoint "Parser", @@ -15,7 +16,7 @@ __all__ = [ "Type", "Primitive", "Number", - *["Bitfield", "BitfieldVal"], + *["Bitfield", "Bit", "BitCat", "BitAlias"], *["Struct", "StructMember", "Expr", "ExprOp", "ExprSym", "ExprLit"], "Message", ] @@ -36,7 +37,7 @@ class Primitive(enum.Enum): return set() @property - def name(self) -> str: + def typname(self) -> str: return str(self.value) @property @@ -51,7 +52,7 @@ class Primitive(enum.Enum): class Number: - name: str + typname: str in_versions: set[str] prim: Primitive @@ -73,27 +74,49 @@ class Number: return self.static_size -class BitfieldVal: - name: str +class BitCat(enum.Enum): + UNUSED = 1 + USED = 2 + RESERVED = 3 + SUBFIELD = 4 + + +class Bit: + bitname: str in_versions: set[str] + num: int + cat: BitCat - val: str + def __init__(self, num: int) -> None: + self.bitname = "" + self.in_versions = set() + self.num = num + self.cat = BitCat.UNUSED - def __init__(self) -> None: + +class BitAlias: + bitname: str + in_versions: set[str] + val: str # FIXME: Don't have bitfield aliases be raw C expressions + + def __init__(self, name: str, val: str) -> None: + self.bitname = name self.in_versions = set() + self.val = val class Bitfield: - name: str + typname: str in_versions: set[str] - prim: Primitive + bits: list[Bit] + names: dict[str, Bit | BitAlias] - bits: list[str] # bitnames - names: dict[str, BitfieldVal] # bits *and* aliases - - def __init__(self) -> None: + def __init__(self, name: str, prim: Primitive) -> None: + self.typname = name self.in_versions = set() + self.prim = prim + self.bits = [Bit(i) for i in range(prim.static_size * 8)] self.names = {} @property @@ -106,21 +129,6 @@ class Bitfield: def max_size(self, version: str) -> int: return self.static_size - def bit_is_valid(self, bit: str | int, ver: str | None = None) -> bool: - """Return whether the given bit is valid in the given protocol - version. - - """ - bitname = self.bits[bit] if isinstance(bit, int) else bit - assert bitname in self.bits - if not bitname: - return False - if bitname.startswith("_"): - return False - if ver and (ver not in self.names[bitname].in_versions): - return False - return True - class ExprLit: val: int @@ -130,16 +138,16 @@ class ExprLit: class ExprSym: - name: str + symname: str def __init__(self, name: str) -> None: - self.name = name + self.symname = name class ExprOp: - op: Literal["-", "+"] + op: typing.Literal["-", "+"] - def __init__(self, op: Literal["-", "+"]) -> None: + def __init__(self, op: typing.Literal["-", "+"]) -> None: self.op = op @@ -156,7 +164,7 @@ class Expr: class StructMember: # from left-to-right when parsing cnt: "StructMember | None" = None - name: str + membname: str typ: "Type" max: Expr val: Expr @@ -168,10 +176,10 @@ class StructMember: assert self.cnt if not isinstance(self.cnt.typ, Primitive): raise ValueError( - f"list count must be an integer type: {repr(self.cnt.name)}" + f"list count must be an integer type: {self.cnt.membname!r}" ) if self.cnt.val: # TODO: allow this? - raise ValueError(f"list count may not have ,val=: {repr(self.cnt.name)}") + raise ValueError(f"list count may not have ,val=: {self.cnt.membname!r}") return 0 @property @@ -179,26 +187,26 @@ class StructMember: assert self.cnt if not isinstance(self.cnt.typ, Primitive): raise ValueError( - f"list count must be an integer type: {repr(self.cnt.name)}" + f"list count must be an integer type: {self.cnt.membname!r}" ) if self.cnt.val: # TODO: allow this? - raise ValueError(f"list count may not have ,val=: {repr(self.cnt.name)}") + raise ValueError(f"list count may not have ,val=: {self.cnt.membname!r}") if self.cnt.max: # TODO: be more flexible? if len(self.cnt.max.tokens) != 1: raise ValueError( - f"list count ,max= may only have 1 token: {repr(self.cnt.name)}" + f"list count ,max= may only have 1 token: {self.cnt.membname!r}" ) match tok := self.cnt.max.tokens[0]: case ExprLit(): return tok.val - case ExprSym(name="s32_max"): + case ExprSym(symname="s32_max"): return (1 << 31) - 1 - case ExprSym(name="s64_max"): + case ExprSym(symname="s64_max"): return (1 << 63) - 1 case _: raise ValueError( - f'list count ,max= only allows literal, "s32_max", and "s64_max" tokens: {repr(self.cnt.name)}' + f'list count ,max= only allows literal, "s32_max", and "s64_max" tokens: {self.cnt.membname!r}' ) return (1 << (self.cnt.typ.value * 8)) - 1 @@ -218,7 +226,7 @@ class StructMember: class Struct: - name: str + typname: str in_versions: set[str] members: list[StructMember] @@ -257,7 +265,7 @@ class Message(Struct): @property def msgid(self) -> int: assert len(self.members) >= 3 - assert self.members[1].name == "typ" + assert self.members[1].membname == "typ" assert self.members[1].static_size == 1 assert self.members[1].val assert len(self.members[1].val.tokens) == 1 @@ -266,12 +274,15 @@ class Message(Struct): type Type = Primitive | Number | Bitfield | Struct | Message -T = TypeVar("T", Number, Bitfield, Struct, Message) +type UserType = Number | Bitfield | Struct | Message +T = typing.TypeVar("T", Number, Bitfield, Struct, Message) # Parse ######################################################################## re_priname = "(?:1|2|4|8)" # primitive names re_symname = "(?:[a-zA-Z_][a-zA-Z_0-9]*)" # "symbol" names; most *.9p-defined names +re_symname_u = "(?:[A-Z_][A-Z_0-9]*)" # upper-case "symbol" names; bit names +re_symname_l = "(?:[a-z_][a-z_0-9]*)" # lower-case "symbol" names; bit names re_impname = r"(?:\*|" + re_symname + ")" # names we can import re_msgname = r"(?:[TR][a-zA-Z_0-9]*)" # names a message can be @@ -281,8 +292,18 @@ re_expr = f"(?:(?:-|\\+|[0-9]+|&?{re_symname})+)" re_numspec = f"(?P<name>{re_symname})\\s*=\\s*(?P<val>\\S+)" -re_bitspec_bit = f"(?P<bit>[0-9]+)\\s*=\\s*(?P<name>{re_symname})" -re_bitspec_alias = f"(?P<name>{re_symname})\\s*=\\s*(?P<val>\\S+)" +re_bitspec_bit = ( + "(?P<bitnum>[0-9]+)\\s*=\\s*(?:" + + "|".join( + [ + f"(?P<name_used>{re_symname_u})", + f"reserved\\((?P<name_reserved>{re_symname_u})\\)", + f"subfield\\((?P<name_subfield>{re_symname_l})\\)", + ] + ) + + ")" +) +re_bitspec_alias = f"(?P<name>{re_symname_u})\\s*=\\s*(?P<val>\\S+)" re_memberspec = f"(?:(?P<cnt>{re_symname})\\*\\()?(?P<name>{re_symname})\\[(?P<typ>{re_memtype})(?:,max=(?P<max>{re_expr})|,val=(?P<val>{re_expr}))*\\]\\)?" @@ -294,55 +315,67 @@ def parse_numspec(ver: str, n: Number, spec: str) -> None: name = m.group("name") val = m.group("val") if name in n.vals: - raise ValueError(f"{n.name}: name {repr(name)} already assigned") + raise ValueError(f"{n.typname}: name {name!r} already assigned") n.vals[name] = val else: - raise SyntaxError(f"invalid num spec {repr(spec)}") + raise SyntaxError(f"invalid num spec {spec!r}") def parse_bitspec(ver: str, bf: Bitfield, spec: str) -> None: spec = spec.strip() - bit: int | None - val: BitfieldVal if m := re.fullmatch(re_bitspec_bit, spec): - bit = int(m.group("bit")) - name = m.group("name") - - val = BitfieldVal() - val.name = name - val.val = f"1<<{bit}" - val.in_versions.add(ver) - - if bit < 0 or bit >= len(bf.bits): - raise ValueError(f"{bf.name}: bit {bit} is out-of-bounds") - if bf.bits[bit]: - raise ValueError(f"{bf.name}: bit {bit} already assigned") - bf.bits[bit] = val.name + bitnum = int(m.group("bitnum")) + if bitnum < 0 or bitnum >= len(bf.bits): + raise ValueError(f"{bf.typname}: bit num {bitnum} out-of-bounds") + bit = bf.bits[bitnum] + if bit.cat != BitCat.UNUSED: + raise ValueError(f"{bf.typname}: bit num {bitnum} already assigned") + if name := m.group("name_used"): + bit.bitname = name + bit.cat = BitCat.USED + bit.in_versions.add(ver) + elif name := m.group("name_reserved"): + bit.bitname = name + bit.cat = BitCat.RESERVED + bit.in_versions.add(ver) + elif name := m.group("name_subfield"): + bit.bitname = name + bit.cat = BitCat.SUBFIELD + bit.in_versions.add(ver) + if bit.bitname: + if bit.bitname in bf.names: + other = bf.names[bit.bitname] + if ( + isinstance(other, Bit) + and other.cat == bit.cat + and bit.cat == BitCat.SUBFIELD + ): + return + raise ValueError( + f"{bf.typname}: bit name {bit.bitname!r} already assigned" + ) + bf.names[bit.bitname] = bit elif m := re.fullmatch(re_bitspec_alias, spec): - name = m.group("name") - valstr = m.group("val") - - val = BitfieldVal() - val.name = name - val.val = valstr - val.in_versions.add(ver) + alias = BitAlias(m.group("name"), m.group("val")) + alias.in_versions.add(ver) + if alias.bitname in bf.names: + raise ValueError( + f"{bf.typname}: bit name {alias.bitname!r} already assigned" + ) + bf.names[alias.bitname] = alias else: - raise SyntaxError(f"invalid bitfield spec {repr(spec)}") - - if val.name in bf.names: - raise ValueError(f"{bf.name}: name {val.name} already assigned") - bf.names[val.name] = val + raise SyntaxError(f"invalid bitfield spec {spec!r}") def parse_expr(expr: str) -> Expr: assert re.fullmatch(re_expr, expr) ret = Expr() for tok in re.split("([-+])", expr): - if tok == "-" or tok == "+": + if tok in ("-", "+"): # I, for the life of me, do not understand why I need this - # cast() to keep mypy happy. - ret.tokens += [ExprOp(cast(Literal["-", "+"], tok))] + # typing.cast() to keep mypy happy. + ret.tokens += [ExprOp(typing.cast(typing.Literal["-", "+"], tok))] elif re.fullmatch("[0-9]+", tok): ret.tokens += [ExprLit(int(tok))] else: @@ -354,22 +387,22 @@ def parse_members(ver: str, env: dict[str, Type], struct: Struct, specs: str) -> for spec in specs.split(): m = re.fullmatch(re_memberspec, spec) if not m: - raise SyntaxError(f"invalid member spec {repr(spec)}") + raise SyntaxError(f"invalid member spec {spec!r}") member = StructMember() member.in_versions = {ver} - member.name = m.group("name") - if any(x.name == member.name for x in struct.members): - raise ValueError(f"duplicate member name {repr(member.name)}") + member.membname = m.group("name") + if any(x.membname == member.membname for x in struct.members): + raise ValueError(f"duplicate member name {member.membname!r}") if m.group("typ") not in env: - raise NameError(f"Unknown type {repr(m.group('typ'))}") + raise NameError(f"Unknown type {m.group('typ')!r}") member.typ = env[m.group("typ")] if cnt := m.group("cnt"): - if len(struct.members) == 0 or struct.members[-1].name != cnt: - raise ValueError(f"list count must be previous item: {repr(cnt)}") + if len(struct.members) == 0 or struct.members[-1].membname != cnt: + raise ValueError(f"list count must be previous item: {cnt!r}") cnt_mem = struct.members[-1] member.cnt = cnt_mem _ = member.max_cnt # force validation @@ -412,8 +445,8 @@ re_line_cont = f"\\s+{re_string('specs')}" # could be bitfield/struct/msg def parse_file( - filename: str, get_include: Callable[[str], tuple[str, list[Type]]] -) -> tuple[str, list[Type]]: + filename: str, get_include: typing.Callable[[str], tuple[str, list[UserType]]] +) -> tuple[str, list[UserType]]: version: str | None = None env: dict[str, Type] = { "1": Primitive.u8, @@ -425,13 +458,13 @@ def parse_file( def get_type(name: str, tc: type[T]) -> T: nonlocal env if name not in env: - raise NameError(f"Unknown type {repr(name)}") + raise NameError(f"Unknown type {name!r}") ret = env[name] if (not isinstance(ret, tc)) or (ret.__class__.__name__ != tc.__name__): - raise NameError(f"Type {repr(ret.name)} is not a {tc.__name__}") + raise NameError(f"Type {ret.typname!r} is not a {tc.__name__}") return ret - with open(filename, "r") as fh: + with open(filename, "r", encoding="utf-8") as fh: prev: Type | None = None for lineno, line in enumerate(fh): try: @@ -452,7 +485,7 @@ def parse_file( symname = symname.strip() found = False for typ in other_typs: - if typ.name == symname or symname == "*": + if symname in (typ.typname, "*"): found = True match typ: case Primitive(): @@ -461,6 +494,9 @@ def parse_file( typ.in_versions.add(version) case Bitfield(): typ.in_versions.add(version) + for bit in typ.bits: + if other_version in bit.in_versions: + bit.in_versions.add(version) for val in typ.names.values(): if other_version in val.in_versions: val.in_versions.add(version) @@ -469,42 +505,38 @@ def parse_file( for member in typ.members: if other_version in member.in_versions: member.in_versions.add(version) - if typ.name in env and env[typ.name] != typ: + if typ.typname in env and env[typ.typname] != typ: raise ValueError( - f"duplicate type name {repr(typ.name)}" + f"duplicate type name {typ.typname!r}" ) - env[typ.name] = typ + env[typ.typname] = typ if symname != "*" and not found: raise ValueError( - f"import: {m.group('file')}: no symbol {repr(symname)}" + f"import: {m.group('file')}: no symbol {symname!r}" ) elif m := re.fullmatch(re_line_num, line): num = Number() - num.name = m.group("name") + num.typname = m.group("name") num.in_versions.add(version) prim = env[m.group("prim")] assert isinstance(prim, Primitive) num.prim = prim - if num.name in env: - raise ValueError(f"duplicate type name {repr(num.name)}") - env[num.name] = num + if num.typname in env: + raise ValueError(f"duplicate type name {num.typname!r}") + env[num.typname] = num prev = num elif m := re.fullmatch(re_line_bitfield, line): - bf = Bitfield() - bf.name = m.group("name") - bf.in_versions.add(version) - prim = env[m.group("prim")] assert isinstance(prim, Primitive) - bf.prim = prim - bf.bits = (prim.static_size * 8) * [""] + bf = Bitfield(m.group("name"), prim) + bf.in_versions.add(version) - if bf.name in env: - raise ValueError(f"duplicate type name {repr(bf.name)}") - env[bf.name] = bf + if bf.typname in env: + raise ValueError(f"duplicate type name {bf.typname!r}") + env[bf.typname] = bf prev = bf elif m := re.fullmatch(re_line_bitfield_, line): bf = get_type(m.group("name"), Bitfield) @@ -515,16 +547,16 @@ def parse_file( match m.group("op"): case "=": struct = Struct() - struct.name = m.group("name") + struct.typname = m.group("name") struct.in_versions.add(version) struct.members = [] parse_members(version, env, struct, m.group("members")) - if struct.name in env: + if struct.typname in env: raise ValueError( - f"duplicate type name {repr(struct.name)}" + f"duplicate type name {struct.typname!r}" ) - env[struct.name] = struct + env[struct.typname] = struct prev = struct case "+=": struct = get_type(m.group("name"), Struct) @@ -535,16 +567,14 @@ def parse_file( match m.group("op"): case "=": msg = Message() - msg.name = m.group("name") + msg.typname = m.group("name") msg.in_versions.add(version) msg.members = [] parse_members(version, env, msg, m.group("members")) - if msg.name in env: - raise ValueError( - f"duplicate type name {repr(msg.name)}" - ) - env[msg.name] = msg + if msg.typname in env: + raise ValueError(f"duplicate type name {msg.typname!r}") + env[msg.typname] = msg prev = msg case "+=": msg = get_type(m.group("name"), Message) @@ -574,22 +604,27 @@ def parse_file( if not version: raise SyntaxError("must have exactly 1 version line") - typs: list[Type] = [x for x in env.values() if not isinstance(x, Primitive)] + typs: list[UserType] = [x for x in env.values() if not isinstance(x, Primitive)] for typ in [typ for typ in typs if isinstance(typ, Struct)]: - valid_syms = ["end", "s32_max", "s64_max", *["&" + m.name for m in typ.members]] + valid_syms = [ + "end", + "s32_max", + "s64_max", + *["&" + m.membname for m in typ.members], + ] for member in typ.members: if ( not isinstance(member.typ, Primitive) and member.typ.in_versions < member.in_versions ): raise ValueError( - f"{typ.name}.{member.name}: type {member.typ.name} does not exist in {member.in_versions.difference(member.typ.in_versions)}" + f"{typ.typname}.{member.membname}: type {member.typ.typname} does not exist in {member.in_versions.difference(member.typ.in_versions)}" ) for tok in [*member.max.tokens, *member.val.tokens]: - if isinstance(tok, ExprSym) and tok.name not in valid_syms: + if isinstance(tok, ExprSym) and tok.symname not in valid_syms: raise ValueError( - f"{typ.name}.{member.name}: invalid sym: {tok.name}" + f"{typ.typname}.{member.membname}: invalid sym: {tok.symname}" ) return version, typs @@ -599,35 +634,35 @@ def parse_file( class Parser: - cache: dict[str, tuple[str, list[Type]]] = {} + cache: dict[str, tuple[str, list[UserType]]] = {} - def parse_file(self, filename: str) -> tuple[str, list[Type]]: + def parse_file(self, filename: str) -> tuple[str, list[UserType]]: filename = os.path.normpath(filename) if filename not in self.cache: - def get_include(other_filename: str) -> tuple[str, list[Type]]: + def get_include(other_filename: str) -> tuple[str, list[UserType]]: return self.parse_file(os.path.join(filename, "..", other_filename)) self.cache[filename] = parse_file(filename, get_include) return self.cache[filename] - def all(self) -> tuple[set[str], list[Type]]: + def all(self) -> tuple[set[str], list[UserType]]: ret_versions: set[str] = set() - ret_typs: dict[str, Type] = {} + ret_typs: dict[str, UserType] = {} for version, typs in self.cache.values(): if version in ret_versions: - raise ValueError(f"duplicate protocol version {repr(version)}") + raise ValueError(f"duplicate protocol version {version!r}") ret_versions.add(version) for typ in typs: - if typ.name in ret_typs: - if typ != ret_typs[typ.name]: - raise ValueError(f"duplicate type name {repr(typ.name)}") + if typ.typname in ret_typs: + if typ != ret_typs[typ.typname]: + raise ValueError(f"duplicate type name {typ.typname!r}") else: - ret_typs[typ.name] = typ + ret_typs[typ.typname] = typ msgids: set[int] = set() for typ in ret_typs.values(): if isinstance(typ, Message): if typ.msgid in msgids: - raise ValueError(f"duplicate msgid {repr(typ.msgid)}") + raise ValueError(f"duplicate msgid {typ.msgid!r}") msgids.add(typ.msgid) return ret_versions, list(ret_typs.values()) diff --git a/lib9p/include/lib9p/9p.generated.h b/lib9p/include/lib9p/9p.generated.h index d34a0f6..7a50537 100644 --- a/lib9p/include/lib9p/9p.generated.h +++ b/lib9p/include/lib9p/9p.generated.h @@ -1,4 +1,4 @@ -/* Generated by `lib9p/idl.gen lib9p/idl/2002-9P2000.9p lib9p/idl/2003-9P2000.p9p.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2010-9P2000.L.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */ +/* Generated by `lib9p/proto.gen lib9p/idl/2002-9P2000.9p lib9p/idl/2003-9P2000.p9p.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2010-9P2000.L.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */ #ifndef _LIB9P_9P_H_ #error Do not include <lib9p/9p.generated.h> directly; include <lib9p/9p.h> instead @@ -24,7 +24,7 @@ #error config.h must define CONFIG_9P_ENABLE_9P2000_e #else #if CONFIG_9P_ENABLE_9P2000_e - #ifndef(CONFIG_9P_MAX_9P2000_e_WELEM) + #ifndef CONFIG_9P_MAX_9P2000_e_WELEM #error if CONFIG_9P_ENABLE_9P2000_e then config.h must define CONFIG_9P_MAX_9P2000_e_WELEM #endif static_assert(CONFIG_9P_MAX_9P2000_e_WELEM > 0); @@ -176,62 +176,62 @@ struct lib9p_s { /* size = 4 ; max_iov = 1 ; max_copy = 4 */ typedef uint32_t lib9p_dm_t; -#define LIB9P_DM_DIR ((lib9p_dm_t)(1<<31)) -#define LIB9P_DM_APPEND ((lib9p_dm_t)(1<<30)) -#define LIB9P_DM_EXCL ((lib9p_dm_t)(1<<29)) -#define _LIB9P_DM_PLAN9_MOUNT ((lib9p_dm_t)(1<<28)) -#define LIB9P_DM_AUTH ((lib9p_dm_t)(1<<27)) -#define LIB9P_DM_TMP ((lib9p_dm_t)(1<<26)) -/* unused ((lib9p_dm_t)(1<<25)) */ -/* unused ((lib9p_dm_t)(1<<24)) */ +#define LIB9P_DM_DIR ((lib9p_dm_t)(1<<31)) +#define LIB9P_DM_APPEND ((lib9p_dm_t)(1<<30)) +#define LIB9P_DM_EXCL ((lib9p_dm_t)(1<<29)) +#define _LIB9P_DM_RESERVED_PLAN9_MOUNT ((lib9p_dm_t)(1<<28)) +#define LIB9P_DM_AUTH ((lib9p_dm_t)(1<<27)) +#define LIB9P_DM_TMP ((lib9p_dm_t)(1<<26)) +/* unused ((lib9p_dm_t)(1<<25)) */ +/* unused ((lib9p_dm_t)(1<<24)) */ #if CONFIG_9P_ENABLE_9P2000_u -# define LIB9P_DM_DEVICE ((lib9p_dm_t)(1<<23)) +# define LIB9P_DM_DEVICE ((lib9p_dm_t)(1<<23)) #endif /* CONFIG_9P_ENABLE_9P2000_u */ -/* unused ((lib9p_dm_t)(1<<22)) */ +/* unused ((lib9p_dm_t)(1<<22)) */ #if CONFIG_9P_ENABLE_9P2000_u -# define LIB9P_DM_NAMEDPIPE ((lib9p_dm_t)(1<<21)) -# define LIB9P_DM_SOCKET ((lib9p_dm_t)(1<<20)) -# define LIB9P_DM_SETUID ((lib9p_dm_t)(1<<19)) -# define LIB9P_DM_SETGID ((lib9p_dm_t)(1<<18)) +# define LIB9P_DM_NAMEDPIPE ((lib9p_dm_t)(1<<21)) +# define LIB9P_DM_SOCKET ((lib9p_dm_t)(1<<20)) +# define LIB9P_DM_SETUID ((lib9p_dm_t)(1<<19)) +# define LIB9P_DM_SETGID ((lib9p_dm_t)(1<<18)) #endif /* CONFIG_9P_ENABLE_9P2000_u */ -/* unused ((lib9p_dm_t)(1<<17)) */ -/* unused ((lib9p_dm_t)(1<<16)) */ -/* unused ((lib9p_dm_t)(1<<15)) */ -/* unused ((lib9p_dm_t)(1<<14)) */ -/* unused ((lib9p_dm_t)(1<<13)) */ -/* unused ((lib9p_dm_t)(1<<12)) */ -/* unused ((lib9p_dm_t)(1<<11)) */ -/* unused ((lib9p_dm_t)(1<<10)) */ -/* unused ((lib9p_dm_t)(1<<9)) */ -#define LIB9P_DM_OWNER_R ((lib9p_dm_t)(1<<8)) -#define LIB9P_DM_OWNER_W ((lib9p_dm_t)(1<<7)) -#define LIB9P_DM_OWNER_X ((lib9p_dm_t)(1<<6)) -#define LIB9P_DM_GROUP_R ((lib9p_dm_t)(1<<5)) -#define LIB9P_DM_GROUP_W ((lib9p_dm_t)(1<<4)) -#define LIB9P_DM_GROUP_X ((lib9p_dm_t)(1<<3)) -#define LIB9P_DM_OTHER_R ((lib9p_dm_t)(1<<2)) -#define LIB9P_DM_OTHER_W ((lib9p_dm_t)(1<<1)) -#define LIB9P_DM_OTHER_X ((lib9p_dm_t)(1<<0)) - -#define LIB9P_DM_PERM_MASK ((lib9p_dm_t)(0777)) +/* unused ((lib9p_dm_t)(1<<17)) */ +/* unused ((lib9p_dm_t)(1<<16)) */ +/* unused ((lib9p_dm_t)(1<<15)) */ +/* unused ((lib9p_dm_t)(1<<14)) */ +/* unused ((lib9p_dm_t)(1<<13)) */ +/* unused ((lib9p_dm_t)(1<<12)) */ +/* unused ((lib9p_dm_t)(1<<11)) */ +/* unused ((lib9p_dm_t)(1<<10)) */ +/* unused ((lib9p_dm_t)(1<<9)) */ +#define LIB9P_DM_OWNER_R ((lib9p_dm_t)(1<<8)) +#define LIB9P_DM_OWNER_W ((lib9p_dm_t)(1<<7)) +#define LIB9P_DM_OWNER_X ((lib9p_dm_t)(1<<6)) +#define LIB9P_DM_GROUP_R ((lib9p_dm_t)(1<<5)) +#define LIB9P_DM_GROUP_W ((lib9p_dm_t)(1<<4)) +#define LIB9P_DM_GROUP_X ((lib9p_dm_t)(1<<3)) +#define LIB9P_DM_OTHER_R ((lib9p_dm_t)(1<<2)) +#define LIB9P_DM_OTHER_W ((lib9p_dm_t)(1<<1)) +#define LIB9P_DM_OTHER_X ((lib9p_dm_t)(1<<0)) + +#define LIB9P_DM_PERM_MASK ((lib9p_dm_t)(0777)) #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u /* size = 1 ; max_iov = 1 ; max_copy = 1 */ typedef uint8_t lib9p_qt_t; -#define LIB9P_QT_DIR ((lib9p_qt_t)(1<<7)) -#define LIB9P_QT_APPEND ((lib9p_qt_t)(1<<6)) -#define LIB9P_QT_EXCL ((lib9p_qt_t)(1<<5)) -#define _LIB9P_QT_PLAN9_MOUNT ((lib9p_qt_t)(1<<4)) -#define LIB9P_QT_AUTH ((lib9p_qt_t)(1<<3)) -#define LIB9P_QT_TMP ((lib9p_qt_t)(1<<2)) +#define LIB9P_QT_DIR ((lib9p_qt_t)(1<<7)) +#define LIB9P_QT_APPEND ((lib9p_qt_t)(1<<6)) +#define LIB9P_QT_EXCL ((lib9p_qt_t)(1<<5)) +#define _LIB9P_QT_RESERVED_PLAN9_MOUNT ((lib9p_qt_t)(1<<4)) +#define LIB9P_QT_AUTH ((lib9p_qt_t)(1<<3)) +#define LIB9P_QT_TMP ((lib9p_qt_t)(1<<2)) #if CONFIG_9P_ENABLE_9P2000_u -# define LIB9P_QT_SYMLINK ((lib9p_qt_t)(1<<1)) +# define LIB9P_QT_SYMLINK ((lib9p_qt_t)(1<<1)) #endif /* CONFIG_9P_ENABLE_9P2000_u */ -/* unused ((lib9p_qt_t)(1<<0)) */ +/* unused ((lib9p_qt_t)(1<<0)) */ -#define LIB9P_QT_FILE ((lib9p_qt_t)(0)) +#define LIB9P_QT_FILE ((lib9p_qt_t)(0)) #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u @@ -244,24 +244,140 @@ typedef uint32_t lib9p_nuid_t; /* size = 1 ; max_iov = 1 ; max_copy = 1 */ typedef uint8_t lib9p_o_t; -/* unused ((lib9p_o_t)(1<<7)) */ -#define LIB9P_O_RCLOSE ((lib9p_o_t)(1<<6)) -/* unused ((lib9p_o_t)(1<<5)) */ -#define LIB9P_O_TRUNC ((lib9p_o_t)(1<<4)) -/* unused ((lib9p_o_t)(1<<3)) */ -/* unused ((lib9p_o_t)(1<<2)) */ -#define LIB9P_O_mode_1 ((lib9p_o_t)(1<<1)) -#define LIB9P_O_mode_0 ((lib9p_o_t)(1<<0)) - -#define LIB9P_O_READ ((lib9p_o_t)(0)) -#define LIB9P_O_WRITE ((lib9p_o_t)(1)) -#define LIB9P_O_RDWR ((lib9p_o_t)(2)) -#define LIB9P_O_EXEC ((lib9p_o_t)(3)) -#define LIB9P_O_MODE_MASK ((lib9p_o_t)(0b00000011)) -#define LIB9P_O_FLAG_MASK ((lib9p_o_t)(0b11111100)) +/* unused ((lib9p_o_t)(1<<7)) */ +#define LIB9P_O_RCLOSE ((lib9p_o_t)(1<<6)) +#define _LIB9P_O_RESERVED_CEXEC ((lib9p_o_t)(1<<5)) +#define LIB9P_O_TRUNC ((lib9p_o_t)(1<<4)) +/* unused ((lib9p_o_t)(1<<3)) */ +/* unused ((lib9p_o_t)(1<<2)) */ +#define _LIB9P_O_mode_1 ((lib9p_o_t)(1<<1)) +#define _LIB9P_O_mode_0 ((lib9p_o_t)(1<<0)) + +#define LIB9P_O_READ ((lib9p_o_t)(0)) +#define LIB9P_O_WRITE ((lib9p_o_t)(1)) +#define LIB9P_O_RDWR ((lib9p_o_t)(2)) +#define LIB9P_O_EXEC ((lib9p_o_t)(3)) +#define LIB9P_O_MODE_MASK ((lib9p_o_t)(0b00000011)) +#define LIB9P_O_FLAG_MASK ((lib9p_o_t)(0b11111100)) #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u +/* size = 4 ; max_iov = 1 ; max_copy = 4 */ +typedef uint32_t lib9p_errno_t; +#define LIB9P_ERRNO_NOERROR ((lib9p_errno_t)UINT32_C(0)) + +#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_L +/* size = 4 ; max_iov = 1 ; max_copy = 4 */ +typedef uint32_t lib9p_super_magic_t; +#define LIB9P_SUPER_MAGIC_V9FS_MAGIC ((lib9p_super_magic_t)UINT32_C(0x01021997)) + +/* size = 4 ; max_iov = 1 ; max_copy = 4 */ +typedef uint32_t lib9p_lo_t; + +/* unused ((lib9p_lo_t)(1<<31)) */ +/* unused ((lib9p_lo_t)(1<<30)) */ +/* unused ((lib9p_lo_t)(1<<29)) */ +/* unused ((lib9p_lo_t)(1<<28)) */ +/* unused ((lib9p_lo_t)(1<<27)) */ +/* unused ((lib9p_lo_t)(1<<26)) */ +/* unused ((lib9p_lo_t)(1<<25)) */ +/* unused ((lib9p_lo_t)(1<<24)) */ +/* unused ((lib9p_lo_t)(1<<23)) */ +/* unused ((lib9p_lo_t)(1<<22)) */ +/* unused ((lib9p_lo_t)(1<<21)) */ +#define LIB9P_LO_SYNC ((lib9p_lo_t)(1<<20)) +#define LIB9P_LO_CLOEXEC ((lib9p_lo_t)(1<<19)) +#define LIB9P_LO_NOATIME ((lib9p_lo_t)(1<<18)) +#define LIB9P_LO_NOFOLLOW ((lib9p_lo_t)(1<<17)) +#define LIB9P_LO_DIRECTORY ((lib9p_lo_t)(1<<16)) +#define LIB9P_LO_LARGEFILE ((lib9p_lo_t)(1<<15)) +#define LIB9P_LO_DIRECT ((lib9p_lo_t)(1<<14)) +#define LIB9P_LO_BSD_FASYNC ((lib9p_lo_t)(1<<13)) +#define LIB9P_LO_DSYNC ((lib9p_lo_t)(1<<12)) +#define LIB9P_LO_NONBLOCK ((lib9p_lo_t)(1<<11)) +#define LIB9P_LO_APPEND ((lib9p_lo_t)(1<<10)) +#define LIB9P_LO_TRUNC ((lib9p_lo_t)(1<<9)) +#define LIB9P_LO_NOCTTY ((lib9p_lo_t)(1<<8)) +#define LIB9P_LO_EXCL ((lib9p_lo_t)(1<<7)) +#define LIB9P_LO_CREATE ((lib9p_lo_t)(1<<6)) +/* unused ((lib9p_lo_t)(1<<5)) */ +/* unused ((lib9p_lo_t)(1<<4)) */ +/* unused ((lib9p_lo_t)(1<<3)) */ +/* unused ((lib9p_lo_t)(1<<2)) */ +#define _LIB9P_LO_mode_1 ((lib9p_lo_t)(1<<1)) +#define _LIB9P_LO_mode_0 ((lib9p_lo_t)(1<<0)) + +#define LIB9P_LO_RDONLY ((lib9p_lo_t)(0)) +#define LIB9P_LO_WRONLY ((lib9p_lo_t)(1)) +#define LIB9P_LO_RDWR ((lib9p_lo_t)(2)) +#define LIB9P_LO_NOACCESS ((lib9p_lo_t)(3)) +#define LIB9P_LO_MODE_MASK ((lib9p_lo_t)(0b000000000000000000011)) +#define LIB9P_LO_FLAG_MASK ((lib9p_lo_t)(0b111111111111111000000)) + +/* size = 1 ; max_iov = 1 ; max_copy = 1 */ +typedef uint8_t lib9p_dt_t; +#define LIB9P_DT_UNKNOWN ((lib9p_dt_t)UINT8_C(0)) +#define LIB9P_DT_NAMED_PIPE ((lib9p_dt_t)UINT8_C(1)) +#define LIB9P_DT_CHAR_DEV ((lib9p_dt_t)UINT8_C(2)) +#define LIB9P_DT_DIRECTORY ((lib9p_dt_t)UINT8_C(4)) +#define LIB9P_DT_BLOCK_DEV ((lib9p_dt_t)UINT8_C(6)) +#define LIB9P_DT_REGULAR ((lib9p_dt_t)UINT8_C(8)) +#define LIB9P_DT_SYMLINK ((lib9p_dt_t)UINT8_C(10)) +#define LIB9P_DT_SOCKET ((lib9p_dt_t)UINT8_C(12)) +#define LIB9P_DT_WHITEOUT ((lib9p_dt_t)UINT8_C(14)) + +/* size = 4 ; max_iov = 1 ; max_copy = 4 */ +typedef uint32_t lib9p_mode_t; + +/* unused ((lib9p_mode_t)(1<<31)) */ +/* unused ((lib9p_mode_t)(1<<30)) */ +/* unused ((lib9p_mode_t)(1<<29)) */ +/* unused ((lib9p_mode_t)(1<<28)) */ +/* unused ((lib9p_mode_t)(1<<27)) */ +/* unused ((lib9p_mode_t)(1<<26)) */ +/* unused ((lib9p_mode_t)(1<<25)) */ +/* unused ((lib9p_mode_t)(1<<24)) */ +/* unused ((lib9p_mode_t)(1<<23)) */ +/* unused ((lib9p_mode_t)(1<<22)) */ +/* unused ((lib9p_mode_t)(1<<21)) */ +/* unused ((lib9p_mode_t)(1<<20)) */ +/* unused ((lib9p_mode_t)(1<<19)) */ +/* unused ((lib9p_mode_t)(1<<18)) */ +/* unused ((lib9p_mode_t)(1<<17)) */ +/* unused ((lib9p_mode_t)(1<<16)) */ +#define _LIB9P_MODE_fmt_3 ((lib9p_mode_t)(1<<15)) +#define _LIB9P_MODE_fmt_2 ((lib9p_mode_t)(1<<14)) +#define _LIB9P_MODE_fmt_1 ((lib9p_mode_t)(1<<13)) +#define _LIB9P_MODE_fmt_0 ((lib9p_mode_t)(1<<12)) +#define LIB9P_MODE_PERM_SETGROUP ((lib9p_mode_t)(1<<11)) +#define LIB9P_MODE_PERM_SETUSER ((lib9p_mode_t)(1<<10)) +#define LIB9P_MODE_PERM_STICKY ((lib9p_mode_t)(1<<9)) +#define LIB9P_MODE_PERM_OWNER_R ((lib9p_mode_t)(1<<8)) +#define LIB9P_MODE_PERM_OWNER_W ((lib9p_mode_t)(1<<7)) +#define LIB9P_MODE_PERM_OWNER_X ((lib9p_mode_t)(1<<6)) +#define LIB9P_MODE_PERM_GROUP_R ((lib9p_mode_t)(1<<5)) +#define LIB9P_MODE_PERM_GROUP_W ((lib9p_mode_t)(1<<4)) +#define LIB9P_MODE_PERM_GROUP_X ((lib9p_mode_t)(1<<3)) +#define LIB9P_MODE_PERM_OTHER_R ((lib9p_mode_t)(1<<2)) +#define LIB9P_MODE_PERM_OTHER_W ((lib9p_mode_t)(1<<1)) +#define LIB9P_MODE_PERM_OTHER_X ((lib9p_mode_t)(1<<0)) + +#define LIB9P_MODE_FMT_NAMED_PIPE ((lib9p_mode_t)(LIB9P_DT_NAMED_PIPE<<12)) +#define LIB9P_MODE_FMT_CHAR_DEV ((lib9p_mode_t)(LIB9P_DT_CHAR_DEV<<12)) +#define LIB9P_MODE_FMT_DIRECTORY ((lib9p_mode_t)(LIB9P_DT_DIRECTORY<<12)) +#define LIB9P_MODE_FMT_BLOCK_DEV ((lib9p_mode_t)(LIB9P_DT_BLOCK_DEV<<12)) +#define LIB9P_MODE_FMT_REGULAR ((lib9p_mode_t)(LIB9P_DT_REGULAR<<12)) +#define LIB9P_MODE_FMT_SYMLINK ((lib9p_mode_t)(LIB9P_DT_SYMLINK<<12)) +#define LIB9P_MODE_FMT_SOCKET ((lib9p_mode_t)(LIB9P_DT_SOCKET<<12)) +#define LIB9P_MODE_PERM_MASK ((lib9p_mode_t)(0000777)) +#define LIB9P_MODE_FMT_MASK ((lib9p_mode_t)(0170000)) + +/* size = 4 ; max_iov = 1 ; max_copy = 4 */ +typedef uint32_t lib9p_b4_t; +#define LIB9P_B4_FALSE ((lib9p_b4_t)UINT32_C(0)) +#define LIB9P_B4_TRUE ((lib9p_b4_t)UINT32_C(1)) + /* size = 8 ; max_iov = 1 ; max_copy = 8 */ typedef uint64_t lib9p_getattr_t; @@ -463,26 +579,6 @@ struct lib9p_msg_Rwstat { #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_L -/* size = 11 ; max_iov = 1 ; max_copy = 11 */ -struct lib9p_msg_Rlerror { - lib9p_tag_t tag; - uint32_t ecode; -}; - -/* size = 67 ; max_iov = 1 ; max_copy = 67 */ -struct lib9p_msg_Rstatfs { - lib9p_tag_t tag; - uint32_t type; - uint32_t bsize; - uint64_t blocks; - uint64_t bfree; - uint64_t bavail; - uint64_t files; - uint64_t ffree; - uint64_t fsid; - uint32_t namelen; -}; - /* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rrename { lib9p_tag_t tag; @@ -604,13 +700,6 @@ struct lib9p_msg_Tstatfs { lib9p_fid_t fid; }; -/* size = 15 ; max_iov = 1 ; max_copy = 15 */ -struct lib9p_msg_Tlopen { - lib9p_tag_t tag; - lib9p_fid_t fid; - uint32_t flags; -}; - /* size = 11 ; max_iov = 1 ; max_copy = 11 */ struct lib9p_msg_Treadlink { lib9p_tag_t tag; @@ -625,13 +714,6 @@ struct lib9p_msg_Treaddir { uint32_t count; }; -/* size = 15 ; max_iov = 1 ; max_copy = 15 */ -struct lib9p_msg_Tfsync { - lib9p_tag_t tag; - lib9p_fid_t fid; - uint32_t datasync; -}; - #endif /* CONFIG_9P_ENABLE_9P2000_L */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u /* min_size = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 2 ; max_copy = 13 */ @@ -648,19 +730,6 @@ struct lib9p_msg_Rversion { struct lib9p_s version; }; -/* LIB9P_VER_9P2000 : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ -/* LIB9P_VER_9P2000_L : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ -/* LIB9P_VER_9P2000_e : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ -/* LIB9P_VER_9P2000_p9p: min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ -/* LIB9P_VER_9P2000_u : min_size = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 3 ; max_copy = 13 */ -struct lib9p_msg_Rerror { - lib9p_tag_t tag; - struct lib9p_s ename; -#if CONFIG_9P_ENABLE_9P2000_u - uint32_t errno; -#endif /* CONFIG_9P_ENABLE_9P2000_u */ -}; - /* min_size = 17 ; exp_size = 481 ; max_size = 1,048,609 ; max_iov = 32 ; max_copy = 49 */ struct lib9p_msg_Twalk { lib9p_tag_t tag; @@ -703,27 +772,6 @@ struct lib9p_msg_Txattrcreate { uint32_t flags; }; -/* min_size = 34 ; exp_size = 61 ; max_size = 65,569 ; max_iov = 2 ; max_copy = 34 */ -struct lib9p_msg_Tgetlock { - lib9p_tag_t tag; - lib9p_fid_t fid; - uint8_t type; - uint64_t start; - uint64_t length; - uint32_t proc_id; - struct lib9p_s client_id; -}; - -/* min_size = 30 ; exp_size = 57 ; max_size = 65,565 ; max_iov = 2 ; max_copy = 30 */ -struct lib9p_msg_Rgetlock { - lib9p_tag_t tag; - uint8_t type; - uint64_t start; - uint64_t length; - uint32_t proc_id; - struct lib9p_s client_id; -}; - /* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */ struct lib9p_msg_Tlink { lib9p_tag_t tag; @@ -811,16 +859,6 @@ struct lib9p_msg_Tattach { #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_L -/* min_size = 25 ; exp_size = 52 ; max_size = 65,560 ; max_iov = 3 ; max_copy = 25 */ -struct lib9p_msg_Tlcreate { - lib9p_tag_t tag; - lib9p_fid_t fid; - struct lib9p_s name; - uint32_t flags; - uint32_t mode; - lib9p_nuid_t gid; -}; - /* min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 5 ; max_copy = 19 */ struct lib9p_msg_Tsymlink { lib9p_tag_t tag; @@ -830,26 +868,6 @@ struct lib9p_msg_Tsymlink { lib9p_nuid_t gid; }; -/* min_size = 29 ; exp_size = 56 ; max_size = 65,564 ; max_iov = 3 ; max_copy = 29 */ -struct lib9p_msg_Tmknod { - lib9p_tag_t tag; - lib9p_fid_t dfid; - struct lib9p_s name; - uint32_t mode; - uint32_t major; - uint32_t minor; - lib9p_nuid_t gid; -}; - -/* min_size = 21 ; exp_size = 48 ; max_size = 65,556 ; max_iov = 3 ; max_copy = 21 */ -struct lib9p_msg_Tmkdir { - lib9p_tag_t tag; - lib9p_fid_t dfid; - struct lib9p_s name; - uint32_t mode; - lib9p_nuid_t gid; -}; - #endif /* CONFIG_9P_ENABLE_9P2000_L */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u /* size = 12 ; max_iov = 1 ; max_copy = 12 */ @@ -878,7 +896,86 @@ struct lib9p_msg_Topenfd { }; #endif /* CONFIG_9P_ENABLE_9P2000_p9p */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +/* LIB9P_VER_9P2000 : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ +/* LIB9P_VER_9P2000_L : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ +/* LIB9P_VER_9P2000_e : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ +/* LIB9P_VER_9P2000_p9p: min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ +/* LIB9P_VER_9P2000_u : min_size = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 3 ; max_copy = 13 */ +struct lib9p_msg_Rerror { + lib9p_tag_t tag; + struct lib9p_s ename; +#if CONFIG_9P_ENABLE_9P2000_u + lib9p_errno_t errno; +#endif /* CONFIG_9P_ENABLE_9P2000_u */ +}; + +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_L +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ +struct lib9p_msg_Rlerror { + lib9p_tag_t tag; + lib9p_errno_t ecode; +}; + +/* size = 67 ; max_iov = 1 ; max_copy = 67 */ +struct lib9p_msg_Rstatfs { + lib9p_tag_t tag; + lib9p_super_magic_t type; + uint32_t bsize; + uint64_t blocks; + uint64_t bfree; + uint64_t bavail; + uint64_t files; + uint64_t ffree; + uint64_t fsid; + uint32_t namelen; +}; + +/* size = 15 ; max_iov = 1 ; max_copy = 15 */ +struct lib9p_msg_Tlopen { + lib9p_tag_t tag; + lib9p_fid_t fid; + lib9p_lo_t flags; +}; + +/* min_size = 25 ; exp_size = 52 ; max_size = 65,560 ; max_iov = 3 ; max_copy = 25 */ +struct lib9p_msg_Tlcreate { + lib9p_tag_t tag; + lib9p_fid_t fid; + struct lib9p_s name; + lib9p_lo_t flags; + lib9p_mode_t mode; + lib9p_nuid_t gid; +}; + +/* min_size = 29 ; exp_size = 56 ; max_size = 65,564 ; max_iov = 3 ; max_copy = 29 */ +struct lib9p_msg_Tmknod { + lib9p_tag_t tag; + lib9p_fid_t dfid; + struct lib9p_s name; + lib9p_mode_t mode; + uint32_t major; + uint32_t minor; + lib9p_nuid_t gid; +}; + +/* min_size = 21 ; exp_size = 48 ; max_size = 65,556 ; max_iov = 3 ; max_copy = 21 */ +struct lib9p_msg_Tmkdir { + lib9p_tag_t tag; + lib9p_fid_t dfid; + struct lib9p_s name; + lib9p_mode_t mode; + lib9p_nuid_t gid; +}; + +/* size = 15 ; max_iov = 1 ; max_copy = 15 */ +struct lib9p_msg_Tfsync { + lib9p_tag_t tag; + lib9p_fid_t fid; + lib9p_b4_t datasync; +}; + /* size = 19 ; max_iov = 1 ; max_copy = 19 */ struct lib9p_msg_Tgetattr { lib9p_tag_t tag; @@ -891,7 +988,7 @@ struct lib9p_msg_Tsetattr { lib9p_tag_t tag; lib9p_fid_t fid; lib9p_setattr_t valid; - uint32_t mode; + lib9p_mode_t mode; lib9p_nuid_t uid; lib9p_nuid_t gid; uint64_t filesize; @@ -901,6 +998,27 @@ struct lib9p_msg_Tsetattr { uint64_t mtime_nsec; }; +/* min_size = 34 ; exp_size = 61 ; max_size = 65,569 ; max_iov = 2 ; max_copy = 34 */ +struct lib9p_msg_Tgetlock { + lib9p_tag_t tag; + lib9p_fid_t fid; + lib9p_lock_type_t type; + uint64_t start; + uint64_t length; + uint32_t proc_id; + struct lib9p_s client_id; +}; + +/* min_size = 30 ; exp_size = 57 ; max_size = 65,565 ; max_iov = 2 ; max_copy = 30 */ +struct lib9p_msg_Rgetlock { + lib9p_tag_t tag; + lib9p_lock_type_t type; + uint64_t start; + uint64_t length; + uint32_t proc_id; + struct lib9p_s client_id; +}; + /* min_size = 38 ; exp_size = 65 ; max_size = 65,573 ; max_iov = 2 ; max_copy = 38 */ struct lib9p_msg_Tlock { lib9p_tag_t tag; @@ -1023,9 +1141,9 @@ struct lib9p_msg_Rmknod { /* size = 160 ; max_iov = 1 ; max_copy = 160 */ struct lib9p_msg_Rgetattr { lib9p_tag_t tag; - uint64_t valid; + lib9p_getattr_t valid; struct lib9p_qid qid; - uint32_t mode; + lib9p_mode_t mode; lib9p_nuid_t uid; lib9p_nuid_t gid; uint64_t nlink; diff --git a/lib9p/include/lib9p/9p.h b/lib9p/include/lib9p/9p.h index 7724fc8..ffac453 100644 --- a/lib9p/include/lib9p/9p.h +++ b/lib9p/include/lib9p/9p.h @@ -46,7 +46,7 @@ struct lib9p_ctx { /* state */ #ifdef CONFIG_9P_ENABLE_9P2000_u - uint32_t err_num; + lib9p_errno_t err_num; #endif [[gnu::nonstring]] char err_msg[CONFIG_9P_MAX_ERR_SIZE]; }; @@ -56,9 +56,9 @@ void lib9p_ctx_clear_error(struct lib9p_ctx *ctx); bool lib9p_ctx_has_error(struct lib9p_ctx *ctx); /** Write an static error into ctx, return -1. */ -int lib9p_error(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *msg); +int lib9p_error(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *msg); /** Write a printf-style error into ctx, return -1. */ -int lib9p_errorf(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *fmt, ...); +int lib9p_errorf(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *fmt, ...) [[gnu::format(printf, 3, 4)]]; /* main T-message functions ***************************************************/ @@ -139,12 +139,11 @@ bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *bo /** Assert that a `struct lib9p_stat` object looks valid. */ static inline void lib9p_stat_assert(struct lib9p_stat stat) { - assert( ((bool)(stat.file_mode & LIB9P_DM_DIR )) == ((bool)(stat.file_qid.type & LIB9P_QT_DIR )) ); - assert( ((bool)(stat.file_mode & LIB9P_DM_APPEND )) == ((bool)(stat.file_qid.type & LIB9P_QT_APPEND )) ); - assert( ((bool)(stat.file_mode & LIB9P_DM_EXCL )) == ((bool)(stat.file_qid.type & LIB9P_QT_EXCL )) ); - assert( ((bool)(stat.file_mode & _LIB9P_DM_PLAN9_MOUNT)) == ((bool)(stat.file_qid.type & _LIB9P_QT_PLAN9_MOUNT)) ); - assert( ((bool)(stat.file_mode & LIB9P_DM_AUTH )) == ((bool)(stat.file_qid.type & LIB9P_QT_AUTH )) ); - assert( ((bool)(stat.file_mode & LIB9P_DM_TMP )) == ((bool)(stat.file_qid.type & LIB9P_QT_TMP )) ); + assert( ((bool)(stat.file_mode & LIB9P_DM_DIR )) == ((bool)(stat.file_qid.type & LIB9P_QT_DIR )) ); + assert( ((bool)(stat.file_mode & LIB9P_DM_APPEND)) == ((bool)(stat.file_qid.type & LIB9P_QT_APPEND)) ); + assert( ((bool)(stat.file_mode & LIB9P_DM_EXCL )) == ((bool)(stat.file_qid.type & LIB9P_QT_EXCL )) ); + assert( ((bool)(stat.file_mode & LIB9P_DM_AUTH )) == ((bool)(stat.file_qid.type & LIB9P_QT_AUTH )) ); + assert( ((bool)(stat.file_mode & LIB9P_DM_TMP )) == ((bool)(stat.file_qid.type & LIB9P_QT_TMP )) ); assert( (stat.file_size == 0) || !(stat.file_mode & LIB9P_DM_DIR) ); } @@ -160,7 +159,7 @@ static inline void lib9p_stat_assert(struct lib9p_stat stat) { * @return whether there was an error */ bool lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, - uint32_t *ret_net_size, ssize_t *ret_host_size); + uint32_t *ret_net_size, ssize_t *ret_host_size); /** * Unmarshal the 9P `net_bytes` into the C struct `ret_obj`. @@ -171,12 +170,10 @@ bool lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_ * @param ctx : negotiated protocol parameters * @param net_bytes : network-encoded stat structure * - * @return ret_obj : where to put the stat object itself - * @return ret_extra : where to put strings for the stat object - * @return consumed net_bytes + * @return ret : the stat object, must be at least lib9p_stat_validate()->ret_net_size bytes */ -uint32_t lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, - struct lib9p_stat *ret_obj, void *ret_extra); +void lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, + struct lib9p_stat *ret); /** * Marhsal a `struct lib9p_stat` structure into a byte-array. diff --git a/lib9p/include/lib9p/linux-errno.h.gen b/lib9p/include/lib9p/linux-errno.h.gen index 8f4e0c8..2c736a2 100755 --- a/lib9p/include/lib9p/linux-errno.h.gen +++ b/lib9p/include/lib9p/linux-errno.h.gen @@ -1,7 +1,7 @@ #!/usr/bin/env python # lib9p/linux-errno.h.gen - Generate a C header from a list of errno numbers # -# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later import sys @@ -13,7 +13,7 @@ def print_errnos() -> None: ) errnos: dict[str, tuple[int, str]] = {} for txtlist in sys.argv[1:]: - with open(txtlist, "r") as fh: + with open(txtlist, "r", encoding="utf-8") as fh: for line in fh: if line.startswith("#"): print(f"/* {line[1:].strip()} */") @@ -26,12 +26,10 @@ def print_errnos() -> None: print("#ifndef _LIB9P_LINUX_ERRNO_H_") print("#define _LIB9P_LINUX_ERRNO_H_") print() - namelen = max(len(name) for name in errnos.keys()) + namelen = max(len(name) for name in errnos) numlen = max(len(str(num)) for (num, desc) in errnos.values()) - for name in errnos: - print( - f"#define LINUX_{name.ljust(namelen)} {str(errnos[name][0]).rjust(numlen)} /* {errnos[name][1]} */" - ) + for name, [num, msg] in errnos.items(): + print(f"#define LINUX_{name:<{namelen}} {num:>{numlen}} /* {msg} */") print() print("#endif /* _LIB9P_LINUX_ERRNO_H_ */") diff --git a/lib9p/internal.h b/lib9p/internal.h index 801dc4c..92340a5 100644 --- a/lib9p/internal.h +++ b/lib9p/internal.h @@ -36,47 +36,18 @@ static_assert(CONFIG_9P_MAX_ERR_SIZE <= UINT16_MAX); static_assert(CONFIG_9P_MAX_MSG_SIZE <= CONFIG_9P_MAX_HOSTMSG_SIZE); static_assert(CONFIG_9P_MAX_HOSTMSG_SIZE <= SSIZE_MAX); -/* specialized contexts *******************************************************/ - -struct _validate_ctx { - /* input */ - struct lib9p_ctx *ctx; - uint32_t net_size; - uint8_t *net_bytes; - - /* output */ - uint32_t net_offset; - /* Increment `host_extra` to pre-allocate space that is - * "extra" beyond sizeof(). */ - size_t host_extra; -}; -typedef bool (*_validate_fn_t)(struct _validate_ctx *ctx); - -struct _unmarshal_ctx { - /* input */ - struct lib9p_ctx *ctx; - uint8_t *net_bytes; - - /* output */ - uint32_t net_offset; - /* `extra` points to the beginning of unallocated space. */ - void *extra; -}; -typedef void (*_unmarshal_fn_t)(struct _unmarshal_ctx *ctx, void *out); +/* tables / exports ***********************************************************/ -struct _marshal_ctx { - /* input */ - struct lib9p_ctx *ctx; +typedef ssize_t (*_validate_fn_t)(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes); +typedef void (*_unmarshal_fn_t)(struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out); - /* output */ +struct _marshal_ret { size_t net_iov_cnt; struct iovec *net_iov; size_t net_copied_size; uint8_t *net_copied; }; -typedef bool (*_marshal_fn_t)(struct _marshal_ctx *ctx, void *host_val); - -/* tables / exports ***********************************************************/ +typedef bool (*_marshal_fn_t)(struct lib9p_ctx *ctx, void *host_val, struct _marshal_ret *ret); struct _lib9p_recv_tentry { size_t basesize; @@ -96,9 +67,9 @@ extern const struct _lib9p_recv_tentry _lib9p_table_Rmsg_recv[LIB9P_VER_NUM][0x8 extern const struct _lib9p_send_tentry _lib9p_table_Tmsg_send[LIB9P_VER_NUM][0x80]; extern const struct _lib9p_send_tentry _lib9p_table_Rmsg_send[LIB9P_VER_NUM][0x80]; -bool _lib9p_stat_validate(struct _validate_ctx *ctx); -void _lib9p_stat_unmarshal(struct _unmarshal_ctx *ctx, struct lib9p_stat *out); -bool _lib9p_stat_marshal(struct _marshal_ctx *ctx, struct lib9p_stat *val); +ssize_t _lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size); +void _lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out); +bool _lib9p_stat_marshal(struct lib9p_ctx *ctx, struct lib9p_stat *val, struct _marshal_ret *ret); /* unmarshal utilities ********************************************************/ diff --git a/lib9p/proto.gen b/lib9p/proto.gen new file mode 100755 index 0000000..60f1347 --- /dev/null +++ b/lib9p/proto.gen @@ -0,0 +1,15 @@ +#!/usr/bin/env python +# lib9p/proto.gen - Generate C marshalers/unmarshalers for .9p files +# defining 9P protocol variants. +# +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +import os.path +import sys + +sys.path.insert(0, os.path.normpath(os.path.join(__file__, ".."))) +import protogen # pylint: disable=wrong-import-position + +if __name__ == "__main__": + protogen.main() diff --git a/lib9p/protogen/__init__.py b/lib9p/protogen/__init__.py new file mode 100644 index 0000000..c2c6173 --- /dev/null +++ b/lib9p/protogen/__init__.py @@ -0,0 +1,57 @@ +# lib9p/protogen/__init__.py - Generate C marshalers/unmarshalers for +# .9p files defining 9P protocol variants +# +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +import os.path +import sys +import typing + +import idl + +from . import c, h + +# pylint: disable=unused-variable +__all__ = ["main"] + + +def main() -> None: + if typing.TYPE_CHECKING: + + class ANSIColors: + MAGENTA = "\x1b[35m" + RED = "\x1b[31m" + RESET = "\x1b[0m" + + else: + from _colorize import ANSIColors # Present in Python 3.13+ + + if len(sys.argv) < 2: + raise ValueError("requires at least 1 .9p filename") + parser = idl.Parser() + for txtname in sys.argv[1:]: + try: + parser.parse_file(txtname) + except SyntaxError as e: + print( + f"{ANSIColors.RED}{e.filename}{ANSIColors.RESET}:{ANSIColors.MAGENTA}{e.lineno}{ANSIColors.RESET}: {e.msg}", + file=sys.stderr, + ) + assert e.text + print(f"\t{e.text}", file=sys.stderr) + text_suffix = e.text.lstrip() + text_prefix = e.text[: -len(text_suffix)] + print( + f"\t{text_prefix}{ANSIColors.RED}{'~'*len(text_suffix)}{ANSIColors.RESET}", + file=sys.stderr, + ) + sys.exit(2) + versions, typs = parser.all() + outdir = os.path.normpath(os.path.join(sys.argv[0], "..")) + with open( + os.path.join(outdir, "include/lib9p/9p.generated.h"), "w", encoding="utf-8" + ) as fh: + fh.write(h.gen_h(versions, typs)) + with open(os.path.join(outdir, "9p.generated.c"), "w", encoding="utf-8") as fh: + fh.write(c.gen_c(versions, typs)) diff --git a/lib9p/protogen/c.py b/lib9p/protogen/c.py new file mode 100644 index 0000000..5e67939 --- /dev/null +++ b/lib9p/protogen/c.py @@ -0,0 +1,200 @@ +# lib9p/protogen/c.py - Generate 9p.generated.c +# +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +import sys + +import idl + +from . import c9util, c_marshal, c_unmarshal, c_validate, cutil + +# This strives to be "general-purpose" in that it just acts on the +# *.9p inputs; but (unfortunately?) there are a few special-cases in +# this script, marked with "SPECIAL". + + +# pylint: disable=unused-variable +__all__ = ["gen_c"] + + +def gen_c(versions: set[str], typs: list[idl.UserType]) -> str: + cutil.ifdef_init() + + ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */ + +#include <stdbool.h> +#include <stddef.h> /* for size_t */ +#include <inttypes.h> /* for PRI* macros */ +#include <string.h> /* for memset() */ + +#include <libmisc/assert.h> + +#include <lib9p/9p.h> + +#include "internal.h" +""" + + # utilities ################################################################ + ret += """ +/* utilities ******************************************************************/ +""" + + id2typ: dict[int, idl.Message] = {} + for msg in [msg for msg in typs if isinstance(msg, idl.Message)]: + id2typ[msg.msgid] = msg + + def msg_table(grp: str, meth: str, tentry: str, rng: tuple[int, int, int]) -> str: + ret = f"const {tentry} {c9util.ident(f'_table_{grp}_{meth}')}[{c9util.ver_enum('NUM')}][{hex(len(range(*rng)))}] = {{\n" + for ver in ["unknown", *sorted(versions)]: + if ver != "unknown": + ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver})) + ret += f"\t[{c9util.ver_enum(ver)}] = {{\n" + for n in range(*rng): + xmsg: idl.Message | None = id2typ.get(n, None) + if xmsg: + if ver == "unknown": # SPECIAL (initialization) + if xmsg.typname not in ["Tversion", "Rversion", "Rerror"]: + xmsg = None + else: + if ver not in xmsg.in_versions: + xmsg = None + if xmsg: + ret += f"\t\t_MSG_{meth.upper()}({xmsg.typname}),\n" + ret += "\t},\n" + ret += cutil.ifdef_pop(0) + ret += "};\n" + return ret + + for v in sorted(versions): + ret += f"#if CONFIG_9P_ENABLE_{v.replace('.', '_')}\n" + ret += ( + f"\t#define _is_ver_{v.replace('.', '_')}(v) (v == {c9util.ver_enum(v)})\n" + ) + ret += "#else\n" + ret += f"\t#define _is_ver_{v.replace('.', '_')}(v) false\n" + ret += "#endif\n" + ret += "\n" + ret += "/**\n" + ret += f" * is_ver(ctx, ver) is essentially `(ctx->version == {c9util.Ident('VER_')}##ver)`, but\n" + ret += f" * compiles correctly (to `false`) even if `{c9util.Ident('VER_')}##ver` isn't defined\n" + ret += " * (because `!CONFIG_9P_ENABLE_##ver`). This is useful when `||`ing\n" + ret += " * several version checks together.\n" + ret += " */\n" + ret += "#define is_ver(ctx, ver) _is_ver_##ver((ctx)->version)\n" + + # strings ################################################################## + ret += f""" +/* strings ********************************************************************/ + +const char *const {c9util.ident('_table_ver_name')}[{c9util.ver_enum('NUM')}] = {{ +""" + for ver in ["unknown", *sorted(versions)]: + if ver in versions: + ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver})) + ret += f'\t[{c9util.ver_enum(ver)}] = "{ver}",\n' + ret += cutil.ifdef_pop(0) + ret += "};\n" + + ret += "\n" + ret += f"#define _MSG_NAME(typ) [{c9util.Ident('TYP_')}##typ] = #typ\n" + ret += msg_table("msg", "name", "char *const", (0, 0x100, 1)) + + # bitmasks ################################################################# + ret += """ +/* bitmasks *******************************************************************/ +""" + for typ in typs: + if not isinstance(typ, idl.Bitfield): + continue + ret += "\n" + ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions)) + ret += f"static const {c9util.typename(typ)} {typ.typname}_masks[{c9util.ver_enum('NUM')}] = {{\n" + verwidth = max(len(ver) for ver in versions) + for ver in sorted(versions): + ret += cutil.ifdef_push(2, c9util.ver_ifdef({ver})) + ret += ( + f"\t[{c9util.ver_enum(ver)}]{' '*(verwidth-len(ver))} = 0b" + + "".join( + ( + "1" + if bit.cat in (idl.BitCat.USED, idl.BitCat.SUBFIELD) + and ver in bit.in_versions + else "0" + ) + for bit in reversed(typ.bits) + ) + + ",\n" + ) + ret += cutil.ifdef_pop(1) + ret += "};\n" + ret += cutil.ifdef_pop(0) + + # validate_* ############################################################### + ret += c_validate.gen_c_validate(versions, typs) + + # unmarshal_* ############################################################## + ret += c_unmarshal.gen_c_unmarshal(versions, typs) + + # marshal_* ################################################################ + ret += c_marshal.gen_c_marshal(versions, typs) + + # function tables ########################################################## + ret += """ +/* function tables ************************************************************/ +""" + + ret += "\n" + ret += f"const uint32_t {c9util.ident('_table_msg_min_size')}[{c9util.ver_enum('NUM')}] = {{\n" + rerror = next(typ for typ in typs if typ.typname == "Rerror") + ret += f"\t[{c9util.ver_enum('unknown')}] = {rerror.min_size('9P2000')},\n" # SPECIAL (initialization) + for ver in sorted(versions): + ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver})) + ret += f"\t[{c9util.ver_enum(ver)}] = {rerror.min_size(ver)},\n" + ret += cutil.ifdef_pop(0) + ret += "};\n" + + ret += "\n" + ret += cutil.macro( + f"#define _MSG_RECV(typ) [{c9util.Ident('TYP_')}##typ/2] = {{\n" + f"\t\t.basesize = sizeof(struct {c9util.ident('msg_')}##typ),\n" + f"\t\t.validate = validate_##typ,\n" + f"\t\t.unmarshal = (_unmarshal_fn_t)unmarshal_##typ,\n" + f"\t}}\n" + ) + ret += cutil.macro( + f"#define _MSG_SEND(typ) [{c9util.Ident('TYP_')}##typ/2] = {{\n" + f"\t\t.marshal = (_marshal_fn_t)marshal_##typ,\n" + f"\t}}\n" + ) + ret += "\n" + ret += msg_table( + "Tmsg", "recv", f"struct {c9util.ident('_recv_tentry')}", (0, 0x100, 2) + ) + ret += "\n" + ret += msg_table( + "Rmsg", "recv", f"struct {c9util.ident('_recv_tentry')}", (1, 0x100, 2) + ) + ret += "\n" + ret += msg_table( + "Tmsg", "send", f"struct {c9util.ident('_send_tentry')}", (0, 0x100, 2) + ) + ret += "\n" + ret += msg_table( + "Rmsg", "send", f"struct {c9util.ident('_send_tentry')}", (1, 0x100, 2) + ) + + ret += f""" +LM_FLATTEN ssize_t {c9util.ident('_stat_validate')}(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) {{ +\treturn validate_stat(ctx, net_size, net_bytes, ret_net_size); +}} +LM_FLATTEN void {c9util.ident('_stat_unmarshal')}(struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out) {{ +\tunmarshal_stat(ctx, net_bytes, out); +}} +LM_FLATTEN bool {c9util.ident('_stat_marshal')}(struct lib9p_ctx *ctx, struct {c9util.ident('stat')} *val, struct _marshal_ret *ret) {{ +\treturn marshal_stat(ctx, val, ret); +}} +""" + + ############################################################################ + return ret diff --git a/lib9p/protogen/c9util.py b/lib9p/protogen/c9util.py new file mode 100644 index 0000000..e7ad999 --- /dev/null +++ b/lib9p/protogen/c9util.py @@ -0,0 +1,109 @@ +# lib9p/protogen/c9util.py - Utilities for generating lib9p-specific C +# +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +import typing + +import idl + +# This strives to be "general-purpose" in that it just acts on the +# *.9p inputs; but (unfortunately?) there are a few special-cases in +# this script, marked with "SPECIAL". + +# pylint: disable=unused-variable +__all__ = [ + "add_prefix", + "ident", + "Ident", + "IDENT", + "ver_enum", + "ver_ifdef", + "ver_cond", + "typename", + "idl_expr", +] + +# idents ####################################################################### + + +def add_prefix(p: str, s: str) -> str: + if s.startswith("_"): + return "_" + p + s[1:] + return p + s + + +def _ident(p: str, s: str) -> str: + return add_prefix(p, s.replace(".", "_")) + + +def ident(s: str) -> str: + return _ident("lib9p_", s) + + +def Ident(s: str) -> str: + return _ident("lib9p_".upper(), s) + + +def IDENT(s: str) -> str: + return _ident("lib9p_", s).upper() + + +# versions ##################################################################### + + +def ver_enum(ver: str) -> str: + return Ident("VER_" + ver) + + +def ver_ifdef(versions: typing.Collection[str]) -> str: + return " || ".join( + f"CONFIG_9P_ENABLE_{v.replace('.', '_')}" for v in sorted(versions) + ) + + +def ver_cond(versions: typing.Collection[str]) -> str: + if len(versions) == 1: + v = next(v for v in versions) + return f"is_ver(ctx, {v.replace('.', '_')})" + return "( " + (" || ".join(ver_cond({v}) for v in sorted(versions))) + " )" + + +# misc ######################################################################### + + +def typename(typ: idl.Type, parent: idl.StructMember | None = None) -> str: + match typ: + case idl.Primitive(): + if typ.value == 1 and parent and parent.cnt: # SPECIAL (string) + return "[[gnu::nonstring]] char" + return f"uint{typ.value*8}_t" + case idl.Number(): + return ident(f"{typ.typname}_t") + case idl.Bitfield(): + return ident(f"{typ.typname}_t") + case idl.Message(): + return f"struct {ident(f'msg_{typ.typname}')}" + case idl.Struct(): + return f"struct {ident(typ.typname)}" + case _: + raise ValueError(f"not a type: {typ.__class__.__name__}") + + +def idl_expr(expr: idl.Expr, lookup_sym: typing.Callable[[str], str]) -> str: + ret: list[str] = [] + for tok in expr.tokens: + match tok: + case idl.ExprOp(): + ret.append(tok.op) + case idl.ExprLit(): + ret.append(str(tok.val)) + case idl.ExprSym(symname="s32_max"): + ret.append("INT32_MAX") + case idl.ExprSym(symname="s64_max"): + ret.append("INT64_MAX") + case idl.ExprSym(): + ret.append(lookup_sym(tok.symname)) + case _: + assert False + return " ".join(ret) diff --git a/lib9p/protogen/c_marshal.py b/lib9p/protogen/c_marshal.py new file mode 100644 index 0000000..74b64f5 --- /dev/null +++ b/lib9p/protogen/c_marshal.py @@ -0,0 +1,386 @@ +# lib9p/protogen/c_marshal.py - Generate C marshal functions +# +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +import typing + +import idl + +from . import c9util, cutil, idlutil + +# This strives to be "general-purpose" in that it just acts on the +# *.9p inputs; but (unfortunately?) there are a few special-cases in +# this script, marked with "SPECIAL". + + +# pylint: disable=unused-variable +__all__ = ["gen_c_marshal"] + +# get_offset_expr() ############################################################ + + +class OffsetExpr: + static: int + cond: dict[frozenset[str], "OffsetExpr"] + rep: list[tuple[idlutil.Path, "OffsetExpr"]] + + def __init__(self) -> None: + self.static = 0 + self.rep = [] + self.cond = {} + + def add(self, other: "OffsetExpr") -> None: + self.static += other.static + self.rep += other.rep + for k, v in other.cond.items(): + if k in self.cond: + self.cond[k].add(v) + else: + self.cond[k] = v + + def gen_c( + self, + dsttyp: str, + dstvar: str, + root: str, + indent_depth: int, + loop_depth: int, + ) -> str: + oneline: list[str] = [] + multiline = "" + if self.static: + oneline.append(str(self.static)) + for cnt, sub in self.rep: + if not sub.cond and not sub.rep: + if sub.static == 1: + oneline.append(cnt.c_str(root)) + else: + oneline.append(f"({cnt.c_str(root)})*{sub.static}") + continue + loopvar = chr(ord("i") + loop_depth) + multiline += f"{'\t'*indent_depth}for ({c9util.typename(cnt.elems[-1].typ)} {loopvar} = 0; {loopvar} < {cnt.c_str(root)}; {loopvar}++) {{\n" + multiline += sub.gen_c("", dstvar, root, indent_depth + 1, loop_depth + 1) + multiline += f"{'\t'*indent_depth}}}\n" + for vers, sub in self.cond.items(): + multiline += cutil.ifdef_push(indent_depth + 1, c9util.ver_ifdef(vers)) + multiline += f"{'\t'*indent_depth}if {c9util.ver_cond(vers)} {{\n" + multiline += sub.gen_c("", dstvar, root, indent_depth + 1, loop_depth) + multiline += f"{'\t'*indent_depth}}}\n" + multiline += cutil.ifdef_pop(indent_depth) + ret = "" + if dsttyp: + if not oneline: + oneline.append("0") + ret += f"{'\t'*indent_depth}{dsttyp} {dstvar} = {' + '.join(oneline)};\n" + elif oneline: + ret += f"{'\t'*indent_depth}{dstvar} += {' + '.join(oneline)};\n" + ret += multiline + return ret + + +type OffsetExprRecursion = typing.Callable[[idlutil.Path], idlutil.WalkCmd] + + +def get_offset_expr(typ: idl.UserType, recurse: OffsetExprRecursion) -> OffsetExpr: + if not isinstance(typ, idl.Struct): + assert typ.static_size + ret = OffsetExpr() + ret.static = typ.static_size + return ret + + class ExprStackItem(typing.NamedTuple): + path: idlutil.Path + expr: OffsetExpr + pop: typing.Callable[[], None] + + expr_stack: list[ExprStackItem] + + def pop_root() -> None: + assert False + + def pop_cond() -> None: + nonlocal expr_stack + key = frozenset(expr_stack[-1].path.elems[-1].in_versions) + if key in expr_stack[-2].expr.cond: + expr_stack[-2].expr.cond[key].add(expr_stack[-1].expr) + else: + expr_stack[-2].expr.cond[key] = expr_stack[-1].expr + expr_stack = expr_stack[:-1] + + def pop_rep() -> None: + nonlocal expr_stack + member_path = expr_stack[-1].path + member = member_path.elems[-1] + assert member.cnt + cnt_path = member_path.parent().add(member.cnt) + expr_stack[-2].expr.rep.append((cnt_path, expr_stack[-1].expr)) + expr_stack = expr_stack[:-1] + + def handle( + path: idlutil.Path, + ) -> tuple[idlutil.WalkCmd, typing.Callable[[], None] | None]: + nonlocal recurse + + ret = recurse(path) + if ret != idlutil.WalkCmd.KEEP_GOING: + return ret, None + + nonlocal expr_stack + expr_stack_len = len(expr_stack) + + def pop() -> None: + nonlocal expr_stack + nonlocal expr_stack_len + while len(expr_stack) > expr_stack_len: + expr_stack[-1].pop() + + if path.elems: + child = path.elems[-1] + parent = path.elems[-2].typ if len(path.elems) > 1 else path.root + if child.in_versions < parent.in_versions: + expr_stack.append( + ExprStackItem(path=path, expr=OffsetExpr(), pop=pop_cond) + ) + if child.cnt: + expr_stack.append( + ExprStackItem(path=path, expr=OffsetExpr(), pop=pop_rep) + ) + if not isinstance(child.typ, idl.Struct): + assert child.typ.static_size + expr_stack[-1].expr.static += child.typ.static_size + return ret, pop + + expr_stack = [ + ExprStackItem(path=idlutil.Path(typ), expr=OffsetExpr(), pop=pop_root) + ] + idlutil.walk(typ, handle) + return expr_stack[0].expr + + +def go_to_end(path: idlutil.Path) -> idlutil.WalkCmd: + return idlutil.WalkCmd.KEEP_GOING + + +def go_to_tok(name: str) -> typing.Callable[[idlutil.Path], idlutil.WalkCmd]: + def ret(path: idlutil.Path) -> idlutil.WalkCmd: + if len(path.elems) == 1 and path.elems[0].membname == name: + return idlutil.WalkCmd.ABORT + return idlutil.WalkCmd.KEEP_GOING + + return ret + + +# Generate .c ################################################################## + + +def gen_c_marshal(versions: set[str], typs: list[idl.UserType]) -> str: + ret = """ +/* marshal_* ******************************************************************/ + +""" + ret += cutil.macro( + "#define MARSHAL_BYTES_ZEROCOPY(ctx, data, len)\n" + "\tif (ret->net_iov[ret->net_iov_cnt-1].iov_len)\n" + "\t\tret->net_iov_cnt++;\n" + "\tret->net_iov[ret->net_iov_cnt-1].iov_base = data;\n" + "\tret->net_iov[ret->net_iov_cnt-1].iov_len = len;\n" + "\tret->net_iov_cnt++;\n" + ) + ret += cutil.macro( + "#define MARSHAL_BYTES(ctx, data, len)\n" + "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n" + "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n" + "\tmemcpy(&ret->net_copied[ret->net_copied_size], data, len);\n" + "\tret->net_copied_size += len;\n" + "\tret->net_iov[ret->net_iov_cnt-1].iov_len += len;\n" + ) + ret += cutil.macro( + "#define MARSHAL_U8LE(ctx, val)\n" + "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n" + "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n" + "\tret->net_copied[ret->net_copied_size] = val;\n" + "\tret->net_copied_size += 1;\n" + "\tret->net_iov[ret->net_iov_cnt-1].iov_len += 1;\n" + ) + ret += cutil.macro( + "#define MARSHAL_U16LE(ctx, val)\n" + "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n" + "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n" + "\tuint16le_encode(&ret->net_copied[ret->net_copied_size], val);\n" + "\tret->net_copied_size += 2;\n" + "\tret->net_iov[ret->net_iov_cnt-1].iov_len += 2;\n" + ) + ret += cutil.macro( + "#define MARSHAL_U32LE(ctx, val)\n" + "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n" + "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n" + "\tuint32le_encode(&ret->net_copied[ret->net_copied_size], val);\n" + "\tret->net_copied_size += 4;\n" + "\tret->net_iov[ret->net_iov_cnt-1].iov_len += 4;\n" + ) + ret += cutil.macro( + "#define MARSHAL_U64LE(ctx, val)\n" + "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n" + "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n" + "\tuint64le_encode(&ret->net_copied[ret->net_copied_size], val);\n" + "\tret->net_copied_size += 8;\n" + "\tret->net_iov[ret->net_iov_cnt-1].iov_len += 8;\n" + ) + + class IndentLevel(typing.NamedTuple): + ifdef: bool # whether this is both `{` and `#if`, or just `{` + + indent_stack: list[IndentLevel] + + def ifdef_lvl() -> int: + return sum(1 if lvl.ifdef else 0 for lvl in indent_stack) + + def indent_lvl() -> int: + return len(indent_stack) + + max_size: int + + def handle( + path: idlutil.Path, + ) -> tuple[idlutil.WalkCmd, typing.Callable[[], None]]: + nonlocal ret + nonlocal indent_stack + nonlocal max_size + indent_stack_len = len(indent_stack) + + def pop() -> None: + nonlocal ret + nonlocal indent_stack + nonlocal indent_stack_len + while len(indent_stack) > indent_stack_len: + if len(indent_stack) == indent_stack_len + 1 and indent_stack[-1].ifdef: + break + ret += f"{'\t'*(indent_lvl()-1)}}}\n" + if indent_stack.pop().ifdef: + ret += cutil.ifdef_pop(ifdef_lvl()) + + loopdepth = sum(1 for elem in path.elems if elem.cnt) + struct = path.elems[-1].typ if path.elems else path.root + if isinstance(struct, idl.Struct): + offsets: list[str] = [] + for member in struct.members: + if not member.val: + continue + for tok in member.val.tokens: + if not isinstance(tok, idl.ExprSym): + continue + if tok.symname == "end" or tok.symname.startswith("&"): + if tok.symname not in offsets: + offsets.append(tok.symname) + for name in offsets: + name_prefix = f"offsetof{''.join('_'+m.membname for m in path.elems)}_" + if name == "end": + if not path.elems: + if max_size > cutil.UINT32_MAX: + ret += f"{'\t'*indent_lvl()}uint32_t {name_prefix}end = (uint32_t)needed_size;\n" + else: + ret += f"{'\t'*indent_lvl()}uint32_t {name_prefix}end = needed_size;\n" + continue + recurse: OffsetExprRecursion = go_to_end + else: + assert name.startswith("&") + name = name[1:] + recurse = go_to_tok(name) + expr = get_offset_expr(struct, recurse) + expr_prefix = path.c_str("val->", loopdepth) + if not expr_prefix.endswith(">"): + expr_prefix += "." + ret += expr.gen_c( + "uint32_t", + name_prefix + name, + expr_prefix, + indent_lvl(), + loopdepth, + ) + if not path.elems: + return idlutil.WalkCmd.KEEP_GOING, pop + + child = path.elems[-1] + parent = path.elems[-2].typ if len(path.elems) > 1 else path.root + if child.in_versions < parent.in_versions: + if line := cutil.ifdef_push( + ifdef_lvl() + 1, c9util.ver_ifdef(child.in_versions) + ): + ret += line + ret += ( + f"{'\t'*indent_lvl()}if ({c9util.ver_cond(child.in_versions)}) {{\n" + ) + indent_stack.append(IndentLevel(ifdef=True)) + if child.cnt: + cnt_path = path.parent().add(child.cnt) + if child.typ.static_size == 1: # SPECIAL (zerocopy) + if path.root.typname == "stat": # SPECIAL (stat) + ret += f"{'\t'*indent_lvl()}MARSHAL_BYTES(ctx, {path.c_str('val->')[:-3]}, {cnt_path.c_str('val->')});\n" + else: + ret += f"{'\t'*indent_lvl()}MARSHAL_BYTES_ZEROCOPY(ctx, {path.c_str('val->')[:-3]}, {cnt_path.c_str('val->')});\n" + return idlutil.WalkCmd.KEEP_GOING, pop + loopvar = chr(ord("i") + loopdepth - 1) + ret += f"{'\t'*indent_lvl()}for ({c9util.typename(child.cnt.typ)} {loopvar} = 0; {loopvar} < {cnt_path.c_str('val->')}; {loopvar}++) {{\n" + indent_stack.append(IndentLevel(ifdef=False)) + if not isinstance(child.typ, idl.Struct): + if child.val: + + def lookup_sym(sym: str) -> str: + nonlocal path + if sym.startswith("&"): + sym = sym[1:] + return f"offsetof{''.join('_'+m.membname for m in path.elems[:-1])}_{sym}" + + val = c9util.idl_expr(child.val, lookup_sym) + else: + val = path.c_str("val->") + if isinstance(child.typ, idl.Bitfield): + val += f" & {child.typ.typname}_masks[ctx->version]" + ret += f"{'\t'*indent_lvl()}MARSHAL_U{child.typ.static_size*8}LE(ctx, {val});\n" + return idlutil.WalkCmd.KEEP_GOING, pop + + for typ in typs: + if not ( + isinstance(typ, idl.Message) or typ.typname == "stat" + ): # SPECIAL (include stat) + continue + assert isinstance(typ, idl.Struct) + ret += "\n" + ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions)) + ret += f"static bool marshal_{typ.typname}(struct lib9p_ctx *ctx, {c9util.typename(typ)} *val, struct _marshal_ret *ret) {{\n" + + # Pass 1 - check size + max_size = max(typ.max_size(v) for v in typ.in_versions) + + if max_size > cutil.UINT32_MAX: # SPECIAL (9P2000.e) + ret += get_offset_expr(typ, go_to_end).gen_c( + "uint64_t", "needed_size", "val->", 1, 0 + ) + ret += "\tif (needed_size > (uint64_t)(ctx->max_msg_size)) {\n" + else: + ret += get_offset_expr(typ, go_to_end).gen_c( + "uint32_t", "needed_size", "val->", 1, 0 + ) + ret += "\tif (needed_size > ctx->max_msg_size) {\n" + if isinstance(typ, idl.Message): # SPECIAL (disable for stat) + ret += '\t\tlib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",\n' + ret += f'\t\t\t"{typ.typname}",\n' + ret += f'\t\t\tctx->version ? "negotiated" : "{'client' if typ.msgid % 2 == 0 else 'server'}",\n' + ret += "\t\t\tctx->max_msg_size);\n" + ret += "\t\treturn true;\n" + ret += "\t}\n" + + # Pass 2 - write data + indent_stack = [IndentLevel(ifdef=True)] + idlutil.walk(typ, handle) + while len(indent_stack) > 1: + ret += f"{'\t'*(indent_lvl()-1)}}}\n" + if indent_stack.pop().ifdef: + ret += cutil.ifdef_pop(ifdef_lvl()) + + # Return + ret += "\treturn false;\n" + ret += "}\n" + ret += cutil.ifdef_pop(0) + return ret diff --git a/lib9p/protogen/c_unmarshal.py b/lib9p/protogen/c_unmarshal.py new file mode 100644 index 0000000..018d750 --- /dev/null +++ b/lib9p/protogen/c_unmarshal.py @@ -0,0 +1,133 @@ +# lib9p/protogen/c_unmarshal.py - Generate C unmarshal functions +# +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +import typing + +import idl + +from . import c9util, cutil, idlutil + +# This strives to be "general-purpose" in that it just acts on the +# *.9p inputs; but (unfortunately?) there are a few special-cases in +# this script, marked with "SPECIAL". + + +# pylint: disable=unused-variable +__all__ = ["gen_c_unmarshal"] + + +def gen_c_unmarshal(versions: set[str], typs: list[idl.UserType]) -> str: + ret = """ +/* unmarshal_* ****************************************************************/ + +""" + ret += cutil.macro( + "#define UNMARSHAL_BYTES(ctx, data_lvalue, len)\n" + "\tdata_lvalue = (char *)&net_bytes[net_offset];\n" + "\tnet_offset += len;\n" + ) + ret += cutil.macro( + "#define UNMARSHAL_U8LE(ctx, val_lvalue)\n" + "\tval_lvalue = net_bytes[net_offset];\n" + "\tnet_offset += 1;\n" + ) + ret += cutil.macro( + "#define UNMARSHAL_U16LE(ctx, val_lvalue)\n" + "\tval_lvalue = uint16le_decode(&net_bytes[net_offset]);\n" + "\tnet_offset += 2;\n" + ) + ret += cutil.macro( + "#define UNMARSHAL_U32LE(ctx, val_lvalue)\n" + "\tval_lvalue = uint32le_decode(&net_bytes[net_offset]);\n" + "\tnet_offset += 4;\n" + ) + ret += cutil.macro( + "#define UNMARSHAL_U64LE(ctx, val_lvalue)\n" + "\tval_lvalue = uint64le_decode(&net_bytes[net_offset]);\n" + "\tnet_offset += 8;\n" + ) + + class IndentLevel(typing.NamedTuple): + ifdef: bool # whether this is both `{` and `#if`, or just `{` + + indent_stack: list[IndentLevel] + + def ifdef_lvl() -> int: + return sum(1 if lvl.ifdef else 0 for lvl in indent_stack) + + def indent_lvl() -> int: + return len(indent_stack) + + def handle( + path: idlutil.Path, + ) -> tuple[idlutil.WalkCmd, typing.Callable[[], None]]: + nonlocal ret + nonlocal indent_stack + indent_stack_len = len(indent_stack) + + def pop() -> None: + nonlocal ret + nonlocal indent_stack + nonlocal indent_stack_len + while len(indent_stack) > indent_stack_len: + if len(indent_stack) == indent_stack_len + 1 and indent_stack[-1].ifdef: + break + ret += f"{'\t'*(indent_lvl()-1)}}}\n" + if indent_stack.pop().ifdef: + ret += cutil.ifdef_pop(ifdef_lvl()) + + if not path.elems: + return idlutil.WalkCmd.KEEP_GOING, pop + + child = path.elems[-1] + parent = path.elems[-2].typ if len(path.elems) > 1 else path.root + if child.in_versions < parent.in_versions: + if line := cutil.ifdef_push( + ifdef_lvl() + 1, c9util.ver_ifdef(child.in_versions) + ): + ret += line + ret += ( + f"{'\t'*indent_lvl()}if ({c9util.ver_cond(child.in_versions)}) {{\n" + ) + indent_stack.append(IndentLevel(ifdef=True)) + if child.cnt: + cnt_path = path.parent().add(child.cnt) + if child.typ.static_size == 1: # SPECIAL (zerocopy) + ret += f"{'\t'*indent_lvl()}UNMARSHAL_BYTES(ctx, {path.c_str('out->')[:-3]}, {cnt_path.c_str('out->')});\n" + return idlutil.WalkCmd.KEEP_GOING, pop + ret += f"{'\t'*indent_lvl()}{path.c_str('out->')[:-3]} = extra;\n" + ret += f"{'\t'*indent_lvl()}extra += sizeof({path.c_str('out->')[:-3]}[0]) * {cnt_path.c_str('out->')};\n" + loopdepth = sum(1 for elem in path.elems if elem.cnt) + loopvar = chr(ord("i") + loopdepth - 1) + ret += f"{'\t'*indent_lvl()}for ({c9util.typename(child.cnt.typ)} {loopvar} = 0; {loopvar} < {cnt_path.c_str('out->')}; {loopvar}++) {{\n" + indent_stack.append(IndentLevel(ifdef=False)) + if not isinstance(child.typ, idl.Struct): + if child.val: + ret += f"{'\t'*indent_lvl()}net_offset += {child.typ.static_size};\n" + else: + ret += f"{'\t'*indent_lvl()}UNMARSHAL_U{child.typ.static_size*8}LE(ctx, {path.c_str('out->')});\n" + return idlutil.WalkCmd.KEEP_GOING, pop + + for typ in typs: + if not ( + isinstance(typ, idl.Message) or typ.typname == "stat" + ): # SPECIAL (include stat) + continue + assert isinstance(typ, idl.Struct) + ret += "\n" + ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions)) + ret += f"static void unmarshal_{typ.typname}([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {{\n" + ret += f"\t{c9util.typename(typ)} *out = out_buf;\n" + ret += "\t[[gnu::unused]] void *extra = &out[1];\n" + ret += "\tuint32_t net_offset = 0;\n" + + indent_stack = [IndentLevel(ifdef=True)] + idlutil.walk(typ, handle) + while len(indent_stack) > 0: + ret += f"{'\t'*(indent_lvl()-1)}}}\n" + if indent_stack.pop().ifdef and indent_stack: + ret += cutil.ifdef_pop(ifdef_lvl()) + ret += cutil.ifdef_pop(0) + return ret diff --git a/lib9p/protogen/c_validate.py b/lib9p/protogen/c_validate.py new file mode 100644 index 0000000..e315b60 --- /dev/null +++ b/lib9p/protogen/c_validate.py @@ -0,0 +1,287 @@ +# lib9p/protogen/c_validate.py - Generate C validation functions +# +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +import typing + +import idl + +from . import c9util, cutil, idlutil + +# This strives to be "general-purpose" in that it just acts on the +# *.9p inputs; but (unfortunately?) there are a few special-cases in +# this script, marked with "SPECIAL". + + +# pylint: disable=unused-variable +__all__ = ["gen_c_validate"] + + +def should_save_offset(parent: idl.Struct, child: idl.StructMember) -> bool: + if child.val or child.max or isinstance(child.typ, idl.Bitfield): + return True + for sibling in parent.members: + if sibling.val: + for tok in sibling.val.tokens: + if isinstance(tok, idl.ExprSym) and tok.symname == f"&{child.membname}": + return True + if sibling.max: + for tok in sibling.max.tokens: + if isinstance(tok, idl.ExprSym) and tok.symname == f"&{child.membname}": + return True + return False + + +def should_save_end_offset(struct: idl.Struct) -> bool: + for memb in struct.members: + if memb.val: + for tok in memb.val.tokens: + if isinstance(tok, idl.ExprSym) and tok.symname == "end": + return True + if memb.max: + for tok in memb.max.tokens: + if isinstance(tok, idl.ExprSym) and tok.symname == "end": + return True + return False + + +def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str: + ret = """ +/* validate_* *****************************************************************/ + +""" + ret += cutil.macro( + "#define VALIDATE_NET_BYTES(n)\n" + "\tif (__builtin_add_overflow(net_offset, n, &net_offset))\n" + "\t\t/* If needed-net-size overflowed uint32_t, then\n" + "\t\t * there's no way that actual-net-size will live up to\n" + "\t\t * that. */\n" + '\t\treturn lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content");\n' + "\tif (net_offset > net_size)\n" + '\t\treturn lib9p_errorf(ctx, LINUX_EBADMSG, "message is too short for content (%"PRIu32" > %"PRIu32") @ %d", net_offset, net_size, __LINE__);\n' + ) + ret += cutil.macro( + "#define VALIDATE_NET_UTF8(n)\n" + "\t{\n" + "\t\tsize_t len = n;\n" + "\t\tVALIDATE_NET_BYTES(len);\n" + "\t\tif (!is_valid_utf8_without_nul(&net_bytes[net_offset-len], len))\n" + '\t\t\treturn lib9p_error(ctx, LINUX_EBADMSG, "message contains invalid UTF-8");\n' + "\t}\n" + ) + ret += cutil.macro( + "#define RESERVE_HOST_BYTES(n)\n" + "\tif (__builtin_add_overflow(host_size, n, &host_size))\n" + "\t\t/* If needed-host-size overflowed ssize_t, then there's\n" + "\t\t * no way that actual-net-size will live up to\n" + "\t\t * that. */\n" + '\t\treturn lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content");\n' + ) + + ret += "#define GET_U8LE(off) (net_bytes[off])\n" + ret += "#define GET_U16LE(off) uint16le_decode(&net_bytes[off])\n" + ret += "#define GET_U32LE(off) uint32le_decode(&net_bytes[off])\n" + ret += "#define GET_U64LE(off) uint64le_decode(&net_bytes[off])\n" + + ret += "#define LAST_U8LE() GET_U8LE(net_offset-1)\n" + ret += "#define LAST_U16LE() GET_U16LE(net_offset-2)\n" + ret += "#define LAST_U32LE() GET_U32LE(net_offset-4)\n" + ret += "#define LAST_U64LE() GET_U64LE(net_offset-8)\n" + + class IndentLevel(typing.NamedTuple): + ifdef: bool # whether this is both `{` and `#if`, or just `{` + + indent_stack: list[IndentLevel] + + def ifdef_lvl() -> int: + return sum(1 if lvl.ifdef else 0 for lvl in indent_stack) + + def indent_lvl() -> int: + return len(indent_stack) + + incr_buf: int + + def incr_flush() -> None: + nonlocal ret + nonlocal incr_buf + if incr_buf: + ret += f"{'\t'*indent_lvl()}VALIDATE_NET_BYTES({incr_buf});\n" + incr_buf = 0 + + def gen_validate_size(path: idlutil.Path) -> None: + nonlocal ret + nonlocal incr_buf + nonlocal indent_stack + + assert path.elems + child = path.elems[-1] + parent = path.elems[-2].typ if len(path.elems) > 1 else path.root + assert isinstance(parent, idl.Struct) + + if child.in_versions < parent.in_versions: + if line := cutil.ifdef_push( + ifdef_lvl() + 1, c9util.ver_ifdef(child.in_versions) + ): + incr_flush() + ret += line + ret += ( + f"{'\t'*indent_lvl()}if ({c9util.ver_cond(child.in_versions)}) {{\n" + ) + indent_stack.append(IndentLevel(ifdef=True)) + if should_save_offset(parent, child): + ret += f"{'\t'*indent_lvl()}uint32_t offsetof{''.join('_'+m.membname for m in path.elems)} = net_offset + {incr_buf};\n" + if child.cnt: + assert child.cnt.typ.static_size + cnt_path = path.parent().add(child.cnt) + incr_flush() + if child.membname == "utf8": # SPECIAL (string) + # Yes, this is content-validation and "belongs" in + # gen_validate_content(), not here. But it's just + # easier this way. + ret += f"{'\t'*indent_lvl()}VALIDATE_NET_UTF8(LAST_U{child.cnt.typ.static_size*8}LE());\n" + return + if child.typ.static_size == 1: # SPECIAL (zerocopy) + ret += f"{'\t'*indent_lvl()}VALIDATE_NET_BYTES(LAST_U{child.cnt.typ.static_size*8}LE());\n" + return + loopdepth = sum(1 for elem in path.elems if elem.cnt) + loopvar = chr(ord("i") + loopdepth - 1) + ret += f"{'\t'*indent_lvl()}for ({c9util.typename(child.cnt.typ)} {loopvar} = 0, cnt = LAST_U{child.cnt.typ.static_size*8}LE(); {loopvar} < cnt; {loopvar}++) {{\n" + indent_stack.append(IndentLevel(ifdef=False)) + ret += f"{'\t'*indent_lvl()}RESERVE_HOST_BYTES(sizeof({c9util.typename(child.typ)}));\n" + if not isinstance(child.typ, idl.Struct): + incr_buf += child.typ.static_size + + def gen_validate_content(path: idlutil.Path) -> None: + nonlocal ret + nonlocal incr_buf + nonlocal indent_stack + + assert path.elems + child = path.elems[-1] + parent = path.elems[-2].typ if len(path.elems) > 1 else path.root + assert isinstance(parent, idl.Struct) + + def lookup_sym(sym: str) -> str: + if sym.startswith("&"): + sym = sym[1:] + return f"offsetof{''.join('_'+m.membname for m in path.elems[:-1])}_{sym}" + + if child.val: + incr_flush() + assert child.typ.static_size + nbits = child.typ.static_size * 8 + nbits = child.typ.static_size * 8 + if nbits < 32 and any( + isinstance(tok, idl.ExprSym) + and (tok.symname == "end" or tok.symname.startswith("&")) + for tok in child.val.tokens + ): + nbits = 32 + act = f"(uint{nbits}_t)GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})" + exp = f"(uint{nbits}_t)({c9util.idl_expr(child.val, lookup_sym)})" + ret += f"{'\t'*indent_lvl()}if ({act} != {exp})\n" + ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, LINUX_EBADMSG, "{path} value is wrong: actual: %"PRIu{nbits}" != correct:%"PRIu{nbits},\n' + ret += f"{'\t'*(indent_lvl()+2)}{act}, {exp});\n" + if child.max: + incr_flush() + assert child.typ.static_size + nbits = child.typ.static_size * 8 + if nbits < 32 and any( + isinstance(tok, idl.ExprSym) + and (tok.symname == "end" or tok.symname.startswith("&")) + for tok in child.max.tokens + ): + nbits = 32 + act = f"(uint{nbits}_t)GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})" + exp = f"(uint{nbits}_t)({c9util.idl_expr(child.max, lookup_sym)})" + ret += f"{'\t'*indent_lvl()}if ({act} > {exp})\n" + ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, LINUX_EBADMSG, "{path} value is too large: %"PRIu{nbits}" > %"PRIu{nbits},\n' + ret += f"{'\t'*(indent_lvl()+2)}{act}, {exp});\n" + if isinstance(child.typ, idl.Bitfield): + incr_flush() + nbytes = child.typ.static_size + nbits = nbytes * 8 + act = f"GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})" + ret += f"{'\t'*indent_lvl()}if ({act} & ~{child.typ.typname}_masks[ctx->version])\n" + ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in {child.typ.typname} bitfield: %#0{nbytes*2}"PRIx{nbits},\n' + ret += f"{'\t'*(indent_lvl()+2)}{act} & ~{child.typ.typname}_masks[ctx->version]);\n" + + def handle( + path: idlutil.Path, + ) -> tuple[idlutil.WalkCmd, typing.Callable[[], None]]: + nonlocal ret + nonlocal incr_buf + nonlocal indent_stack + indent_stack_len = len(indent_stack) + pop_struct = path.elems[-1].typ if path.elems else path.root + pop_path = path + pop_indent_stack_len: int + + def pop() -> None: + nonlocal ret + nonlocal indent_stack + nonlocal indent_stack_len + nonlocal pop_struct + nonlocal pop_path + nonlocal pop_indent_stack_len + if isinstance(pop_struct, idl.Struct): + while len(indent_stack) > pop_indent_stack_len: + incr_flush() + ret += f"{'\t'*(indent_lvl()-1)}}}\n" + if indent_stack.pop().ifdef: + ret += cutil.ifdef_pop(ifdef_lvl()) + parent = pop_struct + path = pop_path + if should_save_end_offset(parent): + ret += f"{'\t'*indent_lvl()}uint32_t offsetof{''.join('_'+m.membname for m in path.elems)}_end = net_offset + {incr_buf};\n" + for child in parent.members: + gen_validate_content(pop_path.add(child)) + while len(indent_stack) > indent_stack_len: + if len(indent_stack) == indent_stack_len + 1 and indent_stack[-1].ifdef: + break + incr_flush() + ret += f"{'\t'*(indent_lvl()-1)}}}\n" + if indent_stack.pop().ifdef: + ret += cutil.ifdef_pop(ifdef_lvl()) + + if path.elems: + gen_validate_size(path) + + pop_indent_stack_len = len(indent_stack) + + return idlutil.WalkCmd.KEEP_GOING, pop + + for typ in typs: + if not ( + isinstance(typ, idl.Message) or typ.typname == "stat" + ): # SPECIAL (include stat) + continue + assert isinstance(typ, idl.Struct) + ret += "\n" + ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions)) + if typ.typname == "stat": # SPECIAL (stat) + ret += f"static ssize_t validate_{typ.typname}(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) {{\n" + else: + ret += f"static ssize_t validate_{typ.typname}(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {{\n" + + ret += "\tuint32_t net_offset = 0;\n" + ret += f"\tssize_t host_size = sizeof({c9util.typename(typ)});\n" + + incr_buf = 0 + indent_stack = [IndentLevel(ifdef=True)] + idlutil.walk(typ, handle) + while len(indent_stack) > 1: + incr_flush() + ret += f"{'\t'*(indent_lvl()-1)}}}\n" + if indent_stack.pop().ifdef: + ret += cutil.ifdef_pop(ifdef_lvl()) + + incr_flush() + if typ.typname == "stat": # SPECIAL (stat) + ret += "\tif (ret_net_size)\n" + ret += "\t\t*ret_net_size = net_offset;\n" + ret += "\treturn (ssize_t)host_size;\n" + ret += "}\n" + ret += cutil.ifdef_pop(0) + return ret diff --git a/lib9p/protogen/cutil.py b/lib9p/protogen/cutil.py new file mode 100644 index 0000000..8df6db9 --- /dev/null +++ b/lib9p/protogen/cutil.py @@ -0,0 +1,84 @@ +# lib9p/protogen/cutil.py - Utilities for generating C code +# +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +# pylint: disable=unused-variable +__all__ = [ + "UINT32_MAX", + "UINT64_MAX", + "macro", + "ifdef_init", + "ifdef_push", + "ifdef_pop", + "ifdef_leaf_is_noop", +] + +UINT32_MAX = (1 << 32) - 1 +UINT64_MAX = (1 << 64) - 1 + + +def tab_ljust(s: str, width: int) -> str: + cur = len(s.expandtabs(tabsize=8)) + if cur >= width: + return s + return s + " " * (width - cur) + + +def macro(full: str) -> str: + full = full.rstrip() + assert "\n" in full + lines = [l.rstrip() for l in full.split("\n")] + width = max(len(l.expandtabs(tabsize=8)) for l in lines[:-1]) + lines = [tab_ljust(l, width) for l in lines] + return " \\\n".join(lines).rstrip() + "\n" + + +_ifdef_stack: list[str | None] = [] + + +def ifdef_init() -> None: + global _ifdef_stack + _ifdef_stack = [] + + +def ifdef_push(n: int, _newval: str) -> str: + # Grow the stack as needed + while len(_ifdef_stack) < n: + _ifdef_stack.append(None) + + # Set some variables + parentval: str | None = None + for x in _ifdef_stack[:-1]: + if x is not None: + parentval = x + oldval = _ifdef_stack[-1] + newval: str | None = _newval + if newval == parentval: + newval = None + + # Put newval on the stack. + _ifdef_stack[-1] = newval + + # Build output. + ret = "" + if newval != oldval: + if oldval is not None: + ret += f"#endif /* {oldval} */\n" + if newval is not None: + ret += f"#if {newval}\n" + return ret + + +def ifdef_pop(n: int) -> str: + global _ifdef_stack + ret = "" + while len(_ifdef_stack) > n: + if _ifdef_stack[-1] is not None: + ret += f"#endif /* {_ifdef_stack[-1]} */\n" + _ifdef_stack = _ifdef_stack[:-1] + return ret + + +def ifdef_leaf_is_noop() -> bool: + return not _ifdef_stack[-1] diff --git a/lib9p/protogen/h.py b/lib9p/protogen/h.py new file mode 100644 index 0000000..7785ca1 --- /dev/null +++ b/lib9p/protogen/h.py @@ -0,0 +1,447 @@ +# lib9p/protogen/h.py - Generate 9p.generated.h +# +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +import sys +import typing + +import idl + +from . import c9util, cutil, idlutil + +# This strives to be "general-purpose" in that it just acts on the +# *.9p inputs; but (unfortunately?) there are a few special-cases in +# this script, marked with "SPECIAL". + +# pylint: disable=unused-variable +__all__ = ["gen_h"] + +# get_buffer_size() ############################################################ + + +class BufferSize(typing.NamedTuple): + min_size: int # really just here to sanity-check against typ.min_size(version) + exp_size: int # "expected" or max-reasonable size + max_size: int # really just here to sanity-check against typ.max_size(version) + max_copy: int + max_copy_extra: str + max_iov: int + max_iov_extra: str + + +class TmpBufferSize: + min_size: int + exp_size: int + max_size: int + max_copy: int + max_copy_extra: str + max_iov: int + max_iov_extra: str + + tmp_starts_with_copy: bool + tmp_ends_with_copy: bool + + def __init__(self) -> None: + self.min_size = 0 + self.exp_size = 0 + self.max_size = 0 + self.max_copy = 0 + self.max_copy_extra = "" + self.max_iov = 0 + self.max_iov_extra = "" + self.tmp_starts_with_copy = False + self.tmp_ends_with_copy = False + + +def _get_buffer_size(typ: idl.Type, version: str) -> TmpBufferSize: + assert isinstance(typ, idl.Primitive) or (version in typ.in_versions) + + ret = TmpBufferSize() + + if not isinstance(typ, idl.Struct): + assert typ.static_size + ret.min_size = typ.static_size + ret.exp_size = typ.static_size + ret.max_size = typ.static_size + ret.max_copy = typ.static_size + ret.max_iov = 1 + ret.tmp_starts_with_copy = True + ret.tmp_ends_with_copy = True + return ret + + def handle(path: idlutil.Path) -> tuple[idlutil.WalkCmd, None]: + nonlocal ret + if path.elems: + child = path.elems[-1] + if version not in child.in_versions: + return idlutil.WalkCmd.DONT_RECURSE, None + if child.cnt: + if child.typ.static_size == 1: # SPECIAL (zerocopy) + ret.max_iov += 1 + # HEURISTIC: 27 for strings (max-strlen from 9P1), 8KiB for other data + ret.exp_size += 27 if child.membname == "utf8" else 8192 + ret.max_size += child.max_cnt + ret.tmp_ends_with_copy = False + return idlutil.WalkCmd.DONT_RECURSE, None + sub = _get_buffer_size(child.typ, version) + ret.exp_size += sub.exp_size * 16 # HEURISTIC: MAXWELEM + ret.max_size += sub.max_size * child.max_cnt + if child.membname == "wname" and path.root.typname in ( + "Tsread", + "Tswrite", + ): # SPECIAL (9P2000.e) + assert ret.tmp_ends_with_copy + assert sub.tmp_starts_with_copy + assert not sub.tmp_ends_with_copy + ret.max_copy_extra = ( + f" + (CONFIG_9P_MAX_9P2000_e_WELEM * {sub.max_copy})" + ) + ret.max_iov_extra = ( + f" + (CONFIG_9P_MAX_9P2000_e_WELEM * {sub.max_iov})" + ) + ret.max_iov -= 1 + else: + ret.max_copy += sub.max_copy * child.max_cnt + if sub.max_iov == 1 and sub.tmp_starts_with_copy: # is purely copy + ret.max_iov += 1 + else: # contains zero-copy segments + ret.max_iov += sub.max_iov * child.max_cnt + if ret.tmp_ends_with_copy and sub.tmp_starts_with_copy: + # we can merge this one + ret.max_iov -= 1 + if ( + sub.tmp_ends_with_copy + and sub.tmp_starts_with_copy + and sub.max_iov > 1 + ): + # we can merge these + ret.max_iov -= child.max_cnt - 1 + ret.tmp_ends_with_copy = sub.tmp_ends_with_copy + return idlutil.WalkCmd.DONT_RECURSE, None + if not isinstance(child.typ, idl.Struct): + assert child.typ.static_size + if not ret.tmp_ends_with_copy: + if ret.max_size == 0: + ret.tmp_starts_with_copy = True + ret.max_iov += 1 + ret.tmp_ends_with_copy = True + ret.min_size += child.typ.static_size + ret.exp_size += child.typ.static_size + ret.max_size += child.typ.static_size + ret.max_copy += child.typ.static_size + return idlutil.WalkCmd.KEEP_GOING, None + + idlutil.walk(typ, handle) + assert ret.min_size == typ.min_size(version) + assert ret.max_size == typ.max_size(version) + return ret + + +def get_buffer_size(typ: idl.Type, version: str) -> BufferSize: + tmp = _get_buffer_size(typ, version) + return BufferSize( + min_size=tmp.min_size, + exp_size=tmp.exp_size, + max_size=tmp.max_size, + max_copy=tmp.max_copy, + max_copy_extra=tmp.max_copy_extra, + max_iov=tmp.max_iov, + max_iov_extra=tmp.max_iov_extra, + ) + + +# Generate .h ################################################################## + + +def gen_h(versions: set[str], typs: list[idl.UserType]) -> str: + cutil.ifdef_init() + + ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */ + +#ifndef _LIB9P_9P_H_ +\t#error Do not include <lib9p/9p.generated.h> directly; include <lib9p/9p.h> instead +#endif + +#include <stdint.h> /* for uint{{n}}_t types */ + +#include <libhw/generic/net.h> /* for struct iovec */ +""" + + id2typ: dict[int, idl.Message] = {} + for msg in [msg for msg in typs if isinstance(msg, idl.Message)]: + id2typ[msg.msgid] = msg + + ret += """ +/* config *********************************************************************/ + +#include "config.h" +""" + for ver in sorted(versions): + ret += "\n" + ret += f"#ifndef {c9util.ver_ifdef({ver})}\n" + ret += f"\t#error config.h must define {c9util.ver_ifdef({ver})}\n" + if ver == "9P2000.e": # SPECIAL (9P2000.e) + ret += "#else\n" + ret += f"\t#if {c9util.ver_ifdef({ver})}\n" + ret += "\t\t#ifndef CONFIG_9P_MAX_9P2000_e_WELEM\n" + ret += f"\t\t\t#error if {c9util.ver_ifdef({ver})} then config.h must define CONFIG_9P_MAX_9P2000_e_WELEM\n" + ret += "\t\t#endif\n" + ret += "\t\tstatic_assert(CONFIG_9P_MAX_9P2000_e_WELEM > 0);\n" + ret += "\t#endif\n" + ret += "#endif\n" + + ret += f""" +/* enum version ***************************************************************/ + +enum {c9util.ident('version')} {{ +""" + fullversions = ["unknown = 0", *sorted(versions)] + verwidth = max(len(v) for v in fullversions) + for ver in fullversions: + if ver in versions: + ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver})) + ret += f"\t{c9util.ver_enum(ver)}," + ret += (" " * (verwidth - len(ver))) + ' /* "' + ver.split()[0] + '" */\n' + ret += cutil.ifdef_pop(0) + ret += f"\t{c9util.ver_enum('NUM')},\n" + ret += "};\n" + + ret += """ +/* enum msg_type **************************************************************/ + +""" + ret += f"enum {c9util.ident('msg_type')} {{ /* uint8_t */\n" + namewidth = max(len(msg.typname) for msg in typs if isinstance(msg, idl.Message)) + for n in range(0x100): + if n not in id2typ: + continue + msg = id2typ[n] + ret += cutil.ifdef_push(1, c9util.ver_ifdef(msg.in_versions)) + ret += f"\t{c9util.Ident(f'TYP_{msg.typname:<{namewidth}}')} = {msg.msgid},\n" + ret += cutil.ifdef_pop(0) + ret += "};\n" + + ret += """ +/* payload types **************************************************************/ +""" + + def per_version_comment( + typ: idl.UserType, fn: typing.Callable[[idl.UserType, str], str] + ) -> str: + lines: dict[str, str] = {} + for version in sorted(typ.in_versions): + lines[version] = fn(typ, version) + if len(set(lines.values())) == 1: + for _, line in lines.items(): + return f"/* {line} */\n" + assert False + else: + ret = "" + v_width = max(len(c9util.ver_enum(v)) for v in typ.in_versions) + for version, line in lines.items(): + ret += f"/* {c9util.ver_enum(version):<{v_width}}: {line} */\n" + return ret + + for typ in idlutil.topo_sorted(typs): + ret += "\n" + ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions)) + + def sum_size(typ: idl.UserType, version: str) -> str: + sz = get_buffer_size(typ, version) + assert ( + sz.min_size <= sz.exp_size + and sz.exp_size <= sz.max_size + and sz.max_size < cutil.UINT64_MAX + ) + ret = "" + if sz.min_size == sz.max_size: + ret += f"size = {sz.min_size:,}" + else: + ret += f"min_size = {sz.min_size:,} ; exp_size = {sz.exp_size:,} ; max_size = {sz.max_size:,}" + if sz.max_size > cutil.UINT32_MAX: + ret += " (warning: >UINT32_MAX)" + ret += f" ; max_iov = {sz.max_iov:,}{sz.max_iov_extra} ; max_copy = {sz.max_copy:,}{sz.max_copy_extra}" + return ret + + ret += per_version_comment(typ, sum_size) + + match typ: + case idl.Number(): + ret += f"typedef {c9util.typename(typ.prim)} {c9util.typename(typ)};\n" + prefix = f"{c9util.IDENT(typ.typname)}_" + namewidth = max(len(name) for name in typ.vals) + for name, val in typ.vals.items(): + ret += f"#define {prefix}{name:<{namewidth}} (({c9util.typename(typ)})UINT{typ.static_size*8}_C({val}))\n" + case idl.Bitfield(): + ret += f"typedef {c9util.typename(typ.prim)} {c9util.typename(typ)};\n" + + def bitname(val: idl.Bit | idl.BitAlias) -> str: + s = val.bitname + match val: + case idl.Bit(cat=idl.BitCat.RESERVED): + s = "_RESERVED_" + s + case idl.Bit(cat=idl.BitCat.SUBFIELD): + assert isinstance(typ, idl.Bitfield) + n = sum( + 1 + for b in typ.bits[: val.num] + if b.cat == idl.BitCat.SUBFIELD + and b.bitname == val.bitname + ) + s = f"_{s}_{n}" + case idl.Bit(cat=idl.BitCat.UNUSED): + return "" + return c9util.Ident(c9util.add_prefix(typ.typname.upper() + "_", s)) + + namewidth = max( + len(bitname(val)) for val in [*typ.bits, *typ.names.values()] + ) + + ret += "\n" + for bit in reversed(typ.bits): + vers = bit.in_versions + if bit.cat == idl.BitCat.UNUSED: + vers = typ.in_versions + ret += cutil.ifdef_push(2, c9util.ver_ifdef(vers)) + + # It is important all of the `beg` strings have + # the same length. + end = "" + match bit.cat: + case ( + idl.BitCat.USED | idl.BitCat.RESERVED | idl.BitCat.SUBFIELD + ): + if cutil.ifdef_leaf_is_noop(): + beg = "#define " + else: + beg = "# define" + case idl.BitCat.UNUSED: + beg = "/* unused" + end = " */" + + c_name = bitname(bit) + c_val = f"1<<{bit.num}" + ret += f"{beg} {c_name:<{namewidth}} (({c9util.typename(typ)})({c_val})){end}\n" + if aliases := [ + alias + for alias in typ.names.values() + if isinstance(alias, idl.BitAlias) + ]: + ret += "\n" + + for alias in aliases: + ret += cutil.ifdef_push(2, c9util.ver_ifdef(alias.in_versions)) + + end = "" + if cutil.ifdef_leaf_is_noop(): + beg = "#define " + else: + beg = "# define" + + c_name = bitname(alias) + c_val = alias.val + ret += f"{beg} {c_name:<{namewidth}} (({c9util.typename(typ)})({c_val})){end}\n" + ret += cutil.ifdef_pop(1) + del bitname + case idl.Struct(): # and idl.Message(): + ret += c9util.typename(typ) + " {" + if not typ.members: + ret += "};\n" + continue + ret += "\n" + + typewidth = max(len(c9util.typename(m.typ, m)) for m in typ.members) + + for member in typ.members: + if member.val: + continue + ret += cutil.ifdef_push(2, c9util.ver_ifdef(member.in_versions)) + ret += f"\t{c9util.typename(member.typ, member):<{typewidth}} {'*' if member.cnt else ' '}{member.membname};\n" + ret += cutil.ifdef_pop(1) + ret += "};\n" + del typ + ret += cutil.ifdef_pop(0) + + ret += """ +/* containers *****************************************************************/ +""" + ret += "\n" + ret += f"#define {c9util.IDENT('_MAX')}(a, b) ((a) > (b)) ? (a) : (b)\n" + + tmsg_max_iov: dict[str, int] = {} + tmsg_max_copy: dict[str, int] = {} + rmsg_max_iov: dict[str, int] = {} + rmsg_max_copy: dict[str, int] = {} + for typ in typs: + if not isinstance(typ, idl.Message): + continue + if typ.typname in ("Tsread", "Tswrite"): # SPECIAL (9P2000.e) + continue + max_iov = tmsg_max_iov if typ.msgid % 2 == 0 else rmsg_max_iov + max_copy = tmsg_max_copy if typ.msgid % 2 == 0 else rmsg_max_copy + for version in typ.in_versions: + if version not in max_iov: + max_iov[version] = 0 + max_copy[version] = 0 + sz = get_buffer_size(typ, version) + if sz.max_iov > max_iov[version]: + max_iov[version] = sz.max_iov + if sz.max_copy > max_copy[version]: + max_copy[version] = sz.max_copy + + for name, table in [ + ("tmsg_max_iov", tmsg_max_iov), + ("tmsg_max_copy", tmsg_max_copy), + ("rmsg_max_iov", rmsg_max_iov), + ("rmsg_max_copy", rmsg_max_copy), + ]: + inv: dict[int, set[str]] = {} + for version, maxval in table.items(): + if maxval not in inv: + inv[maxval] = set() + inv[maxval].add(version) + + ret += "\n" + directive = "if" + seen_e = False # SPECIAL (9P2000.e) + for maxval in sorted(inv, reverse=True): + ret += f"#{directive} {c9util.ver_ifdef(inv[maxval])}\n" + indent = 1 + if name.startswith("tmsg") and not seen_e: # SPECIAL (9P2000.e) + typ = next(typ for typ in typs if typ.typname == "Tswrite") + sz = get_buffer_size(typ, "9P2000.e") + match name: + case "tmsg_max_iov": + maxexpr = f"{sz.max_iov}{sz.max_iov_extra}" + case "tmsg_max_copy": + maxexpr = f"{sz.max_copy}{sz.max_copy_extra}" + case _: + assert False + ret += f"\t#if {c9util.ver_ifdef({"9P2000.e"})}\n" + ret += f"\t\t#define {c9util.IDENT(name)} {c9util.IDENT('_MAX')}({maxval}, {maxexpr})\n" + ret += "\t#else\n" + indent += 1 + ret += f"{'\t'*indent}#define {c9util.IDENT(name)} {maxval}\n" + if name.startswith("tmsg") and not seen_e: # SPECIAL (9P2000.e) + ret += "\t#endif\n" + if "9P2000.e" in inv[maxval]: + seen_e = True + directive = "elif" + ret += "#endif\n" + + ret += "\n" + ret += f"struct {c9util.ident('Tmsg_send_buf')} {{\n" + ret += "\tsize_t iov_cnt;\n" + ret += f"\tstruct iovec iov[{c9util.IDENT('TMSG_MAX_IOV')}];\n" + ret += f"\tuint8_t copied[{c9util.IDENT('TMSG_MAX_COPY')}];\n" + ret += "};\n" + + ret += "\n" + ret += f"struct {c9util.ident('Rmsg_send_buf')} {{\n" + ret += "\tsize_t iov_cnt;\n" + ret += f"\tstruct iovec iov[{c9util.IDENT('RMSG_MAX_IOV')}];\n" + ret += f"\tuint8_t copied[{c9util.IDENT('RMSG_MAX_COPY')}];\n" + ret += "};\n" + + return ret diff --git a/lib9p/protogen/idlutil.py b/lib9p/protogen/idlutil.py new file mode 100644 index 0000000..dc4d012 --- /dev/null +++ b/lib9p/protogen/idlutil.py @@ -0,0 +1,112 @@ +# lib9p/protogen/idlutil.py - Utilities for working with the 9P idl package +# +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +import enum +import graphlib +import typing + +import idl + +# pylint: disable=unused-variable +__all__ = [ + "topo_sorted", + "Path", + "WalkCmd", + "WalkHandler", + "walk", +] + +# topo_sorted() ################################################################ + + +def topo_sorted(typs: list[idl.UserType]) -> typing.Iterable[idl.UserType]: + ts: graphlib.TopologicalSorter[idl.UserType] = graphlib.TopologicalSorter() + for typ in typs: + match typ: + case idl.Number(): + ts.add(typ) + case idl.Bitfield(): + ts.add(typ) + case idl.Struct(): # and idl.Message(): + deps = [ + member.typ + for member in typ.members + if not isinstance(member.typ, idl.Primitive) + ] + ts.add(typ, *deps) + return ts.static_order() + + +# walk() ####################################################################### + + +class Path: + root: idl.Type + elems: list[idl.StructMember] + + def __init__( + self, root: idl.Type, elems: list[idl.StructMember] | None = None + ) -> None: + self.root = root + self.elems = elems if elems is not None else [] + + def add(self, elem: idl.StructMember) -> "Path": + return Path(self.root, self.elems + [elem]) + + def parent(self) -> "Path": + return Path(self.root, self.elems[:-1]) + + def c_str(self, base: str, loopdepth: int = 0) -> str: + ret = base + for i, elem in enumerate(self.elems): + if i > 0: + ret += "." + ret += elem.membname + if elem.cnt: + ret += f"[{chr(ord('i')+loopdepth)}]" + loopdepth += 1 + return ret + + def __str__(self) -> str: + return self.c_str(self.root.typname + "->") + + +class WalkCmd(enum.Enum): + KEEP_GOING = 1 + DONT_RECURSE = 2 + ABORT = 3 + + +type WalkHandler = typing.Callable[ + [Path], tuple[WalkCmd, typing.Callable[[], None] | None] +] + + +def _walk(path: Path, handle: WalkHandler) -> WalkCmd: + typ = path.elems[-1].typ if path.elems else path.root + + ret, atexit = handle(path) + + if isinstance(typ, idl.Struct): + match ret: + case WalkCmd.KEEP_GOING: + for member in typ.members: + if _walk(path.add(member), handle) == WalkCmd.ABORT: + ret = WalkCmd.ABORT + break + case WalkCmd.DONT_RECURSE: + ret = WalkCmd.KEEP_GOING + case WalkCmd.ABORT: + ret = WalkCmd.ABORT + case _: + assert False, f"invalid cmd: {ret}" + + if atexit: + atexit() + return ret + + +def walk(typ: idl.Type, handle: WalkHandler) -> None: + _walk(Path(typ), handle) diff --git a/lib9p/srv.c b/lib9p/srv.c index 932cd4d..2475baf 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -81,7 +81,7 @@ struct _srv_fidinfo { uint8_t flags; uint32_t iounit; size_t dir_idx; - uint32_t dir_off; + uint64_t dir_off; }; #define NAME fidmap @@ -566,7 +566,7 @@ static void handle_Tversion(struct _lib9p_srv_req *ctx, if (req->max_msg_size < min_msg_size) { lib9p_errorf(&ctx->ctx.basectx, LINUX_EDOM, "requested max_msg_size is less than minimum for %s (%"PRIu32" < %"PRIu32")", - version, req->max_msg_size, min_msg_size); + lib9p_version_str(version), req->max_msg_size, min_msg_size); return; } @@ -935,7 +935,7 @@ static void handle_Tread(struct _lib9p_srv_req *ctx, idx = fidinfo->dir_idx; else { lib9p_errorf(&ctx->ctx.basectx, - LINUX_EINVAL, "invalid offset (must be 0 or %"PRIu32"): %"PRIu32, + LINUX_EINVAL, "invalid offset (must be 0 or %"PRIu64"): %"PRIu64, fidinfo->dir_off, req->offset); return; } diff --git a/lib9p/tests/runtest b/lib9p/tests/runtest index c2f6c41..a745f12 100755 --- a/lib9p/tests/runtest +++ b/lib9p/tests/runtest @@ -7,11 +7,12 @@ set -euE -o pipefail set -x -valgrind --error-exitcode=2 ./tests/test_server/test_server & +port=$(python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()') +valgrind --error-exitcode=2 ./tests/test_server/test_server "$port" & server_pid=$! # shellcheck disable=SC2064 trap "kill $server_pid || true; wait $server_pid || true" EXIT -server_addr='localhost:9000' +server_addr="localhost:${port}" client=(9p -a "$server_addr") @@ -31,7 +32,7 @@ expect_lines \ out=$("${client[@]}" ls -l 'Documentation/') expect_lines \ - '--r--r--r-- M 0 root root 162 Oct 7 15:51 x' + '--r--r--r-- M 0 root root 166 Oct 7 15:51 x' out=$("${client[@]}" read 'README.md') expect_lines \ @@ -46,7 +47,7 @@ expect_lines \ out=$("${client[@]}" read 'Documentation/x') expect_lines \ '<!--' \ - ' Documentation/x - test static file' \ + ' Documentation/x.txt - test static file' \ '' \ ' Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>' \ ' SPDX-License-Identifier: AGPL-3.0-or-later' \ @@ -55,7 +56,7 @@ expect_lines \ out=$("${client[@]}" stat 'Documentation/x') expect_lines \ - "'x' 'root' 'root' 'root' q (0000000000000001 1 ) m 0444 at 1728337905 mt 1728337904 l 162 t 0 d 0" + "'x' 'root' 'root' 'root' q (0000000000000001 1 ) m 0444 at 1728337905 mt 1728337904 l 166 t 0 d 0" out=$("${client[@]}" write 'shutdown' <<<1) expect_lines '' diff --git a/lib9p/tests/test_compile.c b/lib9p/tests/test_compile.c new file mode 100644 index 0000000..6abee05 --- /dev/null +++ b/lib9p/tests/test_compile.c @@ -0,0 +1,157 @@ +/* lib9p/tests/test_compile.c - Generated by lib9p/tests/test_compile.c.gen. DO NOT EDIT! */ + +#include <lib9p/9p.h> +int main(void) { + [[gnu::unused]] uint64_t x; + x = LIB9P_TAG_NOTAG; + x = LIB9P_FID_NOFID; + x = LIB9P_DM_DIR; + x = LIB9P_DM_APPEND; + x = LIB9P_DM_EXCL; + x = _LIB9P_DM_RESERVED_PLAN9_MOUNT; + x = LIB9P_DM_AUTH; + x = LIB9P_DM_TMP; + x = LIB9P_DM_DEVICE; + x = LIB9P_DM_NAMEDPIPE; + x = LIB9P_DM_SOCKET; + x = LIB9P_DM_SETUID; + x = LIB9P_DM_SETGID; + x = LIB9P_DM_OWNER_R; + x = LIB9P_DM_OWNER_W; + x = LIB9P_DM_OWNER_X; + x = LIB9P_DM_GROUP_R; + x = LIB9P_DM_GROUP_W; + x = LIB9P_DM_GROUP_X; + x = LIB9P_DM_OTHER_R; + x = LIB9P_DM_OTHER_W; + x = LIB9P_DM_OTHER_X; + x = LIB9P_DM_PERM_MASK; + x = LIB9P_QT_DIR; + x = LIB9P_QT_APPEND; + x = LIB9P_QT_EXCL; + x = _LIB9P_QT_RESERVED_PLAN9_MOUNT; + x = LIB9P_QT_AUTH; + x = LIB9P_QT_TMP; + x = LIB9P_QT_SYMLINK; + x = LIB9P_QT_FILE; + x = LIB9P_NUID_NONUID; + x = LIB9P_O_RCLOSE; + x = _LIB9P_O_RESERVED_CEXEC; + x = LIB9P_O_TRUNC; + x = _LIB9P_O_mode_1; + x = _LIB9P_O_mode_0; + x = LIB9P_O_READ; + x = LIB9P_O_WRITE; + x = LIB9P_O_RDWR; + x = LIB9P_O_EXEC; + x = LIB9P_O_MODE_MASK; + x = LIB9P_O_FLAG_MASK; + x = LIB9P_ERRNO_NOERROR; + x = LIB9P_SUPER_MAGIC_V9FS_MAGIC; + x = LIB9P_LO_SYNC; + x = LIB9P_LO_CLOEXEC; + x = LIB9P_LO_NOATIME; + x = LIB9P_LO_NOFOLLOW; + x = LIB9P_LO_DIRECTORY; + x = LIB9P_LO_LARGEFILE; + x = LIB9P_LO_DIRECT; + x = LIB9P_LO_BSD_FASYNC; + x = LIB9P_LO_DSYNC; + x = LIB9P_LO_NONBLOCK; + x = LIB9P_LO_APPEND; + x = LIB9P_LO_TRUNC; + x = LIB9P_LO_NOCTTY; + x = LIB9P_LO_EXCL; + x = LIB9P_LO_CREATE; + x = _LIB9P_LO_mode_1; + x = _LIB9P_LO_mode_0; + x = LIB9P_LO_RDONLY; + x = LIB9P_LO_WRONLY; + x = LIB9P_LO_RDWR; + x = LIB9P_LO_NOACCESS; + x = LIB9P_LO_MODE_MASK; + x = LIB9P_LO_FLAG_MASK; + x = LIB9P_DT_UNKNOWN; + x = LIB9P_DT_NAMED_PIPE; + x = LIB9P_DT_CHAR_DEV; + x = LIB9P_DT_DIRECTORY; + x = LIB9P_DT_BLOCK_DEV; + x = LIB9P_DT_REGULAR; + x = LIB9P_DT_SYMLINK; + x = LIB9P_DT_SOCKET; + x = LIB9P_DT_WHITEOUT; + x = _LIB9P_MODE_fmt_3; + x = _LIB9P_MODE_fmt_2; + x = _LIB9P_MODE_fmt_1; + x = _LIB9P_MODE_fmt_0; + x = LIB9P_MODE_PERM_SETGROUP; + x = LIB9P_MODE_PERM_SETUSER; + x = LIB9P_MODE_PERM_STICKY; + x = LIB9P_MODE_PERM_OWNER_R; + x = LIB9P_MODE_PERM_OWNER_W; + x = LIB9P_MODE_PERM_OWNER_X; + x = LIB9P_MODE_PERM_GROUP_R; + x = LIB9P_MODE_PERM_GROUP_W; + x = LIB9P_MODE_PERM_GROUP_X; + x = LIB9P_MODE_PERM_OTHER_R; + x = LIB9P_MODE_PERM_OTHER_W; + x = LIB9P_MODE_PERM_OTHER_X; + x = LIB9P_MODE_FMT_NAMED_PIPE; + x = LIB9P_MODE_FMT_CHAR_DEV; + x = LIB9P_MODE_FMT_DIRECTORY; + x = LIB9P_MODE_FMT_BLOCK_DEV; + x = LIB9P_MODE_FMT_REGULAR; + x = LIB9P_MODE_FMT_SYMLINK; + x = LIB9P_MODE_FMT_SOCKET; + x = LIB9P_MODE_PERM_MASK; + x = LIB9P_MODE_FMT_MASK; + x = LIB9P_B4_FALSE; + x = LIB9P_B4_TRUE; + x = LIB9P_GETATTR_DATA_VERSION; + x = LIB9P_GETATTR_GEN; + x = LIB9P_GETATTR_BTIME; + x = LIB9P_GETATTR_BLOCKS; + x = LIB9P_GETATTR_SIZE; + x = LIB9P_GETATTR_INO; + x = LIB9P_GETATTR_CTIME; + x = LIB9P_GETATTR_MTIME; + x = LIB9P_GETATTR_ATIME; + x = LIB9P_GETATTR_RDEV; + x = LIB9P_GETATTR_GID; + x = LIB9P_GETATTR_UID; + x = LIB9P_GETATTR_NLINK; + x = LIB9P_GETATTR_MODE; + x = LIB9P_GETATTR_BASIC; + x = LIB9P_GETATTR_ALL; + x = LIB9P_SETATTR_MTIME_SET; + x = LIB9P_SETATTR_ATIME_SET; + x = LIB9P_SETATTR_CTIME; + x = LIB9P_SETATTR_MTIME; + x = LIB9P_SETATTR_ATIME; + x = LIB9P_SETATTR_SIZE; + x = LIB9P_SETATTR_GID; + x = LIB9P_SETATTR_UID; + x = LIB9P_SETATTR_MODE; + x = LIB9P_LOCK_TYPE_RDLCK; + x = LIB9P_LOCK_TYPE_WRLCK; + x = LIB9P_LOCK_TYPE_UNLCK; + x = LIB9P_LOCK_FLAGS_RECLAIM; + x = LIB9P_LOCK_FLAGS_BLOCK; + x = LIB9P_LOCK_STATUS_SUCCESS; + x = LIB9P_LOCK_STATUS_BLOCKED; + x = LIB9P_LOCK_STATUS_ERROR; + x = LIB9P_LOCK_STATUS_GRACE; + x = LIB9P_TMSG_MAX_IOV; + x = LIB9P_TMSG_MAX_IOV; + x = LIB9P_TMSG_MAX_COPY; + x = LIB9P_TMSG_MAX_COPY; + x = LIB9P_TMSG_MAX_COPY; + x = LIB9P_TMSG_MAX_COPY; + x = LIB9P_TMSG_MAX_COPY; + x = LIB9P_TMSG_MAX_COPY; + x = LIB9P_RMSG_MAX_IOV; + x = LIB9P_RMSG_MAX_IOV; + x = LIB9P_RMSG_MAX_IOV; + x = LIB9P_RMSG_MAX_COPY; + return 0; +} diff --git a/lib9p/tests/test_compile.c.gen b/lib9p/tests/test_compile.c.gen new file mode 100755 index 0000000..47046b3 --- /dev/null +++ b/lib9p/tests/test_compile.c.gen @@ -0,0 +1,19 @@ +#!/bin/sh +# lib9p/tests/test_compile.c.gen - Generate code to make sure all generated macros work +# +# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +generated_h=$1 +outfile=$2 + +{ + echo "/* ${outfile} - Generated by $0. DO NOT EDIT! */" + echo + echo "#include <lib9p/9p.h>" + echo 'int main(void) {' + echo ' [[gnu::unused]] uint64_t x;' + sed -nE 's/^\s*#\s*define\s*(\S[^ (]*)\s.*/ x = \1;/p' <"$generated_h" + echo ' return 0;' + echo '}' +} >"$outfile" diff --git a/lib9p/tests/test_compile_config/config.h b/lib9p/tests/test_compile_config/config.h new file mode 100644 index 0000000..38ab0c0 --- /dev/null +++ b/lib9p/tests/test_compile_config/config.h @@ -0,0 +1,38 @@ +/* config.h - Compile-time configuration for lib9p/test/test_compile + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +/* 9P *************************************************************************/ + +#define CONFIG_9P_MAX_MSG_SIZE ((4*1024)+24) +#define CONFIG_9P_MAX_HOSTMSG_SIZE CONFIG_9P_MAX_MSG_SIZE+16 +#define CONFIG_9P_MAX_ERR_SIZE 128 +#define CONFIG_9P_MAX_9P2000_e_WELEM 16 + +#define CONFIG_9P_SRV_MAX_FIDS 16 +#define CONFIG_9P_SRV_MAX_REQS 2 +#define CONFIG_9P_SRV_MAX_DEPTH 3 + +#define CONFIG_9P_ENABLE_9P2000 1 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_e 1 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_L 1 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_p9p 1 /* bool */ + +/* COROUTINE ******************************************************************/ + +#define CONFIG_COROUTINE_STACK_SIZE_DEFAULT (32*1024) +#define CONFIG_COROUTINE_NAME_LEN 16 +#define CONFIG_COROUTINE_MEASURE_STACK 1 /* bool */ +#define CONFIG_COROUTINE_PROTECT_STACK 1 /* bool */ +#define CONFIG_COROUTINE_DEBUG 0 /* bool */ +#define CONFIG_COROUTINE_VALGRIND 1 /* bool */ +#define CONFIG_COROUTINE_GDB 1 /* bool */ +#define CONFIG_COROUTINE_NUM 2 + +#endif /* _CONFIG_H_ */ diff --git a/lib9p/tests/test_server/CMakeLists.txt b/lib9p/tests/test_server/CMakeLists.txt index a107b75..74a759d 100644 --- a/lib9p/tests/test_server/CMakeLists.txt +++ b/lib9p/tests/test_server/CMakeLists.txt @@ -18,6 +18,7 @@ target_link_libraries(test_server_objs libmisc lib9p lib9p_util + libhw ) # Analyze the stack ############################################################ @@ -36,7 +37,7 @@ target_sources(test_server PRIVATE target_embed_sources(test_server_objs test_server static.h static/README.md - static/Documentation/x + static/Documentation/x.txt ) endif() diff --git a/lib9p/tests/test_server/config/config.h b/lib9p/tests/test_server/config/config.h index 67960ca..afe6dc0 100644 --- a/lib9p/tests/test_server/config/config.h +++ b/lib9p/tests/test_server/config/config.h @@ -1,4 +1,4 @@ -/* config.h - Compile-time configuration for srv9p +/* config.h - Compile-time configuration for lib9p/test/test_server * * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later @@ -12,7 +12,6 @@ /* 9P *************************************************************************/ -#define CONFIG_9P_PORT LIB9P_DEFAULT_PORT_9FS /** * This max-msg-size is sized so that a Twrite message can return * 8KiB of data. diff --git a/lib9p/tests/test_server/main.c b/lib9p/tests/test_server/main.c index c60dd71..074dbe7 100644 --- a/lib9p/tests/test_server/main.c +++ b/lib9p/tests/test_server/main.c @@ -5,6 +5,7 @@ */ #include <error.h> +#include <stdlib.h> /* for atoi() */ #include <lib9p/srv.h> #include <libcr/coroutine.h> @@ -32,6 +33,7 @@ static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *, struct lib9p const char *hexdig = "0123456789abcdef"; struct { + uint16_t port; struct hostnet_tcp_listener listeners[CONFIG_SRV9P_NUM_CONNS]; struct lib9p_srv srv; } globals = { @@ -130,7 +132,7 @@ enum { PATH_BASE = __COUNTER__ }; struct lib9p_srv_file root = STATIC_DIR("", STATIC_DIR("Documentation", - STATIC_FILE("x", Documentation_x), + STATIC_FILE("x", Documentation_x_txt), ), STATIC_FILE("README.md", README_md), lo_box_api_as_lib9p_srv_file(&(struct api_file){.pathnum = PATH_COUNTER}), @@ -146,7 +148,7 @@ static COROUTINE read_cr(void *_i) { int i = *((int *)_i); cr_begin(); - hostnet_tcp_listener_init(&globals.listeners[i], 9000); + hostnet_tcp_listener_init(&globals.listeners[i], globals.port); lib9p_srv_read_cr(&globals.srv, lo_box_hostnet_tcplist_as_net_stream_listener(&globals.listeners[i])); @@ -172,7 +174,10 @@ static COROUTINE init_cr(void *) { cr_exit(); } -int main() { +int main(int argc, char *argv[]) { + if (argc != 2) + error(2, 0, "usage: %s PORT_NUMBER", argv[0]); + globals.port = atoi(argv[1]); struct hostclock clock_monotonic = { .clock_id = CLOCK_MONOTONIC, }; diff --git a/lib9p/tests/test_server/static/Documentation/x b/lib9p/tests/test_server/static/Documentation/x.txt index b9b08d4..e85ee4e 100644 --- a/lib9p/tests/test_server/static/Documentation/x +++ b/lib9p/tests/test_server/static/Documentation/x.txt @@ -1,5 +1,5 @@ <!-- - Documentation/x - test static file + Documentation/x.txt - test static file Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/libhw/CMakeLists.txt b/libhw/CMakeLists.txt index d1767da..242a3fa 100644 --- a/libhw/CMakeLists.txt +++ b/libhw/CMakeLists.txt @@ -1,6 +1,6 @@ # libhw/CMakeLists.txt - Device drivers # -# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later add_library(libhw INTERFACE) @@ -14,8 +14,10 @@ if (PICO_PLATFORM STREQUAL "rp2040") libcr_ipc ) target_sources(libhw INTERFACE - rp2040_hwtimer.c + rp2040_dma.c + rp2040_gpioirq.c rp2040_hwspi.c + rp2040_hwtimer.c w5500.c ) target_link_libraries(libhw INTERFACE diff --git a/libhw/rp2040_dma.c b/libhw/rp2040_dma.c new file mode 100644 index 0000000..dfbf136 --- /dev/null +++ b/libhw/rp2040_dma.c @@ -0,0 +1,56 @@ +/* libhw/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 + */ + +#include <stdbool.h> + +#include <hardware/irq.h> /* for irq_set_exclusive_handler() */ + +#include "rp2040_dma.h" + +struct dmairq_handler_entry { + dmairq_handler_t fn; + void *arg; +}; +struct dmairq_handler_entry dmairq_handlers[NUM_DMA_CHANNELS] = {0}; + +bool dmairq_initialized[NUM_DMA_IRQS] = {0}; + +static void dmairq_handler(void) { + enum dmairq irq = __get_current_exception() - VTABLE_FIRST_IRQ; + size_t irq_idx = irq - DMAIRQ_0; + assert(irq_idx < NUM_DMA_IRQS); + + uint32_t regval = dma_hw->irq_ctrl[irq_idx].ints; + for (uint channel = 0; channel < NUM_DMA_CHANNELS; channel++) { + if (regval & 1u<<channel) { + struct dmairq_handler_entry *handler = &dmairq_handlers[channel]; + if (handler->fn) + handler->fn(handler->arg, irq, channel); + } + } + /* acknowledge irq */ + dma_hw->intr = regval; +} + +void dmairq_set_and_enable_exclusive_handler(enum dmairq irq, uint channel, dmairq_handler_t fn, void *arg) { + assert(irq == DMAIRQ_0 || irq == DMAIRQ_1); + assert(channel < NUM_DMA_CHANNELS); + assert(fn); + + assert(dmairq_handlers[channel].fn == NULL); + + dmairq_handlers[channel].fn = fn; + dmairq_handlers[channel].arg = arg; + + size_t irq_idx = irq - DMAIRQ_0; + hw_set_bits(&dma_hw->irq_ctrl[irq_idx].inte, 1u<<channel); + + if (!dmairq_initialized[irq_idx]) { + irq_set_exclusive_handler(irq, dmairq_handler); + irq_set_enabled(irq, true); + dmairq_initialized[irq_idx] = true; + } +} diff --git a/libhw/rp2040_dma.h b/libhw/rp2040_dma.h new file mode 100644 index 0000000..c8d69b1 --- /dev/null +++ b/libhw/rp2040_dma.h @@ -0,0 +1,128 @@ +/* libhw/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 + * + * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBHW_RP2040_DMA_H_ +#define _LIBHW_RP2040_DMA_H_ + +#include <assert.h> +#include <stdint.h> /* for uint32_t */ + +#include <hardware/regs/dreq.h> /* for DREQ_* for use with DMA_CTRL_TREQ_SEL() */ +#include <hardware/structs/dma.h> /* for dma_hw, dma_channel_hw_t, DMA_NUM_CHANNELS */ + +#include <libmisc/macro.h> /* for LM_FLOORLOG2() */ + +/* Borrowed from <hardware/dma.h> *********************************************/ + +static inline dma_channel_hw_t *dma_channel_hw_addr(uint channel) { + assert(channel < NUM_DMA_CHANNELS); + return &dma_hw->ch[channel]; +} + +enum dma_channel_transfer_size { + DMA_SIZE_8 = 0, ///< Byte transfer (8 bits) + DMA_SIZE_16 = 1, ///< Half word transfer (16 bits) + DMA_SIZE_32 = 2 ///< Word transfer (32 bits) +}; + +/* Our own code ***************************************************************/ + +enum dmairq { + DMAIRQ_0 = DMA_IRQ_0, + DMAIRQ_1 = DMA_IRQ_1, +}; + +typedef void (*dmairq_handler_t)(void *arg, enum dmairq irq, uint channel); + +/** + * Register `fn(arg, ...)` to be called when `channel` completes or + * has a NULL trigger (depending on the channel's configuration). + * + * Your handler does not need to acknowledge the IRQ; that will be + * done for you after your handler is called. + * + * It is illegal to enable the same channel on more than one IRQ. + */ +void dmairq_set_and_enable_exclusive_handler(enum dmairq irq, uint channel, dmairq_handler_t fn, void *arg); + +#define DMA_CTRL_ENABLE (1<<0) +#define DMA_CTRL_HI_PRIO (1<<1) +#define DMA_CTRL_DATA_SIZE(sz) ((sz)<<2) +#define DMA_CTRL_INCR_READ (1<<4) +#define DMA_CTRL_INCR_WRITE (1<<5) +#define _DMA_CTRL_RING_BITS(b) ((b)<<6) +#define _DMA_CTRL_RING_RD (0) +#define _DMA_CTRL_RING_WR (1<<10) +#define DMA_CTRL_RING(rdwr, bits) (_DMA_CTRL_RING_##rdwr | _DMA_CTRL_RING_BITS(bits)) +#define DMA_CTRL_CHAIN_TO(ch) ((ch)<<11) +#define DMA_CTRL_TREQ_SEL(dreq) ((dreq)<<15) +#define DMA_CTRL_IRQ_QUIET (1<<21) +#define DMA_CTRL_BSWAP (1<<22) +#define DMA_CTRL_SNIFF_EN (1<<23) + +/* | elem | val | name */ +#define READ_ADDR /*|*/volatile const void/*|*/ * /*|*/read_addr +#define WRITE_ADDR /*|*/volatile void/*|*/ * /*|*/write_addr +#define TRANS_COUNT /*|*/ /*|*/uint32_t/*|*/trans_count +#define CTRL /*|*/ /*|*/uint32_t/*|*/ctrl + +/* { +0x0 ; +0x4 ; +0x8 ; +0xC (Trigger) */ +struct dma_alias0 { READ_ADDR ; WRITE_ADDR ; TRANS_COUNT ; CTRL ; }; +struct dma_alias1 { CTRL ; READ_ADDR ; WRITE_ADDR ; TRANS_COUNT ; }; +struct dma_alias2 { CTRL ; TRANS_COUNT ; READ_ADDR ; WRITE_ADDR ; }; +struct dma_alias3 { CTRL ; WRITE_ADDR ; TRANS_COUNT ; READ_ADDR ; }; +struct dma_alias0_short2 { TRANS_COUNT ; CTRL ; }; +struct dma_alias1_short2 { WRITE_ADDR ; TRANS_COUNT ; }; +struct dma_alias2_short2 { READ_ADDR ; WRITE_ADDR ; }; +struct dma_alias3_short2 { TRANS_COUNT ; READ_ADDR ; }; +struct dma_alias0_short3 { CTRL ; }; +struct dma_alias1_short3 { TRANS_COUNT ; }; +struct dma_alias2_short3 { WRITE_ADDR ; }; +struct dma_alias3_short3 { READ_ADDR ; }; + +#undef CTRL +#undef TRANS_COUNT +#undef WRITE_ADDR +#undef READ_ADDR + +#define DMA_CHAN_ADDR(CH, TYP) ((TYP *volatile)_Generic((TYP){}, \ + struct dma_alias0: &dma_channel_hw_addr(CH)->read_addr, \ + struct dma_alias1: &dma_channel_hw_addr(CH)->al1_ctrl, \ + struct dma_alias2: &dma_channel_hw_addr(CH)->al2_ctrl, \ + struct dma_alias3: &dma_channel_hw_addr(CH)->al3_ctrl, \ + struct dma_alias0_short2: &dma_channel_hw_addr(CH)->transfer_count, \ + struct dma_alias1_short2: &dma_channel_hw_addr(CH)->al1_write_addr, \ + struct dma_alias2_short2: &dma_channel_hw_addr(CH)->al2_read_addr, \ + struct dma_alias3_short2: &dma_channel_hw_addr(CH)->al3_transfer_count, \ + struct dma_alias0_short3: &dma_channel_hw_addr(CH)->ctrl_trig, \ + struct dma_alias1_short3: &dma_channel_hw_addr(CH)->al1_transfer_count_trig, \ + struct dma_alias2_short3: &dma_channel_hw_addr(CH)->al2_write_addr_trig, \ + struct dma_alias3_short3: &dma_channel_hw_addr(CH)->al3_read_addr_trig)) + +#define DMA_CHAN_WR_TRANS_COUNT(TYP) \ + (sizeof(TYP)/4) + +#define DMA_CHAN_WR_CTRL(TYP) ( DMA_CTRL_DATA_SIZE(DMA_SIZE_32) \ + | DMA_CTRL_INCR_WRITE \ + | DMA_CTRL_RING(WR, LM_FLOORLOG2(sizeof(TYP))) \ + ) + +#define DMA_NONTRIGGER(CH, FIELD) (DMA_CHAN_ADDR(CH, _DMA_NONTRIGGER_##FIELD)->FIELD) +#define _DMA_NONTRIGGER_read_addr struct dma_alias0 +#define _DMA_NONTRIGGER_write_addr struct dma_alias0 +#define _DMA_NONTRIGGER_trans_count struct dma_alias0 +#define _DMA_NONTRIGGER_ctrl struct dma_alias1 + +#define DMA_TRIGGER(CH, FIELD) (DMA_CHAN_ADDR(CH, _DMA_TRIGGER_##FIELD)->FIELD) +#define _DMA_TRIGGER_read_addr struct dma_alias3 +#define _DMA_TRIGGER_write_addr struct dma_alias2 +#define _DMA_TRIGGER_trans_count struct dma_alias1 +#define _DMA_TRIGGER_ctrl struct dma_alias0 + +#endif /* _LIBHW_RP2040_DMA_H_ */ diff --git a/libhw/rp2040_gpioirq.c b/libhw/rp2040_gpioirq.c new file mode 100644 index 0000000..2f0ceac --- /dev/null +++ b/libhw/rp2040_gpioirq.c @@ -0,0 +1,75 @@ +/* libhw/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 + */ + +#include <hardware/structs/io_bank0.h> /* for io_bank0_hw */ +#include <hardware/irq.h> /* for irq_set_exclusive_handler() */ + +#include <libmisc/macro.h> + +#include "rp2040_gpioirq.h" + +struct gpioirq_handler_entry { + gpioirq_handler_t fn; + void *arg; +}; +struct gpioirq_handler_entry gpioirq_handlers[NUM_BANK0_GPIOS][4] = {0}; + +int gpioirq_core = -1; + +static void gpioirq_handler(void) { + uint core = get_core_num(); + io_bank0_irq_ctrl_hw_t *irq_ctrl_base; + switch (core) { + case 0: irq_ctrl_base = &io_bank0_hw->proc0_irq_ctrl; break; + case 1: irq_ctrl_base = &io_bank0_hw->proc1_irq_ctrl; break; + default: assert_notreached("invalid core number"); + } + for (uint regnum = 0; regnum < LM_ARRAY_LEN(irq_ctrl_base->ints); regnum++) { + uint32_t regval = irq_ctrl_base->ints[regnum]; + for (uint bit = 0; bit < 32 && (regnum*8)+(bit/4) < NUM_BANK0_GPIOS; bit++) { + if (regval & 1u<<bit) { + uint gpio = (regnum*8)+(bit/4); + uint event_idx = bit%4; + struct gpioirq_handler_entry *handler = &gpioirq_handlers[gpio][event_idx]; + if (handler->fn) + handler->fn(handler->arg, gpio, 1u<<event_idx); + } + } + /* acknowledge irq */ + io_bank0_hw->intr[regnum] = regval; + } +} + +void gpioirq_set_and_enable_exclusive_handler(uint gpio, enum gpio_irq_level event, gpioirq_handler_t fn, void *arg) { + assert(gpio < NUM_BANK0_GPIOS); + assert(event == GPIO_IRQ_LEVEL_LOW || + event == GPIO_IRQ_LEVEL_HIGH || + event == GPIO_IRQ_EDGE_FALL || + event == GPIO_IRQ_EDGE_RISE); + assert(fn); + + uint event_idx = LM_FLOORLOG2(event); + assert(gpioirq_handlers[gpio][event_idx].fn == NULL); + + uint core = get_core_num(); + assert(gpioirq_core == -1 || gpioirq_core == (int)core); + + io_bank0_irq_ctrl_hw_t *irq_ctrl_base; + switch (core) { + case 0: irq_ctrl_base = &io_bank0_hw->proc0_irq_ctrl; break; + case 1: irq_ctrl_base = &io_bank0_hw->proc1_irq_ctrl; break; + default: assert_notreached("invalid core number"); + } + + gpioirq_handlers[gpio][event_idx].fn = fn; + gpioirq_handlers[gpio][event_idx].arg = arg; + hw_set_bits(&irq_ctrl_base->inte[gpio/8], 1u<<((4*(gpio%8))+event_idx)); + if (gpioirq_core == -1) { + irq_set_exclusive_handler(IO_IRQ_BANK0, gpioirq_handler); + irq_set_enabled(IO_IRQ_BANK0, true); + gpioirq_core = core; + } +} diff --git a/libhw/rp2040_gpioirq.h b/libhw/rp2040_gpioirq.h new file mode 100644 index 0000000..06041c9 --- /dev/null +++ b/libhw/rp2040_gpioirq.h @@ -0,0 +1,33 @@ +/* libhw/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_ + +#include <hardware/gpio.h> /* for enum gpio_irq_level */ + +typedef void (*gpioirq_handler_t)(void *arg, uint gpio, enum gpio_irq_level event); + +/** + * Register `fn(arg, ...)` to be called when `event` fires on GPIO pin + * `gpio`. + * + * If multiple events happen close together, the handlers will not + * necessarily be called in-order. + * + * Your handler does not need to acknowledge the IRQ; that will be + * done for you after your handler is called. + * + * It is illegal to call gpioirq_set_and_enable_exclusive_handler() + * on multiple cores. + * + * This is better than the Pico-SDK <hardware/gpio.h> IRQ functions + * because their functions call the handlers for every event, and it + * is up to you to de-mux them in your handler. + */ +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_ */ diff --git a/libhw/rp2040_hwspi.c b/libhw/rp2040_hwspi.c index 8c87666..f747b1e 100644 --- a/libhw/rp2040_hwspi.c +++ b/libhw/rp2040_hwspi.c @@ -4,37 +4,76 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -#include <hardware/spi.h> /* pico-sdk:hardware_spi */ -#include <hardware/gpio.h> /* pico-sdk:hardware_gpio */ +#include <alloca.h> +#include <inttypes.h> /* for PRIu{n} */ +#include <hardware/clocks.h> /* for clock_get_hz() and clk_peri */ +#include <hardware/gpio.h> +#include <hardware/spi.h> + +#include <libcr/coroutine.h> #include <libmisc/assert.h> +#define LOG_NAME RP2040_SPI +#include <libmisc/log.h> + #define IMPLEMENTATION_FOR_LIBHW_RP2040_HWSPI_H YES #include <libhw/rp2040_hwspi.h> +#include <libhw/generic/alarmclock.h> + +#include "rp2040_dma.h" + +#include "config.h" + +#ifndef CONFIG_RP2040_SPI_DEBUG + #error config.h must define CONFIG_RP2040_SPI_DEBUG (bool) +#endif + LO_IMPLEMENTATION_C(io_duplex_readwriter, struct rp2040_hwspi, rp2040_hwspi, static) LO_IMPLEMENTATION_C(spi, struct rp2040_hwspi, rp2040_hwspi, static) +static void rp2040_hwspi_intrhandler(void *_self, enum dmairq LM_UNUSED(irq), uint LM_UNUSED(channel)) { + struct rp2040_hwspi *self = _self; + gpio_put(self->pin_cs, 1); + cr_sema_signal_from_intrhandler(&self->sema); +} + +#define assert_4distinct(a, b, c, d) \ + assert(a != b); \ + assert(a != c); \ + assert(a != d); \ + assert(b != c); \ + assert(b != d); \ + assert(c != d); + void _rp2040_hwspi_init(struct rp2040_hwspi *self, enum rp2040_hwspi_instance inst_num, enum spi_mode mode, uint baudrate_hz, + uint64_t min_delay_ns, + uint8_t bogus_data, uint pin_miso, uint pin_mosi, uint pin_clk, - uint pin_cs) { + uint pin_cs, + uint dma1, + uint dma2, + uint dma3, + uint dma4) +{ /* Be not weary: This is but 12 lines of actual code; and many * lines of comments and assert()s. */ spi_inst_t *inst; + uint actual_baudrate_hz; assert(self); assert(baudrate_hz); - assert(pin_miso != pin_mosi); - assert(pin_miso != pin_clk); - assert(pin_miso != pin_cs); - assert(pin_mosi != pin_clk); - assert(pin_mosi != pin_cs); - assert(pin_clk != pin_cs); + uint32_t clk_peri_hz = clock_get_hz(clk_peri); + debugf("clk_peri = %"PRIu32"Hz", clk_peri_hz); + assert(baudrate_hz*2 <= clk_peri_hz); + assert_4distinct(pin_miso, pin_mosi, pin_clk, pin_cs); + assert_4distinct(dma1, dma2, dma3, dma4); /* Regarding the constraints on pin assignments: see the * RP2040 datasheet, table 2, in ยง1.4.3 "GPIO Functions". */ @@ -57,7 +96,9 @@ void _rp2040_hwspi_init(struct rp2040_hwspi *self, assert_notreached("invalid hwspi instance number"); } - spi_init(inst, baudrate_hz); + actual_baudrate_hz = spi_init(inst, baudrate_hz); + debugf("baudrate = %uHz", actual_baudrate_hz); + assert(actual_baudrate_hz == baudrate_hz); spi_set_format(inst, 8, (mode & 0b10) ? SPI_CPOL_1 : SPI_CPOL_0, (mode & 0b01) ? SPI_CPHA_1 : SPI_CPHA_0, @@ -79,30 +120,125 @@ void _rp2040_hwspi_init(struct rp2040_hwspi *self, gpio_set_dir(pin_cs, GPIO_OUT); gpio_put(pin_cs, 1); - /* Return. */ + /* Initialize self. */ self->inst = inst; + self->min_delay_ns = min_delay_ns; + self->bogus_data = bogus_data; self->pin_cs = pin_cs; + self->dma_tx_ctrl = dma1; + self->dma_rx_ctrl = dma2; + self->dma_tx_data = dma3; + self->dma_rx_data = dma4; + self->dead_until_ns = 0; + self->sema = (cr_sema_t){0}; + + /* Initialize the interrupt handler. */ + dmairq_set_and_enable_exclusive_handler(DMAIRQ_0, self->dma_rx_data, rp2040_hwspi_intrhandler, self); } static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct duplex_iovec *iov, int iovcnt) { assert(self); - spi_inst_t *inst = self->inst; - - assert(inst); + assert(self->inst); assert(iov); - assert(iovcnt); + assert(iovcnt > 0); - gpio_put(self->pin_cs, 0); - /* TODO: Replace blocking reads+writes with DMA. */ - for (int i = 0; i < iovcnt; i++) { - if (iov[i].iov_write_src && iov[i].iov_read_dst) - spi_write_read_blocking(inst, iov[i].iov_write_src, iov[i].iov_read_dst, iov[i].iov_len); - else if (iov[i].iov_write_src) - spi_write_blocking(inst, iov[i].iov_write_src, iov[i].iov_len); - else if (iov[i].iov_read_dst) - spi_read_blocking(inst, 0, iov[i].iov_read_dst, iov[i].iov_len); - else - assert_notreached("duplex_iovec is neither read nor write"); + /* At this time, I have no intention to run SPI faster than + * 80MHz (= 80Mb/s = 10MB/s). If we ran the CPU at just + * 100MHz (we'll be running it faster than that, maybe even + * 200MHz), that means we'd have 10 clock cycles to send each + * byte. + * + * This affords us substantial simplifications, like being + * able to afford 4-cycle changeovers between DMA blocks, and + * not having to worry about alignment because we can just use + * DMA_SIZE_8. + */ + + uint8_t bogus_rx_dst; + + int pruned_iovcnt = 0; + for (int i = 0; i < iovcnt; i++) + if (iov[i].iov_len) + pruned_iovcnt++; + if (!pruned_iovcnt) + return; + + /* For tx_data_blocks, it doesn't really matter which aliases + * we choose: + * - None of our fields can be NULL (so no + * false-termination). + * - Moving const fields first so they don't have to be + * re-programmed each time isn't possible for us there need + * to be at least 2 const fields, and we only have 1 + * (read_addr for rx_data_blocks, and write_addr for + * tx_data_blocks). + * + * But for rx_data_blocks, we need ctrl to be the trigger + * register so that the DMA_CTRL_IRQ_QUIET flag isn't cleared + * before we get to the trigger; and while for tx_data_blocks + * it doesn't really matter, the inverse would be nice. + */ + struct dma_alias1 *tx_data_blocks = alloca(sizeof(struct dma_alias1)*(pruned_iovcnt+1)); + struct dma_alias0 *rx_data_blocks = alloca(sizeof(struct dma_alias0)*(pruned_iovcnt+1)); + + for (int i = 0, j = 0; i < iovcnt; i++) { + 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, + .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) + | 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, + .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) + | DMA_CTRL_CHAIN_TO(self->dma_rx_ctrl) + | DMA_CTRL_TREQ_SEL(SPI_DREQ_NUM(self->inst, false)) + | DMA_CTRL_IRQ_QUIET), + }; + j++; } - gpio_put(self->pin_cs, 1); + tx_data_blocks[pruned_iovcnt] = (typeof(tx_data_blocks[0])){0}; + rx_data_blocks[pruned_iovcnt] = (typeof(rx_data_blocks[0])){0}; + + /* Set up ctrl. */ + DMA_NONTRIGGER(self->dma_tx_ctrl, read_addr) = tx_data_blocks; + DMA_NONTRIGGER(self->dma_tx_ctrl, write_addr) = DMA_CHAN_ADDR(self->dma_tx_data, typeof(tx_data_blocks[0])); + DMA_NONTRIGGER(self->dma_tx_ctrl, trans_count) = DMA_CHAN_WR_TRANS_COUNT(typeof(tx_data_blocks[0])); + DMA_NONTRIGGER(self->dma_tx_ctrl, ctrl) = (DMA_CTRL_ENABLE + | DMA_CHAN_WR_CTRL(typeof(tx_data_blocks[0])) + | DMA_CTRL_INCR_READ + | DMA_CTRL_CHAIN_TO(self->dma_tx_data) + | DMA_CTRL_TREQ_SEL(DREQ_FORCE) + | DMA_CTRL_IRQ_QUIET); + DMA_NONTRIGGER(self->dma_rx_ctrl, read_addr) = rx_data_blocks; + DMA_NONTRIGGER(self->dma_rx_ctrl, write_addr) = DMA_CHAN_ADDR(self->dma_rx_data, typeof(rx_data_blocks[0])); + DMA_NONTRIGGER(self->dma_rx_ctrl, trans_count) = DMA_CHAN_WR_TRANS_COUNT(typeof(rx_data_blocks[0])); + DMA_NONTRIGGER(self->dma_rx_ctrl, ctrl) = (DMA_CTRL_ENABLE + | DMA_CHAN_WR_CTRL(typeof(rx_data_blocks[0])) + | DMA_CTRL_INCR_READ + | DMA_CTRL_CHAIN_TO(self->dma_rx_data) + | DMA_CTRL_TREQ_SEL(DREQ_FORCE) + | DMA_CTRL_IRQ_QUIET); + + /* Run. */ + uint64_t now = LO_CALL(bootclock, get_time_ns); + if (now < self->dead_until_ns) + sleep_until_ns(self->dead_until_ns); + bool saved = cr_save_and_disable_interrupts(); + gpio_put(self->pin_cs, 0); + dma_hw->multi_channel_trigger = (1u<<self->dma_tx_ctrl) | (1u<<self->dma_rx_ctrl); + cr_restore_interrupts(saved); + cr_sema_wait(&self->sema); + self->dead_until_ns = LO_CALL(bootclock, get_time_ns) + self->min_delay_ns; } diff --git a/libhw/rp2040_include/libhw/rp2040_hwspi.h b/libhw/rp2040_include/libhw/rp2040_hwspi.h index 76e0709..eb54cdc 100644 --- a/libhw/rp2040_include/libhw/rp2040_hwspi.h +++ b/libhw/rp2040_include/libhw/rp2040_hwspi.h @@ -9,6 +9,7 @@ #include <pico/binary_info.h> /* for bi_* */ +#include <libcr_ipc/sema.h> #include <libmisc/private.h> #include <libhw/generic/spi.h> @@ -20,9 +21,19 @@ enum rp2040_hwspi_instance { struct rp2040_hwspi { BEGIN_PRIVATE(LIBHW_RP2040_HWSPI_H) + /* const */ LM_IF(IS_IMPLEMENTATION_FOR(LIBHW_RP2040_HWSPI_H))(spi_inst_t)(void) *inst; + uint64_t min_delay_ns; + uint8_t bogus_data; + uint pin_cs; + uint dma_tx_data; + uint dma_tx_ctrl; + uint dma_rx_data; + uint dma_rx_ctrl; - uint pin_cs; + /* mutable */ + uint64_t dead_until_ns; + cr_sema_t sema; END_PRIVATE(LIBHW_RP2040_HWSPI_H) }; LO_IMPLEMENTATION_H(io_duplex_readwriter, struct rp2040_hwspi, rp2040_hwspi) @@ -31,14 +42,18 @@ LO_IMPLEMENTATION_H(spi, struct rp2040_hwspi, rp2040_hwspi) /** * Initialize an instance of `struct rp2040_hwspi`. * - * @param self : struct rp2040_hwspi : the structure to initialize - * @param name : char * : a name for the SPI port; to include in the bininfo - * @param inst_num : enum rp2040_hwspi_instance : the PL220 instance number; RP2040_HWSPI_{0,1} - * @param mode : enum spi_mode : the SPI mode; SPI_MODE_{0..3} - * @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 - * @param pin_cs : uint : pin number; any unused GPIO pin + * @param self : struct rp2040_hwspi : the structure to initialize + * @param name : char * : a name for the SPI port; to include in the bininfo + * @param inst_num : enum rp2040_hwspi_instance : the PL220 instance number; RP2040_HWSPI_{0,1} + * @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 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 + * @param pin_cs : uint : pin number; any unused GPIO pin + * @param dma{1-4} : uint : DMA channel; any unused channel * * There is no bit-order argument; the RP2040's hardware SPI always * uses MSB-first bit order. @@ -48,16 +63,32 @@ LO_IMPLEMENTATION_H(spi, struct rp2040_hwspi, rp2040_hwspi) * the CPU. This is because the PL022 has a maximum of 16-bit frames, * but we need to be able to do *at least* 32-bit frames (and ideally, * much larger). By managing it ourselves, we can just keep CS pulled - * low extra-long, making the frame extra-long. However, this means - * that we can't SPI so fast that the CPU can't do things in time; - * experimentally much faster than 60MHz seems to be when I start - * getting mangled messages. We wouldn't have this speed limit with a - * PIO-based SPI driver, because it could toggle CLK and CS in - * lock-step with receiving data from the FIFO. + * low extra-long, making the frame extra-long. + * + * Restrictions on baudrate: + * + * - The PL022 requires that the baudrate is an even-number fraction + * of clk_peri. + * + This implies that the maximum baudrate is clk_peri/2. + * + Pico-SDK' default clk_peri is 125MHz, max is 200MHz. + * - The CS-from-GPIO hack above means that that we can't go so fast + * that the CPU can't do things in time. + * + Experimentally: + * | clk_sys=125MHz | baud=31.25MHz | works OK | + * | clk_sys=160MHz | baud=40 MHz | works OK | + * | clk_sys=170MHz | baud=42.5 MHz | works OK | + * | clk_sys=180MHz | baud=45 MHz | mangled in funny ways? | + * | clk_sys=200MHz | baud=50 MHz | messages get shifted right a bit | + * | clk_sys=125MHz | baud=62.5 MHz | messages get shifted right a bit | + * + * Both of these restrictions aught to be avoidable by using a + * PIO-based SPI driver instead of this PLL02-based driver. */ #define rp2040_hwspi_init(self, name, \ inst_num, mode, baudrate_hz, \ - pin_miso, pin_mosi, pin_clk, pin_cs) \ + min_delay_ns, bogus_data, \ + pin_miso, pin_mosi, pin_clk, pin_cs, \ + dma1, dma2, dma3, dma4) \ do { \ bi_decl(bi_4pins_with_names(pin_miso, name" SPI MISO", \ pin_mosi, name" SPI MOSI", \ @@ -65,15 +96,23 @@ LO_IMPLEMENTATION_H(spi, struct rp2040_hwspi, rp2040_hwspi) pin_mosi, name" SPI CS")); \ _rp2040_hwspi_init(self, \ inst_num, mode, baudrate_hz, \ - pin_miso, pin_mosi, pin_clk, pin_cs); \ + min_delay_ns, bogus_data, \ + pin_miso, pin_mosi, pin_clk, pin_cs, \ + dma1, dma2, dma3, dma4); \ } while(0) void _rp2040_hwspi_init(struct rp2040_hwspi *self, enum rp2040_hwspi_instance inst_num, enum spi_mode mode, uint baudrate_hz, + uint64_t min_delay_ns, + uint8_t bogus_data, uint pin_miso, uint pin_mosi, uint pin_clk, - uint pin_cs); + uint pin_cs, + uint dma1, + uint dma2, + uint dma3, + uint dma4); #endif /* _LIBHW_RP2040_HWSPI_H_ */ diff --git a/libhw/w5500.c b/libhw/w5500.c index 64b373b..c4d36f3 100644 --- a/libhw/w5500.c +++ b/libhw/w5500.c @@ -72,6 +72,7 @@ /* TODO: Write a <libhw/generic/gpio.h> to avoid w5500.c being * pico-sdk-specific. */ #include <hardware/gpio.h> /* pico-sdk:hardware_gpio */ +#include "rp2040_gpioirq.h" #include <libcr/coroutine.h> /* for cr_yield() */ @@ -95,8 +96,8 @@ #ifndef CONFIG_W5500_LOCAL_PORT_MAX #error config.h must define CONFIG_W5500_LOCAL_PORT_MAX #endif -#ifndef CONFIG_W5500_NUM - #error config.h must define CONFIG_W5500_NUM +#ifndef CONFIG_W5500_VALIDATE_SPI + #error config.h must define CONFIG_W5500_VALIDATE_SPI #endif #ifndef CONFIG_W5500_DEBUG #error config.h must define CONFIG_W5500_DEBUG @@ -280,13 +281,10 @@ static inline void w5500_socket_close(struct _w5500_socket *socket) { /* init() *********************************************************************/ -static struct w5500 *w5500_chips[CONFIG_W5500_NUM] = {0}; - -static void w5500_intrhandler(uint gpio, uint32_t LM_UNUSED(event_mask)) { - debugf("w5500_intrhandler(): interrupt on pin %u", gpio); - for (size_t i = 0; i < LM_ARRAY_LEN(w5500_chips); i++) - if (w5500_chips[i] && w5500_chips[i]->pin_intr == gpio) - cr_sema_signal_from_intrhandler(&w5500_chips[i]->intr); +static void w5500_intrhandler(void *_chip, uint LM_UNUSED(gpio), enum gpio_irq_level LM_UNUSED(event)) { + struct w5500 *chip = _chip; + debugf("w5500_intrhandler()"); + cr_sema_signal_from_intrhandler(&chip->intr); } void _w5500_init(struct w5500 *chip, @@ -317,20 +315,28 @@ void _w5500_init(struct w5500 *chip, }; } +#if CONFIG_W5500_VALIDATE_SPI + /* Validate that SPI works correctly. */ + bool spi_ok = true; + for (uint16_t a = 0; a < 0x100; a++) { + w5500ll_write_sock_reg(chip->spidev, 0, mode, a); + uint8_t b = w5500ll_read_sock_reg(chip->spidev, 0, mode); + if (b != a) { + errorf("SPI to W5500 does not appear to be functional: wrote:0x%02"PRIx16" != read:0x%02"PRIx8, a, b); + spi_ok = false; + } + } + if (!spi_ok) + __lm_abort(); + w5500ll_write_sock_reg(chip->spidev, 0, mode, 0); +#endif + /* Initialize the hardware. */ - gpio_set_irq_enabled_with_callback(pin_intr, GPIO_IRQ_EDGE_FALL, true, w5500_intrhandler); + gpioirq_set_and_enable_exclusive_handler(pin_intr, GPIO_IRQ_EDGE_FALL, w5500_intrhandler, chip); gpio_set_dir(chip->pin_reset, GPIO_OUT); w5500_hard_reset(chip); /* Finally, wire in the interrupt handler. */ - bool saved = cr_save_and_disable_interrupts(); - for (size_t i = 0; i < LM_ARRAY_LEN(w5500_chips); i++) { - if (w5500_chips[i] == NULL) { - w5500_chips[i] = chip; - break; - } - } - cr_restore_interrupts(saved); coroutine_add("w5500_irq", w5500_irq_cr, chip); } @@ -342,9 +348,9 @@ static void w5500_post_reset(struct w5500 *chip) { w5500ll_write_common_reg(chip->spidev, eth_addr, chip->hwaddr); /* The RP2040 needs a 1/sys_clk hysteresis between interrupts - * for us to notice them. At the maximum-rated clock-rate of - * 133MHz, that means 7.5ns (but the sbc-harness overclocks - * the RP2040, so we could get away with even shorter). + * for us to notice them. At the default clock-rate of + * 125MHz, that means 8ns; and at the maximum-rated clock-rate + * of 200MHz, that means 5ns. * * If intlevel is non-zero, then the hysteresis is * (intlevel+1)*4/(150MHz), or (intlevel+1)*26.7ns; so even diff --git a/libmisc/log.c b/libmisc/log.c index ff4dac6..be87de6 100644 --- a/libmisc/log.c +++ b/libmisc/log.c @@ -1,17 +1,13 @@ /* libmisc/log.c - stdio logging * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ -#include <stdio.h> /* for vprintf() */ -#include <stdarg.h> /* for va_list, va_start(), va_end() */ +#include <stdint.h> /* for uint{n}_t */ #include <libmisc/assert.h> /* for static_assert() */ -#define LOG_NAME -#include <libmisc/log.h> - static const char *byte_strs[] = { "0x00", "0x01", @@ -1,7 +1,7 @@ <!-- notes.md - Misc notes - Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> SPDX-License-Identifier: AGPL-3.0-or-later --> @@ -140,6 +140,19 @@ sections" wut does that mean 8 16-bit values in both the TX buffer and the RX buffer +| Ver. 1.0.0 | 2013-08-01 | https://www.alldatasheet.com/datasheet-pdf/view/554784/ETC2/W5500.html https://www.alldatasheet.com/pdfjsview/web/viewer.html?file=//www.alldatasheet.com/datasheet-pdf/view/554784/ETC2/W5500/+_44J97VwSw9bZYvAB+/datasheet.pdf | +| Ver. 1.0.1 | 2013-09-13 | | +| Ver. 1.0.2 | 2013-11-14 | https://cdn.sparkfun.com/datasheets/Dev/Arduino/Shields/W5500_datasheet_v1.0.2_1.pdf | +| Ver. 1.0.3 | 2014-05-29 | | +| Ver. 1.0.4 | 2014-06-13 | | +| Ver. 1.0.5 | 2014-11-10 | | +| Ver. 1.0.6 | 2014-12-30 | | +| Ver. 1.0.7 | 2016-02-24 | | +| Ver. 1.0.8 | 2017-05-19 | https://docs.wiznet.io/img/products/w5500/w5500_ds_v108e.pdf (on-page version and date are wrong) | +| Ver. 1.0.9 | 2019-05-22 | https://docs.wiznet.io/img/products/w5500/w5500_ds_v109e.pdf | +| Ver. 1.1.0 | 2022-12-17 | https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf | + +https://github.com/Bodmer/TFT_eSPI/discussions/2432 ---- |