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

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.1.5 ! root       20: u8 *bounce_buf_fl VAR16VISIBLE;
1.1       root       21: 
                     22: struct drive_s *
                     23: getDrive(u8 exttype, u8 extdriveoffset)
                     24: {
1.1.1.4   root       25:     if (extdriveoffset >= ARRAY_SIZE(IDMap[0]))
1.1       root       26:         return NULL;
1.1.1.4   root       27:     struct drive_s *drive_gf = GET_GLOBAL(IDMap[exttype][extdriveoffset]);
1.1.1.3   root       28:     if (!drive_gf)
1.1       root       29:         return NULL;
1.1.1.3   root       30:     return GLOBALFLAT2GLOBAL(drive_gf);
1.1       root       31: }
                     32: 
1.1.1.4   root       33: int getDriveId(u8 exttype, struct drive_s *drive_g)
                     34: {
                     35:     int i;
                     36:     for (i = 0; i < ARRAY_SIZE(IDMap[0]); i++)
                     37:         if (getDrive(exttype, i) == drive_g)
                     38:             return i;
                     39:     return -1;
                     40: }
                     41: 
1.1.1.5 ! root       42: int bounce_buf_init(void)
        !            43: {
        !            44:     if (bounce_buf_fl)
        !            45:         return 0;
        !            46: 
        !            47:     u8 *buf = malloc_low(CDROM_SECTOR_SIZE);
        !            48:     if (!buf) {
        !            49:         warn_noalloc();
        !            50:         return -1;
        !            51:     }
        !            52:     bounce_buf_fl = buf;
        !            53:     return 0;
        !            54: }
1.1       root       55: 
                     56: /****************************************************************
                     57:  * Disk geometry translation
                     58:  ****************************************************************/
                     59: 
                     60: static u8
                     61: get_translation(struct drive_s *drive_g)
                     62: {
                     63:     u8 type = GET_GLOBAL(drive_g->type);
                     64:     if (! CONFIG_COREBOOT && type == DTYPE_ATA) {
                     65:         // Emulators pass in the translation info via nvram.
                     66:         u8 ataid = GET_GLOBAL(drive_g->cntl_id);
                     67:         u8 channel = ataid / 2;
                     68:         u8 translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2);
                     69:         translation >>= 2 * (ataid % 4);
                     70:         translation &= 0x03;
                     71:         return translation;
                     72:     }
                     73: 
1.1.1.3   root       74:     // Otherwise use a heuristic to determine translation type.
1.1       root       75:     u16 heads = GET_GLOBAL(drive_g->pchs.heads);
                     76:     u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders);
                     77:     u16 spt = GET_GLOBAL(drive_g->pchs.spt);
1.1.1.3   root       78:     u64 sectors = GET_GLOBAL(drive_g->sectors);
                     79:     u64 psectors = (u64)heads * cylinders * spt;
                     80:     if (!heads || !cylinders || !spt || psectors > sectors)
                     81:         // pchs doesn't look valid - use LBA.
                     82:         return TRANSLATION_LBA;
1.1       root       83: 
                     84:     if (cylinders <= 1024 && heads <= 16 && spt <= 63)
                     85:         return TRANSLATION_NONE;
                     86:     if (cylinders * heads <= 131072)
                     87:         return TRANSLATION_LARGE;
                     88:     return TRANSLATION_LBA;
                     89: }
                     90: 
1.1.1.4   root       91: static void
1.1       root       92: setup_translation(struct drive_s *drive_g)
                     93: {
                     94:     u8 translation = get_translation(drive_g);
                     95:     SET_GLOBAL(drive_g->translation, translation);
                     96: 
                     97:     u16 heads = GET_GLOBAL(drive_g->pchs.heads);
                     98:     u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders);
                     99:     u16 spt = GET_GLOBAL(drive_g->pchs.spt);
                    100:     u64 sectors = GET_GLOBAL(drive_g->sectors);
                    101:     const char *desc = NULL;
                    102: 
                    103:     switch (translation) {
                    104:     default:
                    105:     case TRANSLATION_NONE:
                    106:         desc = "none";
                    107:         break;
                    108:     case TRANSLATION_LBA:
                    109:         desc = "lba";
                    110:         spt = 63;
                    111:         if (sectors > 63*255*1024) {
                    112:             heads = 255;
                    113:             cylinders = 1024;
                    114:             break;
                    115:         }
                    116:         u32 sect = (u32)sectors / 63;
                    117:         heads = sect / 1024;
                    118:         if (heads>128)
                    119:             heads = 255;
                    120:         else if (heads>64)
                    121:             heads = 128;
                    122:         else if (heads>32)
                    123:             heads = 64;
                    124:         else if (heads>16)
                    125:             heads = 32;
                    126:         else
                    127:             heads = 16;
                    128:         cylinders = sect / heads;
                    129:         break;
                    130:     case TRANSLATION_RECHS:
                    131:         desc = "r-echs";
                    132:         // Take care not to overflow
                    133:         if (heads==16) {
                    134:             if (cylinders>61439)
                    135:                 cylinders=61439;
                    136:             heads=15;
                    137:             cylinders = (u16)((u32)(cylinders)*16/15);
                    138:         }
                    139:         // then go through the large bitshift process
                    140:     case TRANSLATION_LARGE:
                    141:         if (translation == TRANSLATION_LARGE)
                    142:             desc = "large";
                    143:         while (cylinders > 1024) {
                    144:             cylinders >>= 1;
                    145:             heads <<= 1;
                    146: 
                    147:             // If we max out the head count
                    148:             if (heads > 127)
                    149:                 break;
                    150:         }
                    151:         break;
                    152:     }
                    153:     // clip to 1024 cylinders in lchs
                    154:     if (cylinders > 1024)
                    155:         cylinders = 1024;
