Ejemplo n.º 1
0
Size readBootSymbols(char *prog, char *file,
                     Vector<BootEntry *> *entries)
{
    char line[128];
    Size num = MAX_REGIONS;
    Size totalBytes = 0, totalEntries = 0;
    BootEntry *entry;
    FILE *fp;
    ExecutableFormat *format;
    
    /* Open configuration file. */
    if ((fp = fopen(file, "r")) == NULL)
    {
        fprintf(stderr, "%s: failed to open `%s': %s\n",
                prog, file, strerror(errno));
        exit(EXIT_FAILURE);
    }
    /* Read out lines. */
    while (fgets(line, sizeof(line), fp) != NULL)
    {
        /* Clear newline. */
        line[strlen(line) - 1] = 0;

        /* Allocate new boot entry. */
        entry = new BootEntry;
        strncpy(entry->symbol.name, line, BOOTIMAGE_NAMELEN);

        // Find the file
        struct stat st;
        if (stat(line, &st) == -1)
        {
            fprintf(stderr, "%s: failed to stat `%s': %s\n",
                    prog, line, strerror(errno));
            exit(EXIT_FAILURE);
        }
        // Allocate buffer
        u8 *buffer = new u8[st.st_size];

        // Read the file
        FILE *entry_fd = fopen(line, "r");
        if (!entry_fd)
        {
            fprintf(stderr, "%s: failed to open `%s': %s\n",
                    prog, line, strerror(errno));
            exit(EXIT_FAILURE);
        }
        if (fread(buffer, st.st_size, 1, entry_fd) != 1)
        {
            fprintf(stderr, "%s: failed to fread `%s': %s\n",
                    prog, line, strerror(errno));
            exit(EXIT_FAILURE);
        }
        fclose(entry_fd);

        // Try to parse as BootProgram using libexec.
        if (ExecutableFormat::find(buffer, st.st_size, &format) == ExecutableFormat::Success)
        {
            // Extract memory regions
            if (format->regions(entry->regions, &num) != ExecutableFormat::Success || num <= 0)
            {
                fprintf(stderr, "%s: failed to extract memory regions from `%s': %s\n",
                            prog, line, strerror(errno));
                exit(EXIT_FAILURE);
            }
            entry->numRegions   = num;
            entry->symbol.type  = BootProgram;
            format->entry((Address *)&entry->symbol.entry);
        }
        // BootData
        else
        {
            // Fill BootEntry
            entry->symbol.type = BootData;
            entry->numRegions  = 1;
            entry->regions[0].virt = 0;
            entry->regions[0].access = Memory::User | Memory::Readable | Memory::Writable;
            entry->regions[0].size = st.st_size;
            entry->regions[0].data = buffer;
        }
        // Insert into Array
        entries->insert(entry);
        totalEntries++;
        
        /* Debug out memory sections. */
        for (Size i = 0; i < entry->numRegions; i++)
        {
            printf("%s[%u]: vaddr=%x size=%u\n",
                    line, i, (uint) entry->regions[i].virt,
                    entry->regions[i].size);
            totalBytes += entry->regions[i].size;
        }
    }
    /* All done. */
    printf("%d entries, %d bytes total\n", totalEntries, totalBytes);
    return totalEntries;
}    
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
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;
}