Skip to content

lazy Scheduling Context rebind + improve tool <-> monitor ABI#439

Open
dreamliner787-9 wants to merge 2 commits intoseL4:mainfrom
au-ts:lazy_sc_rebind
Open

lazy Scheduling Context rebind + improve tool <-> monitor ABI#439
dreamliner787-9 wants to merge 2 commits intoseL4:mainfrom
au-ts:lazy_sc_rebind

Conversation

@dreamliner787-9
Copy link
Contributor

@dreamliner787-9 dreamliner787-9 commented Mar 15, 2026

Applied seL4/seL4#523 to workaround seL4/seL4#1617, and improved tool <-> monitor ABI by creating a metadata struct per PD, rather than adding a new symbol for every type of metadata.

@dreamliner787-9 dreamliner787-9 changed the title monitor: lazy Scheduling Context rebind lazy Scheduling Context rebind + improve tool <-> monitor ABI Mar 16, 2026
Copy link

@Indanz Indanz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First, this really should be two separate commits, not lumped together like this.

Secondly, I'm missing creating a notifications object for passive servers that don't otherwise have one already, and binding the SC to the notification object if the PD is passive.

That last thing is really the only change you need compared to active PDs for setup.

Only other change needed is that you bind the SC when restarting the task, but I don't think Microkit does that yet, but rust-sel4 does I think.

Comment on lines +896 to +918
/* If there are passive PDs in the system, lazily rebind it's Scheduling Context and resume TCB.
* To workaround https://github.com/seL4/seL4/issues/1617 by applying https://github.com/seL4/seL4/pull/523
*/
for (unsigned idx = 0; idx < pd_metadata_len; idx++) {
if (pd_metadata[idx].passive) {
seL4_Error err = seL4_SchedContext_Bind(BASE_SCHED_CONTEXT_CAP + idx, BASE_NOTIFICATION_CAP + idx);
if (err != seL4_NoError) {
puts("MON|ERROR: could not bind scheduling context to notification object\n");
continue;
}

err = seL4_TCB_Resume(BASE_PD_TCB_CAP + idx);
if (err != seL4_NoError) {
puts("MON|ERROR: could not bind resume passive PD TCB\n");
continue;
}

puts("MON|INFO: PD '");
puts(pd_metadata[idx].name);
puts("' is now passive!\n");
}
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to do this resume and you can bind the SC to the notification when you create the notification for a passive thread. This feels like the wrong place for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to do this resume

I think this ties in to my reply below.

and you can bind the SC to the notification when you create the notification for a passive thread. This feels like the wrong place for that.

We did consider binding the PD's Notification to the SC in the initialiser by adding a passive: bool to the TCB spec object. But we felt like the initialiser should not be concerned with this detail.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We did consider binding the PD's Notification to the SC in the initialiser by adding a passive: bool to the TCB spec object. But we felt like the initialiser should not be concerned with this detail.

But this is init code, of course it belongs in the initialiser. These details are exactly the kind of things it should be concerned about. And if you do it in the loader, you also automatically fix any race because you can do the operations in the correct order. Now you add subtle ad hoc code to work around the ordering problem, without being explicit about it. That's a bad sign.

You already have pd.passive property anyway, passing that info to the loader only seems prudent.

Comment on lines +982 to +983
// Passive PDs are resumed by the Monitor
pd_tcb.extra.resume = !pd.passive;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Indan, we intended for passive PDs to be resumed by the monitor, because we don't want them to start processing events before being converted to passive. Which can happen on multi-core.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There isn't any race condition, other than a harmless corner case of possibly handling the very first IPC call with the NF's SC instead of the caller's SC.

But that's only true if the TCB is running while you bind SC's. Normally you would do that only after setup. That is, if you do the seL4_TCB_WriteRegisters with resume == true after the SC and NF binding, there is no race.

Improved tool <-> monitor ABI by creating a metadata struct per PD,
rather than adding a new symbol for every type of metadata.

Signed-off-by: Bill Nguyen <bill.nguyen@unsw.edu.au>
@dreamliner787-9
Copy link
Contributor Author

First, this really should be two separate commits, not lumped together like this.

Yes I agree, will split them up.

Secondly, I'm missing creating a notifications object for passive servers that don't otherwise have one already, and binding the SC to the notification object if the PD is passive.

All PDs have a notification object in their capDL spec so they will be created automatically by the initialiser.

// Step 3-7 Create endpoint object for the PD if it has children or can receive PPCs, else it will be a notification
let pd_ntfn_obj_id = capdl_util_make_ntfn_obj(&mut spec_container, &pd.name);
let pd_ntfn_cap = capdl_util_make_ntfn_cap(pd_ntfn_obj_id, true, true, 0);
let mut pd_ep_obj_id: Option<ObjectId> = None;
pd_id_to_ntfn_id.insert(pd_global_idx, pd_ntfn_obj_id);
if pd.needs_ep(pd_global_idx, &system.channels) {
pd_ep_obj_id = Some(capdl_util_make_endpoint_obj(
&mut spec_container,
&pd.name,
false,
));
let pd_ep_cap =
capdl_util_make_endpoint_cap(pd_ep_obj_id.unwrap(), true, true, true, 0);
pd_id_to_ep_id.insert(pd_global_idx, pd_ep_obj_id.unwrap());
caps_to_insert_to_pd_cspace
.push(capdl_util_make_cte(PD_INPUT_CAP_IDX as u32, pd_ep_cap));
} else {
let pd_ntfn_cap_clone = pd_ntfn_cap.clone();
caps_to_insert_to_pd_cspace.push(capdl_util_make_cte(
PD_INPUT_CAP_IDX as u32,
pd_ntfn_cap_clone,
));
}
caps_to_bind_to_tcb.push(capdl_util_make_cte(
TcbBoundSlot::BoundNotification as u32,
pd_ntfn_cap,
));

Only other change needed is that you bind the SC when restarting the task, but I don't think Microkit does that yet, but rust-sel4 does I think.

Yes, the capDL initialiser configure SCs and bind them to TCBs for us, so we only need to bind Notification to SC for passive PDs.

Signed-off-by: Bill Nguyen <bill.nguyen@unsw.edu.au>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants