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 | } |