source: trunk/packages/xen-3.1/xen-3.1/tools/firmware/hvmloader/acpi/build.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 12.2 KB
Line 
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 */
18
19#include "acpi2_0.h"
20#include "ssdt_tpm.h"
21#include "../config.h"
22#include "../util.h"
23
24#define align16(sz)        (((sz) + 15) & ~15)
25#define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
26
27extern struct acpi_20_rsdp Rsdp;
28extern struct acpi_20_rsdt Rsdt;
29extern struct acpi_20_xsdt Xsdt;
30extern struct acpi_20_fadt Fadt;
31extern struct acpi_20_facs Facs;
32extern unsigned char AmlCode[];
33extern int DsdtLen;
34
35static void set_checksum(
36    void *table, uint32_t checksum_offset, uint32_t length)
37{
38    uint8_t *p, sum = 0;
39
40    p = table;
41    p[checksum_offset] = 0;
42
43    while ( length-- )
44        sum = sum + *p++;
45
46    p = table;
47    p[checksum_offset] = -sum;
48}
49
50int construct_madt(struct acpi_20_madt *madt)
51{
52    struct acpi_20_madt_intsrcovr *intsrcovr;
53    struct acpi_20_madt_ioapic    *io_apic;
54    struct acpi_20_madt_lapic     *lapic;
55    int i, offset = 0;
56
57    memset(madt, 0, sizeof(*madt));
58    madt->header.signature    = ACPI_2_0_MADT_SIGNATURE;
59    madt->header.revision     = ACPI_2_0_MADT_REVISION;
60    fixed_strcpy(madt->header.oem_id, ACPI_OEM_ID);
61    fixed_strcpy(madt->header.oem_table_id, ACPI_OEM_TABLE_ID);
62    madt->header.oem_revision = ACPI_OEM_REVISION;
63    madt->header.creator_id   = ACPI_CREATOR_ID;
64    madt->header.creator_revision = ACPI_CREATOR_REVISION;
65    madt->lapic_addr = LAPIC_BASE_ADDRESS;
66    madt->flags      = ACPI_PCAT_COMPAT;
67    offset += sizeof(*madt);
68
69    intsrcovr = (struct acpi_20_madt_intsrcovr *)(madt + 1);
70    for ( i = 0; i < 16; i++ )
71    {
72        memset(intsrcovr, 0, sizeof(*intsrcovr));
73        intsrcovr->type   = ACPI_INTERRUPT_SOURCE_OVERRIDE;
74        intsrcovr->length = sizeof(*intsrcovr);
75        intsrcovr->source = i;
76
77        if ( i == 0 )
78        {
79            /* ISA IRQ0 routed to IOAPIC GSI 2. */
80            intsrcovr->gsi    = 2;
81            intsrcovr->flags  = 0x0;
82        }
83        else if ( PCI_ISA_IRQ_MASK & (1U << i) )
84        {
85            /* PCI: active-low level-triggered. */
86            intsrcovr->gsi    = i;
87            intsrcovr->flags  = 0xf;
88        }
89        else
90        {
91            /* No need for a INT source override structure. */
92            continue;
93        }
94
95        offset += sizeof(*intsrcovr);
96        intsrcovr++;
97    }
98
99    io_apic = (struct acpi_20_madt_ioapic *)intsrcovr;
100    memset(io_apic, 0, sizeof(*io_apic));
101    io_apic->type        = ACPI_IO_APIC;
102    io_apic->length      = sizeof(*io_apic);
103    io_apic->ioapic_id   = IOAPIC_ID;
104    io_apic->ioapic_addr = IOAPIC_BASE_ADDRESS;
105    offset += sizeof(*io_apic);
106
107    lapic = (struct acpi_20_madt_lapic *)(io_apic + 1);
108    for ( i = 0; i < get_vcpu_nr(); i++ )
109    {
110        memset(lapic, 0, sizeof(*lapic));
111        lapic->type    = ACPI_PROCESSOR_LOCAL_APIC;
112        lapic->length  = sizeof(*lapic);
113        /* Processor ID must match processor-object IDs in the DSDT. */
114        lapic->acpi_processor_id = i;
115        lapic->apic_id = LAPIC_ID(i);
116        lapic->flags   = ACPI_LOCAL_APIC_ENABLED;
117        offset += sizeof(*lapic);
118        lapic++;
119    }
120
121    madt->header.length = offset;
122    set_checksum(madt, offsetof(struct acpi_header, checksum), offset);
123
124    return align16(offset);
125}
126
127int construct_hpet(struct acpi_20_hpet *hpet)
128{
129    int offset;
130
131    memset(hpet, 0, sizeof(*hpet));
132    hpet->header.signature    = ACPI_2_0_HPET_SIGNATURE;
133    hpet->header.revision     = ACPI_2_0_HPET_REVISION;
134    fixed_strcpy(hpet->header.oem_id, ACPI_OEM_ID);
135    fixed_strcpy(hpet->header.oem_table_id, ACPI_OEM_TABLE_ID);
136    hpet->header.oem_revision = ACPI_OEM_REVISION;
137    hpet->header.creator_id   = ACPI_CREATOR_ID;
138    hpet->header.creator_revision = ACPI_CREATOR_REVISION;
139    hpet->timer_block_id      = 0x8086a201;
140    hpet->addr.address        = ACPI_HPET_ADDRESS;
141    offset = sizeof(*hpet);
142
143    hpet->header.length = offset;
144    set_checksum(hpet, offsetof(struct acpi_header, checksum), offset);
145
146    return offset;
147}
148
149int construct_processor_objects(uint8_t *buf)
150{
151    static const char pdat[13] = { 0x5b, 0x83, 0x0b, 0x50, 0x52 };
152    static const char hex[] = "0123456789ABCDEF";
153    static const char pr_scope[] = "\\_PR_";
154    unsigned int i, length, nr_cpus = get_vcpu_nr();
155    struct acpi_header *hdr;
156    uint8_t *p = buf;
157
158    /*
159     * 1. Table Header.
160     */
161
162    hdr = (struct acpi_header *)p;
163    hdr->signature = ASCII32('S','S','D','T');
164    hdr->revision  = 2;
165    fixed_strcpy(hdr->oem_id, ACPI_OEM_ID);
166    fixed_strcpy(hdr->oem_table_id, ACPI_OEM_TABLE_ID);
167    hdr->oem_revision = ACPI_OEM_REVISION;
168    hdr->creator_id = ACPI_CREATOR_ID;
169    hdr->creator_revision = ACPI_CREATOR_REVISION;
170    p += sizeof(*hdr);
171
172    /*
173     * 2. Scope Definition.
174     */
175
176    /* ScopeOp */
177    *p++ = 0x10;
178
179    /* PkgLength (includes length bytes!). */
180    length = 1 + strlen(pr_scope) + (nr_cpus * sizeof(pdat));
181    if ( length <= 0x3f )
182    {
183        *p++ = length;
184    }
185    else if ( ++length <= 0xfff )
186    {
187        *p++ = 0x40 | (length & 0xf);
188        *p++ = length >> 4;
189    }
190    else
191    {
192        length++;
193        *p++ = 0x80 | (length & 0xf);
194        *p++ = (length >>  4) & 0xff;
195        *p++ = (length >> 12) & 0xff;
196    }
197
198    /* NameString */
199    strncpy(p, pr_scope, strlen(pr_scope));
200    p += strlen(pr_scope);
201
202    /*
203     * 3. Processor Objects.
204     */
205
206    for ( i = 0; i < nr_cpus; i++ )
207    {
208        memcpy(p, pdat, sizeof(pdat));
209        /* ProcessorName */
210        p[5] = hex[(i>>4)&15];
211        p[6] = hex[(i>>0)&15];
212        /* ProcessorID */
213        p[7] = i;
214        p += sizeof(pdat);
215    }
216
217    hdr->length = p - buf;
218    set_checksum(hdr, offsetof(struct acpi_header, checksum), hdr->length);
219
220    return hdr->length;
221}
222
223int construct_secondary_tables(uint8_t *buf, unsigned long *table_ptrs)
224{
225    int offset = 0, nr_tables = 0;
226    struct acpi_20_madt *madt;
227    struct acpi_20_hpet *hpet;
228    struct acpi_20_tcpa *tcpa;
229    static const uint16_t tis_signature[] = {0x0001, 0x0001, 0x0001};
230    uint16_t *tis_hdr;
231
232    /* MADT. */
233    if ( (get_vcpu_nr() > 1) || get_apic_mode() )
234    {
235        madt = (struct acpi_20_madt *)&buf[offset];
236        offset += construct_madt(madt);
237        table_ptrs[nr_tables++] = (unsigned long)madt;
238    }
239
240    /* HPET. */
241    hpet = (struct acpi_20_hpet *)&buf[offset];
242    offset += construct_hpet(hpet);
243    table_ptrs[nr_tables++] = (unsigned long)hpet;
244
245    /* Processor Object SSDT. */
246    table_ptrs[nr_tables++] = (unsigned long)&buf[offset];
247    offset += construct_processor_objects(&buf[offset]);
248
249    /* TPM TCPA and SSDT. */
250    tis_hdr = (uint16_t *)0xFED40F00;
251    if ( (tis_hdr[0] == tis_signature[0]) &&
252         (tis_hdr[1] == tis_signature[1]) &&
253         (tis_hdr[2] == tis_signature[2]) )
254    {
255        memcpy(&buf[offset], AmlCode_TPM, sizeof(AmlCode_TPM));
256        table_ptrs[nr_tables++] = (unsigned long)&buf[offset];
257        offset += align16(sizeof(AmlCode_TPM));
258
259        tcpa = (struct acpi_20_tcpa *)&buf[offset];
260        memset(tcpa, 0, sizeof(*tcpa));
261        offset += align16(sizeof(*tcpa));
262        table_ptrs[nr_tables++] = (unsigned long)tcpa;
263
264        tcpa->header.signature = ACPI_2_0_TCPA_SIGNATURE;
265        tcpa->header.length    = sizeof(*tcpa);
266        tcpa->header.revision  = ACPI_2_0_TCPA_REVISION;
267        fixed_strcpy(tcpa->header.oem_id, ACPI_OEM_ID);
268        fixed_strcpy(tcpa->header.oem_table_id, ACPI_OEM_TABLE_ID);
269        tcpa->header.oem_revision = ACPI_OEM_REVISION;
270        tcpa->header.creator_id   = ACPI_CREATOR_ID;
271        tcpa->header.creator_revision = ACPI_CREATOR_REVISION;
272        tcpa->lasa = e820_malloc(ACPI_2_0_TCPA_LAML_SIZE);
273        if ( tcpa->lasa )
274        {
275            tcpa->laml = ACPI_2_0_TCPA_LAML_SIZE;
276            memset((char *)(unsigned long)tcpa->lasa, 0, tcpa->laml);
277            set_checksum(tcpa,
278                         offsetof(struct acpi_header, checksum),
279                         tcpa->header.length);
280        }
281    }
282
283    table_ptrs[nr_tables] = 0;
284    return align16(offset);
285}
286
287/* Copy all the ACPI table to buffer. */
288int acpi_build_tables(uint8_t *buf)
289{
290    struct acpi_20_rsdp *rsdp;
291    struct acpi_20_rsdt *rsdt;
292    struct acpi_20_xsdt *xsdt;
293    struct acpi_20_fadt *fadt;
294    struct acpi_10_fadt *fadt_10;
295    struct acpi_20_facs *facs;
296    unsigned char       *dsdt;
297    unsigned long        secondary_tables[16];
298    int                  offset = 0, i;
299
300    facs = (struct acpi_20_facs *)&buf[offset];
301    memcpy(facs, &Facs, sizeof(struct acpi_20_facs));
302    offset += align16(sizeof(struct acpi_20_facs));
303
304    dsdt = (unsigned char *)&buf[offset];
305    memcpy(dsdt, &AmlCode, DsdtLen);
306    offset += align16(DsdtLen);
307
308    /*
309     * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
310     * or above properly, notably Windows 2000, which tries to copy FADT
311     * into a 116 bytes buffer thus causing an overflow. The solution is to
312     * link the higher revision FADT with the XSDT only and introduce a
313     * compatible revision 1 FADT that is linked with the RSDT. Refer to:
314     *     http://www.acpi.info/presentations/S01USMOBS169_OS%20new.ppt
315     */
316    fadt_10 = (struct acpi_10_fadt *)&buf[offset];
317    memcpy(fadt_10, &Fadt, sizeof(struct acpi_10_fadt));
318    offset += align16(sizeof(struct acpi_10_fadt));
319    fadt_10->header.length = sizeof(struct acpi_10_fadt);
320    fadt_10->header.revision = ACPI_1_0_FADT_REVISION;
321    fadt_10->dsdt          = (unsigned long)dsdt;
322    fadt_10->firmware_ctrl = (unsigned long)facs;
323    set_checksum(fadt_10,
324                 offsetof(struct acpi_header, checksum),
325                 sizeof(struct acpi_10_fadt));
326
327    fadt = (struct acpi_20_fadt *)&buf[offset];
328    memcpy(fadt, &Fadt, sizeof(struct acpi_20_fadt));
329    offset += align16(sizeof(struct acpi_20_fadt));
330    fadt->dsdt   = (unsigned long)dsdt;
331    fadt->x_dsdt = (unsigned long)dsdt;
332    fadt->firmware_ctrl   = (unsigned long)facs;
333    fadt->x_firmware_ctrl = (unsigned long)facs;
334    set_checksum(fadt,
335                 offsetof(struct acpi_header, checksum),
336                 sizeof(struct acpi_20_fadt));
337
338    offset += construct_secondary_tables(&buf[offset], secondary_tables);
339
340    xsdt = (struct acpi_20_xsdt *)&buf[offset];
341    memcpy(xsdt, &Xsdt, sizeof(struct acpi_header));
342    xsdt->entry[0] = (unsigned long)fadt;
343    for ( i = 0; secondary_tables[i]; i++ )
344        xsdt->entry[i+1] = secondary_tables[i];
345    xsdt->header.length = sizeof(struct acpi_header) + (i+1)*sizeof(uint64_t);
346    offset += align16(xsdt->header.length);
347    set_checksum(xsdt,
348                 offsetof(struct acpi_header, checksum),
349                 xsdt->header.length);
350
351    rsdt = (struct acpi_20_rsdt *)&buf[offset];
352    memcpy(rsdt, &Rsdt, sizeof(struct acpi_header));
353    rsdt->entry[0] = (unsigned long)fadt_10;
354    for ( i = 0; secondary_tables[i]; i++ )
355        rsdt->entry[i+1] = secondary_tables[i];
356    rsdt->header.length = sizeof(struct acpi_header) + (i+1)*sizeof(uint32_t);
357    offset += align16(rsdt->header.length);
358    set_checksum(rsdt,
359                 offsetof(struct acpi_header, checksum),
360                 rsdt->header.length);
361
362    rsdp = (struct acpi_20_rsdp *)&buf[offset];
363    memcpy(rsdp, &Rsdp, sizeof(struct acpi_20_rsdp));
364    offset += align16(sizeof(struct acpi_20_rsdp));
365    rsdp->rsdt_address = (unsigned long)rsdt;
366    rsdp->xsdt_address = (unsigned long)xsdt;
367    set_checksum(rsdp,
368                 offsetof(struct acpi_10_rsdp, checksum),
369                 sizeof(struct acpi_10_rsdp));
370    set_checksum(rsdp,
371                 offsetof(struct acpi_20_rsdp, extended_checksum),
372                 sizeof(struct acpi_20_rsdp));
373
374    return offset;
375}
376
377/*
378 * Local variables:
379 * mode: C
380 * c-set-style: "BSD"
381 * c-basic-offset: 4
382 * tab-width: 4
383 * indent-tabs-mode: nil
384 * End:
385 */
Note: See TracBrowser for help on using the repository browser.