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

📄 volume.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (C) 1998, 1999, 2001, 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 <assert.h>#include <limits.h>#include <stdlib.h>#include <memory.h>#include <unistd.h>#include <stdio.h>#include <errno.h>#include <time.h>#include <a.out.h>#include <sys/fcntl.h>#include <sys/stat.h>#include <disk/DiskNode.hxx>#include <disk/PagePot.hxx>#include <disk/DiskCkpt.hxx>#include <erosimg/App.hxx>#include <erosimg/Volume.hxx>#include <erosimg/DiskDescrip.hxx>#include <erosimg/ExecImage.hxx>#include <eros/Reserve.h>#include <new.h>#define BOOT "/eros/lib/boot/boot"#define min(x,y) ((x) > (y) ? (y) : (x))#define RESERVE_BYTES (MAX_CPU_RESERVE * sizeof(CpuReserveInfo))#define RESERVES_PER_PAGE (EROS_PAGE_SIZE / sizeof(CpuReserveInfo))#define RESERVE_PAGES ((RESERVE_BYTES + EROS_PAGE_SIZE - 1) / EROS_PAGE_SIZE)voidVolume::InitVolume(){  working_fd = -1;  target_fd = -1;  topDiv = 0;  topLogLid = 0;  lastAvailLogLid = 0;  firstAvailLogLid = (2 * EROS_OBJECTS_PER_FRAME);  dskCkptHdr0 = (DiskCheckpoint*) new uint8_t[EROS_PAGE_SIZE];  dskCkptHdr1 = (DiskCheckpoint*) new uint8_t[EROS_PAGE_SIZE];  curDskCkpt = dskCkptHdr0;  oldDskCkpt = dskCkptHdr1;    rewriting = true;  ckptDir = 0;  maxCkptDirent = 0;  nCkptDirent = 0;  threadDir = 0;  maxThreadDirent = 0;  nThreadDirent = 0;  reserveTable = new CpuReserveInfo[MAX_CPU_RESERVE];  bzero(reserveTable, sizeof(CpuReserveInfo) * MAX_CPU_RESERVE);    /* Following just for now... */  for (int i = 0; i < STD_CPU_RESERVE; i++) {    reserveTable[i].index = i;    reserveTable[i].normPrio = i;    reserveTable[i].rsrvPrio = -2;  }  for (int i = STD_CPU_RESERVE; i < MAX_CPU_RESERVE; i++) {    reserveTable[i].index = i;    reserveTable[i].normPrio = -2;    reserveTable[i].rsrvPrio = -2;  }    needSyncDivisions = false;  needSyncHdr = false;  needSyncCkptLog = false;  needDivInit = false;  curLogPotLid = UNDEF_LID;}Volume::Volume(){  InitVolume();#ifdef DEAD_BAD_MAP /* spare ranges are a thing of the past */  divTable = (Division *) divPage;  badmap = (BadEnt*) &divTable[NDIVENT];#endif}Volume::~Volume(){  Close();}CpuReserveInfoVolume::GetReserve(uint32_t ndx){  if (ndx >= MAX_CPU_RESERVE)    Diag::fatal(1, "Reserve %d is out of range\n");    return reserveTable[ndx];}voidVolume::SetReserve(const CpuReserveInfo& cri){  if (cri.index >= MAX_CPU_RESERVE)    Diag::fatal(1, "Reserve %d is out of range\n");    reserveTable[cri.index] = cri;}boolVolume::Read(uint32_t offset, void *buf, uint32_t sz){  assert(working_fd >= 0);  if (::lseek(working_fd, (int) offset, SEEK_SET) < 0)    return false;  if (::read(working_fd, buf, (int) sz) != (int) sz)    return false;  return true;}boolVolume::Write(uint32_t offset, const void *buf, uint32_t sz){  assert(working_fd >= 0);  if (::lseek(working_fd, (int) offset, SEEK_SET) < 0)    return false;  if (::write(working_fd, buf, (int) sz) != (int) sz)    return false;  return true;}/* This version finds an empty spot big enough for the division and puts it * there. */intVolume::AddDivision(DivType type, uint32_t sz, const OID& oid){  uint32_t nObFrames = sz / EROS_PAGE_SECTORS;  OID endOid;  switch (type) {  case dt_Kernel:  case dt_Object:    nObFrames -= (nObFrames / PAGES_PER_PAGE_CLUSTER);    if (nObFrames < 1)      Diag::fatal(1, "Range too small\n");    if (nObFrames % PAGES_PER_PAGE_CLUSTER)      nObFrames -= 1;		/* at least one page pot */    if (nObFrames < 1)      Diag::fatal(1, "Range too small\n");    /* Take out one more for the first page, which is used to capture     * seqno of most recent checkpoint.     */    nObFrames--;    endOid = oid + (nObFrames * EROS_OBJECTS_PER_FRAME);    break;  case dt_Log:    endOid = oid + (nObFrames * EROS_OBJECTS_PER_FRAME);    break;  default:    Diag::fatal(1, "Attempt to set OID on inappropriate division type\n");    break;  }    if ((type != dt_Log) && (oid % EROS_OBJECTS_PER_FRAME))    Diag::fatal(1, "Starting OID for range must be multiple of %d\n",		EROS_OBJECTS_PER_FRAME);      int div = AddAdjustableDivision(type, sz);    if (type == dt_Log && endOid > topLogLid) {    topLogLid = endOid;    lastAvailLogLid = endOid;  }      divTable[div].startOid = oid;  divTable[div].endOid = endOid;  Diag::printf("Division %d: %6d %6d [%6s] %s=[",	       div, divTable[div].start, divTable[div].end,	       div_TypeName(divTable[div].type),	       (type == dt_Log) ? "LID" : "OID");  Diag::print(divTable[div].startOid);  Diag::printf(", ");  Diag::print(divTable[div].endOid);  Diag::printf(")\n");    return div;}/* This version finds an empty spot big enough for the division and puts it * there. */intVolume::AddDivision(DivType type, uint32_t sz){  switch (type) {  case dt_Object:  case dt_Log:    Diag::fatal(1, "Attempt to create %s division without OID\n",		div_TypeName(type));    break;  default:    break;  }    int div = AddAdjustableDivision(type, sz);  Diag::printf("Division %d: %6d %6d [%6s]\n",	       div, divTable[div].start, divTable[div].end,	       div_TypeName(divTable[div].type));  return div;}intVolume::AddAdjustableDivision(DivType type, uint32_t sz){  int i;  uint32_t start = 0;  assert(working_fd >= 0);        /* make sure we do not collide with another division: */  for (i = 0; i < topDiv; i++) {    uint32_t end = start + sz;	/* if some other division starts or ends in our proposed range,	 * go to the end of the colliding division:	 */    if ((divTable[i].start >= start && divTable[i].start < end) ||	(divTable[i].end > start && divTable[i].end <= end)) {      start = divTable[i].end;      i = -1;			/* restart for loop */    }  }    int div = DoAddDivision(type, start, sz);  return div;}intVolume::AddFixedDivision(DivType type, uint32_t start, uint32_t sz){  int div = DoAddDivision(type, start,  sz);    Diag::printf("Division %d: %6d %6d [%6s]\n",	       div, start, start+sz, div_TypeName(divTable[div].type));  return div;}/* The versions that follow add a division at a fixed location: */intVolume::DoAddDivision(DivType type, uint32_t start, uint32_t sz){  assert(working_fd >= 0);    if (topDiv >= NDIVENT)    Diag::fatal(4, "Too many divisions\n");    uint32_t end = start + sz;    /* Need to verify that this division does not overlap some other   * division if it has nonzero size   */    int i;  if (sz) {    for (i = 0; i < topDiv; i++) {      if ((divTable[i].start != divTable[i].end) &&	  (start >= divTable[i].start && start < divTable[i].end) ||	  (end > divTable[i].start && end <= divTable[i].end))	Diag::fatal(4, "Division range error\n");    }  }    int div = topDiv;  topDiv++;    divTable[div].type = type;  divTable[div].start = start;  divTable[div].end = end;  divTable[div].startOid = 0;  divTable[div].endOid = 0;    if (type == dt_DivTbl) {    /* Perfectly okay to have lots of division tables, but only two     * end up in the volume header:     */        /* assert(!volHdr.AltDivTable); */    if (!volHdr.DivTable)      volHdr.DivTable = start;    else      volHdr.AltDivTable = start;  }  needSyncHdr = 1;		/* if nothing else, volume size changed */  #ifdef DEAD_BAD_MAP /* spare ranges are a thing of the past */  if (type == dt_Spare)    spareDivNdx = div;#endif    divNeedsInit[div] = true;  needDivInit = true;  needSyncDivisions = true;    return div;}voidVolume::FormatObjectDivision(int ndx){  assert(working_fd >= 0);  if (ndx >= topDiv)    Diag::fatal(1, "Attempt to format nonexistent division\n");    Division& d = divTable[ndx];    for (OID oid = d.startOid; oid < d.endOid; oid += EROS_OBJECTS_PER_FRAME) {    VolPagePot pagePot;    ReadPagePotEntry(oid, pagePot);    pagePot.type = FRM_TYPE_ZDPAGE;    pagePot.count = 0;    WritePagePotEntry(oid, pagePot);    oid++;  }  /* Set up a first page with suitable ckpt sequence number: */  uint8_t buf[EROS_PAGE_SIZE];  uint64_t *seqNo = (uint64_t *) buf;  *seqNo = 1;  Write(d.start * EROS_SECTOR_SIZE, buf, EROS_PAGE_SIZE);}/* Once the log division has been zeroed, we simply need to write * suitable checkpoint header pages: */voidVolume::FormatLogDivision(int ndx){  assert(working_fd >= 0);  if (ndx >= topDiv)    Diag::fatal(1, "Attempt to format nonexistent division\n");    Division& d = divTable[ndx];    if (d.startOid == 0) {    oldDskCkpt->sequenceNumber = 0;    oldDskCkpt->hasMigrated = true;    oldDskCkpt->maxLogLid = topLogLid;    oldDskCkpt->nRsrvPage = 0;    oldDskCkpt->nThreadPage = 0;    oldDskCkpt->nDirPage = 0;    curDskCkpt->sequenceNumber = 1;    curDskCkpt->hasMigrated = false;    curDskCkpt->maxLogLid = topLogLid;    curDskCkpt->nRsrvPage = 0;    curDskCkpt->nThreadPage = 0;    curDskCkpt->nDirPage = 0;    WriteLogPage((lid_t)0, (uint8_t *) dskCkptHdr0);    WriteLogPage((lid_t)(1*EROS_OBJECTS_PER_FRAME), (uint8_t *) dskCkptHdr1);  }  needSyncCkptLog = true;}voidVolume::ZeroDivision(int ndx){  assert(working_fd >= 0);  if (ndx >= topDiv)    Diag::fatal(1, "Attempt to zero nonexistent division\n");    uint8_t buf[EROS_SECTOR_SIZE];  bzero(buf, EROS_SECTOR_SIZE);    Division& d = divTable[ndx];    for (uint32_t i = d.start; i < d.end; i++)    if ( !Write(i * EROS_SECTOR_SIZE, buf, EROS_SECTOR_SIZE) )      Diag::fatal(1, "Couldn't zero division %d\n", ndx);  divNeedsInit[ndx] = false;}voidVolume::SetVolFlag(VolHdr::Flags flag){  volHdr.BootFlags |= flag;  needSyncHdr = 1;}voidVolume::ClearVolFlag(VolHdr::Flags flag){  volHdr.BootFlags &= ~flag;  needSyncHdr = 1;}voidVolume::SetIplSysId(uint64_t dw){  volHdr.iplSysId = dw;  needSyncHdr = 1;}voidVolume::SetIplKey(const DiskKey& k){  volHdr.iplKey = k;  needSyncHdr = 1;}voidVolume::WriteKernelImage(int div, const ExecImage& image){  ZeroDivision(div);  FormatObjectDivision(div);  divNeedsInit[div] = false;    assert(working_fd >= 0);    if (div >= topDiv)    Diag::fatal(1, "Attempt to write image %s on nonexistent division\n",		image.GetName().str());  if (image.NumRegions() != 1)    Diag::fatal(1, "Image %s has inappropriate number of regions\n",		image.GetName().str());  const ExecRegion& er = image.GetRegion(0);  /* If the image was built correctly, it should start at a page boundary: */  if (er.vaddr % EROS_PAGE_SIZE)    Diag::fatal(1, "ELF Image %s has start vaddr at nonpage boundary\n",		image.GetName().str());  uint32_t bytes = er.filesz;  const uint8_t *fileImage = image.GetImage();  fileImage += er.offset;    Division& d = divTable[div];  OID oid = d.startOid;  uint32_t divPages = (d.endOid - d.startOid) / EROS_OBJECTS_PER_FRAME;  if (divPages * EROS_PAGE_SIZE < er.filesz)    Diag::fatal(1, "Image \"%s\" (%d bytes) will not fit in division %d (%d pages)\n",		image.GetName().str(), bytes, div, divPages);  while (bytes) {    uint8_t buf[EROS_PAGE_SIZE];        memset(buf, 0, EROS_PAGE_SIZE);    memcpy(buf, fileImage, min (bytes, EROS_PAGE_SIZE));    WriteDataPage(oid, buf);    fileImage += EROS_PAGE_SIZE;    bytes -= min(bytes, EROS_PAGE_SIZE);    oid += EROS_OBJECTS_PER_FRAME;  }}/* NOTE!!! This only works for dense images, such as the kernel and * bootstrap code.  Domain images MUST be handled through the * DomainImage class.  Offset is in bytes. */voidVolume::WriteImageAtDivisionOffset(int div, const ExecImage& image,				   uint32_t offset){  assert(working_fd >= 0);    if (div >= topDiv)    Diag::fatal(1, "Attempt to write image %s on nonexistent division\n",		image.GetName().str());  if (image.NumRegions() != 1)    Diag::fatal(1, "Image %s has inappropriate number of regions\n",		image.GetName().str());  const ExecRegion& er = image.GetRegion(0);  /* If the image was built correctly, it should start at a page boundary: */  if (er.vaddr % EROS_PAGE_SIZE)    Diag::fatal(1, "ELF Image %s has start vaddr at nonpage boundary\n",		image.GetName().str());      uint32_t secs = er.filesz / EROS_SECTOR_SIZE;  if (er.filesz % EROS_SECTOR_SIZE)    secs++;    uint32_t imageSz = secs * EROS_SECTOR_SIZE;    /* The following copy is necessary because the file itself may   * contain garbage or other stuff at the tail of the alleged region,   * so we must zero-extend to the end of the sector by hand.   */    uint8_t *imageBuf = new uint8_t[imageSz];  bzero(imageBuf, imageSz);  const uint8_t *fileImage = image.GetImage();    memcpy(imageBuf, &fileImage[er.offset], er.filesz);  Division& d = divTable[div];    uint32_t divStart = d.start * EROS_SECTOR_SIZE;  uint32_t divEnd   = d.end * EROS_SECTOR_SIZE;  if (divStart + offset + imageSz > divEnd)    Diag::fatal(1, "Image \"%s\" will not fit in division %d\n",		image.GetName().str(), div);  Write(divStart + offset, imageBuf, imageSz);    delete [] imageBuf;  divNeedsInit[div] = false;}voidVolume::DelDivision(int ndx){  int i;  assert(working_fd >= 0);  if (ndx >= topDiv)    Diag::fatal(1, "Attempt to delete nonexistent division\n");  switch (divTable[ndx].type) {  case dt_Boot:  case dt_DivTbl:      Diag::fatal(1, "Division type %s cannot be deleted\n",		  div_TypeName(divTable[ndx].type));      break;  break;  case dt_Spare:    /* Can only delete spare division if no spare sectors are     * in use.     */    break;  }  for (i = ndx+1; i < topDiv; i++)    divTable[i-1] = divTable[i];  divTable[i].type = dt_Unused;  topDiv--;  needSyncHdr = 1;		/* volume size may have changed */}uint32_tVolume::DivisionSetFlags(int ndx, uint32_t flags){  assert(working_fd >= 0);  if (ndx >= topDiv)    Diag::fatal(1, "Attempt to update flags for nonexistent division\n");  divTable[ndx].flags |= flags;  Diag::printf("Division %d: flags set to [ ", ndx);  if (divTable[ndx].flags & DF_PRELOAD)    Diag::printf("preload ");  Diag::printf("]\n");  needSyncDivisions = true;  return divTable[ndx].flags;}uint32_t

⌨️ 快捷键说明

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