Annotation of qemu/roms/seabios/src/block.c, revision 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.