// dist2 library errors
errors kaluga KALUGA_ERR_ {
failure PARSE_MODULES "Cannot parse menu.lst.",
+ failure MODULE_NOT_FOUND "Boot module not found",
};
// errors generated by THC
}
assert(service_iref != 0);
+ // XXX: Not sure but I think it would be better not to run the THC client
+ // on the default waitset?
err = dist2_thc_connect(service_iref,
get_default_waitset(), IDC_BIND_FLAGS_DEFAULT, &(rpc.binding));
if (err_is_fail(err)) {
}
// TODO: Hack. Tell the server that these bindings belong together
- // We can't use the same binding in 2 different threads with
- // rpc and non-rpc calls.
dist2_thc_client_binding_t* cl = dist_get_thc_client();
err = cl->call_seq.get_identifier(cl, &client_identifier);
if (err_is_fail(err)) {
#define MAX_DRIVER_MODULES 128
+extern char **environ;
+
static struct module_info modules[MAX_DRIVER_MODULES];
inline bool is_auto_driver(struct module_info* mi) {
return strcmp(mi->argv[1], "auto") == 0;
}
+inline bool is_started(struct module_info* mi)
+{
+ return mi->did > 0;
+}
+
+static errval_t default_start_function(coreid_t where, struct module_info* mi,
+ char* record)
+{
+ errval_t err = SYS_ERR_OK;
+
+ if (!is_started(mi)) {
+ err = spawn_program(where, mi->path, mi->argv+1,
+ environ, 0, &mi->did);
+ if (err_is_fail(err)) {
+ DEBUG_ERR(err, "Spawning %s failed.", mi->path);
+ }
+ }
+
+ return err;
+}
+
+void set_start_function(char* binary, module_start_fn start_fn)
+{
+ struct module_info* mi = find_module(binary);
+ if (mi != NULL) {
+ mi->start_function = start_fn;
+ }
+}
+
struct module_info* find_module(char *binary)
{
assert(binary != NULL);
char* binary_start = strrchr(si->path, '/');
si->binary = strdup(binary_start+1); // exclude /
si->did = 0;
+ si->start_function = default_start_function;
char* cmdstart = line + path_size - strlen(si->binary);
si->cmdargs = strdup(cmdstart);
#include "kaluga.h"
errval_t trigger_existing_and_watch(const char* query,
- trigger_handler_fn event_handler, dist2_trigger_id_t* tid)
+ trigger_handler_fn event_handler, void* state,
+ dist2_trigger_id_t* tid)
{
errval_t error_code;
char** names = NULL;
char* record = NULL; // freed by cpu_change_event
size_t len = 0;
dist2_trigger_t t = dist_mktrigger(SYS_ERR_OK, dist2_BINDING_EVENT,
- TRIGGER_ALWAYS, event_handler, NULL);
+ TRIGGER_ALWAYS, event_handler, state);
// Get current cores registered in system
struct dist2_thc_client_binding_t* rpc = dist_get_thc_client();
switch (err_no(err)) {
case SYS_ERR_OK:
- event_handler(DIST_ON_SET, record, NULL);
+ event_handler(DIST_ON_SET, record, state);
break;
case DIST2_ERR_NO_RECORD:
#define TRIGGER_ALWAYS (DIST_PERSIST | DIST_ON_SET | DIST_ON_DEL | DIST_ALWAYS_SET)
#define BSP_CORE_ID 0
+struct module_info;
+typedef errval_t(*module_start_fn)(coreid_t where, struct module_info* mi,
+ char* record);
+
struct module_info {
char* complete_line;
char* path;
int argc;
char* argv[MAX_CMDLINE_ARGS + 1];
+ module_start_fn start_function;
domainid_t did;
};
errval_t trigger_existing_and_watch(const char*,
- trigger_handler_fn, dist2_trigger_id_t*);
+ trigger_handler_fn, void*, dist2_trigger_id_t*);
errval_t watch_for_cores(void);
errval_t watch_for_pci_root_bridge(void);
void init_environ(void);
errval_t init_boot_modules(void);
struct module_info* find_module(char*);
-bool is_auto_driver(struct module_info* mi);
+bool is_started(struct module_info*);
+bool is_auto_driver(struct module_info*);
+void set_start_function(char*, module_start_fn);
#endif /* KALUGA_H_ */
#include <barrelfish/barrelfish.h>
#include <barrelfish/cpu_arch.h>
#include <barrelfish/nameservice_client.h>
+#include <barrelfish/spawn_client.h>
#include <if/monitor_defs.h>
coreid_t my_core_id = 0; // Core ID
uint32_t my_arch_id = 0; // APIC ID
+extern char **environ;
+
+static errval_t start_networking(coreid_t core, struct module_info* driver,
+ char* record)
+{
+ errval_t err = SYS_ERR_OK;
+
+ if (!is_started(driver)) {
+ err = spawn_program(core, driver->path, driver->argv+1,
+ environ, 0, &driver->did);
+ if (err_is_fail(err)) {
+ DEBUG_ERR(err, "Spawning %s failed.", driver->path);
+ return err;
+ }
+
+ struct module_info* netd = find_module("netd");
+ if (netd == NULL || !is_auto_driver(netd)) {
+ KALUGA_DEBUG("netd not found. Driver will probably not work correctly.");
+ return err;
+ }
+
+ // XXX: Manually add cardname (overwrite first (auto) argument)
+ size_t name_len = strlen("cardname=")+strlen(driver->binary)+1;
+ char* cardname = malloc(name_len);
+ sprintf(cardname, "cardname=%s", driver->binary);
+ netd->argv[0] = cardname;
+ err = spawn_program(core, netd->path, netd->argv,
+ environ, 0, &netd->did);
+ free(cardname);
+ }
+
+ return err;
+
+}
+
+static void add_start_function_overrides(void)
+{
+ set_start_function("e1000", start_networking);
+ set_start_function("rtl8029", start_networking);
+}
+
static void parse_arguments(int argc, char** argv)
{
for (int i = 1; i < argc; i++) {
if (err_is_fail(err)) {
USER_PANIC_ERR(err, "Parse boot modules.");
}
+ add_start_function_overrides();
// The current boot protocol needs us to have
// knowledge about how many CPUs are available at boot
// boot_initialize_request after all cores have booted
// It's is a hack (see monitors boot.c)
static coreid_t cores_on_boot = 0;
+static coreid_t core_counter = 1; // BSP already up
+static bool cores_booted = false;
static errval_t new_mon_msg(struct mon_msg_state** mms, send_handler_fn s)
{
static void boot_initialize_reply(struct monitor_binding *st)
{
KALUGA_DEBUG("boot_initialize_reply\n");
+ cores_booted = true;
errval_t err = dist_set("all_spawnds_up { iref: 0 }");
assert(err_is_ok(err));
}
mms->core_id = core_id++;
mms->arch_id = arch_id;
mms->send(mb, mms);
+ (*(coreid_t*) state) += 1;
// XXX: copied this line from spawnd bsp_bootup,
// not sure why x86_64 is hardcoded here but it
// seems broken...
skb_add_fact("corename(%d, x86_64, apic(%lu)).",
- core_id, arch_id);
+ mms->core_id, mms->arch_id);
}
}
free(record);
}
-errval_t watch_for_cores(void) {
+errval_t watch_for_cores(void)
+{
configure_monitor_binding();
- errval_t error_code;
- char** names = NULL;
- char* output = NULL;
- char* core_record = NULL; // freed by cpu_change_event
- size_t len = 0;
- dist2_trigger_id_t tid;
- dist2_trigger_t t = dist_mktrigger(SYS_ERR_OK, dist2_BINDING_EVENT,
- TRIGGER_ALWAYS, cpu_change_event, NULL);
-
- // Get current cores registered in system
- struct dist2_thc_client_binding_t* rpc = dist_get_thc_client();
static char* local_apics = "r'hw\\.apic\\.[0-9]+' { cpu_id: _, "
" enabled: 1, "
" id: _ }";
- errval_t err = rpc->call_seq.get_names(rpc, local_apics,
- t, &output, &tid, &error_code);
- if (err_is_fail(err)) {
- goto out;
- }
- err = error_code;
-
- switch(err_no(err)) {
- case SYS_ERR_OK:
- err = dist_parse_names(output, &names, &len);
- if (err_is_fail(err)) {
- goto out;
- }
- cores_on_boot = (coreid_t) len;
-
- for (size_t i=0; i < cores_on_boot; i++) {
- KALUGA_DEBUG("get core record for name:%s\n", names[i]);
- err = dist_get(&core_record, names[i]);
-
- switch (err_no(err)) {
- case SYS_ERR_OK:
- cpu_change_event(DIST_ON_SET, core_record, NULL);
- break;
-
- case DIST2_ERR_NO_RECORD:
- // Core was removed in the meantime - ignore
- assert(core_record == NULL);
- break;
-
- default:
- DEBUG_ERR(err, "Unable to retrieve core record for %s", names[i]);
- assert(core_record == NULL);
- break;
- }
+ dist2_trigger_id_t tid;
+ errval_t err = trigger_existing_and_watch(local_apics, cpu_change_event,
+ &core_counter, &tid);
+ cores_on_boot = core_counter;
+
+ if (err_is_ok(err)) {
+ if (cores_on_boot == 1) {
+ // No additional cores found
+ // XXX: We simulate a boot initialize reply to set the
+ // all_spawnds_up record. The whole app monitor boot protocol will
+ // most likely change in the future and render this unnecessary.
+ boot_initialize_reply(NULL);
}
- break;
-
- case DIST2_ERR_NO_RECORD:
- // No cores found, do nothing for now
- KALUGA_DEBUG("No additional cores found in ACPI!\n");
- cores_on_boot = 1;
-
- // XXX: We simulate a boot initialize reply to set the
- // all_spawnds_up record. The whole app monitor boot protocol will
- // most likely change in the future and render this unnecessary.
- boot_initialize_reply(NULL);
- break;
-
- default:
- USER_PANIC_ERR(err, "Failed to check for CPU cores in SKB.");
- break;
}
-out:
- dist_free_names(names, cores_on_boot);
- free(output);
+ // Wait until all cores found are booted, this ensures
+ // we won't deadlock in case we start a driver on
+ // a core that is not ready
+ /*
+ while (!cores_booted) {
+ messages_wait_and_handle_next();
+ }*/
return err;
}
goto out;
}
- // XXX: always spawn on my_core_id
KALUGA_DEBUG("bridge_change_event: spawn mi->path: %s\n", mi->path);
+ // XXX: always spawn on my_core_id; otherwise we need to check that
+ // the other core is already up
errval_t err = spawn_program(my_core_id, mi->path, mi->argv+1,
environ, 0, &pci_driver);
if (err_is_fail(err)) {
" bus: _, device: _, function: _, maxbus: _,"
" acpi_node: _ }";
dist2_trigger_id_t tid;
- return trigger_existing_and_watch(root_bridge, bridge_change_event, &tid);
+ return trigger_existing_and_watch(root_bridge, bridge_change_event,
+ NULL, &tid);
}
#include <assert.h>
#include <barrelfish/barrelfish.h>
-#include <barrelfish/spawn_client.h>
#include <dist2/dist2.h>
#include <skb/skb.h>
#include "kaluga.h"
-extern char **environ;
+static void pci_change_event(dist2_mode_t mode, char* device_record, void* st);
+
+static void spawnd_up_event(dist2_mode_t mode, char* spawnd_record, void* st)
+{
+ assert(mode & DIST_ON_SET);
+ uint64_t iref;
+ errval_t err = dist_read(spawnd_record, "_ { iref: %d }", &iref);
+ if (err_is_fail(err)) {
+ USER_PANIC_ERR(err, "Failed to read iref from spawnd record?");
+ }
+
+ // Pass the iref as state, this tells pci_change_event that we
+ // don't need to look again for the spawnd iref
+ pci_change_event(DIST_ON_SET, st, (void*)iref);
+ free(spawnd_record);
+}
+
+static errval_t wait_for_spawnd(coreid_t core, void* state)
+{
+ // Check if the core we're spawning on is already up...
+ struct dist2_thc_client_binding_t* cl = dist_get_thc_client();
+ char* iref_record = NULL;
+ dist2_trigger_id_t tid;
+ errval_t error_code;
+ dist2_trigger_t t = dist_mktrigger(DIST2_ERR_NO_RECORD,
+ dist2_BINDING_EVENT, DIST_ON_SET, spawnd_up_event, state);
+
+ // Construct service name
+ static char* format = "spawn.%hhu { iref: _ }";
+ int length = snprintf(NULL, 0, format, core);
+ char* query = malloc(length+1);
+ snprintf(query, length+1, format, core);
+
+ errval_t err = cl->call_seq.get(cl, query, t, &iref_record, &tid, &error_code);
+ free(query);
+ free(iref_record);
+
+ if (err_is_fail(err)) {
+ return err;
+ }
+
+ return error_code;
+}
static void pci_change_event(dist2_mode_t mode, char* device_record, void* st)
{
- KALUGA_DEBUG("pci_change_event: %s\n", device_record);
errval_t err;
if (mode & DIST_ON_SET) {
uint64_t vendor_id, device_id;
goto out;
}
- // XXX: Find better way to parse binary
- // name from SKB
+ // XXX: Find better way to parse binary name from SKB
char* binary_name = malloc(strlen(skb_get_output()));
coreid_t core;
- skb_read_output("driver(%s, %c)", binary_name, &core);
- *strrchr(binary_name, ',') = '\0';
+ skb_read_output("driver(%hhu, %s)", &core, binary_name);
+ *strrchr(binary_name, ')') = '\0';
- // No need to ask the SKB as we always start pci for
- // in case we find a root bridge
struct module_info* mi = find_module(binary_name);
free(binary_name);
if (mi == NULL || !is_auto_driver(mi)) {
goto out;
}
- if (mi->did == 0) {
- KALUGA_DEBUG("Spawn PCI driver: %s\n", mi->binary);
-
- err = spawn_program(core, mi->path, mi->argv+1,
- environ, 0, &mi->did);
- if (err_is_fail(err)) {
- DEBUG_ERR(err, "Spawning %s failed.", mi->path);
+ if (st == NULL && core != my_core_id) {
+ err = wait_for_spawnd(core, device_record);
+ if (err_no(err) == DIST2_ERR_NO_RECORD) {
+ KALUGA_DEBUG("Core where driver %s runs is not up yet.\n",
+ mi->binary);
+ // Don't want to free device record here...
+ return;
+ }
+ else if (err_is_fail(err)) {
+ DEBUG_ERR(err, "Waiting for core %d failed?\n", core);
+ goto out;
}
}
- else {
- // Driver already running.
- }
+
+ // If we've come here the core where we spawn the driver
+ // is already up
+ KALUGA_DEBUG("Spawn PCI driver: %s\n", mi->binary);
+ mi->start_function(core, mi, device_record);
}
out:
" device_id: _, class: _, subclass: _, "
" prog_if: _ }";
dist2_trigger_id_t tid;
- return trigger_existing_and_watch(pci_device, pci_change_event, &tid);
+ return trigger_existing_and_watch(pci_device, pci_change_event, NULL, &tid);
}
!,
% TODO: Core Selection based on PCI Info, core_hint, irqload, platforms,
% (+ may need to pass bus number here as well?)
- DriverInfo = driver(Binary, Core).
+ DriverInfo = driver(Core, Binary).
find_cpu_driver(ApicId, DriverInfo) :-
cpu_driver{binary: Binary, platforms: Platforms},
find_ioapic_driver(IOApicId, DriverInfo) :-
bus_driver{binary: Binary, core_hint: Core, platforms: Platforms},
% TODO: Select appropriate Core based on core_hint, platform, ioapic id
- DriverInfo = driver(Binary, Core).
+ DriverInfo = driver(Core, Binary).