/*
 * Copyright (c) 2019 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/kernel.h>
#include <kernel_arch_func.h>
#include <kernel_arch_interface.h>
#include <zephyr/arch/x86/multiboot.h>
#include <zephyr/arch/x86/efi.h>
#include <x86_mmu.h>
#include <zephyr/platform/hooks.h>
#include <zephyr/cache.h>
#include <zephyr/arch/common/init.h>

K_KERNEL_PINNED_STACK_ARRAY_DECLARE(z_interrupt_stacks,
		CONFIG_MP_MAX_NUM_CPUS,
		CONFIG_ISR_STACK_SIZE);

extern void x86_64_irq_init(void);

#if !defined(CONFIG_X86_64)
__pinned_data x86_boot_arg_t x86_cpu_boot_arg;
#endif



extern int spec_ctrl_init(void);

/* Early global initialization functions, C domain. This runs only on the first
 * CPU for SMP systems.
 */
__boot_func
FUNC_NORETURN void z_prep_c(void *arg)
{
	x86_boot_arg_t *cpu_arg = arg;

	soc_prep_hook();

	_kernel.cpus[0].nested = 0;

#ifdef CONFIG_MMU
	z_x86_mmu_init();
#endif

#if defined(CONFIG_LOAPIC)
	z_loapic_enable(0);
#endif

#ifdef CONFIG_X86_64
	x86_64_irq_init();
#endif

	if (IS_ENABLED(CONFIG_MULTIBOOT_INFO) &&
		cpu_arg->boot_type == MULTIBOOT_BOOT_TYPE) {
		z_multiboot_init((struct multiboot_info *)cpu_arg->arg);
	} else if (IS_ENABLED(CONFIG_X86_EFI) &&
		cpu_arg->boot_type == EFI_BOOT_TYPE) {
		efi_init((struct efi_boot_arg *)cpu_arg->arg);
	} else {
		ARG_UNUSED(cpu_arg);
	}

#ifdef CONFIG_X86_VERY_EARLY_CONSOLE
	z_x86_early_serial_init();

#if defined(CONFIG_QEMU_TARGET)
	/*
	 * Under QEMU and SeaBIOS, everything gets to be printed
	 * immediately after "Booting from ROM.." as there is no newline.
	 * This prevents parsing QEMU console output for the very first
	 * line where it needs to match from the beginning of the line.
	 * So add a dummy newline here so the next output is at
	 * the beginning of a line.
	 */
	arch_printk_char_out('\n');
#endif
#endif

#ifdef CONFIG_X86_STACK_PROTECTION
	unsigned int num_cpus = arch_num_cpus();

	for (int i = 0; i < num_cpus; i++) {
		z_x86_set_stack_guard(z_interrupt_stacks[i]);
	}
#endif
#if CONFIG_ARCH_CACHE
	arch_cache_init();
#endif
#if defined(CONFIG_X86_DISABLE_SSBD) || defined(CONFIG_X86_ENABLE_EXTENDED_IBRS)
	spec_ctrl_init();
#endif

	z_cstart();
	CODE_UNREACHABLE;
}
