Annotation of qemu/roms/seabios/src/block.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.