root / hw / acpi.c @ 0d2e91c1
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 | } |