blob: 6f9be40bf06f873bb4dd97b60566b80e7ae4a842 [file] [log] [blame]
// Copyright 2021 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
#ifndef ZIRCON_KERNEL_PHYS_INCLUDE_PHYS_HANDOFF_H_
#define ZIRCON_KERNEL_PHYS_INCLUDE_PHYS_HANDOFF_H_
#include <lib/arch/ticks.h>
#include <lib/crypto/entropy_pool.h>
#include <lib/uart/all.h>
#include <stddef.h>
#include <zircon/assert.h>
#include <zircon/boot/image.h>
#include <ktl/byte.h>
#include <ktl/optional.h>
#include <ktl/span.h>
#include <ktl/type_traits.h>
#include <phys/arch/arch-handoff.h>
#include "handoff-ptr.h"
struct BootOptions;
// This holds arch::EarlyTicks timestamps collected by physboot before the
// kernel proper is cognizant. Once the platform timer hardware is set up for
// real, platform_convert_early_ticks translates these values into zx_ticks_t
// values that can be published as kcounters and then converted to actual time
// units in userland via zx_ticks_per_second().
//
// platform_convert_early_ticks returns zero if arch::EarlyTicks samples cannot
// be accurately converted to zx_ticks_t. This can happen on suboptimal x86
// hardware, where the early samples are in TSC but the platform timer decides
// that a synchronized and monotonic TSC is not available on the machine.
class PhysBootTimes {
public:
// These are various time points sampled during physboot's work.
// kernel/top/handoff.cc has a kcounter corresponding to each of these.
// When a new time point is added here, a new kcounter must be added
// there to make that sample visible anywhere.
enum Index : size_t {
kZbiEntry, // ZBI entry from boot loader.
kPhysSetup, // Earliest/arch-specific phys setup (e.g. paging).
kDecompressStart, // Begin decompression.
kDecompressEnd, // STORAGE_KERNEL decompressed.
kZbiDone, // ZBI items have been ingested.
kCount
};
constexpr arch::EarlyTicks Get(Index i) const { return timestamps_[i]; }
constexpr void Set(Index i, arch::EarlyTicks ts) { timestamps_[i] = ts; }
void SampleNow(Index i) { Set(i, arch::EarlyTicks::Get()); }
private:
arch::EarlyTicks timestamps_[kCount] = {};
};
// This is instrumentation data (if any) about physboot itself. The data
// handed off may be updated in place by physboot's instrumented code.
struct PhysInstrumentationData {
PhysHandoffTemporaryString symbolizer_log;
PhysHandoffTemporarySpan<const ktl::byte> llvm_profdata;
};
static_assert(ktl::is_default_constructible_v<PhysInstrumentationData>);
// This holds (or points to) everything that is handed off from physboot to the
// kernel proper at boot time.
struct PhysHandoff {
constexpr bool Valid() const { return magic == kMagic; }
static constexpr uint64_t kMagic = 0xfeedfaceb002da2a;
const uint64_t magic = kMagic;
// TODO(fxbug.dev/84107): This will eventually be made a permanent pointer.
PhysHandoffTemporaryPtr<const BootOptions> boot_options;
PhysBootTimes times;
static_assert(ktl::is_default_constructible_v<PhysBootTimes>);
PhysInstrumentationData instrumentation;
// Physical address of the data ZBI.
uint64_t zbi = 0;
// Entropy gleaned from ZBI Items such as 'ZBI_TYPE_SECURE_ENTROPY' and/or command line.
ktl::optional<crypto::EntropyPool> entropy_pool;
// ZBI container of items to be propagated in mexec.
// TODO(fxbug.dev/84107): later this will be propagated
// as a whole page the kernel can stuff into a VMO.
PhysHandoffTemporarySpan<const ktl::byte> mexec_data;
// Architecture-specific content.
ArchPhysHandoff arch_handoff;
static_assert(ktl::is_default_constructible_v<ArchPhysHandoff>);
// ZBI_TYPE_MEM_CONFIG payload.
PhysHandoffTemporarySpan<const zbi_mem_range_t> mem_config;
// ZBI_TYPE_CPU_TOPOLOGY payload (or translated legacy equivalent).
PhysHandoffTemporarySpan<const zbi_topology_node_t> cpu_topology;
// ZBI_TYPE_CRASHLOG payload.
PhysHandoffTemporaryString crashlog;
// ZBI_TYPE_HW_REBOOT_REASON payload.
ktl::optional<zbi_hw_reboot_reason_t> reboot_reason;
// ZBI_TYPE_NVRAM payload.
// A physical memory region that will persist across warm boots.
ktl::optional<zbi_nvram_t> nvram;
// ZBI_TYPE_PLATFORM_ID payload.
ktl::optional<zbi_platform_id_t> platform_id;
};
static_assert(ktl::is_default_constructible_v<PhysHandoff>);
extern PhysHandoff* gPhysHandoff;
#ifdef _KERNEL
// These functions relate to PhysHandoff but exist only in the kernel proper.
#include <sys/types.h>
// Called as soon as the physmap is available to set the gPhysHandoff pointer.
void HandoffFromPhys(paddr_t handoff_paddr);
// This can be used after HandoffFromPhys and before the ZBI is handed off to
// userboot at the very end of kernel initialization code. Userboot calls it
// with true to ensure no later calls will succeed.
ktl::span<ktl::byte> ZbiInPhysmap(bool own = false);
#endif // _KERNEL
#endif // ZIRCON_KERNEL_PHYS_INCLUDE_PHYS_HANDOFF_H_