3 * \brief Code responsible for booting application cores
7 * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
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, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
20 #include <barrelfish/barrelfish.h>
22 #include <octopus/octopus.h>
23 #include <if/octopus_thc.h>
29 static struct capref all_irq_cap;
31 static void pci_change_event(octopus_mode_t mode, char* device_record, void* st);
33 static void spawnd_up_event(octopus_mode_t mode, char* spawnd_record, void* st)
35 assert(mode & OCT_ON_SET);
37 errval_t err = oct_read(spawnd_record, "_ { iref: %d }", &iref);
38 if (err_is_fail(err)) {
39 USER_PANIC_ERR(err, "Failed to read iref from spawnd record?");
42 // Pass the iref as state, this tells pci_change_event that we
43 // don't need to look again for the spawnd iref
45 pci_change_event(OCT_ON_SET, st, (void*)(uintptr_t)iref);
49 static errval_t wait_for_spawnd(coreid_t core, void* state)
51 // Check if the core we're spawning on is already up...
52 struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
54 octopus_trigger_t t = oct_mktrigger(OCT_ERR_NO_RECORD,
55 octopus_BINDING_EVENT, OCT_ON_SET, spawnd_up_event, state);
57 // Construct service name
58 static char* format = "spawn.%"PRIuCOREID" { iref: _ }";
59 int length = snprintf(NULL, 0, format, core);
60 char* query = malloc(length+1);
61 snprintf(query, length+1, format, core);
63 errval_t err = cl->call_seq.get(cl, query, t, NULL, NULL, &error_code);
66 if (err_is_fail(err)) {
73 static void pci_change_event(octopus_mode_t mode, char* device_record, void* st)
76 char intcaps_debug_msg[100];
77 char *binary_name = NULL;
78 strcpy(intcaps_debug_msg, "none");
79 if (mode & OCT_ON_SET) {
80 KALUGA_DEBUG("pci_change_event: device_record: %s\n", device_record);
81 uint64_t vendor_id, device_id, bus, dev, fun;
82 err = oct_read(device_record, "_ { vendor: %d, device_id: %d, bus: %d, device: %d,"
84 &vendor_id, &device_id, &bus, &dev, &fun);
85 if (err_is_fail(err)) {
86 USER_PANIC_ERR(err, "Got malformed device record?");
89 /* duplicate device record as we may need it for later */
90 device_record = strdup(device_record);
91 assert(device_record);
94 // Ask the SKB which binary and where to start it...
95 static char* query = "find_pci_driver(pci_card(%"PRIu64", %"PRIu64", _, _, _), Driver),"
97 err = skb_execute_query(query, vendor_id, device_id);
98 if (err_no(err) == SKB_ERR_EXECUTION) {
99 KALUGA_DEBUG("No PCI driver found for: VendorId=0x%"PRIx64", "
100 "DeviceId=0x%"PRIx64"\n",
101 vendor_id, device_id);
104 else if (err_is_fail(err)) {
105 DEBUG_SKB_ERR(err, "Failed to query SKB.\n");
109 // XXX: Find better way to parse binary name from SKB
110 binary_name = malloc(strlen(skb_get_output()));
113 uint8_t int_model_in;
114 struct int_startup_argument int_arg;
115 int_arg.int_range_start = 1000;
116 int_arg.int_range_end = 1004;
118 err = skb_read_output("driver(%"SCNu8", %"SCNu8", %"SCNu8", %[^,], "
119 "%"SCNu8")", &core, &multi, &offset, binary_name, &int_model_in);
120 if(err_is_fail(err)){
121 USER_PANIC_SKB_ERR(err, "Could not parse SKB output.\n");
123 int_arg.model = int_model_in;
125 struct driver_argument driver_arg;
126 driver_arg.int_arg = int_arg;
127 // TODO: every driver should specify the int_model in device_db
128 // until then, we treat them like legacy, so they can use the standard
129 // pci client functionality.
130 if(int_arg.model == INT_MODEL_LEGACY || int_arg.model == INT_MODEL_NONE){
131 KALUGA_DEBUG("Starting driver (%s) with legacy interrupts\n", binary_name);
132 // No controller has to instantiated, but we need to get caps for the int numbers
133 err = skb_execute_query("get_pci_legacy_int_range(addr(%"PRIu64",%"PRIu64",%"PRIu64"),Li),"
134 "writeln(Li).", bus, dev, fun);
135 KALUGA_DEBUG("(Driver=%s,bus=%"PRIu64",dev=%"PRIu64",fun=%"PRIu64") "
136 "int_range skb reply: %s\n",
137 binary_name, bus, dev, fun, skb_get_output() );
140 strncpy(intcaps_debug_msg, skb_get_output(), sizeof(intcaps_debug_msg));
141 char * nl = strchr(intcaps_debug_msg, '\n');
143 intcaps_debug_msg[99] = '\0';
145 uint64_t start=0, end=0;
146 err = skb_read_output("%"SCNu64", %"SCNu64, &start, &end);
147 if(err_is_fail(err)){
148 DEBUG_SKB_ERR(err, "Could not parse SKB output. Not starting driver.\n");
152 struct cnoderef argnode_ref;
153 err = cnode_create_l2(&driver_arg.arg_caps, &argnode_ref);
154 if(err_is_fail(err)){
155 USER_PANIC_ERR(err, "Could not cnode_create_l2");
159 cap.cnode = argnode_ref;
161 //err = sys_debug_create_irq_src_cap(cap, start, end);
162 err = cap_retype(cap, all_irq_cap, start, ObjType_IRQSrc,
164 if(err_is_fail(err)){
165 USER_PANIC_ERR(err, "Could not create int_src cap");
167 } else if(int_arg.model == INT_MODEL_MSI){
168 KALUGA_DEBUG("Starting driver (%s) with MSI interrupts\n", binary_name);
169 // TODO instantiate controller
170 } else if(int_arg.model == INT_MODEL_MSIX){
171 KALUGA_DEBUG("Starting driver (%s) with MSI-x interrupts\n", binary_name);
172 // TODO instantiate controller
174 KALUGA_DEBUG("No interrupt model specified for %s. No interrupts for this driver.\n",
178 struct module_info* mi = find_module(binary_name);
180 KALUGA_DEBUG("Driver %s not loaded. Ignore.\n", binary_name);
184 set_multi_instance(mi, multi);
185 set_core_id_offset(mi, offset);
187 // Wait until the core where we start the driver
189 if (st == NULL && core != my_core_id) {
190 err = wait_for_spawnd(core, device_record);
191 if (err_no(err) == OCT_ERR_NO_RECORD) {
192 KALUGA_DEBUG("Core where driver %s runs is not up yet.\n",
194 // Don't want to free device record yet...
197 else if (err_is_fail(err)) {
198 DEBUG_ERR(err, "Waiting for core %d failed?\n", core);
203 // If we've come here the core where we spawn the driver
205 printf("Kaluga: Starting \"%s\" for (bus=%"PRIu64",dev=%"PRIu64",fun=%"PRIu64")"
206 ", intcaps: %s, on core %"PRIuCOREID"\n",
207 binary_name, bus, dev, fun, intcaps_debug_msg, core);
209 err = mi->start_function(core, mi, device_record, &driver_arg);
210 switch (err_no(err)) {
212 KALUGA_DEBUG("Spawned PCI driver: %s\n", mi->binary);
216 case KALUGA_ERR_DRIVER_ALREADY_STARTED:
217 KALUGA_DEBUG("%s already running.\n", mi->binary);
220 case KALUGA_ERR_DRIVER_NOT_AUTO:
221 KALUGA_DEBUG("%s not declared as auto, ignore.\n", mi->binary);
225 DEBUG_ERR(err, "Unhandled error while starting %s\n", mi->binary);
235 errval_t watch_for_pci_devices(void)
237 static char* pci_device = "r'hw\\.pci\\.device\\.[0-9]+' { "
238 " bus: _, device: _, function: _, vendor: _,"
239 " device_id: _, class: _, subclass: _, "
241 octopus_trigger_id_t tid;
242 return oct_trigger_existing_and_watch(pci_device, pci_change_event, NULL, &tid);
245 static void bridge_change_event(octopus_mode_t mode, char* bridge_record, void* st)
247 if (mode & OCT_ON_SET) {
248 // No need to ask the SKB as we always start pci for
249 // in case we find a root bridge
250 struct module_info* mi = find_module("pci");
252 KALUGA_DEBUG("PCI driver not found or not declared as auto.");
256 // XXX: always spawn on my_core_id; otherwise we need to check that
257 // the other core is already up
258 errval_t err = mi->start_function(my_core_id, mi, bridge_record, NULL);
259 switch (err_no(err)) {
261 KALUGA_DEBUG("Spawned PCI bus driver: %s\n", mi->binary);
265 case KALUGA_ERR_DRIVER_ALREADY_STARTED:
266 KALUGA_DEBUG("%s already running.\n", mi->binary);
269 case KALUGA_ERR_DRIVER_NOT_AUTO:
270 KALUGA_DEBUG("%s not declared as auto, ignore.\n", mi->binary);
274 DEBUG_ERR(err, "Unhandled error while starting %s\n", mi->binary);
280 errval_t watch_for_pci_root_bridge(void)
283 // TODO: Get all_irq_cap from somewhere and remove sys_debug call
285 err = slot_alloc(&all_irq_cap);
286 assert(err_is_ok(err));
287 err = sys_debug_create_irq_src_cap(all_irq_cap, 0, 65536);
288 assert(err_is_ok(err));
290 static char* root_bridge = "r'hw\\.pci\\.rootbridge\\.[0-9]+' { "
291 " bus: _, device: _, function: _, maxbus: _,"
293 octopus_trigger_id_t tid;
294 return oct_trigger_existing_and_watch(root_bridge, bridge_change_event,