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

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

unix.superglobalmegacorp.com

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