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