Statistics
| Branch: | Revision:

root / hw / acpi.c @ 0b8f9be6

History | View | Annotate | Download (5.1 kB)

1 6515b203 bellard
/*
2 6515b203 bellard
 * ACPI implementation
3 5fafdf24 ths
 *
4 6515b203 bellard
 * Copyright (c) 2006 Fabrice Bellard
5 5fafdf24 ths
 *
6 6515b203 bellard
 * This library is free software; you can redistribute it and/or
7 6515b203 bellard
 * modify it under the terms of the GNU Lesser General Public
8 6515b203 bellard
 * License version 2 as published by the Free Software Foundation.
9 6515b203 bellard
 *
10 6515b203 bellard
 * This library is distributed in the hope that it will be useful,
11 6515b203 bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 6515b203 bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 6515b203 bellard
 * Lesser General Public License for more details.
14 6515b203 bellard
 *
15 6515b203 bellard
 * You should have received a copy of the GNU Lesser General Public
16 8167ee88 Blue Swirl
 * License along with this library; if not, see <http://www.gnu.org/licenses/>
17 6515b203 bellard
 */
18 87ecb68b pbrook
#include "hw.h"
19 87ecb68b pbrook
#include "pc.h"
20 990b150e Isaku Yamahata
#include "acpi.h"
21 6515b203 bellard
22 8a92ea2f aliguori
struct acpi_table_header
23 8a92ea2f aliguori
{
24 8a92ea2f aliguori
    char signature [4];    /* ACPI signature (4 ASCII characters) */
25 8a92ea2f aliguori
    uint32_t length;          /* Length of table, in bytes, including header */
26 8a92ea2f aliguori
    uint8_t revision;         /* ACPI Specification minor version # */
27 8a92ea2f aliguori
    uint8_t checksum;         /* To make sum of entire table == 0 */
28 8a92ea2f aliguori
    char oem_id [6];       /* OEM identification */
29 8a92ea2f aliguori
    char oem_table_id [8]; /* OEM table identification */
30 8a92ea2f aliguori
    uint32_t oem_revision;    /* OEM revision number */
31 8a92ea2f aliguori
    char asl_compiler_id [4]; /* ASL compiler vendor ID */
32 8a92ea2f aliguori
    uint32_t asl_compiler_revision; /* ASL compiler revision number */
33 8a92ea2f aliguori
} __attribute__((packed));
34 8a92ea2f aliguori
35 8a92ea2f aliguori
char *acpi_tables;
36 8a92ea2f aliguori
size_t acpi_tables_len;
37 8a92ea2f aliguori
38 8a92ea2f aliguori
static int acpi_checksum(const uint8_t *data, int len)
39 8a92ea2f aliguori
{
40 8a92ea2f aliguori
    int sum, i;
41 8a92ea2f aliguori
    sum = 0;
42 8a92ea2f aliguori
    for(i = 0; i < len; i++)
43 8a92ea2f aliguori
        sum += data[i];
44 8a92ea2f aliguori
    return (-sum) & 0xff;
45 8a92ea2f aliguori
}
46 8a92ea2f aliguori
47 8a92ea2f aliguori
int acpi_table_add(const char *t)
48 8a92ea2f aliguori
{
49 8a92ea2f aliguori
    static const char *dfl_id = "QEMUQEMU";
50 8a92ea2f aliguori
    char buf[1024], *p, *f;
51 8a92ea2f aliguori
    struct acpi_table_header acpi_hdr;
52 8a92ea2f aliguori
    unsigned long val;
53 8a92ea2f aliguori
    size_t off;
54 8a92ea2f aliguori
55 8a92ea2f aliguori
    memset(&acpi_hdr, 0, sizeof(acpi_hdr));
56 8a92ea2f aliguori
  
57 8a92ea2f aliguori
    if (get_param_value(buf, sizeof(buf), "sig", t)) {
58 8a92ea2f aliguori
        strncpy(acpi_hdr.signature, buf, 4);
59 8a92ea2f aliguori
    } else {
60 8a92ea2f aliguori
        strncpy(acpi_hdr.signature, dfl_id, 4);
61 8a92ea2f aliguori
    }
62 8a92ea2f aliguori
    if (get_param_value(buf, sizeof(buf), "rev", t)) {
63 8a92ea2f aliguori
        val = strtoul(buf, &p, 10);
64 8a92ea2f aliguori
        if (val > 255 || *p != '\0')
65 8a92ea2f aliguori
            goto out;
66 8a92ea2f aliguori
    } else {
67 8a92ea2f aliguori
        val = 1;
68 8a92ea2f aliguori
    }
69 8a92ea2f aliguori
    acpi_hdr.revision = (int8_t)val;
70 8a92ea2f aliguori
71 8a92ea2f aliguori
    if (get_param_value(buf, sizeof(buf), "oem_id", t)) {
72 8a92ea2f aliguori
        strncpy(acpi_hdr.oem_id, buf, 6);
73 8a92ea2f aliguori
    } else {
74 8a92ea2f aliguori
        strncpy(acpi_hdr.oem_id, dfl_id, 6);
75 8a92ea2f aliguori
    }
76 8a92ea2f aliguori
77 8a92ea2f aliguori
    if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) {
78 8a92ea2f aliguori
        strncpy(acpi_hdr.oem_table_id, buf, 8);
79 8a92ea2f aliguori
    } else {
80 8a92ea2f aliguori
        strncpy(acpi_hdr.oem_table_id, dfl_id, 8);
81 8a92ea2f aliguori
    }
