📄 io_blockdev.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 + -