1.1.1.3   root      156:     dprintf(1, "drive %p: PCHS=%u/%d/%d translation=%s LCHS=%d/%d/%d s=%d\n"
                    157:             , drive_g
1.1       root      158:             , drive_g->pchs.cylinders, drive_g->pchs.heads, drive_g->pchs.spt
                    159:             , desc
1.1.1.3   root      160:             , cylinders, heads, spt
                    161:             , (u32)sectors);
1.1       root      162: 
                    163:     SET_GLOBAL(drive_g->lchs.heads, heads);
                    164:     SET_GLOBAL(drive_g->lchs.cylinders, cylinders);
                    165:     SET_GLOBAL(drive_g->lchs.spt, spt);
                    166: }
                    167: 
                    168: 
                    169: /****************************************************************
                    170:  * Drive mapping
                    171:  ****************************************************************/
                    172: 
                    173: // Fill in Fixed Disk Parameter Table (located in ebda).
                    174: static void
                    175: fill_fdpt(struct drive_s *drive_g, int hdid)
                    176: {
                    177:     if (hdid > 1)
                    178:         return;
                    179: 
                    180:     u16 nlc   = GET_GLOBAL(drive_g->lchs.cylinders);
                    181:     u16 nlh   = GET_GLOBAL(drive_g->lchs.heads);
                    182:     u16 nlspt = GET_GLOBAL(drive_g->lchs.spt);
                    183: 
                    184:     u16 npc   = GET_GLOBAL(drive_g->pchs.cylinders);
                    185:     u16 nph   = GET_GLOBAL(drive_g->pchs.heads);
                    186:     u16 npspt = GET_GLOBAL(drive_g->pchs.spt);
                    187: 
                    188:     struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[hdid];
                    189:     fdpt->precompensation = 0xffff;
                    190:     fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3);
                    191:     fdpt->landing_zone = npc;
                    192:     fdpt->cylinders = nlc;
                    193:     fdpt->heads = nlh;
                    194:     fdpt->sectors = nlspt;
                    195: 
1.1.1.2   root      196:     if (nlc != npc || nlh != nph || nlspt != npspt) {
                    197:         // Logical mapping present - use extended structure.
1.1       root      198: 
1.1.1.2   root      199:         // complies with Phoenix style Translated Fixed Disk Parameter
                    200:         // Table (FDPT)
                    201:         fdpt->phys_cylinders = npc;
                    202:         fdpt->phys_heads = nph;
                    203:         fdpt->phys_sectors = npspt;
                    204:         fdpt->a0h_signature = 0xa0;
1.1       root      205: 
1.1.1.2   root      206:         // Checksum structure.
                    207:         fdpt->checksum -= checksum(fdpt, sizeof(*fdpt));
                    208:     }
1.1       root      209: 
                    210:     if (hdid == 0)
                    211:         SET_IVT(0x41, SEGOFF(get_ebda_seg(), offsetof(
                    212:                                  struct extended_bios_data_area_s, fdpt[0])));
                    213:     else
                    214:         SET_IVT(0x46, SEGOFF(get_ebda_seg(), offsetof(
                    215:                                  struct extended_bios_data_area_s, fdpt[1])));
                    216: }
                    217: 
                    218: // Find spot to add a drive
                    219: static void
