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