1/**
2 * \file
3 * \brief
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <string.h>
17#include <inttypes.h>
18#include <barrelfish/barrelfish.h>
19#include <spawndomain/spawndomain.h>
20#include "spawn.h"
21
22#ifndef min
23#define min(a,b) ((a) < (b) ? (a) : (b))
24#endif
25#ifndef max
26#define max(a,b) ((a) > (b) ? (a) : (b))
27#endif
28
29const char *multiboot_strings = NULL;
30
31const char *getopt_module(struct mem_region *module)
32{
33    assert(module != NULL);
34    assert(module->mr_type == RegionType_Module);
35
36    const char *optstring = multiboot_strings + module->mrmod_data;
37
38    // find the first space (or end of string if there is none)
39    const char *args = strchr(optstring, ' ');
40    if (args == NULL) {
41        args = optstring + strlen(optstring);
42    }
43
44    // search backward for last '/' before the first ' '
45    for (const char *c = args; c > optstring; c--) {
46        if (*c == '/') {
47            return c + 1;
48        }
49    }
50
51    return optstring;
52}
53
54/// Map in the frame caps for a module into our vspace, return their location
55errval_t spawn_map_module(struct mem_region *module, size_t *retsize,
56                          lvaddr_t *retaddr, genpaddr_t *retpaddr)
57{
58    assert(module != NULL);
59    assert(module->mr_type == RegionType_Module);
60
61    errval_t err;
62
63    size_t size = module->mrmod_size;
64
65    void *base;
66    struct memobj *memobj;
67    struct vregion *vregion;
68
69    err = vspace_map_anon_attr(&base, &memobj, &vregion, size, &size,
70                               VREGION_FLAGS_READ);
71    if (err_is_fail(err)) {
72        return err_push(err, LIB_ERR_VSPACE_MAP);
73    }
74    struct capref frame = {
75        .cnode = cnode_module,
76        .slot  = module->mrmod_slot,
77    };
78
79    if (retpaddr != NULL) {
80        *retpaddr = module->mr_base;
81    }
82
83    if (retsize != NULL) {
84        *retsize = size;
85    }
86
87    if (retaddr != NULL) {
88        *retaddr = (lvaddr_t)base;
89    }
90
91    assert((size & BASE_PAGE_MASK) == 0);
92
93    struct frame_identity id;
94    err = frame_identify(frame, &id);
95    assert(err_is_ok(err));
96    // all multiboot modules backed with a single cap
97    assert(size <= id.bytes);
98
99    err = memobj->f.fill(memobj, 0, frame, id.bytes);
100    if (err_is_fail(err)) {
101        return err_push(err, LIB_ERR_MEMOBJ_FILL);
102    }
103
104    err = memobj->f.pagefault(memobj, vregion, 0, 0);
105    if (err_is_fail(err)) {
106        return err_push(err, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER);
107    }
108
109    return SYS_ERR_OK;
110}
111
112errval_t spawn_unmap_module(lvaddr_t mapped_addr)
113{
114    return vspace_unmap((void *)mapped_addr);
115}
116
117/// Returns a raw pointer to the modules string area string
118const char *multiboot_module_rawstring(struct mem_region *region)
119{
120    if (multiboot_strings == NULL) {
121        errval_t err;
122        /* Map in multiboot module strings area */
123        struct capref mmstrings_cap = {
124            .cnode = cnode_module,
125            .slot = 0
126        };
127        err = vspace_map_one_frame_attr((void**)&multiboot_strings,
128                                        BASE_PAGE_SIZE, mmstrings_cap,
129                                        VREGION_FLAGS_READ,
130                                        NULL, NULL);
131        if (err_is_fail(err)) {
132            DEBUG_ERR(err, "vspace_map failed");
133	    return NULL;
134        }
135#if 0
136        printf("Mapped multiboot_strings at %p\n", multiboot_strings);
137        for (int i = 0; i < 256; i++) {
138            if ((i & 15) == 0) printf("%04x  ", i);
139            printf ("%02x ", multiboot_strings[i]& 0xff);
140            if ((i & 15) == 15) printf("\n");
141        }
142#endif
143    }
144
145    if (region == NULL || region->mr_type != RegionType_Module) {
146        return NULL;
147    }
148    return multiboot_strings + region->mrmod_data;
149}
150
151errval_t multiboot_cleanup_mapping(void)
152{
153    errval_t err = vspace_unmap(multiboot_strings);
154    if (err_is_fail(err)) {
155        DEBUG_ERR(err, "multiboot_cleanup_mapping: vspace_unmap() failed\n");
156        return err_push(err, LIB_ERR_VSPACE_REMOVE_REGION);
157    }
158    multiboot_strings = NULL;
159    return SYS_ERR_OK;
160}
161
162
163/// returns the basename without arguments of a multiboot module
164// XXX: returns pointer to static buffer. NOT THREAD SAFE
165const char *multiboot_module_name(struct mem_region *region)
166{
167    const char *str = multiboot_module_rawstring(region);
168    if (str == NULL) {
169	return NULL;
170    }
171
172    // copy module data to local buffer so we can mess with it
173    static char buf[128];
174    strncpy(buf, str, sizeof(buf));
175    buf[sizeof(buf) - 1] = '\0'; // ensure termination
176
177    // ignore arguments for name comparison
178    char *args = strchr(buf, ' ');
179    if (args != NULL) {
180        *args = '\0';
181    }
182
183    return buf;
184}
185
186struct mem_region *multiboot_find_module(struct bootinfo *bi, const char *name)
187{
188
189    for(size_t i = 0; i < bi->regions_length; i++) {
190        struct mem_region *region = &bi->regions[i];
191        const char *modname = multiboot_module_name(region);
192        if (modname != NULL &&
193            strncmp(modname + strlen(modname) - strlen(name),
194                    name, strlen(name)) == 0) {
195            return region;
196        }
197    }
198
199    return NULL;
200}
201
202struct mem_region *multiboot_find_module_containing(struct bootinfo *bi,
203						    const char *name,
204						    const char *containing)
205{
206    assert(bi != NULL);
207    assert(name != NULL);
208    assert(containing != NULL);
209
210    size_t namelen = strlen(name);
211
212    for(size_t i = 0; i < bi->regions_length; i++) {
213        struct mem_region *region = &bi->regions[i];
214	if (region->mr_type != RegionType_Module)
215	    continue;
216	const char *raw = multiboot_module_rawstring(region);
217	if (raw == NULL)
218	    continue;
219
220	const char *space = strchr(raw, ' ');
221	if (space == NULL || (space - raw < namelen))
222	    continue;
223
224	if (strncmp(space - namelen, name, namelen))
225	    continue;
226
227	if ((strstr(raw, containing)) != NULL)
228	    return region;
229    }
230
231    return NULL;
232}
233
234