# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the virtio storage
#

ccflags-y += -I$(src)/include -Werror -include $(src)/include/hpvs/hpvs_version.h
ccflags-y += -include $(src)/include/hpvs/error-injection.h

# set module version
version := 3.5.3
lversion := 030503
sversion := 30503

# enable hpvs_fuse transport?
enable_hpvs_fuse := 0

ifeq ($(enable_hpvs_fuse),1)
    ccflags-y += -DCONFIG_ENABLE_HPVS_FUSE
endif

# enable attaching to the kernel's native virtio-pci / virtio-mmio transport?
# (kata-style: virtqueue / virtio_device are created by the kernel; hpvs only
# probes on the kernel virtio bus and reuses those objects.)
#
# Two ways to turn this on:
#   1) build.py --enable-native-virtio-transport
#      rewrites the `:= 0` default below to `:= 1` in place.
#   2) `ENABLE_NATIVE_VIRTIO_TRANSPORT=1 make ...`
#      (or `make ENABLE_NATIVE_VIRTIO_TRANSPORT=1 ...`)
#      overrides the default via environment / command line without
#      touching this file.
enable_native_virtio_transport := 0
ifneq ($(ENABLE_NATIVE_VIRTIO_TRANSPORT),)
    enable_native_virtio_transport := $(ENABLE_NATIVE_VIRTIO_TRANSPORT)
endif

ifeq ($(enable_native_virtio_transport),1)
    ccflags-y += -DCONFIG_NATIVE_VIRTIO_TRANSPORT
endif

# enable hpvs_proxy version
enable_proxy_version := 0
proxy_version := $(lversion)
proxy_sversion := $(sversion)

ifeq ($(enable_proxy_version),1)
    ccflags-y += -DHPVS_PROXY_VERSION=$(proxy_version)
    ccflags-y += -DHPVS_PROXY_SVERSION=$(proxy_sversion)
endif

enable_debug := 0

ifeq ($(enable_debug),1)
    GCOV_PROFILE := y
    ccflags-y += -DCONFIG_HPVS_DEBUG
    $(info enabled debug)
endif

ccflags-y += -DMVERSION=$(version)
ccflags-y += -DMLVERSION=$(lversion)
ccflags-y += -DMSVERSION=$(sversion)

# get os distributor
os_id := $(shell cat /etc/os-release | grep ^ID= | sed 's/[="]/ /g')
os_id := $(word 2,$(os_id))

# get kernel version
KERNEL_UNAME ?= $(shell uname -r)
kversion_all := $(KERNEL_UNAME)
kversion_all_tuple := $(subst -, ,$(kversion_all))

# get main linux version: x.y.z
kversion_main := $(word 1,$(kversion_all_tuple))
kversion_main_tuple := $(subst ., ,$(kversion_main))
kversion_x := $(word 1,$(kversion_main_tuple))
kversion_y := $(word 2,$(kversion_main_tuple))
kversion_z := $(word 3,$(kversion_main_tuple))

# byteatom-ck kernel is 5.15.120.byteatom-ck.13
kversion_ck := $(word 2,$(kversion_all_tuple))

# gb200 kernel is 6.6.63.bsk.2-gb.1-64k-arm64
kversion_gb_tuple := $(subst ., ,$(kversion_ck))
kversion_gb := 0
ifeq ($(word 1,$(kversion_gb_tuple)),gb)
    kversion_gb := $(word 2,$(kversion_gb_tuple))
endif
ccflags-y += -DKVER_GB=$(kversion_gb)

# merge x.y to xyy
gt_nine := $(shell [ $(kversion_y) -gt 9 ] && echo true)
ifeq ($(gt_nine),true)
    kversion_xy := $(kversion_x)$(kversion_y)
else
    kversion_xy := $(kversion_x)0$(kversion_y)
endif
ccflags-y += -DKVER_XY=$(kversion_xy)
ccflags-y += -DKVER_Z=$(kversion_z)
# $(info kversion_xy: $(kversion_xy))

# Detect whether the running kernel's struct virtio_device has the
# byted-private uevent_var field (upstreamed via byted patch a9a248a3).
# Only relevant when the native virtio transport is enabled.
ifeq ($(enable_native_virtio_transport),1)
    have_virtio_dev_uevent_var := $(shell \
	f=/lib/modules/$(kversion_all)/build/include/linux/virtio.h; \
	test -r $$f && awk '/^struct virtio_device \{/,/^\};/' $$f \
	    | grep -q '\<uevent_var\>' && echo yes || echo no)
    ifeq ($(have_virtio_dev_uevent_var), yes)
        ccflags-y += -DHAVE_VIRTIO_DEV_UEVENT_VAR
    endif
endif