1.1.1.4   root      220: add_drive(struct drive_s **idmap, u8 *count, struct drive_s *drive_g)
1.1       root      221: {
1.1.1.4   root      222:     if (*count >= ARRAY_SIZE(IDMap[0])) {
1.1.1.3   root      223:         warn_noalloc();
1.1       root      224:         return;
                    225:     }
1.1.1.4   root      226:     idmap[*count] = drive_g;
1.1       root      227:     *count = *count + 1;
1.1.1.4   root      228: }
                    229: 
                    230: // Map a hard drive
                    231: void
                    232: map_hd_drive(struct drive_s *drive_g)
                    233: {
                    234:     ASSERT32FLAT();
                    235:     struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
                    236:     int hdid = bda->hdcount;
                    237:     dprintf(3, "Mapping hd drive %p to %d\n", drive_g, hdid);
                    238:     add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive_g);
                    239: 
                    240:     // Setup disk geometry translation.
                    241:     setup_translation(drive_g);
                    242: 
                    243:     // Fill "fdpt" structure.
                    244:     fill_fdpt(drive_g, hdid);
1.1       root      245: }
                    246: 
                    247: // Map a cd
                    248: void
                    249: map_cd_drive(struct drive_s *drive_g)
                    250: {
                    251:     dprintf(3, "Mapping cd drive %p\n", drive_g);
1.1.1.4   root      252:     add_drive(IDMap[EXTTYPE_CD], &CDCount, drive_g);
1.1       root      253: }
                    254: 
                    255: // Map a floppy
                    256: void
                    257: map_floppy_drive(struct drive_s *drive_g)
                    258: {
                    259:     dprintf(3, "Mapping floppy drive %p\n", drive_g);
1.1.1.4   root      260:     add_drive(IDMap[EXTTYPE_FLOPPY], &FloppyCount, drive_g);
1.1       root      261: 
                    262:     // Update equipment word bits for floppy
1.1.1.4   root      263:     if (FloppyCount == 1) {
1.1       root      264:         // 1 drive, ready for boot
                    265:         SETBITS_BDA(equipment_list_flags, 0x01);
                    266:         SET_BDA(floppy_harddisk_info, 0x07);
1.1.1.4   root      267:     } else if (FloppyCount >= 2) {
1.1       root      268:         // 2 drives, ready for boot
                    269:         SETBITS_BDA(equipment_list_flags, 0x41);
                    270:         SET_BDA(floppy_harddisk_info, 0x77);
                    271:     }
                    272: }
                    273: 
                    274: 
                    275: /****************************************************************
                    276:  * 16bit calling interface
                    277:  ****************************************************************/
                    278: 
                    279: // Execute a disk_op request.
                    280: int
                    281: process_op(struct disk_op_s *op)
                    282: {
1.1.1.3   root      283:     ASSERT16();
1.1       root      284:     u8 type = GET_GLOBAL(op->drive_g->type);
                    285:     switch (type) {
                    286:     case DTYPE_FLOPPY:
                    287:         return process_floppy_op(op);
                    288:     case DTYPE_ATA:
                    289:         return process_ata_op(op);
                    290:     case DTYPE_ATAPI:
                    291:         return process_atapi_op(op);
                    292:     case DTYPE_RAMDISK:
                    293:         return process_ramdisk_op(op);
                    294:     case DTYPE_CDEMU:
                    295:         return process_cdemu_op(op);
1.1.1.3   root      296:     case DTYPE_USB:
                    297:         return process_usb_op(op);
                    298:     case DTYPE_VIRTIO:
                    299:        return process_virtio_op(op);
1.1.1.4   root      300:     case DTYPE_AHCI:
                    301:        return process_ahci_op(op);
1.1       root      302:     default:
                    303:         op->count = 0;
                    304:         return DISK_RET_EPARAM;
                    305:     }
                    306: }
                    307: 
                    308: // Execute a "disk_op_s" request - this runs on a stack in the ebda.
                    309: static int
                    310: __send_disk_op(struct disk_op_s *op_far, u16 op_seg)
                    311: {
                    312:     struct disk_op_s dop;
                    313:     memcpy_far(GET_SEG(SS), &dop
                    314:                , op_seg, op_far
                    315:                , sizeof(dop));
                    316: 
                    317:     dprintf(DEBUG_HDL_13, "disk_op d=%p lba=%d buf=%p count=%d cmd=%d\n"
                    318:             , dop.drive_g, (u32)dop.lba, dop.buf_fl
                    319:             , dop.count, dop.command);
                    320: 
                    321:     int status = process_op(&dop);
                    322: 
                    323:     // Update count with total sectors transferred.
                    324:     SET_FARVAR(op_seg, op_far->count, dop.count);
                    325: 
                    326:     return status;
                    327: }
                    328: 
                    329: // Execute a "disk_op_s" request by jumping to a stack in the ebda.
                    330: int
                    331: send_disk_op(struct disk_op_s *op)
                    332: {
1.1.1.3   root      333:     ASSERT16();
1.1       root      334:     if (! CONFIG_DRIVES)
                    335:         return -1;
                    336: 
1.1.1.3   root      337:     return stack_hop((u32)op, GET_SEG(SS), __send_disk_op);
1.1       root      338: }

unix.superglobalmegacorp.com

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