82 8a92ea2f aliguori
83 8a92ea2f aliguori
    if (get_param_value(buf, sizeof(buf), "oem_rev", t)) {
84 8a92ea2f aliguori
        val = strtol(buf, &p, 10);
85 8a92ea2f aliguori
        if(*p != '\0')
86 8a92ea2f aliguori
            goto out;
87 8a92ea2f aliguori
    } else {
88 8a92ea2f aliguori
        val = 1;
89 8a92ea2f aliguori
    }
90 8a92ea2f aliguori
    acpi_hdr.oem_revision = cpu_to_le32(val);
91 8a92ea2f aliguori
92 8a92ea2f aliguori
    if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) {
93 8a92ea2f aliguori
        strncpy(acpi_hdr.asl_compiler_id, buf, 4);
94 8a92ea2f aliguori
    } else {
95 8a92ea2f aliguori
        strncpy(acpi_hdr.asl_compiler_id, dfl_id, 4);
96 8a92ea2f aliguori
    }
97 8a92ea2f aliguori
98 8a92ea2f aliguori
    if (get_param_value(buf, sizeof(buf), "asl_compiler_rev", t)) {
99 8a92ea2f aliguori
        val = strtol(buf, &p, 10);
100 8a92ea2f aliguori
        if(*p != '\0')
101 8a92ea2f aliguori
            goto out;
102 8a92ea2f aliguori
    } else {
103 8a92ea2f aliguori
        val = 1;
104 8a92ea2f aliguori
    }
105 8a92ea2f aliguori
    acpi_hdr.asl_compiler_revision = cpu_to_le32(val);
106 8a92ea2f aliguori
    
107 8a92ea2f aliguori
    if (!get_param_value(buf, sizeof(buf), "data", t)) {
108 8a92ea2f aliguori
         buf[0] = '\0';
109 8a92ea2f aliguori
    }
110 8a92ea2f aliguori
111 8a92ea2f aliguori
    acpi_hdr.length = sizeof(acpi_hdr);
112 8a92ea2f aliguori
113 8a92ea2f aliguori
    f = buf;
114 8a92ea2f aliguori
    while (buf[0]) {
115 8a92ea2f aliguori
        struct stat s;
116 54042bcf aliguori
        char *n = strchr(f, ':');
117 8a92ea2f aliguori
        if (n)
118 8a92ea2f aliguori
            *n = '\0';
119 8a92ea2f aliguori
        if(stat(f, &s) < 0) {
120 8a92ea2f aliguori
            fprintf(stderr, "Can't stat file '%s': %s\n", f, strerror(errno));
121 8a92ea2f aliguori
            goto out;
122 8a92ea2f aliguori
        }
123 8a92ea2f aliguori
        acpi_hdr.length += s.st_size;
124 8a92ea2f aliguori
        if (!n)
125 8a92ea2f aliguori
            break;
126 8a92ea2f aliguori
        *n = ':';
127 8a92ea2f aliguori
        f = n + 1;
128 8a92ea2f aliguori
    }