# get the os distribution's version
kversion_os := $(word 2,$(kversion_all_tuple))
kversion_os_tuple := $(subst ., ,$(kversion_os))
kversion_4 := $(word 4,$(kversion_main_tuple))
kversion_update := 0
ifeq ($(kversion_4), bsk)
    # this is inner bsk kernel, set os_id as velinux
    os_id := velinux
    kversion_reversion := $(word 5,$(kversion_main_tuple))
else ifeq ($(kversion_4), ve)
    # velinux2 of debian's version is x.y.z.ve.r-amd64 or x.y.z.ve.ruc-amd64
    # ruc means:
    #     r is the reversion which is same as in x.y.z.bsk.r-amd64
    #     uc is update time
    #
    # we have to do this ugly check. :(
    os_id := velinux
    tmp_reversion := $(word 5,$(kversion_main_tuple))
    tmp_reversion_tuple := $(subst u, ,$(tmp_reversion))
    kversion_reversion := $(word 1,$(tmp_reversion_tuple))
    kversion_update := $(word 2,$(tmp_reversion_tuple))
else ifeq ($(kversion_4), byteatom)
    os_id := ck
    kversion_ck_tuple := $(subst ., ,$(kversion_ck))
    kversion_reversion := $(word 2,$(kversion_ck_tuple))
else
    kversion_reversion := $(word 1,$(kversion_os_tuple))
    kversion_update := $(word 2,$(kversion_os_tuple))
    ifeq ($(word 3,$(kversion_os_tuple)), ve2)
        os_id := velinux
    endif
endif
kversion_reversion_is_number := $(shell [ -n "$(kversion_reversion)" ] && [ $(kversion_reversion) -eq $(kversion_reversion) 2> /dev/null ] && echo yes || echo no)
ifeq ($(kversion_reversion_is_number), no)
    $(warning "kversion_reversion is not one number: $(kversion_reversion), we have to set it to 0")
    kversion_reversion := 0
endif
ccflags-y += -DKVER_RX=$(kversion_reversion)

kversion_update_is_number := $(shell [ -n "$(kversion_update)" ] && [ $(kversion_update) -eq $(kversion_update) 2> /dev/null ] && echo yes || echo no)
ifeq ($(kversion_update_is_number), no)
    kversion_update := 0
endif
ccflags-y += -DKVER_U=$(kversion_update)

# NOTE: fixup velinux1's os_id
ifeq ($(kversion_xy), 504)
    ifeq ($(os_id), centos)
        os_id := velinux
    endif
    ifeq ($(os_id), debian)
        os_id := velinux
    endif
endif
ifeq ($(kversion_xy), 510)
    ifeq ($(os_id), centos)
        os_id := velinux
    else
        tmp := $(word 3,$(kversion_all_tuple))
        ifeq ($(tmp), velinux1)
            os_id := velinux
        endif
    endif
endif

# NOTE: For MaaS which using velinux1.0 os + 5.15 kernel.
ifeq ($(kversion_xy), 515)
    ifeq ($(os_id), centos)
        os_id := velinux
    endif
    ifeq ($(os_id), debian)
        os_id := velinux
    endif
endif

# velinux series:
# inner_bsk: x.y.z.bsk.r-amd64
# velinux1: 5.4.z-r.ve1.x86_64(centos)
#           5.4.z-r-velinux1-amd64
#           5.10.z-r.ve1.x86_64(centos)
#           5.10.z-r-velinux1-amd64
#           5.15.z.ve.ruc
# velinux2: 5.15.z-r.u.ve90.x86_64(centos)
#           5.15.z.ve.ruc-amd64
ifeq ($(os_id), velinux)
    ccflags-y += -DOS_VELINUX
endif

# centos series:
# fedora -> centos stream -> RHEL -> rocky linux
#                             |
#                             +----> alma linux
ifeq ($(os_id), fedora)
    ccflags-y += -DOS_FEDORA
endif

ifeq ($(os_id), centos)
    ccflags-y += -DOS_CENTOS
endif
# rocky linux is the downstream of centos stream
ifeq ($(os_id), rocky)
    ccflags-y += -DOS_CENTOS
    ccflags-y += -DOS_ROCKY
endif
# alma linux is the downstream of centos stream
ifeq ($(os_id), almalinux)
    ccflags-y += -DOS_CENTOS
    ccflags-y += -DOS_ALMALINUX
endif

# debian series:
# debian -> ubuntu
ifeq ($(os_id), debian)
    ccflags-y += -DOS_DEBIAN
endif
ifeq ($(os_id), ubuntu)
    ccflags-y += -DOS_UBUNTU
endif

# openEuler series:
ifeq ($(os_id), openEuler)
    ccflags-y += -DOS_OPENEULER
endif

# suse series:
ifeq ($(os_id), opensuse-leap)
    ccflags-y += -DOS_OPENSUSE
endif

