Statistics
| Branch: | Revision:

root / hw / acpi.c @ 0b8f9be6

History | View | Annotate | Download (5.1 kB)

1
/*
2
 * ACPI implementation
3
 *
4
 * Copyright (c) 2006 Fabrice Bellard
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License version 2 as published by the Free Software Foundation.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, see <http://www.gnu.org/licenses/>
17
 */
18
#include "hw.h"
19
#include "pc.h"
20
#include "acpi.h"
21

    
22
struct acpi_table_header
23
{
24
    char signature [4];    /* ACPI signature (4 ASCII characters) */
25
    uint32_t length;          /* Length of table, in bytes, including header */
26
    uint8_t revision;         /* ACPI Specification minor version # */
27
    uint8_t checksum;         /* To make sum of entire table == 0 */
28
    char oem_id [6];       /* OEM identification */
29
    char oem_table_id [8]; /* OEM table identification */
30
    uint32_t oem_revision;    /* OEM revision number */
31
    char asl_compiler_id [4]; /* ASL compiler vendor ID */
32
    uint32_t asl_compiler_revision; /* ASL compiler revision number */
33
} __attribute__((packed));
34

    
35
char *acpi_tables;
36
size_t acpi_tables_len;
37

    
38
static int acpi_checksum(const uint8_t *data, int len)
39
{
40
    int sum, i;
41
    sum = 0;
42
    for(i = 0; i < len; i++)
43
        sum += data[i];
44
    return (-sum) & 0xff;
45
}
46

    
47
int acpi_table_add(const char *t)
48
{
49
    static const char *dfl_id = "QEMUQEMU";
50
    char buf[1024], *p, *f;
51
    struct acpi_table_header acpi_hdr;
52
    unsigned long val;
53
    size_t off;
54

    
55
    memset(&acpi_hdr, 0, sizeof(acpi_hdr));
56
  
57
    if (get_param_value(buf, sizeof(buf), "sig", t)) {
58
        strncpy(acpi_hdr.signature, buf, 4);
59
    } else {
60
        strncpy(acpi_hdr.signature, dfl_id, 4);
61
    }
62
    if (get_param_value(buf, sizeof(buf), "rev", t)) {
63
        val = strtoul(buf, &p, 10);
64
        if (val > 255 || *p != '\0')
65
            goto out;
66
    } else {
67
        val = 1;
68
    }
69
    acpi_hdr.revision = (int8_t)val;
70

    
71
    if (get_param_value(buf, sizeof(buf), "oem_id", t)) {
72
        strncpy(acpi_hdr.oem_id, buf, 6);
73
    } else {
74
        strncpy(acpi_hdr.oem_id, dfl_id, 6);
75
    }
76

    
77
    if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) {
78
        strncpy(acpi_hdr.oem_table_id, buf, 8);
79
    } else {
80
        strncpy(acpi_hdr.oem_table_id, dfl_id, 8);
81
    }
82

    
83
    if (get_param_value(buf, sizeof(buf), "oem_rev", t)) {
84
        val = strtol(buf, &p, 10);
85
        if(*p != '\0')
86
            goto out;
87
    } else {
88
        val = 1;
89
    }
90
    acpi_hdr.oem_revision = cpu_to_le32(val);
91

    
92
    if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) {
93
        strncpy(acpi_hdr.asl_compiler_id, buf, 4);
94
    } else {
95
        strncpy(acpi_hdr.asl_compiler_id, dfl_id, 4);
96
    }
97

    
98
    if (get_param_value(buf, sizeof(buf), "asl_compiler_rev", t)) {
99
        val = strtol(buf, &p, 10);
100
        if(*p != '\0')
101
            goto out;
102
    } else {
103
        val = 1;
104
    }
105
    acpi_hdr.asl_compiler_revision = cpu_to_le32(val);
106
    
107
    if (!get_param_value(buf, sizeof(buf), "data", t)) {
108
         buf[0] = '\0';
109
    }
110

    
111
    acpi_hdr.length = sizeof(acpi_hdr);
112

    
113
    f = buf;
114
    while (buf[0]) {
115
        struct stat s;
116
        char *n = strchr(f, ':');
117
        if (n)
118
            *n = '\0';
119
        if(stat(f, &s) < 0) {
120
            fprintf(stderr, "Can't stat file '%s': %s\n", f, strerror(errno));
121
            goto out;
122
        }
123
        acpi_hdr.length += s.st_size;
124
        if (!n)
125
            break;
126
        *n = ':';
127
        f = n + 1;
128
    }
129

    
130
    if (!acpi_tables) {
131
        acpi_tables_len = sizeof(uint16_t);
132
        acpi_tables = qemu_mallocz(acpi_tables_len);
133
    }
134
    p = acpi_tables + acpi_tables_len;
135
    acpi_tables_len += sizeof(uint16_t) + acpi_hdr.length;
136
    acpi_tables = qemu_realloc(acpi_tables, acpi_tables_len);
137

    
138
    acpi_hdr.length = cpu_to_le32(acpi_hdr.length);
139
    *(uint16_t*)p = acpi_hdr.length;
140
    p += sizeof(uint16_t);
141
    memcpy(p, &acpi_hdr, sizeof(acpi_hdr));
142
    off = sizeof(acpi_hdr);
143

    
144
    f = buf;
145
    while (buf[0]) {
146
        struct stat s;
147
        int fd;
148
        char *n = strchr(f, ':');
149
        if (n)
150
            *n = '\0';
151
        fd = open(f, O_RDONLY);
152

    
153
        if(fd < 0)
154
            goto out;
155
        if(fstat(fd, &s) < 0) {
156
            close(fd);
157
            goto out;
158
        }
159

    
160
        do {
161
            int r;
162
            r = read(fd, p + off, s.st_size);
163
            if (r > 0) {
164
                off += r;
165
                s.st_size -= r;
166
            } else if ((r < 0 && errno != EINTR) || r == 0) {
167
                close(fd);
168
                goto out;
169
            }
170
        } while(s.st_size);
171

    
172
        close(fd);
173
        if (!n)
174
            break;
175
        f = n + 1;
176
    }
177

    
178
    ((struct acpi_table_header*)p)->checksum = acpi_checksum((uint8_t*)p, off);
179
    /* increase number of tables */
180
    (*(uint16_t*)acpi_tables) =
181
            cpu_to_le32(le32_to_cpu(*(uint16_t*)acpi_tables) + 1);
182
    return 0;
183
out:
184
    if (acpi_tables) {
185
        qemu_free(acpi_tables);
186
        acpi_tables = NULL;
187
    }
188
    return -1;
189
}