Skip to content
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

Add ISA test #29

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open

Add ISA test #29

wants to merge 7 commits into from

Conversation

rmn30
Copy link
Collaborator

@rmn30 rmn30 commented Mar 10, 2023

This adds a test that attempts to trigger various ISA corner cases and increase test coverage.

@rmn30 rmn30 force-pushed the isa_test branch 2 times, most recently from f11cf92 to 44b3b0b Compare March 10, 2023 18:10
tests/isa-test.cc Outdated Show resolved Hide resolved
tests/isa-test.cc Show resolved Hide resolved
tests/isa-test.cc Outdated Show resolved Hide resolved
tests/isa-test.cc Outdated Show resolved Hide resolved
tests/isa-test.cc Outdated Show resolved Hide resolved
tests/isa-test.cc Outdated Show resolved Hide resolved
tests/isa-test.cc Outdated Show resolved Hide resolved
[[cheri::interrupt_state(disabled)]] void *get_interrupts_disabled_sentry()
{
void *returnCap;
asm volatile("cjal %0, 4" : "=C"(returnCap));
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is beautifully horrifying, can you add a comment explaining it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is just a jump and link to the next instruction, putting the link cap in returnCap. I guess might be better written with local label rather than hardcoded offset?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Probably "cjal %0, 1f;\n1:" is the right thing to do, but if you want to be extra horrifying, there's GCC's asm goto... :D

If we ever have a programming guide, we should point to this example as something really contra-indicated. Would you object to a comment here and on the similar method below that this is deliberately unsafe handling of a dangerous thing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Or maybe even simplified to &get_interrupts_disabled_sentry given the way the ABI works.

tests/isa-test.cc Outdated Show resolved Hide resolved
Copy link
Collaborator

@nwf-msr nwf-msr left a comment

Choose a reason for hiding this comment

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

Generally, this is really great. The combinator approach works out really nicely, even if C++ will never be as nice as Haskell. ;)

A small pile of nits, but nothing big.

tests/isa-test.cc Outdated Show resolved Hide resolved
[[cheri::interrupt_state(disabled)]] void *get_interrupts_disabled_sentry()
{
void *returnCap;
asm volatile("cjal %0, 4" : "=C"(returnCap));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Probably "cjal %0, 1f;\n1:" is the right thing to do, but if you want to be extra horrifying, there's GCC's asm goto... :D

If we ever have a programming guide, we should point to this example as something really contra-indicated. Would you object to a comment here and on the similar method below that this is deliberately unsafe handling of a dangerous thing?

* We call this with values we expect to fault and want to know the address
* of the faulting instruction. Since it is so simple it will have no
* prelude so we can use the address of the function as the address of the
* store. Obviously we can't allow it to be inlined.
Copy link
Collaborator

Choose a reason for hiding this comment

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

  1. I'm not sure about the names; these are not intrinsically going to fault, they're just used that way ("He's not evil, he's just written that way")... maybe perform_store or something like that?

  2. Perhaps this and faulting_load should be in assembler rather than relying on the (sensible, probably not going to change, but still not contractual) behavior of the compiler?

* flexible ways before attempting tests.
*/
template<class T>
using CapabilityFilter = Capability<T> (*)(Capability<T>);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This really is Haskell in C++! 👍

*/
void do_load_test(CauseCode expectedFault,
CapabilityFilter<int *> baseFilter,
size_t anExpectedMCause = MCauseCheri)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Very minor nit, but maybe the argument order should be baseFilter, expectedFault, anExpectedMCause, so that it's read as something like "I expect a load with this filter to cause this fault and this code"?

tests/isa-test.cc Outdated Show resolved Hide resolved
// Storing untagged cap via data-only cap is allowed.
do_store_test(
std::nullopt,
permission_filter<PermissionSet{Permission::Load, Permission::Store}>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not identity_filter?

* nops so that we can test things like half of an instruction being in
* bounds. Clang doesn't seem to emit a prelude for this function. If it
* does (e.g. at -O0) our expected error PC calculations will be wrong due
* to alignment.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe these, too, should be in assembler?

rmn30 and others added 5 commits July 1, 2024 15:23
This specifically aims to test features that are not likely to occur
in normal operation, such as exceptions. Hits quite a few potential
corner cases but some are best tested in bare metal assembly and can't
be easily tested in an RTOS tests.
Co-authored-by: Nathaniel Filardo <[email protected]>
The static casts in the pointer DebugFormatArgumentAdapters prevented
function pointers from being printed as the compiler does not permit
static casts from function pointer to void*. Removing them seems to
work fine so not sure what they were there for.
Still some TODOs to resolve.
// sentry {}", reinterpret_cast<void*>(interruptsDisabledSentry.get()));
// TEST(interruptsDisabledSentry.type() == 2,
// "Expected type 2 but got {}",
// interruptsDisabledSentry.type());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there no good way to get these?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I got the linker error in the comment. Suspect it might be a bug @davidchisnall ?

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.

5 participants