Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
[palacios.git] / bios / seabios / src / block.c
1 // Disk setup and access
2 //
3 // Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002  MandrakeSoft S.A.
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "disk.h" // struct ata_s
9 #include "biosvar.h" // GET_GLOBAL
10 #include "cmos.h" // inb_cmos
11 #include "util.h" // dprintf
12 #include "ata.h" // process_ata_op
13 #include "ahci.h" // process_ahci_op
14 #include "usb-msc.h" // process_usb_op
15 #include "virtio-blk.h" // process_virtio_op
16
17 u8 FloppyCount VAR16VISIBLE;
18 u8 CDCount;
19 struct drive_s *IDMap[3][CONFIG_MAX_EXTDRIVE] VAR16VISIBLE;
20 u8 *bounce_buf_fl VAR16VISIBLE;
21
22 struct drive_s *
23 getDrive(u8 exttype, u8 extdriveoffset)
24 {
25     if (extdriveoffset >= ARRAY_SIZE(IDMap[0]))
26         return NULL;
27     struct drive_s *drive_gf = GET_GLOBAL(IDMap[exttype][extdriveoffset]);
28     if (!drive_gf)
29         return NULL;
30     return GLOBALFLAT2GLOBAL(drive_gf);
31 }
32
33 int getDriveId(u8 exttype, struct drive_s *drive_g)
34 {
35     int i;
36     for (i = 0; i < ARRAY_SIZE(IDMap[0]); i++)
37         if (getDrive(exttype, i) == drive_g)
38             return i;
39     return -1;
40 }
41
42 int bounce_buf_init(void)
43 {
44     if (bounce_buf_fl)
45         return 0;
46
47     u8 *buf = malloc_low(CDROM_SECTOR_SIZE);
48     if (!buf) {
49         warn_noalloc();
50         return -1;
51     }
52     bounce_buf_fl = buf;
53     return 0;
54 }
55
56 /****************************************************************
57  * Disk geometry translation
58  ****************************************************************/
59
60 static u8
61 get_translation(struct drive_s *drive_g)
62 {
63     u8 type = GET_GLOBAL(drive_g->type);
64     if (! CONFIG_COREBOOT && type == DTYPE_ATA) {
65         // Emulators pass in the translation info via nvram.
66         u8 ataid = GET_GLOBAL(drive_g->cntl_id);
67         u8 channel = ataid / 2;
68         u8 translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2);
69         translation >>= 2 * (ataid % 4);
70         translation &= 0x03;
71         return translation;
72     }
73
74     // Otherwise use a heuristic to determine translation type.
75     u16 heads = GET_GLOBAL(drive_g->pchs.heads);
76     u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders);
77     u16 spt = GET_GLOBAL(drive_g->pchs.spt);
78     u64 sectors = GET_GLOBAL(drive_g->sectors);
79     u64 psectors = (u64)heads * cylinders * spt;
80     if (!heads || !cylinders || !spt || psectors > sectors)
81         // pchs doesn't look valid - use LBA.
82         return TRANSLATION_LBA;
83
84     if (cylinders <= 1024 && heads <= 16 && spt <= 63)
85         return TRANSLATION_NONE;
86     if (cylinders * heads <= 131072)
87         return TRANSLATION_LARGE;
88     return TRANSLATION_LBA;
89 }
90
91 static void
92 setup_translation(struct drive_s *drive_g)
93 {
94     u8 translation = get_translation(drive_g);
95     SET_GLOBAL(drive_g->translation, translation);
96
97     u16 heads = GET_GLOBAL(drive_g->pchs.heads);
98     u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders);
99     u16 spt = GET_GLOBAL(drive_g->pchs.spt);
100     u64 sectors = GET_GLOBAL(drive_g->sectors);
101     const char *desc = NULL;
102
103     switch (translation) {
104     default:
105     case TRANSLATION_NONE:
106         desc = "none";
107         break;
108     case TRANSLATION_LBA:
109         desc = "lba";
110         spt = 63;
111         if (sectors > 63*255*1024) {
112             heads = 255;
113             cylinders = 1024;
114             break;
115         }
116         u32 sect = (u32)sectors / 63;
117         heads = sect / 1024;
118         if (heads>128)
119             heads = 255;
120         else if (heads>64)
121             heads = 128;
122         else if (heads>32)
123             heads = 64;
124         else if (heads>16)
125             heads = 32;
126         else
127             heads = 16;
128         cylinders = sect / heads;
129         break;
130     case TRANSLATION_RECHS:
131         desc = "r-echs";
132         // Take care not to overflow
133         if (heads==16) {
134             if (cylinders>61439)
135                 cylinders=61439;
136             heads=15;
137             cylinders = (u16)((u32)(cylinders)*16/15);
138         }
139         // then go through the large bitshift process
140     case TRANSLATION_LARGE:
141         if (translation == TRANSLATION_LARGE)
142             desc = "large";
143         while (cylinders > 1024) {
144             cylinders >>= 1;
145             heads <<= 1;
146
147             // If we max out the head count
148             if (heads > 127)
149                 break;
150         }
151         break;
152     }
153     // clip to 1024 cylinders in lchs
154     if (cylinders > 1024)
155         cylinders = 1024;
156     dprintf(1, "drive %p: PCHS=%u/%d/%d translation=%s LCHS=%d/%d/%d s=%d\n"
157             , drive_g
158             , drive_g->pchs.cylinders, drive_g->pchs.heads, drive_g->pchs.spt
159             , desc
160             , cylinders, heads, spt
161             , (u32)sectors);
162
163     SET_GLOBAL(drive_g->lchs.heads, heads);
164     SET_GLOBAL(drive_g->lchs.cylinders, cylinders);
165     SET_GLOBAL(drive_g->lchs.spt, spt);
166 }
167
168
169 /****************************************************************
170  * Drive mapping
171  ****************************************************************/
172
173 // Fill in Fixed Disk Parameter Table (located in ebda).
174 static void
175 fill_fdpt(struct drive_s *drive_g, int hdid)
176 {
177     if (hdid > 1)
178         return;
179
180     u16 nlc   = GET_GLOBAL(drive_g->lchs.cylinders);
181     u16 nlh   = GET_GLOBAL(drive_g->lchs.heads);
182     u16 nlspt = GET_GLOBAL(drive_g->lchs.spt);
183
184     u16 npc   = GET_GLOBAL(drive_g->pchs.cylinders);
185     u16 nph   = GET_GLOBAL(drive_g->pchs.heads);
186     u16 npspt = GET_GLOBAL(drive_g->pchs.spt);
187
188     struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[hdid];
189     fdpt->precompensation = 0xffff;
190     fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3);
191     fdpt->landing_zone = npc;
192     fdpt->cylinders = nlc;
193     fdpt->heads = nlh;
194     fdpt->sectors = nlspt;
195
196     if (nlc != npc || nlh != nph || nlspt != npspt) {
197         // Logical mapping present - use extended structure.
198
199         // complies with Phoenix style Translated Fixed Disk Parameter
200         // Table (FDPT)
201         fdpt->phys_cylinders = npc;
202         fdpt->phys_heads = nph;
203         fdpt->phys_sectors = npspt;
204         fdpt->a0h_signature = 0xa0;
205
206         // Checksum structure.
207         fdpt->checksum -= checksum(fdpt, sizeof(*fdpt));
208     }
209
210     if (hdid == 0)
211         SET_IVT(0x41, SEGOFF(get_ebda_seg(), offsetof(
212                                  struct extended_bios_data_area_s, fdpt[0])));
213     else
214         SET_IVT(0x46, SEGOFF(get_ebda_seg(), offsetof(
215                                  struct extended_bios_data_area_s, fdpt[1])));
216 }
217
218 // Find spot to add a drive
219 static void
220 add_drive(struct drive_s **idmap, u8 *count, struct drive_s *drive_g)
221 {
222     if (*count >= ARRAY_SIZE(IDMap[0])) {
223         warn_noalloc();
224         return;
225     }
226     idmap[*count] = drive_g;
227     *count = *count + 1;
228 }
229
230 // Map a hard drive
231 void
232 map_hd_drive(struct drive_s *drive_g)
233 {
234     ASSERT32FLAT();
235     struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
236     int hdid = bda->hdcount;
237     dprintf(3, "Mapping hd drive %p to %d\n", drive_g, hdid);
238     add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive_g);
239
240     // Setup disk geometry translation.
241     setup_translation(drive_g);
242
243     // Fill "fdpt" structure.
244     fill_fdpt(drive_g, hdid);
245 }
246
247 // Map a cd
248 void
249 map_cd_drive(struct drive_s *drive_g)
250 {
251     dprintf(3, "Mapping cd drive %p\n", drive_g);
252     add_drive(IDMap[EXTTYPE_CD], &CDCount, drive_g);
253 }
254
255 // Map a floppy
256 void
257 map_floppy_drive(struct drive_s *drive_g)
258 {
259     dprintf(3, "Mapping floppy drive %p\n", drive_g);
260     add_drive(IDMap[EXTTYPE_FLOPPY], &FloppyCount, drive_g);
261
262     // Update equipment word bits for floppy
263     if (FloppyCount == 1) {
264         // 1 drive, ready for boot
265         SETBITS_BDA(equipment_list_flags, 0x01);
266         SET_BDA(floppy_harddisk_info, 0x07);
267     } else if (FloppyCount >= 2) {
268         // 2 drives, ready for boot
269         SETBITS_BDA(equipment_list_flags, 0x41);
270         SET_BDA(floppy_harddisk_info, 0x77);
271     }
272 }
273
274
275 /****************************************************************
276  * 16bit calling interface
277  ****************************************************************/
278
279 // Execute a disk_op request.
280 int
281 process_op(struct disk_op_s *op)
282 {
283     ASSERT16();
284     u8 type = GET_GLOBAL(op->drive_g->type);
285     switch (type) {
286     case DTYPE_FLOPPY:
287         return process_floppy_op(op);
288     case DTYPE_ATA:
289         return process_ata_op(op);
290     case DTYPE_ATAPI:
291         return process_atapi_op(op);
292     case DTYPE_RAMDISK:
293         return process_ramdisk_op(op);
294     case DTYPE_CDEMU:
295         return process_cdemu_op(op);
296     case DTYPE_USB:
297         return process_usb_op(op);
298     case DTYPE_VIRTIO:
299         return process_virtio_op(op);
300     case DTYPE_AHCI:
301         return process_ahci_op(op);
302     default:
303         op->count = 0;
304         return DISK_RET_EPARAM;
305     }
306 }
307
308 // Execute a "disk_op_s" request - this runs on a stack in the ebda.
309 static int
310 __send_disk_op(struct disk_op_s *op_far, u16 op_seg)
311 {
312     struct disk_op_s dop;
313     memcpy_far(GET_SEG(SS), &dop
314                , op_seg, op_far
315                , sizeof(dop));
316
317     dprintf(DEBUG_HDL_13, "disk_op d=%p lba=%d buf=%p count=%d cmd=%d\n"
318             , dop.drive_g, (u32)dop.lba, dop.buf_fl
319             , dop.count, dop.command);
320
321     int status = process_op(&dop);
322
323     // Update count with total sectors transferred.
324     SET_FARVAR(op_seg, op_far->count, dop.count);
325
326     return status;
327 }
328
329 // Execute a "disk_op_s" request by jumping to a stack in the ebda.
330 int
331 send_disk_op(struct disk_op_s *op)
332 {
333     ASSERT16();
334     if (! CONFIG_DRIVES)
335         return -1;
336
337     return stack_hop((u32)op, GET_SEG(SS), __send_disk_op);
338 }