ia64/xen-unstable

view tools/firmware/hvmloader/acpi/build.c @ 19079:f3240cd3cd2b

rombios: Indirect through 32-bit jump table from within the 32-bit bios.

This gets rid of shenanigans with relocating the jump table around the
place.

Also clean up bios_info table while we are updating it.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jan 23 14:32:41 2009 +0000 (2009-01-23)
parents b84345ee0d41
children
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 extern struct acpi_20_rsdp Rsdp;
29 extern struct acpi_20_rsdt Rsdt;
30 extern struct acpi_20_xsdt Xsdt;
31 extern struct acpi_20_fadt Fadt;
32 extern struct acpi_20_facs Facs;
33 extern unsigned char AmlCode[];
34 extern int DsdtLen;
36 static void set_checksum(
37 void *table, uint32_t checksum_offset, uint32_t length)
38 {
39 uint8_t *p, sum = 0;
41 p = table;
42 p[checksum_offset] = 0;
44 while ( length-- )
45 sum = sum + *p++;
47 p = table;
48 p[checksum_offset] = -sum;
49 }
51 static uint8_t battery_port_exists(void)
52 {
53 return (inb(0x88) == 0x1F);
54 }
56 static int construct_madt(struct acpi_20_madt *madt)
57 {
58 struct acpi_20_madt_intsrcovr *intsrcovr;
59 struct acpi_20_madt_ioapic *io_apic;
60 struct acpi_20_madt_lapic *lapic;
61 int i, offset = 0;
63 memset(madt, 0, sizeof(*madt));
64 madt->header.signature = ACPI_2_0_MADT_SIGNATURE;
65 madt->header.revision = ACPI_2_0_MADT_REVISION;
66 fixed_strcpy(madt->header.oem_id, ACPI_OEM_ID);
67 fixed_strcpy(madt->header.oem_table_id, ACPI_OEM_TABLE_ID);
68 madt->header.oem_revision = ACPI_OEM_REVISION;
69 madt->header.creator_id = ACPI_CREATOR_ID;
70 madt->header.creator_revision = ACPI_CREATOR_REVISION;
71 madt->lapic_addr = LAPIC_BASE_ADDRESS;
72 madt->flags = ACPI_PCAT_COMPAT;
73 offset += sizeof(*madt);
75 intsrcovr = (struct acpi_20_madt_intsrcovr *)(madt + 1);
76 for ( i = 0; i < 16; i++ )
77 {
78 memset(intsrcovr, 0, sizeof(*intsrcovr));
79 intsrcovr->type = ACPI_INTERRUPT_SOURCE_OVERRIDE;
80 intsrcovr->length = sizeof(*intsrcovr);
81 intsrcovr->source = i;
83 if ( i == 0 )
84 {
85 /* ISA IRQ0 routed to IOAPIC GSI 2. */
86 intsrcovr->gsi = 2;
87 intsrcovr->flags = 0x0;
88 }
89 else if ( PCI_ISA_IRQ_MASK & (1U << i) )
90 {
91 /* PCI: active-low level-triggered. */
92 intsrcovr->gsi = i;
93 intsrcovr->flags = 0xf;
94 }
95 else
96 {
97 /* No need for a INT source override structure. */
98 continue;
99 }
101 offset += sizeof(*intsrcovr);
102 intsrcovr++;
103 }
105 io_apic = (struct acpi_20_madt_ioapic *)intsrcovr;
106 memset(io_apic, 0, sizeof(*io_apic));
107 io_apic->type = ACPI_IO_APIC;
108 io_apic->length = sizeof(*io_apic);
109 io_apic->ioapic_id = IOAPIC_ID;
110 io_apic->ioapic_addr = IOAPIC_BASE_ADDRESS;
111 offset += sizeof(*io_apic);
113 lapic = (struct acpi_20_madt_lapic *)(io_apic + 1);
114 for ( i = 0; i < hvm_info->nr_vcpus; i++ )
115 {
116 memset(lapic, 0, sizeof(*lapic));
117 lapic->type = ACPI_PROCESSOR_LOCAL_APIC;
118 lapic->length = sizeof(*lapic);
119 /* Processor ID must match processor-object IDs in the DSDT. */
120 lapic->acpi_processor_id = i;
121 lapic->apic_id = LAPIC_ID(i);
122 lapic->flags = ACPI_LOCAL_APIC_ENABLED;
123 offset += sizeof(*lapic);
124 lapic++;
125 }
127 madt->header.length = offset;
128 set_checksum(madt, offsetof(struct acpi_header, checksum), offset);
130 return align16(offset);
131 }
133 static int construct_hpet(struct acpi_20_hpet *hpet)
134 {
135 int offset;
137 memset(hpet, 0, sizeof(*hpet));
138 hpet->header.signature = ACPI_2_0_HPET_SIGNATURE;
139 hpet->header.revision = ACPI_2_0_HPET_REVISION;
140 fixed_strcpy(hpet->header.oem_id, ACPI_OEM_ID);
141 fixed_strcpy(hpet->header.oem_table_id, ACPI_OEM_TABLE_ID);
142 hpet->header.oem_revision = ACPI_OEM_REVISION;
143 hpet->header.creator_id = ACPI_CREATOR_ID;
144 hpet->header.creator_revision = ACPI_CREATOR_REVISION;
145 hpet->timer_block_id = 0x8086a201;
146 hpet->addr.address = ACPI_HPET_ADDRESS;
147 offset = sizeof(*hpet);
149 hpet->header.length = offset;
150 set_checksum(hpet, offsetof(struct acpi_header, checksum), offset);
152 return offset;
153 }
155 static int construct_secondary_tables(uint8_t *buf, unsigned long *table_ptrs)
156 {
157 int offset = 0, nr_tables = 0;
158 struct acpi_20_madt *madt;
159 struct acpi_20_hpet *hpet;
160 struct acpi_20_tcpa *tcpa;
161 static const uint16_t tis_signature[] = {0x0001, 0x0001, 0x0001};
162 uint16_t *tis_hdr;
163 void *lasa;
165 /* MADT. */
166 if ( (hvm_info->nr_vcpus > 1) || hvm_info->apic_mode )
167 {
168 madt = (struct acpi_20_madt *)&buf[offset];
169 offset += construct_madt(madt);
170 table_ptrs[nr_tables++] = (unsigned long)madt;
171 }
173 /* HPET. */
174 if ( hpet_exists(ACPI_HPET_ADDRESS) )
175 {
176 hpet = (struct acpi_20_hpet *)&buf[offset];
177 offset += construct_hpet(hpet);
178 table_ptrs[nr_tables++] = (unsigned long)hpet;
179 }
181 if ( battery_port_exists() )
182 {
183 table_ptrs[nr_tables++] = (unsigned long)&buf[offset];
184 memcpy(&buf[offset], AmlCode_PM, sizeof(AmlCode_PM));
185 offset += align16(sizeof(AmlCode_PM));
186 }
188 /* TPM TCPA and SSDT. */
189 tis_hdr = (uint16_t *)0xFED40F00;
190 if ( (tis_hdr[0] == tis_signature[0]) &&
191 (tis_hdr[1] == tis_signature[1]) &&
192 (tis_hdr[2] == tis_signature[2]) )
193 {
194 memcpy(&buf[offset], AmlCode_TPM, sizeof(AmlCode_TPM));
195 table_ptrs[nr_tables++] = (unsigned long)&buf[offset];
196 offset += align16(sizeof(AmlCode_TPM));
198 tcpa = (struct acpi_20_tcpa *)&buf[offset];
199 memset(tcpa, 0, sizeof(*tcpa));
200 offset += align16(sizeof(*tcpa));
201 table_ptrs[nr_tables++] = (unsigned long)tcpa;
203 tcpa->header.signature = ACPI_2_0_TCPA_SIGNATURE;
204 tcpa->header.length = sizeof(*tcpa);
205 tcpa->header.revision = ACPI_2_0_TCPA_REVISION;
206 fixed_strcpy(tcpa->header.oem_id, ACPI_OEM_ID);
207 fixed_strcpy(tcpa->header.oem_table_id, ACPI_OEM_TABLE_ID);
208 tcpa->header.oem_revision = ACPI_OEM_REVISION;
209 tcpa->header.creator_id = ACPI_CREATOR_ID;
210 tcpa->header.creator_revision = ACPI_CREATOR_REVISION;
211 if ( (lasa = mem_alloc(ACPI_2_0_TCPA_LAML_SIZE, 0)) != NULL )
212 {
213 tcpa->lasa = virt_to_phys(lasa);
214 tcpa->laml = ACPI_2_0_TCPA_LAML_SIZE;
215 memset(lasa, 0, tcpa->laml);
216 set_checksum(tcpa,
217 offsetof(struct acpi_header, checksum),
218 tcpa->header.length);
219 }
220 }
222 table_ptrs[nr_tables] = 0;
223 return align16(offset);
224 }
226 static void __acpi_build_tables(uint8_t *buf, int *low_sz, int *high_sz)
227 {
228 struct acpi_20_rsdp *rsdp;
229 struct acpi_20_rsdt *rsdt;
230 struct acpi_20_xsdt *xsdt;
231 struct acpi_20_fadt *fadt;
232 struct acpi_10_fadt *fadt_10;
233 struct acpi_20_facs *facs;
234 unsigned char *dsdt;
235 unsigned long secondary_tables[16];
236 int offset = 0, i;
238 /*
239 * Fill in high-memory data structures, starting at @buf.
240 */
242 facs = (struct acpi_20_facs *)&buf[offset];
243 memcpy(facs, &Facs, sizeof(struct acpi_20_facs));
244 offset += align16(sizeof(struct acpi_20_facs));
246 dsdt = (unsigned char *)&buf[offset];
247 memcpy(dsdt, &AmlCode, DsdtLen);
248 offset += align16(DsdtLen);
250 /*
251 * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
252 * or above properly, notably Windows 2000, which tries to copy FADT
253 * into a 116 bytes buffer thus causing an overflow. The solution is to
254 * link the higher revision FADT with the XSDT only and introduce a
255 * compatible revision 1 FADT that is linked with the RSDT. Refer to:
256 * http://www.acpi.info/presentations/S01USMOBS169_OS%20new.ppt
257 */
258 fadt_10 = (struct acpi_10_fadt *)&buf[offset];
259 memcpy(fadt_10, &Fadt, sizeof(struct acpi_10_fadt));
260 offset += align16(sizeof(struct acpi_10_fadt));
261 fadt_10->header.length = sizeof(struct acpi_10_fadt);
262 fadt_10->header.revision = ACPI_1_0_FADT_REVISION;
263 fadt_10->dsdt = (unsigned long)dsdt;
264 fadt_10->firmware_ctrl = (unsigned long)facs;
265 set_checksum(fadt_10,
266 offsetof(struct acpi_header, checksum),
267 sizeof(struct acpi_10_fadt));
269 fadt = (struct acpi_20_fadt *)&buf[offset];
270 memcpy(fadt, &Fadt, sizeof(struct acpi_20_fadt));
271 offset += align16(sizeof(struct acpi_20_fadt));
272 fadt->dsdt = (unsigned long)dsdt;
273 fadt->x_dsdt = (unsigned long)dsdt;
274 fadt->firmware_ctrl = (unsigned long)facs;
275 fadt->x_firmware_ctrl = (unsigned long)facs;
276 set_checksum(fadt,
277 offsetof(struct acpi_header, checksum),
278 sizeof(struct acpi_20_fadt));
280 offset += construct_secondary_tables(&buf[offset], secondary_tables);
282 xsdt = (struct acpi_20_xsdt *)&buf[offset];
283 memcpy(xsdt, &Xsdt, sizeof(struct acpi_header));
284 xsdt->entry[0] = (unsigned long)fadt;
285 for ( i = 0; secondary_tables[i]; i++ )
286 xsdt->entry[i+1] = secondary_tables[i];
287 xsdt->header.length = sizeof(struct acpi_header) + (i+1)*sizeof(uint64_t);
288 offset += align16(xsdt->header.length);
289 set_checksum(xsdt,
290 offsetof(struct acpi_header, checksum),
291 xsdt->header.length);
293 rsdt = (struct acpi_20_rsdt *)&buf[offset];
294 memcpy(rsdt, &Rsdt, sizeof(struct acpi_header));
295 rsdt->entry[0] = (unsigned long)fadt_10;
296 for ( i = 0; secondary_tables[i]; i++ )
297 rsdt->entry[i+1] = secondary_tables[i];
298 rsdt->header.length = sizeof(struct acpi_header) + (i+1)*sizeof(uint32_t);
299 offset += align16(rsdt->header.length);
300 set_checksum(rsdt,
301 offsetof(struct acpi_header, checksum),
302 rsdt->header.length);
304 *high_sz = offset;
306 /*
307 * Fill in low-memory data structures: bios_info_table and RSDP.
308 */
310 buf = (uint8_t *)ACPI_PHYSICAL_ADDRESS;
311 offset = 0;
313 rsdp = (struct acpi_20_rsdp *)&buf[offset];
314 memcpy(rsdp, &Rsdp, sizeof(struct acpi_20_rsdp));
315 offset += align16(sizeof(struct acpi_20_rsdp));
316 rsdp->rsdt_address = (unsigned long)rsdt;
317 rsdp->xsdt_address = (unsigned long)xsdt;
318 set_checksum(rsdp,
319 offsetof(struct acpi_10_rsdp, checksum),
320 sizeof(struct acpi_10_rsdp));
321 set_checksum(rsdp,
322 offsetof(struct acpi_20_rsdp, extended_checksum),
323 sizeof(struct acpi_20_rsdp));
325 *low_sz = offset;
326 }
328 void acpi_build_tables(void)
329 {
330 int high_sz, low_sz;
331 uint8_t *buf;
333 /* Find out size of high-memory ACPI data area. */
334 buf = (uint8_t *)&_end;
335 __acpi_build_tables(buf, &low_sz, &high_sz);
336 memset(buf, 0, high_sz);
338 /* Allocate data area and set up ACPI tables there. */
339 buf = mem_alloc(high_sz, 0);
340 __acpi_build_tables(buf, &low_sz, &high_sz);
342 printf(" - Lo data: %08lx-%08lx\n"
343 " - Hi data: %08lx-%08lx\n",
344 (unsigned long)ACPI_PHYSICAL_ADDRESS,
345 (unsigned long)ACPI_PHYSICAL_ADDRESS + low_sz - 1,
346 (unsigned long)buf, (unsigned long)buf + high_sz - 1);
347 }
349 /*
350 * Local variables:
351 * mode: C
352 * c-set-style: "BSD"
353 * c-basic-offset: 4
354 * tab-width: 4
355 * indent-tabs-mode: nil
356 * End:
357 */