1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
/*
* Extended boot option ROM support.
*
* Copyright IBM, Corp. 2007
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
#include "hw.h"
#include "pc.h"
#include "isa.h"
#include "block.h"
/* Extended Boot ROM suport */
union extboot_cmd
{
uint16_t type;
struct {
uint16_t type;
uint16_t cylinders;
uint16_t heads;
uint16_t sectors;
uint64_t nb_sectors;
} query_geometry;
struct {
uint16_t type;
uint16_t nb_sectors;
uint16_t segment;
uint16_t offset;
uint64_t sector;
} xfer;
};
static void get_translated_chs(BlockDriverState *bs, int *c, int *h, int *s)
{
bdrv_get_geometry_hint(bs, c, h, s);
if (*c <= 1024) {
*c >>= 0;
*h <<= 0;
} else if (*c <= 2048) {
*c >>= 1;
*h <<= 1;
} else if (*c <= 4096) {
*c >>= 2;
*h <<= 2;
} else if (*c <= 8192) {
*c >>= 3;
*h <<= 3;
} else {
*c >>= 4;
*h <<= 4;
}
/* what is the correct algorithm for this?? */
if (*h == 256) {
*h = 255;
*c = *c + 1;
}
}
static void extboot_write_cmd(void *opaque, uint32_t addr, uint32_t value)
{
union extboot_cmd cmd;
BlockDriverState *bs = opaque;
int cylinders, heads, sectors, err;
uint64_t nb_sectors;
target_phys_addr_t pa = 0;
int blen = 0;
void *buf = NULL;
cpu_physical_memory_read((value & 0xFFFF) << 4, (uint8_t *)&cmd,
sizeof(cmd));
if (cmd.type == 0x01 || cmd.type == 0x02) {
pa = cmd.xfer.segment * 16 + cmd.xfer.offset;
blen = cmd.xfer.nb_sectors * 512;
buf = qemu_memalign(512, blen);
}
switch (cmd.type) {
case 0x00:
get_translated_chs(bs, &cylinders, &heads, §ors);
bdrv_get_geometry(bs, &nb_sectors);
cmd.query_geometry.cylinders = cylinders;
cmd.query_geometry.heads = heads;
cmd.query_geometry.sectors = sectors;
cmd.query_geometry.nb_sectors = nb_sectors;
break;
case 0x01:
err = bdrv_read(bs, cmd.xfer.sector, buf, cmd.xfer.nb_sectors);
if (err)
printf("Read failed\n");
cpu_physical_memory_write(pa, buf, blen);
break;
case 0x02:
cpu_physical_memory_read(pa, buf, blen);
err = bdrv_write(bs, cmd.xfer.sector, buf, cmd.xfer.nb_sectors);
if (err)
printf("Write failed\n");
break;
}
cpu_physical_memory_write((value & 0xFFFF) << 4, (uint8_t *)&cmd,
sizeof(cmd));
if (buf)
qemu_free(buf);
}
void extboot_init(BlockDriverState *bs)
{
register_ioport_write(0x405, 1, 2, extboot_write_cmd, bs);
}
|