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