1 # bend-osdev-acpi, registry.bend: tables by signature. A registry maps each 2 # signature to the parser that reads it; AcpiTable.parse checks a table 3 # (length, checksum: header.bend) and hands it to the parser its signature 4 # names. A new table plugs in two ways: map its signature to AcpiKRaw{} or to 5 # one of the parsers here (AcpiRegistry.set), or give it a tag, 6 # AcpiKExt{tag}, and pass a parser for it as the template argument of 7 # AcpiTable.parse_with, which answers that parser's own type in AcpiTExt. 8 import Base 9 import bend-osdev-bytes@0.1.1.0/bytes.bend as B 10 import ./error.bend as E 11 import ./header.bend as H 12 import ./rsdt.bend as S 13 import ./madt.bend as M 14 import ./fadt.bend as F 15 import ./hpet.bend as P 16 import ./mcfg.bend as C 17 import ./srat.bend as R 18 import ./slit.bend as L 19 import ./bgrt.bend as G 20 import ./dsdt.bend as D 21 22 # the parsers a signature can name 23 type AcpiKind is Data: 24 AcpiKRsdt{} 25 AcpiKXsdt{} 26 AcpiKMadt{} 27 AcpiKFadt{} 28 AcpiKHpet{} 29 AcpiKMcfg{} 30 AcpiKSrat{} 31 AcpiKSlit{} 32 AcpiKBgrt{} 33 # DSDT, SSDT: the AML definition block, as bytes 34 AcpiKAml{} 35 # header and body, unread 36 AcpiKRaw{} 37 # the caller's parser (AcpiTable.parse_with), told this tag 38 AcpiKExt{tag: U32} 39 40 type AcpiRegEntry is Data: 41 AcpiRegEntry{signature: B.Octets, kind: AcpiKind} 42 43 type AcpiRegistry is Data: 44 AcpiRegistry{entries: List<&2, AcpiRegEntry>} 45 46 def reg.e(s: String, k: AcpiKind) -> AcpiRegEntry: 47 AcpiRegEntry{B.Octets.of_string(s), k} 48 49 # every table this package reads 50 def AcpiRegistry.default() -> AcpiRegistry: 51 AcpiRegistry{[reg.e("RSDT", AcpiKRsdt{}), reg.e("XSDT", AcpiKXsdt{}), reg.e("APIC", AcpiKMadt{}), reg.e("FACP", AcpiKFadt{}), reg.e("HPET", AcpiKHpet{}), reg.e("MCFG", AcpiKMcfg{}), reg.e("SRAT", AcpiKSrat{}), reg.e("SLIT", AcpiKSlit{}), reg.e("BGRT", AcpiKBgrt{}), reg.e("DSDT", AcpiKAml{}), reg.e("SSDT", AcpiKAml{})]} 52 53 # no parsers: every table raw 54 def AcpiRegistry.empty() -> AcpiRegistry: 55 AcpiRegistry{Nil{}} 56 57 def reg.lookup.pick(hit: Bool, k: AcpiKind, rest: AcpiKind) -> AcpiKind: 58 match hit: 59 case True{}: 60 k 61 case False{}: 62 rest 63 64 def reg.lookup(es: List<&2, AcpiRegEntry>, +sig: B.Octets) -> AcpiKind: 65 match es: 66 case Nil{}: 67 AcpiKRaw{} 68 case Con{AcpiRegEntry{s, k}, t}: 69 reg.lookup.pick(B.Octets.is_eq(s, sig), k, reg.lookup(t, sig)) 70 71 # the parser for a signature (AcpiKRaw{} if the registry has none) 72 def AcpiRegistry.lookup(r: AcpiRegistry, +sig: B.Octets) -> AcpiKind: 73 match r: 74 case AcpiRegistry{es}: 75 reg.lookup(es, sig) 76 77 def reg.keep(hit: Bool, e: AcpiRegEntry, rest: List<&2, AcpiRegEntry>) -> List<&2, AcpiRegEntry>: 78 match hit: 79 case True{}: 80 rest 81 case False{}: 82 Con{e, rest} 83 84 def reg.drop(es: List<&2, AcpiRegEntry>, +sig: B.Octets) -> List<&2, AcpiRegEntry>: 85 match es: 86 case Nil{}: 87 Nil{} 88 case Con{AcpiRegEntry{+s, k}, t}: 89 reg.keep(B.Octets.is_eq(s, sig), AcpiRegEntry{s, k}, reg.drop(t, sig)) 90 91 # the registry with sig mapped to k (replacing any earlier mapping) 92 def AcpiRegistry.set(r: AcpiRegistry, +sig: B.Octets, k: AcpiKind) -> AcpiRegistry: 93 match r: 94 case AcpiRegistry{es}: 95 AcpiRegistry{Con{AcpiRegEntry{sig, k}, reg.drop(es, sig)}} 96 97 # the registry without sig (its tables then read raw) 98 def AcpiRegistry.remove(r: AcpiRegistry, +sig: B.Octets) -> AcpiRegistry: 99 match r: 100 case AcpiRegistry{es}: 101 AcpiRegistry{reg.drop(es, sig)} 102 103 # A parsed table. X is the type the caller's extension parser answers 104 # (AcpiNoExt when there is none). 105 type AcpiTable<-X: Data> is Data: 106 AcpiTRsdt{t: S.AcpiSdtList} 107 AcpiTXsdt{t: S.AcpiSdtList} 108 AcpiTMadt{t: M.AcpiMadt} 109 AcpiTFadt{t: F.AcpiFadt} 110 AcpiTHpet{t: P.AcpiHpet} 111 AcpiTMcfg{t: C.AcpiMcfg} 112 AcpiTSrat{t: R.AcpiSrat} 113 AcpiTSlit{t: L.AcpiSlit} 114 AcpiTBgrt{t: G.AcpiBgrt} 115 AcpiTAml{t: D.AcpiAml} 116 AcpiTRaw{t: H.AcpiSdt} 117 AcpiTExt{tag: U32, x: X} 118 119 type AcpiNoExt is Data: 120 AcpiNoExt{} 121 122 # the extension parser of AcpiTable.parse: refuses every tag 123 def AcpiNoExt.parse(tag: U32, t: H.AcpiSdt) -> Result<&2, &2, E.AcpiError, AcpiNoExt>: 124 Fail{E.AcpiBadSignature{H.AcpiHeader.signature(H.AcpiSdt.header(t))}} 125 126 def reg.wrap(~X: Data, ~A: Data, ~f: A -> AcpiTable, r: Result<&2, &2, E.AcpiError, A>) -> Result<&2, &2, E.AcpiError, AcpiTable>: 127 match r: 128 case Fail{e}: 129 Fail{e} 130 case Done{a}: 131 Done{f(a)} 132 133 def reg.ext(~X: Data, +tag: U32, r: Result<&2, &2, E.AcpiError, X>) -> Result<&2, &2, E.AcpiError, AcpiTable>: 134 match r: 135 case Fail{e}: 136 Fail{e} 137 case Done{a}: 138 Done{AcpiTExt{tag, a}} 139 140 def reg.dispatch(~X: Data, ~ext: U32 -> H.AcpiSdt -> Result<&2, &2, E.AcpiError, X>, k: AcpiKind, +t: H.AcpiSdt) -> Result<&2, &2, E.AcpiError, AcpiTable>: 141 match k: 142 case AcpiKRsdt{}: 143 reg.wrap(~X, ~S.AcpiSdtList, ~(a => AcpiTRsdt{a}), S.AcpiRsdt.of_sdt(t)) 144 case AcpiKXsdt{}: 145 reg.wrap(~X, ~S.AcpiSdtList, ~(a => AcpiTXsdt{a}), S.AcpiXsdt.of_sdt(t)) 146 case AcpiKMadt{}: 147 reg.wrap(~X, ~M.AcpiMadt, ~(a => AcpiTMadt{a}), M.AcpiMadt.of_sdt(t)) 148 case AcpiKFadt{}: 149 reg.wrap(~X, ~F.AcpiFadt, ~(a => AcpiTFadt{a}), F.AcpiFadt.of_sdt(t)) 150 case AcpiKHpet{}: 151 reg.wrap(~X, ~P.AcpiHpet, ~(a => AcpiTHpet{a}), P.AcpiHpet.of_sdt(t)) 152 case AcpiKMcfg{}: 153 reg.wrap(~X, ~C.AcpiMcfg, ~(a => AcpiTMcfg{a}), C.AcpiMcfg.of_sdt(t)) 154 case AcpiKSrat{}: 155 reg.wrap(~X, ~R.AcpiSrat, ~(a => AcpiTSrat{a}), R.AcpiSrat.of_sdt(t)) 156 case AcpiKSlit{}: 157 reg.wrap(~X, ~L.AcpiSlit, ~(a => AcpiTSlit{a}), L.AcpiSlit.of_sdt(t)) 158 case AcpiKBgrt{}: 159 reg.wrap(~X, ~G.AcpiBgrt, ~(a => AcpiTBgrt{a}), G.AcpiBgrt.of_sdt(t)) 160 case AcpiKAml{}: 161 reg.wrap(~X, ~D.AcpiAml, ~(a => AcpiTAml{a}), D.AcpiAml.of_sdt(t)) 162 case AcpiKRaw{}: 163 Done{AcpiTRaw{t}} 164 case AcpiKExt{+tag}: 165 reg.ext(~X, tag, ext(tag, t)) 166 167 def reg.go(~X: Data, ~ext: U32 -> H.AcpiSdt -> Result<&2, &2, E.AcpiError, X>, +reg: AcpiRegistry, r: Result<&2, &2, E.AcpiError, H.AcpiSdt>) -> Result<&2, &2, E.AcpiError, AcpiTable>: 168 match r: 169 case Fail{e}: 170 Fail{e} 171 case Done{+t}: 172 reg.dispatch(~X, ~ext, AcpiRegistry.lookup(reg, H.AcpiHeader.signature(H.AcpiSdt.header(t))), t) 173 174 # the table at the front of o: checked (AcpiSdt.check: length and checksum), 175 # then read by the parser the registry names for its signature, with ext 176 # for AcpiKExt tags 177 def AcpiTable.parse_with(~X: Data, ~ext: U32 -> H.AcpiSdt -> Result<&2, &2, E.AcpiError, X>, +reg: AcpiRegistry, +o: B.Octets) -> Result<&2, &2, E.AcpiError, AcpiTable>: 178 reg.go(~X, ~ext, reg, H.AcpiSdt.parse(o)) 179 180 # the same without extension parsers 181 def AcpiTable.parse(+reg: AcpiRegistry, +o: B.Octets) -> Result<&2, &2, E.AcpiError, AcpiTable>: 182 AcpiTable.parse_with(~AcpiNoExt, ~AcpiNoExt.parse, reg, o) 183 184 # the name of the parser that read the table 185 def AcpiTable.name(~X: Data, t: AcpiTable) -> String: 186 match t: 187 case AcpiTRsdt{a}: 188 "RSDT" 189 case AcpiTXsdt{a}: 190 "XSDT" 191 case AcpiTMadt{a}: 192 "APIC" 193 case AcpiTFadt{a}: 194 "FACP" 195 case AcpiTHpet{a}: 196 "HPET" 197 case AcpiTMcfg{a}: 198 "MCFG" 199 case AcpiTSrat{a}: 200 "SRAT" 201 case AcpiTSlit{a}: 202 "SLIT" 203 case AcpiTBgrt{a}: 204 "BGRT" 205 case AcpiTAml{a}: 206 B.Octets.to_string(H.AcpiHeader.signature(D.AcpiAml.header(a))) 207 case AcpiTRaw{a}: 208 B.Octets.to_string(H.AcpiHeader.signature(H.AcpiSdt.header(a))) 209 case AcpiTExt{tag, x}: 210 "ext " ++ U32.show(tag)