Create "ProcessManager" and "Domain" capabilities.
authorRazvan Damachi <razvan.damachi@gmail.com>
Mon, 12 Jun 2017 13:37:42 +0000 (15:37 +0200)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Thu, 31 Aug 2017 14:35:07 +0000 (16:35 +0200)
The ProcessManager capability is created by the CPU driver at startup and given
to init, where it will be passed on to the monitor and then the process manager
subsequently.

The Domain capability is an ID-like cap retypeable from the ProcessManager cap
above. The process management server can hence use the ProcessManager cap to
create Domain caps and give them to spawnd instances, to facilitate identifying
domains locally and globally.

Signed-off-by: Razvan Damachi <razvan.damachi@gmail.com>

16 files changed:
capabilities/caps.hl
errors/errno.fugu
include/barrelfish/caddr.h
include/barrelfish_kpi/capabilities.h
include/barrelfish_kpi/distcaps.h
include/barrelfish_kpi/init.h
kernel/cap_delete.c
kernel/capabilities.c
kernel/include/capabilities.h
kernel/startup.c
lib/barrelfish/capabilities.c
lib/barrelfish/debug.c
lib/mdb/mdb_tree.c
usr/init/spawn.c
usr/monitor/spawn.c
usr/proc_mgmt/service.c

index 5fd75c1..a8cdb1e 100644 (file)
@@ -317,3 +317,12 @@ cap KernelControlBlock from RAM {
 };
 
 cap IPI is_always_copy {};
