📄 erosimage.cxx
字号:
/* * 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 <sys/fcntl.h>#include <sys/stat.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <eros/target.h>#include <erosimg/Intern.hxx>#include <erosimg/ExecArch.hxx>#include <erosimg/ErosImage.hxx>#include <erosimg/Parse.hxx>#include <erosimg/App.hxx>#include <eros/Key.h>#include <eros/RangeKey.h>#include <eros/ProcessState.h>#include <disk/DiskNode.hxx>#include <disk/DiskLSS.hxx>/* Following is included as a special case so that AddProcess() register conventions stay in sync with the expectations of the runtime libraries. */#include "../../../lib/domain/include/domain/Runtime.h"#ifndef max#define max(x,y) ( ((x) > (y)) ? (x) : (y) )#endif#define PAGE_ALLOC_QUANTA 16#define NODE_ALLOC_QUANTA 16#define DIR_ALLOC_QUANTA 16#define THREAD_ALLOC_QUANTA 16extern void PrintDiskKey(const DiskKey&);static unsigned intGetAnyBlss(const DiskKey & key){ if (key.IsVoidKey()) return EROS_PAGE_BLSS; return key.GetBlss();}ErosHeader::ErosHeader(){ /* First initialize the domain file image header: */ memset(signature, 0, 8); strcpy(signature, "ErosImg"); imageByteSex = 0; version = EROS_IMAGE_VERSION; architecture = ExecArch::arch_unknown; nDirEnt = 0; nStartups = 0; nPages = 0; nZeroPages = 0; nNodes = 0; strSize = 0; dirOffset = sizeof(ErosHeader); startupsOffset = sizeof(ErosHeader); pageOffset = sizeof(ErosHeader); nodeOffset = sizeof(ErosHeader); strTableOffset = sizeof(strTableOffset);}ErosImage::ErosImage(){ pageImages = 0; nodeImages = 0; dir = 0; startupsDir = 0; maxPage = 0; maxNode = 0; maxDir = 0; maxStartups = 0; DiskKey key = AddNode(); AddDirEnt("volsize", key); key = AddNode(); AddDirEnt("threadlist", key);}ErosImage::~ErosImage(){ delete [] pageImages; delete [] nodeImages; delete [] dir; delete [] startupsDir;}InternedStringErosImage::GetString(int ndx) const{ return InternedString(pool.Get(ndx));}boolErosImage::AddStartup(const char* name, const DiskKey& key){ InternedString is(name); return AddStartup(is, key);}voidErosImage::AddDirEnt(const char* name, const DiskKey& key){ InternedString is(name); AddDirEnt(is, key);}voidErosImage::AssignDirEnt(const char* name, const DiskKey& key){ InternedString is(name); AssignDirEnt(is, key);}boolErosImage::AddStartup(const InternedString& name, const DiskKey& key){ uint32_t nameNdx = pool.Add(name); if (key.IsType(KT_Process) || key.IsType(KT_Node)) { if (GetProcessState(key) == RS_Waiting) { Diag::printf("Attempt to re-start process that is already started.\n"); return false; } SetProcessState(key, RS_Waiting); } else if (key.IsType(KT_Start)) { /* Arrangements should already have been made to get the target process running, in which case it will be in the waiting state: */ if (GetProcessState(key) != RS_Waiting) { Diag::printf("Attempt to invoke constructor that has not been started.\n"); return false; } } else { Diag::printf("Bad key type to AddThead()\n"); return false; } for (uint32_t i = 0; i < nStartups; i++) if (startupsDir[i].name == nameNdx) Diag::fatal(5, "Duplicate name \"%s\" added to image file\n", name.str()); if (nStartups >= maxStartups) GrowStartupsTable(maxStartups + THREAD_ALLOC_QUANTA); startupsDir[nStartups].key = key; startupsDir[nStartups].name = nameNdx; DiskKey threadChain; assert ( GetDirEnt("threadlist", threadChain) ); for (unsigned i = 0; i < nStartups/(EROS_NODE_SIZE-1); i++) threadChain = GetNodeSlot(threadChain, EROS_NODE_SIZE - 1); unsigned ndx = nStartups % (EROS_NODE_SIZE - 1); /* See if we need to append a new node: */ if ( nStartups && ndx == 0 ) { DiskKey newNode = AddNode(); SetNodeSlot(threadChain, EROS_NODE_SIZE - 1, newNode); SetDirEnt("threadlist", newNode); threadChain = newNode; } SetNodeSlot(threadChain, ndx, key); nStartups++; return true;}voidErosImage::AddDirEnt(const InternedString& name, const DiskKey& key){ assert ( (bool) name ); assert (name.str() != 0); uint32_t nameNdx = pool.Add(name); for (uint32_t i = 0; i < nDirEnt; i++) if (dir[i].name == nameNdx) Diag::fatal(5, "Duplicate name \"%s\" added to image file\n", name.str()); if (nDirEnt >= maxDir) GrowDirTable(maxDir + DIR_ALLOC_QUANTA); dir[nDirEnt].key = key; dir[nDirEnt].name = nameNdx; nDirEnt++;}voidErosImage::AssignDirEnt(const InternedString& name, const DiskKey& key){ assert ( (bool) name ); assert (name.str() != 0); uint32_t nameNdx = pool.Add(name); for (uint32_t i = 0; i < nDirEnt; i++) if (dir[i].name == nameNdx) { dir[i].key = key; return; } if (nDirEnt >= maxDir) GrowDirTable(maxDir + DIR_ALLOC_QUANTA); dir[nDirEnt].key = key; dir[nDirEnt].name = nameNdx; nDirEnt++;}boolErosImage::DelDirEnt(const char* name){ InternedString is(name); return DelDirEnt(is);}boolErosImage::DelDirEnt(const InternedString& name){ assert ( (bool) name ); assert (name.str() != 0); uint32_t nameNdx = pool.Add(name); for (uint32_t i = 0; i < nDirEnt; i++) { if (dir[i].name == nameNdx) { for (uint32_t ent = i; ent < (nDirEnt - 1); ent++) dir[ent] = dir[ent+1]; nDirEnt--; return true; } } return false;}boolErosImage::GetDirEnt(const char* name, DiskKey& key){ InternedString is(name); return GetDirEnt(is, key);}boolErosImage::GetDirEnt(const InternedString& name, DiskKey& key){ uint32_t nameNdx = pool.Add(name); for (uint32_t i = 0; i < nDirEnt; i++) { if (dir[i].name == nameNdx) { key = dir[i].key; return true; } } return false;}boolErosImage::GetStartupEnt(const char* name, DiskKey& key){ InternedString is(name); return GetStartupEnt(is, key);}boolErosImage::GetStartupEnt(const InternedString& name, DiskKey& key){ uint32_t nameNdx = pool.Add(name); for (uint32_t i = 0; i < nStartups; i++) { if (startupsDir[i].name == nameNdx) { key = startupsDir[i].key; return true; } } return false;}voidErosImage::SetDirEnt(const InternedString& name, const DiskKey& key){ uint32_t nameNdx = pool.Add(name); for (uint32_t i = 0; i < nDirEnt; i++) { if (dir[i].name == nameNdx) { dir[i].key = key; return; } } Diag::fatal(1, "No directory entry for \"%s\"\n", name.str());}voidErosImage::GrowDirTable(uint32_t newMax){ if (maxDir < newMax) { maxDir = newMax; maxDir += (DIR_ALLOC_QUANTA - 1); maxDir -= (maxDir % DIR_ALLOC_QUANTA); Directory *newDir = new Directory[maxDir]; if (dir) memcpy(newDir, dir, nDirEnt * sizeof(Directory)); delete [] dir; dir = newDir; }}voidErosImage::GrowStartupsTable(uint32_t newMax){ if (maxStartups < newMax) { maxStartups = newMax; maxStartups += (THREAD_ALLOC_QUANTA - 1); maxStartups -= (maxStartups % THREAD_ALLOC_QUANTA); Directory *newThreadDir = new Directory[maxDir]; if (startupsDir) memcpy(newThreadDir, startupsDir, nStartups * sizeof(Directory)); delete [] startupsDir; startupsDir = newThreadDir; }}voidErosImage::GrowNodeTable(uint32_t newMax){ if (maxNode < newMax) { maxNode = newMax; maxNode += (NODE_ALLOC_QUANTA - 1); maxNode -= (maxNode % NODE_ALLOC_QUANTA); DiskNode *newNodeImages = new DiskNode[maxNode]; if (nodeImages) memcpy(newNodeImages, nodeImages, nNodes * sizeof(DiskNode)); delete [] nodeImages; nodeImages = newNodeImages; }}voidErosImage::GrowPageTable(uint32_t newMax){ if (maxPage < newMax) { maxPage = newMax; maxPage += (PAGE_ALLOC_QUANTA - 1); maxPage -= (maxPage % PAGE_ALLOC_QUANTA); uint8_t *newPageImages = new uint8_t[maxPage * EROS_PAGE_SIZE]; if (pageImages) memcpy(newPageImages, pageImages, nPages * EROS_PAGE_SIZE); delete [] pageImages; pageImages = newPageImages; }}DiskKeyErosImage::AddZeroDataPage(bool readOnly){ OID oid(nZeroPages++); DataPageKey key(oid, readOnly); key.SetPrepared(); return key;}DiskKeyErosImage::AddDataPage(const uint8_t *buf, bool readOnly){ if (nPages >= maxPage) GrowPageTable(maxPage + PAGE_ALLOC_QUANTA); memcpy(&pageImages[nPages * EROS_PAGE_SIZE], buf, EROS_PAGE_SIZE); OID oid(nPages++); DataPageKey key(oid, readOnly); return key;}voidErosImage::GetDataPageContent(uint32_t ndx, uint8_t* buf){ if (ndx >= nPages) Diag::fatal(5, "Not that many pages in image file\n"); memcpy(buf, &pageImages[ndx*EROS_PAGE_SIZE], EROS_PAGE_SIZE);}voidErosImage::GetNodeContent(uint32_t ndx, DiskNode& node){ if (ndx >= nNodes) Diag::fatal(5, "Not that many nodes in image file\n"); memcpy(&node, &nodeImages[ndx], sizeof(DiskNode));}DiskKeyErosImage::AddNode(bool readOnly){ if (nNodes >= maxNode) GrowNodeTable(maxNode + NODE_ALLOC_QUANTA); DiskNode& node = nodeImages[nNodes]; OID oid(nNodes++); node.allocCount = 0; node.callCount = 0; node.oid = oid; for (unsigned int i = 0; i < EROS_NODE_SIZE; i++) node[i] = VoidDiskKey(); NodeKey key(oid, readOnly); return key;}#if 0voidErosImage::Import(const ErosImage& image){ /* Step 1: Grow the various tables to hold the new entries: */ GrowDirTable(nDirEnt + image.nDirEnt); GrowStartupsTable(nStartups + image.nStartups); GrowPageTable(nPages + image.nPages); GrowNodeTable(nNodes + image.nNodes-1); /* Step 2: Append the other image's pages and nodes WITHOUT bumping * our counts: */ memcpy(&pageImages[nPages], image.pageImages, image.nPages * EROS_PAGE_SIZE); /* Skip the first node, which is the volsize node: */ memcpy(&nodeImages[nNodes], image.nodeImages + 1, (image.nNodes - 1) * sizeof(DiskNode)); /* Step 3: Relocate the newly added nodes and directory entries: */ for (uint32_t ndx = 0; ndx < image.nNodes; ndx++) { DiskNode& node = nodeImages[ndx + nNodes]; for (uint32_t slot = 0; slot < EROS_NODE_SIZE; slot++) { DiskKey& key = node[slot]; /* If the key's OID needs to be adjusted, do so: */ if (key.IsType(KT_Page) && key.IsPrepared() == false) key.unprep.oid += nPages; else if (key.IsType(KT_Page) && key.IsPrepared()) key.unprep.oid += nZeroPages; else if (key.IsNodeKeyType()) key.unprep.oid += (nNodes - 1); } } /* Step 4: add the foreign directory table entries: */ for (uint32_t ndx = 0; ndx < image.nDirEnt; ndx++) { Directory& dirEnt = image.dir[ndx]; DiskKey key = dirEnt.key; /* Check the string table entry: */ InternedString name = image.GetString(dirEnt.name); InternedString vs("volsize"); if (name == vs) continue; /* If the key's OID needs to be adjusted, do so: */ if (key.IsType(KT_Page) && key.IsPrepared() == false) key.unprep.oid += nPages; else if (key.IsType(KT_Page) && key.IsPrepared()) key.unprep.oid += nZeroPages; else if (key.IsNodeKeyType()) key.unprep.oid += (nNodes - 1); /* Add the resulting entry to our directory using the AddDirEnt
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -