blob: 3ed9ca44fa35820c0185e90165d681aeb9f69df5 [file]
// Copyright 2023 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <lib/arch/asm.h>
#include <lib/boot-options/boot-options.h>
#include <lib/code-patching/self-test.h>
#include <lib/elfldltl/machine.h>
#include <lib/uart/all.h>
#include <stdlib.h>
#include <zircon/assert.h>
#include <phys/address-space.h>
#include <phys/handoff/boot-constants.h>
#include <phys/handoff/handoff.h>
#include <phys/handoff/zircon-abi-spec.h>
extern "C" constexpr ZirconAbiSpec kZirconAbiSpec = {
.machine_stack =
{
.size_bytes = 0x1000,
.lower_guard_size_bytes = 0x1000,
.upper_guard_size_bytes = 0x1000,
},
#if __has_feature(shadow_call_stack)
.shadow_call_stack =
{
.size_bytes = 0x1000,
.lower_guard_size_bytes = 0x1000,
.upper_guard_size_bytes = 0x1000,
},
#endif
#if __has_feature(safe_stack)
.unsafe_stack =
{
.size_bytes = 0x1000,
.lower_guard_size_bytes = 0x1000,
.upper_guard_size_bytes = 0x1000,
},
#endif
.boot_constants{kBootConstants},
.kernel_aspace_base = AddressSpace::kUpperVirtualAddressRangeStart,
.kernel_aspace_size =
(ktl::numeric_limits<uint64_t>::max() - AddressSpace::kUpperVirtualAddressRangeStart) + 1,
};
PhysHandoff* gPhysHandoff = nullptr;
extern "C" arch::AsmLabel __ehdr_start; // NOLINT(bugprone-reserved-identifier)
namespace {
void CheckBootConstants() {
// Access the field via its physical address (still identity-mapped) to check
// that it's really the right physical address.
uintptr_t load_bias =
arch::kAsmLabelAddress<__ehdr_start> - kBootConstants.kernel_physical_load_address;
const uintptr_t* physical_ptr = reinterpret_cast<const uintptr_t*>(
reinterpret_cast<uintptr_t>(&kBootConstants.kernel_physical_load_address) - load_bias);
ZX_ASSERT(*physical_ptr == kBootConstants.kernel_physical_load_address);
}
} // namespace
[[clang::cfi_unchecked_callee]] void PhysbootHandoff(PhysHandoff* handoff) {
// Check that the stack is aligned.
uintptr_t stack_pointer = reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
ZX_ASSERT((stack_pointer & (elfldltl::AbiTraits<>::kStackAlignment<uintptr_t> - 1)) == 0);
// Temporary hand-off pointer dereferencing checks that this is set.
gPhysHandoff = handoff;
__asm__ volatile(
R"""(
.pushsection .rodata.kBootConstants, "a", %%progbits
.balign %cc[alignment]
.globl kBootConstants
.hidden kBootConstants
.type kBootConstants, %%object
kBootConstants:
.space %cc[size], %cc[fill]
.size kBootConstants, %cc[size]
.popsection
)"""
:
:
[alignment] "i"(alignof(BootConstants)), [size] "i"(sizeof(BootConstants)), [fill] "i"(0xbb));
uart::all::KernelDriver<uart::BasicIoProvider, uart::UnsynchronizedPolicy, uart::NullIrqProvider>(
kBootConstants.boot_options->serial)
.Visit([](auto& uart) {
uart.Write("Hello world!\n");
CodePatchingNopTest();
uart.Write("I've been patched!\n");
CheckBootConstants();
uart.Write("\n" BOOT_TEST_SUCCESS_STRING "\n");
});
abort();
}
// This is what ZX_ASSERT calls.
void __zx_panic(const char* format, ...) { __builtin_trap(); }
// This is what libc++ headers call.
[[noreturn]] void std::__libcpp_verbose_abort(const char* format, ...) noexcept {
__builtin_trap();
}