hos/Rsconscript

247 lines
7.7 KiB
Plaintext

require "tmpdir"
project_name "HOS"
path_prepend "x86_64-elf-gcc/bin"
configure do
rscons "x86_64-elf-gcc.rb", "-b", "#{build_dir}/x86_64-elf-gcc"
check_d_compiler "ldc2", use: "ldc2"
check_c_compiler "x86_64-w64-mingw32-gcc", use: "x86_64-w64-mingw32-gcc"
check_c_compiler "x86_64-elf-gcc", use: "x86_64-elf-gcc"
check_c_compiler
check_program "mformat", on_fail: "Install the mtools package"
check_program "parted"
check_cfg package: "freetype2", on_fail: "Install libfreetype-dev", use: "freetype"
sh %w[git submodule update --init]
end
# Kernel default font size.
KFONT_SIZE = 16
# One kilobyte.
KB = 1024
# One megabyte.
MB = 1024 * 1024
class HulkBinObj < Builder
def run(options)
@cache.mkdir_p(File.dirname(@target))
File.write(@target, <<EOF)
.section ".rodata"
.balign 4096
.global _hulk_bin_start
_hulk_bin_start:
.incbin "#{@sources.first}"
.balign 4096
.global _hulk_bin_end
_hulk_bin_end:
EOF
unless @cache.up_to_date?(@target, nil, @sources, @env)
print_run_message("Creating HULK binary object <target>#{@target}<reset>", nil)
@cache.register_build(@target, nil, @sources, @env)
end
true
end
end
# Create a GPT disk image with an EFI partition containing the EFI image.
class Image < Builder
def run(options)
unless @cache.up_to_date?(@target, nil, @sources, @env)
print_run_message("Creating disk image <target>#{@target}<reset>", nil)
efi_image_size = File.stat(@sources.first).size
efi_image_size_mb = (efi_image_size + MB - 1) / MB
partition_size_mb = efi_image_size_mb + 1
empty_mb = "\0".b * MB
File.binwrite(@target, empty_mb * partition_size_mb)
system(*%W[mformat -i #{@target} ::])
system(*%W[mmd -i #{@target} ::/EFI])
system(*%W[mmd -i #{@target} ::/EFI/BOOT])
system(*%W[mcopy -i #{@target} #{@sources.first} ::/EFI/BOOT/BOOTX64.EFI])
partition_contents = File.binread(@target)
disk_image = empty_mb + partition_contents + empty_mb
File.binwrite(@target, disk_image)
system(*%W[parted --script #{@target} mklabel gpt mkpart HOS fat32 1MiB #{partition_size_mb + 1}MiB])
@cache.register_build(@target, nil, @sources, @env)
end
true
end
end
class CheckThreadLocal < Builder
def run(options)
map_file = File.binread(@sources.first)
if map_file =~ /\.(tdata|tbss)\b/
$stderr.puts "Error: found thread-local data in #{@sources.first}"
false
else
true
end
end
end
class FontGen < Builder
def run(options)
if @command
finalize_command
else
fontgen = @vars["fontgen"]
@sources += [fontgen]
command = %W[#{fontgen} #{@sources.first} #{KFONT_SIZE} #{@target}]
standard_command("FontGen <target>#{@target}<reset>", command, {})
end
end
end
fontgen_env = env "fontgen", use: "freetype" do |env|
env.Program("^/fontgen", glob("src/fontgen/**/*.c"))
end
hulk_env = env "hulk", use: %w[ldc2 x86_64-elf-gcc] do |env|
env.add_builder(FontGen)
env.add_builder(CheckThreadLocal)
env.FontGen("^/src/hulk/kfont.d", "font/Hack-Regular.ttf",
"fontgen" => fontgen_env.expand("^/fontgen"))
env["sources"] = glob("src/hulk/**/*.d")
env["sources"] << "^/src/hulk/kfont.d"
cpu_attrs = %w[
-avx
-avx2
-avx512bf16
-avx512bitalg
-avx512bw
-avx512cd
-avx512dq
-avx512er
-avx512f
-avx512ifma
-avx512pf
-avx512vbmi
-avx512vbmi2
-avx512vl
-avx512vnni
-avx512vp2intersect
-avx512vpopcntdq
-sse
-sse-unaligned-mem
-sse2
-sse3
-sse4.1
-sse4.2
-sse4a
-ssse3
]
env["DFLAGS"] += %W[-g -mtriple=x86_64-unknown-elf -mattr=#{cpu_attrs.join(",")} --betterC -release -O3 --wi --enable-cross-module-inlining -code-model=large --disable-red-zone]
env["D_IMPORT_PATH"] += %w[src]
env["D_IMPORT_PATH"] << env.expand("^/src")
env["LD"] = "x86_64-elf-gcc"
env["LDFLAGS"] += %w[-g -nostdlib -Tsrc/hulk/hulk.ld -Wl,--gc-sections -Wl,-Map,${_TARGET}.map -Wl,--no-warn-rwx-segments]
env["LDCMD"] = %w[${LD} -o ${_TARGET} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}]
env["OBJDUMP"] = "x86_64-elf-objdump"
env["OBJCOPY"] = "x86_64-elf-objcopy"
env.Program("^/hulk.elf", "${sources}")
env.produces("^/hulk.elf", "^/hulk.elf.map")
env.CheckThreadLocal(:hulk_map_check, "^/hulk.elf.map")
env.depends("^/hulk.elf", "src/hulk/hulk.ld")
env["SIZE"] = "x86_64-elf-size"
env.Size("^/hulk.elf.size", "^/hulk.elf")
env.Disassemble("^/hulk.elf.txt", "^/hulk.elf")
env.Command("^/hulk.bin", "^/hulk.elf",
"CMD" => %W[${OBJCOPY} -O binary ${_SOURCES} ${_TARGET}],
"CMD_DESC" => "Convert ELF to binary:")
env.add_build_hook do |builder|
if builder.target.end_with?(".o")
env.Disassemble("#{builder.target}.txt", builder.target)
end
end
end
hello_env = env "hello", use: %w[ldc2 x86_64-w64-mingw32-gcc] do |env|
env.add_builder(Image)
env.add_builder(CheckThreadLocal)
env.add_builder(HulkBinObj)
env["sources"] = glob("src/hello/**/*.d")
env["sources"] += %w[
src/hulk/serial.d
src/hulk/writef.d
]
env["sources"] += glob("uefi-d/source/**/*.d")
env.HulkBinObj("^/hulk_bin.S", hulk_env.expand("^/hulk.bin"))
env.Object("^/hulk_bin.o", "^/hulk_bin.S")
env.depends("^/hulk_bin.o", hulk_env.expand("^/hulk.bin"))
env["sources"] << "^/hulk_bin.o"
env["DFLAGS"] += %w[-g -mtriple=x86_64-unknown-windows-coff --betterC -release -O3 --wi --enable-cross-module-inlining --disable-red-zone]
env["D_IMPORT_PATH"] += %w[src uefi-d/source]
env["LD"] = "x86_64-w64-mingw32-gcc"
env["LDFLAGS"] += %w[-g -nostdlib -Wl,-dll -shared -Wl,--subsystem,10 -e efi_main -Wl,-Map,${_TARGET}.map]
env["LDCMD"] = %w[${LD} -o ${_TARGET} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}]
env["OBJDUMP"] = "x86_64-w64-mingw32-objdump"
env.Program("^/HOS.EFI", "${sources}")
env.produces("^/HOS.EFI", "^/HOS.EFI.map")
env.CheckThreadLocal(:hos_map_check, "^/HOS.EFI.map")
env["SIZE"] = "x86_64-w64-mingw32-size"
env.Size("^/HOS.size", "^/HOS.EFI")
env.Disassemble("^/HOS.txt", "^/HOS.EFI")
env.Image("^/HOS.img", "^/HOS.EFI")
end
task "run", desc: "Run HOS in QEMU" do
FileUtils.rm_rf("qemu")
FileUtils.mkdir_p("qemu")
img = hello_env.expand("^/HOS.img")
FileUtils.cp(img, "qemu")
ovmf = "OVMF.fd"
if File.exist?("/usr/share/edk2/x64/OVMF.fd")
ovmf = "/usr/share/edk2/x64/OVMF.fd"
end
sh %W[
qemu-system-x86_64
-machine q35
-cpu max
-smp cpus=4
-serial file:qemu/serial.out
-bios #{ovmf}
-drive file=qemu/HOS.img,format=raw
-device qemu-xhci
-device usb-tablet]
end
# See README.md for how to set up VirtualBox for HOS.
task "mk-vmdk", desc: "Create VirtualBox VMDK virtual drive for HOS" do
path = File.expand_path(hello_env.expand("^/HOS.img"))
sectors = File.stat(path).size / 512
File.binwrite("HOS.vmdk", <<EOF)
# Disk DescriptorFile
version=1
CID=1d1c3615
parentCID=ffffffff
createType="fullDevice"
# Extent description
RW #{sectors} FLAT "#{path}" 0
# The disk Data Base
#DDB
ddb.virtualHWVersion = "4"
ddb.adapterType="ide"
ddb.geometry.cylinders="8"
ddb.geometry.heads="16"
ddb.geometry.sectors="63"
ddb.uuid.image="03783b5a-7587-4d8b-ad04-9d70f70a94c2"
ddb.uuid.parent="00000000-0000-0000-0000-000000000000"
ddb.uuid.modification="00000000-0000-0000-0000-000000000000"
ddb.uuid.parentmodification="00000000-0000-0000-0000-000000000000"
ddb.geometry.biosCylinders="8"
ddb.geometry.biosHeads="16"
ddb.geometry.biosSectors="63"
EOF
#sh %W[VBoxManage createmedium disk --filename=HOS.vmdk --variant=RawDisk --format=VMDK --property RawDrive=#{File.expand_path(hello_env.expand("^/HOS.img"))}]
end
# See README.md for how to set up VirtualBox for HOS.
task "run-vb", desc: "Run HOS in VirtualBox" do
sh %W[VBoxManage startvm HOS]
end