Skip to content

Commit 9f90623

Browse files
committed
feat(cmd/rofl): Add support for building TDX ROFL apps
1 parent e6899c4 commit 9f90623

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1531
-2
lines changed

.golangci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ linters-settings:
7070
- github.com/stretchr/testify
7171
- github.com/tyler-smith/go-bip39
7272
- github.com/zondax/ledger-go
73+
- github.com/foxboron/go-uefi/authenticode
74+
- golang.org/x/text
7375
exhaustive:
7476
# Switch statements are to be considered exhaustive if a 'default' case is
7577
# present, even if all enum members aren't listed in the switch.

build/measurement/acpi/acpi.go

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
package acpi
2+
3+
import (
4+
"bytes"
5+
"embed"
6+
"encoding/binary"
7+
"encoding/hex"
8+
"encoding/json"
9+
"fmt"
10+
11+
"github.com/oasisprotocol/oasis-core/go/runtime/bundle"
12+
)
13+
14+
//go:embed *.hex *.json
15+
var templates embed.FS
16+
17+
// OffsetData is the offset data file format.
18+
type OffsetData struct {
19+
Memory MemoryOffsetData `json:"memory"`
20+
}
21+
22+
type MemoryOffsetData struct {
23+
RangeMinimumOffset int `json:"range_minimum_offset"`
24+
LengthOffset int `json:"length_offset"`
25+
}
26+
27+
// GenerateTablesQemu generates ACPI tables for the given TD configuration.
28+
//
29+
// Returns the raw ACPI tables, RSDP and QEMU table loader command blob.
30+
func GenerateTablesQemu(resources *bundle.TDXResources) ([]byte, []byte, []byte, error) {
31+
// Fetch template based on CPU count.
32+
fn := fmt.Sprintf("template_qemu_cpu%d.hex", resources.CPUCount)
33+
tplHex, err := templates.ReadFile(fn)
34+
if err != nil {
35+
return nil, nil, nil, fmt.Errorf("template for ACPI tables is not available")
36+
}
37+
38+
tpl, err := hex.DecodeString(string(tplHex))
39+
if err != nil {
40+
return nil, nil, nil, fmt.Errorf("malformed ACPI table template")
41+
}
42+
43+
// Fetch corresponding offset data.
44+
fn = fmt.Sprintf("template_qemu_cpu%d.json", resources.CPUCount)
45+
offsetData, err := templates.ReadFile(fn)
46+
if err != nil {
47+
return nil, nil, nil, fmt.Errorf("offset data for ACPI tables is not available")
48+
}
49+
50+
var od OffsetData
51+
if err = json.Unmarshal(offsetData, &od); err != nil {
52+
return nil, nil, nil, fmt.Errorf("malformed ACPI table offset data")
53+
}
54+
55+
// Handle memory split at 2816 MiB (0xB0000000).
56+
if resources.Memory >= 2816 {
57+
binary.LittleEndian.PutUint32(tpl[od.Memory.RangeMinimumOffset:], 0x80000000)
58+
binary.LittleEndian.PutUint32(tpl[od.Memory.LengthOffset:], 0x60000000)
59+
} else {
60+
memSizeBytes := uint32(resources.Memory * 1024 * 1024)
61+
binary.LittleEndian.PutUint32(tpl[od.Memory.RangeMinimumOffset:], memSizeBytes)
62+
binary.LittleEndian.PutUint32(tpl[od.Memory.LengthOffset:], 0xe0000000-memSizeBytes)
63+
}
64+
65+
// Generate RSDP.
66+
rsdp := append([]byte{},
67+
0x52, 0x53, 0x44, 0x20, 0x50, 0x54, 0x52, 0x20, // Signature ("RSDP PTR ").
68+
0x00, // Checksum.
69+
0x42, 0x4F, 0x43, 0x48, 0x53, 0x20, // OEM ID ("BOCHS ").
70+
0x00, // Revision.
71+
)
72+
73+
// Find all required ACPI tables.
74+
dsdtOffset, dsdtCsum, dsdtLen, err := findAcpiTable(tpl, "DSDT")
75+
if err != nil {
76+
return nil, nil, nil, err
77+
}
78+
facpOffset, facpCsum, facpLen, err := findAcpiTable(tpl, "FACP")
79+
if err != nil {
80+
return nil, nil, nil, err
81+
}
82+
apicOffset, apicCsum, apicLen, err := findAcpiTable(tpl, "APIC")
83+
if err != nil {
84+
return nil, nil, nil, err
85+
}
86+
mcfgOffset, mcfgCsum, mcfgLen, err := findAcpiTable(tpl, "MCFG")
87+
if err != nil {
88+
return nil, nil, nil, err
89+
}
90+
waetOffset, waetCsum, waetLen, err := findAcpiTable(tpl, "WAET")
91+
if err != nil {
92+
return nil, nil, nil, err
93+
}
94+
rsdtOffset, rsdtCsum, rsdtLen, err := findAcpiTable(tpl, "RSDT")
95+
if err != nil {
96+
return nil, nil, nil, err
97+
}
98+
99+
// Update RSDP with RSDT address.
100+
var rsdtAddress [4]byte
101+
binary.LittleEndian.PutUint32(rsdtAddress[:], rsdtOffset)
102+
rsdp = append(rsdp, rsdtAddress[:]...)
103+
104+
// Generate table loader commands.
105+
const ldrLength = 4096
106+
ldr := qemuLoaderAppend(nil, &qemuLoaderCmdAllocate{"etc/acpi/rsdp", 16, 2})
107+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAllocate{"etc/acpi/tables", 64, 1})
108+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddChecksum{"etc/acpi/tables", dsdtCsum, dsdtOffset, dsdtLen}) // DSDT
109+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddPtr{"etc/acpi/tables", "etc/acpi/tables", facpOffset + 36, 4})
110+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddPtr{"etc/acpi/tables", "etc/acpi/tables", facpOffset + 40, 4})
111+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddPtr{"etc/acpi/tables", "etc/acpi/tables", facpOffset + 140, 8})
112+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddChecksum{"etc/acpi/tables", facpCsum, facpOffset, facpLen}) // FACP
113+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddChecksum{"etc/acpi/tables", apicCsum, apicOffset, apicLen}) // APIC
114+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddChecksum{"etc/acpi/tables", mcfgCsum, mcfgOffset, mcfgLen}) // MCFG
115+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddChecksum{"etc/acpi/tables", waetCsum, waetOffset, waetLen}) // WAET
116+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddPtr{"etc/acpi/tables", "etc/acpi/tables", rsdtOffset + 36, 4})
117+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddPtr{"etc/acpi/tables", "etc/acpi/tables", rsdtOffset + 40, 4})
118+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddPtr{"etc/acpi/tables", "etc/acpi/tables", rsdtOffset + 44, 4})
119+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddPtr{"etc/acpi/tables", "etc/acpi/tables", rsdtOffset + 48, 4})
120+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddChecksum{"etc/acpi/tables", rsdtCsum, rsdtOffset, rsdtLen}) // RSDT
121+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddPtr{"etc/acpi/rsdp", "etc/acpi/tables", 16, 4}) // RSDT address
122+
ldr = qemuLoaderAppend(ldr, &qemuLoaderCmdAddChecksum{"etc/acpi/rsdp", 8, 0, 20}) // RSDP
123+
if len(ldr) < ldrLength {
124+
ldr = append(ldr, bytes.Repeat([]byte{0x00}, ldrLength-len(ldr))...)
125+
}
126+
127+
return tpl, rsdp, ldr, nil
128+
}
129+
130+
// findAcpiTable searches for the ACPI table with the given signature and returns its offset,
131+
// checksum offset and length.
132+
func findAcpiTable(tables []byte, signature string) (uint32, uint32, uint32, error) {
133+
// Walk the tables to find the right one.
134+
var offset int
135+
for {
136+
if offset >= len(tables) {
137+
return 0, 0, 0, fmt.Errorf("ACPI table '%s' not found", signature)
138+
}
139+
140+
tblSig := string(tables[offset : offset+4])
141+
tblLen := int(binary.LittleEndian.Uint32(tables[offset+4 : offset+8]))
142+
if tblSig == signature {
143+
return uint32(offset), uint32(offset + 9), uint32(tblLen), nil
144+
}
145+
146+
// Skip other tables.
147+
offset += tblLen
148+
}
149+
}
150+
151+
type qemuLoaderCmdAllocate struct {
152+
file string
153+
alignment uint32
154+
zone uint8
155+
}
156+
157+
type qemuLoaderCmdAddPtr struct {
158+
pointerFile string
159+
pointeeFile string
160+
pointerOffset uint32
161+
pointerSize uint8
162+
}
163+
164+
type qemuLoaderCmdAddChecksum struct {
165+
file string
166+
resultOffset uint32
167+
start uint32
168+
length uint32
169+
}
170+
171+
func qemuLoaderAppend(data []byte, cmd interface{}) []byte {
172+
appendFixedString := func(str string) {
173+
const fixedLength = 56
174+
data = append(data, []byte(str)...)
175+
if len(str) < fixedLength {
176+
data = append(data, bytes.Repeat([]byte{0x00}, fixedLength-len(str))...)
177+
}
178+
}
179+
180+
switch c := cmd.(type) {
181+
case *qemuLoaderCmdAllocate:
182+
data = append(data, 0x01, 0x00, 0x00, 0x00)
183+
184+
appendFixedString(c.file)
185+
186+
var val [4]byte
187+
binary.LittleEndian.PutUint32(val[:], c.alignment)
188+
data = append(data, val[:]...)
189+
190+
data = append(data, c.zone)
191+
data = append(data, bytes.Repeat([]byte{0x00}, 63)...) // Padding.
192+
case *qemuLoaderCmdAddPtr:
193+
data = append(data, 0x02, 0x00, 0x00, 0x00)
194+
195+
appendFixedString(c.pointerFile)
196+
appendFixedString(c.pointeeFile)
197+
198+
var val [4]byte
199+
binary.LittleEndian.PutUint32(val[:], c.pointerOffset)
200+
data = append(data, val[:]...)
201+
data = append(data, c.pointerSize)
202+
data = append(data, bytes.Repeat([]byte{0x00}, 7)...) // Padding.
203+
case *qemuLoaderCmdAddChecksum:
204+
data = append(data, 0x03, 0x00, 0x00, 0x00)
205+
206+
appendFixedString(c.file)
207+
208+
var val [4]byte
209+
binary.LittleEndian.PutUint32(val[:], c.resultOffset)
210+
data = append(data, val[:]...)
211+
212+
binary.LittleEndian.PutUint32(val[:], c.start)
213+
data = append(data, val[:]...)
214+
215+
binary.LittleEndian.PutUint32(val[:], c.length)
216+
data = append(data, val[:]...)
217+
218+
data = append(data, bytes.Repeat([]byte{0x00}, 56)...) // Padding.
219+
default:
220+
panic("unsupported command")
221+
}
222+
return data
223+
}

build/measurement/acpi/template_qemu_cpu1.hex

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"memory": {
3+
"range_minimum_offset": 7489,
4+
"length_offset": 7501
5+
}
6+
}

build/measurement/acpi/template_qemu_cpu10.hex

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"memory": {
3+
"range_minimum_offset": 8261,
4+
"length_offset": 8273
5+
}
6+
}

build/measurement/acpi/template_qemu_cpu11.hex

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"memory": {
3+
"range_minimum_offset": 8347,
4+
"length_offset": 8359
5+
}
6+
}

build/measurement/acpi/template_qemu_cpu12.hex

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"memory": {
3+
"range_minimum_offset": 8433,
4+
"length_offset": 8445
5+
}
6+
}

0 commit comments

Comments
 (0)