void MemoryServer::reservePrivate(MemoryMessage *msg) { Address *pageDir; /* Verify virtual addresses. */ if (!(msg->virtualAddress >= 1024*1024*16)) { msg->result = EINVAL; return; } /* Point page directory. */ pageDir = (Address *) PAGETABADDR_FROM(PAGETABFROM, PAGEUSERFROM); /* Map page directory. */ VMCtl(msg->from, MapTables); /* Loop directory. Mark them reserved. */ for (Address i = msg->virtualAddress; i < msg->virtualAddress + msg->bytes; i += (PAGESIZE * PAGETAB_MAX)) { pageDir[DIRENTRY(i)] |= PAGE_RESERVED; } /* Unmap. */ VMCtl(msg->from, UnMapTables); /* Done. */ msg->result = ESUCCESS; }
Address MemoryServer::findFreeRange(ProcessID procID, Size size) { Address *pageDir, *pageTab, vaddr, vbegin; /* Initialize variables. */ vbegin = ZERO; vaddr = 1024 * 1024 * 16; pageDir = PAGETABADDR_FROM(PAGETABFROM, PAGEUSERFROM); pageTab = PAGETABADDR_FROM(vaddr, PAGEUSERFROM); /* Map page tables. */ VMCtl(procID, MapTables); /* Scan tables. */ for (Size inc = PAGESIZE; DIRENTRY(vaddr) < PAGEDIR_MAX ; vaddr += inc) { /* Is the hole big enough? */ if (vbegin && vaddr - vbegin >= size) { break; } /* Increment per page table. */ inc = PAGETAB_MAX * PAGESIZE; /* Try the current address. */ if (pageDir[DIRENTRY(vaddr)] & PAGE_RESERVED) { vbegin = ZERO; continue; } else if (pageDir[DIRENTRY(vaddr)] & PAGE_PRESENT) { /* Look further into the page table. */ inc = PAGESIZE; pageTab = PAGETABADDR_FROM(vaddr, PAGEUSERFROM); if (pageTab[TABENTRY(vaddr)] & PAGE_PRESENT) { vbegin = ZERO; continue; } } /* Reset start address if needed. */ if (!vbegin) { vbegin = vaddr; } } /* Clean up. */ VMCtl(procID, UnMapTables); /* Done. */ return vbegin; }
CoreServer::Result CoreServer::clearPages(Address addr, Size size) { Memory::Range range; range.phys = addr; range.virt = ZERO; range.size = size; range.access = Memory::User | Memory::Readable | Memory::Writable; VMCtl(SELF, Map, &range); MemoryBlock::set((void *) range.virt, 0, size); VMCtl(SELF, UnMap, &range); return Success; }
Address VMCtlAllocator::allocate(Size *size) { Address ret = heapStart + allocated; VirtualMemory::Range range; Size bytes; /* Start allocating. */ for (bytes = 0; bytes < *size; bytes += PAGESIZE) { range.virt = ret + bytes; range.phys = ZERO; range.size = PAGESIZE; range.access = VirtualMemory::Present | VirtualMemory::User | VirtualMemory::Readable | VirtualMemory::Writable; VMCtl(SELF, Map, &range); } /* Update count. */ allocated += bytes; /* Success. */ *size = bytes; return ret; }
Error VGA::initialize() { Memory::Range range; // Request VGA memory range.size = PAGESIZE; range.access = Memory::User | Memory::Readable | Memory::Writable; range.virt = ZERO; range.phys = VGA_PADDR; VMCtl(SELF, Map, &range); // Point to the VGA mapping vga = (u16 *) range.virt; // Clear screen for (uint i = 0; i < width * height; i++) { vga[i] = VGA_CHAR(' ', LIGHTGREY, BLACK); } // Disable hardware cursor WriteByte(VGA_IOADDR, 0x0a); WriteByte(VGA_IODATA, 1 << 5); // Successfull return ESUCCESS; }
Address VMCtlAllocator::allocate(Size *size) { Address ret = heapStart + allocated; MemoryRange range; Size bytes; /* Start allocating. */ for (bytes = 0; bytes < *size; bytes += PAGESIZE) { range.virtualAddress = ret + bytes; range.physicalAddress = ZERO; range.bytes = PAGESIZE; VMCtl(SELF, Map, &range); } /* Update end-of-heap pointer. */ heapEnd = ret + bytes; /* Update count. */ allocated += bytes; /* Success. */ *size = bytes; return ret; }
Allocator::Result PageAllocator::allocate(Size *size, Address *addr, Size align) { Memory::Range range; // Set return address *addr = m_base + m_allocated; // TODO: sanity checks Size bytes = *size > PAGEALLOC_MINIMUM ? *size : PAGEALLOC_MINIMUM; // Align to pagesize bytes = aligned(bytes, PAGESIZE); // Fill in the message. */ range.size = bytes; range.access = Memory::User | Memory::Readable | Memory::Writable; range.virt = m_base + m_allocated; range.phys = ZERO; // TODO: #warning do we need to pass the region here too? //range.region = Memory::UserPrivate; VMCtl(SELF, Map, &range); // Clear the pages MemoryBlock::set((void *) range.virt, 0, range.size); // Update count m_allocated += range.size; // Success *size = range.size; return Success; }
void SMSC95xxUSB::writeStart() { DEBUG(""); if (m_txPacket) { ERROR("transmit already in progress"); return; } m_txPacket = m_smsc->getTransmitQueue()->pop(); if (!m_txPacket) { DEBUG("no transmit data packet available"); return; } // Flush L1 cache VMCtl(SELF, CacheClean, 0); // Start bulk transfer Error err = beginTransfer( USBTransfer::Bulk, USBTransfer::Out, m_endpoints[1].endpointAddress & 0xf, m_txPacket->data, m_txPacket->size, m_endpoints[1].maxPacketSize, m_writeFinished ); }
IO::Result IO::map(Address phys, Size size, Memory::Access access) { m_range.virt = 0; m_range.phys = phys; m_range.access = access; m_range.size = size; if (!isKernel) { if (VMCtl(SELF, Map, &m_range) != API::Success) return MapFailure; } else { m_range.access &= ~Memory::User; MemoryContext *ctx = MemoryContext::getCurrent(); if (!ctx) return MapFailure; if (ctx->findFree(size, MemoryMap::KernelPrivate, &m_range.virt) != MemoryContext::Success) return OutOfMemory; if (ctx->map(m_range.virt, phys, m_range.access) != MemoryContext::Success) return MapFailure; } m_base = m_range.virt; return Success; }
int main(int argc, char **argv) { u64 t1 = 0, t2 = 0; ProcessID pid = 0; ProcessInfo info; MemoryRange range; char *foo[128]; t1 = timestamp(); pid = ProcessCtl(SELF, GetPID); t2 = timestamp(); printf("SystemCall (GetPID) Ticks: %u\r\n", t2 - t1); t1 = timestamp(); ProcessCtl(SELF, InfoPID, (Address) &info); t2 = timestamp(); printf("SystemCall (InfoPID) Ticks: %u\r\n", t2 - t1); t1 = timestamp(); ProcessCtl(SELF, Schedule); t2 = timestamp(); printf("SystemCall (Schedule) Ticks: %u\r\n", t2 - t1); range.virtualAddress = 0x80000000; range.bytes = PAGESIZE; t1 = timestamp(); VMCtl(SELF, LookupVirtual, &range); t2 = timestamp(); printf("SystemCall (VMCtl) Ticks: %u\r\n", t2 - t1); t1 = timestamp(); getpid(); t2 = timestamp(); printf("IPC Ticks: %u\r\n", t2 - t1); t1 = timestamp(); for (int i = 0; i < 128; i++) foo[i] = new char[16]; t2 = timestamp(); printf("allocate() Ticks: %u (%u AVG)\r\n", (u32)(t2 - t1), (u32)(t2 - t1) / 128); t1 = timestamp(); for (int i = 0; i < 128; i++) delete foo[i]; t2 = timestamp(); printf("release() Ticks: %u (%u AVG)\r\n", (u32)(t2 - t1), (u32)(t2 - t1) / 128); /* Done. */ return EXIT_SUCCESS; }
SharedMemory * MemoryServer::insertShared(ProcessID procID, char *key, Size size, MemoryRange *range, bool *created) { SharedMemory *obj = findShared(key); bool needCreate = obj == ZERO; if (needCreate) obj = new SharedMemory; range->virtualAddress = findFreeRange(procID, size); range->bytes = size; range->access = Memory::Present | Memory::User | Memory::Readable | Memory::Writable | Memory::Pinned; /* Only create a new mapping, if non-existent. */ if (needCreate) { range->physicalAddress = ZERO; VMCtl(procID, Map, range); /* Create new shared memory object. */ obj->size = size; obj->key = key; obj->address = range->physicalAddress; /* Insert to the list. */ shared.append(obj); /* We created a new mapping, flag that. */ if (created) *created = true; } else { range->physicalAddress = obj->address; VMCtl(procID, Map, range); /* We didn't create a new mapping, flag that. */ if (created) *created = false; } /* Done. */ return obj; }
int __assertWrite(Address addr) { MemoryRange range; range.virtualAddress = addr; range.physicalAddress = ZERO; range.bytes = sizeof(Address); range.protection = PAGE_PRESENT | PAGE_USER | PAGE_RW; return VMCtl(SELF, Access, &range); }
Error MemoryServer::insertMapping(ProcessID procID, MemoryRange *range) { MemoryRange tmp; Error result; tmp.virtualAddress = range->virtualAddress; tmp.access = Memory::Present; tmp.bytes = range->bytes; /* The given range must be free. */ if (VMCtl(procID, Access, &tmp)) { return EFAULT; } /* Perform mapping. */ if ((result = VMCtl(procID, Map, range)) != 0) { return result; } /* Done! */ return ESUCCESS; }
SharedMemory * MemoryServer::insertShared(ProcessID procID, char *key, Size size, MemoryRange *range, bool *created) { SharedMemory *obj; range->virtualAddress = findFreeRange(procID, size); range->bytes = size; range->protection = PAGE_PRESENT | PAGE_USER | PAGE_RW | PAGE_PINNED; /* Only create a new mapping, if non-existent. */ if (!(obj = findShared(key))) { range->physicalAddress = ZERO; VMCtl(procID, Map, range); /* Create new shared memory object. */ obj = new SharedMemory; obj->size = size; obj->key = new String(key); obj->address = range->physicalAddress; /* Insert to the list. */ shared.insertTail(obj); /* We created a new mapping, flag that. */ if (created) *created = true; } else { range->physicalAddress = obj->address; VMCtl(procID, Map, range); /* We didn't create a new mapping, flag that. */ if (created) *created = false; } /* Done. */ return obj; }
IO::Result IO::unmap() { if (!isKernel) { if (VMCtl(SELF, UnMap, &m_range) != API::Success) return MapFailure; } else { MemoryContext *ctx = MemoryContext::getCurrent(); if (!ctx) return MapFailure; if (ctx->unmapRange(&m_range) != MemoryContext::Success) return MapFailure; } return Success; }
void CoreServer::createPrivate(CoreMessage *msg) { Memory::Range range; // Set mapping flags // TODO: only allow pinned pages for uid == 0! range.virt = msg->virt & PAGEMASK; range.phys = msg->phys; range.size = msg->size; range.access = msg->access; // Try to map the range VMCtl(msg->from, Map, &range); msg->virt = range.virt; msg->phys = range.phys; msg->result = ESUCCESS; }
int MPI_Init(int *argc, char ***argv) { SystemInformation info; FileSystemMessage msg; struct stat st; char *programName = (*argv)[0]; char programPath[64]; u8 *programBuffer; int fd; Memory::Range memChannelBase; // If we are master (node 0): if (info.coreId == 0) { msg.type = ChannelMessage::Request; msg.action = ReadFile; msg.from = SELF; ChannelClient::instance->syncSendReceive(&msg, CORESRV_PID); // provide -n COUNT, --help and other stuff in here too. // to influence the launching of more MPI programs coreCount = msg.size; // Read our own ELF program to a buffer and pass it to CoreServer // for creating new programs on the remote core. if (strncmp(programName, "/bin/", 5) != 0) snprintf(programPath, sizeof(programPath), "/bin/%s", programName); else strlcpy(programPath, programName, sizeof(programPath)); if (stat(programPath, &st) != 0) { printf("%s: failed to stat '%s': %s\n", programName, programPath, strerror(errno)); return MPI_ERR_BAD_FILE; } programBuffer = new u8[st.st_size]; MemoryBlock::set(programBuffer, 0, st.st_size); // Read ELF program if ((fd = open(programPath, O_RDONLY)) == -1) { printf("%s: failed to open '%s': %s\n", programName, programPath, strerror(errno)); return MPI_ERR_BAD_FILE; } if (read(fd, programBuffer, st.st_size) != st.st_size) { printf("%s: failed to read '%s': %s\n", programName, programPath, strerror(errno)); return MPI_ERR_BAD_FILE; } if (close(fd) != 0) { printf("%s: failed to close '%s': %s\n", programName, programPath, strerror(errno)); return MPI_ERR_BAD_FILE; } // Allocate memory space on the local processor for the whole // UniChannel array, NxN communication with MPI. // Then pass the channel offset physical address as an argument -addr 0x.... to spawn() memChannelBase.size = (PAGESIZE * 2) * (msg.size * msg.size); memChannelBase.phys = 0; memChannelBase.virt = 0; memChannelBase.access = Memory::Readable | Memory::Writable | Memory::User; if (VMCtl(SELF, Map, &memChannelBase) != API::Success) { printf("%s: failed to allocate MemoryChannel\n", programName); return MPI_ERR_NO_MEM; } printf("%s: MemoryChannel at physical address %x\n", programName, memChannelBase.phys); // Clear channel pages MemoryBlock::set((void *) memChannelBase.virt, 0, memChannelBase.size); // now create the slaves using coreservers. for (Size i = 1; i < coreCount; i++) { // TODO: check for cmd buffer size... char *cmd = new char[512]; snprintf(cmd, 512, "%s -a %x -c %d", programPath, memChannelBase.phys, coreCount); for (int j = 1; j < *argc; j++) { strcat(cmd, " "); strcat(cmd, (*argv)[j]); } msg.type = ChannelMessage::Request; msg.action = CreateFile; msg.size = i; msg.buffer = (char *) programBuffer; msg.offset = st.st_size; msg.path = cmd; ChannelClient::instance->syncSendReceive(&msg, CORESRV_PID); if (msg.result != ESUCCESS) { printf("%s: failed to create process on core%d\n", programName, i); return MPI_ERR_SPAWN; } } } else { // If we are slave (node N): // read the -addr argument, and map the UniChannels into our address space. for (int i = 1; i < (*argc); i++) { if (!strcmp((*argv)[i], "--addr") || !strcmp((*argv)[i], "-a")) { if ((*argc) < i+1) return MPI_ERR_ARG; String s = (*argv)[i+1]; memChannelBase.phys = s.toLong(Number::Hex); i++; } else if (!strcmp((*argv)[i], "--cores") || !strcmp((*argv)[i], "-c")) { if ((*argc) < i+1) return MPI_ERR_ARG; coreCount = atoi((*argv)[i+1]); i++; } // Unknown MPI argument. Pass the rest to the user program. else { (*argc) -= (i-1); (*argv)[i-1] = (*argv)[0]; (*argv) += (i-1); break; } } } // Create MemoryChannels readChannel = new Index<MemoryChannel>(coreCount); writeChannel = new Index<MemoryChannel>(coreCount); // Fill read channels for (Size i = 0; i < coreCount; i++) { MemoryChannel *ch = new MemoryChannel(); ch->setMode(MemoryChannel::Consumer); ch->setMessageSize(sizeof(MPIMessage)); ch->setPhysical(MEMBASE(info.coreId) + (PAGESIZE * 2 * i), MEMBASE(info.coreId) + (PAGESIZE * 2 * i) + PAGESIZE); readChannel->insert(i, *ch); if (info.coreId == 0) printf("%s: read: core%d: data=%x feedback=%x base%d=%x\n", (*argv)[0], i, MEMBASE(info.coreId) + (PAGESIZE * 2 * i), MEMBASE(info.coreId) + (PAGESIZE * 2 * i) + PAGESIZE, i, MEMBASE(i)); } // Fill write channels for (Size i = 0; i < coreCount; i++) { MemoryChannel *ch = new MemoryChannel(); ch->setMode(MemoryChannel::Producer); ch->setMessageSize(sizeof(MPIMessage)); ch->setPhysical(MEMBASE(i) + (PAGESIZE * 2 * info.coreId), MEMBASE(i) + (PAGESIZE * 2 * info.coreId) + PAGESIZE); writeChannel->insert(i, *ch); if (info.coreId == 0) printf("%s: write: core%d: data=%x feedback=%x base%d=%x\n", (*argv)[0], i, MEMBASE(i) + (PAGESIZE * 2 * info.coreId), MEMBASE(i) + (PAGESIZE * 2 * info.coreId) + PAGESIZE, i, MEMBASE(i)); } return MPI_SUCCESS; }
CoreServer::Result CoreServer::bootCore(uint coreId, CoreInfo *info, ExecutableFormat::Region *regions) { SystemInformation sysInfo; DEBUG("Reserving: " << (void *)info->memory.phys << " size=" << info->memory.size << " available=" << sysInfo.memoryAvail); // Claim the core's memory if (VMCtl(SELF, RemoveMem, &info->memory) != API::Success) { ERROR("failed to reserve memory for core" << coreId << " at " << (void *)info->memory.phys); return OutOfMemory; } DEBUG("Starting core" << coreId << " with " << info->memory.size / 1024 / 1024 << "MB"); // Map the kernel for (int i = 0; i < m_numRegions; i++) { Memory::Range range; range.phys = info->memory.phys + regions[i].virt; range.virt = 0; range.size = regions[i].size; range.access = Memory::Readable | Memory::Writable | Memory::User; // Map the target kernel's memory for regions[i].size if (VMCtl(SELF, Map, &range) != 0) { // TODO: convert from API::Error to errno. //errno = EFAULT; return OutOfMemory; } // Copy the kernel to the target core's memory #warning VMCopy should just return API::Result, not a Size Error r = VMCopy(SELF, API::Write, (Address) regions[i].data, range.virt, regions[i].size); if (r != regions[i].size) return MemoryError; // Unmap the target kernel's memory if (VMCtl(SELF, Release, &range) != API::Success) { return MemoryError; } DEBUG(kernelPath << "[" << i << "] = " << (void *) m_regions[i].virt); } // Copy the BootImage after the kernel. Memory::Range range; range.phys = info->bootImageAddress; range.virt = 0; range.size = info->bootImageSize; range.access = Memory::Readable | Memory::Writable | Memory::User; // Map BootImage buffer if (VMCtl(SELF, Map, &range) != API::Success) { return OutOfMemory; } // Copy the BootImage Error r = VMCopy(SELF, API::Write, sysInfo.bootImageAddress, range.virt, sysInfo.bootImageSize); if (r != (Error) sysInfo.bootImageSize) return MemoryError; // Unmap the BootImage if (VMCtl(SELF, Release, &range) != API::Success) return MemoryError; #ifdef INTEL // Signal the core to boot if (m_mp.boot(info) != IntelMP::Success) { ERROR("failed to boot core" << coreId); return BootError; } else { NOTICE("core" << coreId << " started"); } #endif return Success; }
void ProcessServer::spawnProcessHandler(ProcessMessage *msg) { char path[PATHLEN], *tmp; FileSystemMessage fs; ExecutableFormat *fmt; MemoryRegion regions[16]; MemoryRange range; Error numRegions, ret; Size size; ProcessID pid; Shared<FileDescriptor> *parentFd, *childFd; /* Read out the path to the executable. */ if ((msg->result = VMCopy(msg->from, Read, (Address) path, (Address) msg->path, PATHLEN) < 0)) { return; } /* Attempt to read executable format. */ if (!(fmt = ExecutableFormat::find(path))) { msg->result = errno; return; } /* Retrieve memory regions. */ if ((numRegions = fmt->regions(regions, 16)) < 0) { msg->result = errno; return; } /* Create new process. */ pid = ProcessCtl(ANY, Spawn, fmt->entry()); /* Map program regions into virtual memory of the new process. */ for (int i = 0; i < numRegions; i++) { /* Copy executable memory from this region. */ for (Size j = 0; j < regions[i].size; j += PAGESIZE) { range.virtualAddress = regions[i].virtualAddress + j; range.physicalAddress = ZERO; range.bytes = PAGESIZE; /* Create mapping first. */ if ((ret = VMCtl(pid, Map, &range)) != 0) { msg->result = ret; return; } /* Copy bytes. */ VMCopy(pid, Write, (Address) (regions[i].data) + j, regions[i].virtualAddress + j, PAGESIZE); } } /* Create mapping for command-line arguments. */ range.virtualAddress = ARGV_ADDR; range.physicalAddress = ZERO; range.bytes = PAGESIZE; VMCtl(pid, Map, &range); /* Allocate temporary variable. */ tmp = new char[PAGESIZE]; memset(tmp, 0, PAGESIZE); /* Calculate number of bytes to copy. */ size = msg->number * ARGV_SIZE < PAGESIZE ? msg->number * ARGV_SIZE : PAGESIZE; /* Copy arguments into the temporary variable. */ if ((msg->result = VMCopy(msg->from, Read, (Address) tmp, (Address) msg->arguments, size)) < 0) { delete tmp; return; } /* Copy argc/argv into the new process. */ if ((msg->result = VMCopy(pid, Write, (Address) tmp, (Address) ARGV_ADDR, PAGESIZE)) < 0) { delete tmp; return; } /* Set command-line string. */ snprintf(procs[pid]->command, COMMANDLEN, "%s", path); /* Copy the FileDescriptor table. */ parentFd = getFileDescriptors(files, msg->from); childFd = getFileDescriptors(files, pid); memcpy(**childFd, **parentFd, childFd->size()); /* Inherit user and group identities. */ procs[pid]->userID = procs[msg->from]->userID; procs[pid]->groupID = procs[msg->from]->groupID; strncpy(procs[pid]->currentDirectory, procs[msg->from]->currentDirectory, PATHLEN); /* Begin execution. */ ProcessCtl(pid, Resume); /* Success. */ msg->number = pid; msg->result = ESUCCESS; /* Cleanup. */ delete fmt; delete tmp; }
CoreServer::CoreServer() : IPCServer<CoreServer, CoreMessage>(this) { SystemInformation info; Memory::Range range; BootImage *image; BootSymbol *symbol; /* Register message handlers. */ addIPCHandler(CreatePrivate, &CoreServer::createPrivate); addIPCHandler(ReleasePrivate, &CoreServer::releasePrivate); addIPCHandler(ReadProcess, &CoreServer::readProcessHandler); addIPCHandler(GetMounts, &CoreServer::getMountsHandler); addIPCHandler(SetMount, &CoreServer::setMountHandler); addIPCHandler(ExitProcess, &CoreServer::exitProcessHandler, false); addIPCHandler(SpawnProcess, &CoreServer::spawnProcessHandler); addIPCHandler(WaitProcess, &CoreServer::waitProcessHandler, false); /* Allocate a user process table. */ procs = new UserProcess[MAX_PROCS]; memset(procs, 0, sizeof(UserProcess) * MAX_PROCS); /* Allocate FileSystemMounts table. */ mounts = new FileSystemMount[FILESYSTEM_MAXMOUNTS]; memset(mounts, 0, sizeof(FileSystemMount) * FILESYSTEM_MAXMOUNTS); /* We only guarantee that / and /dev, /proc are mounted. */ strlcpy(mounts[0].path, "/dev", PATHLEN); strlcpy(mounts[1].path, "/", PATHLEN); strlcpy(mounts[2].path, "/proc", PATHLEN); mounts[0].procID = DEVSRV_PID; mounts[0].options = ZERO; mounts[1].procID = ROOTSRV_PID; mounts[1].options = ZERO; mounts[2].procID = 13; mounts[2].options = ZERO; // Attempt to load the boot image range.virt = ZERO; range.phys = info.bootImageAddress; range.access = Arch::Memory::Present | Arch::Memory::User | Arch::Memory::Readable; range.size = info.bootImageSize; VMCtl(SELF, Map, &range); image = (BootImage *) range.virt; /* Loop all embedded programs. */ for (Size j = 0; j < image->symbolTableCount; j++) { /* Read out the next program. */ symbol = (BootSymbol *)(((Address)image) + image->symbolTableOffset); symbol += j; if (symbol->type != BootProgram) continue; /* Write commandline. */ snprintf(procs[j].command, COMMANDLEN, "[%s]", symbol->name); /* Set user and group identities. */ procs[j].userID = 0; procs[j].groupID = 0; } }
void CoreServer::createProcess(FileSystemMessage *msg) { char cmd[128]; Memory::Range range; if (m_info.coreId == 0) { MemoryChannel *ch = (MemoryChannel *) m_toSlave->get(msg->size); if (!ch) { ERROR("invalid coreId=" << msg->size); msg->result = EBADF; return; } // TODO:move in libmpi? range.virt = (Address) msg->buffer; VMCtl(msg->from, LookupVirtual, &range); msg->buffer = (char *) range.phys; range.virt = (Address) msg->path; VMCtl(msg->from, LookupVirtual, &range); msg->path = (char *) range.phys; if (ch->write(msg) != Channel::Success) { ERROR("failed to write channel on core"<<msg->size); msg->result = EBADF; return; } DEBUG("creating program at phys " << (void *) msg->buffer << " on core" << msg->size); ch = (MemoryChannel *) m_fromSlave->get(msg->size); if (!ch) { ERROR("cannot find read channel for core" << msg->size); msg->result = EBADF; return; } // TODO: replace with ChannelClient::syncReceiveFrom while (ch->read(msg) != Channel::Success); DEBUG("program created with result " << (int)msg->result << " at core" << msg->size); msg->result = ESUCCESS; //IPCMessage(msg->from, API::Send, msg, sizeof(*msg)); ChannelClient::instance->syncSendTo(msg, msg->from); } else { VMCopy(SELF, API::ReadPhys, (Address) cmd, (Address) msg->path, sizeof(cmd)); range.phys = (Address) msg->buffer; range.virt = 0; range.access = Memory::Readable | Memory::User; range.size = msg->offset; VMCtl(SELF, Map, &range); pid_t pid = spawn(range.virt, msg->offset, cmd); int status; // reply to master msg->result = ESUCCESS; while (m_toMaster->write(msg) != Channel::Success); // TODO: temporary make coreserver waitpid() to save polling time waitpid(pid, &status, 0); } }
int forkexec(const char *path, const char *argv[]) { CoreMessage msg; ExecutableFormat *fmt; MemoryRegion regions[16]; Memory::Range range; uint count = 0; pid_t pid = 0; int numRegions = 0; Vector<FileDescriptor> *fds = getFiles(); // Attempt to read executable format if (!(fmt = ExecutableFormat::find(path))) return -1; // Retrieve memory regions if ((numRegions = fmt->regions(regions, 16)) < 0) return -1; // Create new process pid = ProcessCtl(ANY, Spawn, fmt->entry()); // TODO: check the result of ProcessCtl() // TODO: make this much more efficient. perhaps let libexec write directly to the target buffer. // at least Map & copy in one shot. // TODO: move the memory administration updates to coreserver instead. // this process can read the libexec data once, and then let coreserver create a process for it. // Map program regions into virtual memory of the new process for (int i = 0; i < numRegions; i++) { // Copy executable memory from this region range.virt = regions[i].virtualAddress; range.phys = ZERO; range.size = regions[i].size; range.access = Memory::Present | Memory::User | Memory::Readable | Memory::Writable | Memory::Executable; // Create mapping first if (VMCtl(pid, Map, &range) != 0) { // TODO: convert from API::Error to errno. errno = EFAULT; return -1; } // Copy bytes VMCopy(pid, API::Write, (Address) regions[i].data, regions[i].virtualAddress, regions[i].size); } /* Create mapping for command-line arguments. */ range.virt = ARGV_ADDR; range.phys = ZERO; range.size = PAGESIZE; VMCtl(pid, Map, &range); // Allocate arguments char *arguments = new char[PAGESIZE]; memset(arguments, 0, PAGESIZE); // Fill in arguments while (argv[count] && count < PAGESIZE / ARGV_SIZE) { strlcpy(arguments + (ARGV_SIZE * count), argv[count], ARGV_SIZE); count++; } // Copy argc/argv into the new process if ((VMCopy(pid, API::Write, (Address) arguments, (Address) ARGV_ADDR, PAGESIZE)) < 0) { delete arguments; errno = EFAULT; return -1; } // Let the Child begin execution ProcessCtl(pid, Resume); // Send a pointer to our list of file descriptors to the child // TODO: ofcourse, insecure. To be fixed later. msg.type = IPCType; msg.from = SELF; msg.path = (char *) fds->vector(); IPCMessage(pid, API::SendReceive, &msg, sizeof(msg)); // Done. Cleanup. delete arguments; return pid; }
MemoryServer::MemoryServer() : IPCServer<MemoryServer, MemoryMessage>(this) { SystemInformation info; MemoryRange range; BootImage *image; BootProgram *program; /* Register message handlers. */ addIPCHandler(CreatePrivate, &MemoryServer::createPrivate); addIPCHandler(ReservePrivate, &MemoryServer::reservePrivate); addIPCHandler(ReleasePrivate, &MemoryServer::releasePrivate); addIPCHandler(CreateShared, &MemoryServer::createShared); addIPCHandler(SystemMemory, &MemoryServer::systemMemory); /* Allocate a user process table. */ insertShared(SELF, USER_PROCESS_KEY, sizeof(UserProcess) * MAX_PROCS, &range); /* Clear it. */ procs = (UserProcess *) range.virtualAddress; memset(procs, 0, sizeof(UserProcess) * MAX_PROCS); /* Allocate FileSystemMounts table. */ insertShared(SELF, FILE_SYSTEM_MOUNT_KEY, sizeof(FileSystemMount) * MAX_MOUNTS, &range); /* Also Clear it. */ mounts = (FileSystemMount *) range.virtualAddress; memset(mounts, 0, sizeof(FileSystemMount) * MAX_MOUNTS); /* We only guarantee that / and /dev are mounted. */ strlcpy(mounts[0].path, "/dev", PATHLEN); strlcpy(mounts[1].path, "/", PATHLEN); mounts[0].procID = DEVSRV_PID; mounts[0].options = ZERO; mounts[1].procID = ROOTSRV_PID; mounts[1].options = ZERO; /* Attempt to load the boot image. */ for (Size i = 0; i < info.moduleCount; i++) { if (strcmp(info.modules[i].string, "/boot/boot.img.gz") == 0) { range.virtualAddress = findFreeRange(SELF, PAGESIZE * 2); range.physicalAddress = info.modules[i].modStart; range.access = Memory::Present | Memory::User | Memory::Readable; #warning Dangerous value for bytes here? range.bytes = PAGESIZE * 2; VMCtl(SELF, Map, &range); image = (BootImage *) range.virtualAddress; break; } } /* Loop all embedded programs. */ for (Size j = 0; j < image->programsTableCount; j++) { /* Read out the next program. */ program = (BootProgram *)(((Address)image) + image->programsTableOffset); program += j; /* Write commandline. */ snprintf(procs[j].command, COMMANDLEN, "[%s]", program->path); /* Set current directory. */ snprintf(procs[j].currentDirectory, PATHLEN, "/"); /* Set user and group identities. */ procs[j].userID = 0; procs[j].groupID = 0; } }