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

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 *
1.1.1.2 ! root       34: allocDrive(void)
1.1       root       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: 
1.1.1.2 ! root      183:     if (nlc != npc || nlh != nph || nlspt != npspt) {
        !           184:         // Logical mapping present - use extended structure.
1.1       root      185: 
1.1.1.2 ! root      186:         // complies with Phoenix style Translated Fixed Disk Parameter
        !           187:         // Table (FDPT)
        !           188:         fdpt->phys_cylinders = npc;
        !           189:         fdpt->phys_heads = nph;
        !           190:         fdpt->phys_sectors = npspt;
        !           191:         fdpt->a0h_signature = 0xa0;
1.1       root      192: 
1.1.1.2 ! root      193:         // Checksum structure.
        !           194:         fdpt->checksum -= checksum(fdpt, sizeof(*fdpt));
        !           195:     }
1.1       root      196: 
                    197:     if (hdid == 0)
                    198:         SET_IVT(0x41, SEGOFF(get_ebda_seg(), offsetof(
                    199:                                  struct extended_bios_data_area_s, fdpt[0])));
                    200:     else
                    201:         SET_IVT(0x46, SEGOFF(get_ebda_seg(), offsetof(
                    202:                                  struct extended_bios_data_area_s, fdpt[1])));
                    203: }
                    204: 
                    205: // Map a drive (that was registered via add_bcv_hd)
                    206: void
                    207: map_hd_drive(struct drive_s *drive_g)
                    208: {
                    209:     // fill hdidmap
                    210:     u8 hdcount = GET_BDA(hdcount);
                    211:     if (hdcount >= ARRAY_SIZE(Drives.idmap[0]))
                    212:         return;
                    213:     dprintf(3, "Mapping hd drive %p to %d\n", drive_g, hdcount);
                    214:     int driveid = drive_g - Drives.drives;
                    215:     SET_GLOBAL(Drives.idmap[EXTTYPE_HD][hdcount], driveid);
                    216:     SET_BDA(hdcount, hdcount + 1);
                    217: 
                    218:     // Fill "fdpt" structure.
                    219:     fill_fdpt(drive_g, hdcount);
                    220: }
                    221: 
                    222: // Find spot to add a drive
                    223: static void
                    224: add_ordered_drive(u8 *idmap, u8 *count, struct drive_s *drive_g)
                    225: {
                    226:     if (*count >= ARRAY_SIZE(Drives.idmap[0])) {
                    227:         dprintf(1, "No room to map drive %p\n", drive_g);
                    228:         return;
                    229:     }
                    230:     u8 *pos = &idmap[*count];
                    231:     *count = *count + 1;
                    232:     if (CONFIG_THREADS) {
                    233:         // Add to idmap with assured drive order.
                    234:         u8 *end = pos;
                    235:         for (;;) {
                    236:             u8 *prev = pos - 1;
                    237:             if (prev < idmap)
                    238:                 break;
                    239:             struct drive_s *prevdrive = &Drives.drives[*prev];
                    240:             if (prevdrive->type < drive_g->type
                    241:                 || (prevdrive->type == drive_g->type
                    242:                     && prevdrive->cntl_id < drive_g->cntl_id))
                    243:                 break;
                    244:             pos--;
                    245:         }
                    246:         if (pos != end)
                    247:             memmove(pos+1, pos, (void*)end-(void*)pos);
                    248:     }
                    249:     *pos = drive_g - Drives.drives;
                    250: }
                    251: 
                    252: // Map a cd
                    253: void
                    254: map_cd_drive(struct drive_s *drive_g)
                    255: {
                    256:     dprintf(3, "Mapping cd drive %p\n", drive_g);
                    257:     add_ordered_drive(Drives.idmap[EXTTYPE_CD], &Drives.cdcount, drive_g);
                    258: }
                    259: 
                    260: // Map a floppy
                    261: void
                    262: map_floppy_drive(struct drive_s *drive_g)
                    263: {
                    264:     // fill idmap
                    265:     dprintf(3, "Mapping floppy drive %p\n", drive_g);
                    266:     add_ordered_drive(Drives.idmap[EXTTYPE_FLOPPY], &Drives.floppycount
                    267:                       , drive_g);
                    268: 
                    269:     // Update equipment word bits for floppy
                    270:     if (Drives.floppycount == 1) {
                    271:         // 1 drive, ready for boot
                    272:         SETBITS_BDA(equipment_list_flags, 0x01);
                    273:         SET_BDA(floppy_harddisk_info, 0x07);
                    274:     } else if (Drives.floppycount >= 2) {
                    275:         // 2 drives, ready for boot
                    276:         SETBITS_BDA(equipment_list_flags, 0x41);
                    277:         SET_BDA(floppy_harddisk_info, 0x77);
                    278:     }
                    279: }
                    280: 
                    281: // Show a one line description (without trailing newline) of a drive.
                    282: void
                    283: describe_drive(struct drive_s *drive_g)
                    284: {
1.1.1.2 ! root      285:     ASSERT32FLAT();
1.1       root      286:     u8 type = GET_GLOBAL(drive_g->type);
                    287:     switch (type) {
                    288:     case DTYPE_FLOPPY:
                    289:         describe_floppy(drive_g);
                    290:         break;
                    291:     case DTYPE_ATA:
                    292:         describe_ata(drive_g);
                    293:         break;
                    294:     case DTYPE_ATAPI:
                    295:         describe_atapi(drive_g);
                    296:         break;
                    297:     case DTYPE_RAMDISK:
                    298:         describe_ramdisk(drive_g);
                    299:         break;
                    300:     default:
                    301:         printf("Unknown");
                    302:         break;
                    303:     }
                    304: }
                    305: 
                    306: 
                    307: /****************************************************************
                    308:  * 16bit calling interface
                    309:  ****************************************************************/
                    310: 
                    311: // Execute a disk_op request.
                    312: int
                    313: process_op(struct disk_op_s *op)
                    314: {
                    315:     u8 type = GET_GLOBAL(op->drive_g->type);
                    316:     switch (type) {
                    317:     case DTYPE_FLOPPY:
                    318:         return process_floppy_op(op);
                    319:     case DTYPE_ATA:
                    320:         return process_ata_op(op);
                    321:     case DTYPE_ATAPI:
                    322:         return process_atapi_op(op);
                    323:     case DTYPE_RAMDISK:
                    324:         return process_ramdisk_op(op);
                    325:     case DTYPE_CDEMU:
                    326:         return process_cdemu_op(op);
                    327:     default:
                    328:         op->count = 0;
                    329:         return DISK_RET_EPARAM;
                    330:     }
                    331: }
                    332: 
                    333: // Execute a "disk_op_s" request - this runs on a stack in the ebda.
                    334: static int
                    335: __send_disk_op(struct disk_op_s *op_far, u16 op_seg)
                    336: {
                    337:     struct disk_op_s dop;
                    338:     memcpy_far(GET_SEG(SS), &dop
                    339:                , op_seg, op_far
                    340:                , sizeof(dop));
                    341: 
                    342:     dprintf(DEBUG_HDL_13, "disk_op d=%p lba=%d buf=%p count=%d cmd=%d\n"
                    343:             , dop.drive_g, (u32)dop.lba, dop.buf_fl
                    344:             , dop.count, dop.command);
                    345: 
                    346:     int status = process_op(&dop);
                    347: 
                    348:     // Update count with total sectors transferred.
                    349:     SET_FARVAR(op_seg, op_far->count, dop.count);
                    350: 
                    351:     return status;
                    352: }
                    353: 
                    354: // Execute a "disk_op_s" request by jumping to a stack in the ebda.
                    355: int
                    356: send_disk_op(struct disk_op_s *op)
                    357: {
                    358:     if (! CONFIG_DRIVES)
                    359:         return -1;
                    360:     ASSERT16();
                    361: 
                    362:     return stack_hop((u32)op, GET_SEG(SS), 0, __send_disk_op);
                    363: }
                    364: 
                    365: 
                    366: /****************************************************************
                    367:  * Setup
                    368:  ****************************************************************/
                    369: 
                    370: void
1.1.1.2 ! root      371: drive_setup(void)
1.1       root      372: {
                    373:     memset(&Drives, 0, sizeof(Drives));
                    374:     memset(&Drives.idmap, 0xff, sizeof(Drives.idmap));
                    375: }

unix.superglobalmegacorp.com

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