# SPDX-License-Identifier: GPL-2.0

lib-objs := clear_page.o copy_page.o memcpy.o memset.o
lib-objs := $(addprefix ../../../lib/, $(lib-objs))

hyp-obj-y := hyp-init.o host.o cache.o
hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
	 ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o
hyp-obj-y += $(lib-objs)

ifndef CONFIG_X1_RMS
hyp-obj-y += mem_protect.o setup.o psci-relay.o sdei-relay.o alloc_mgt.o alloc.o \
	 early_alloc.o page_alloc.o hyp-smp.o tlb.o hyp-main.o debug-sr.o \
     mm.o sys_regs.o ffa.o serial.o pkvm.o sysreg-sr.o stacktrace.o \
     timer-sr.o switch.o
hyp-obj-$(CONFIG_LIST_HARDENED) += list_debug.o
hyp-obj-$(CONFIG_MODULES) += modules.o
else
XHYPERVISOR := ../xhypervisor

ifdef CONFIG_JUMP_LABEL
always-y += $(XHYPERVISOR)/src/macros/generated_arch_static_branch_asm.rs
always-y += $(XHYPERVISOR)/src/macros/generated_arch_static_branch_jump_asm.rs
endif

#quiet_cmd_rustc_rs_rs_S = RSCPP $(quiet_modtag) $@
#      cmd_rustc_rs_rs_S = $(CPP) $(c_flags) -xc -C -P $< | sed '1,/^\/\/ Cut here.$$/d' >$@

quiet_cmd_rustc_rs_rs_S = RSCPP $(quiet_modtag) $@
      cmd_rustc_rs_rs_S = mkdir -p $(dir $@); \
	$(CPP) $(c_flags) -xc -C -P $< | sed '1,/^\/\/ Cut here.$$/d' > $@

$(obj)/$(XHYPERVISOR)/src/macros/%.rs: $(obj)/$(XHYPERVISOR)/src/macros/%.rs.S FORCE
	+$(call if_changed_dep,rustc_rs_rs_S)

# 设置Rust目标文件
rust-obj-y := xhypervisor.o
rust-obj-y := $(addprefix $(XHYPERVISOR)/, $(rust-obj-y))

hyp-obj-y += $(rust-obj-y)

ifdef CONFIG_CC_IS_CLANG
bindgen_c_flags = $(c_flags)
else
# bindgen relies on libclang to parse C. Ideally, bindgen would support a GCC
# plugin backend and/or the Clang driver would be perfectly compatible with GCC.
#
# For the moment, here we are tweaking the flags on the fly. This is a hack,
# and some kernel configurations may not work (e.g. `GCC_PLUGIN_RANDSTRUCT`
# if we end up using one of those structs).
bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \
       -mskip-rax-setup -mgeneral-regs-only -msign-return-address=% \
       -mindirect-branch=thunk-extern -mindirect-branch-register \
       -mfunction-return=thunk-extern -mrecord-mcount -mabi=lp64 \
       -mindirect-branch-cs-prefix -mstack-protector-guard% -mtraceback=no \
       -mno-pointers-to-nested-functions -mno-string \
       -mno-strict-align -mstrict-align \
       -fconserve-stack -falign-jumps=% -falign-loops=% \
       -femit-struct-debug-baseonly -fno-ipa-cp-clone -fno-ipa-sra \
       -fno-partial-inlining -fplugin-arg-arm_ssp_per_task_plugin-% \
       -fno-reorder-blocks -fno-allow-store-data-races -fasan-shadow-offset=% \
       -fzero-call-used-regs=% -fno-stack-clash-protection \
       -fno-inline-functions-called-once -fsanitize=bounds-strict \
       -fstrict-flex-arrays=% \
       --param=% --param asan-%

# Derived from `scripts/Makefile.clang`.
BINDGEN_TARGET_x86     := x86_64-linux-gnu
BINDGEN_TARGET_arm64   := aarch64-linux-gnu
BINDGEN_TARGET         := $(BINDGEN_TARGET_$(SRCARCH))

# All warnings are inhibited since GCC builds are very experimental,
# many GCC warnings are not supported by Clang, they may only appear in
# some configurations, with new GCC versions, etc.
bindgen_extra_c_flags = -w --target=$(BINDGEN_TARGET)

# Auto variable zero-initialization requires an additional special option with
# clang that is going to be removed sometime in the future (likely in
# clang-18), so make sure to pass this option only if clang supports it
# (libclang major version < 16).
#
# https://github.com/llvm/llvm-project/issues/44842
# https://github.com/llvm/llvm-project/blob/llvmorg-16.0.0-rc2/clang/docs/ReleaseNotes.rst#deprecated-compiler-flags
ifdef CONFIG_INIT_STACK_ALL_ZERO
libclang_maj_ver=$(shell $(BINDGEN) $(srctree)/scripts/rust_is_available_bindgen_libclang.h 2>&1 | sed -ne 's/.*clang version \([0-9]*\).*/\1/p')
ifeq ($(shell expr $(libclang_maj_ver) \< 16), 1)
bindgen_extra_c_flags += -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang
endif
endif

