example.bend

bend-osdev-acpi@0.1.2.0 · 268 lines · 0 definitions

1# bend-osdev-acpi, example.bend: AcpiExample, a small x86 machine's tables
2# built with this package's writers, for the tests and as a guide: an RSDP
3# leading to an XSDT (and an RSDT), an FADT, FACS, MADT, HPET, MCFG, SRAT,
4# SLIT, BGRT, an SSDT, and a DSDT in AML that has a PCI host bridge with
5# _HID, _CID, _CRS and _PRT, an LPC bridge whose PIRQ routing registers are
6# a PCI_Config field, a PCI interrupt link device whose _STA and _CRS read
7# them (the CreateWordField pattern), an embedded controller with an
8# EmbeddedControl region and a query method that sends a Notify, a thermal
9# zone, a power button and a processor device. Its shape follows the
10# examples of ACPI 6.5, sections 6.2.13 (_PRT), 6.4 (resource templates)
11# and 11 (thermal zones).
12import Base
13import bend-osdev-word64@0.1.1.1/word64.bend as W
14import bend-osdev-bytes@0.1.1.1/bytes.bend as B
15import bend-osdev-acpi@0.1.2.0/header.bend as H
16import bend-osdev-acpi@0.1.2.0/rsdp.bend as P
17import bend-osdev-acpi@0.1.2.0/rsdt.bend as S
18import bend-osdev-acpi@0.1.2.0/fadt.bend as F
19import bend-osdev-acpi@0.1.2.0/facs.bend as FS
20import bend-osdev-acpi@0.1.2.0/gas.bend as G
21import bend-osdev-acpi@0.1.2.0/madt.bend as M
22import bend-osdev-acpi@0.1.2.0/hpet.bend as Hp
23import bend-osdev-acpi@0.1.2.0/mcfg.bend as Mc
24import bend-osdev-acpi@0.1.2.0/srat.bend as Sr
25import bend-osdev-acpi@0.1.2.0/slit.bend as Sl
26import bend-osdev-acpi@0.1.2.0/bgrt.bend as Bg
27import bend-osdev-acpi@0.1.2.0/dsdt.bend as D
28import bend-osdev-acpi@0.1.2.0/acpi.bend as A
29import bend-osdev-acpi@0.1.2.0/aml_term.bend as T
30import bend-osdev-acpi@0.1.2.0/aml_resource.bend as R
31import bend-osdev-acpi@0.1.2.0/aml_host.bend as Hs
32
33def ex.hdr(s: String, r: U32) -> H.AcpiHeader:
34  H.AcpiHeader.make(B.Octets.of_string(s), r, B.Octets.of_string("BENDOS"), B.Octets.of_string("EXAMPLE"))
35
36def ex.i(v: U32) -> T.AmlTerm:
37  T.AmlT.int32(v)
38
39# Physical addresses
40def AcpiExample.rsdp_address() -> W.W64:
41  W.W64.from_u32(917520)
42
43def AcpiExample.base() -> U32:
44  1048576
45
46def ex.at(off: U32) -> U32:
47  U32.add(AcpiExample.base(), off)
48
49def ex.at64(+off: U32) -> W.W64:
50  W.W64.from_u32(ex.at(off))
51
52# the offsets of the tables from the base
53def ex.xsdt() -> U32:
54  0
55
56def ex.rsdt() -> U32:
57  256
58
59def ex.fadt() -> U32:
60  512
61
62def ex.facs() -> U32:
63  1024
64
65def ex.madt() -> U32:
66  1280
67
68def ex.hpet() -> U32:
69  1536
70
71def ex.mcfg() -> U32:
72  1664
73
74def ex.srat() -> U32:
75  1792
76
77def ex.slit() -> U32:
78  2048
79
80def ex.bgrt() -> U32:
81  2176
82
83def ex.ssdt() -> U32:
84  2304
85
86def ex.dsdt() -> U32:
87  3072
88
89# The DSDT
90
91def ex.lnk.crs() -> List<&2, T.AmlTerm>:
92  [T.AmlT.name("RTLA", T.AmlT.buf(R.AmlResource.template([R.AmlRIrq{0, 24}]))),
93   T.AmlT.create_field(139, T.AmlT.nm("RTLA"), T.AmlT.one(), "IRQ0"),
94   T.AmlT.store(T.AmlT.zero(), T.AmlT.nm("IRQ0")),
95   T.AmlT.shift_left(T.AmlT.one(), T.AmlT.and(T.AmlT.nm("^^PCI0.LPCB.PIRA"), ex.i(15), T.AmlT.none()), T.AmlT.nm("IRQ0")),
96   T.AmlT.ret(T.AmlT.nm("RTLA"))]
97
98def ex.lnka() -> T.AmlTerm:
99  T.AmlT.device("LNKA", [
100    T.AmlT.name("_HID", T.AmlT.eisaid("PNP0C0F")),
101    T.AmlT.name("_UID", T.AmlT.one()),
102    T.AmlT.method("_STA", 0n, False{}, [T.AmlT.if_else(T.AmlT.and(T.AmlT.nm("^^PCI0.LPCB.PIRA"), ex.i(128), T.AmlT.none()), [T.AmlT.ret(ex.i(9))], [T.AmlT.ret(ex.i(11))])]),
103    T.AmlT.method("_CRS", 0n, True{}, ex.lnk.crs())])
104
105def ex.pci.crs() -> B.Octets:
106  R.AmlResource.template([
107    R.AmlRAddr{16, 2, 12, 0, R.AmlRange{W.W64.zero(), W.W64.zero(), W.W64.from_u32(255), W.W64.zero(), W.W64.from_u32(256)}},
108    R.AmlRIo{1, 3320, 3320, 1, 8},
109    R.AmlRAddr{16, 1, 12, 3, R.AmlRange{W.W64.zero(), W.W64.zero(), W.W64.from_u32(3319), W.W64.zero(), W.W64.from_u32(3320)}},
110    R.AmlRAddr{32, 0, 12, 1, R.AmlRange{W.W64.zero(), W.W64.from_u32(2147483648), W.W64.from_u32(4273995775), W.W64.zero(), W.W64.from_u32(2126512128)}}])
111
112def ex.prt() -> T.AmlTerm:
113  T.AmlT.package([
114    T.AmlT.package([ex.i(131071), T.AmlT.zero(), T.AmlT.nm("^LNKA"), T.AmlT.zero()]),
115    T.AmlT.package([ex.i(131071), T.AmlT.one(), T.AmlT.zero(), ex.i(17)]),
116    T.AmlT.package([ex.i(2031615), T.AmlT.zero(), T.AmlT.zero(), ex.i(16)])])
117
118def ex.ec() -> T.AmlTerm:
119  T.AmlT.device("EC0_", [
120    T.AmlT.name("_HID", T.AmlT.eisaid("PNP0C09")),
121    T.AmlT.name("_CRS", T.AmlT.buf(R.AmlResource.template([R.AmlRIo{1, 98, 98, 0, 1}, R.AmlRIo{1, 102, 102, 0, 1}]))),
122    T.AmlT.name("_GPE", ex.i(23)),
123    T.AmlT.region("ECOR", 3, T.AmlT.zero(), ex.i(256)),
124    T.AmlT.field("ECOR", T.AmlT.field_flags(1, True{}, 0), [T.AmlFReserved{128}, T.AmlT.fnamed("TMP0", 8), T.AmlT.fnamed("FAN0", 1), T.AmlT.fnamed("LID0", 1)]),
125    T.AmlT.method("_Q01", 0n, False{}, [T.AmlT.notify(T.AmlT.nm("\\_TZ.TZ00"), ex.i(128))])])
126
127def ex.lpcb() -> T.AmlTerm:
128  T.AmlT.device("LPCB", [
129    T.AmlT.name("_ADR", ex.i(2031616)),
130    T.AmlT.region("LPCR", 2, ex.i(96), ex.i(4)),
131    T.AmlT.field("LPCR", T.AmlT.field_flags(1, False{}, 0), [T.AmlT.fnamed("PIRA", 8), T.AmlT.fnamed("PIRB", 8), T.AmlT.fnamed("PIRC", 8), T.AmlT.fnamed("PIRD", 8)]),
132    ex.ec()])
133
134def ex.pci0() -> T.AmlTerm:
135  T.AmlT.device("PCI0", [
136    T.AmlT.name("_HID", T.AmlT.eisaid("PNP0A08")),
137    T.AmlT.name("_CID", T.AmlT.eisaid("PNP0A03")),
138    T.AmlT.name("_ADR", T.AmlT.zero()),
139    T.AmlT.name("_BBN", T.AmlT.zero()),
140    T.AmlT.name("_UID", T.AmlT.zero()),
141    T.AmlT.name("_CRS", T.AmlT.buf(ex.pci.crs())),
142    T.AmlT.name("_PRT", ex.prt()),
143    ex.lpcb()])
144
145def ex.osys() -> T.AmlTerm:
146  T.AmlT.method("OSYS", 0n, False{}, [
147    T.AmlT.store(ex.i(2000), T.AmlT.local(0)),
148    T.AmlT.if_(T.AmlT.call("\\_OSI", [T.AmlT.str("Windows 2015")]), [T.AmlT.store(ex.i(2015), T.AmlT.local(0))]),
149    T.AmlT.if_(T.AmlT.call("\\_OSI", [T.AmlT.str("Linux")]), [T.AmlT.store(ex.i(1), T.AmlT.local(0))]),
150    T.AmlT.ret(T.AmlT.local(0))])
151
152# the DSDT's terms
153def AcpiExample.dsdt_terms() -> List<&2, T.AmlTerm>:
154  [T.AmlT.scope("\\_SB", [
155     ex.pci0(),
156     ex.lnka(),
157     T.AmlT.device("PWRB", [T.AmlT.name("_HID", T.AmlT.eisaid("PNP0C0C"))]),
158     T.AmlT.device("CPU0", [T.AmlT.name("_HID", T.AmlT.str("ACPI0007")), T.AmlT.name("_UID", T.AmlT.zero())]),
159     ex.osys(),
160     T.AmlT.method("SUM_", 1n, False{}, [
161       T.AmlT.store(T.AmlT.zero(), T.AmlT.local(0)),
162       T.AmlT.store(T.AmlT.zero(), T.AmlT.local(1)),
163       T.AmlT.while_(T.AmlT.lless_equal(T.AmlT.local(1), T.AmlT.arg(0)), [
164         T.AmlT.add(T.AmlT.local(0), T.AmlT.local(1), T.AmlT.local(0)),
165         T.AmlT.increment(T.AmlT.local(1))]),
166       T.AmlT.ret(T.AmlT.local(0))]),
167     T.AmlT.method("SPIN", 0n, False{}, [T.AmlT.while_(T.AmlT.one(), [T.AmlT.noop()])])]),
168   T.AmlT.scope("\\_TZ", [
169     T.AmlT.thermal_zone("TZ00", [
170       T.AmlT.method("_TMP", 0n, False{}, [T.AmlT.ret(T.AmlT.add(T.AmlT.multiply(T.AmlT.nm("\\_SB.PCI0.LPCB.EC0.TMP0"), ex.i(10), T.AmlT.none()), ex.i(2732), T.AmlT.none()))]),
171       T.AmlT.name("_CRT", ex.i(3732))])])]
172
173def AcpiExample.dsdt_aml() -> B.Octets:
174  T.AmlT.encode(AcpiExample.dsdt_terms())
175
176def AcpiExample.dsdt() -> D.AcpiAml:
177  D.AcpiAml{ex.hdr("DSDT", 2), AcpiExample.dsdt_aml()}
178
179# an SSDT that adds a device to a scope the DSDT defines
180def AcpiExample.ssdt() -> D.AcpiAml:
181  D.AcpiAml{ex.hdr("SSDT", 2), T.AmlT.encode([
182    T.AmlT.external("\\_SB.PCI0", 6, 0),
183    T.AmlT.scope("\\_SB.PCI0", [T.AmlT.device("GFX0", [T.AmlT.name("_ADR", ex.i(131072)), T.AmlT.method("_STA", 0n, False{}, [T.AmlT.ret(ex.i(15))])])])])}
184
185# The other tables
186
187def ex.blocks() -> F.AcpiFadtBlocks:
188  F.AcpiFadtBlocks{1536, 0, 1540, 0, 1616, 1544, 1568, 0}
189
190def ex.lens() -> F.AcpiFadtLens:
191  F.AcpiFadtLens{4, 2, 1, 4, 16, 0, 0}
192
193def ex.io(+port: U32, +len: U32) -> G.AcpiGas:
194  G.AcpiGas{1, U32.mul(len, 8), 0, 0, W.W64.from_u32(port)}
195
196def AcpiExample.fadt() -> F.AcpiFadt:
197  +z = G.AcpiGas.zero()
198  +core = {F.AcpiFadtCore{ex.at(ex.facs()), ex.at(ex.dsdt()), 0, 1, 9, 178, 240, 241, 0, 0, ex.blocks(), ex.lens(), 0, 101, 1001, 0, 0, 1, 3, 13, 0, 50, 3, 34101} : F.AcpiFadtCore}
199  +x = {F.AcpiFadtX{ex.io(1536, 4), z, ex.io(1540, 2), z, ex.io(1616, 1), ex.io(1544, 4), ex.io(1568, 16), z} : F.AcpiFadtX}
200  F.AcpiFadt{ex.hdr("FACP", 6), core, Some{F.AcpiFadtExt{G.AcpiGas{1, 8, 0, 1, W.W64.from_u32(3321)}, 6, 0, 5, ex.at64(ex.facs()), ex.at64(ex.dsdt()), x}}, Some{F.AcpiFadtSleep{z, z}}, Some{W.W64.zero()}}
201
202def AcpiExample.facs() -> FS.AcpiFacs:
203  FS.AcpiFacs{64, 305419896, 0, 0, 0, W.W64.zero(), 2, 0}
204
205def AcpiExample.madt() -> M.AcpiMadt:
206  M.AcpiMadt{ex.hdr("APIC", 5), 4276092928, 1, {[M.AcpiMadtLapic{0, 0, 1}, M.AcpiMadtLapic{1, 1, 1}, M.AcpiMadtIoApic{2, 4273995776, 0}, M.AcpiMadtIso{0, 0, 2, 0}, M.AcpiMadtIso{0, 9, 9, 13}, M.AcpiMadtLapicNmi{255, 5, 1}, M.AcpiMadtX2apic{256, 1, 2}] : List<&2, M.AcpiMadtEntry>}}
207
208def AcpiExample.hpet() -> Hp.AcpiHpet:
209  Hp.AcpiHpet{ex.hdr("HPET", 1), 2156306945, G.AcpiGas{0, 64, 0, 0, W.W64.from_u32(4275044352)}, 0, 14318, 0}
210
211def AcpiExample.mcfg() -> Mc.AcpiMcfg:
212  Mc.AcpiMcfg{ex.hdr("MCFG", 1), [Mc.AcpiMcfgEntry{W.W64.from_u32(3758096384), 0, 0, 255}]}
213
214def AcpiExample.srat() -> Sr.AcpiSrat:
215  Sr.AcpiSrat{ex.hdr("SRAT", 3), {[Sr.AcpiSratLapic{0, 0, 1, 0, 0}, Sr.AcpiSratLapic{1, 1, 1, 0, 0}, Sr.AcpiSratMemory{0, W.W64.zero(), W.W64.from_u32(2147483648), 1}, Sr.AcpiSratMemory{1, W.W64.from_parts(1, 0), W.W64.from_u32(2147483648), 1}] : List<&2, Sr.AcpiSratEntry>}}
216
217def AcpiExample.slit() -> Sl.AcpiSlit:
218  Sl.AcpiSlit{ex.hdr("SLIT", 1), 2n, B.Octets.of_list([10, 21, 21, 10])}
219
220def AcpiExample.bgrt() -> Bg.AcpiBgrt:
221  Bg.AcpiBgrt{ex.hdr("BGRT", 1), 1, 1, 0, W.W64.from_u32(2113929216), 100, 200}
222
223def AcpiExample.rsdp() -> P.AcpiRsdp:
224  P.AcpiRsdp{B.Octets.of_string("BENDOS"), 2, ex.at(ex.rsdt()), Some{P.AcpiRsdpExt{36, ex.at64(ex.xsdt())}}}
225
226def ex.listed() -> List<&2, W.W64>:
227  [ex.at64(ex.fadt()), ex.at64(ex.madt()), ex.at64(ex.hpet()), ex.at64(ex.mcfg()), ex.at64(ex.srat()), ex.at64(ex.slit()), ex.at64(ex.bgrt()), ex.at64(ex.ssdt())]
228
229# each table as bytes, with its offset from the base
230type AcpiExamplePiece is Data:
231  AcpiExamplePiece{offset: U32, bytes: B.Octets}
232
233def AcpiExample.pieces() -> List<&2, AcpiExamplePiece>:
234  [AcpiExamplePiece{ex.xsdt(), S.AcpiXsdt.build(ex.hdr("XSDT", 1), ex.listed())},
235   AcpiExamplePiece{ex.rsdt(), S.AcpiRsdt.build(ex.hdr("RSDT", 1), ex.listed())},
236   AcpiExamplePiece{ex.fadt(), F.AcpiFadt.build(AcpiExample.fadt())},
237   AcpiExamplePiece{ex.facs(), FS.AcpiFacs.build(AcpiExample.facs())},
238   AcpiExamplePiece{ex.madt(), M.AcpiMadt.build(AcpiExample.madt())},
239   AcpiExamplePiece{ex.hpet(), Hp.AcpiHpet.build(AcpiExample.hpet())},
240   AcpiExamplePiece{ex.mcfg(), Mc.AcpiMcfg.build(AcpiExample.mcfg())},
241   AcpiExamplePiece{ex.srat(), Sr.AcpiSrat.build(AcpiExample.srat())},
242   AcpiExamplePiece{ex.slit(), Sl.AcpiSlit.build(AcpiExample.slit())},
243   AcpiExamplePiece{ex.bgrt(), Bg.AcpiBgrt.build(AcpiExample.bgrt())},
244   AcpiExamplePiece{ex.ssdt(), D.AcpiAml.build(AcpiExample.ssdt())},
245   AcpiExamplePiece{ex.dsdt(), D.AcpiAml.build(AcpiExample.dsdt())}]
246
247# the pieces laid out from offset at, zeros between them
248def ex.lay(ps: List<&2, AcpiExamplePiece>, +at: Nat) -> List<&2, B.Octets>:
249  match ps:
250    case Nil{}:
251      Nil{}
252    case Con{AcpiExamplePiece{off, +o}, t}:
253      +gap = Nat.sub(U32.to_nat(off), at)
254      Con{B.Octets.zeros(gap), Con{o, ex.lay(t, Nat.add(Nat.add(at, gap), B.Octets.len(o)))}}
255
256def AcpiExample.region() -> B.Octets:
257  B.Octets.concat(ex.lay(AcpiExample.pieces(), 0n))
258
259# physical memory: the RSDP at 0xE0010, the tables from 0x100000
260def AcpiExample.memory() -> A.AcpiMemImage:
261  A.AcpiMemImage{[A.AcpiMemRegion{W.W64.from_u32(917504), B.Octets.append(B.Octets.zeros(16n), P.AcpiRsdp.build(AcpiExample.rsdp()))}, A.AcpiMemRegion{W.W64.from_u32(AcpiExample.base()), AcpiExample.region()}]}
262
263# the host the DSDT runs against: the LPC bridge's PIRQ registers (PCI
264# config space of device 0x1F, from offset 0x60: PIRQA routed to IRQ 11,
265# PIRQB disabled) and the EC's temperature byte (offset 0x10: 30 degrees)
266def AcpiExample.host() -> Hs.AmlMemHost:
267  +pci = Hs.AmlMemHost.poke(Hs.AmlMemHost.new(), 2, W.W64.add(Hs.AmlPci.address(0, 0, 31, 0, 0), W.W64.from_u32(96)), B.Octets.of_list([11, 128, 10, 5]))
268  Hs.AmlMemHost.poke(pci, 3, W.W64.from_u32(16), B.Octets.of_list([30]))