Extended Kaluga: Added custom handler function for boot modules. Also improved some...
authorGerd Zellweger <zgerd@student.ethz.ch>
Fri, 2 Mar 2012 22:38:30 +0000 (23:38 +0100)
committerGerd Zellweger <zgerd@student.ethz.ch>
Fri, 2 Mar 2012 22:38:30 +0000 (23:38 +0100)
errors/errno.fugu
lib/dist2/client/dist2.c
usr/kaluga/boot_modules.c
usr/kaluga/common.c
usr/kaluga/kaluga.h
usr/kaluga/main.c
usr/kaluga/start_cpu.c
usr/kaluga/start_pci.c
usr/kaluga/start_pci_driver.c
usr/skb/programs/device_db.pl

index 90c9fa0..411ebf3 100644 (file)
@@ -800,6 +800,7 @@ errors libdist2  DIST2_ERR_ {
 // 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
index 2e686ee..a48be14 100644 (file)
@@ -173,6 +173,8 @@ errval_t dist_thc_init(void)
     }
 
     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)) {
@@ -186,8 +188,6 @@ errval_t dist_thc_init(void)
     }
 
     // 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)) {
index e6ce1e5..e4d23bd 100644 (file)
 
 #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);
@@ -53,6 +84,7 @@ static void parse_module(char* line, struct module_info* si)
     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);
index 1cd9f35..948c7b1 100644 (file)
@@ -4,7 +4,8 @@
 #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;
@@ -12,7 +13,7 @@ errval_t trigger_existing_and_watch(const char* query,
     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();
@@ -36,7 +37,7 @@ errval_t trigger_existing_and_watch(const char* query,
 
             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:
index 7d55ab3..9ef0373 100644 (file)
 #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;
@@ -19,6 +23,7 @@ struct module_info {
     int argc;
     char* argv[MAX_CMDLINE_ARGS + 1];
 
+    module_start_fn start_function;
     domainid_t did;
 };
 
@@ -27,7 +32,7 @@ extern uint32_t my_arch_id;
 
 
 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);
@@ -36,6 +41,8 @@ errval_t watch_for_pci_devices(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_ */
index c2d2ef2..c246802 100644 (file)
@@ -25,6 +25,7 @@
 #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++) {
@@ -88,6 +130,7 @@ int main(int argc, char** argv)
     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
index 0905cc0..fa2ba93 100644 (file)
@@ -31,6 +31,8 @@
 // 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)
 {
@@ -86,6 +88,7 @@ static void boot_core_reply(struct monitor_binding *st, errval_t msgerr)
 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));
 }
@@ -146,12 +149,13 @@ static void cpu_change_event(dist2_mode_t mode, char* record, void* state)
             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);
         }
 
     }
@@ -165,79 +169,35 @@ out:
     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;
 }
index 729993e..c0d5dbd 100644 (file)
@@ -43,8 +43,9 @@ static void bridge_change_event(dist2_mode_t mode, char* bridge_record, void* st
             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)) {
@@ -62,5 +63,6 @@ errval_t watch_for_pci_root_bridge(void)
                                " 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);
 }
index 639d414..3cfd9f6 100644 (file)
 #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;
@@ -54,15 +94,12 @@ static void pci_change_event(dist2_mode_t mode, char* device_record, void* st)
             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)) {
@@ -70,18 +107,24 @@ static void pci_change_event(dist2_mode_t mode, char* device_record, void* st)
             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:
@@ -95,5 +138,5 @@ errval_t watch_for_pci_devices(void)
                                " 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);
 }
index 70f7377..146516a 100644 (file)
@@ -72,7 +72,7 @@ find_pci_driver(PciInfo, DriverInfo) :-
     !,
     % 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},
@@ -83,5 +83,5 @@ find_cpu_driver(ApicId, DriverInfo) :-
 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).