1848SN/A/* 29956SN/A * Copyright (c) 2013 ARM Limited 39956SN/A * All rights reserved 49956SN/A * 59956SN/A * The license below extends only to copyright in the software and shall 69956SN/A * not be construed as granting a license to any other intellectual 79956SN/A * property including but not limited to intellectual property relating 89956SN/A * to a hardware implementation of the functionality of the software 99956SN/A * licensed hereunder. You may use the software subject to the license 109956SN/A * terms below provided that you ensure that this notice is replicated 119956SN/A * unmodified and in its entirety in all distributions of the software, 129956SN/A * modified or unmodified, in source code or in binary form. 139956SN/A * 141762SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 15848SN/A * All rights reserved. 16848SN/A * 17848SN/A * Redistribution and use in source and binary forms, with or without 18848SN/A * modification, are permitted provided that the following conditions are 19848SN/A * met: redistributions of source code must retain the above copyright 20848SN/A * notice, this list of conditions and the following disclaimer; 21848SN/A * redistributions in binary form must reproduce the above copyright 22848SN/A * notice, this list of conditions and the following disclaimer in the 23848SN/A * documentation and/or other materials provided with the distribution; 24848SN/A * neither the name of the copyright holders nor the names of its 25848SN/A * contributors may be used to endorse or promote products derived from 26848SN/A * this software without specific prior written permission. 27848SN/A * 28848SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29848SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30848SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31848SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32848SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33848SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34848SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35848SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36848SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37848SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38848SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392665SN/A * 402665SN/A * Authors: Andrew Schultz 412665SN/A * Ali Saidi 422665SN/A * Miguel Serrano 43848SN/A */ 44848SN/A 4511264Sandreas.sandberg@arm.com#include "dev/storage/ide_ctrl.hh" 4611264Sandreas.sandberg@arm.com 47848SN/A#include <string> 48848SN/A 49848SN/A#include "cpu/intr_control.hh" 508232SN/A#include "debug/IdeCtrl.hh" 5111264Sandreas.sandberg@arm.com#include "dev/storage/ide_disk.hh" 522565SN/A#include "mem/packet.hh" 533348SN/A#include "mem/packet_access.hh" 544762SN/A#include "params/IdeController.hh" 552565SN/A#include "sim/byteswap.hh" 56848SN/A 578737SN/A// clang complains about std::set being overloaded with Packet::set if 588737SN/A// we open up the entire namespace std 598737SN/Ausing std::string; 60848SN/A 615772SN/A// Bus master IDE registers 625772SN/Aenum BMIRegOffset { 635772SN/A BMICommand = 0x0, 645772SN/A BMIStatus = 0x2, 655772SN/A BMIDescTablePtr = 0x4 665772SN/A}; 675772SN/A 685772SN/A// PCI config space registers 695772SN/Aenum ConfRegOffset { 705772SN/A PrimaryTiming = 0x40, 715772SN/A SecondaryTiming = 0x42, 725772SN/A DeviceTiming = 0x44, 735772SN/A UDMAControl = 0x48, 745772SN/A UDMATiming = 0x4A, 755772SN/A IDEConfig = 0x54 765772SN/A}; 775772SN/A 785772SN/Astatic const uint16_t timeRegWithDecodeEn = 0x8000; 795772SN/A 805772SN/AIdeController::Channel::Channel( 815772SN/A string newName, Addr _cmdSize, Addr _ctrlSize) : 825772SN/A _name(newName), 835772SN/A cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize), 845772SN/A master(NULL), slave(NULL), selected(NULL) 855772SN/A{ 8612895Sjason@lowepower.com bmiRegs.reset(); 875772SN/A bmiRegs.status.dmaCap0 = 1; 885772SN/A bmiRegs.status.dmaCap1 = 1; 895772SN/A} 905772SN/A 915772SN/AIdeController::Channel::~Channel() 925772SN/A{ 935772SN/A} 94848SN/A 951149SN/AIdeController::IdeController(Params *p) 969807SN/A : PciDevice(p), primary(name() + ".primary", BARSize[0], BARSize[1]), 975772SN/A secondary(name() + ".secondary", BARSize[2], BARSize[3]), 985772SN/A bmiAddr(0), bmiSize(BARSize[4]), 995772SN/A primaryTiming(htole(timeRegWithDecodeEn)), 1005772SN/A secondaryTiming(htole(timeRegWithDecodeEn)), 1015772SN/A deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0), 1027750SN/A ioEnabled(false), bmEnabled(false), 1037750SN/A ioShift(p->io_shift), ctrlOffset(p->ctrl_offset) 104848SN/A{ 105848SN/A 1065772SN/A // Assign the disks to channels 1071149SN/A for (int i = 0; i < params()->disks.size(); i++) { 10812201Sgabeblack@google.com if (!params()->disks[i]) 10912201Sgabeblack@google.com continue; 11012201Sgabeblack@google.com switch (i) { 11112201Sgabeblack@google.com case 0: 11212201Sgabeblack@google.com primary.master = params()->disks[0]; 11312201Sgabeblack@google.com break; 11412201Sgabeblack@google.com case 1: 11512201Sgabeblack@google.com primary.slave = params()->disks[1]; 11612201Sgabeblack@google.com break; 11712201Sgabeblack@google.com case 2: 11812201Sgabeblack@google.com secondary.master = params()->disks[2]; 11912201Sgabeblack@google.com break; 12012201Sgabeblack@google.com case 3: 12112201Sgabeblack@google.com secondary.slave = params()->disks[3]; 12212201Sgabeblack@google.com break; 12312201Sgabeblack@google.com default: 12412201Sgabeblack@google.com panic("IDE controllers support a maximum " 12512201Sgabeblack@google.com "of 4 devices attached!\n"); 12612201Sgabeblack@google.com } 1275772SN/A params()->disks[i]->setController(this); 128848SN/A } 12912201Sgabeblack@google.com 1305772SN/A primary.select(false); 1315772SN/A secondary.select(false); 1326431SN/A 1338198SN/A if ((BARAddrs[0] & ~BAR_IO_MASK) && (!legacyIO[0] || ioShift)) { 1347750SN/A primary.cmdAddr = BARAddrs[0]; primary.cmdSize = BARSize[0]; 1359956SN/A primary.ctrlAddr = BARAddrs[1]; primary.ctrlSize = BARSize[1]; 1367750SN/A } 1378198SN/A if ((BARAddrs[2] & ~BAR_IO_MASK) && (!legacyIO[2] || ioShift)) { 1387750SN/A secondary.cmdAddr = BARAddrs[2]; secondary.cmdSize = BARSize[2]; 1399956SN/A secondary.ctrlAddr = BARAddrs[3]; secondary.ctrlSize = BARSize[3]; 1407750SN/A } 1417750SN/A 1426431SN/A ioEnabled = (config.command & htole(PCI_CMD_IOSE)); 1436431SN/A bmEnabled = (config.command & htole(PCI_CMD_BME)); 144864SN/A} 145864SN/A 146929SN/Abool 147929SN/AIdeController::isDiskSelected(IdeDisk *diskPtr) 148929SN/A{ 1495772SN/A return (primary.selected == diskPtr || secondary.selected == diskPtr); 150929SN/A} 151929SN/A 1525772SN/Avoid 1535772SN/AIdeController::intrPost() 1545772SN/A{ 1555772SN/A primary.bmiRegs.status.intStatus = 1; 1569807SN/A PciDevice::intrPost(); 1575772SN/A} 158849SN/A 159849SN/Avoid 160849SN/AIdeController::setDmaComplete(IdeDisk *disk) 161849SN/A{ 1625772SN/A Channel *channel; 1635772SN/A if (disk == primary.master || disk == primary.slave) { 1645772SN/A channel = &primary; 1655772SN/A } else if (disk == secondary.master || disk == secondary.slave) { 1665772SN/A channel = &secondary; 1675772SN/A } else { 1685772SN/A panic("Unable to find disk based on pointer %#x\n", disk); 1695772SN/A } 170849SN/A 1715772SN/A channel->bmiRegs.command.startStop = 0; 1725772SN/A channel->bmiRegs.status.active = 0; 1735772SN/A channel->bmiRegs.status.intStatus = 1; 174849SN/A} 175849SN/A 1762846SN/ATick 1773349SN/AIdeController::readConfig(PacketPtr pkt) 178848SN/A{ 1792846SN/A int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 1804875SN/A if (offset < PCI_DEVICE_SPECIFIC) { 1819807SN/A return PciDevice::readConfig(pkt); 1824875SN/A } 1834875SN/A 1842846SN/A switch (pkt->getSize()) { 1852846SN/A case sizeof(uint8_t): 1862565SN/A switch (offset) { 1875772SN/A case DeviceTiming: 18813342Sgabeblack@google.com pkt->setLE<uint8_t>(deviceTiming); 1891817SN/A break; 1905772SN/A case UDMAControl: 19113342Sgabeblack@google.com pkt->setLE<uint8_t>(udmaControl); 1921817SN/A break; 1935772SN/A case PrimaryTiming + 1: 19413342Sgabeblack@google.com pkt->setLE<uint8_t>(bits(htole(primaryTiming), 15, 8)); 1952565SN/A break; 1965772SN/A case SecondaryTiming + 1: 19713342Sgabeblack@google.com pkt->setLE<uint8_t>(bits(htole(secondaryTiming), 15, 8)); 1982565SN/A break; 1995772SN/A case IDEConfig: 20013342Sgabeblack@google.com pkt->setLE<uint8_t>(bits(htole(ideConfig), 7, 0)); 2012565SN/A break; 2025772SN/A case IDEConfig + 1: 20313342Sgabeblack@google.com pkt->setLE<uint8_t>(bits(htole(ideConfig), 15, 8)); 2041817SN/A break; 2051817SN/A default: 2062565SN/A panic("Invalid PCI configuration read for size 1 at offset: %#x!\n", 2072565SN/A offset); 208848SN/A } 2092846SN/A DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset, 21013342Sgabeblack@google.com (uint32_t)pkt->getLE<uint8_t>()); 2112846SN/A break; 2122846SN/A case sizeof(uint16_t): 2132565SN/A switch (offset) { 21410775SN/A case UDMAControl: 21513342Sgabeblack@google.com pkt->setLE<uint16_t>(udmaControl); 21610775SN/A break; 2175772SN/A case PrimaryTiming: 21813342Sgabeblack@google.com pkt->setLE<uint16_t>(primaryTiming); 2191877SN/A break; 2205772SN/A case SecondaryTiming: 22113342Sgabeblack@google.com pkt->setLE<uint16_t>(secondaryTiming); 2221877SN/A break; 2235772SN/A case UDMATiming: 22413342Sgabeblack@google.com pkt->setLE<uint16_t>(udmaTiming); 2252565SN/A break; 2265772SN/A case IDEConfig: 22713342Sgabeblack@google.com pkt->setLE<uint16_t>(ideConfig); 2281817SN/A break; 2291817SN/A default: 2302565SN/A panic("Invalid PCI configuration read for size 2 offset: %#x!\n", 2312565SN/A offset); 2321817SN/A } 2332846SN/A DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset, 23413342Sgabeblack@google.com (uint32_t)pkt->getLE<uint16_t>()); 2352846SN/A break; 2362846SN/A case sizeof(uint32_t): 23710775SN/A switch (offset) { 23810775SN/A case PrimaryTiming: 23913342Sgabeblack@google.com pkt->setLE<uint32_t>(primaryTiming); 24010775SN/A break; 24110775SN/A case IDEConfig: 24213342Sgabeblack@google.com pkt->setLE<uint32_t>(ideConfig); 24310775SN/A break; 24410775SN/A default: 2458522SN/A panic("No 32bit reads implemented for this device."); 24610775SN/A } 2472846SN/A DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset, 24813342Sgabeblack@google.com (uint32_t)pkt->getLE<uint32_t>()); 2492846SN/A break; 2502846SN/A default: 2512846SN/A panic("invalid access size(?) for PCI configspace!\n"); 2522565SN/A } 2534870SN/A pkt->makeAtomicResponse(); 2542846SN/A return configDelay; 2552565SN/A} 2562565SN/A 2572846SN/A 2582846SN/ATick 2593349SN/AIdeController::writeConfig(PacketPtr pkt) 2602565SN/A{ 2612846SN/A int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 2622565SN/A if (offset < PCI_DEVICE_SPECIFIC) { 2639807SN/A PciDevice::writeConfig(pkt); 2642565SN/A } else { 2652846SN/A switch (pkt->getSize()) { 2662846SN/A case sizeof(uint8_t): 2672846SN/A switch (offset) { 2685772SN/A case DeviceTiming: 26913342Sgabeblack@google.com deviceTiming = pkt->getLE<uint8_t>(); 2702846SN/A break; 2715772SN/A case UDMAControl: 27213342Sgabeblack@google.com udmaControl = pkt->getLE<uint8_t>(); 2732846SN/A break; 2745772SN/A case IDEConfig: 27513342Sgabeblack@google.com replaceBits(ideConfig, 7, 0, pkt->getLE<uint8_t>()); 2762846SN/A break; 2775772SN/A case IDEConfig + 1: 27813342Sgabeblack@google.com replaceBits(ideConfig, 15, 8, pkt->getLE<uint8_t>()); 2792846SN/A break; 2802846SN/A default: 2815772SN/A panic("Invalid PCI configuration write " 2825772SN/A "for size 1 offset: %#x!\n", offset); 2832846SN/A } 2842846SN/A DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n", 28513342Sgabeblack@google.com offset, (uint32_t)pkt->getLE<uint8_t>()); 2862846SN/A break; 2872846SN/A case sizeof(uint16_t): 2882846SN/A switch (offset) { 28910775SN/A case UDMAControl: 29013342Sgabeblack@google.com udmaControl = pkt->getLE<uint16_t>(); 29110775SN/A break; 2925772SN/A case PrimaryTiming: 29313342Sgabeblack@google.com primaryTiming = pkt->getLE<uint16_t>(); 2942846SN/A break; 2955772SN/A case SecondaryTiming: 29613342Sgabeblack@google.com secondaryTiming = pkt->getLE<uint16_t>(); 2972846SN/A break; 2985772SN/A case UDMATiming: 29913342Sgabeblack@google.com udmaTiming = pkt->getLE<uint16_t>(); 3002846SN/A break; 3015772SN/A case IDEConfig: 30213342Sgabeblack@google.com ideConfig = pkt->getLE<uint16_t>(); 3032846SN/A break; 3042846SN/A default: 3055772SN/A panic("Invalid PCI configuration write " 3065772SN/A "for size 2 offset: %#x!\n", 3072846SN/A offset); 3082846SN/A } 3092846SN/A DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n", 31013342Sgabeblack@google.com offset, (uint32_t)pkt->getLE<uint16_t>()); 3112846SN/A break; 3122846SN/A case sizeof(uint32_t): 31310775SN/A switch (offset) { 31410775SN/A case PrimaryTiming: 31513342Sgabeblack@google.com primaryTiming = pkt->getLE<uint32_t>(); 31610775SN/A break; 31710775SN/A case IDEConfig: 31813342Sgabeblack@google.com ideConfig = pkt->getLE<uint32_t>(); 31910775SN/A break; 32010775SN/A default: 3218522SN/A panic("Write of unimplemented PCI config. register: %x\n", offset); 32210775SN/A } 3232846SN/A break; 3242846SN/A default: 3252846SN/A panic("invalid access size(?) for PCI configspace!\n"); 3262846SN/A } 3274875SN/A pkt->makeAtomicResponse(); 3282565SN/A } 3292565SN/A 3302846SN/A /* Trap command register writes and enable IO/BM as appropriate as well as 3312846SN/A * BARs. */ 3322565SN/A switch(offset) { 333897SN/A case PCI0_BASE_ADDR0: 3342565SN/A if (BARAddrs[0] != 0) 3355772SN/A primary.cmdAddr = BARAddrs[0]; 336897SN/A break; 337848SN/A 338897SN/A case PCI0_BASE_ADDR1: 3392565SN/A if (BARAddrs[1] != 0) 3405772SN/A primary.ctrlAddr = BARAddrs[1]; 341897SN/A break; 342848SN/A 343897SN/A case PCI0_BASE_ADDR2: 3442565SN/A if (BARAddrs[2] != 0) 3455772SN/A secondary.cmdAddr = BARAddrs[2]; 346897SN/A break; 347848SN/A 348897SN/A case PCI0_BASE_ADDR3: 3492565SN/A if (BARAddrs[3] != 0) 3505772SN/A secondary.ctrlAddr = BARAddrs[3]; 351897SN/A break; 352848SN/A 353897SN/A case PCI0_BASE_ADDR4: 3542565SN/A if (BARAddrs[4] != 0) 3555772SN/A bmiAddr = BARAddrs[4]; 356897SN/A break; 3572846SN/A 3582846SN/A case PCI_COMMAND: 3598522SN/A DPRINTF(IdeCtrl, "Writing to PCI Command val: %#x\n", config.command); 3605772SN/A ioEnabled = (config.command & htole(PCI_CMD_IOSE)); 3615772SN/A bmEnabled = (config.command & htole(PCI_CMD_BME)); 3622846SN/A break; 363848SN/A } 3642846SN/A return configDelay; 365848SN/A} 366848SN/A 3675772SN/Avoid 3685772SN/AIdeController::Channel::accessCommand(Addr offset, 3695772SN/A int size, uint8_t *data, bool read) 3705772SN/A{ 3715772SN/A const Addr SelectOffset = 6; 3725772SN/A const uint8_t SelectDevBit = 0x10; 3735772SN/A 3745772SN/A if (!read && offset == SelectOffset) 3755772SN/A select(*data & SelectDevBit); 3765772SN/A 3775772SN/A if (selected == NULL) { 3785772SN/A assert(size == sizeof(uint8_t)); 3795772SN/A *data = 0; 3805772SN/A } else if (read) { 3815772SN/A selected->readCommand(offset, size, data); 3825772SN/A } else { 3835772SN/A selected->writeCommand(offset, size, data); 3845772SN/A } 3855772SN/A} 3865772SN/A 3875772SN/Avoid 3885772SN/AIdeController::Channel::accessControl(Addr offset, 3895772SN/A int size, uint8_t *data, bool read) 3905772SN/A{ 3915772SN/A if (selected == NULL) { 3925772SN/A assert(size == sizeof(uint8_t)); 3935772SN/A *data = 0; 3945772SN/A } else if (read) { 3955772SN/A selected->readControl(offset, size, data); 3965772SN/A } else { 3975772SN/A selected->writeControl(offset, size, data); 3985772SN/A } 3995772SN/A} 4005772SN/A 4015772SN/Avoid 4025772SN/AIdeController::Channel::accessBMI(Addr offset, 4035772SN/A int size, uint8_t *data, bool read) 4045772SN/A{ 4055772SN/A assert(offset + size <= sizeof(BMIRegs)); 4065772SN/A if (read) { 4075772SN/A memcpy(data, (uint8_t *)&bmiRegs + offset, size); 4085772SN/A } else { 4095772SN/A switch (offset) { 4105772SN/A case BMICommand: 4115772SN/A { 4125772SN/A if (size != sizeof(uint8_t)) 4135772SN/A panic("Invalid BMIC write size: %x\n", size); 4145772SN/A 4155772SN/A BMICommandReg oldVal = bmiRegs.command; 4165772SN/A BMICommandReg newVal = *data; 4175772SN/A 4185772SN/A // if a DMA transfer is in progress, R/W control cannot change 4195772SN/A if (oldVal.startStop && oldVal.rw != newVal.rw) 4205772SN/A oldVal.rw = newVal.rw; 4215772SN/A 4225772SN/A if (oldVal.startStop != newVal.startStop) { 4235772SN/A if (selected == NULL) 4245772SN/A panic("DMA start for disk which does not exist\n"); 4255772SN/A 4265772SN/A if (oldVal.startStop) { 4275772SN/A DPRINTF(IdeCtrl, "Stopping DMA transfer\n"); 4285772SN/A bmiRegs.status.active = 0; 4295772SN/A 4305772SN/A selected->abortDma(); 4315772SN/A } else { 4325772SN/A DPRINTF(IdeCtrl, "Starting DMA transfer\n"); 4335772SN/A bmiRegs.status.active = 1; 4345772SN/A 4355772SN/A selected->startDma(letoh(bmiRegs.bmidtp)); 4365772SN/A } 4375772SN/A } 4385772SN/A 4395772SN/A bmiRegs.command = newVal; 4405772SN/A } 4415772SN/A break; 4425772SN/A case BMIStatus: 4435772SN/A { 4445772SN/A if (size != sizeof(uint8_t)) 4455772SN/A panic("Invalid BMIS write size: %x\n", size); 4465772SN/A 4475772SN/A BMIStatusReg oldVal = bmiRegs.status; 4485772SN/A BMIStatusReg newVal = *data; 4495772SN/A 4505772SN/A // the BMIDEA bit is read only 4515772SN/A newVal.active = oldVal.active; 4525772SN/A 4535772SN/A // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each 4549956SN/A if ((oldVal.intStatus == 1) && (newVal.intStatus == 1)) { 4555772SN/A newVal.intStatus = 0; // clear the interrupt? 4569956SN/A } else { 4579956SN/A // Assigning two bitunion fields to each other does not 4589956SN/A // work as intended, so we need to use this temporary variable 4599956SN/A // to get around the bug. 4609956SN/A uint8_t tmp = oldVal.intStatus; 4619956SN/A newVal.intStatus = tmp; 4629956SN/A } 4639956SN/A if ((oldVal.dmaError == 1) && (newVal.dmaError == 1)) { 4645772SN/A newVal.dmaError = 0; 4659956SN/A } else { 4669956SN/A uint8_t tmp = oldVal.dmaError; 4679956SN/A newVal.dmaError = tmp; 4689956SN/A } 4695772SN/A 4705772SN/A bmiRegs.status = newVal; 4715772SN/A } 4725772SN/A break; 4735772SN/A case BMIDescTablePtr: 4745772SN/A if (size != sizeof(uint32_t)) 4755772SN/A panic("Invalid BMIDTP write size: %x\n", size); 4765772SN/A bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3); 4775772SN/A break; 4785772SN/A default: 4795772SN/A if (size != sizeof(uint8_t) && size != sizeof(uint16_t) && 4805772SN/A size != sizeof(uint32_t)) 4815772SN/A panic("IDE controller write of invalid write size: %x\n", size); 4825772SN/A memcpy((uint8_t *)&bmiRegs + offset, data, size); 4835772SN/A } 4845772SN/A } 4855772SN/A} 4865772SN/A 4875772SN/Avoid 4885772SN/AIdeController::dispatchAccess(PacketPtr pkt, bool read) 4895772SN/A{ 4905772SN/A if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4) 4915772SN/A panic("Bad IDE read size: %d\n", pkt->getSize()); 4925772SN/A 4935772SN/A if (!ioEnabled) { 4945772SN/A pkt->makeAtomicResponse(); 4955772SN/A DPRINTF(IdeCtrl, "io not enabled\n"); 4965772SN/A return; 4975772SN/A } 4985772SN/A 4995772SN/A Addr addr = pkt->getAddr(); 5005772SN/A int size = pkt->getSize(); 5015772SN/A uint8_t *dataPtr = pkt->getPtr<uint8_t>(); 5025772SN/A 5035772SN/A if (addr >= primary.cmdAddr && 5045772SN/A addr < (primary.cmdAddr + primary.cmdSize)) { 5055772SN/A addr -= primary.cmdAddr; 5067750SN/A // linux may have shifted the address by ioShift, 5077750SN/A // here we shift it back, similarly for ctrlOffset. 5087750SN/A addr >>= ioShift; 5095772SN/A primary.accessCommand(addr, size, dataPtr, read); 5105772SN/A } else if (addr >= primary.ctrlAddr && 5115772SN/A addr < (primary.ctrlAddr + primary.ctrlSize)) { 5125772SN/A addr -= primary.ctrlAddr; 5137750SN/A addr += ctrlOffset; 5145772SN/A primary.accessControl(addr, size, dataPtr, read); 5155772SN/A } else if (addr >= secondary.cmdAddr && 5165772SN/A addr < (secondary.cmdAddr + secondary.cmdSize)) { 5175772SN/A addr -= secondary.cmdAddr; 5185772SN/A secondary.accessCommand(addr, size, dataPtr, read); 5195772SN/A } else if (addr >= secondary.ctrlAddr && 5205772SN/A addr < (secondary.ctrlAddr + secondary.ctrlSize)) { 5215772SN/A addr -= secondary.ctrlAddr; 5225772SN/A secondary.accessControl(addr, size, dataPtr, read); 5235772SN/A } else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) { 5245772SN/A if (!read && !bmEnabled) 5255772SN/A return; 5265772SN/A addr -= bmiAddr; 5275772SN/A if (addr < sizeof(Channel::BMIRegs)) { 5285772SN/A primary.accessBMI(addr, size, dataPtr, read); 5295772SN/A } else { 5305772SN/A addr -= sizeof(Channel::BMIRegs); 5315772SN/A secondary.accessBMI(addr, size, dataPtr, read); 5325772SN/A } 5335772SN/A } else { 5345772SN/A panic("IDE controller access to invalid address: %#x\n", addr); 5355772SN/A } 5365772SN/A 5378641SN/A#ifndef NDEBUG 5385772SN/A uint32_t data; 5395772SN/A if (pkt->getSize() == 1) 54013342Sgabeblack@google.com data = pkt->getLE<uint8_t>(); 5415772SN/A else if (pkt->getSize() == 2) 54213342Sgabeblack@google.com data = pkt->getLE<uint16_t>(); 5435772SN/A else 54413342Sgabeblack@google.com data = pkt->getLE<uint32_t>(); 5455772SN/A DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n", 5465772SN/A read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data); 5478641SN/A#endif 5485772SN/A 5495772SN/A pkt->makeAtomicResponse(); 5505772SN/A} 5512846SN/A 5522565SN/ATick 5533349SN/AIdeController::read(PacketPtr pkt) 554848SN/A{ 5555772SN/A dispatchAccess(pkt, true); 5562565SN/A return pioDelay; 557848SN/A} 558848SN/A 5592565SN/ATick 5603349SN/AIdeController::write(PacketPtr pkt) 561848SN/A{ 5625772SN/A dispatchAccess(pkt, false); 5632565SN/A return pioDelay; 564848SN/A} 565848SN/A 566848SN/Avoid 56710905SN/AIdeController::serialize(CheckpointOut &cp) const 568848SN/A{ 5699807SN/A // Serialize the PciDevice base class 57010905SN/A PciDevice::serialize(cp); 571897SN/A 5725772SN/A // Serialize channels 57310905SN/A primary.serialize("primary", cp); 57410905SN/A secondary.serialize("secondary", cp); 575864SN/A 5765772SN/A // Serialize config registers 5775772SN/A SERIALIZE_SCALAR(primaryTiming); 5785772SN/A SERIALIZE_SCALAR(secondaryTiming); 5795772SN/A SERIALIZE_SCALAR(deviceTiming); 5805772SN/A SERIALIZE_SCALAR(udmaControl); 5815772SN/A SERIALIZE_SCALAR(udmaTiming); 5825772SN/A SERIALIZE_SCALAR(ideConfig); 583864SN/A 584864SN/A // Serialize internal state 5855772SN/A SERIALIZE_SCALAR(ioEnabled); 5865772SN/A SERIALIZE_SCALAR(bmEnabled); 5875776SN/A SERIALIZE_SCALAR(bmiAddr); 5885776SN/A SERIALIZE_SCALAR(bmiSize); 5895772SN/A} 5905772SN/A 5915772SN/Avoid 59210905SN/AIdeController::Channel::serialize(const std::string &base, 59310905SN/A CheckpointOut &cp) const 5945772SN/A{ 59510905SN/A paramOut(cp, base + ".cmdAddr", cmdAddr); 59610905SN/A paramOut(cp, base + ".cmdSize", cmdSize); 59710905SN/A paramOut(cp, base + ".ctrlAddr", ctrlAddr); 59810905SN/A paramOut(cp, base + ".ctrlSize", ctrlSize); 5995775SN/A uint8_t command = bmiRegs.command; 60010905SN/A paramOut(cp, base + ".bmiRegs.command", command); 60110905SN/A paramOut(cp, base + ".bmiRegs.reserved0", bmiRegs.reserved0); 6025775SN/A uint8_t status = bmiRegs.status; 60310905SN/A paramOut(cp, base + ".bmiRegs.status", status); 60410905SN/A paramOut(cp, base + ".bmiRegs.reserved1", bmiRegs.reserved1); 60510905SN/A paramOut(cp, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp); 60610905SN/A paramOut(cp, base + ".selectBit", selectBit); 607848SN/A} 608848SN/A 609848SN/Avoid 61010905SN/AIdeController::unserialize(CheckpointIn &cp) 611848SN/A{ 6129807SN/A // Unserialize the PciDevice base class 61310905SN/A PciDevice::unserialize(cp); 614897SN/A 6155772SN/A // Unserialize channels 61610905SN/A primary.unserialize("primary", cp); 61710905SN/A secondary.unserialize("secondary", cp); 618864SN/A 6195772SN/A // Unserialize config registers 6205772SN/A UNSERIALIZE_SCALAR(primaryTiming); 6215772SN/A UNSERIALIZE_SCALAR(secondaryTiming); 6225772SN/A UNSERIALIZE_SCALAR(deviceTiming); 6235772SN/A UNSERIALIZE_SCALAR(udmaControl); 6245772SN/A UNSERIALIZE_SCALAR(udmaTiming); 6255772SN/A UNSERIALIZE_SCALAR(ideConfig); 626864SN/A 627864SN/A // Unserialize internal state 6285772SN/A UNSERIALIZE_SCALAR(ioEnabled); 6295772SN/A UNSERIALIZE_SCALAR(bmEnabled); 6305776SN/A UNSERIALIZE_SCALAR(bmiAddr); 6315776SN/A UNSERIALIZE_SCALAR(bmiSize); 6325772SN/A} 6335772SN/A 6345772SN/Avoid 63510905SN/AIdeController::Channel::unserialize(const std::string &base, CheckpointIn &cp) 6365772SN/A{ 63710905SN/A paramIn(cp, base + ".cmdAddr", cmdAddr); 63810905SN/A paramIn(cp, base + ".cmdSize", cmdSize); 63910905SN/A paramIn(cp, base + ".ctrlAddr", ctrlAddr); 64010905SN/A paramIn(cp, base + ".ctrlSize", ctrlSize); 6415775SN/A uint8_t command; 64210905SN/A paramIn(cp, base +".bmiRegs.command", command); 6435775SN/A bmiRegs.command = command; 64410905SN/A paramIn(cp, base + ".bmiRegs.reserved0", bmiRegs.reserved0); 6455775SN/A uint8_t status; 64610905SN/A paramIn(cp, base + ".bmiRegs.status", status); 6475775SN/A bmiRegs.status = status; 64810905SN/A paramIn(cp, base + ".bmiRegs.reserved1", bmiRegs.reserved1); 64910905SN/A paramIn(cp, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp); 65010905SN/A paramIn(cp, base + ".selectBit", selectBit); 6515772SN/A select(selectBit); 652848SN/A} 653848SN/A 6544762SN/AIdeController * 6554762SN/AIdeControllerParams::create() 656848SN/A{ 6574762SN/A return new IdeController(this); 658848SN/A} 659