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

📄 io_blockdevmount.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. *//* Mounting disk units presents us with a small problem -- we can't * really initiate a sequence of IO operations on behalf of a user * thread, because the stack is lost, but we must do just such a * sequence in order to read the partition table off of a DOS * formatted volume.  Similar problems probably arise in other * partitioning mechanisms, but I have no intention of getting sucked * in to that. *  * In the EROS design, a disk cannot be mounted without reading it's * partition table.  If you wish to change the partition structure, * you must rewrite the partition table and dismount and remount the * device. *  * Given all of this, disk mount is handled as follows:  The mount * function (see BlockDev.hxx) marks the device as *wanting* to be * mounted, and places the caller to sleep on the mount completion * stall queue.  It then wakes up the mount daemon (a kernel thread), * which mounts the device and reads the partition table if * appropriate.  The Mount Daemon will keep doing this until there are * no more devices to mount, and then it will wake up all of the * threads that are stalled on it. */#include <kerninc/kernel.hxx>#include <kerninc/Thread.hxx>#include <kerninc/CpuReserve.hxx>#include <kerninc/Task.hxx>#include <kerninc/MsgLog.hxx>#include <kerninc/ObjectHeader.hxx>#include <kerninc/ObjectCache.hxx>#include <kerninc/Machine.hxx>#include <kerninc/BlockDev.hxx>#include <kerninc/Partition.hxx>#include <disk/LowVolume.hxx>struct DosPartition {	unsigned char boot_ind;		/* 0x80 - active */	unsigned char head;		/* starting head */	unsigned char sector;		/* starting sector */	unsigned char cyl;		/* starting cylinder */	unsigned char sys_ind;		/* What partition type */	unsigned char end_head;		/* end head */	unsigned char end_sector;	/* end sector */	unsigned char end_cyl;		/* end cylinder */	unsigned int start_sect;	/* starting sector counting from 0 */	unsigned int nr_sects;		/* nr of sectors in partition */};#define MOUNT_DEBUGstatic ThreadPile MountIdle;Task *BlockDev::pTask;const uint32_t StackSize = 1024;static uint32_t MntStack[StackSize];class MountDaemon : public KernThread {public:  static void Start();  MountDaemon()    :KernThread("MntDmn",		&MountDaemon::Start,		MntStack, &MntStack[StackSize])  {    procContext.InitStack();  }};static MountDaemon TheMountDaemon;voidBlockDev::Init(){  CpuReserve::KernThreadCpuReserve.AddKernelThread(&TheMountDaemon);    pTask = new Task(BlockDev::StartAll);  assert(pTask);  TheMountDaemon.SleepOn(MountIdle);}voidMountDaemon::Start(){  for (;;) {    while (BlockDev::DoAutoMount())      ;    TheMountDaemon.SleepOn(MountIdle);    BlockDev::WakeMountWaiters();    TheMountDaemon.DirectedYield();  }}boolBlockDev::DoAutoMount(){  bool found = false;#ifdef MOUNT_DEBUG  MsgLog::printf("Enter BlockDev::DoAutoMount()\n");#endif  for (uint32_t i = 0; i < KTUNE_NBLKDEV; i++) {    BlockDev *ctrlr = registry[i];    if (ctrlr) {#ifdef MOUNT_DEBUG      MsgLog::printf("  Checking ctrlr=0x%08x\n", ctrlr);#endif      for (uint8_t unit = 0; unit < ctrlr->nUnits; unit++) {	BlockUnitInfo ui;	ctrlr->GetUnitInfo(unit, ui);	if (ui.isDisk == false) {	  MsgLog::dprintf(false, "  Unit %d is not a disk\n", unit);	  continue;	}	if (ui.needsMount == false) {	  MsgLog::dprintf(false, "  Unit %d should not be mounted\n", unit);	  continue;	}	if (ui.isMounted) {	  MsgLog::dprintf(false, "  Unit %d already mounted\n", unit);	  continue;	}		found = true;	  	/* mount the unit and do format detection: */#ifdef MOUNT_DEBUG	MsgLog::printf("  Mounting %s%d...\n", ctrlr->name, unit);#endif	ctrlr->MountUnit(unit);	/* Need to check again, since on some devices the answers	 * depend on the media:	 */	ctrlr->GetUnitInfo(unit, ui);	if (ui.nSecs == 0)	  MsgLog::fatal("%s%d: Format could not be detected\n",			ctrlr->name, unit);	if (ui.hasPartitions == false) {	  /* If the unit has no partitions, forge a single partition	   * spanning the entire unit:	   */	  Partition *p = new Partition(ctrlr, unit, 0);	  assert(p);	  p->lba_start = 0;	  p->nSecs = ui.nSecs;	  /* Forge BIOS entries for the ramdisk: */	  p->bios_start.cyl = 0;	  p->bios_start.hd = 0;	  p->bios_start.sec = 0;	  /* This is an EXCLUSIVE bound */	  p->bios_end = ui.b_geom;	  p->isBoot = ui.isBoot;	  p->isEros = ui.isEros;#ifdef MOUNT_DEBUG	  MsgLog::printf("  Forge partition %s%d-%d: %d/%d/%d, %d secs\n",			 p->ctrlr->name, p->unit, p->ndx,			 p->bios_start.cyl,			 p->bios_start.hd,			 p->bios_start.sec,			 p->nSecs);#endif	  if (p->isEros) {	    /* Machine::SpinWait(4000); */	    CheckErosPartition(p);	  }	  if (p->isBoot)	    MsgLog::printf("*** Is boot partition\n");	  /* Machine::SpinWait(4000); */	}	else {	  ObjectHeader *ioPage = ObjectCache::GrabPageFrame();	  MsgLog::printf("Grabbed frame 0x%08x\n", ioPage);  	  /* Only need the first sector: */	  ctrlr->DoDeviceRead(unit, ioPage, 0, 1);	  kva_t addr = ObjectCache::ObHdrToPage(ioPage);	  /* Partition table is at offset 0x1BE: */	  	  DosPartition * ptable = (DosPartition *) (addr + 0x1BE);	  for (uint32_t prt = 0; prt < 4; prt++) {	    DosPartition *pdp = &ptable[prt];	    Partition *p = new Partition(ctrlr, unit, prt);	    assert(p);	    /* Forge BIOS entries for the ramdisk: */	    p->bios_start.cyl = pdp->cyl;	    p->bios_start.hd = pdp->head;	    p->bios_start.sec = pdp->sector;	    p->lba_start = pdp->start_sect;	    p->nSecs = pdp->nr_sects;	    /* This is an EXCLUSIVE bound */	    p->bios_end.cyl = pdp->end_cyl;	    p->bios_end.hd = pdp->end_head;	    p->bios_end.sec = pdp->end_sector;	    /* Actually, this isn't the right way to go about it, but	     * for now:	     */	    p->isBoot = pdp->boot_ind ? true : false;	    p->isEros = (pdp->sys_ind == EROS_PARTITION_TYPE);	    /* FIX: Many formatting programs do not correctly set up the	     * starting lba and nSecs fields in the partition table.	     */	  #ifdef MOUNT_DEBUG	    MsgLog::printf("  Partition %s%d-%d: %d/%d/%d, %d secs\n",			   p->ctrlr->name, p->unit, p->ndx,			   p->bios_start.cyl,			   p->bios_start.hd,			   p->bios_start.sec,			   p->nSecs);	    if (p->isBoot)	      MsgLog::printf("*** Is boot partition\n");#endif	    if (p->isEros) {	      /* Machine::SpinWait(4000); */	      CheckErosPartition(p);	    }	    /* Machine::SpinWait(4000); */	  }	  ObjectCache::ReleasePageFrame(ioPage);	}      }    }  }   #ifdef MOUNT_DEBUG  MsgLog::printf("Exit BlockDev::DoAutoMount()\n");#endif  return found;}voidBlockDev::CheckErosPartition(Partition *p){  /* fix -- this should read the first sector and verify that it is   * really an EROS partition.   */  ObjectHeader *pObHdr = ObjectCache::GrabPageFrame();  kva_t buf = ObjectCache::ObHdrToPage(pObHdr);  Request::Require(1);    /* just the first sector! */  Request *req = new Request(p->unit, IoCmd::Read, 0, 1);  req->req_ioaddr = buf;  MsgLog::printf("Queueing request for %d sectors\n", req->req_nsec);  Thread::Current()->SleepOn(req->rawStallQ);  p->InsertRequest(req);	/* MAY run promptly! */  Thread::Current()->DirectedYield();  VolHdr * pHdr = (VolHdr*) buf;  if (memcmp(pHdr->signature, "EROS", 4) != 0) {#ifdef MOUNT_DEBUG    MsgLog::printf("  Not really an EROS partition\n");#endif    p->isEros = false;  }  else if (pHdr->iplSysId != Machine::GetIplSysId()) {#ifdef MOUNT_DEBUG    MsgLog::printf("  Partition doesn't match booted IplSysID\n");#endif    p->isEros = false;  }  else#ifdef MOUNT_DEBUG    MsgLog::printf("  Really an EROS partition\n");#endif  ObjectCache::ReleasePageFrame(pObHdr);}voidBlockDev::RunMountDaemon(){  Thread::Current()->SleepOn(MountWait);  MountIdle.WakeAll();  Thread::Current()->DirectedYield();}

⌨️ 快捷键说明

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