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