1#
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2019 Western Digital Corporation or its affiliates.
5#
6# Authors:
7#   Anup Patel <anup.patel@wdc.com>
8#
9
10# Select Make Options:
11# o  Do not use make's built-in rules
12# o  Do not print "Entering directory ...";
13MAKEFLAGS += -r --no-print-directory
14
15# Find out source, build, and install directories
16src_dir=$(CURDIR)
17ifdef O
18 build_dir=$(shell readlink -f $(O))
19else
20 build_dir=$(CURDIR)/build
21endif
22ifeq ($(build_dir),$(CURDIR))
23$(error Build directory is same as source directory.)
24endif
25ifdef I
26 install_dir=$(shell readlink -f $(I))
27else
28 install_dir=$(CURDIR)/install
29endif
30ifeq ($(install_dir),$(CURDIR))
31$(error Install directory is same as source directory.)
32endif
33ifeq ($(install_dir),$(build_dir))
34$(error Install directory is same as build directory.)
35endif
36ifdef PLATFORM_DIR
37  platform_dir_path=$(shell readlink -f $(PLATFORM_DIR))
38  ifdef PLATFORM
39    platform_parent_dir=$(platform_dir_path)
40  else
41    PLATFORM=$(shell basename $(platform_dir_path))
42    platform_parent_dir=$(subst $(PLATFORM),,$(platform_dir_path))
43  endif
44else
45 platform_parent_dir=$(src_dir)/platform
46endif
47
48# Check if verbosity is ON for build process
49CMD_PREFIX_DEFAULT := @
50ifeq ($(V), 1)
51	CMD_PREFIX :=
52else
53	CMD_PREFIX := $(CMD_PREFIX_DEFAULT)
54endif
55
56# Setup path of directories
57export platform_subdir=$(PLATFORM)
58export platform_src_dir=$(platform_parent_dir)/$(platform_subdir)
59export platform_build_dir=$(build_dir)/platform/$(platform_subdir)
60export include_dir=$(CURDIR)/include
61export libsbi_dir=$(CURDIR)/lib/sbi
62export libsbiutils_dir=$(CURDIR)/lib/utils
63export firmware_dir=$(CURDIR)/firmware
64
65# Find library version
66OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'`
67OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
68OPENSBI_VERSION_GIT=$(shell if [ -d $(src_dir)/.git ]; then git describe 2> /dev/null; fi)
69
70# Setup compilation commands
71ifdef CROSS_COMPILE
72CC		=	$(CROSS_COMPILE)gcc
73CPP		=	$(CROSS_COMPILE)cpp
74AR		=	$(CROSS_COMPILE)ar
75LD		=	$(CROSS_COMPILE)ld
76OBJCOPY		=	$(CROSS_COMPILE)objcopy
77else
78CC		?=	gcc
79CPP		?=	cpp
80AR		?=	ar
81LD		?=	ld
82OBJCOPY		?=	objcopy
83endif
84AS		=	$(CC)
85DTC		=	dtc
86
87# Guess the compillers xlen
88OPENSBI_CC_XLEN := $(shell TMP=`$(CC) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP})
89
90# Setup platform XLEN
91ifndef PLATFORM_RISCV_XLEN
92  ifeq ($(OPENSBI_CC_XLEN), 32)
93    PLATFORM_RISCV_XLEN = 32
94  else
95    PLATFORM_RISCV_XLEN = 64
96  endif
97endif
98
99# Setup list of objects.mk files
100ifdef PLATFORM
101platform-object-mks=$(shell if [ -d $(platform_src_dir)/ ]; then find $(platform_src_dir) -iname "objects.mk" | sort -r; fi)
102endif
103libsbi-object-mks=$(shell if [ -d $(libsbi_dir) ]; then find $(libsbi_dir) -iname "objects.mk" | sort -r; fi)
104libsbiutils-object-mks=$(shell if [ -d $(libsbiutils_dir) ]; then find $(libsbiutils_dir) -iname "objects.mk" | sort -r; fi)
105firmware-object-mks=$(shell if [ -d $(firmware_dir) ]; then find $(firmware_dir) -iname "objects.mk" | sort -r; fi)
106
107# Include platform specifig config.mk
108ifdef PLATFORM
109include $(platform_src_dir)/config.mk
110endif
111
112# Include all object.mk files
113ifdef PLATFORM
114include $(platform-object-mks)
115endif
116include $(libsbi-object-mks)
117include $(libsbiutils-object-mks)
118include $(firmware-object-mks)
119
120# Setup list of objects
121libsbi-objs-path-y=$(foreach obj,$(libsbi-objs-y),$(build_dir)/lib/sbi/$(obj))
122libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(build_dir)/lib/utils/$(obj))
123ifdef PLATFORM
124platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj))
125platform-dtb-path-y=$(foreach obj,$(platform-dtb-y),$(platform_build_dir)/$(obj))
126firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin))
127endif
128firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf)
129firmware-objs-path-y=$(firmware-bins-path-y:.bin=.o)
130
131# Setup list of deps files for objects
132deps-y=$(platform-objs-path-y:.o=.dep)
133deps-y+=$(libsbi-objs-path-y:.o=.dep)
134deps-y+=$(libsbiutils-objs-path-y:.o=.dep)
135deps-y+=$(firmware-objs-path-y:.o=.dep)
136
137# Setup platform ABI, ISA and Code Model
138ifndef PLATFORM_RISCV_ABI
139  ifeq ($(PLATFORM_RISCV_XLEN), 32)
140    PLATFORM_RISCV_ABI = ilp$(PLATFORM_RISCV_XLEN)
141  else
142    PLATFORM_RISCV_ABI = lp$(PLATFORM_RISCV_XLEN)
143  endif
144endif
145ifndef PLATFORM_RISCV_ISA
146  PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
147endif
148ifndef PLATFORM_RISCV_CODE_MODEL
149  PLATFORM_RISCV_CODE_MODEL = medany
150endif
151
152# Setup compilation commands flags
153GENFLAGS	=	-I$(platform_src_dir)/include
154GENFLAGS	+=	-I$(include_dir)
155ifneq ($(OPENSBI_VERSION_GIT),)
156GENFLAGS	+=	-DOPENSBI_VERSION_GIT="\"$(OPENSBI_VERSION_GIT)\""
157endif
158GENFLAGS	+=	$(libsbiutils-genflags-y)
159GENFLAGS	+=	$(platform-genflags-y)
160GENFLAGS	+=	$(firmware-genflags-y)
161
162CFLAGS		=	-g -Wall -Werror -nostdlib -fno-strict-aliasing -O2
163CFLAGS		+=	-fno-omit-frame-pointer -fno-optimize-sibling-calls
164CFLAGS		+=	-mno-save-restore -mstrict-align
165CFLAGS		+=	-mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
166CFLAGS		+=	-mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
167CFLAGS		+=	$(GENFLAGS)
168CFLAGS		+=	$(platform-cflags-y)
169CFLAGS		+=	$(firmware-cflags-y)
170CFLAGS		+=	-fno-pie -no-pie
171
172CPPFLAGS	+=	$(GENFLAGS)
173CPPFLAGS	+=	$(platform-cppflags-y)
174CPPFLAGS	+=	$(firmware-cppflags-y)
175
176ASFLAGS		=	-g -Wall -nostdlib -D__ASSEMBLY__
177ASFLAGS		+=	-fno-omit-frame-pointer -fno-optimize-sibling-calls
178ASFLAGS		+=	-mno-save-restore -mstrict-align
179ASFLAGS		+=	-mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
180ASFLAGS		+=	-mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
181ASFLAGS		+=	$(GENFLAGS)
182ASFLAGS		+=	$(platform-asflags-y)
183ASFLAGS		+=	$(firmware-asflags-y)
184
185ARFLAGS		=	rcs
186
187ELFFLAGS	+=	-Wl,--build-id=none -N -static-libgcc -lgcc
188ELFFLAGS	+=	$(platform-ldflags-y)
189ELFFLAGS	+=	$(firmware-ldflags-y)
190
191MERGEFLAGS	+=	-r
192MERGEFLAGS	+=	-b elf$(PLATFORM_RISCV_XLEN)-littleriscv
193MERGEFLAGS	+=	-m elf$(PLATFORM_RISCV_XLEN)lriscv
194
195DTCFLAGS	=	-O dtb
196
197# Setup functions for compilation
198define dynamic_flags
199-I$(shell dirname $(2)) -D__OBJNAME__=$(subst -,_,$(shell basename $(1) .o))
200endef
201merge_objs = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
202	     echo " MERGE     $(subst $(build_dir)/,,$(1))"; \
203	     $(LD) $(MERGEFLAGS) $(2) -o $(1)
204merge_deps = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
205	     echo " MERGE-DEP $(subst $(build_dir)/,,$(1))"; \
206	     cat $(2) > $(1)
207copy_file =  $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
208	     echo " COPY      $(subst $(build_dir)/,,$(1))"; \
209	     cp -f $(2) $(1)
210inst_file =  $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
211	     echo " INSTALL   $(subst $(install_dir)/,,$(1))"; \
212	     cp -f $(2) $(1)
213inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
214	     mkdir -p $(1)/$(3); \
215	     for file in $(4) ; do \
216	     rel_file=`echo $$file | sed -e 's@$(2)/$(3)/@@'`; \
217	     dest_file=$(1)"/"$(3)"/"`echo $$rel_file`; \
218	     dest_dir=`dirname $$dest_file`; \
219	     echo " INSTALL   "$(3)"/"`echo $$rel_file`; \
220	     mkdir -p $$dest_dir; \
221	     cp -f $$file $$dest_file; \
222	     done \
223	     fi
224inst_header_dir =  $(CMD_PREFIX)mkdir -p $(1); \
225	     echo " INSTALL   $(subst $(install_dir)/,,$(1))"; \
226	     cp -rf $(2) $(1)
227compile_cpp = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
228	     echo " CPP       $(subst $(build_dir)/,,$(1))"; \
229	     $(CPP) $(CPPFLAGS) -x c $(2) | grep -v "\#" > $(1)
230compile_cc_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
231	     echo " CC-DEP    $(subst $(build_dir)/,,$(1))"; \
232	     printf %s `dirname $(1)`/  > $(1) && \
233	     $(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2))   \
234	       -MM $(2) >> $(1) || rm -f $(1)
235compile_cc = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
236	     echo " CC        $(subst $(build_dir)/,,$(1))"; \
237	     $(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1)
238compile_as_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
239	     echo " AS-DEP    $(subst $(build_dir)/,,$(1))"; \
240	     printf %s `dirname $(1)`/ > $(1) && \
241	     $(AS) $(ASFLAGS) $(call dynamic_flags,$(1),$(2)) \
242	       -MM $(2) >> $(1) || rm -f $(1)
243compile_as = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
244	     echo " AS        $(subst $(build_dir)/,,$(1))"; \
245	     $(AS) $(ASFLAGS) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1)
246compile_elf = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
247	     echo " ELF       $(subst $(build_dir)/,,$(1))"; \
248	     $(CC) $(CFLAGS) $(3) $(ELFFLAGS) -Wl,-T$(2) -o $(1)
249compile_ar = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
250	     echo " AR        $(subst $(build_dir)/,,$(1))"; \
251	     $(AR) $(ARFLAGS) $(1) $(2)
252compile_objcopy = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
253	     echo " OBJCOPY   $(subst $(build_dir)/,,$(1))"; \
254	     $(OBJCOPY) -S -O binary $(2) $(1)
255compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
256	     echo " DTC       $(subst $(build_dir)/,,$(1))"; \
257	     $(DTC) $(DTCFLAGS) -o $(1) $(2)
258
259targets-y  = $(build_dir)/lib/libsbi.a
260targets-y  += $(build_dir)/lib/libsbiutils.a
261ifdef PLATFORM
262targets-y += $(platform_build_dir)/lib/libplatsbi.a
263targets-y += $(platform-dtb-path-y)
264endif
265targets-y += $(firmware-bins-path-y)
266
267# Default rule "make" should always be first rule
268.PHONY: all
269all: $(targets-y)
270
271# Preserve all intermediate files
272.SECONDARY:
273
274$(build_dir)/%.bin: $(build_dir)/%.elf
275	$(call compile_objcopy,$@,$<)
276
277$(build_dir)/%.elf: $(build_dir)/%.o $(build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
278	$(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
279
280$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
281	$(call compile_cpp,$@,$<)
282
283$(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y)
284	$(call compile_ar,$@,$^)
285
286$(build_dir)/lib/libsbiutils.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y)
287	$(call compile_ar,$@,$^)
288
289$(platform_build_dir)/lib/libplatsbi.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y) $(platform-objs-path-y)
290	$(call compile_ar,$@,$^)
291
292$(build_dir)/%.dep: $(src_dir)/%.c
293	$(call compile_cc_dep,$@,$<)
294
295$(build_dir)/%.o: $(src_dir)/%.c
296	$(call compile_cc,$@,$<)
297
298$(build_dir)/%.dep: $(src_dir)/%.S
299	$(call compile_as_dep,$@,$<)
300
301$(build_dir)/%.o: $(src_dir)/%.S
302	$(call compile_as,$@,$<)
303
304$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
305	$(call compile_cc_dep,$@,$<)
306
307$(platform_build_dir)/%.o: $(platform_src_dir)/%.c
308	$(call compile_cc,$@,$<)
309
310$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
311	$(call compile_as_dep,$@,$<)
312
313$(platform_build_dir)/%.o: $(platform_src_dir)/%.S
314	$(call compile_as,$@,$<)
315
316$(platform_build_dir)/%.dep: $(src_dir)/%.c
317	$(call compile_cc_dep,$@,$<)
318
319$(platform_build_dir)/%.o: $(src_dir)/%.c
320	$(call compile_cc,$@,$<)
321
322$(platform_build_dir)/%.dep: $(src_dir)/%.S
323	$(call compile_as_dep,$@,$<)
324
325$(platform_build_dir)/%.o: $(src_dir)/%.S
326	$(call compile_as,$@,$<)
327
328$(build_dir)/%.dtb: $(src_dir)/%.dts
329	$(call compile_dts,$@,$<)
330
331# Rule for "make docs"
332$(build_dir)/docs/latex/refman.pdf: $(build_dir)/docs/latex/refman.tex
333	$(CMD_PREFIX)mkdir -p $(build_dir)/docs
334	$(CMD_PREFIX)$(MAKE) -C $(build_dir)/docs/latex
335$(build_dir)/docs/latex/refman.tex: $(build_dir)/docs/doxygen.cfg
336	$(CMD_PREFIX)mkdir -p $(build_dir)/docs
337	$(CMD_PREFIX)doxygen $(build_dir)/docs/doxygen.cfg
338$(build_dir)/docs/doxygen.cfg: $(src_dir)/docs/doxygen.cfg
339	$(CMD_PREFIX)mkdir -p $(build_dir)/docs
340	$(CMD_PREFIX)cat docs/doxygen.cfg | sed -e "s#@@SRC_DIR@@#$(src_dir)#" -e "s#@@BUILD_DIR@@#$(build_dir)#" -e "s#@@OPENSBI_MAJOR@@#$(OPENSBI_VERSION_MAJOR)#" -e "s#@@OPENSBI_MINOR@@#$(OPENSBI_VERSION_MINOR)#" > $(build_dir)/docs/doxygen.cfg
341.PHONY: docs
342docs: $(build_dir)/docs/latex/refman.pdf
343
344# Dependency files should only be included after default Makefile rules
345# They should not be included for any "xxxconfig" or "xxxclean" rule
346all-deps-1 = $(if $(findstring config,$(MAKECMDGOALS)),,$(deps-y))
347all-deps-2 = $(if $(findstring clean,$(MAKECMDGOALS)),,$(all-deps-1))
348-include $(all-deps-2)
349
350# Include external dependency of firmwares after default Makefile rules
351include $(src_dir)/firmware/external_deps.mk
352
353# Convenient "make run" command for emulated platforms
354.PHONY: run
355run: all
356ifneq ($(platform-runcmd),)
357	$(platform-runcmd) $(RUN_ARGS)
358else
359ifdef PLATFORM
360	@echo "Platform $(PLATFORM) doesn't specify a run command"
361	@false
362else
363	@echo Run command only available when targeting a platform
364	@false
365endif
366endif
367
368install_targets-y  = install_libsbi
369install_targets-y  += install_libsbiutils
370ifdef PLATFORM
371install_targets-y += install_libplatsbi
372install_targets-y += install_firmwares
373endif
374
375# Rule for "make install"
376.PHONY: install
377install: $(install_targets-y)
378
379.PHONY: install_libsbi
380install_libsbi: $(build_dir)/lib/libsbi.a
381	$(call inst_header_dir,$(install_dir)/include,$(include_dir)/sbi)
382	$(call inst_file,$(install_dir)/lib/libsbi.a,$(build_dir)/lib/libsbi.a)
383
384.PHONY: install_libsbiutils
385install_libsbiutils: $(build_dir)/lib/libsbiutils.a
386	$(call inst_header_dir,$(install_dir)/include,$(include_dir)/sbi_utils)
387	$(call inst_file,$(install_dir)/lib/libsbiutils.a,$(build_dir)/lib/libsbiutils.a)
388
389.PHONY: install_libplatsbi
390install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a
391	$(call inst_file,$(install_dir)/platform/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
392
393.PHONY: install_firmwares
394install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a $(firmware-bins-path-y)
395	$(call inst_file_list,$(install_dir),$(build_dir),platform/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
396	$(call inst_file_list,$(install_dir),$(build_dir),platform/$(platform_subdir)/firmware,$(firmware-bins-path-y))
397
398.PHONY: install_docs
399install_docs: $(build_dir)/docs/latex/refman.pdf
400	$(call inst_file,$(install_dir)/docs/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
401
402# Rule for "make clean"
403.PHONY: clean
404clean:
405	$(CMD_PREFIX)mkdir -p $(build_dir)
406	$(if $(V), @echo " RM        $(build_dir)/*.o")
407	$(CMD_PREFIX)find $(build_dir) -type f -name "*.o" -exec rm -rf {} +
408	$(if $(V), @echo " RM        $(build_dir)/*.a")
409	$(CMD_PREFIX)find $(build_dir) -type f -name "*.a" -exec rm -rf {} +
410	$(if $(V), @echo " RM        $(build_dir)/*.elf")
411	$(CMD_PREFIX)find $(build_dir) -type f -name "*.elf" -exec rm -rf {} +
412	$(if $(V), @echo " RM        $(build_dir)/*.bin")
413	$(CMD_PREFIX)find $(build_dir) -type f -name "*.bin" -exec rm -rf {} +
414
415# Rule for "make distclean"
416.PHONY: distclean
417distclean: clean
418	$(CMD_PREFIX)mkdir -p $(build_dir)
419	$(if $(V), @echo " RM        $(build_dir)/*.dep")
420	$(CMD_PREFIX)find $(build_dir) -type f -name "*.dep" -exec rm -rf {} +
421ifeq ($(build_dir),$(CURDIR)/build)
422	$(if $(V), @echo " RM        $(build_dir)")
423	$(CMD_PREFIX)rm -rf $(build_dir)
424endif
425ifeq ($(install_dir),$(CURDIR)/install)
426	$(if $(V), @echo " RM        $(install_dir)")
427	$(CMD_PREFIX)rm -rf $(install_dir)
428endif
429