129 8a92ea2f aliguori
130 8a92ea2f aliguori
    if (!acpi_tables) {
131 8a92ea2f aliguori
        acpi_tables_len = sizeof(uint16_t);
132 8a92ea2f aliguori
        acpi_tables = qemu_mallocz(acpi_tables_len);
133 8a92ea2f aliguori
    }
134 8a92ea2f aliguori
    p = acpi_tables + acpi_tables_len;
135 8a92ea2f aliguori
    acpi_tables_len += sizeof(uint16_t) + acpi_hdr.length;
136 8a92ea2f aliguori
    acpi_tables = qemu_realloc(acpi_tables, acpi_tables_len);
137 8a92ea2f aliguori
138 8a92ea2f aliguori
    acpi_hdr.length = cpu_to_le32(acpi_hdr.length);
139 8a92ea2f aliguori
    *(uint16_t*)p = acpi_hdr.length;
140 8a92ea2f aliguori
    p += sizeof(uint16_t);
141 8a92ea2f aliguori
    memcpy(p, &acpi_hdr, sizeof(acpi_hdr));
142 8a92ea2f aliguori
    off = sizeof(acpi_hdr);
143 8a92ea2f aliguori
144 8a92ea2f aliguori
    f = buf;
145 8a92ea2f aliguori
    while (buf[0]) {
146 8a92ea2f aliguori
        struct stat s;
147 8a92ea2f aliguori
        int fd;
148 54042bcf aliguori
        char *n = strchr(f, ':');
149 8a92ea2f aliguori
        if (n)
150 8a92ea2f aliguori
            *n = '\0';
151 8a92ea2f aliguori
        fd = open(f, O_RDONLY);
152 8a92ea2f aliguori
153 8a92ea2f aliguori
        if(fd < 0)
154 8a92ea2f aliguori
            goto out;
155 8a92ea2f aliguori
        if(fstat(fd, &s) < 0) {
156 8a92ea2f aliguori
            close(fd);
157 8a92ea2f aliguori
            goto out;
158 8a92ea2f aliguori
        }
159 8a92ea2f aliguori
160 8a92ea2f aliguori
        do {
161 8a92ea2f aliguori
            int r;
162 8a92ea2f aliguori
            r = read(fd, p + off, s.st_size);
163 8a92ea2f aliguori
            if (r > 0) {
164 8a92ea2f aliguori
                off += r;
165 8a92ea2f aliguori
                s.st_size -= r;
166 8a92ea2f aliguori
            } else if ((r < 0 && errno != EINTR) || r == 0) {
167 8a92ea2f aliguori
                close(fd);
168 8a92ea2f aliguori
                goto out;
169 8a92ea2f aliguori
            }
170 8a92ea2f aliguori
        } while(s.st_size);
171 8a92ea2f aliguori
172 8a92ea2f aliguori
        close(fd);
173 8a92ea2f aliguori
        if (!n)
174 8a92ea2f aliguori
            break;
175 8a92ea2f aliguori
        f = n + 1;
176 8a92ea2f aliguori
    }
177 8a92ea2f aliguori
178 8a92ea2f aliguori
    ((struct acpi_table_header*)p)->checksum = acpi_checksum((uint8_t*)p, off);
179 8a92ea2f aliguori
    /* increase number of tables */
180 8a92ea2f aliguori
    (*(uint16_t*)acpi_tables) =
181 8a92ea2f aliguori
            cpu_to_le32(le32_to_cpu(*(uint16_t*)acpi_tables) + 1);
182 8a92ea2f aliguori
    return 0;
183 8a92ea2f aliguori
out:
184 8a92ea2f aliguori
    if (acpi_tables) {
185 b2538b4b Jean-Christophe DUBOIS
        qemu_free(acpi_tables);
186 8a92ea2f aliguori
        acpi_tables = NULL;
187 8a92ea2f aliguori
    }
188 8a92ea2f aliguori
    return -1;
189 8a92ea2f aliguori
}