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

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

unix.superglobalmegacorp.com

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