+
+cap ProcessManager is_always_copy {
+    // Capability to act as process manager, i.e. create new domain caps.
+};
+
+cap Domain from ProcessManager {
+    eq coreid coreid;  /* Core where the domain was created. */
+    eq uint32 core_local_id;  /* Core-local ID of the domain. */
+};
\ No newline at end of file
index f245a5c..36485f6 100755 (executable)
@@ -162,6 +162,9 @@ errors kernel SYS_ERR_ {
     // ID capability
     failure ID_SPACE_EXHAUSTED  "ID space exhausted",
 
+    // Domain capability
+    failure DOMAIN_SPACE_EXHAUSTED "Domain space exhausted",
+
     // I2C driver
     // XXX: should not be in kernel
     failure I2C_UNINITIALIZED           "Trying to use uninitialized i2c controller",
@@ -650,6 +653,7 @@ errors spawn SPAWN_ERR_ {
     failure COPY_PERF_MON      "Error copying performance monitoring cap",
     failure COPY_KERNEL_CAP     "Error copying Kernel cap",
     failure COPY_INHERITCN_CAP  "Error copying capability from inherited cnode",
+    failure COPY_PROC_MNG_CAP   "Error copying ProcessManager cap",
 
     // make_runnable
     failure DISPATCHER_SETUP    "Dispatcher setup",
@@ -719,6 +723,7 @@ errors init INIT_ERR_ {
     failure COPY_KERNEL_CAP     "Failed to copy kernel cap to monitor",
     failure COPY_BSP_KCB        "Error copying BSP KernelControlBlock",
     failure COPY_IPI            "Failed to copy IPI cap to monitor",
+    failure COPY_PROC_MNG_CAP   "Failed to copy ProcessManager cap to monitor",
     failure COPY_PERF_MON       "Failed to copy performance monitoring cap to monitor",
     failure COPY_MODULECN_CAP   "Failed to copy module CNode cap to monitor",
     failure COPY_PACN_CAP       "Failed to copy phys addr CNode cap to monitor",
index 8033996..4874a52 100644 (file)
@@ -104,7 +104,7 @@ extern struct cnoderef cnode_root, cnode_task, cnode_base, cnode_super,
 /* well-known capabilities */
 extern struct capref cap_root, cap_monitorep, cap_irq, cap_io, cap_dispatcher,
                      cap_selfep, cap_kernel, cap_initep, cap_perfmon, cap_dispframe,
-                     cap_sessionid, cap_ipi, cap_vroot, cap_argcn;
+                     cap_sessionid, cap_ipi, cap_vroot, cap_argcn, cap_procmng;
 
 /**
  * \brief Returns the depth in the CSpace address of a cap
index 6086160..965d5e7 100644 (file)
@@ -57,7 +57,7 @@ STATIC_ASSERT((L2_CNODE_SLOTS  * (1UL << OBJBITS_CTE)) == OBJSIZE_L2CNODE,
 
 static inline bool type_is_vnode(enum objtype type)
 {
-    STATIC_ASSERT(48 == ObjType_Num, "Check VNode definitions");
+    STATIC_ASSERT(50 == ObjType_Num, "Check VNode definitions");
 
     return (type == ObjType_VNode_x86_64_pml4 ||
             type == ObjType_VNode_x86_64_pdpt ||
@@ -77,7 +77,7 @@ static inline bool type_is_vnode(enum objtype type)
 
 static inline bool type_is_vroot(enum objtype type)
 {
-    STATIC_ASSERT(48 == ObjType_Num, "Check VNode definitions");
+    STATIC_ASSERT(50 == ObjType_Num, "Check VNode definitions");
 
     return (type == ObjType_VNode_x86_64_pml4 ||
 #ifdef CONFIG_PAE
@@ -99,7 +99,7 @@ static inline bool type_is_vroot(enum objtype type)
 static inline size_t vnode_objbits(enum objtype type)
 {
     // This function should be emitted by hamlet or somesuch.
-    STATIC_ASSERT(48 == ObjType_Num, "Check VNode definitions");
+    STATIC_ASSERT(50 == ObjType_Num, "Check VNode definitions");
 
     if (type == ObjType_VNode_x86_64_pml4 ||
         type == ObjType_VNode_x86_64_pdpt ||
@@ -144,7 +144,7 @@ static inline size_t vnode_objbits(enum objtype type)
 static inline size_t vnode_objsize(enum objtype type)
 {
     // This function should be emitted by hamlet or somesuch.
-    STATIC_ASSERT(48 == ObjType_Num, "Check VNode definitions");
+    STATIC_ASSERT(50 == ObjType_Num, "Check VNode definitions");
 
     if (type == ObjType_VNode_x86_64_pml4 ||
         type == ObjType_VNode_x86_64_pdpt ||
@@ -186,7 +186,7 @@ static inline size_t vnode_objsize(enum objtype type)
  */
 static inline size_t vnode_entry_bits(enum objtype type) {
     // This function should be emitted by hamlet or somesuch.
-    STATIC_ASSERT(48 == ObjType_Num, "Check VNode definitions");
+    STATIC_ASSERT(50 == ObjType_Num, "Check VNode definitions");
 
     if (type == ObjType_VNode_x86_64_pml4 ||
         type == ObjType_VNode_x86_64_pdpt ||
@@ -240,7 +240,7 @@ static inline size_t vnode_entry_bits(enum objtype type) {
  * @return Number of page table entries in bits
  */
 static inline size_t cnode_get_slots(struct capability *cnode) {
-    STATIC_ASSERT(48 == ObjType_Num, "Check CNode definitions");
+    STATIC_ASSERT(50 == ObjType_Num, "Check CNode definitions");
 
     switch (cnode->type) {
         case ObjType_L1CNode:
@@ -255,7 +255,7 @@ static inline size_t cnode_get_slots(struct capability *cnode) {
 
 static inline enum objtype get_mapping_type(enum objtype captype)
 {
-    STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all mapping types");
+    STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all mapping types");
 
     switch (captype) {
         case ObjType_Frame:
@@ -296,7 +296,7 @@ static inline enum objtype get_mapping_type(enum objtype captype)
 
 static inline bool type_is_mapping(enum objtype type)
 {
-    STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all mapping types");
+    STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all mapping types");
 
     switch (type) {
         case ObjType_Frame_Mapping:
@@ -324,7 +324,7 @@ static inline bool type_is_mapping(enum objtype type)
 
 static inline bool type_is_mappable(enum objtype type)
 {
-    STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all mappable types");
+    STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all mappable types");
 
     switch (type) {
         case ObjType_Frame:
index 80397e2..9fc31d4 100644 (file)
@@ -40,7 +40,7 @@ distcap_state_is_foreign(distcap_state_t state)
  * Predicates related to sharing capabilities
  */
 
-STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all cap types");
+STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all cap types");
 static inline bool
 distcap_needs_locality(enum objtype type)
 {
@@ -90,7 +90,7 @@ distcap_needs_locality(enum objtype type)
     }
 }
 
-STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all cap types");
+STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all cap types");
 static inline bool
 distcap_is_moveable(enum objtype type)
 {
index 379c405..9ee3173 100644 (file)
@@ -95,7 +95,8 @@
 #define TASKCN_SLOT_SYSMEM      15  ///< ???
 #define TASKCN_SLOT_COREBOOT    16  ///< Copy of realmode section used to bootstrap a core
 #define TASKCN_SLOT_IPI         17  ///< Copy of IPI cap
-#define TASKCN_SLOTS_USER       18  ///< First free slot in taskcn for user
+#define TASKCN_SLOT_PROC_MNG    18  ///< Cap for the process manager
+#define TASKCN_SLOTS_USER       19  ///< First free slot in taskcn for user
 
 /* Page CNode */
 #define PAGECN_SLOT_VROOT       0 ///< First slot of page cnode is root page table
index 556ceb8..3aab3b0 100644 (file)
@@ -201,7 +201,7 @@ cleanup_copy(struct cte *cte)
 /**
  * \brief Cleanup the last cap copy for an object and the object itself
  */
-STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all RAM-backed cap types");
+STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all RAM-backed cap types");
 static errval_t
 cleanup_last(struct cte *cte, struct cte *ret_ram_cap)
 {
index 6739091..dc05297 100644 (file)
@@ -55,7 +55,7 @@ void caps_trace_ctrl(uint64_t types, genpaddr_t start, gensize_t size)
 
 struct capability monitor_ep;
 
-STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all cap types");
+STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all cap types");
 int sprint_cap(char *buf, size_t len, struct capability *cap)
 {
     switch (cap->type) {
@@ -277,6 +277,13 @@ int sprint_cap(char *buf, size_t len, struct capability *cap)
         return snprintf(buf, len, "ID capability (coreid 0x%" PRIxCOREID
                         " core_local_id 0x%" PRIx32 ")", cap->u.id.coreid,
                         cap->u.id.core_local_id);
+    case ObjType_ProcessManager:
+        return snprintf(buf, len, "Process manager capability");
+
+    case ObjType_Domain:
+        return snprintf(buf, len, "Domain capability (coreid 0x%" PRIxCOREID
+                        " core_local_id 0x%" PRIx32 ")", cap->u.domain.coreid,
+                        cap->u.domain.core_local_id);
 
     case ObjType_PerfMon:
         return snprintf(buf, len, "PerfMon cap");
@@ -321,6 +328,11 @@ void caps_trace(const char *func, int line, struct cte *cte, const char *msg)
 static uint32_t id_cap_counter = 1;
 
 /**
+ * Domain capability core_local_id counter.
+ */
+static uint32_t domain_cap_counter = 1;
+
+/**
  *  Sets #dest equal to #src
  *
  * #dest cannot be in use.
@@ -362,7 +374,7 @@ static errval_t set_cap(struct capability *dest, struct capability *src)
 
 // If you create more capability types you need to deal with them
 // in the table below.
-STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all cap types");
+STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all cap types");
 static size_t caps_max_numobjs(enum objtype type, gensize_t srcsize, gensize_t objsize)
 {
     switch(type) {
@@ -438,6 +450,8 @@ static size_t caps_max_numobjs(enum objtype type, gensize_t srcsize, gensize_t o
     case ObjType_Notify_IPI:
     case ObjType_PerfMon:
     case ObjType_IPI:
+    case ObjType_ProcessManager:
+    case ObjType_Domain:
     case ObjType_VNode_ARM_l1_Mapping:
     case ObjType_VNode_ARM_l2_Mapping:
     case ObjType_VNode_AARCH64_l0_Mapping:
@@ -466,7 +480,7 @@ static size_t caps_max_numobjs(enum objtype type, gensize_t srcsize, gensize_t o
  *
  * For the meaning of the parameters, see the 'caps_create' function.
  */
-STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all cap types");
+STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all cap types");
 
 static errval_t caps_zero_objects(enum objtype type, lpaddr_t lpaddr,
                                   gensize_t objsize, size_t count)
@@ -574,7 +588,7 @@ static errval_t caps_zero_objects(enum objtype type, lpaddr_t lpaddr,
  */
 // If you create more capability types you need to deal with them
 // in the table below.
-STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all cap types");
+STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all cap types");
 
 static errval_t caps_create(enum objtype type, lpaddr_t lpaddr, gensize_t size,
                             gensize_t objsize, size_t count, coreid_t owner,
@@ -1005,6 +1019,25 @@ static errval_t caps_create(enum objtype type, lpaddr_t lpaddr, gensize_t size,
         err = set_cap(&dest_caps->cap, &temp_cap);
         break;
 
+    case ObjType_Domain:
+        // Domain type does not refer to a kernel object
+        assert(lpaddr  == 0);
+        assert(size    == 0);
+        assert(objsize == 0);
+        assert(count   == 1);
+
+        // Prevent wrap around
+        if (domain_cap_counter >= UINT32_MAX) {
+            return SYS_ERR_DOMAIN_SPACE_EXHAUSTED;
+        }
+
+        // Generate a new ID, core_local_id monotonically increases
+        temp_cap.u.domain.coreid = my_core_id;
+        temp_cap.u.domain.core_local_id = domain_cap_counter++;
+
+        // Insert the capability
+        err = set_cap(&dest_caps->cap, &temp_cap);
+        break;
     case ObjType_IO:
         temp_cap.u.io.start = 0;
         temp_cap.u.io.end   = 65535;
@@ -1019,6 +1052,7 @@ static errval_t caps_create(enum objtype type, lpaddr_t lpaddr, gensize_t size,
     case ObjType_EndPoint:
     case ObjType_Notify_IPI:
     case ObjType_PerfMon:
+    case ObjType_ProcessManager:
         // These types do not refer to a kernel object
         assert(lpaddr  == 0);
         assert(size    == 0);
@@ -1293,7 +1327,7 @@ errval_t caps_create_from_existing(struct capability *root, capaddr_t cnode_cptr
 //{{{1 Capability creation
 
 /// check arguments, return true iff ok
-STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all cap types");
+STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all cap types");
 static bool check_caps_create_arguments(enum objtype type,
                                         size_t bytes, size_t objsize,
                                         bool exact)
@@ -1409,7 +1443,7 @@ errval_t caps_create_new(enum objtype type, lpaddr_t addr, size_t bytes,
     return SYS_ERR_OK;
 }
 
-STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all cap types");
+STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all cap types");
 /// Retype caps
 /// Create `count` new caps of `type` from `offset` in src, and put them in
 /// `dest_cnode` starting at `dest_slot`.
@@ -1500,7 +1534,8 @@ errval_t caps_retype(enum objtype type, gensize_t objsize, size_t count,
            src_cap->type == ObjType_Dispatcher ||
            src_cap->type == ObjType_Frame ||
            src_cap->type == ObjType_DevFrame ||
-           src_cap->type == ObjType_IRQSrc);
+           src_cap->type == ObjType_IRQSrc ||
+           src_cap->type == ObjType_ProcessManager);
 
     if (src_cap->type != ObjType_Dispatcher && src_cap->type != ObjType_IRQSrc) {
         base = get_address(src_cap);
@@ -1529,7 +1564,8 @@ errval_t caps_retype(enum objtype type, gensize_t objsize, size_t count,
 
     /* check that we can create `count` objs from `offset` in source, and
      * update base accordingly */
-    if (src_cap->type != ObjType_Dispatcher && src_cap->type != ObjType_IRQSrc) {
+    if (src_cap->type != ObjType_Dispatcher && src_cap->type != ObjType_IRQSrc
+            && src_cap->type != ObjType_Domain) {
         // TODO: convince ourselves that this is the only condition on offset
         if (offset + count * objsize > get_size(src_cap)) {
             debug(SUBSYS_CAPS, "caps_retype: cannot create all %zu objects"
@@ -1736,7 +1772,7 @@ errval_t caps_copy_to_cnode(struct cte *dest_cnode_cte, cslot_t dest_slot,
 }
 
 /// Create copies to a cte
-STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all cap types");
+STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all cap types");
 errval_t caps_copy_to_cte(struct cte *dest_cte, struct cte *src_cte, bool mint,
                           uintptr_t param1, uintptr_t param2)
 {
index 03ee874..9f13c34 100644 (file)
@@ -85,7 +85,7 @@ static inline struct cte *cte_for_cap(struct capability *cap)
 static inline size_t caps_get_mapping_offset(struct capability *cap) {
 
     // This function should be emitted by hamlet or somesuch.
-    STATIC_ASSERT(48 == ObjType_Num, "Check Mapping definitions");
+    STATIC_ASSERT(50 == ObjType_Num, "Check Mapping definitions");
 
     switch (cap->type) {
     case ObjType_VNode_AARCH64_l3_Mapping:
@@ -164,7 +164,7 @@ errval_t caps_revoke(struct cte *cte);
  * Cap tracing
  */
 #ifdef TRACE_PMEM_CAPS
-STATIC_ASSERT(48 == ObjType_Num, "knowledge of all cap types");
+STATIC_ASSERT(50 == ObjType_Num, "knowledge of all cap types");
 STATIC_ASSERT(64 >= ObjType_Num, "cap types fit in uint64_t bitfield");
 #define MAPPING_TYPES \
     ((1ull<<ObjType_VNode_x86_64_pml4_Mapping) | \
index 50418b7..eb6d9da 100644 (file)
@@ -305,6 +305,13 @@ struct dcb *spawn_module(struct spawn_state *st,
     err = caps_create_new(ObjType_IPI, 0, 0, 0, my_core_id, ipicap_cte);
     assert(err_is_ok(err));
 
+    // Create process manager capability
+    struct cte *procmngcap_cte = caps_locate_slot(CNODE(st->taskcn),
+                                                  TASKCN_SLOT_PROC_MNG);
+    err = caps_create_new(ObjType_ProcessManager, 0, 0, 0, my_core_id,
+                          procmngcap_cte);
+    assert(err_is_ok(err));
+
     /* Initialize dispatcher */
     dispatcher_handle_t init_handle
         = local_phys_to_mem(init_dispframe_cte->cap.u.frame.base);
index 89034f0..c167b77 100644 (file)
@@ -147,6 +147,12 @@ struct capref cap_sessionid = {
     .slot = TASKCN_SLOT_SESSIONID
 };
 
+/// Process manager cap, allows creating domains.
+struct capref cap_procmng = {
+    .cnode = TASK_CNODE_INIT,
+    .slot = TASKCN_SLOT_PROC_MNG
+};
+
 /// Root PML4 VNode
 struct capref cap_vroot = {
     .cnode = PAGE_CNODE_INIT,
index 1dfd66c..3c42017 100644 (file)
@@ -153,7 +153,7 @@ void debug_printf(const char *fmt, ...)
 /**
  * \brief Function to do the actual printing based on the type of capability
  */
-STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all cap types");
+STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all cap types");
 int debug_print_cap(char *buf, size_t len, struct capability *cap)
 {
     switch (cap->type) {
@@ -381,6 +381,14 @@ int debug_print_cap(char *buf, size_t len, struct capability *cap)
                         " core_local_id 0x%" PRIx32 ")", cap->u.id.coreid,
                         cap->u.id.core_local_id);
 
+    case ObjType_ProcessManager:
+        return snprintf(buf, len, "Process manager capability");
+
+    case ObjType_Domain:
+        return snprintf(buf, len, "Domain capability (coreid 0x%" PRIxCOREID
+                        " core_local_id 0x%" PRIx32 ")", cap->u.domain.coreid,
+                        cap->u.domain.core_local_id);
+
     case ObjType_PerfMon:
         return snprintf(buf, len, "PerfMon cap");
 
index 0278c6a..08fda8d 100644 (file)
@@ -170,7 +170,7 @@ mdb_dump_all_the_things(void)
     mdb_dump(mdb_root, 0);
 }
 
-STATIC_ASSERT(48 == ObjType_Num, "Knowledge of all cap types");
+STATIC_ASSERT(50 == ObjType_Num, "Knowledge of all cap types");
 static void print_cte(struct cte *cte, char *indent_buff)
 {
     struct mdbnode *node = N(cte);
index 3ce0112..5bdb8ba 100644 (file)
@@ -83,6 +83,16 @@ errval_t initialize_monitor(struct spawninfo *si)
         return err_push(err, INIT_ERR_COPY_IPI);
     }
 
+    /* Give monitor the ProcessManager capability */
+    dest.cnode = si->taskcn;
+    dest.slot = TASKCN_SLOT_PROC_MNG;
+    src.cnode = cnode_task;
+    src.slot = TASKCN_SLOT_PROC_MNG;
+    err = cap_copy(dest, src);
+    if (err_is_fail(err)) {
+        return err_push(err, INIT_ERR_COPY_PROC_MNG_CAP);
+    }
+
     /* Give monitor modulecn */
     dest.cnode = si->rootcn;
     dest.slot  = ROOTCN_SLOT_MODULECN;
index ada09b6..7d73698 100644 (file)
@@ -59,6 +59,18 @@ static errval_t set_special_caps(struct spawninfo *si, const char *pname)
         }
        }
 
+    if (!strcmp(name, "proc_mgmt")) {
+        // Pass ProcessManager cap.
+        dest.cnode = si->taskcn;
+        dest.slot = TASKCN_SLOT_PROC_MNG;
+        src = cap_procmng;
+        err = cap_copy(dest, src);
+        if (err_is_fail(err)) {
+            DEBUG_ERR(err, "Can not give ProcessManager cap");
+            return err_push(err, SPAWN_ERR_COPY_PROC_MNG_CAP);
+        }
+    }
+
 #ifdef __k1om__
     if (!strcmp(name, "xeon_phi")) {
         dest.cnode = si->taskcn;
index d338eb6..d3d3e1e 100644 (file)
@@ -150,6 +150,29 @@ static void export_cb(void *st, errval_t err, iref_t iref)
     if (err_is_fail(err)) {
         USER_PANIC_ERR(err, "nameservice_register failed");
     }
+
+    // Try to create a few domains?
+    // TODO(razvan): Remove this.
+    size_t num_domains = 5;
+    struct capref domain_caps[num_domains];
+    for (size_t i = 1; i <= num_domains; ++i) {
+        err = slot_alloc(&domain_caps[i]);
+        if (err_is_fail(err)) {
+            USER_PANIC_ERR(err, "slot_alloc domain_cap");
+        }
+        err = cap_retype(domain_caps[i], cap_procmng, 0, ObjType_Domain, 0, 1);
+        if (err_is_fail(err)) {
+            USER_PANIC_ERR(err, "cap_retype domain_cap from cap_procmng");
+        }
+        struct capability ret;
+        err = debug_cap_identify(domain_caps[i], &ret);
+        if (err_is_fail(err)) {
+            USER_PANIC_ERR(err, "cap identify domain_cap");
+        }
+        debug_printf("Process manager successfully created domain { .coreid=%u,"
+                     " .core_local_id=%u } (%lu/%lu)\n", ret.u.domain.coreid,
+                     ret.u.domain.core_local_id, i, num_domains);
+    }
 }
 
 static errval_t connect_cb(void *st, struct proc_mgmt_binding *b)