[hypervisor] Traps should not cancel other packets
Traps should only cancel port packets that are associated with the trap
on tear-down, and not cancel other packets with the same key.
ZX-4221 #done
Change-Id: I1da9b0cd051db58bb03a7d2571819f00e27b5408
diff --git a/zircon/kernel/lib/hypervisor/trap_map.cpp b/zircon/kernel/lib/hypervisor/trap_map.cpp
index b207df7..8e34b09 100644
--- a/zircon/kernel/lib/hypervisor/trap_map.cpp
+++ b/zircon/kernel/lib/hypervisor/trap_map.cpp
@@ -34,7 +34,7 @@
}
PortPacket* BlockingPortAllocator::Alloc() {
- return arena_.New(nullptr, this);
+ return arena_.New(this /* handle */, this /* allocator */);
}
void BlockingPortAllocator::Free(PortPacket* port_packet) {
@@ -44,15 +44,13 @@
Trap::Trap(uint32_t kind, zx_gpaddr_t addr, size_t len, fbl::RefPtr<PortDispatcher> port,
uint64_t key)
- : kind_(kind), addr_(addr), len_(len), port_(ktl::move(port)), key_(key) {
- (void) key_;
-}
+ : kind_(kind), addr_(addr), len_(len), port_(ktl::move(port)), key_(key) {}
Trap::~Trap() {
if (port_ == nullptr) {
return;
}
- port_->CancelQueued(nullptr /* handle */, key_);
+ port_->CancelQueued(&port_allocator_ /* handle */, key_);
}
zx_status_t Trap::Init() {
diff --git a/zircon/kernel/object/port_dispatcher.cpp b/zircon/kernel/object/port_dispatcher.cpp
index dc74218..0c0bfef 100644
--- a/zircon/kernel/object/port_dispatcher.cpp
+++ b/zircon/kernel/object/port_dispatcher.cpp
@@ -82,11 +82,6 @@
PortPacket::PortPacket(const void* handle, PortAllocator* allocator)
: packet{}, handle(handle), observer(nullptr), allocator(allocator) {
// Note that packet is initialized to zeros.
- if (handle) {
- // Currently |handle| is only valid if the packets are not ephemeral
- // which means that PortObserver always uses the kernel heap.
- DEBUG_ASSERT(allocator == nullptr);
- }
}
PortObserver::PortObserver(uint32_t type, const Handle* handle, fbl::RefPtr<PortDispatcher> port,
diff --git a/zircon/system/utest/hypervisor/guest.cpp b/zircon/system/utest/hypervisor/guest.cpp
index 160799ef..f75c2d7 100644
--- a/zircon/system/utest/hypervisor/guest.cpp
+++ b/zircon/system/utest/hypervisor/guest.cpp
@@ -77,20 +77,19 @@
typedef struct test {
bool supported = false;
bool interrupts_enabled = false;
+ uintptr_t host_addr = 0;
zx::vmo vmo;
- uintptr_t host_addr;
zx::guest guest;
zx::vmar vmar;
zx::vcpu vcpu;
-} test_t;
-static bool teardown(test_t* test) {
- BEGIN_HELPER;
- ASSERT_EQ(zx::vmar::root_self()->unmap(test->host_addr, VMO_SIZE), ZX_OK);
- return true;
- END_HELPER;
-}
+ ~test() {
+ if (host_addr != 0) {
+ zx::vmar::root_self()->unmap(host_addr, VMO_SIZE);
+ }
+ }
+} test_t;
// TODO(MAC-246): Convert to C++ FIDL interface.
static zx_status_t get_sysinfo(zx::channel* sysinfo) {
@@ -139,6 +138,8 @@
#endif // __aarch64__
static bool setup(test_t* test, const char* start, const char* end) {
+ BEGIN_HELPER;
+
ASSERT_EQ(zx::vmo::create(VMO_SIZE, 0, &test->vmo), ZX_OK);
ASSERT_EQ(
zx::vmar::root_self()->map(0, test->vmo, 0, VMO_SIZE, kHostMapFlags, &test->host_addr),
@@ -154,7 +155,7 @@
test->supported = status != ZX_ERR_NOT_SUPPORTED;
if (!test->supported) {
fprintf(stderr, "Guest creation not supported\n");
- return teardown(test);
+ return true;
}
ASSERT_EQ(status, ZX_OK);
@@ -180,11 +181,11 @@
test->supported = status != ZX_ERR_NOT_SUPPORTED;
if (!test->supported) {
fprintf(stderr, "VCPU creation not supported\n");
- return teardown(test);
+ return true;
}
ASSERT_EQ(status, ZX_OK);
- return true;
+ END_HELPER;
}
static bool setup_and_interrupt(test_t* test, const char* start, const char* end) {
@@ -261,7 +262,6 @@
}
ASSERT_TRUE(resume_and_clean_exit(&test));
- ASSERT_TRUE(teardown(&test));
END_TEST;
}
@@ -369,7 +369,6 @@
EXPECT_EQ(vcpu_state.rflags, (1u << 0) | (1u << 18));
#endif // __x86_64__
- ASSERT_TRUE(teardown(&test));
END_TEST;
}
@@ -399,8 +398,6 @@
EXPECT_EQ(vcpu_state.rax, kInterruptVector);
#endif
- ASSERT_TRUE(teardown(&test));
-
END_TEST;
}
@@ -424,7 +421,6 @@
EXPECT_EQ(packet.type, ZX_PKT_TYPE_GUEST_MEM);
ASSERT_TRUE(resume_and_clean_exit(&test));
- ASSERT_TRUE(teardown(&test));
END_TEST;
}
@@ -455,8 +451,6 @@
EXPECT_EQ(packet.type, ZX_PKT_TYPE_GUEST_BELL);
EXPECT_EQ(packet.guest_bell.addr, TRAP_ADDR);
- ASSERT_TRUE(teardown(&test));
-
END_TEST;
}
@@ -483,14 +477,50 @@
EXPECT_EQ(packet.type, ZX_PKT_TYPE_GUEST_MEM);
EXPECT_EQ(packet.guest_mem.addr, EXIT_TEST_ADDR);
- ASSERT_TRUE(teardown(&test));
-
// The guest in test is destructed with one packet still queued on the
// port. This should work correctly.
END_TEST;
}
+// Test for ZX-4221.
+static bool guest_set_trap_with_bell_and_user() {
+ BEGIN_TEST;
+
+ zx::port port;
+ ASSERT_EQ(zx::port::create(0, &port), ZX_OK);
+
+ // Queue a packet with the same key as the trap.
+ zx_port_packet packet = {};
+ packet.key = kTrapKey;
+ packet.type = ZX_PKT_TYPE_USER;
+ ASSERT_EQ(port.queue(&packet), ZX_OK);
+
+ // Force guest to be released and cancel all packets associated with traps.
+ {
+ test_t test;
+ ASSERT_TRUE(setup(&test, guest_set_trap_start, guest_set_trap_end));
+ if (!test.supported) {
+ // The hypervisor isn't supported, so don't run the test.
+ return true;
+ }
+
+ // Trap on access of TRAP_ADDR.
+ ASSERT_EQ(test.guest.set_trap(ZX_GUEST_TRAP_BELL, TRAP_ADDR, PAGE_SIZE, port, kTrapKey),
+ ZX_OK);
+
+ ASSERT_EQ(test.vcpu.resume(&packet), ZX_OK);
+ EXPECT_EQ(packet.type, ZX_PKT_TYPE_GUEST_MEM);
+ EXPECT_EQ(packet.guest_mem.addr, EXIT_TEST_ADDR);
+ }
+
+ ASSERT_EQ(port.wait(zx::time::infinite(), &packet), ZX_OK);
+ EXPECT_EQ(packet.key, kTrapKey);
+ EXPECT_EQ(packet.type, ZX_PKT_TYPE_USER);
+
+ END_TEST;
+}
+
#ifdef __aarch64__
static bool vcpu_wfi() {
@@ -504,7 +534,6 @@
}
ASSERT_TRUE(resume_and_clean_exit(&test));
- ASSERT_TRUE(teardown(&test));
END_TEST;
}
@@ -538,7 +567,6 @@
ASSERT_EQ(test.vcpu.interrupt(kInterruptVector + 1), ZX_OK);
ASSERT_TRUE(resume_and_clean_exit(&test));
- ASSERT_TRUE(teardown(&test));
END_TEST;
}
@@ -560,8 +588,6 @@
EXPECT_EQ(packet.guest_mem.read, false);
EXPECT_EQ(packet.guest_mem.data, 0);
- ASSERT_TRUE(teardown(&test));
-
END_TEST;
}
@@ -576,7 +602,6 @@
}
ASSERT_TRUE(resume_and_clean_exit(&test));
- ASSERT_TRUE(teardown(&test));
END_TEST;
}
@@ -598,8 +623,6 @@
EXPECT_EQ(packet.guest_mem.read, false);
EXPECT_EQ(packet.guest_mem.data, 0);
- ASSERT_TRUE(teardown(&test));
-
END_TEST;
}
@@ -629,8 +652,6 @@
// TODO(MAC-225): Check that the exception is cleared.
- ASSERT_TRUE(teardown(&test));
-
END_TEST;
}
@@ -654,7 +675,6 @@
zx_vcpu_state_t vcpu_state;
ASSERT_EQ(test.vcpu.read_state(ZX_VCPU_STATE, &vcpu_state, sizeof(vcpu_state)), ZX_OK);
EXPECT_EQ(vcpu_state.rax, kNmiVector);
- ASSERT_TRUE(teardown(&test));
END_TEST;
}
@@ -683,8 +703,6 @@
// TODO(MAC-225): Check that the interrupt is queued.
- ASSERT_TRUE(teardown(&test));
-
END_TEST;
}
@@ -708,7 +726,6 @@
zx_vcpu_state_t vcpu_state;
ASSERT_EQ(test.vcpu.read_state(ZX_VCPU_STATE, &vcpu_state, sizeof(vcpu_state)), ZX_OK);
EXPECT_EQ(vcpu_state.rax, kExceptionVector);
- ASSERT_TRUE(teardown(&test));
END_TEST;
}
@@ -724,7 +741,6 @@
}
ASSERT_TRUE(resume_and_clean_exit(&test));
- ASSERT_TRUE(teardown(&test));
END_TEST;
}
@@ -740,7 +756,6 @@
}
ASSERT_TRUE(resume_and_clean_exit(&test));
- ASSERT_TRUE(teardown(&test));
END_TEST;
}
@@ -762,8 +777,6 @@
// Check that cr0 has the NE bit set when read.
EXPECT_TRUE(vcpu_state.rax & X86_CR0_NE);
- ASSERT_TRUE(teardown(&test));
-
END_TEST;
}
@@ -786,8 +799,6 @@
EXPECT_EQ(vcpu_state.rcx, 2u);
#endif
- ASSERT_TRUE(teardown(&test));
-
END_TEST;
}
@@ -802,7 +813,6 @@
}
ASSERT_TRUE(resume_and_clean_exit(&test));
- ASSERT_TRUE(teardown(&test));
END_TEST;
}
@@ -818,7 +828,6 @@
}
ASSERT_TRUE(resume_and_clean_exit(&test));
- ASSERT_TRUE(teardown(&test));
END_TEST;
}
@@ -834,7 +843,6 @@
}
ASSERT_TRUE(resume_and_clean_exit(&test));
- ASSERT_TRUE(teardown(&test));
END_TEST;
}
@@ -857,8 +865,6 @@
const uint64_t kVmCallNoSys = -1000;
EXPECT_EQ(vcpu_state.rax, kVmCallNoSys);
- ASSERT_TRUE(teardown(&test));
-
END_TEST;
}
@@ -898,8 +904,6 @@
// Guest successfully runs again
ASSERT_TRUE(resume_and_clean_exit(&test));
- ASSERT_TRUE(teardown(&test));
-
END_TEST;
}
@@ -923,7 +927,6 @@
EXPECT_EQ(packet.guest_io.port, TRAP_PORT);
ASSERT_TRUE(resume_and_clean_exit(&test));
- ASSERT_TRUE(teardown(&test));
END_TEST;
}
@@ -937,6 +940,7 @@
RUN_TEST(guest_set_trap_with_mem)
RUN_TEST(guest_set_trap_with_bell)
RUN_TEST(guest_set_trap_with_bell_drop)
+RUN_TEST(guest_set_trap_with_bell_and_user)
#if __aarch64__
RUN_TEST(vcpu_wfi)
RUN_TEST(vcpu_wfi_pending_interrupt)