⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 io_blockdev.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
字号:
/* * Copyright (C) 1998, 1999, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <kerninc/kernel.hxx>#include <kerninc/MsgLog.hxx>#include <kerninc/Thread.hxx>#include <kerninc/Task.hxx>#include <kerninc/ObjectCache.hxx>#include <kerninc/Debug.hxx>#include <arch-kerninc/KernTune.hxx>#include <kerninc/IoRequest.hxx>#include <kerninc/BlockDev.hxx>#include <kerninc/Invocation.hxx>#include <eros/DeviceKey.h>#include <eros/Invoke.h>#define dbg_plug  0x1		/* io requests *//* Following should be an OR of some of the above */#define dbg_flags   (0)#define DEBUG(x) if (dbg_##x & dbg_flags)BlockDev*  BlockDev::registry[KTUNE_NBLKDEV];BlockDev*  BlockDev::readyChain = 0;uint32_t   BlockDev::totalMountedUnits = 0;ThreadPile BlockDev::MountWait;voidBlockDev::WakeMountWaiters(){  MountWait.WakeAll();}voidBlockDev::WaitForMount(){  Thread::Current()->SleepOn(MountWait);  Thread::Current()->Yield();}voidBlockDev::ActivateTask(){  pTask->ActivateTask();}BlockDev::BlockDev(){  nUnits = 0;  isRegistered = false;  name = "???";  inDuplexWait = false;}voidBlockDev::Register(){  if (isRegistered)    return;  for (uint32_t i = 0; i < KTUNE_NBLKDEV; i++) {    if (registry[i] == 0) {      registry[i] = this;      isRegistered = true;      return;    }  }  MsgLog::fatal("Block device limit exceeded\n");}voidBlockDev::Unregister(){  if (isRegistered == false)    return;  for (uint32_t i = 0; i < KTUNE_NBLKDEV; i++) {    if (registry[i] == this) {      registry[i] = 0;      isRegistered = false;      return;    }  }}#if 0/* AutoMount is a pain in the ass because it involves long delays and * can be initiated by the user.  All of the delays involved in * spinning up the device and media format detection can reasonably be * captured in a state machine - if the user has been diverted before * the attach completes, the attach will complete anyway.  If the user * requests the attach redundantly, no great harm will be done. *  * Reading the partition table is another matter.  I'm loathe to build * this into the state machine, for two reasons: *  *  1. It's complex.  The spinup logic has to be there to handle sleep *     mode anyway, so we might as well use it, but partition read is *     more or less a one-shot event at disk mount time. *  *  2. It's machine specific.  The format of the partition table *     depends a great deal on the platform. *  * For this reason, I have divided the disk mount procedure into two * phases: attachment and mounting.  The attachment phase spins up the * drive and does media detection.  The mounting phase reads the * partition table.  Note that in order for the unit to be marked for * automounting, it must already be attached. *  * FOR THE MOMENT I am leaving the code here, but it should ultimately * move into the arch/i486/kernel directory. *  */voidBlockDev::AutoMount(){  MsgLog::printf("Enter BlockDev::AutoMount()\n");  for (uint32_t i = 0; i < KTUNE_NBLKDEV; i++) {    BlockDev *ctrlr = registry[i];    if (ctrlr) {      for (uint8_t unit = 0; unit < ctrlr->nUnits; unit++) {	if (ctrlr->ShouldAutoMount(unit)) {	  MsgLog::printf("  Mounting %s%d...\n", ctrlr->name, unit);	  ctrlr->MountUnit(unit);	}      }    }  }  MsgLog::printf("Exit BlockDev::AutoMount()\n");}voidBlockDev::AutoMountPartitions(){  assert (Thread::Current()->IsKernel());    static uint32_t callCount = 0;  if (callCount)    Debug::Backtrace("AutoMountPartitions() recalled\n");  callCount++;    MsgLog::printf("Enter BlockDev::AutoMountPartitions()\n");  bool found = false;    do {    found = false;        for (uint32_t i = 0; i < KTUNE_NBLKDEV; i++) {      BlockDev *ctrlr = registry[i];      if (ctrlr) {	for (uint8_t unit = 0; unit < ctrlr->nUnits; unit++) {	  if (ctrlr->ShouldMountPartitions(unit)) {	    found = true;	    ctrlr->MountUnitPartitions(unit);	  }	}      }    }  } while(found);  MsgLog::printf("Exit BlockDev::AutoMountPartitions()\n");}#endifvoidBlockDev::StartAll(Task *){  while (readyChain) {    BlockDev *bd = readyChain;    readyChain = readyChain->next;      bd->StartIO();  }}static voidRawIoCompleted(Request *req){  req->rawStallQ.IoWakeAll(0);}voidBlockDev::DoDeviceRead(uint8_t unit, ObjectHeader *pOb, uint32_t startSec,		       uint32_t nSec){#ifndef NDEBUG  extern uint32_t TrapDepth;  assert ( Thread::Current()->IsKernel() && TrapDepth == 0);#endif#if 0  if (isKernel == false)    assert ( Thread::Current()->IsUser() );  else    assert ( Thread::Current()->IsKernel() );#endif  /* Read at most one page at a time: */  assert(nSec <= EROS_PAGE_SECTORS);    Thread::DO_NOT_PREEMPT();    Request::Require(1);    /* FIX: Should check for read hazard first! */  pOb->SetFlags(OFLG_IO);  pOb->ob.ioCount = 1;    Request *req = new Request(unit, IoCmd::Read, startSec, nSec);  req->req_ioaddr = ObjectCache::ObHdrToPage(pOb);  req->completionCallBack = RawIoCompleted;  Thread::Current()->SleepOn(req->rawStallQ);  InsertRequest(req);  Thread::Current()->DirectedYield();}voidBlockDev::DoDeviceWrite(uint8_t unit, ObjectHeader *pOb, uint32_t startSec, uint32_t nSec){#ifndef NDEBUG  extern uint32_t TrapDepth;  assert ( Thread::Current()->IsKernel() && TrapDepth == 0);#endif  /* Read at most one page at a time: */  assert(nSec <= EROS_PAGE_SECTORS);    Thread::DO_NOT_PREEMPT();    Request::Require(1);    /* FIX: Should check for read hazard first! */  pOb->SetFlags(OFLG_IO);  pOb->ob.ioCount = 1;    Request *req = new Request(unit, IoCmd::Write, startSec, nSec);  req->req_ioaddr = ObjectCache::ObHdrToPage(pOb);  req->completionCallBack = RawIoCompleted;  Thread::Current()->SleepOn(req->rawStallQ);  InsertRequest(req);  Thread::Current()->DirectedYield();}#if 0voidBlockDev::DevicePlug(uint8_t unit){  Request *req = new Request(unit, IoCmd::Plug, 0);  Thread::Current()->SleepOn(req->rawStallQ);  InsertRequest(req);  Thread::Current()->Yield(true);}#endifvoidBlockDev::PlugAllBlockDevices(void (*callBack)(DuplexedIO *)){  Request::Require(totalMountedUnits);  DuplexedIO *dio = DuplexedIO::Grab(0, IoCmd::Plug);  dio->completionCallBack = callBack;    Thread::Current()->SleepOn(dio->stallQ);  for (uint32_t i = 0; i < KTUNE_NBLKDEV; i++) {    BlockDev *ctrlr = registry[i];    if (ctrlr) {      for (uint8_t unit = 0; unit < ctrlr->nUnits; unit++) {	BlockUnitInfo ui;	ctrlr->GetUnitInfo(unit, ui);	if (ui.isDisk && ui.isMounted) {	  Request *req = new Request(unit, IoCmd::Plug, 0, 0);	  assert(req);	  dio->AddRequest(req);	  DEBUG(plug) MsgLog::printf("Insert plug on %s%d\n",				     ctrlr->name,				     unit);	  ctrlr->InsertRequest(req);	}      }    }  }  DEBUG(plug) MsgLog::dprintf(true, "Plug DIO release\n");  dio->Release();    Thread::Current()->Yield(/* true */);}voidBlockDev::Invoke(Invocation& inv){  BlockUnitInfo ui;  uint32_t unit = inv.key->dk.devUnit;  COMMIT_POINT();    if (unit >= nUnits) {	inv.exit.code = RC_NoSuchDevice;	return;  }  GetUnitInfo(unit, ui);  if (!ui.isMounted) {    inv.exit.code = RC_NoSuchDevice;    return;  }  if ((uint32_t)inv.exit.data % EROS_PAGE_SIZE) {    inv.exit.code = RC_NotPageAddr;    return;  }  if ((uint32_t)inv.exit.len > EROS_PAGE_SIZE) {    inv.exit.code = RC_TooBig;    return;  }  switch(inv.entry.code) {  case OC_Device_Mount:  case OC_Device_Unmount:  case OC_Device_Rewind:    inv.exit.code = RC_UnknownRequest;    MsgLog::fatal("Device order %d is unimplemented\n",		  inv.entry.code);    break;  case OC_Device_Read:    {#if 0      uint32_t startSec = inv.entry.w1;      uint32_t nSec = inv.entry.w1;      uint32_t len = inv.exit.len;      uint32_t addr = (uint32_t) inv.exit.data;      DeviceRead(unit, 0, startSec, nSec);#endif      inv.exit.code = RC_UnknownRequest;      MsgLog::fatal("Device order %d is unimplemented\n",		    inv.entry.code);      break;    }    case OC_Device_Write:    {      inv.exit.code = RC_UnknownRequest;      MsgLog::fatal("Device order %d is unimplemented\n",		    inv.entry.code);      break;    }  }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -