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