// 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

#include <lib/arch/ticks.h>
#include <lib/boot-options/boot-options.h>
#include <lib/counters.h>
#include <lib/zbitl/view.h>
#include <platform.h>

#include <lk/init.h>
#include <phys/handoff.h>
#include <platform/boot_timestamps.h>
#include <platform/timer.h>
#include <vm/physmap.h>

PhysHandoff* gPhysHandoff;

namespace {

// TODO(https://fxbug.dev/42164859): Eventually physboot will hand off a permanent pointer
// we can store in gBootOptions.  For now, handoff only provides temporary
// pointers that we must copy out of.
BootOptions gBootOptionsInstance;

// When using physboot, other samples are available in the handoff data too.
//
// **NOTE** Each sample here is represented in the userland test code in
// //src/tests/benchmarks/kernel_boot_stats.cc that knows the order of the
// steps and gives names to the intervals between the steps (as well as
// tracking the first-to-last total elapsed time across the first to last
// boot.timeline.* samples, not all recorded right here).  Any time a new time
// sample is added to PhysBootTimes, a kcounter should be added here and
// kernel_boot_stats.cc should be updated to give the new intervals appropriate
// names for the performance tracking infrastructure (see the pages at
// https://chromeperf.appspot.com/report and look for "fuchsia.kernel.boot").
KCOUNTER(timeline_hw_startup, "boot.timeline.hw")
KCOUNTER(timeline_zbi_entry, "boot.timeline.zbi")
KCOUNTER(timeline_physboot_setup, "boot.timeline.physboot-setup")
KCOUNTER(timeline_decompress_start, "boot.timeline.decompress-start")
KCOUNTER(timeline_decompress_end, "boot.timeline.decompress-end")
KCOUNTER(timeline_zbi_done, "boot.timeline.zbi-done")
KCOUNTER(timeline_physboot_handoff, "boot.timeline.physboot-handoff")
KCOUNTER(timeline_virtual_entry, "boot.timeline.virtual")

void Set(const Counter& counter, arch::EarlyTicks sample) {
  counter.Set(platform_convert_early_ticks(sample));
}

void Set(const Counter& counter, PhysBootTimes::Index i) {
  counter.Set(platform_convert_early_ticks(gPhysHandoff->times.Get(i)));
}

// Convert early boot timeline points into zx_ticks_t values in kcounters.
void TimelineCounters(unsigned int level) {
  // This isn't really a loop in any meaningful sense, but structuring it
  // this way gets the compiler to warn about any forgotten enum entry.
  for (size_t i = 0; i <= PhysBootTimes::kCount; ++i) {
    const PhysBootTimes::Index when = static_cast<PhysBootTimes::Index>(i);
    switch (when) {
      case PhysBootTimes::kZbiEntry:
        Set(timeline_zbi_entry, when);
        break;
      case PhysBootTimes::kPhysSetup:
        Set(timeline_physboot_setup, when);
        break;
      case PhysBootTimes::kDecompressStart:
        Set(timeline_decompress_start, when);
        break;
      case PhysBootTimes::kDecompressEnd:
        Set(timeline_decompress_end, when);
        break;
      case PhysBootTimes::kZbiDone:
        Set(timeline_zbi_done, when);
        break;
      case PhysBootTimes::kCount:
        // There is no PhysBootTimes entry corresponding to kCount.
        // This is the first sample taken by the kernel proper after physboot handed off.
        Set(timeline_physboot_handoff, kernel_entry_ticks);
        break;
    }
  }
  Set(timeline_virtual_entry, kernel_virtual_entry_ticks);
  Set(timeline_hw_startup, arch::EarlyTicks::Zero());
}

// This can happen really any time after the platform clock is configured.
LK_INIT_HOOK(TimelineCounters, TimelineCounters, LK_INIT_LEVEL_PLATFORM)

}  // namespace

template <>
void* PhysHandoffPtrImportPhysAddr<PhysHandoffPtrEncoding::PhysAddr>(uintptr_t ptr) {
  return paddr_to_physmap(ptr);
}

void HandoffFromPhys(paddr_t handoff_paddr) {
  gPhysHandoff = static_cast<PhysHandoff*>(paddr_to_physmap(handoff_paddr));

  gBootOptionsInstance = *gPhysHandoff->boot_options;
  gBootOptions = &gBootOptionsInstance;

  if (gPhysHandoff->reboot_reason) {
    platform_set_hw_reboot_reason(gPhysHandoff->reboot_reason.value());
  }
  gAcpiRsdp = gPhysHandoff->acpi_rsdp.value_or(0);
  gSmbiosPhys = gPhysHandoff->smbios_phys.value_or(0);
}

ktl::span<ktl::byte> ZbiInPhysmap(bool own) {
  ZX_ASSERT(gPhysHandoff->zbi != 0);
  void* data = paddr_to_physmap(gPhysHandoff->zbi);
  if (own) {
    gPhysHandoff->zbi = 0;
  }

  zbitl::ByteView zbi = zbitl::StorageFromRawHeader(static_cast<zbi_header_t*>(data));
  ZX_ASSERT(!zbi.empty());
  return {const_cast<ktl::byte*>(zbi.data()), zbi.size()};
}
