-
Notifications
You must be signed in to change notification settings - Fork 217
Add read_panic_message kipc
#2313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5ba535a
1313935
07460ec
68a2fb7
2ab7a43
8a221c1
425c221
3748fda
09fe93f
e468ef7
7b4a6bb
2d9b1d2
fb2af3f
5193057
1890e0a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,7 @@ use unwrap_lite::UnwrapLite; | |
| use crate::arch; | ||
| use crate::err::UserError; | ||
| use crate::task::{current_id, ArchState, NextTask, Task}; | ||
| use crate::umem::USlice; | ||
| use crate::umem::{safe_copy, USlice}; | ||
|
|
||
| /// Message dispatcher. | ||
| pub fn handle_kernel_message( | ||
|
|
@@ -43,6 +43,9 @@ pub fn handle_kernel_message( | |
| Ok(Kipcnum::FindFaultedTask) => { | ||
| find_faulted_task(tasks, caller, args.message?, args.response?) | ||
| } | ||
| Ok(Kipcnum::ReadPanicMessage) => { | ||
| read_panic_message(tasks, caller, args.message?, args.response?) | ||
| } | ||
|
|
||
| _ => { | ||
| // Task has sent an unknown message to the kernel. That's bad. | ||
|
|
@@ -507,3 +510,75 @@ fn find_faulted_task( | |
| .set_send_response_and_length(0, response_len); | ||
| Ok(NextTask::Same) | ||
| } | ||
|
|
||
| fn read_panic_message( | ||
| tasks: &mut [Task], | ||
| caller: usize, | ||
| message: USlice<u8>, | ||
| response: USlice<u8>, | ||
| ) -> Result<NextTask, UserError> { | ||
| let index: u32 = deserialize_message(&tasks[caller], message)?; | ||
| let index = index as usize; | ||
| let Some(task) = tasks.get(index) else { | ||
| return Err(UserError::Unrecoverable(FaultInfo::SyscallUsage( | ||
| UsageError::TaskOutOfRange, | ||
| ))); | ||
| }; | ||
|
|
||
| // Make sure the task is actually panicked. | ||
| let TaskState::Faulted { | ||
| fault: FaultInfo::Panic, | ||
| .. | ||
| } = task.state() | ||
| else { | ||
hawkw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return Err(UserError::Recoverable( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you have any code that uses this API yet? I suspect this error is going to be FWIW all the other errors in this implementation look right to me.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I was imagining we might see this error in the event that a task responsible for collecting panic messages (i.e., If we don't end up implementing that behavior in the supervisor, and instead make it wait to be informed that a panic message has been collected before restarting the faulted task, it might make more sense to make this case a fault for the caller. But, the approach we discussed in #2309 (comment) made me feel inclined to go down the path of treating the restart cooldown in
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I find this convincing, I hadn't considered which task was likely to be calling this API. |
||
| abi::ReadPanicMessageError::TaskNotPanicked as u32, | ||
| NextTask::Same, | ||
| )); | ||
| }; | ||
|
|
||
| let Ok(message) = task.save().as_panic_args().message else { | ||
| // There's really only one reason that `as_panic_args().message` would | ||
| // be an error. Because it's just a `USlice<u8>`, it can't be | ||
| // misaligned, so the only possible invalid slice here is one whose | ||
| // length exceeds the size of the address space, so that `base + len` | ||
| // would overflow. | ||
| // | ||
| // But, we shouldn't fault the *caller* over that; they didn't do it! | ||
| return Err(UserError::Recoverable( | ||
hawkw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| abi::ReadPanicMessageError::BadPanicBuffer as u32, | ||
| NextTask::Same, | ||
| )); | ||
| }; | ||
|
|
||
| // Note that if the panic was recorded by `userlib`'s panic handler, it will | ||
| // never exceed 128 bytes in length, and if the caller requested this kipc | ||
| // using the `userlib::ipc::read_panic_message()` wrapper, then the caller's | ||
| // buffer will always be exactly 128 bytes long. However, we can't rely on | ||
| // that here, as either task *could* be an arbitrary binary that wasn't | ||
| // compiled with the Hubris userlib, so we need to be safe regardless. | ||
hawkw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| match safe_copy(tasks, index, message, caller, response) { | ||
| Ok(len) => { | ||
| // Ladies and gentlemen...we got him! | ||
| tasks[caller] | ||
| .save_mut() | ||
| .set_send_response_and_length(0, len); | ||
|
|
||
| Ok(NextTask::Same) | ||
| } | ||
| Err(crate::err::InteractFault { | ||
| dst: Some(fault), .. | ||
| }) => { | ||
| // If the caller's buffer was invalid, they take a fault. | ||
| Err(UserError::Unrecoverable(fault)) | ||
| } | ||
| Err(_) => { | ||
| // Source region was bad, but it's not the caller's fault; give them | ||
| // a recoverable error. | ||
| Err(UserError::Recoverable( | ||
| abi::ReadPanicMessageError::BadPanicBuffer as u32, | ||
| NextTask::Same, | ||
| )) | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.