root / tests / hd-geo-test.c @ 5e954943
History | View | Annotate | Download (10.5 kB)
1 |
/*
|
---|---|
2 |
* Hard disk geometry test cases.
|
3 |
*
|
4 |
* Copyright (c) 2012 Red Hat Inc.
|
5 |
*
|
6 |
* Authors:
|
7 |
* Markus Armbruster <armbru@redhat.com>,
|
8 |
*
|
9 |
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
10 |
* See the COPYING file in the top-level directory.
|
11 |
*/
|
12 |
|
13 |
/*
|
14 |
* Covers only IDE and tests only CMOS contents. Better than nothing.
|
15 |
* Improvements welcome.
|
16 |
*/
|
17 |
|
18 |
#include <glib.h> |
19 |
#include <stdlib.h> |
20 |
#include <string.h> |
21 |
#include <unistd.h> |
22 |
#include "qemu-common.h" |
23 |
#include "libqtest.h" |
24 |
|
25 |
static const char test_image[] = "/tmp/qtest.XXXXXX"; |
26 |
|
27 |
static char *create_test_img(int secs) |
28 |
{ |
29 |
char *template = strdup("/tmp/qtest.XXXXXX"); |
30 |
int fd, ret;
|
31 |
|
32 |
fd = mkstemp(template); |
33 |
g_assert(fd >= 0);
|
34 |
ret = ftruncate(fd, (off_t)secs * 512);
|
35 |
g_assert(ret == 0);
|
36 |
close(fd); |
37 |
return template;
|
38 |
} |
39 |
|
40 |
typedef struct { |
41 |
int cyls, heads, secs, trans;
|
42 |
} CHST; |
43 |
|
44 |
typedef enum { |
45 |
mbr_blank, mbr_lba, mbr_chs, |
46 |
mbr_last |
47 |
} MBRcontents; |
48 |
|
49 |
typedef enum { |
50 |
/* order is relevant */
|
51 |
backend_small, backend_large, backend_empty, |
52 |
backend_last |
53 |
} Backend; |
54 |
|
55 |
static const int img_secs[backend_last] = { |
56 |
[backend_small] = 61440,
|
57 |
[backend_large] = 8388608,
|
58 |
[backend_empty] = -1,
|
59 |
}; |
60 |
|
61 |
static const CHST hd_chst[backend_last][mbr_last] = { |
62 |
[backend_small] = { |
63 |
[mbr_blank] = { 60, 16, 63, 0 }, |
64 |
[mbr_lba] = { 60, 16, 63, 2 }, |
65 |
[mbr_chs] = { 60, 16, 63, 0 } |
66 |
}, |
67 |
[backend_large] = { |
68 |
[mbr_blank] = { 8322, 16, 63, 1 }, |
69 |
[mbr_lba] = { 8322, 16, 63, 1 }, |
70 |
[mbr_chs] = { 8322, 16, 63, 0 } |
71 |
}, |
72 |
}; |
73 |
|
74 |
static const char *img_file_name[backend_last]; |
75 |
|
76 |
static const CHST *cur_ide[4]; |
77 |
|
78 |
static bool is_hd(const CHST *expected_chst) |
79 |
{ |
80 |
return expected_chst && expected_chst->cyls;
|
81 |
} |
82 |
|
83 |
static void test_cmos_byte(int reg, int expected) |
84 |
{ |
85 |
enum { cmos_base = 0x70 }; |
86 |
int actual;
|
87 |
|
88 |
outb(cmos_base + 0, reg);
|
89 |
actual = inb(cmos_base + 1);
|
90 |
g_assert(actual == expected); |
91 |
} |
92 |
|
93 |
static void test_cmos_bytes(int reg0, int n, uint8_t expected[]) |
94 |
{ |
95 |
int i;
|
96 |
|
97 |
for (i = 0; i < 9; i++) { |
98 |
test_cmos_byte(reg0 + i, expected[i]); |
99 |
} |
100 |
} |
101 |
|
102 |
static void test_cmos_disk_data(void) |
103 |
{ |
104 |
test_cmos_byte(0x12,
|
105 |
(is_hd(cur_ide[0]) ? 0xf0 : 0) | |
106 |
(is_hd(cur_ide[1]) ? 0x0f : 0)); |
107 |
} |
108 |
|
109 |
static void test_cmos_drive_cyl(int reg0, const CHST *expected_chst) |
110 |
{ |
111 |
if (is_hd(expected_chst)) {
|
112 |
int c = expected_chst->cyls;
|
113 |
int h = expected_chst->heads;
|
114 |
int s = expected_chst->secs;
|
115 |
uint8_t expected_bytes[9] = {
|
116 |
c & 0xff, c >> 8, h, 0xff, 0xff, 0xc0 | ((h > 8) << 3), |
117 |
c & 0xff, c >> 8, s |
118 |
}; |
119 |
test_cmos_bytes(reg0, 9, expected_bytes);
|
120 |
} else {
|
121 |
int i;
|
122 |
|
123 |
for (i = 0; i < 9; i++) { |
124 |
test_cmos_byte(reg0 + i, 0);
|
125 |
} |
126 |
} |
127 |
} |
128 |
|
129 |
static void test_cmos_drive1(void) |
130 |
{ |
131 |
test_cmos_byte(0x19, is_hd(cur_ide[0]) ? 47 : 0); |
132 |
test_cmos_drive_cyl(0x1b, cur_ide[0]); |
133 |
} |
134 |
|
135 |
static void test_cmos_drive2(void) |
136 |
{ |
137 |
test_cmos_byte(0x1a, is_hd(cur_ide[1]) ? 47 : 0); |
138 |
test_cmos_drive_cyl(0x24, cur_ide[1]); |
139 |
} |
140 |
|
141 |
static void test_cmos_disktransflag(void) |
142 |
{ |
143 |
int val, i;
|
144 |
|
145 |
val = 0;
|
146 |
for (i = 0; i < ARRAY_SIZE(cur_ide); i++) { |
147 |
if (is_hd(cur_ide[i])) {
|
148 |
val |= cur_ide[i]->trans << (2 * i);
|
149 |
} |
150 |
} |
151 |
test_cmos_byte(0x39, val);
|
152 |
} |
153 |
|
154 |
static void test_cmos(void) |
155 |
{ |
156 |
test_cmos_disk_data(); |
157 |
test_cmos_drive1(); |
158 |
test_cmos_drive2(); |
159 |
test_cmos_disktransflag(); |
160 |
} |
161 |
|
162 |
static int append_arg(int argc, char *argv[], int argv_sz, char *arg) |
163 |
{ |
164 |
g_assert(argc + 1 < argv_sz);
|
165 |
argv[argc++] = arg; |
166 |
argv[argc] = NULL;
|
167 |
return argc;
|
168 |
} |
169 |
|
170 |
static int setup_common(char *argv[], int argv_sz) |
171 |
{ |
172 |
memset(cur_ide, 0, sizeof(cur_ide)); |
173 |
return append_arg(0, argv, argv_sz, |
174 |
g_strdup("-nodefaults"));
|
175 |
} |
176 |
|
177 |
static void setup_mbr(int img_idx, MBRcontents mbr) |
178 |
{ |
179 |
static const uint8_t part_lba[16] = { |
180 |
/* chs 0,1,1 (lba 63) to chs 0,127,63 (8001 sectors) */
|
181 |
0x80, 1, 1, 0, 6, 127, 63, 0, 63, 0, 0, 0, 0x41, 0x1F, 0, 0, |
182 |
}; |
183 |
static const uint8_t part_chs[16] = { |
184 |
/* chs 0,1,1 (lba 63) to chs 7,15,63 (8001 sectors) */
|
185 |
0x80, 1, 1, 0, 6, 15, 63, 7, 63, 0, 0, 0, 0x41, 0x1F, 0, 0, |
186 |
}; |
187 |
uint8_t buf[512];
|
188 |
int fd, ret;
|
189 |
|
190 |
memset(buf, 0, sizeof(buf)); |
191 |
|
192 |
if (mbr != mbr_blank) {
|
193 |
buf[0x1fe] = 0x55; |
194 |
buf[0x1ff] = 0xAA; |
195 |
memcpy(buf + 0x1BE, mbr == mbr_lba ? part_lba : part_chs, 16); |
196 |
} |
197 |
|
198 |
fd = open(img_file_name[img_idx], O_WRONLY); |
199 |
g_assert(fd >= 0);
|
200 |
ret = write(fd, buf, sizeof(buf));
|
201 |
g_assert(ret == sizeof(buf));
|
202 |
close(fd); |
203 |
} |
204 |
|
205 |
static int setup_ide(int argc, char *argv[], int argv_sz, |
206 |
int ide_idx, const char *dev, int img_idx, |
207 |
MBRcontents mbr, const char *opts) |
208 |
{ |
209 |
char *s1, *s2, *s3;
|
210 |
|
211 |
s1 = g_strdup_printf("-drive id=drive%d,if=%s",
|
212 |
ide_idx, dev ? "none" : "ide"); |
213 |
s2 = dev ? g_strdup("") : g_strdup_printf(",index=%d", ide_idx); |
214 |
|
215 |
if (img_secs[img_idx] >= 0) { |
216 |
setup_mbr(img_idx, mbr); |
217 |
s3 = g_strdup_printf(",file=%s", img_file_name[img_idx]);
|
218 |
} else {
|
219 |
s3 = g_strdup(",media=cdrom");
|
220 |
} |
221 |
argc = append_arg(argc, argv, argv_sz, |
222 |
g_strdup_printf("%s%s%s%s", s1, s2, s3, opts));
|
223 |
g_free(s1); |
224 |
g_free(s2); |
225 |
g_free(s3); |
226 |
|
227 |
if (dev) {
|
228 |
argc = append_arg(argc, argv, argv_sz, |
229 |
g_strdup_printf("-device %s,drive=drive%d,"
|
230 |
"bus=ide.%d,unit=%d",
|
231 |
dev, ide_idx, |
232 |
ide_idx / 2, ide_idx % 2)); |
233 |
} |
234 |
return argc;
|
235 |
} |
236 |
|
237 |
/*
|
238 |
* Test case: no IDE devices
|
239 |
*/
|
240 |
static void test_ide_none(void) |
241 |
{ |
242 |
char *argv[256]; |
243 |
|
244 |
setup_common(argv, ARRAY_SIZE(argv)); |
245 |
qtest_start(g_strjoinv(" ", argv));
|
246 |
test_cmos(); |
247 |
qtest_end(); |
248 |
} |
249 |
|
250 |
static void test_ide_mbr(bool use_device, MBRcontents mbr) |
251 |
{ |
252 |
char *argv[256]; |
253 |
int argc;
|
254 |
Backend i; |
255 |
const char *dev; |
256 |
|
257 |
argc = setup_common(argv, ARRAY_SIZE(argv)); |
258 |
for (i = 0; i < backend_last; i++) { |
259 |
cur_ide[i] = &hd_chst[i][mbr]; |
260 |
dev = use_device ? (is_hd(cur_ide[i]) ? "ide-hd" : "ide-cd") : NULL; |
261 |
argc = setup_ide(argc, argv, ARRAY_SIZE(argv), i, dev, i, mbr, "");
|
262 |
} |
263 |
qtest_start(g_strjoinv(" ", argv));
|
264 |
test_cmos(); |
265 |
qtest_end(); |
266 |
} |
267 |
|
268 |
/*
|
269 |
* Test case: IDE devices (if=ide) with blank MBRs
|
270 |
*/
|
271 |
static void test_ide_drive_mbr_blank(void) |
272 |
{ |
273 |
test_ide_mbr(false, mbr_blank);
|
274 |
} |
275 |
|
276 |
/*
|
277 |
* Test case: IDE devices (if=ide) with MBRs indicating LBA is in use
|
278 |
*/
|
279 |
static void test_ide_drive_mbr_lba(void) |
280 |
{ |
281 |
test_ide_mbr(false, mbr_lba);
|
282 |
} |
283 |
|
284 |
/*
|
285 |
* Test case: IDE devices (if=ide) with MBRs indicating CHS is in use
|
286 |
*/
|
287 |
static void test_ide_drive_mbr_chs(void) |
288 |
{ |
289 |
test_ide_mbr(false, mbr_chs);
|
290 |
} |
291 |
|
292 |
/*
|
293 |
* Test case: IDE devices (if=none) with blank MBRs
|
294 |
*/
|
295 |
static void test_ide_device_mbr_blank(void) |
296 |
{ |
297 |
test_ide_mbr(true, mbr_blank);
|
298 |
} |
299 |
|
300 |
/*
|
301 |
* Test case: IDE devices (if=none) with MBRs indicating LBA is in use
|
302 |
*/
|
303 |
static void test_ide_device_mbr_lba(void) |
304 |
{ |
305 |
test_ide_mbr(true, mbr_lba);
|
306 |
} |
307 |
|
308 |
/*
|
309 |
* Test case: IDE devices (if=none) with MBRs indicating CHS is in use
|
310 |
*/
|
311 |
static void test_ide_device_mbr_chs(void) |
312 |
{ |
313 |
test_ide_mbr(true, mbr_chs);
|
314 |
} |
315 |
|
316 |
static void test_ide_drive_user(const char *dev, bool trans) |
317 |
{ |
318 |
char *argv[256], *opts; |
319 |
int argc;
|
320 |
int secs = img_secs[backend_small];
|
321 |
const CHST expected_chst = { secs / (4 * 32) , 4, 32, trans }; |
322 |
|
323 |
argc = setup_common(argv, ARRAY_SIZE(argv)); |
324 |
opts = g_strdup_printf("%s,%s%scyls=%d,heads=%d,secs=%d",
|
325 |
dev ?: "",
|
326 |
trans && dev ? "bios-chs-" : "", |
327 |
trans ? "trans=lba," : "", |
328 |
expected_chst.cyls, expected_chst.heads, |
329 |
expected_chst.secs); |
330 |
cur_ide[0] = &expected_chst;
|
331 |
argc = setup_ide(argc, argv, ARRAY_SIZE(argv), |
332 |
0, dev ? opts : NULL, backend_small, mbr_chs, |
333 |
dev ? "" : opts);
|
334 |
g_free(opts); |
335 |
qtest_start(g_strjoinv(" ", argv));
|
336 |
test_cmos(); |
337 |
qtest_end(); |
338 |
} |
339 |
|
340 |
/*
|
341 |
* Test case: IDE device (if=ide) with explicit CHS
|
342 |
*/
|
343 |
static void test_ide_drive_user_chs(void) |
344 |
{ |
345 |
test_ide_drive_user(NULL, false); |
346 |
} |
347 |
|
348 |
/*
|
349 |
* Test case: IDE device (if=ide) with explicit CHS and translation
|
350 |
*/
|
351 |
static void test_ide_drive_user_chst(void) |
352 |
{ |
353 |
test_ide_drive_user(NULL, true); |
354 |
} |
355 |
|
356 |
/*
|
357 |
* Test case: IDE device (if=none) with explicit CHS
|
358 |
*/
|
359 |
static void test_ide_device_user_chs(void) |
360 |
{ |
361 |
test_ide_drive_user("ide-hd", false); |
362 |
} |
363 |
|
364 |
/*
|
365 |
* Test case: IDE device (if=none) with explicit CHS and translation
|
366 |
*/
|
367 |
static void test_ide_device_user_chst(void) |
368 |
{ |
369 |
test_ide_drive_user("ide-hd", true); |
370 |
} |
371 |
|
372 |
/*
|
373 |
* Test case: IDE devices (if=ide), but use index=0 for CD-ROM
|
374 |
*/
|
375 |
static void test_ide_drive_cd_0(void) |
376 |
{ |
377 |
char *argv[256]; |
378 |
int argc, ide_idx;
|
379 |
Backend i; |
380 |
|
381 |
argc = setup_common(argv, ARRAY_SIZE(argv)); |
382 |
for (i = 0; i <= backend_empty; i++) { |
383 |
ide_idx = backend_empty - i; |
384 |
cur_ide[ide_idx] = &hd_chst[i][mbr_blank]; |
385 |
argc = setup_ide(argc, argv, ARRAY_SIZE(argv), |
386 |
ide_idx, NULL, i, mbr_blank, ""); |
387 |
} |
388 |
qtest_start(g_strjoinv(" ", argv));
|
389 |
test_cmos(); |
390 |
qtest_end(); |
391 |
} |
392 |
|
393 |
int main(int argc, char **argv) |
394 |
{ |
395 |
Backend i; |
396 |
int ret;
|
397 |
|
398 |
g_test_init(&argc, &argv, NULL);
|
399 |
|
400 |
for (i = 0; i < backend_last; i++) { |
401 |
if (img_secs[i] >= 0) { |
402 |
img_file_name[i] = create_test_img(img_secs[i]); |
403 |
} else {
|
404 |
img_file_name[i] = NULL;
|
405 |
} |
406 |
} |
407 |
|
408 |
qtest_add_func("hd-geo/ide/none", test_ide_none);
|
409 |
qtest_add_func("hd-geo/ide/drive/mbr/blank", test_ide_drive_mbr_blank);
|
410 |
qtest_add_func("hd-geo/ide/drive/mbr/lba", test_ide_drive_mbr_lba);
|
411 |
qtest_add_func("hd-geo/ide/drive/mbr/chs", test_ide_drive_mbr_chs);
|
412 |
qtest_add_func("hd-geo/ide/drive/user/chs", test_ide_drive_user_chs);
|
413 |
qtest_add_func("hd-geo/ide/drive/user/chst", test_ide_drive_user_chst);
|
414 |
qtest_add_func("hd-geo/ide/drive/cd_0", test_ide_drive_cd_0);
|
415 |
qtest_add_func("hd-geo/ide/device/mbr/blank", test_ide_device_mbr_blank);
|
416 |
qtest_add_func("hd-geo/ide/device/mbr/lba", test_ide_device_mbr_lba);
|
417 |
qtest_add_func("hd-geo/ide/device/mbr/chs", test_ide_device_mbr_chs);
|
418 |
qtest_add_func("hd-geo/ide/device/user/chs", test_ide_device_user_chs);
|
419 |
qtest_add_func("hd-geo/ide/device/user/chst", test_ide_device_user_chst);
|
420 |
|
421 |
ret = g_test_run(); |
422 |
|
423 |
for (i = 0; i < backend_last; i++) { |
424 |
unlink(img_file_name[i]); |
425 |
} |
426 |
|
427 |
return ret;
|
428 |
} |