$(info main kernel version: $(kversion_xy), sub version is: $(kversion_z), os type is: $(os_id), kernel reversion: $(kversion_reversion), gb version: $(kversion_gb))

hpvs_ko := hpvs-$(lversion)
ifeq ($(enable_proxy_version),1)
    proxy_ko := hpvs-proxy-$(proxy_version)
else
    proxy_ko := hpvs-proxy
endif

obj-m += $(hpvs_ko).o
obj-m += $(proxy_ko).o

$(hpvs_ko)-y := $(addprefix core/, \
                dstruct.o \
                main.o \
                )

$(hpvs_ko)-y += $(addprefix core/hpvs_fs/, \
                acl.o \
                control.o \
                dir.o \
                export.o \
                file.o \
                fuse_backend.o \
                fuse_conn.o \
                inode.o \
                readdir.o \
                request.o \
                shrinker.o \
                super.o \
                upgrade.o \
                xattr.o \
                )

ifeq ($(enable_hpvs_fuse),1)
    $(hpvs_ko)-y += $(addprefix core/hpvs_fs/transport/fuse/, \
                       dev.o \
                       super.o \
                       )
endif

$(hpvs_ko)-y += $(addprefix core/hpvs_fs/transport/virtio_blk/, \
                )

$(hpvs_ko)-y += $(addprefix core/hpvs_fs/transport/virtio_fs/, \
                control_plane.o \
                fuse_backend_common.o \
                fuse_backend_mq.o \
                fuse_backend_sq.o \
                fuse_chan_vq.o \
                data_plane.o \
                super.o \
                upgrade.o \
                vnotify.o \
                )

$(hpvs_ko)-y += $(addprefix core/libiov/, \
                iov_iter.o \
                )

$(hpvs_ko)-y += $(addprefix core/libvirtio/, \
                virtio_ring.o \
                )

$(hpvs_ko)-y += $(addprefix core/vduse/, \
                iova.o \
                iova_domain.o \
                vduse_dev.o \
                )

$(hpvs_ko)-y += $(addprefix core/libvhost/, \
                iotlb.o \
                vringh.o \
                )

$(proxy_ko)-y := $(addprefix proxy/, \
                    main.o \
                    private.o \
                    proxy_driver.o \
                    proxy_vfs.o \
                    )

default:
	make -C /lib/modules/$(kversion_all)/build M=`pwd` modules
clean:
	rm -f *.mod.c *.ko */*.mod.c modules.order Module.symvers *.mod del_pvduse io_ops_flags
	find . -type f -name "*.cmd" ! -name ".private.o.cmd" -exec rm {} +
	find . -type f -name "*.d" ! -name ".private.o.d" -exec rm {} +
	find . -type f -name "*.o" ! -name "private.o" -exec rm {} +

# compile tools
tools_extra_flags := -I include
tools_del_pvduse := del_pvduse
tools_io_ops_flags := io_ops_flags
ifeq ($(enable_proxy_version),1)
    tools_extra_flags += -DHPVS_PROXY_VERSION=$(proxy_version)
    tools_del_pvduse := del_pvduse_$(proxy_version)
    tools_io_ops_flags := io_ops_flags_$(proxy_version)
endif

tools: del_pvduse io_ops_flags

del_pvduse: tools/del_pvduse.c
	gcc tools/del_pvduse.c -o $(tools_del_pvduse) $(tools_extra_flags)

io_ops_flags: tools/io_ops_flags.c
	gcc tools/io_ops_flags.c -o $(tools_io_ops_flags) $(tools_extra_flags)

private_extra_flags := -I include -include include/hpvs/hpvs_version.h -Wall -fno-pie -O2 -Werror

# compile proxy/private.c
ARCH := $(shell uname -m | sed -e 's/i.86/i386/' \
    -e 's/armv[0-7]\w\+/arm/' \
    -e 's/aarch64/arm64/' \
    -e 's/ppc64le/powerpc/' \
    -e 's/riscv64/riscv/' \
    )
ifeq ($(ARCH),x86_64)
    private_extra_flags += -mcmodel=kernel
endif
ifeq ($(enable_proxy_version),1)
    private_extra_flags += -DHPVS_PROXY_VERSION=$(proxy_version)
endif
ifeq ($(enable_native_virtio_transport),1)
    private_extra_flags += -DCONFIG_NATIVE_VIRTIO_TRANSPORT
endif

proxy/private.o: proxy/private.c
	@echo "cmd_$(notdir $@) := gcc $(private_extra_flags) -c $< -o $@" > $(dir $@).$(notdir $@).cmd
	gcc $(private_extra_flags) -c -MM -MT $@ -MF $(dir $@).$(notdir $@).d $<
	gcc $(private_extra_flags) -c $< -o $@

private: proxy/private.o
