Revision 104bf02e

b/hw/acpi.c
20 20
#include "pc.h"
21 21
#include "acpi.h"
22 22

  
23
struct acpi_table_header
24
{
25
    char signature [4];    /* ACPI signature (4 ASCII characters) */
23
struct acpi_table_header {
24
    uint16_t _length;         /* our length, not actual part of the hdr */
25
                              /* XXX why we have 2 length fields here? */
26
    char sig[4];              /* ACPI signature (4 ASCII characters) */
26 27
    uint32_t length;          /* Length of table, in bytes, including header */
27 28
    uint8_t revision;         /* ACPI Specification minor version # */
28 29
    uint8_t checksum;         /* To make sum of entire table == 0 */
29
    char oem_id [6];       /* OEM identification */
30
    char oem_table_id [8]; /* OEM table identification */
30
    char oem_id[6];           /* OEM identification */
31
    char oem_table_id[8];     /* OEM table identification */
31 32
    uint32_t oem_revision;    /* OEM revision number */
32
    char asl_compiler_id [4]; /* ASL compiler vendor ID */
33
    char asl_compiler_id[4];  /* ASL compiler vendor ID */
33 34
    uint32_t asl_compiler_revision; /* ASL compiler revision number */
34 35
} __attribute__((packed));
35 36

  
37
#define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header)
38
#define ACPI_TABLE_PFX_SIZE sizeof(uint16_t)  /* size of the extra prefix */
39

  
40
static const char dfl_hdr[ACPI_TABLE_HDR_SIZE] =
41
    "\0\0"                   /* fake _length (2) */
42
    "QEMU\0\0\0\0\1\0"       /* sig (4), len(4), revno (1), csum (1) */
43
    "QEMUQEQEMUQEMU\1\0\0\0" /* OEM id (6), table (8), revno (4) */
44
    "QEMU\1\0\0\0"           /* ASL compiler ID (4), version (4) */
45
    ;
46

  
36 47
char *acpi_tables;
37 48
size_t acpi_tables_len;
38 49

  
......
40 51
{
41 52
    int sum, i;
42 53
    sum = 0;
43
    for(i = 0; i < len; i++)
54
    for (i = 0; i < len; i++) {
44 55
        sum += data[i];
56
    }
45 57
    return (-sum) & 0xff;
46 58
}
47 59

  
60
/* like strncpy() but zero-fills the tail of destination */
61
static void strzcpy(char *dst, const char *src, size_t size)
62
{
63
    size_t len = strlen(src);
64
    if (len >= size) {
65
        len = size;
66
    } else {
67
      memset(dst + len, 0, size - len);
68
    }
69
    memcpy(dst, src, len);
70
}
71

  
72
/* XXX fixme: this function uses obsolete argument parsing interface */
48 73
int acpi_table_add(const char *t)
49 74
{
50
    static const char *dfl_id = "QEMUQEMU";
51 75
    char buf[1024], *p, *f;
52
    struct acpi_table_header acpi_hdr;
53 76
    unsigned long val;
54
    uint32_t length;
55
    struct acpi_table_header *acpi_hdr_p;
56
    size_t off;
77
    size_t len, start, allen;
78
    bool has_header;
79
    int changed;
80
    int r;
81
    struct acpi_table_header hdr;
82

  
83
    r = 0;
84
    r |= get_param_value(buf, sizeof(buf), "data", t) ? 1 : 0;
85
    r |= get_param_value(buf, sizeof(buf), "file", t) ? 2 : 0;
86
    switch (r) {
87
    case 0:
88
        buf[0] = '\0';
89
        /* fallthrough for default behavior */
90
    case 1:
91
        has_header = false;
92
        break;
93
    case 2:
94
        has_header = true;
95
        break;
96
    default:
97
        fprintf(stderr, "acpitable: both data and file are specified\n");
98
        return -1;
99
    }
57 100

  
58
    memset(&acpi_hdr, 0, sizeof(acpi_hdr));
59
  
60
    if (get_param_value(buf, sizeof(buf), "sig", t)) {
61
        strncpy(acpi_hdr.signature, buf, 4);
101
    if (!acpi_tables) {
102
        allen = sizeof(uint16_t);
103
        acpi_tables = qemu_mallocz(allen);
62 104
    } else {
63
        strncpy(acpi_hdr.signature, dfl_id, 4);
105
        allen = acpi_tables_len;
64 106
    }
107

  
108
    start = allen;
109
    acpi_tables = qemu_realloc(acpi_tables, start + ACPI_TABLE_HDR_SIZE);
110
    allen += has_header ? ACPI_TABLE_PFX_SIZE : ACPI_TABLE_HDR_SIZE;
111

  
112
    /* now read in the data files, reallocating buffer as needed */
113

  
114
    for (f = strtok(buf, ":"); f; f = strtok(NULL, ":")) {
115
        int fd = open(f, O_RDONLY);
116

  
117
        if (fd < 0) {
118
            fprintf(stderr, "can't open file %s: %s\n", f, strerror(errno));
119
            return -1;
120
        }
121

  
122
        for (;;) {
123
            char data[8192];
124
            r = read(fd, data, sizeof(data));
125
            if (r == 0) {
126
                break;
127
            } else if (r > 0) {
128
                acpi_tables = qemu_realloc(acpi_tables, allen + r);
129
                memcpy(acpi_tables + allen, data, r);
130
                allen += r;
131
            } else if (errno != EINTR) {
132
                fprintf(stderr, "can't read file %s: %s\n",
133
                        f, strerror(errno));
134
                close(fd);
135
                return -1;
136
            }
137
        }
138

  
139
        close(fd);
140
    }
141

  
142
    /* now fill in the header fields */
143

  
144
    f = acpi_tables + start;   /* start of the table */
145
    changed = 0;
146

  
147
    /* copy the header to temp place to align the fields */
148
    memcpy(&hdr, has_header ? f : dfl_hdr, ACPI_TABLE_HDR_SIZE);
149

  
150
    /* length of the table minus our prefix */
151
    len = allen - start - ACPI_TABLE_PFX_SIZE;
152

  
153
    hdr._length = cpu_to_le16(len);
154

  
155
    if (get_param_value(buf, sizeof(buf), "sig", t)) {
156
        strzcpy(hdr.sig, buf, sizeof(hdr.sig));
157
        ++changed;
158
    }
159

  
160
    /* length of the table including header, in bytes */
161
    if (has_header) {
162
        /* check if actual length is correct */
163
        val = le32_to_cpu(hdr.length);
164
        if (val != len) {
165
            fprintf(stderr,
166
                "warning: acpitable has wrong length,"
167
                " header says %lu, actual size %zu bytes\n",
168
                val, len);
169
            ++changed;
170
        }
171
    }
172
    /* we may avoid putting length here if has_header is true */
173
    hdr.length = cpu_to_le32(len);
174

  
65 175
    if (get_param_value(buf, sizeof(buf), "rev", t)) {
66
        val = strtoul(buf, &p, 10);
67
        if (val > 255 || *p != '\0')
68
            goto out;
69
    } else {
70
        val = 1;
176
        val = strtoul(buf, &p, 0);
177
        if (val > 255 || *p) {
178
            fprintf(stderr, "acpitable: \"rev=%s\" is invalid\n", buf);
179
            return -1;
180
        }
181
        hdr.revision = (uint8_t)val;
182
        ++changed;
71 183
    }
72
    acpi_hdr.revision = (int8_t)val;
73 184

  
74 185
    if (get_param_value(buf, sizeof(buf), "oem_id", t)) {
75
        strncpy(acpi_hdr.oem_id, buf, 6);
76
    } else {
77
        strncpy(acpi_hdr.oem_id, dfl_id, 6);
186
        strzcpy(hdr.oem_id, buf, sizeof(hdr.oem_id));
187
        ++changed;
78 188
    }
79 189

  
80 190
    if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) {
81
        strncpy(acpi_hdr.oem_table_id, buf, 8);
82
    } else {
83
        strncpy(acpi_hdr.oem_table_id, dfl_id, 8);
191
        strzcpy(hdr.oem_table_id, buf, sizeof(hdr.oem_table_id));
192
        ++changed;
84 193
    }
85 194

  
86 195
    if (get_param_value(buf, sizeof(buf), "oem_rev", t)) {
87
        val = strtol(buf, &p, 10);
88
        if(*p != '\0')
89
            goto out;
90
    } else {
91
        val = 1;
196
        val = strtol(buf, &p, 0);
197
        if (*p) {
198
            fprintf(stderr, "acpitable: \"oem_rev=%s\" is invalid\n", buf);
199
            return -1;
200
        }
201
        hdr.oem_revision = cpu_to_le32(val);
202
        ++changed;
92 203
    }
93
    acpi_hdr.oem_revision = cpu_to_le32(val);
94 204

  
95 205
    if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) {
96
        strncpy(acpi_hdr.asl_compiler_id, buf, 4);
97
    } else {
98
        strncpy(acpi_hdr.asl_compiler_id, dfl_id, 4);
206
        strzcpy(hdr.asl_compiler_id, buf, sizeof(hdr.asl_compiler_id));
207
        ++changed;
99 208
    }
100 209

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

  
114
    length = sizeof(acpi_hdr);
115

  
116
    f = buf;
117
    while (buf[0]) {
118
        struct stat s;
119
        char *n = strchr(f, ':');
120
        if (n)
121
            *n = '\0';
122
        if(stat(f, &s) < 0) {
123
            fprintf(stderr, "Can't stat file '%s': %s\n", f, strerror(errno));
124
            goto out;
211
        val = strtol(buf, &p, 0);
212
        if (*p) {
213
            fprintf(stderr, "acpitable: \"%s=%s\" is invalid\n",
214
                    "asl_compiler_rev", buf);
215
            return -1;
125 216
        }
126
        length += s.st_size;
127
        if (!n)
128
            break;
129
        *n = ':';
130
        f = n + 1;
217
        hdr.asl_compiler_revision = cpu_to_le32(val);
218
        ++changed;
131 219
    }
132 220

  
133
    if (!acpi_tables) {
134
        acpi_tables_len = sizeof(uint16_t);
135
        acpi_tables = qemu_mallocz(acpi_tables_len);
221
    if (!has_header && !changed) {
222
        fprintf(stderr, "warning: acpitable: no table headers are specified\n");
136 223
    }
137
    acpi_tables = qemu_realloc(acpi_tables,
138
                               acpi_tables_len + sizeof(uint16_t) + length);
139
    p = acpi_tables + acpi_tables_len;
140
    acpi_tables_len += sizeof(uint16_t) + length;
141

  
142
    *(uint16_t*)p = cpu_to_le32(length);
143
    p += sizeof(uint16_t);
144
    memcpy(p, &acpi_hdr, sizeof(acpi_hdr));
145
    off = sizeof(acpi_hdr);
146

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

  
156
        if(fd < 0)
157
            goto out;
158
        if(fstat(fd, &s) < 0) {
159
            close(fd);
160
            goto out;
161
        }
162 224

  
163
        /* off < length is necessary because file size can be changed
164
           under our foot */
165
        while(s.st_size && off < length) {
166
            int r;
167
            r = read(fd, p + off, s.st_size);
168
            if (r > 0) {
169
                off += r;
170
                s.st_size -= r;
171
            } else if ((r < 0 && errno != EINTR) || r == 0) {
172
                close(fd);
173
                goto out;
174
            }
175
        }
176 225

  
177
        close(fd);
178
        if (!n)
179
            break;
180
        f = n + 1;
181
    }
182
    if (off < length) {
183
        /* don't pass random value in process to guest */
184
        memset(p + off, 0, length - off);
226
    /* now calculate checksum of the table, complete with the header */
227
    /* we may as well leave checksum intact if has_header is true */
228
    /* alternatively there may be a way to set cksum to a given value */
229
    hdr.checksum = 0;    /* for checksum calculation */
230

  
231
    /* put header back */
232
    memcpy(f, &hdr, sizeof(hdr));
233

  
234
    if (changed || !has_header || 1) {
235
        ((struct acpi_table_header *)f)->checksum =
236
            acpi_checksum((uint8_t *)f + ACPI_TABLE_PFX_SIZE, len);
185 237
    }
186 238

  
187
    acpi_hdr_p = (struct acpi_table_header*)p;
188
    acpi_hdr_p->length = cpu_to_le32(length);
189
    acpi_hdr_p->checksum = acpi_checksum((uint8_t*)p, length);
190 239
    /* increase number of tables */
191
    (*(uint16_t*)acpi_tables) =
192
	    cpu_to_le32(le32_to_cpu(*(uint16_t*)acpi_tables) + 1);
240
    (*(uint16_t *)acpi_tables) =
241
        cpu_to_le32(le32_to_cpu(*(uint16_t *)acpi_tables) + 1);
242

  
243
    acpi_tables_len = allen;
193 244
    return 0;
194
out:
195
    if (acpi_tables) {
196
        qemu_free(acpi_tables);
197
        acpi_tables = NULL;
198
    }
199
    return -1;
245

  
200 246
}
201 247

  
202 248
/* ACPI PM1a EVT */
b/qemu-options.hx
1074 1074
ETEXI
1075 1075

  
1076 1076
DEF("acpitable", HAS_ARG, QEMU_OPTION_acpitable,
1077
    "-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,data=file1[:file2]...]\n"
1077
    "-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,{data|file}=file1[:file2]...]\n"
1078 1078
    "                ACPI table description\n", QEMU_ARCH_I386)
1079 1079
STEXI
1080 1080
@item -acpitable [sig=@var{str}][,rev=@var{n}][,oem_id=@var{str}][,oem_table_id=@var{str}][,oem_rev=@var{n}] [,asl_compiler_id=@var{str}][,asl_compiler_rev=@var{n}][,data=@var{file1}[:@var{file2}]...]
1081 1081
@findex -acpitable
1082 1082
Add ACPI table with specified header fields and context from specified files.
1083
For file=, take whole ACPI table from the specified files, including all
1084
ACPI headers (possible overridden by other options).
1085
For data=, only data
1086
portion of the table is used, all header information is specified in the
1087
command line.
1083 1088
ETEXI
1084 1089

  
1085 1090
DEF("smbios", HAS_ARG, QEMU_OPTION_smbios,

Also available in: Unified diff