Statistics
| Branch: | Revision:

root / hw / acpi.c @ 8ca209ad

History | View | Annotate | Download (5.5 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 d729bb9a Isaku Yamahata
    uint32_t length;
54 d729bb9a Isaku Yamahata
    struct acpi_table_header *acpi_hdr_p;
55 8a92ea2f aliguori
    size_t off;
56 8a92ea2f aliguori
57 8a92ea2f aliguori
    memset(&acpi_hdr, 0, sizeof(acpi_hdr));
58 8a92ea2f aliguori
  
59 8a92ea2f aliguori
    if (get_param_value(buf, sizeof(buf), "sig", t)) {
60 8a92ea2f aliguori
        strncpy(acpi_hdr.signature, buf, 4);
61 8a92ea2f aliguori
    } else {
62 8a92ea2f aliguori
        strncpy(acpi_hdr.signature, dfl_id, 4);
63 8a92ea2f aliguori
    }
64 8a92ea2f aliguori
    if (get_param_value(buf, sizeof(buf), "rev", t)) {
65 8a92ea2f aliguori
        val = strtoul(buf, &p, 10);
66 8a92ea2f aliguori
        if (val > 255 || *p != '\0')
67 8a92ea2f aliguori
            goto out;
68 8a92ea2f aliguori
    } else {
69 8a92ea2f aliguori
        val = 1;
70 8a92ea2f aliguori
    }
71 8a92ea2f aliguori
    acpi_hdr.revision = (int8_t)val;
72 8a92ea2f aliguori
73 8a92ea2f aliguori
    if (get_param_value(buf, sizeof(buf), "oem_id", t)) {
74 8a92ea2f aliguori
        strncpy(acpi_hdr.oem_id, buf, 6);
75 8a92ea2f aliguori
    } else {
76 8a92ea2f aliguori
        strncpy(acpi_hdr.oem_id, dfl_id, 6);
77 8a92ea2f aliguori
    }
78 8a92ea2f aliguori
79 8a92ea2f aliguori
    if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) {
80 8a92ea2f aliguori
        strncpy(acpi_hdr.oem_table_id, buf, 8);
81 8a92ea2f aliguori
    } else {
82 8a92ea2f aliguori
        strncpy(acpi_hdr.oem_table_id, dfl_id, 8);
83 8a92ea2f aliguori
    }
84 8a92ea2f aliguori
85 8a92ea2f aliguori
    if (get_param_value(buf, sizeof(buf), "oem_rev", t)) {
86 8a92ea2f aliguori
        val = strtol(buf, &p, 10);
87 8a92ea2f aliguori
        if(*p != '\0')
88 8a92ea2f aliguori
            goto out;
89 8a92ea2f aliguori
    } else {
90 8a92ea2f aliguori
        val = 1;
91 8a92ea2f aliguori
    }
92 8a92ea2f aliguori
    acpi_hdr.oem_revision = cpu_to_le32(val);
93 8a92ea2f aliguori
94 8a92ea2f aliguori
    if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) {
95 8a92ea2f aliguori
        strncpy(acpi_hdr.asl_compiler_id, buf, 4);
96 8a92ea2f aliguori
    } else {
97 8a92ea2f aliguori
        strncpy(acpi_hdr.asl_compiler_id, dfl_id, 4);
98 8a92ea2f aliguori
    }
99 8a92ea2f aliguori
100 8a92ea2f aliguori
    if (get_param_value(buf, sizeof(buf), "asl_compiler_rev", t)) {
101 8a92ea2f aliguori
        val = strtol(buf, &p, 10);
102 8a92ea2f aliguori
        if(*p != '\0')
103 8a92ea2f aliguori
            goto out;
104 8a92ea2f aliguori
    } else {
105 8a92ea2f aliguori
        val = 1;
106 8a92ea2f aliguori
    }
107 8a92ea2f aliguori
    acpi_hdr.asl_compiler_revision = cpu_to_le32(val);
108 8a92ea2f aliguori
    
109 8a92ea2f aliguori
    if (!get_param_value(buf, sizeof(buf), "data", t)) {
110 8a92ea2f aliguori
         buf[0] = '\0';
111 8a92ea2f aliguori
    }
112 8a92ea2f aliguori
113 d729bb9a Isaku Yamahata
    length = sizeof(acpi_hdr);
114 8a92ea2f aliguori
115 8a92ea2f aliguori
    f = buf;
116 8a92ea2f aliguori
    while (buf[0]) {
117 8a92ea2f aliguori
        struct stat s;
118 54042bcf aliguori
        char *n = strchr(f, ':');
119 8a92ea2f aliguori
        if (n)
120 8a92ea2f aliguori
            *n = '\0';
121 8a92ea2f aliguori
        if(stat(f, &s) < 0) {
122 8a92ea2f aliguori
            fprintf(stderr, "Can't stat file '%s': %s\n", f, strerror(errno));
123 8a92ea2f aliguori
            goto out;
124 8a92ea2f aliguori
        }
125 d729bb9a Isaku Yamahata
        length += s.st_size;
126 8a92ea2f aliguori
        if (!n)
127 8a92ea2f aliguori
            break;
128 8a92ea2f aliguori
        *n = ':';
129 8a92ea2f aliguori
        f = n + 1;
130 8a92ea2f aliguori
    }
