1 # bend-osdev-acpi, rsdt.bend: the Root and Extended System Description 2 # Tables (ACPI 6.5, sections 5.2.7 and 5.2.8): a header, then the physical 3 # addresses of the other tables, 4 bytes each in the RSDT ("RSDT"), 8 bytes 4 # each in the XSDT ("XSDT"). Addresses are answered as W64 for both. 5 import Base 6 import bend-osdev-word64@0.1.1.1/word64.bend as W 7 import bend-osdev-bytes@0.1.1.1/bytes.bend as B 8 import ./error.bend as E 9 import ./header.bend as H 10 import ./fields.bend as F 11 12 type AcpiSdtList is Data: 13 AcpiSdtList{header: H.AcpiHeader, entries: List<&2, W.W64>} 14 15 def AcpiSdtList.entries(t: AcpiSdtList) -> List<&2, W.W64>: 16 match t: 17 case AcpiSdtList{h, es}: 18 es 19 20 def AcpiSdtList.header(t: AcpiSdtList) -> H.AcpiHeader: 21 match t: 22 case AcpiSdtList{h, es}: 23 h 24 25 def sl.rev(xs: List<&2, W.W64>, acc: List<&2, W.W64>) -> List<&2, W.W64>: 26 match xs: 27 case Nil{}: 28 acc 29 case Con{h, t}: 30 sl.rev(t, Con{h, acc}) 31 32 # n entries of width 4 or 8 bytes from the front of o 33 def sl.read(n: Nat, wide: Bool, +o: B.Octets, acc: List<&2, W.W64>) -> List<&2, W.W64>: 34 match n: 35 case 0n: 36 sl.rev(acc, Nil{}) 37 case 1n+p: 38 match wide: 39 case True{}: 40 sl.read(p, True{}, B.Octets.drop(8n, o), Con{F.AcpiF.u64(o, 0n), acc}) 41 case False{}: 42 sl.read(p, False{}, B.Octets.drop(4n, o), Con{W.W64.from_u32(F.AcpiF.u32(o, 0n)), acc}) 43 44 def sl.width(wide: Bool) -> Nat: 45 match wide: 46 case True{}: 47 8n 48 case False{}: 49 4n 50 51 def sl.body(ok: Bool, +wide: Bool, +h: H.AcpiHeader, +body: B.Octets) -> Result<&2, &2, E.AcpiError, AcpiSdtList>: 52 match ok: 53 case False{}: 54 Fail{E.AcpiBadSize{B.Octets.len(body)}} 55 case True{}: 56 Done{AcpiSdtList{h, sl.read(Nat.div(B.Octets.len(body), sl.width(wide)), wide, body, Nil{})}} 57 58 # a checked table's body as entries; AcpiBadSize if it is not a whole 59 # number of them 60 def sl.of_sdt(+wide: Bool, t: H.AcpiSdt) -> Result<&2, &2, E.AcpiError, AcpiSdtList>: 61 match t: 62 case H.AcpiSdt{h, +body}: 63 sl.body(Nat.is_eq(Nat.mod(B.Octets.len(body), sl.width(wide)), 0n), wide, h, body) 64 65 def AcpiRsdt.of_sdt(t: H.AcpiSdt) -> Result<&2, &2, E.AcpiError, AcpiSdtList>: 66 sl.of_sdt(False{}, t) 67 68 def AcpiXsdt.of_sdt(t: H.AcpiSdt) -> Result<&2, &2, E.AcpiError, AcpiSdtList>: 69 sl.of_sdt(True{}, t) 70 71 def sl.parse(+wide: Bool, r: Result<&2, &2, E.AcpiError, H.AcpiSdt>) -> Result<&2, &2, E.AcpiError, AcpiSdtList>: 72 match r: 73 case Fail{e}: 74 Fail{e} 75 case Done{t}: 76 sl.of_sdt(wide, t) 77 78 def AcpiRsdt.parse(+o: B.Octets) -> Result<&2, &2, E.AcpiError, AcpiSdtList>: 79 sl.parse(False{}, H.AcpiSdt.parse_sig(B.Octets.of_string("RSDT"), o)) 80 81 def AcpiXsdt.parse(+o: B.Octets) -> Result<&2, &2, E.AcpiError, AcpiSdtList>: 82 sl.parse(True{}, H.AcpiSdt.parse_sig(B.Octets.of_string("XSDT"), o)) 83 84 def sl.enc(xs: List<&2, W.W64>, wide: Bool) -> List<&2, B.Octets>: 85 match xs: 86 case Nil{}: 87 Nil{} 88 case Con{h, t}: 89 match wide: 90 case True{}: 91 Con{B.Octets.le64(h), sl.enc(t, True{})} 92 case False{}: 93 Con{B.Octets.le32(W.W64.lo(h)), sl.enc(t, False{})} 94 95 # the table (header from H.AcpiHeader.make or decoded; its signature is 96 # replaced, its length and checksum computed). RSDT entries keep the low 32 97 # bits of each address. 98 def AcpiRsdt.build(h: H.AcpiHeader, xs: List<&2, W.W64>) -> B.Octets: 99 match h: 100 case H.AcpiHeader{s, l, r, c, o, t, orv, ci, cr}: 101 H.AcpiSdt.build(H.AcpiHeader{B.Octets.of_string("RSDT"), l, r, c, o, t, orv, ci, cr}, B.Octets.concat(sl.enc(xs, False{}))) 102 103 def AcpiXsdt.build(h: H.AcpiHeader, xs: List<&2, W.W64>) -> B.Octets: 104 match h: 105 case H.AcpiHeader{s, l, r, c, o, t, orv, ci, cr}: 106 H.AcpiSdt.build(H.AcpiHeader{B.Octets.of_string("XSDT"), l, r, c, o, t, orv, ci, cr}, B.Octets.concat(sl.enc(xs, True{})))