Error SynopsisUSB::transfer(const FileSystemMessage *msg, USBMessage *usb) { DEBUG(""); switch (usb->state) { case USBMessage::Setup: startTransfer(0, msg, usb); break; case USBMessage::Data: break; case USBMessage::Status: break; default: break; } usb->state = USBMessage::Success; USBDescriptor::Device desc; desc.vendorId = 111; desc.productId = 222; VMCopy(msg->from, API::Write, (Address) &desc, usb->buffer, usb->size); return ESUCCESS; }
int main(int argc, char **argv) { ProcessInfo info; // TODO: ask the kernel for the whole process table in one shot. // Print header printf("ID PARENT USER GROUP STATUS CMD\r\n"); memset(&cmd, 0, sizeof(cmd)); // Loop processes for (uint i = 0; i < MAX_PROCS; i++) { // Request kernel's process information if (ProcessCtl(i, InfoPID, (Address) &info) != API::NotFound) { // Get the command VMCopy(i, API::Read, (Address) cmd, ARGV_ADDR, PAGESIZE); // Output a line printf("%3d %7d %4d %5d %10s %32s\r\n", i, info.parent, 0, 0, states[info.state], cmd); } } return EXIT_SUCCESS; }
void CoreServer::getMountsHandler(CoreMessage *msg) { // TODO: memory access checks /* Copy FileSystemMount table buffer. */ VMCopy(msg->from, API::Write, (Address) mounts, (Address) (msg->mounts), sizeof(FileSystemMount) * FILESYSTEM_MAXMOUNTS); msg->result = ESUCCESS; }
void setupMappings() { // The CoreServer does not need to setup mappings if (getpid() == CORESRV_PID) return; // Fill the mounts table memset(mounts, 0, sizeof(FileSystemMount) * FILESYSTEM_MAXMOUNTS); 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; // Set currentDirectory currentDirectory = "/"; // Load FileDescriptors. for (Size i = 0; i < FILE_DESCRIPTOR_MAX; i++) { FileDescriptor fd; fd.open = false; files.insert(fd); } #warning Solve this, by passing the file descriptor, procinfo, etc as a parameter to entry(), constructed by the kernel #warning If there was a parent, it would have passed the file descriptor table, argc/argv, memorymap, etc as an argument to ProcessCtl() // TODO: perhaps we can "bundle" the GetMounts() and ReadProcess() calls, so that // we do not need to send IPC message twice in this part (for mounts and getppid()) // TODO: this is inefficient. It should take only one IPC request to retrieve these things from our parent. Or better, avoid it. // Get our parent ID ProcessID ppid = getppid(); // Skip processes with no parent (e.g. from the BootImage) if (!ppid) return; // Inherit file descriptors, current directory, and more. CoreMessage msg; msg.type = IPCType; msg.from = SELF; // NOTE: we "abuse" the CoreMessage for ipc with our parent... IPCMessage(ppid, API::Receive, &msg, sizeof(msg)); // Copy the file descriptors VMCopy(ppid, API::Read, (Address) files.vector(), (Address) msg.path, files.size() * sizeof(FileDescriptor)); // Dummy reply, to tell our parent we received the fds.... very inefficient. IPCMessage(ppid, API::Send, &msg, sizeof(msg)); }
void ProcessServer::setCurrentDirectory(ProcessMessage *msg) { /* Handle request. */ msg->result = VMCopy(msg->from, Read, (Address) procs[msg->from]->currentDirectory, (Address) msg->path, PATHLEN); /* Mark with ESUCCESS? */ if (msg->result > 0) msg->result = ESUCCESS; }
void setupMappings() { // The CoreServer does not need to setup mappings if (getpid() == CORESRV_PID) return; // Ask CoreServer for FileSystemMounts table CoreMessage msg; msg.action = GetMounts; msg.mounts = mounts; msg.type = IPCType; msg.from = SELF; IPCMessage(CORESRV_PID, API::SendReceive, &msg, sizeof(msg)); // Set currentDirectory currentDirectory = "/"; // Load FileDescriptors. for (Size i = 0; i < FILE_DESCRIPTOR_MAX; i++) { FileDescriptor fd; fd.open = false; files.insert(fd); } // TODO: perhaps we can "bundle" the GetMounts() and ReadProcess() calls, so that // we do not need to send IPC message twice in this part (for mounts and getppid()) // TODO: this is inefficient. It should take only one IPC request to retrieve these things from our parent. Or better, avoid it. // Get our parent ID ProcessID ppid = getppid(); // Skip processes with no parent (e.g. from the BootImage) if (!ppid) return; // Inherit file descriptors, current directory, and more. // NOTE: we "abuse" the CoreMessage for ipc with our parent... IPCMessage(ppid, API::Receive, &msg, sizeof(msg)); // Copy the file descriptors VMCopy(ppid, API::Read, (Address) files.vector(), (Address) msg.path, files.size() * sizeof(FileDescriptor)); // Dummy reply, to tell our parent we received the fds.... very inefficient. IPCMessage(ppid, API::Send, &msg, sizeof(msg)); }
IntelMP::Result IntelMP::boot(uint cpuId, const char *kernelPath) { NOTICE("booting core#" << cpuId << " with kernel: " << kernelPath); // TODO: load the kernel, reserve memory, etc // TODO: upper layer should have loaded the kernel in memory already. // Copy 16-bit realmode startup code // TODO: place this in the kernel somewhere instead? VMCopy(SELF, API::Write, (Address) bootEntry16, 0xf000, PAGESIZE); // Send inter-processor-interrupt to wakeup the processor if (m_apic.sendStartupIPI(cpuId, 0xf000) == IntelAPIC::Success) return Success; else return IOError; }
static void VMChunkFinish(Chunk chunk) { VMStruct vmStruct; VM vm = &vmStruct; VMChunk vmChunk = Chunk2VMChunk(chunk); /* Copy VM descriptor to stack-local storage so that we can continue * using the descriptor after the VM has been unmapped. */ VMCopy(vm, VMChunkVM(vmChunk)); vmArenaUnmap(VMChunkVMArena(vmChunk), vm, VMBase(vm), vmChunk->overheadMappedLimit); /* No point in finishing the other fields, since they are unmapped. */ VMFinish(vm); }
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; }
Error FileSystem::processRequest(FileSystemRequest *req) { char buf[PATHLEN]; FileSystemPath path; FileCache *cache = ZERO; File *file = ZERO; Directory *parent; FileSystemMessage *msg = req->getMessage(); // Copy the file path if ((msg->result = VMCopy(msg->from, API::Read, (Address) buf, (Address) msg->path, PATHLEN)) <= 0) { msg->result = EACCES; msg->type = IPCType; IPCMessage(msg->from, API::Send, msg, sizeof(*msg)); return msg->result; } path.parse(buf + strlen(m_mountPath)); // Do we have this file cached? if ((cache = findFileCache(&path)) || (cache = lookupFile(&path))) { file = cache->file; } // File not found else if (msg->action != CreateFile) { msg->result = ENOENT; msg->type = IPCType; IPCMessage(msg->from, API::Send, msg, sizeof(*msg)); return msg->result; } // Perform I/O on the file switch (msg->action) { case CreateFile: if (cache) msg->result = EEXIST; else { /* Attempt to create the new file. */ if ((file = createFile(msg->filetype, msg->deviceID))) { const char *p = **path.full(); insertFileCache(file, "%s", p); /* Add directory entry to our parent. */ if (path.parent()) { parent = (Directory *) findFileCache(**path.parent())->file; } else parent = (Directory *) m_root->file; parent->insert(file->getType(), **path.full()); msg->result = ESUCCESS; } else msg->result = EIO; } break; case DeleteFile: if (cache->entries.count() == 0) { clearFileCache(cache); msg->result = ESUCCESS; } else msg->result = ENOTEMPTY; break; case StatFile: msg->result = file->status(msg); break; case ReadFile: { msg->result = file->read(req->getBuffer(), msg->size, msg->offset); if (req->getBuffer().getCount()) req->getBuffer().flush(); } break; case WriteFile: { if (!req->getBuffer().getCount()) req->getBuffer().bufferedRead(); msg->result = file->write(req->getBuffer(), msg->size, msg->offset); } break; } // Only send reply if completed (not EAGAIN) if (msg->result != EAGAIN) { msg->type = IPCType; IPCMessage(msg->from, API::Send, msg, sizeof(*msg)); } return msg->result; }
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); } }
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; }
Error IOBuffer::write(void *buffer, Size size, Size offset) const { return VMCopy(m_message->from, API::Write, (Address) buffer, (Address) m_message->buffer + offset, size); }
/* VMChunkCreate -- create a chunk * * chunkReturn, return parameter for the created chunk. * vmArena, the parent VMArena. * size, approximate amount of virtual address that the chunk should reserve. */ static Res VMChunkCreate(Chunk *chunkReturn, VMArena vmArena, Size size) { Arena arena; Res res; Addr base, limit, chunkStructLimit; VMStruct vmStruct; VM vm = &vmStruct; BootBlockStruct bootStruct; BootBlock boot = &bootStruct; VMChunk vmChunk; void *p; AVER(chunkReturn != NULL); AVERT(VMArena, vmArena); arena = VMArena2Arena(vmArena); AVER(size > 0); res = VMInit(vm, size, ArenaGrainSize(arena), vmArena->vmParams); if (res != ResOK) goto failVMInit; base = VMBase(vm); limit = VMLimit(vm); res = BootBlockInit(boot, (void *)base, (void *)limit); if (res != ResOK) goto failBootInit; /* Allocate and map the descriptor. */ /* See <design/arena/>.@@@@ */ res = BootAlloc(&p, boot, sizeof(VMChunkStruct), MPS_PF_ALIGN); if (res != ResOK) goto failChunkAlloc; vmChunk = p; /* Calculate the limit of the grain where the chunkStruct resides. */ chunkStructLimit = AddrAlignUp((Addr)(vmChunk + 1), ArenaGrainSize(arena)); res = vmArenaMap(vmArena, vm, base, chunkStructLimit); if (res != ResOK) goto failChunkMap; vmChunk->overheadMappedLimit = chunkStructLimit; /* Copy VM descriptor into its place in the chunk. */ VMCopy(VMChunkVM(vmChunk), vm); res = ChunkInit(VMChunk2Chunk(vmChunk), arena, base, limit, VMReserved(VMChunkVM(vmChunk)), boot); if (res != ResOK) goto failChunkInit; BootBlockFinish(boot); vmChunk->sig = VMChunkSig; AVERT(VMChunk, vmChunk); *chunkReturn = VMChunk2Chunk(vmChunk); return ResOK; failChunkInit: VMUnmap(vm, VMBase(vm), chunkStructLimit); failChunkMap: failChunkAlloc: failBootInit: VMFinish(vm); failVMInit: return res; }