summaryrefslogtreecommitdiff
path: root/lib9p
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-10-02 14:29:52 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-10-02 14:29:52 -0600
commit79e6cb0f6f7627284a7614b70a25e976b426d82e (patch)
tree492b5cacfbb5482b00e023979c0f62f2097a2030 /lib9p
parentb7a140a42f272aadb5400f013cd21a7a218d26e8 (diff)
wip bitfield
Diffstat (limited to 'lib9p')
-rw-r--r--lib9p/include/lib9p/_types.h4
-rw-r--r--lib9p/types.c9
-rwxr-xr-xlib9p/types.gen106
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"