131 8a92ea2f aliguori
132 8a92ea2f aliguori
    if (!acpi_tables) {
133 8a92ea2f aliguori
        acpi_tables_len = sizeof(uint16_t);
134 8a92ea2f aliguori
        acpi_tables = qemu_mallocz(acpi_tables_len);
135 8a92ea2f aliguori
    }
136 d729bb9a Isaku Yamahata
    acpi_tables = qemu_realloc(acpi_tables,
137 d729bb9a Isaku Yamahata
                               acpi_tables_len + sizeof(uint16_t) + length);
138 8a92ea2f aliguori
    p = acpi_tables + acpi_tables_len;
139 d729bb9a Isaku Yamahata
    acpi_tables_len += sizeof(uint16_t) + length;
140 8a92ea2f aliguori
141 d729bb9a Isaku Yamahata
    *(uint16_t*)p = cpu_to_le32(length);
142 8a92ea2f aliguori
    p += sizeof(uint16_t);
143 8a92ea2f aliguori
    memcpy(p, &acpi_hdr, sizeof(acpi_hdr));
144 8a92ea2f aliguori
    off = sizeof(acpi_hdr);
145 8a92ea2f aliguori
146 8a92ea2f aliguori
    f = buf;
147 8a92ea2f aliguori
    while (buf[0]) {
148 8a92ea2f aliguori
        struct stat s;
149 8a92ea2f aliguori
        int fd;
150 54042bcf aliguori
        char *n = strchr(f, ':');
151 8a92ea2f aliguori
        if (n)
152 8a92ea2f aliguori
            *n = '\0';
153 8a92ea2f aliguori
        fd = open(f, O_RDONLY);
154 8a92ea2f aliguori
155 8a92ea2f aliguori
        if(fd < 0)
156 8a92ea2f aliguori
            goto out;
157 8a92ea2f aliguori
        if(fstat(fd, &s) < 0) {
158 8a92ea2f aliguori
            close(fd);
159 8a92ea2f aliguori
            goto out;
160 8a92ea2f aliguori
        }
161 8a92ea2f aliguori
162 d729bb9a Isaku Yamahata
        /* off < length is necessary because file size can be changed
163 d729bb9a Isaku Yamahata
           under our foot */
164 b755a428 Vincent Minet
        while(s.st_size && off < length) {
165 8a92ea2f aliguori
            int r;
166 8a92ea2f aliguori
            r = read(fd, p + off, s.st_size);
167 8a92ea2f aliguori
            if (r > 0) {
168 8a92ea2f aliguori
                off += r;
169 8a92ea2f aliguori
                s.st_size -= r;
170 8a92ea2f aliguori
            } else if ((r < 0 && errno != EINTR) || r == 0) {
171 8a92ea2f aliguori
                close(fd);
172 8a92ea2f aliguori
                goto out;
173 8a92ea2f aliguori
            }
174 d729bb9a Isaku Yamahata
        }
175 8a92ea2f aliguori
176 8a92ea2f aliguori
        close(fd);
177 8a92ea2f aliguori
        if (!n)
178 8a92ea2f aliguori
            break;
179 8a92ea2f aliguori
        f = n + 1;
180 8a92ea2f aliguori
    }
181 d729bb9a Isaku Yamahata
    if (off < length) {
182 d729bb9a Isaku Yamahata
        /* don't pass random value in process to guest */
183 d729bb9a Isaku Yamahata
        memset(p + off, 0, length - off);
184 d729bb9a Isaku Yamahata
    }
185 8a92ea2f aliguori
186 d729bb9a Isaku Yamahata
    acpi_hdr_p = (struct acpi_table_header*)p;
187 d729bb9a Isaku Yamahata
    acpi_hdr_p->length = cpu_to_le32(length);
188 d729bb9a Isaku Yamahata
    acpi_hdr_p->checksum = acpi_checksum((uint8_t*)p, length);
189 8a92ea2f aliguori
    /* increase number of tables */
190 8a92ea2f aliguori
    (*(uint16_t*)acpi_tables) =
191 8a92ea2f aliguori
            cpu_to_le32(le32_to_cpu(*(uint16_t*)acpi_tables) + 1);
192 8a92ea2f aliguori
    return 0;
193 8a92ea2f aliguori
out:
194 8a92ea2f aliguori
    if (acpi_tables) {
195 b2538b4b Jean-Christophe DUBOIS
        qemu_free(acpi_tables);
196 8a92ea2f aliguori
        acpi_tables = NULL;
197 8a92ea2f aliguori
    }
198 8a92ea2f aliguori
    return -1;
199 8a92ea2f aliguori
}