bindgen_c_flags = $(filter-out $(bindgen_skip_c_flags), $(c_flags)) \
       $(bindgen_extra_c_flags)
endif  # End of CONFIG_CC_IS_CLANG

ifdef CONFIG_LTO
bindgen_c_flags_lto = $(filter-out $(CC_FLAGS_LTO), $(bindgen_c_flags))
else
bindgen_c_flags_lto = $(bindgen_c_flags)
endif

bindgen_c_flags_final = $(bindgen_c_flags_lto) -D__BINDGEN__ -I$(srctree) \
    -ULATENT_ENTROPY_PLUGIN

quiet_cmd_bindgen = BINDGEN $@
      cmd_bindgen = mkdir -p $(dir $@); \
       $(BINDGEN) $< $(bindgen_target_flags) \
               --use-core --with-derive-default --ctypes-prefix core::ffi --no-layout-tests \
               --no-debug '.*' \
               -o $@ -- $(bindgen_c_flags_final) -DMODULE \
               $(bindgen_target_cflags) $(bindgen_target_extra)

$(obj)/$(XHYPERVISOR)/src/bindings/bindings_generated.rs: private bindgen_target_flags = \
    $(shell grep -Ev '^#|^$$' $(srctree)/$(src)/$(XHYPERVISOR)/bindgen_parameters)
$(obj)/$(XHYPERVISOR)/src/bindings/bindings_generated.rs: private bindgen_target_extra = ; \
    sed -Ei 's/pub const RUST_CONST_HELPER_([a-zA-Z0-9_]*)/pub const \1/g' $@
$(obj)/$(XHYPERVISOR)/src/bindings/bindings_generated.rs: $(src)/$(XHYPERVISOR)/src/bindings/bindings_helper.h \
    $(src)/$(XHYPERVISOR)/bindgen_parameters FORCE
	$(call if_changed_dep,bindgen)

# 添加Rust构建规则 - 同时创建.o和.nvhe.o文件
# $(obj)/$(XHYPERVISOR)/xhypervisor.o: $(obj)/$(XHYPERVISOR)/src/bindings/bindings_generated.rs FORCE
#	$(Q)cd $(src) && CONFIG_XCORE_UNIT_TEST=$(CONFIG_XCORE_UNIT_TEST) ./$(XHYPERVISOR)/build_rust.sh

$(obj)/$(XHYPERVISOR)/xhypervisor.o: $(obj)/$(XHYPERVISOR)/src/bindings/bindings_generated.rs FORCE
	$(Q)OUT_DIR="$(abspath $(objtree)/$(obj)/$(XHYPERVISOR)/src/bindings)" \
	CARGO_TARGET_DIR="$(abspath $(objtree)/$(obj)/$(XHYPERVISOR)/target)" \
	RUSTC_CFG="$(abspath $(objtree)/include/generated/rustc_cfg)" \
	NVHE_RUST_OBJ="$(abspath $(objtree)/$(obj)/$(XHYPERVISOR)/xhypervisor.o)" \
	KERNEL_SRC="$(abspath $(srctree))" \
	KERNEL_OBJ="$(abspath $(objtree))" \
	CONFIG_XCORE_UNIT_TEST="$(CONFIG_XCORE_UNIT_TEST)" \
	$(CONFIG_SHELL) $(srctree)/$(src)/$(XHYPERVISOR)/build_rust.sh

# 添加.nvhe.o构建规则
$(obj)/$(XHYPERVISOR)/xhypervisor.nvhe.o: $(obj)/$(XHYPERVISOR)/xhypervisor.o
	@cp "$<" "$@"
endif    # CONFIG_X1_RMS

include $(srctree)/arch/arm64/kvm/hyp/nvhe/Makefile.nvhe
obj-y := kvm_nvhe.o

# KVM nVHE code is run at a different exception code with a different map, so
# compiler instrumentation that inserts callbacks or checks into the code may
# cause crashes. Just disable it.
GCOV_PROFILE	:= n
KASAN_SANITIZE	:= n
KCSAN_SANITIZE	:= n
UBSAN_SANITIZE	:= n
KCOV_INSTRUMENT	:= n

# Skip objtool checking for this directory because nVHE code is compiled with
# non-standard build rules.
OBJECT_FILES_NON_STANDARD := y
