From 79e6cb0f6f7627284a7614b70a25e976b426d82e Mon Sep 17 00:00:00 2001 From: "Luke T. Shumaker" Date: Wed, 2 Oct 2024 14:29:52 -0600 Subject: wip bitfield --- lib9p/include/lib9p/_types.h | 4 +- lib9p/types.c | 9 +++- lib9p/types.gen | 106 +++++++++++++++++++++++++++++-------------- 3 files changed, 82 insertions(+), 37 deletions(-) diff --git a/lib9p/include/lib9p/_types.h b/lib9p/include/lib9p/_types.h index b904318..8a47102 100644 --- a/lib9p/include/lib9p/_types.h +++ b/lib9p/include/lib9p/_types.h @@ -23,11 +23,11 @@ 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_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_SYMLINK ((lib9p_qt_t)(1<<1)) -#define LIB9P_QT__UNUSED_0 ((lib9p_qt_t)(1<<0)) +#define _LIB9P_QT_UNUSED_0 ((lib9p_qt_t)(1<<0)) #define LIB9P_QT_FILE ((lib9p_qt_t)(0)) struct lib9p_d { diff --git a/lib9p/types.c b/lib9p/types.c index cb410ea..3505a4a 100644 --- a/lib9p/types.c +++ b/lib9p/types.c @@ -344,7 +344,14 @@ static ALWAYS_INLINE bool validate_s(struct _validate_ctx *ctx) { } static ALWAYS_INLINE bool validate_qt(struct _validate_ctx *ctx) { - return validate_1(ctx); + if (validate_1(ctx)) + return true; + const lib9p_qt_t mask = 0b11111110; + lib9p_qt_t val = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); + if (val & ~mask) + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#01"PRIx8, + val & ~mask); + return false; } static ALWAYS_INLINE bool validate_qid(struct _validate_ctx *ctx) { diff --git a/lib9p/types.gen b/lib9p/types.gen index b41442a..0c9269d 100755 --- a/lib9p/types.gen +++ b/lib9p/types.gen @@ -32,21 +32,22 @@ class Atom(enum.Enum): return self.value +class BitfieldVal: + name: str + val: str + ver: set[str] + + def __init__(self) -> None: + self.ver = set() + + class Bitfield: name: str bits: list[str] - names: dict[str, str] + names: dict[str, BitfieldVal] @property def static_size(self) -> int: - if len(self.bits) <= 8: - return 1 - if len(self.bits) <= 16: - return 2 - if len(self.bits) <= 32: - return 4 - if len(self.bits) <= 64: - return 8 return int((len(self.bits) + 7) / 8) @@ -167,12 +168,17 @@ def parse_file( symname = symname.strip() for typ in other_typs: if typ.name == symname or symname == "*": - if isinstance(typ, Struct): - if typ.msgid: - typ.msgver.add(version) - for member in typ.members: - if other_version in member.ver: - member.ver.add(version) + match typ: + case Bitfield(): + for val in typ.names.values(): + if other_version in val.ver: + val.ver.add(version) + case Struct(): + if typ.msgid: + typ.msgver.add(version) + for member in typ.members: + if other_version in member.ver: + member.ver.add(version) env[typ.name] = typ elif m := re.fullmatch(re_structspec, line): if not version: @@ -214,10 +220,14 @@ def parse_file( version, env, prev.members, m.group("members") ) elif m := re.fullmatch(re_bitfieldspec, line): + if not version: + raise SyntaxError("must have exactly 1 version line") bf = Bitfield() bf.name = m.group("name") bf.bits = int(m.group("size")) * [""] bf.names = {} + if len(bf.bits) not in [8, 16, 32, 64]: + raise ValueError(f"Bitfield {repr(bf.name)} has an unusual size") env[bf.name] = bf prev = bf elif m := re.fullmatch(re_bitfieldspec_bit, line): @@ -242,8 +252,15 @@ def parse_file( raise ValueError(f"{bf.name}: bit {bit} already assigned") if name in bf.names: raise ValueError(f"{bf.name}: name {name} already assigned") + bf.bits[bit] = name - bf.names[name] = "" + + assert version + _val = BitfieldVal() + _val.name = name + _val.val = f"1<<{bit}" + _val.ver.add(version) + bf.names[name] = _val elif m := re.fullmatch(re_bitfieldspec_alias, line): if m.group("bitfield"): if m.group("bitfield") not in env: @@ -262,13 +279,19 @@ def parse_file( val = m.group("val") if name in bf.names: raise ValueError(f"{bf.name}: name {name} already assigned") - bf.names[name] = val + + assert version + _val = BitfieldVal() + _val.name = name + _val.val = val + _val.ver.add(version) + bf.names[name] = _val else: raise SyntaxError(f"invalid line {repr(line)}") if not version: raise SyntaxError("must have exactly 1 version line") - typs = [x for x in env.values() if not isinstance(x, Atom)] + typs = [x for x in env.values() if not isinstance(x, Atom)] return version, typs @@ -356,20 +379,22 @@ enum {idprefix}version {{ for bf in just_bitfields(typs): ret += "\n" ret += f"typedef uint{bf.static_size*8}_t {c_typename(idprefix, bf)};\n" - vals = dict( - [ - *reversed( - [ - ((k or f"_UNUSED_{v}"), f"1<<{v}") - for (v, k) in enumerate(bf.bits) - ] - ), - *[(k, v) for (k, v) in bf.names.items() if k not in bf.bits], - ] - ) - namewidth = max(len(name) for name in vals) - for name, val in vals.items(): - ret += f"#define {idprefix.upper()}{bf.name.upper()}_{name.ljust(namewidth)} (({c_typename(idprefix, bf)})({val}))\n" + names = [ + *reversed([bf.bits[n] or f"_UNUSED_{n}" for n in range(0, len(bf.bits))]), + *[k for k in bf.names if k not in bf.bits], + ] + namewidth = max(len(name) for name in names) + for name in names: + if name.startswith("_"): + cname = f"_{idprefix.upper()}{bf.name.upper()}_{name[1:]}" + else: + cname = f"{idprefix.upper()}{bf.name.upper()}_{name}" + if name in bf.names: + val = bf.names[name].val + else: + assert name.startswith("_UNUSED_") + val = f"1<<{name[len('_UNUSED_'):]}" + ret += f"#define {cname}{' '*(namewidth-len(name))} (({c_typename(idprefix, bf)})({val}))\n" for struct in just_structs_nonmsg(typs): all_the_same = len(struct.members) == 0 or all( @@ -560,8 +585,21 @@ static ALWAYS_INLINE bool _validate_list(struct _validate_ctx *ctx, match typ: case Bitfield(): ret += "\n" - # ret += "\t{c_typename(idprefix, typ)} mask = 0b" + (''.join('1' if b else '0' for b in reversed(typ.bits))) + ";\n" - ret += f"\treturn validate_{typ.static_size}(ctx);\n" + if all(not bit for bit in typ.bits): + ret += f"\treturn validate_{typ.static_size}(ctx));\n" + else: + ret += f"\t if (validate_{typ.static_size}(ctx))\n" + ret += "\t\treturn true;\n" + ret += ( + f"\tconst {c_typename(idprefix, typ)} mask = 0b" + + ("".join("1" if b else "0" for b in reversed(typ.bits))) + + ";\n" + ) + ret += f"\t{c_typename(idprefix, typ)} val = decode_u{typ.static_size*8}le(&ctx->net_bytes[ctx->net_offset-{typ.static_size}]);\n" + ret += f"\tif (val & ~mask)\n" + ret += f'\t\treturn lib9p_error(ctx->ctx, LINUX_EBADMSG, "unknown bits in {typ.name} bitfield: %#0{typ.static_size}"PRIx{typ.static_size*8},\n' + ret += "\t\t val & ~mask);\n" + ret += "\treturn false;\n" case Struct(): if len(typ.members) == 0: ret += "\n\treturn false;\n" -- cgit v1.2.3-2-g168b