debuggers.hg

view tools/firmware/hvmloader/acpi/build.c @ 20978:363bbf511573

hvmloader: Remove checked-in ready-compiled SSDT_PM and SSDT_TPM.

These can be built at the same time as the DSDT.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Feb 11 21:49:47 2010 +0000 (2010-02-11)
parents 5ea096ef7603
children a259e779467c
line source
1 /*
2 * Copyright (c) 2004, Intel Corporation.
3 * Copyright (c) 2006, Keir Fraser, XenSource Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License, version
7 * 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT ANY
10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12 * details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307 USA.
17 */
19 #include "acpi2_0.h"
20 #include "ssdt_tpm.h"
21 #include "ssdt_pm.h"
22 #include "../config.h"
23 #include "../util.h"
25 #define align16(sz) (((sz) + 15) & ~15)
26 #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
28 /* MADT parameters for filling in bios_info structure for DSDT. */
29 uint32_t madt_csum_addr, madt_lapic0_addr;
31 extern struct acpi_20_rsdp Rsdp;
32 extern struct acpi_20_rsdt Rsdt;
33 extern struct acpi_20_xsdt Xsdt;
34 extern struct acpi_20_fadt Fadt;
35 extern struct acpi_20_facs Facs;
36 extern unsigned char Dsdt[];
37 extern int DsdtLen;
39 static void set_checksum(
40 void *table, uint32_t checksum_offset, uint32_t length)
41 {
42 uint8_t *p, sum = 0;
44 p = table;
45 p[checksum_offset] = 0;
47 while ( length-- )
48 sum = sum + *p++;
50 p = table;
51 p[checksum_offset] = -sum;
52 }
54 static uint8_t battery_port_exists(void)
55 {
56 return (inb(0x88) == 0x1F);
57 }
59 static int construct_madt(struct acpi_20_madt *madt)
60 {
61 struct acpi_20_madt_intsrcovr *intsrcovr;
62 struct acpi_20_madt_ioapic *io_apic;
63 struct acpi_20_madt_lapic *lapic;
64 int i, offset = 0;
66 memset(madt, 0, sizeof(*madt));
67 madt->header.signature = ACPI_2_0_MADT_SIGNATURE;
68 madt->header.revision = ACPI_2_0_MADT_REVISION;
69 fixed_strcpy(madt->header.oem_id, ACPI_OEM_ID);
70 fixed_strcpy(madt->header.oem_table_id, ACPI_OEM_TABLE_ID);
71 madt->header.oem_revision = ACPI_OEM_REVISION;
72 madt->header.creator_id = ACPI_CREATOR_ID;
73 madt->header.creator_revision = ACPI_CREATOR_REVISION;
74 madt->lapic_addr = LAPIC_BASE_ADDRESS;
75 madt->flags = ACPI_PCAT_COMPAT;
76 offset += sizeof(*madt);
78 intsrcovr = (struct acpi_20_madt_intsrcovr *)(madt + 1);
79 for ( i = 0; i < 16; i++ )
80 {
81 memset(intsrcovr, 0, sizeof(*intsrcovr));
82 intsrcovr->type = ACPI_INTERRUPT_SOURCE_OVERRIDE;
83 intsrcovr->length = sizeof(*intsrcovr);
84 intsrcovr->source = i;
86 if ( i == 0 )
87 {
88 /* ISA IRQ0 routed to IOAPIC GSI 2. */
89 intsrcovr->gsi = 2;
90 intsrcovr->flags = 0x0;
91 }
92 else if ( PCI_ISA_IRQ_MASK & (1U << i) )
93 {
94 /* PCI: active-low level-triggered. */
95 intsrcovr->gsi = i;
96 intsrcovr->flags = 0xf;
97 }
98 else
99 {
100 /* No need for a INT source override structure. */
101 continue;
102 }
104 offset += sizeof(*intsrcovr);
105 intsrcovr++;
106 }
108 io_apic = (struct acpi_20_madt_ioapic *)intsrcovr;
109 memset(io_apic, 0, sizeof(*io_apic));
110 io_apic->type = ACPI_IO_APIC;
111 io_apic->length = sizeof(*io_apic);
112 io_apic->ioapic_id = IOAPIC_ID;
113 io_apic->ioapic_addr = IOAPIC_BASE_ADDRESS;
114 offset += sizeof(*io_apic);
116 lapic = (struct acpi_20_madt_lapic *)(io_apic + 1);
117 madt_lapic0_addr = (uint32_t)lapic;
118 for ( i = 0; i < HVM_MAX_VCPUS; i++ )
119 {
120 memset(lapic, 0, sizeof(*lapic));
121 lapic->type = ACPI_PROCESSOR_LOCAL_APIC;
122 lapic->length = sizeof(*lapic);
123 /* Processor ID must match processor-object IDs in the DSDT. */
124 lapic->acpi_processor_id = i;
125 lapic->apic_id = LAPIC_ID(i);
126 lapic->flags = ((i < hvm_info->nr_vcpus) &&
127 test_bit(i, hvm_info->vcpu_online)
128 ? ACPI_LOCAL_APIC_ENABLED : 0);
129 offset += sizeof(*lapic);
130 lapic++;
131 }
133 madt->header.length = offset;
134 set_checksum(madt, offsetof(struct acpi_header, checksum), offset);
135 madt_csum_addr = (uint32_t)&madt->header.checksum;
137 return align16(offset);
138 }
140 static int construct_hpet(struct acpi_20_hpet *hpet)
141 {
142 int offset;
144 memset(hpet, 0, sizeof(*hpet));
145 hpet->header.signature = ACPI_2_0_HPET_SIGNATURE;
146 hpet->header.revision = ACPI_2_0_HPET_REVISION;
147 fixed_strcpy(hpet->header.oem_id, ACPI_OEM_ID);
148 fixed_strcpy(hpet->header.oem_table_id, ACPI_OEM_TABLE_ID);
149 hpet->header.oem_revision = ACPI_OEM_REVISION;
150 hpet->header.creator_id = ACPI_CREATOR_ID;
151 hpet->header.creator_revision = ACPI_CREATOR_REVISION;
152 hpet->timer_block_id = 0x8086a201;
153 hpet->addr.address = ACPI_HPET_ADDRESS;
154 offset = sizeof(*hpet);
156 hpet->header.length = offset;
157 set_checksum(hpet, offsetof(struct acpi_header, checksum), offset);
159 return offset;
160 }
162 static int construct_secondary_tables(uint8_t *buf, unsigned long *table_ptrs)
163 {
164 int offset = 0, nr_tables = 0;
165 struct acpi_20_madt *madt;
166 struct acpi_20_hpet *hpet;
167 struct acpi_20_tcpa *tcpa;
168 static const uint16_t tis_signature[] = {0x0001, 0x0001, 0x0001};
169 uint16_t *tis_hdr;
170 void *lasa;
172 /* MADT. */
173 if ( (hvm_info->nr_vcpus > 1) || hvm_info->apic_mode )
174 {
175 madt = (struct acpi_20_madt *)&buf[offset];
176 offset += construct_madt(madt);
177 table_ptrs[nr_tables++] = (unsigned long)madt;
178 }
180 /* HPET. */
181 if ( hpet_exists(ACPI_HPET_ADDRESS) )
182 {
183 hpet = (struct acpi_20_hpet *)&buf[offset];
184 offset += construct_hpet(hpet);
185 table_ptrs[nr_tables++] = (unsigned long)hpet;
186 }
188 if ( battery_port_exists() )
189 {
190 table_ptrs[nr_tables++] = (unsigned long)&buf[offset];
191 memcpy(&buf[offset], ssdt_pm, sizeof(ssdt_pm));
192 offset += align16(sizeof(ssdt_pm));
193 }
195 /* TPM TCPA and SSDT. */
196 tis_hdr = (uint16_t *)0xFED40F00;
197 if ( (tis_hdr[0] == tis_signature[0]) &&
198 (tis_hdr[1] == tis_signature[1]) &&
199 (tis_hdr[2] == tis_signature[2]) )
200 {
201 memcpy(&buf[offset], ssdt_tpm, sizeof(ssdt_tpm));
202 table_ptrs[nr_tables++] = (unsigned long)&buf[offset];
203 offset += align16(sizeof(ssdt_tpm));
205 tcpa = (struct acpi_20_tcpa *)&buf[offset];
206 memset(tcpa, 0, sizeof(*tcpa));
207 offset += align16(sizeof(*tcpa));
208 table_ptrs[nr_tables++] = (unsigned long)tcpa;
210 tcpa->header.signature = ACPI_2_0_TCPA_SIGNATURE;
211 tcpa->header.length = sizeof(*tcpa);
212 tcpa->header.revision = ACPI_2_0_TCPA_REVISION;
213 fixed_strcpy(tcpa->header.oem_id, ACPI_OEM_ID);
214 fixed_strcpy(tcpa->header.oem_table_id, ACPI_OEM_TABLE_ID);
215 tcpa->header.oem_revision = ACPI_OEM_REVISION;
216 tcpa->header.creator_id = ACPI_CREATOR_ID;
217 tcpa->header.creator_revision = ACPI_CREATOR_REVISION;
218 if ( (lasa = mem_alloc(ACPI_2_0_TCPA_LAML_SIZE, 0)) != NULL )
219 {
220 tcpa->lasa = virt_to_phys(lasa);
221 tcpa->laml = ACPI_2_0_TCPA_LAML_SIZE;
222 memset(lasa, 0, tcpa->laml);
223 set_checksum(tcpa,
224 offsetof(struct acpi_header, checksum),
225 tcpa->header.length);
226 }
227 }
229 table_ptrs[nr_tables] = 0;
230 return align16(offset);
231 }
233 static void __acpi_build_tables(uint8_t *buf, int *low_sz, int *high_sz)
234 {
235 struct acpi_20_rsdp *rsdp;
236 struct acpi_20_rsdt *rsdt;
237 struct acpi_20_xsdt *xsdt;
238 struct acpi_20_fadt *fadt;
239 struct acpi_10_fadt *fadt_10;
240 struct acpi_20_facs *facs;
241 unsigned char *dsdt;
242 unsigned long secondary_tables[16];
243 int offset = 0, i;
245 /*
246 * Fill in high-memory data structures, starting at @buf.
247 */
249 facs = (struct acpi_20_facs *)&buf[offset];
250 memcpy(facs, &Facs, sizeof(struct acpi_20_facs));
251 offset += align16(sizeof(struct acpi_20_facs));
253 dsdt = (unsigned char *)&buf[offset];
254 memcpy(dsdt, &Dsdt, DsdtLen);
255 offset += align16(DsdtLen);
257 /*
258 * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
259 * or above properly, notably Windows 2000, which tries to copy FADT
260 * into a 116 bytes buffer thus causing an overflow. The solution is to
261 * link the higher revision FADT with the XSDT only and introduce a
262 * compatible revision 1 FADT that is linked with the RSDT. Refer to:
263 * http://www.acpi.info/presentations/S01USMOBS169_OS%20new.ppt
264 */
265 fadt_10 = (struct acpi_10_fadt *)&buf[offset];
266 memcpy(fadt_10, &Fadt, sizeof(struct acpi_10_fadt));
267 offset += align16(sizeof(struct acpi_10_fadt));
268 fadt_10->header.length = sizeof(struct acpi_10_fadt);
269 fadt_10->header.revision = ACPI_1_0_FADT_REVISION;
270 fadt_10->dsdt = (unsigned long)dsdt;
271 fadt_10->firmware_ctrl = (unsigned long)facs;
272 set_checksum(fadt_10,
273 offsetof(struct acpi_header, checksum),
274 sizeof(struct acpi_10_fadt));
276 fadt = (struct acpi_20_fadt *)&buf[offset];
277 memcpy(fadt, &Fadt, sizeof(struct acpi_20_fadt));
278 offset += align16(sizeof(struct acpi_20_fadt));
279 fadt->dsdt = (unsigned long)dsdt;
280 fadt->x_dsdt = (unsigned long)dsdt;
281 fadt->firmware_ctrl = (unsigned long)facs;
282 fadt->x_firmware_ctrl = (unsigned long)facs;
283 set_checksum(fadt,
284 offsetof(struct acpi_header, checksum),
285 sizeof(struct acpi_20_fadt));
287 offset += construct_secondary_tables(&buf[offset], secondary_tables);
289 xsdt = (struct acpi_20_xsdt *)&buf[offset];
290 memcpy(xsdt, &Xsdt, sizeof(struct acpi_header));
291 xsdt->entry[0] = (unsigned long)fadt;
292 for ( i = 0; secondary_tables[i]; i++ )
293 xsdt->entry[i+1] = secondary_tables[i];
294 xsdt->header.length = sizeof(struct acpi_header) + (i+1)*sizeof(uint64_t);
295 offset += align16(xsdt->header.length);
296 set_checksum(xsdt,
297 offsetof(struct acpi_header, checksum),
298 xsdt->header.length);
300 rsdt = (struct acpi_20_rsdt *)&buf[offset];
301 memcpy(rsdt, &Rsdt, sizeof(struct acpi_header));
302 rsdt->entry[0] = (unsigned long)fadt_10;
303 for ( i = 0; secondary_tables[i]; i++ )
304 rsdt->entry[i+1] = secondary_tables[i];
305 rsdt->header.length = sizeof(struct acpi_header) + (i+1)*sizeof(uint32_t);
306 offset += align16(rsdt->header.length);
307 set_checksum(rsdt,
308 offsetof(struct acpi_header, checksum),
309 rsdt->header.length);
311 *high_sz = offset;
313 /*
314 * Fill in low-memory data structures: bios_info_table and RSDP.
315 */
317 buf = (uint8_t *)ACPI_PHYSICAL_ADDRESS;
318 offset = 0;
320 rsdp = (struct acpi_20_rsdp *)&buf[offset];
321 memcpy(rsdp, &Rsdp, sizeof(struct acpi_20_rsdp));
322 offset += align16(sizeof(struct acpi_20_rsdp));
323 rsdp->rsdt_address = (unsigned long)rsdt;
324 rsdp->xsdt_address = (unsigned long)xsdt;
325 set_checksum(rsdp,
326 offsetof(struct acpi_10_rsdp, checksum),
327 sizeof(struct acpi_10_rsdp));
328 set_checksum(rsdp,
329 offsetof(struct acpi_20_rsdp, extended_checksum),
330 sizeof(struct acpi_20_rsdp));
332 *low_sz = offset;
333 }
335 void acpi_build_tables(void)
336 {
337 int high_sz, low_sz;
338 uint8_t *buf;
340 /* Find out size of high-memory ACPI data area. */
341 buf = (uint8_t *)&_end;
342 __acpi_build_tables(buf, &low_sz, &high_sz);
343 memset(buf, 0, high_sz);
345 /* Allocate data area and set up ACPI tables there. */
346 buf = mem_alloc(high_sz, 0);
347 __acpi_build_tables(buf, &low_sz, &high_sz);
349 printf(" - Lo data: %08lx-%08lx\n"
350 " - Hi data: %08lx-%08lx\n",
351 (unsigned long)ACPI_PHYSICAL_ADDRESS,
352 (unsigned long)ACPI_PHYSICAL_ADDRESS + low_sz - 1,
353 (unsigned long)buf, (unsigned long)buf + high_sz - 1);
354 }
356 /*
357 * Local variables:
358 * mode: C
359 * c-set-style: "BSD"
360 * c-basic-offset: 4
361 * tab-width: 4
362 * indent-tabs-mode: nil
363 * End:
364 */