ide_disk.cc revision 1762
12817Sksewell@umich.edu/* 28733Sgeoffrey.blake@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan 37763SAli.Saidi@ARM.com * All rights reserved. 47763SAli.Saidi@ARM.com * 57763SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without 67763SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are 77763SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright 87763SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer; 97763SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright 107763SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the 117763SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution; 127763SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its 137763SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from 142817Sksewell@umich.edu * this software without specific prior written permission. 152817Sksewell@umich.edu * 162817Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172817Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182817Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192817Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202817Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212817Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222817Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232817Sksewell@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242817Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252817Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262817Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272817Sksewell@umich.edu */ 282817Sksewell@umich.edu 292817Sksewell@umich.edu/** @file 302817Sksewell@umich.edu * Device model implementation for an IDE disk 312817Sksewell@umich.edu */ 322817Sksewell@umich.edu 332817Sksewell@umich.edu#include <cerrno> 342817Sksewell@umich.edu#include <cstring> 352817Sksewell@umich.edu#include <deque> 362817Sksewell@umich.edu#include <string> 372817Sksewell@umich.edu 382817Sksewell@umich.edu#include "base/cprintf.hh" // csprintf 392817Sksewell@umich.edu#include "base/trace.hh" 402817Sksewell@umich.edu#include "dev/disk_image.hh" 412817Sksewell@umich.edu#include "dev/ide_disk.hh" 422817Sksewell@umich.edu#include "dev/ide_ctrl.hh" 432817Sksewell@umich.edu#include "dev/tsunami.hh" 448793Sgblack@eecs.umich.edu#include "dev/tsunami_pchip.hh" 456329Sgblack@eecs.umich.edu#include "mem/functional/physical.hh" 466658Snate@binkert.org#include "mem/bus/bus.hh" 478733Sgeoffrey.blake@arm.com#include "mem/bus/dma_interface.hh" 482817Sksewell@umich.edu#include "mem/bus/pio_interface.hh" 492834Sksewell@umich.edu#include "mem/bus/pio_interface_impl.hh" 508232Snate@binkert.org#include "sim/builder.hh" 512817Sksewell@umich.edu#include "sim/sim_object.hh" 522817Sksewell@umich.edu#include "sim/root.hh" 538852Sandreas.hansson@arm.com#include "targetarch/isa_traits.hh" 548706Sandreas.hansson@arm.com 552817Sksewell@umich.eduusing namespace std; 568706Sandreas.hansson@arm.com 572817Sksewell@umich.eduIdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys, 582817Sksewell@umich.edu int id, Tick delay) 592817Sksewell@umich.edu : SimObject(name), ctrl(NULL), image(img), physmem(phys), diskDelay(delay), 602817Sksewell@umich.edu dmaTransferEvent(this), dmaReadWaitEvent(this), 612817Sksewell@umich.edu dmaWriteWaitEvent(this), dmaPrdReadEvent(this), 622817Sksewell@umich.edu dmaReadEvent(this), dmaWriteEvent(this) 633126Sktlim@umich.edu{ 642817Sksewell@umich.edu // Reset the device state 652817Sksewell@umich.edu reset(id); 662817Sksewell@umich.edu 672817Sksewell@umich.edu // fill out the drive ID structure 682817Sksewell@umich.edu memset(&driveID, 0, sizeof(struct ataparams)); 692817Sksewell@umich.edu 702817Sksewell@umich.edu // Calculate LBA and C/H/S values 712817Sksewell@umich.edu uint16_t cylinders; 722817Sksewell@umich.edu uint8_t heads; 732817Sksewell@umich.edu uint8_t sectors; 742817Sksewell@umich.edu 752817Sksewell@umich.edu uint32_t lba_size = image->size(); 762817Sksewell@umich.edu if (lba_size >= 16383*16*63) { 775714Shsul@eecs.umich.edu cylinders = 16383; 785715Shsul@eecs.umich.edu heads = 16; 792817Sksewell@umich.edu sectors = 63; 808793Sgblack@eecs.umich.edu } else { 818793Sgblack@eecs.umich.edu if (lba_size >= 63) 828793Sgblack@eecs.umich.edu sectors = 63; 838793Sgblack@eecs.umich.edu else 848793Sgblack@eecs.umich.edu sectors = lba_size; 858793Sgblack@eecs.umich.edu 868793Sgblack@eecs.umich.edu if ((lba_size / sectors) >= 16) 878793Sgblack@eecs.umich.edu heads = 16; 888793Sgblack@eecs.umich.edu else 898793Sgblack@eecs.umich.edu heads = (lba_size / sectors); 908793Sgblack@eecs.umich.edu 918793Sgblack@eecs.umich.edu cylinders = lba_size / (heads * sectors); 928793Sgblack@eecs.umich.edu } 938793Sgblack@eecs.umich.edu 948793Sgblack@eecs.umich.edu // Setup the model name 958793Sgblack@eecs.umich.edu sprintf((char *)driveID.atap_model, "5MI EDD si k"); 962817Sksewell@umich.edu // Set the maximum multisector transfer size 972817Sksewell@umich.edu driveID.atap_multi = MAX_MULTSECT; 986029Ssteve.reinhardt@amd.com // IORDY supported, IORDY disabled, LBA enabled, DMA enabled 992817Sksewell@umich.edu driveID.atap_capabilities1 = 0x7; 1002817Sksewell@umich.edu // UDMA support, EIDE support 1012817Sksewell@umich.edu driveID.atap_extensions = 0x6; 1022817Sksewell@umich.edu // Setup default C/H/S settings 1032817Sksewell@umich.edu driveID.atap_cylinders = cylinders; 1042817Sksewell@umich.edu driveID.atap_sectors = sectors; 1052817Sksewell@umich.edu driveID.atap_heads = heads; 1062817Sksewell@umich.edu // Setup the current multisector transfer size 1072817Sksewell@umich.edu driveID.atap_curmulti = MAX_MULTSECT; 1082875Sksewell@umich.edu driveID.atap_curmulti_valid = 0x1; 1095715Shsul@eecs.umich.edu // Number of sectors on disk 1102817Sksewell@umich.edu driveID.atap_capacity = lba_size; 1112817Sksewell@umich.edu // Multiword DMA mode 2 and below supported 1122817Sksewell@umich.edu driveID.atap_dmamode_supp = 0x400; 1132817Sksewell@umich.edu // Set PIO mode 4 and 3 supported 1147823Ssteve.reinhardt@amd.com driveID.atap_piomode_supp = 0x3; 1152817Sksewell@umich.edu // Set DMA mode 4 and below supported 1162817Sksewell@umich.edu driveID.atap_udmamode_supp = 0x10; 1172817Sksewell@umich.edu // Statically set hardware config word 1185715Shsul@eecs.umich.edu driveID.atap_hwreset_res = 0x4001; 1192817Sksewell@umich.edu} 1202817Sksewell@umich.edu 1212817Sksewell@umich.eduIdeDisk::~IdeDisk() 1222817Sksewell@umich.edu{ 1235250Sksewell@umich.edu // destroy the data buffer 1242817Sksewell@umich.edu delete [] dataBuffer; 1252875Sksewell@umich.edu} 1265715Shsul@eecs.umich.edu 1272817Sksewell@umich.eduvoid 1282817Sksewell@umich.eduIdeDisk::reset(int id) 1292817Sksewell@umich.edu{ 1302817Sksewell@umich.edu // initialize the data buffer and shadow registers 1317823Ssteve.reinhardt@amd.com dataBuffer = new uint8_t[MAX_DMA_SIZE]; 1327823Ssteve.reinhardt@amd.com 1338793Sgblack@eecs.umich.edu memset(dataBuffer, 0, MAX_DMA_SIZE); 1342817Sksewell@umich.edu memset(&cmdReg, 0, sizeof(CommandReg_t)); 1355715Shsul@eecs.umich.edu memset(&curPrd.entry, 0, sizeof(PrdEntry_t)); 1362817Sksewell@umich.edu 1372817Sksewell@umich.edu dmaInterfaceBytes = 0; 1382817Sksewell@umich.edu curPrdAddr = 0; 1392817Sksewell@umich.edu curSector = 0; 1405250Sksewell@umich.edu cmdBytes = 0; 1412817Sksewell@umich.edu cmdBytesLeft = 0; 1422875Sksewell@umich.edu drqBytesLeft = 0; 1435715Shsul@eecs.umich.edu dmaRead = false; 1442817Sksewell@umich.edu intrPending = false; 1452817Sksewell@umich.edu 1462817Sksewell@umich.edu // set the device state to idle 1472817Sksewell@umich.edu dmaState = Dma_Idle; 1482817Sksewell@umich.edu 1495715Shsul@eecs.umich.edu if (id == DEV0) { 1502817Sksewell@umich.edu devState = Device_Idle_S; 1512817Sksewell@umich.edu devID = DEV0; 1522817Sksewell@umich.edu } else if (id == DEV1) { 1532817Sksewell@umich.edu devState = Device_Idle_NS; 1542817Sksewell@umich.edu devID = DEV1; 1552817Sksewell@umich.edu } else { 1568793Sgblack@eecs.umich.edu panic("Invalid device ID: %#x\n", id); 1578793Sgblack@eecs.umich.edu } 1588793Sgblack@eecs.umich.edu 1598793Sgblack@eecs.umich.edu // set the device ready bit 1602817Sksewell@umich.edu status = STATUS_DRDY_BIT; 1612817Sksewell@umich.edu} 1622817Sksewell@umich.edu 1632817Sksewell@umich.edu//// 1642817Sksewell@umich.edu// Utility functions 1652817Sksewell@umich.edu//// 1668793Sgblack@eecs.umich.edu 1672817Sksewell@umich.edubool 1682817Sksewell@umich.eduIdeDisk::isDEVSelect() 1692817Sksewell@umich.edu{ 1702817Sksewell@umich.edu return ctrl->isDiskSelected(this); 1712817Sksewell@umich.edu} 1722817Sksewell@umich.edu 1732817Sksewell@umich.eduAddr 1748793Sgblack@eecs.umich.eduIdeDisk::pciToDma(Addr pciAddr) 1752817Sksewell@umich.edu{ 1762817Sksewell@umich.edu if (ctrl) 1772817Sksewell@umich.edu return ctrl->plat->pciToDma(pciAddr); 1782817Sksewell@umich.edu else 1792817Sksewell@umich.edu panic("Access to unset controller!\n"); 1802817Sksewell@umich.edu} 1812817Sksewell@umich.edu 1822817Sksewell@umich.eduuint32_t 1832817Sksewell@umich.eduIdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft) 1842817Sksewell@umich.edu{ 1852817Sksewell@umich.edu uint32_t bytesInPage = 0; 1862817Sksewell@umich.edu 1872817Sksewell@umich.edu // First calculate how many bytes could be in the page 1882817Sksewell@umich.edu if (bytesLeft > TheISA::PageBytes) 1892817Sksewell@umich.edu bytesInPage = TheISA::PageBytes; 1902817Sksewell@umich.edu else 1912817Sksewell@umich.edu bytesInPage = bytesLeft; 1922817Sksewell@umich.edu 1932817Sksewell@umich.edu // Next, see if we have crossed a page boundary, and adjust 1942817Sksewell@umich.edu Addr upperBound = curAddr + bytesInPage; 1953126Sktlim@umich.edu Addr pageBound = TheISA::TruncPage(curAddr) + TheISA::PageBytes; 1963126Sktlim@umich.edu 1973126Sktlim@umich.edu assert(upperBound >= curAddr && "DMA read wraps around address space!\n"); 1982817Sksewell@umich.edu 1992817Sksewell@umich.edu if (upperBound >= pageBound) 2002817Sksewell@umich.edu bytesInPage = pageBound - curAddr; 2012817Sksewell@umich.edu 2023126Sktlim@umich.edu return bytesInPage; 2033126Sktlim@umich.edu} 2043126Sktlim@umich.edu 2052817Sksewell@umich.edu//// 2062817Sksewell@umich.edu// Device registers read/write 2072817Sksewell@umich.edu//// 2082817Sksewell@umich.edu 2092817Sksewell@umich.eduvoid 2108208SAli.Saidi@ARM.comIdeDisk::read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data) 2118208SAli.Saidi@ARM.com{ 2128208SAli.Saidi@ARM.com DevAction_t action = ACT_NONE; 2138208SAli.Saidi@ARM.com 2142817Sksewell@umich.edu if (cmdBlk) { 2158793Sgblack@eecs.umich.edu if (offset < 0 || offset > sizeof(CommandReg_t)) 2168793Sgblack@eecs.umich.edu panic("Invalid disk command register offset: %#x\n", offset); 2172817Sksewell@umich.edu 2182817Sksewell@umich.edu if (!byte && offset != DATA_OFFSET) 2192817Sksewell@umich.edu panic("Invalid 16-bit read, only allowed on data reg\n"); 2202817Sksewell@umich.edu 2212817Sksewell@umich.edu if (!byte) 2227763SAli.Saidi@ARM.com *(uint16_t *)data = *(uint16_t *)&cmdReg.data0; 2237763SAli.Saidi@ARM.com else 2247763SAli.Saidi@ARM.com *data = ((uint8_t *)&cmdReg)[offset]; 2252817Sksewell@umich.edu 2262817Sksewell@umich.edu // determine if an action needs to be taken on the state machine 2272817Sksewell@umich.edu if (offset == STATUS_OFFSET) { 2282817Sksewell@umich.edu action = ACT_STAT_READ; 2292817Sksewell@umich.edu *data = status; // status is in a shadow, explicity copy 2306313Sgblack@eecs.umich.edu } else if (offset == DATA_OFFSET) { 2315715Shsul@eecs.umich.edu if (byte) 2322817Sksewell@umich.edu action = ACT_DATA_READ_BYTE; 2332817Sksewell@umich.edu else 2342817Sksewell@umich.edu action = ACT_DATA_READ_SHORT; 2352986Sgblack@eecs.umich.edu } 2362817Sksewell@umich.edu 2372817Sksewell@umich.edu } else { 2386313Sgblack@eecs.umich.edu if (offset != ALTSTAT_OFFSET) 2396314Sgblack@eecs.umich.edu panic("Invalid disk control register offset: %#x\n", offset); 2402817Sksewell@umich.edu 2412817Sksewell@umich.edu if (!byte) 2422817Sksewell@umich.edu panic("Invalid 16-bit read from control block\n"); 2432986Sgblack@eecs.umich.edu 2442817Sksewell@umich.edu *data = status; 2452817Sksewell@umich.edu } 2466313Sgblack@eecs.umich.edu 2475715Shsul@eecs.umich.edu if (action != ACT_NONE) 2482817Sksewell@umich.edu updateState(action); 2492817Sksewell@umich.edu} 2502817Sksewell@umich.edu 2512817Sksewell@umich.eduvoid 2522817Sksewell@umich.eduIdeDisk::write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data) 2532817Sksewell@umich.edu{ 2546313Sgblack@eecs.umich.edu DevAction_t action = ACT_NONE; 2555715Shsul@eecs.umich.edu 2562817Sksewell@umich.edu if (cmdBlk) { 2572817Sksewell@umich.edu if (offset < 0 || offset > sizeof(CommandReg_t)) 2582817Sksewell@umich.edu panic("Invalid disk command register offset: %#x\n", offset); 2595715Shsul@eecs.umich.edu 2602817Sksewell@umich.edu if (!byte && offset != DATA_OFFSET) 2612817Sksewell@umich.edu panic("Invalid 16-bit write, only allowed on data reg\n"); 2622817Sksewell@umich.edu 2632817Sksewell@umich.edu if (!byte) 2642817Sksewell@umich.edu *((uint16_t *)&cmdReg.data0) = *(uint16_t *)data; 2652817Sksewell@umich.edu else 2662817Sksewell@umich.edu ((uint8_t *)&cmdReg)[offset] = *data; 2676313Sgblack@eecs.umich.edu 2686314Sgblack@eecs.umich.edu // determine if an action needs to be taken on the state machine 2692817Sksewell@umich.edu if (offset == COMMAND_OFFSET) { 2702817Sksewell@umich.edu action = ACT_CMD_WRITE; 2715715Shsul@eecs.umich.edu } else if (offset == DATA_OFFSET) { 2722817Sksewell@umich.edu if (byte) 2732817Sksewell@umich.edu action = ACT_DATA_WRITE_BYTE; 2742817Sksewell@umich.edu else 2752817Sksewell@umich.edu action = ACT_DATA_WRITE_SHORT; 2762817Sksewell@umich.edu } else if (offset == SELECT_OFFSET) { 2772817Sksewell@umich.edu action = ACT_SELECT_WRITE; 2782817Sksewell@umich.edu } 2796313Sgblack@eecs.umich.edu 2805715Shsul@eecs.umich.edu } else { 2812817Sksewell@umich.edu if (offset != CONTROL_OFFSET) 2822817Sksewell@umich.edu panic("Invalid disk control register offset: %#x\n", offset); 2832817Sksewell@umich.edu 2845715Shsul@eecs.umich.edu if (!byte) 2852817Sksewell@umich.edu panic("Invalid 16-bit write to control block\n"); 2862817Sksewell@umich.edu 2872817Sksewell@umich.edu if (*data & CONTROL_RST_BIT) { 2882817Sksewell@umich.edu // force the device into the reset state 2892817Sksewell@umich.edu devState = Device_Srst; 2907720Sgblack@eecs.umich.edu action = ACT_SRST_SET; 2912817Sksewell@umich.edu } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) { 2927720Sgblack@eecs.umich.edu action = ACT_SRST_CLEAR; 2935258Sksewell@umich.edu } 2945258Sksewell@umich.edu 2955258Sksewell@umich.edu nIENBit = (*data & CONTROL_IEN_BIT) ? true : false; 2965715Shsul@eecs.umich.edu } 2975258Sksewell@umich.edu 2985258Sksewell@umich.edu if (action != ACT_NONE) 2995258Sksewell@umich.edu updateState(action); 3008733Sgeoffrey.blake@arm.com} 3018733Sgeoffrey.blake@arm.com 3028733Sgeoffrey.blake@arm.com//// 3038733Sgeoffrey.blake@arm.com// Perform DMA transactions 3048733Sgeoffrey.blake@arm.com//// 3058733Sgeoffrey.blake@arm.com 3068733Sgeoffrey.blake@arm.comvoid 3078733Sgeoffrey.blake@arm.comIdeDisk::doDmaTransfer() 3088733Sgeoffrey.blake@arm.com{ 3098733Sgeoffrey.blake@arm.com if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) 3108733Sgeoffrey.blake@arm.com panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", 3118733Sgeoffrey.blake@arm.com dmaState, devState); 3128733Sgeoffrey.blake@arm.com 3138733Sgeoffrey.blake@arm.com // first read the current PRD 3145258Sksewell@umich.edu if (dmaInterface) { 3156313Sgblack@eecs.umich.edu if (dmaInterface->busy()) { 3166313Sgblack@eecs.umich.edu // reschedule after waiting period 3176313Sgblack@eecs.umich.edu dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 3186313Sgblack@eecs.umich.edu return; 3196313Sgblack@eecs.umich.edu } 3206313Sgblack@eecs.umich.edu 3216313Sgblack@eecs.umich.edu dmaInterface->doDMA(Read, curPrdAddr, sizeof(PrdEntry_t), curTick, 3226313Sgblack@eecs.umich.edu &dmaPrdReadEvent); 3236313Sgblack@eecs.umich.edu } else { 3246313Sgblack@eecs.umich.edu dmaPrdReadDone(); 3256313Sgblack@eecs.umich.edu } 3266313Sgblack@eecs.umich.edu} 3276313Sgblack@eecs.umich.edu 3286313Sgblack@eecs.umich.eduvoid 3295258Sksewell@umich.eduIdeDisk::dmaPrdReadDone() 3304172Ssaidi@eecs.umich.edu{ 3312817Sksewell@umich.edu // actually copy the PRD from physical memory 3325715Shsul@eecs.umich.edu memcpy((void *)&curPrd.entry, 3332817Sksewell@umich.edu physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)), 3342817Sksewell@umich.edu sizeof(PrdEntry_t)); 3352817Sksewell@umich.edu 3365715Shsul@eecs.umich.edu DPRINTF(IdeDisk, 3372817Sksewell@umich.edu "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n", 3382817Sksewell@umich.edu curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()), 3392817Sksewell@umich.edu curPrd.getByteCount(), (cmdBytesLeft/SectorSize), 3402817Sksewell@umich.edu curPrd.getEOT(), curSector); 3413468Sgblack@eecs.umich.edu 3428518Sgeoffrey.blake@arm.com // the prd pointer has already been translated, so just do an increment 3432817Sksewell@umich.edu curPrdAddr = curPrdAddr + sizeof(PrdEntry_t); 3445715Shsul@eecs.umich.edu 3452817Sksewell@umich.edu if (dmaRead) 3462817Sksewell@umich.edu doDmaRead(); 3472817Sksewell@umich.edu else 3485715Shsul@eecs.umich.edu doDmaWrite(); 3492817Sksewell@umich.edu} 3502817Sksewell@umich.edu 3512817Sksewell@umich.eduvoid 352IdeDisk::doDmaRead() 353{ 354 /** @TODO we need to figure out what the delay actually will be */ 355 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 356 357 DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n", 358 diskDelay, totalDiskDelay); 359 if (dmaInterface) { 360 if (dmaInterface->busy()) { 361 // reschedule after waiting period 362 dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 363 return; 364 } 365 366 Addr dmaAddr = pciToDma(curPrd.getBaseAddr()); 367 368 uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(), 369 (uint32_t)curPrd.getByteCount()); 370 371 dmaInterfaceBytes = bytesInPage; 372 373 dmaInterface->doDMA(Read, dmaAddr, bytesInPage, 374 curTick + totalDiskDelay, &dmaReadEvent); 375 } else { 376 // schedule dmaReadEvent with sectorDelay (dmaReadDone) 377 dmaReadEvent.schedule(curTick + totalDiskDelay); 378 } 379} 380 381void 382IdeDisk::dmaReadDone() 383{ 384 385 Addr curAddr = 0, dmaAddr = 0; 386 uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0; 387 388 // continue to use the DMA interface until all pages are read 389 if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) { 390 // see if the interface is busy 391 if (dmaInterface->busy()) { 392 // reschedule after waiting period 393 dmaReadEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 394 return; 395 } 396 397 uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes; 398 curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes; 399 dmaAddr = pciToDma(curAddr); 400 401 bytesInPage = bytesInDmaPage(curAddr, bytesLeft); 402 dmaInterfaceBytes += bytesInPage; 403 404 dmaInterface->doDMA(Read, dmaAddr, bytesInPage, 405 curTick, &dmaReadEvent); 406 407 return; 408 } 409 410 // set initial address 411 curAddr = curPrd.getBaseAddr(); 412 413 // clear out the data buffer 414 memset(dataBuffer, 0, MAX_DMA_SIZE); 415 416 // read the data from memory via DMA into a data buffer 417 while (bytesWritten < curPrd.getByteCount()) { 418 if (cmdBytesLeft <= 0) 419 panic("DMA data is larger than # of sectors specified\n"); 420 421 dmaAddr = pciToDma(curAddr); 422 423 // calculate how many bytes are in the current page 424 bytesLeft = curPrd.getByteCount() - bytesWritten; 425 bytesInPage = bytesInDmaPage(curAddr, bytesLeft); 426 427 // copy the data from memory into the data buffer 428 memcpy((void *)(dataBuffer + bytesWritten), 429 physmem->dma_addr(dmaAddr, bytesInPage), 430 bytesInPage); 431 432 curAddr += bytesInPage; 433 bytesWritten += bytesInPage; 434 cmdBytesLeft -= bytesInPage; 435 } 436 437 // write the data to the disk image 438 for (bytesWritten = 0; 439 bytesWritten < curPrd.getByteCount(); 440 bytesWritten += SectorSize) { 441 442 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); 443 } 444 445 // check for the EOT 446 if (curPrd.getEOT()) { 447 assert(cmdBytesLeft == 0); 448 dmaState = Dma_Idle; 449 updateState(ACT_DMA_DONE); 450 } else { 451 doDmaTransfer(); 452 } 453} 454 455void 456IdeDisk::doDmaWrite() 457{ 458 /** @TODO we need to figure out what the delay actually will be */ 459 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 460 461 DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n", 462 diskDelay, totalDiskDelay); 463 464 if (dmaInterface) { 465 if (dmaInterface->busy()) { 466 // reschedule after waiting period 467 dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 468 return; 469 } 470 471 Addr dmaAddr = pciToDma(curPrd.getBaseAddr()); 472 473 uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(), 474 (uint32_t)curPrd.getByteCount()); 475 476 dmaInterfaceBytes = bytesInPage; 477 478 dmaInterface->doDMA(WriteInvalidate, dmaAddr, 479 bytesInPage, curTick + totalDiskDelay, 480 &dmaWriteEvent); 481 } else { 482 // schedule event with disk delay (dmaWriteDone) 483 dmaWriteEvent.schedule(curTick + totalDiskDelay); 484 } 485} 486 487void 488IdeDisk::dmaWriteDone() 489{ 490 Addr curAddr = 0, pageAddr = 0, dmaAddr = 0; 491 uint32_t bytesRead = 0, bytesInPage = 0; 492 493 // continue to use the DMA interface until all pages are read 494 if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) { 495 // see if the interface is busy 496 if (dmaInterface->busy()) { 497 // reschedule after waiting period 498 dmaWriteEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 499 return; 500 } 501 502 uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes; 503 curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes; 504 dmaAddr = pciToDma(curAddr); 505 506 bytesInPage = bytesInDmaPage(curAddr, bytesLeft); 507 dmaInterfaceBytes += bytesInPage; 508 509 dmaInterface->doDMA(WriteInvalidate, dmaAddr, 510 bytesInPage, curTick, 511 &dmaWriteEvent); 512 513 return; 514 } 515 516 // setup the initial page and DMA address 517 curAddr = curPrd.getBaseAddr(); 518 pageAddr = TheISA::TruncPage(curAddr); 519 dmaAddr = pciToDma(curAddr); 520 521 // clear out the data buffer 522 memset(dataBuffer, 0, MAX_DMA_SIZE); 523 524 while (bytesRead < curPrd.getByteCount()) { 525 // see if we have crossed into a new page 526 if (pageAddr != TheISA::TruncPage(curAddr)) { 527 // write the data to memory 528 memcpy(physmem->dma_addr(dmaAddr, bytesInPage), 529 (void *)(dataBuffer + (bytesRead - bytesInPage)), 530 bytesInPage); 531 532 // update the DMA address and page address 533 pageAddr = TheISA::TruncPage(curAddr); 534 dmaAddr = pciToDma(curAddr); 535 536 bytesInPage = 0; 537 } 538 539 if (cmdBytesLeft <= 0) 540 panic("DMA requested data is larger than # sectors specified\n"); 541 542 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); 543 544 curAddr += SectorSize; 545 bytesRead += SectorSize; 546 bytesInPage += SectorSize; 547 cmdBytesLeft -= SectorSize; 548 } 549 550 // write the last page worth read to memory 551 if (bytesInPage != 0) { 552 memcpy(physmem->dma_addr(dmaAddr, bytesInPage), 553 (void *)(dataBuffer + (bytesRead - bytesInPage)), 554 bytesInPage); 555 } 556 557 // check for the EOT 558 if (curPrd.getEOT()) { 559 assert(cmdBytesLeft == 0); 560 dmaState = Dma_Idle; 561 updateState(ACT_DMA_DONE); 562 } else { 563 doDmaTransfer(); 564 } 565} 566 567//// 568// Disk utility routines 569/// 570 571void 572IdeDisk::readDisk(uint32_t sector, uint8_t *data) 573{ 574 uint32_t bytesRead = image->read(data, sector); 575 576 if (bytesRead != SectorSize) 577 panic("Can't read from %s. Only %d of %d read. errno=%d\n", 578 name(), bytesRead, SectorSize, errno); 579} 580 581void 582IdeDisk::writeDisk(uint32_t sector, uint8_t *data) 583{ 584 uint32_t bytesWritten = image->write(data, sector); 585 586 if (bytesWritten != SectorSize) 587 panic("Can't write to %s. Only %d of %d written. errno=%d\n", 588 name(), bytesWritten, SectorSize, errno); 589} 590 591//// 592// Setup and handle commands 593//// 594 595void 596IdeDisk::startDma(const uint32_t &prdTableBase) 597{ 598 if (dmaState != Dma_Start) 599 panic("Inconsistent DMA state, should be in Dma_Start!\n"); 600 601 if (devState != Transfer_Data_Dma) 602 panic("Inconsistent device state for DMA start!\n"); 603 604 // PRD base address is given by bits 31:2 605 curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); 606 607 dmaState = Dma_Transfer; 608 609 // schedule dma transfer (doDmaTransfer) 610 dmaTransferEvent.schedule(curTick + 1); 611} 612 613void 614IdeDisk::abortDma() 615{ 616 if (dmaState == Dma_Idle) 617 panic("Inconsistent DMA state, should be Start or Transfer!"); 618 619 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) 620 panic("Inconsistent device state, should be Transfer or Prepare!\n"); 621 622 updateState(ACT_CMD_ERROR); 623} 624 625void 626IdeDisk::startCommand() 627{ 628 DevAction_t action = ACT_NONE; 629 uint32_t size = 0; 630 dmaRead = false; 631 632 // Decode commands 633 switch (cmdReg.command) { 634 // Supported non-data commands 635 case WDSF_READ_NATIVE_MAX: 636 size = image->size() - 1; 637 cmdReg.sec_num = (size & 0xff); 638 cmdReg.cyl_low = ((size & 0xff00) >> 8); 639 cmdReg.cyl_high = ((size & 0xff0000) >> 16); 640 cmdReg.head = ((size & 0xf000000) >> 24); 641 642 devState = Command_Execution; 643 action = ACT_CMD_COMPLETE; 644 break; 645 646 case WDCC_RECAL: 647 case WDCC_IDP: 648 case WDCC_STANDBY_IMMED: 649 case WDCC_FLUSHCACHE: 650 case WDSF_VERIFY: 651 case WDSF_SEEK: 652 case SET_FEATURES: 653 case WDCC_SETMULTI: 654 devState = Command_Execution; 655 action = ACT_CMD_COMPLETE; 656 break; 657 658 // Supported PIO data-in commands 659 case WDCC_IDENTIFY: 660 cmdBytes = cmdBytesLeft = sizeof(struct ataparams); 661 devState = Prepare_Data_In; 662 action = ACT_DATA_READY; 663 break; 664 665 case WDCC_READMULTI: 666 case WDCC_READ: 667 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 668 panic("Attempt to perform CHS access, only supports LBA\n"); 669 670 if (cmdReg.sec_count == 0) 671 cmdBytes = cmdBytesLeft = (256 * SectorSize); 672 else 673 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 674 675 curSector = getLBABase(); 676 677 /** @todo make this a scheduled event to simulate disk delay */ 678 devState = Prepare_Data_In; 679 action = ACT_DATA_READY; 680 break; 681 682 // Supported PIO data-out commands 683 case WDCC_WRITEMULTI: 684 case WDCC_WRITE: 685 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 686 panic("Attempt to perform CHS access, only supports LBA\n"); 687 688 if (cmdReg.sec_count == 0) 689 cmdBytes = cmdBytesLeft = (256 * SectorSize); 690 else 691 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 692 693 curSector = getLBABase(); 694 695 devState = Prepare_Data_Out; 696 action = ACT_DATA_READY; 697 break; 698 699 // Supported DMA commands 700 case WDCC_WRITEDMA: 701 dmaRead = true; // a write to the disk is a DMA read from memory 702 case WDCC_READDMA: 703 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 704 panic("Attempt to perform CHS access, only supports LBA\n"); 705 706 if (cmdReg.sec_count == 0) 707 cmdBytes = cmdBytesLeft = (256 * SectorSize); 708 else 709 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 710 711 curSector = getLBABase(); 712 713 devState = Prepare_Data_Dma; 714 action = ACT_DMA_READY; 715 break; 716 717 default: 718 panic("Unsupported ATA command: %#x\n", cmdReg.command); 719 } 720 721 if (action != ACT_NONE) { 722 // set the BSY bit 723 status |= STATUS_BSY_BIT; 724 // clear the DRQ bit 725 status &= ~STATUS_DRQ_BIT; 726 // clear the DF bit 727 status &= ~STATUS_DF_BIT; 728 729 updateState(action); 730 } 731} 732 733//// 734// Handle setting and clearing interrupts 735//// 736 737void 738IdeDisk::intrPost() 739{ 740 DPRINTF(IdeDisk, "Posting Interrupt\n"); 741 if (intrPending) 742 panic("Attempt to post an interrupt with one pending\n"); 743 744 intrPending = true; 745 746 // talk to controller to set interrupt 747 if (ctrl) 748 ctrl->intrPost(); 749} 750 751void 752IdeDisk::intrClear() 753{ 754 DPRINTF(IdeDisk, "Clearing Interrupt\n"); 755 if (!intrPending) 756 panic("Attempt to clear a non-pending interrupt\n"); 757 758 intrPending = false; 759 760 // talk to controller to clear interrupt 761 if (ctrl) 762 ctrl->intrClear(); 763} 764 765//// 766// Manage the device internal state machine 767//// 768 769void 770IdeDisk::updateState(DevAction_t action) 771{ 772 switch (devState) { 773 case Device_Srst: 774 if (action == ACT_SRST_SET) { 775 // set the BSY bit 776 status |= STATUS_BSY_BIT; 777 } else if (action == ACT_SRST_CLEAR) { 778 // clear the BSY bit 779 status &= ~STATUS_BSY_BIT; 780 781 // reset the device state 782 reset(devID); 783 } 784 break; 785 786 case Device_Idle_S: 787 if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 788 devState = Device_Idle_NS; 789 } else if (action == ACT_CMD_WRITE) { 790 startCommand(); 791 } 792 793 break; 794 795 case Device_Idle_SI: 796 if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 797 devState = Device_Idle_NS; 798 intrClear(); 799 } else if (action == ACT_STAT_READ || isIENSet()) { 800 devState = Device_Idle_S; 801 intrClear(); 802 } else if (action == ACT_CMD_WRITE) { 803 intrClear(); 804 startCommand(); 805 } 806 807 break; 808 809 case Device_Idle_NS: 810 if (action == ACT_SELECT_WRITE && isDEVSelect()) { 811 if (!isIENSet() && intrPending) { 812 devState = Device_Idle_SI; 813 intrPost(); 814 } 815 if (isIENSet() || !intrPending) { 816 devState = Device_Idle_S; 817 } 818 } 819 break; 820 821 case Command_Execution: 822 if (action == ACT_CMD_COMPLETE) { 823 // clear the BSY bit 824 setComplete(); 825 826 if (!isIENSet()) { 827 devState = Device_Idle_SI; 828 intrPost(); 829 } else { 830 devState = Device_Idle_S; 831 } 832 } 833 break; 834 835 case Prepare_Data_In: 836 if (action == ACT_CMD_ERROR) { 837 // clear the BSY bit 838 setComplete(); 839 840 if (!isIENSet()) { 841 devState = Device_Idle_SI; 842 intrPost(); 843 } else { 844 devState = Device_Idle_S; 845 } 846 } else if (action == ACT_DATA_READY) { 847 // clear the BSY bit 848 status &= ~STATUS_BSY_BIT; 849 // set the DRQ bit 850 status |= STATUS_DRQ_BIT; 851 852 // copy the data into the data buffer 853 if (cmdReg.command == WDCC_IDENTIFY) { 854 // Reset the drqBytes for this block 855 drqBytesLeft = sizeof(struct ataparams); 856 857 memcpy((void *)dataBuffer, (void *)&driveID, 858 sizeof(struct ataparams)); 859 } else { 860 // Reset the drqBytes for this block 861 drqBytesLeft = SectorSize; 862 863 readDisk(curSector++, dataBuffer); 864 } 865 866 // put the first two bytes into the data register 867 memcpy((void *)&cmdReg.data0, (void *)dataBuffer, 868 sizeof(uint16_t)); 869 870 if (!isIENSet()) { 871 devState = Data_Ready_INTRQ_In; 872 intrPost(); 873 } else { 874 devState = Transfer_Data_In; 875 } 876 } 877 break; 878 879 case Data_Ready_INTRQ_In: 880 if (action == ACT_STAT_READ) { 881 devState = Transfer_Data_In; 882 intrClear(); 883 } 884 break; 885 886 case Transfer_Data_In: 887 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { 888 if (action == ACT_DATA_READ_BYTE) { 889 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); 890 } else { 891 drqBytesLeft -= 2; 892 cmdBytesLeft -= 2; 893 894 // copy next short into data registers 895 if (drqBytesLeft) 896 memcpy((void *)&cmdReg.data0, 897 (void *)&dataBuffer[SectorSize - drqBytesLeft], 898 sizeof(uint16_t)); 899 } 900 901 if (drqBytesLeft == 0) { 902 if (cmdBytesLeft == 0) { 903 // Clear the BSY bit 904 setComplete(); 905 devState = Device_Idle_S; 906 } else { 907 devState = Prepare_Data_In; 908 // set the BSY_BIT 909 status |= STATUS_BSY_BIT; 910 // clear the DRQ_BIT 911 status &= ~STATUS_DRQ_BIT; 912 913 /** @todo change this to a scheduled event to simulate 914 disk delay */ 915 updateState(ACT_DATA_READY); 916 } 917 } 918 } 919 break; 920 921 case Prepare_Data_Out: 922 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { 923 // clear the BSY bit 924 setComplete(); 925 926 if (!isIENSet()) { 927 devState = Device_Idle_SI; 928 intrPost(); 929 } else { 930 devState = Device_Idle_S; 931 } 932 } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) { 933 // clear the BSY bit 934 status &= ~STATUS_BSY_BIT; 935 // set the DRQ bit 936 status |= STATUS_DRQ_BIT; 937 938 // clear the data buffer to get it ready for writes 939 memset(dataBuffer, 0, MAX_DMA_SIZE); 940 941 // reset the drqBytes for this block 942 drqBytesLeft = SectorSize; 943 944 if (cmdBytesLeft == cmdBytes || isIENSet()) { 945 devState = Transfer_Data_Out; 946 } else { 947 devState = Data_Ready_INTRQ_Out; 948 intrPost(); 949 } 950 } 951 break; 952 953 case Data_Ready_INTRQ_Out: 954 if (action == ACT_STAT_READ) { 955 devState = Transfer_Data_Out; 956 intrClear(); 957 } 958 break; 959 960 case Transfer_Data_Out: 961 if (action == ACT_DATA_WRITE_BYTE || 962 action == ACT_DATA_WRITE_SHORT) { 963 964 if (action == ACT_DATA_READ_BYTE) { 965 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); 966 } else { 967 // copy the latest short into the data buffer 968 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], 969 (void *)&cmdReg.data0, 970 sizeof(uint16_t)); 971 972 drqBytesLeft -= 2; 973 cmdBytesLeft -= 2; 974 } 975 976 if (drqBytesLeft == 0) { 977 // copy the block to the disk 978 writeDisk(curSector++, dataBuffer); 979 980 // set the BSY bit 981 status |= STATUS_BSY_BIT; 982 // set the seek bit 983 status |= STATUS_SEEK_BIT; 984 // clear the DRQ bit 985 status &= ~STATUS_DRQ_BIT; 986 987 devState = Prepare_Data_Out; 988 989 /** @todo change this to a scheduled event to simulate 990 disk delay */ 991 updateState(ACT_DATA_READY); 992 } 993 } 994 break; 995 996 case Prepare_Data_Dma: 997 if (action == ACT_CMD_ERROR) { 998 // clear the BSY bit 999 setComplete(); 1000 1001 if (!isIENSet()) { 1002 devState = Device_Idle_SI; 1003 intrPost(); 1004 } else { 1005 devState = Device_Idle_S; 1006 } 1007 } else if (action == ACT_DMA_READY) { 1008 // clear the BSY bit 1009 status &= ~STATUS_BSY_BIT; 1010 // set the DRQ bit 1011 status |= STATUS_DRQ_BIT; 1012 1013 devState = Transfer_Data_Dma; 1014 1015 if (dmaState != Dma_Idle) 1016 panic("Inconsistent DMA state, should be Dma_Idle\n"); 1017 1018 dmaState = Dma_Start; 1019 // wait for the write to the DMA start bit 1020 } 1021 break; 1022 1023 case Transfer_Data_Dma: 1024 if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) { 1025 // clear the BSY bit 1026 setComplete(); 1027 // set the seek bit 1028 status |= STATUS_SEEK_BIT; 1029 // clear the controller state for DMA transfer 1030 ctrl->setDmaComplete(this); 1031 1032 if (!isIENSet()) { 1033 devState = Device_Idle_SI; 1034 intrPost(); 1035 } else { 1036 devState = Device_Idle_S; 1037 } 1038 } 1039 break; 1040 1041 default: 1042 panic("Unknown IDE device state: %#x\n", devState); 1043 } 1044} 1045 1046void 1047IdeDisk::serialize(ostream &os) 1048{ 1049 // Check all outstanding events to see if they are scheduled 1050 // these are all mutually exclusive 1051 Tick reschedule = 0; 1052 Events_t event = None; 1053 1054 int eventCount = 0; 1055 1056 if (dmaTransferEvent.scheduled()) { 1057 reschedule = dmaTransferEvent.when(); 1058 event = Transfer; 1059 eventCount++; 1060 } 1061 if (dmaReadWaitEvent.scheduled()) { 1062 reschedule = dmaReadWaitEvent.when(); 1063 event = ReadWait; 1064 eventCount++; 1065 } 1066 if (dmaWriteWaitEvent.scheduled()) { 1067 reschedule = dmaWriteWaitEvent.when(); 1068 event = WriteWait; 1069 eventCount++; 1070 } 1071 if (dmaPrdReadEvent.scheduled()) { 1072 reschedule = dmaPrdReadEvent.when(); 1073 event = PrdRead; 1074 eventCount++; 1075 } 1076 if (dmaReadEvent.scheduled()) { 1077 reschedule = dmaReadEvent.when(); 1078 event = DmaRead; 1079 eventCount++; 1080 } 1081 if (dmaWriteEvent.scheduled()) { 1082 reschedule = dmaWriteEvent.when(); 1083 event = DmaWrite; 1084 eventCount++; 1085 } 1086 1087 assert(eventCount <= 1); 1088 1089 SERIALIZE_SCALAR(reschedule); 1090 SERIALIZE_ENUM(event); 1091 1092 // Serialize device registers 1093 SERIALIZE_SCALAR(cmdReg.data0); 1094 SERIALIZE_SCALAR(cmdReg.data1); 1095 SERIALIZE_SCALAR(cmdReg.sec_count); 1096 SERIALIZE_SCALAR(cmdReg.sec_num); 1097 SERIALIZE_SCALAR(cmdReg.cyl_low); 1098 SERIALIZE_SCALAR(cmdReg.cyl_high); 1099 SERIALIZE_SCALAR(cmdReg.drive); 1100 SERIALIZE_SCALAR(cmdReg.command); 1101 SERIALIZE_SCALAR(status); 1102 SERIALIZE_SCALAR(nIENBit); 1103 SERIALIZE_SCALAR(devID); 1104 1105 // Serialize the PRD related information 1106 SERIALIZE_SCALAR(curPrd.entry.baseAddr); 1107 SERIALIZE_SCALAR(curPrd.entry.byteCount); 1108 SERIALIZE_SCALAR(curPrd.entry.endOfTable); 1109 SERIALIZE_SCALAR(curPrdAddr); 1110 1111 // Serialize current transfer related information 1112 SERIALIZE_SCALAR(cmdBytesLeft); 1113 SERIALIZE_SCALAR(cmdBytes); 1114 SERIALIZE_SCALAR(drqBytesLeft); 1115 SERIALIZE_SCALAR(curSector); 1116 SERIALIZE_SCALAR(dmaRead); 1117 SERIALIZE_SCALAR(dmaInterfaceBytes); 1118 SERIALIZE_SCALAR(intrPending); 1119 SERIALIZE_ENUM(devState); 1120 SERIALIZE_ENUM(dmaState); 1121 SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1122} 1123 1124void 1125IdeDisk::unserialize(Checkpoint *cp, const string §ion) 1126{ 1127 // Reschedule events that were outstanding 1128 // these are all mutually exclusive 1129 Tick reschedule = 0; 1130 Events_t event = None; 1131 1132 UNSERIALIZE_SCALAR(reschedule); 1133 UNSERIALIZE_ENUM(event); 1134 1135 switch (event) { 1136 case None : break; 1137 case Transfer : dmaTransferEvent.schedule(reschedule); break; 1138 case ReadWait : dmaReadWaitEvent.schedule(reschedule); break; 1139 case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break; 1140 case PrdRead : dmaPrdReadEvent.schedule(reschedule); break; 1141 case DmaRead : dmaReadEvent.schedule(reschedule); break; 1142 case DmaWrite : dmaWriteEvent.schedule(reschedule); break; 1143 } 1144 1145 // Unserialize device registers 1146 UNSERIALIZE_SCALAR(cmdReg.data0); 1147 UNSERIALIZE_SCALAR(cmdReg.data1); 1148 UNSERIALIZE_SCALAR(cmdReg.sec_count); 1149 UNSERIALIZE_SCALAR(cmdReg.sec_num); 1150 UNSERIALIZE_SCALAR(cmdReg.cyl_low); 1151 UNSERIALIZE_SCALAR(cmdReg.cyl_high); 1152 UNSERIALIZE_SCALAR(cmdReg.drive); 1153 UNSERIALIZE_SCALAR(cmdReg.command); 1154 UNSERIALIZE_SCALAR(status); 1155 UNSERIALIZE_SCALAR(nIENBit); 1156 UNSERIALIZE_SCALAR(devID); 1157 1158 // Unserialize the PRD related information 1159 UNSERIALIZE_SCALAR(curPrd.entry.baseAddr); 1160 UNSERIALIZE_SCALAR(curPrd.entry.byteCount); 1161 UNSERIALIZE_SCALAR(curPrd.entry.endOfTable); 1162 UNSERIALIZE_SCALAR(curPrdAddr); 1163 1164 // Unserialize current transfer related information 1165 UNSERIALIZE_SCALAR(cmdBytes); 1166 UNSERIALIZE_SCALAR(cmdBytesLeft); 1167 UNSERIALIZE_SCALAR(drqBytesLeft); 1168 UNSERIALIZE_SCALAR(curSector); 1169 UNSERIALIZE_SCALAR(dmaRead); 1170 UNSERIALIZE_SCALAR(dmaInterfaceBytes); 1171 UNSERIALIZE_SCALAR(intrPending); 1172 UNSERIALIZE_ENUM(devState); 1173 UNSERIALIZE_ENUM(dmaState); 1174 UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1175} 1176 1177#ifndef DOXYGEN_SHOULD_SKIP_THIS 1178 1179enum DriveID { master, slave }; 1180static const char *DriveID_strings[] = { "master", "slave" }; 1181BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) 1182 1183 SimObjectParam<DiskImage *> image; 1184 SimObjectParam<PhysicalMemory *> physmem; 1185 SimpleEnumParam<DriveID> driveID; 1186 Param<int> delay; 1187 1188END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) 1189 1190BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk) 1191 1192 INIT_PARAM(image, "Disk image"), 1193 INIT_PARAM(physmem, "Physical memory"), 1194 INIT_ENUM_PARAM(driveID, "Drive ID (0=master 1=slave)", DriveID_strings), 1195 INIT_PARAM_DFLT(delay, "Fixed disk delay in microseconds", 1) 1196 1197END_INIT_SIM_OBJECT_PARAMS(IdeDisk) 1198 1199 1200CREATE_SIM_OBJECT(IdeDisk) 1201{ 1202 return new IdeDisk(getInstanceName(), image, physmem, driveID, delay); 1203} 1204 1205REGISTER_SIM_OBJECT("IdeDisk", IdeDisk) 1206 1207#endif //DOXYGEN_SHOULD_SKIP_THIS 1208