blob: 52fceeb0e2ebeba076160777cab26645fa63af39 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/lazy_init/lazy_init.h>
#include <lib/standalone-test/standalone.h>
#include <lib/zx/channel.h>
#include <lib/zx/resource.h>
#include <lib/zx/vmo.h>
#include <zircon/assert.h>
#include <zircon/compiler.h>
#include <zircon/processargs.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/log.h>
#include <zircon/types.h>
#include <map>
#include <string>
#include <string_view>
namespace standalone {
namespace {
zx::resource root_resource, ioport_resource, irq_resource, mmio_resource, system_resource;
constexpr std::string_view kMissingRootResource =
"*** standalone-test must run directly from userboot ***\n";
constexpr std::string_view kStartupMessage =
"*** Running standalone test directly from userboot ***\n";
lazy_init::LazyInit<std::map<std::string, zx::vmo, std::less<>>> gVmos;
lazy_init::LazyInit<std::map<std::string, zx::channel, std::less<>>> gNsDir;
} // namespace
zx::unowned_vmo GetVmo(std::string_view name) {
auto it = gVmos->find(name);
if (it == gVmos->end()) {
return {};
}
return it->second.borrow();
}
zx::unowned_channel GetNsDir(std::string_view name) {
auto it = gNsDir->find(name);
if (it == gNsDir->end()) {
return {};
}
return it->second.borrow();
}
zx::unowned_resource GetRootResource() {
ZX_ASSERT_MSG(root_resource, "standalone test didn't receive root resource");
return root_resource.borrow();
}
zx::unowned_resource GetIoportResource() {
ZX_ASSERT_MSG(ioport_resource, "standalone test didn't receive Ioport resource");
return ioport_resource.borrow();
}
zx::unowned_resource GetIrqResource() {
ZX_ASSERT_MSG(irq_resource, "standalone test didn't receive IRQ resource");
return irq_resource.borrow();
}
zx::unowned_resource GetMmioResource() {
ZX_ASSERT_MSG(mmio_resource, "standalone test didn't receive MMIO resource");
return mmio_resource.borrow();
}
zx::unowned_resource GetSystemResource() {
ZX_ASSERT_MSG(system_resource, "standalone test didn't receive system resource");
return system_resource.borrow();
}
// This overrides a weak definition in libc, replacing the hook that's
// ordinarily defined by fdio. The retain attribute makes sure that linker
// doesn't decide it can elide this definition and let libc use its weak one.
extern "C" [[gnu::retain]] __EXPORT void __libc_extensions_init(uint32_t count,
zx_handle_t handle[],
uint32_t info[],
uint32_t name_count, char** names) {
gVmos.Initialize();
gNsDir.Initialize();
auto take_handle = [&handle, &info](size_t index) {
info[index] = 0;
return std::exchange(handle[index], ZX_HANDLE_INVALID);
};
for (unsigned n = 0; n < count; n++) {
switch (PA_HND_TYPE(info[n])) {
case PA_RESOURCE:
if (PA_HND_ARG(info[n]) == 0) {
root_resource.reset(take_handle(n));
}
break;
case PA_IOPORT_RESOURCE:
ioport_resource.reset(take_handle(n));
break;
case PA_IRQ_RESOURCE:
irq_resource.reset(take_handle(n));
break;
case PA_MMIO_RESOURCE:
mmio_resource.reset(take_handle(n));
break;
case PA_SYSTEM_RESOURCE:
system_resource.reset(take_handle(n));
break;
case PA_NS_DIR: {
uint32_t name_index = PA_HND_ARG(info[n]);
if (name_index >= name_count) {
continue;
}
gNsDir->try_emplace(std::string(names[name_index]), take_handle(n));
break;
}
case PA_VMO_BOOTDATA:
case PA_VMO_BOOTFS:
case PA_VMO_KERNEL_FILE: {
// Store it in the map by VMO name for StandaloneGetVmo to find later.
char vmo_name[ZX_MAX_NAME_LEN];
zx_status_t status =
zx_object_get_property(handle[n], ZX_PROP_NAME, vmo_name, sizeof(vmo_name));
if (status == ZX_OK) {
zx::vmo vmo{take_handle(n)};
std::string_view prop(vmo_name, sizeof(vmo_name));
std::string name(prop.substr(0, prop.find_first_of('\0')));
gVmos->try_emplace(std::move(name), std::move(vmo));
}
break;
}
}
}
if (!root_resource.is_valid()) {
zx_debug_write(kMissingRootResource.data(), kMissingRootResource.size());
__builtin_trap();
}
// Eagerly write a message. This ensures that every standalone test links
// in the standalone-io code that overrides functions like write from libc.
LogWrite(kStartupMessage);
}
} // namespace standalone