##
# Ensure that the next Genode build includes no target specific boot modules
#
proc clean_boot_modules { } {
	exec rm -rf boot_modules.s var/libcache/boot_modules/boot_modules.o }


proc run_boot_dir_hook { } {
	clean_boot_modules
}


proc run_boot_string { } {
	return "kernel initialized"
}


##
# Populate boot directory with binaries on hw
#
proc run_boot_dir {binaries} {

	# adapt to wether this is a core-internal test or a common scenario
	global core_test
	if {[info exists core_test]} {
		set core_bin "test-[run_name]"
		set core_target "test/[run_name]"
	} else {
		set core_bin "core"
		set core_target "core"
	}

	# strip binaries
	copy_and_strip_genode_binaries_to_run_dir $binaries

	# append init config
	if {[file exists "[run_dir]/genode/config"] == 1} {
		append binaries " config"
	}

	#
	# Compose a platform specific assembly file 'boot_modules.s', that
	# enables the creation of a single boot image. The file rawly includes
	# all binaries given in 'binaries', minus 'core', if given, plus 'config',
	# if available. It also provides a simple file system, that enables Genode
	# to access these BLOBs. To build a single image this file is simply
	# linked against core. To build core stand-alone this file is substituted
	# by a dummy version. 'boot_modules.s' must be composed on demand, because
	# it depends on the individual run scenario.
	#
	set boot_modules "[run_dir]/boot_modules.s"

	if {[have_spec "64bit"]} {
		set address_type ".quad"
	} else {
		set address_type ".long"
	}

	# introduce boot module headers
	exec echo -e \
		  "/*" \
		"\n * This file was automatically generated by the procedure" \
		"\n * 'run_boot_dir' in 'tool/run/boot_dir/hw'." \
		"\n */" \
		"\n" \
		"\n /* core includes */" \
		"\n.include \"macros.s\"" \
		"\n" \
		"\n.section .data" \
		"\n" \
		"\n.p2align DATA_ACCESS_ALIGNM_LOG2" \
		"\n.global _boot_modules_headers_begin" \
		"\n_boot_modules_headers_begin:" > $boot_modules

	# generate header for each boot module except core
	set i 1
	foreach binary $binaries {
		if {$binary == $core_bin} { continue }
		exec echo -e \
			"\n${address_type} _boot_module_${i}_name" \
			"\n${address_type} _boot_module_${i}_begin" \
			"\n${address_type} _boot_module_${i}_end -" \
			" _boot_module_${i}_begin" >> $boot_modules
		incr i
	}

	# end boot module headers
	exec echo -e \
		"\n.global _boot_modules_headers_end" \
		"\n_boot_modules_headers_end:" >> $boot_modules

	# generate name string for each module except core
	set i 1
	foreach binary $binaries {
		if {$binary == $core_bin} { continue }
		exec echo -e \
			"\n.p2align DATA_ACCESS_ALIGNM_LOG2" \
			"\n_boot_module_${i}_name:" \
			"\n.string \"${binary}\"" \
			"\n.byte 0" >> $boot_modules
		incr i
	}

	exec echo -e \
		"\n.section .data.boot_modules_binaries" \
		"\n" \
		"\n.global _boot_modules_binaries_begin" \
		"\n_boot_modules_binaries_begin:" >> $boot_modules

	# include raw data of modules consecutively but page aligned
	set i 1
	foreach binary $binaries {
		if {$binary == $core_bin} { continue }
		exec echo -e \
			"\n.p2align MIN_PAGE_SIZE_LOG2" \
			"\n_boot_module_${i}_begin:" \
			"\n.incbin \"[run_dir]/genode/${binary}\"" \
			"\n_boot_module_${i}_end:" >> $boot_modules
		incr i
	}

	# finish boot modules file
	exec echo -e \
		"\n.global _boot_modules_binaries_end" \
		"\n_boot_modules_binaries_end:" >> $boot_modules

	clean_boot_modules
	exec ln -s $boot_modules boot_modules.s

	# recompile core with boot modules
	exec cp -L bin/$core_bin $core_target/$core_bin.standalone
	exec find . -type f -name $core_bin -delete
	set timeout 10000
	set pid [eval "spawn make $core_target"]
	expect { eof { } }
	if {[lindex [wait $pid] end] != 0} {
		clean_boot_modules
		puts stderr "Error: Genode build failed"
		exit -1
	}
	clean_boot_modules
	exec mv [run_dir]/genode/config [run_dir]/config
	exec rm -rf "[run_dir]/genode"

	# offer ELF image
	set elf_img "[run_dir]/image.elf"

	# Use raw binary object for base-hw on Muen
	if {[have_spec "muen"]} {
		set raw_img "[run_dir]/image.raw"
		exec [cross_dev_prefix]objcopy -O binary bin/$core_bin $raw_img
		exit 0
	}

	if {[have_spec "x86_64"] && ![have_spec "muen"]} {
		# as startup is done in 32 bit mode, GRUB expects a 32 bit image
		exec [cross_dev_prefix]objcopy -O elf32-i386 bin/$core_bin $elf_img
	}
	if {[expr [have_spec "arm"] || [have_spec "x86_32"]]} {
		exec cp -L bin/$core_bin $elf_img
	}
	exec [cross_dev_prefix]strip $elf_img

	if {[have_include "image/iso"] || [have_include "image/disk"]} {
		#
		# Install isolinux/GRUB files and bender
		#
		install_iso_bootloader_to_run_dir

		#
		# Generate GRUB config file
		#
		set fh [open "[run_dir]/boot/grub/menu.lst" "WRONLY CREAT TRUNC"]
		puts $fh "timeout 0"
		puts $fh "default 0"
		puts $fh "\ntitle Genode on base-hw"
		puts $fh " kernel /boot/bender"
		puts $fh " module /image.elf"
		close $fh
	}

	run_image $elf_img

	# set symbolic link to image.elf file in TFTP directory for PXE boot
	if {[have_spec arm] && [have_include "load/tftp"]} {
		exec ln -sf [pwd]/$elf_img [load_tftp_base_dir][load_tftp_offset_dir]

		if {[have_include "image/uboot"]} {
			exec ln -sf [pwd]/[run_dir]/uImage [load_tftp_base_dir][load_tftp_offset_dir]
		}
	}

	if {[have_spec x86] && [have_include "load/tftp"]} {
		#
		# Install PXE bootloader pulsar
		#
		install_pxe_bootloader_to_run_dir

		#
		# Generate pulsar config file
		#
		set fh [open "[run_dir]/config-52-54-00-12-34-56" "WRONLY CREAT TRUNC"]
		puts $fh " exec /boot/bender"
		puts $fh " load /image.elf"
		close $fh

		generate_tftp_config
	}

	# retrieve stand-alone core
	exec cp $core_target/$core_bin.standalone bin/$core_bin
	exec rm $core_target/$core_bin.standalone
}
