Move to clang, no longer ship prebuilt binary, embed bootloader into the installer and provide a way to install the installer

This commit is contained in:
mintsuki 2020-09-04 05:21:58 +02:00
parent ea62cf37c7
commit 7bde0c80ca
10 changed files with 93 additions and 146 deletions

3
.gitignore vendored
View File

@ -1,5 +1,8 @@
/**/*.o
/**/*.a
/**/*.bc
/**/*.bin
/**/*.elf
/**/*.img
/bochsout.txt
/bx_enh_dbg.ini

View File

@ -1,17 +1,32 @@
DESTDIR =
PREFIX = /usr/local
OS := $(shell uname)
CC = cc
CC = clang
OBJCOPY = llvm-objcopy
CFLAGS = -O2 -pipe -Wall -Wextra
.PHONY: all clean echfs-test ext2-test test.img
.PHONY: all install clean echfs-test ext2-test test.img
all:
$(MAKE) -C src all
cp src/limine.bin ./
all: limine-install
install: all
install -s limine-install $(DESTDIR)$(PREFIX)/bin/
clean:
rm -f limine-install
$(MAKE) -C src clean
limine-install: limine-install.c
$(CC) limine-install.c -o limine-install
src/limine.bin:
$(MAKE) -C src all
limine-install: src/limine.bin limine-install.c
$(CC) $(CFLAGS) -c limine-install.c -o limine-install.o
# FIXME: GNU objcopy supports `-O default` but for some stupid reason
# llvm-objcopy does not. This needs to be worked around.
# For now hardcode elf64-x86-64.
$(OBJCOPY) -I binary -O elf64-x86-64 src/limine.bin limine.o
$(CC) $(CFLAGS) limine.o limine-install.o -o limine-install
test.img:
rm -f test.img
@ -26,15 +41,15 @@ else ifeq ($(OS), FreeBSD)
sudo mdconfig -d -u md9
endif
echfs-test: limine-install test.img all
echfs-test: limine-install test.img
$(MAKE) -C test
echfs-utils -m -p0 test.img quick-format 32768
echfs-utils -m -p0 test.img import test/test.elf boot/test.elf
echfs-utils -m -p0 test.img import test/limine.cfg limine.cfg
./limine-install src/limine.bin test.img
./limine-install test.img
qemu-system-x86_64 -hda test.img -debugcon stdio -enable-kvm
ext2-test: limine-install test.img all
ext2-test: limine-install test.img
$(MAKE) -C test
rm -rf test_image/
mkdir test_image
@ -49,10 +64,10 @@ ext2-test: limine-install test.img all
sudo umount test_image/
sudo losetup -d `cat loopback_dev`
rm -rf test_image loopback_dev
./limine-install src/limine.bin test.img
./limine-install test.img
qemu-system-x86_64 -hda test.img -debugcon stdio
fat32-test: limine-install test.img all
fat32-test: limine-install test.img
$(MAKE) -C test
rm -rf test_image/
mkdir test_image
@ -77,5 +92,5 @@ else ifeq ($(OS), FreeBSD)
sudo mdconfig -d -u md9
endif
rm -rf test_image loopback_dev
./limine-install src/limine.bin test.img
./limine-install test.img
qemu-system-x86_64 -hda test.img -debugcon stdio

View File

@ -16,23 +16,35 @@ x86/x86_64 BIOS Bootloader
* MBR
* GPT
## How to use
This repository contains a prebuilt version of Limine so building it won't be necessary.
## Building
In order to install Limine on a MBR device (which can just be a raw image file), build the
`limine-install` program using `make limine-install`, then run the resulting executable as such:
### Dependencies
To build Limine, it is necessary to have an LLVM/Clang toolchain installed.
More specifically, the following programs need to be present: `clang`, `llvm-objcopy`,
`llvm-link`, `opt`, `ld.lld`.
Furthermore, `nasm` also needs to be installed.
`curl`, `tar`, and `zstd` need to be installed for retrieving `libgcc.a` during build.
### Compiling
A simple `make` and `make install` will suffice. Use the PREFIX variable with
`make install` to specify where to install `limine-install`. It defaults to
`/usr/local`.
## How to use
In order to install Limine on a MBR device (which can just be a raw image file),
run the `limine-install` as such:
```bash
./limine-install ./limine.bin <path to device/image>
limine-install <path to device/image>
```
If using a GPT formatted device, it will be necessary to create an extra partition
(of at least 32K in size) to store stage 2 code. Then it will be necessary to tell
the install script where this partition is located by specifying the start sector.
`limine-install` where this partition is located by specifying the start sector.
```bash
fdisk <device> # Create bootloader partition using your favourite method
./limine-install ./limine.bin <path to device/image> <start sector of boot partition>
limine-install <path to device/image> <start sector of boot partition>
```
Then make sure the device/image contains at least 1 partition formatted in
@ -58,33 +70,12 @@ echfs-utils -m -p0 test.img import path/to/limine.cfg limine.cfg
echfs-utils -m -p0 test.img import path/to/kernel.elf kernel.elf
echfs-utils -m -p0 test.img import <path to file> <path in image>
...
./limine-install $THIS_REPO/limine.bin test.img
limine-install test.img
```
One can get `echfs-utils` by installing https://github.com/qword-os/echfs.
## Building from source
In order to hack Limine, one must build the GCC toolchain from source first.
To do so, run the `make_toolchain.sh` script from within the `toolchain` directory;
keep in mind that the script takes `MAKEFLAGS` as an argument.
```bash
cd toolchain
./make_toolchain.sh -j4
```
After that is done, simply run `make` in the root of the repo to generate
`limine.bin`.
### Building from source with Clang
It is also possible to build Limine with Clang, using the following make command:
```bash
make CC="clang --target=i386-elf"
```
## Discord server
We have a Discord server if you need support, info, or you just want to
hang out: https://discord.gg/QEeZMz4

View File

@ -4,53 +4,45 @@
#include <stddef.h>
#include <inttypes.h>
extern char _binary_src_limine_bin_start[];
int main(int argc, char *argv[]) {
if (argc < 3) {
printf("Usage: %s <path to bootloader binary> <device> [stage2 start sector]\n", argv[0]);
if (argc < 2) {
printf("Usage: %s <device> [stage2 start sector]\n", argv[0]);
return 1;
}
FILE *ql2_bin = fopen(argv[1], "rb");
if (ql2_bin == NULL) {
perror("Error: ");
return 1;
}
FILE *device = fopen(argv[2], "r+b");
FILE *device = fopen(argv[1], "r+b");
if (device == NULL) {
perror("Error: ");
fclose(ql2_bin);
return 1;
}
uint32_t stage2_sect = 1;
if (argc >= 4)
sscanf(argv[3], "%" SCNu32, &stage2_sect);
if (argc >= 3)
sscanf(argv[2], "%" SCNu32, &stage2_sect);
// Save the original partition table of the device
char orig_mbr[64];
fseek(device, 446, SEEK_SET);
fread(orig_mbr, 1, 64, device);
char ql2_bootsect[512];
fseek(ql2_bin, 0, SEEK_SET);
fread(ql2_bootsect, 1, 512, ql2_bin);
// Write the bootsector from the bootloader to the device
fseek(device, 0, SEEK_SET);
fwrite(ql2_bootsect, 1, 512, device);
fwrite(&_binary_src_limine_bin_start[0], 1, 512, device);
char *ql2_stage2 = malloc(63 * 512);
fseek(ql2_bin, 512, SEEK_SET);
fread(ql2_stage2, 63, 512, ql2_bin);
// Write the rest of stage 2 to the device
fseek(device, stage2_sect * 512, SEEK_SET);
fwrite(ql2_stage2, 63, 512, device);
free(ql2_stage2);
fwrite(&_binary_src_limine_bin_start[512], 63, 512, device);
// Hardcode in the bootsector the location of stage 2
fseek(device, 0x1b0, SEEK_SET);
fwrite(&stage2_sect, 1, 4, device);
fwrite(&stage2_sect, 1, sizeof(uint32_t), device);
// Write back the saved partition table to the device
fseek(device, 446, SEEK_SET);
fwrite(orig_mbr, 1, 64, device);
fclose(ql2_bin);
fclose(device);
return 0;

Binary file not shown.

View File

@ -1,46 +1,50 @@
CC = ../toolchain/bin/i386-elf-gcc
LD = ../toolchain/bin/i386-elf-gcc
CFLAGS = -flto -Os -pipe -Wall -Wextra
OPT_LEVEL = z
CFLAGS = -pipe -Wall -Wextra
INTERNAL_CFLAGS = \
-O$(OPT_LEVEL) \
-std=gnu99 \
-ffreestanding \
-fno-pic \
-flto \
-mno-80387 \
-mno-mmx \
-mno-sse \
-mno-sse2 \
-fno-stack-protector \
-I. \
-Wno-address-of-packed-member
LDFLAGS = -flto -Os
INTERNAL_LDFLAGS = \
-static \
-nostdlib \
-no-pie \
-lgcc \
-static-libgcc \
-Tlinker.ld
-Tlinker.ld \
-no-pie
.PHONY: all clean
C_FILES := $(shell find ./ -type f -name '*.c' | sort)
ASM_FILES := $(shell find ./ -type f -name '*.asm' | grep -v bootsect | sort)
OBJ := $(C_FILES:.c=.o) $(ASM_FILES:.asm=.o)
ASM_OBJ := $(ASM_FILES:.asm=.o)
BC := $(C_FILES:.c=.bc)
all: limine.bin
limine.bin: $(OBJ)
$(LD) $(OBJ) $(LDFLAGS) $(INTERNAL_LDFLAGS) -o stage2.bin
limine.bin: libgcc.a $(BC) $(ASM_OBJ)
llvm-link $(BC) -o bundle.bc
opt --O$(OPT_LEVEL) bundle.bc -o optimised_bundle.bc
clang --target=i386-elf -O$(OPT_LEVEL) -c optimised_bundle.bc -o optimised_bundle.o
ld.lld optimised_bundle.o $(ASM_OBJ) libgcc.a $(INTERNAL_LDFLAGS) -o stage2.elf
llvm-objcopy -O binary stage2.elf stage2.bin
cd bootsect && nasm bootsect.asm -fbin -o ../limine.bin
%.o: %.c
$(CC) $(CFLAGS) $(INTERNAL_CFLAGS) -c $< -o $@
libgcc.a:
curl https://mirror.netcologne.de/archlinux/core/os/x86_64/gcc-10.2.0-2-x86_64.pkg.tar.zst | \
tar -I zstd -xv --strip-components=6 --occurrence=1 usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/32/libgcc.a
%.bc: %.c
clang --target=i386-elf $(CFLAGS) $(INTERNAL_CFLAGS) -c $< -o $@
%.o: %.asm
nasm $< -f elf32 -o $@
clean:
rm -f $(OBJ)
rm -f limine.bin $(ASM_OBJ) $(BC)

View File

@ -1,4 +1,4 @@
OUTPUT_FORMAT(binary)
OUTPUT_FORMAT(elf32-i386)
ENTRY(main)
SECTIONS

View File

@ -3,6 +3,8 @@
ASM_BASIC(
".section .entry\n\t"
"cld\n\t"
// Zero out .bss
"xor al, al\n\t"
"mov edi, OFFSET bss_begin\n\t"
@ -10,7 +12,8 @@ ASM_BASIC(
"sub ecx, OFFSET bss_begin\n\t"
"rep stosb\n\t"
"jmp main\n\t"
"mov ebx, OFFSET main\n\t"
"jmp ebx\n\t"
);
#include <limine.h>

View File

@ -1,3 +0,0 @@
*
!.gitignore
!make_toolchain.sh

View File

@ -1,58 +0,0 @@
#!/usr/bin/env bash
set -e
set -x
PREFIX="$(pwd)"
TARGET=i386-elf
BINUTILSVERSION=2.35
GCCVERSION=10.2.0
if [ -z "$MAKEFLAGS" ]; then
MAKEFLAGS="$1"
fi
export MAKEFLAGS
export PATH="$PREFIX/bin:$PATH"
if [ -x "$(command -v gmake)" ]; then
mkdir -p "$PREFIX/bin"
cat <<EOF >"$PREFIX/bin/make"
#!/usr/bin/env sh
gmake "\$@"
EOF
chmod +x "$PREFIX/bin/make"
fi
mkdir -p build
cd build
if [ ! -f binutils-$BINUTILSVERSION.tar.gz ]; then
wget -4 https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILSVERSION.tar.gz # Force IPv4 otherwise wget hangs
fi
if [ ! -f gcc-$GCCVERSION.tar.gz ]; then
wget -4 https://ftp.gnu.org/gnu/gcc/gcc-$GCCVERSION/gcc-$GCCVERSION.tar.gz # Same as above
fi
tar -xf binutils-$BINUTILSVERSION.tar.gz
tar -xf gcc-$GCCVERSION.tar.gz
rm -rf build-gcc build-binutils
mkdir build-binutils
cd build-binutils
../binutils-$BINUTILSVERSION/configure --target=$TARGET --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror
make
make install
cd ..
cd gcc-$GCCVERSION
contrib/download_prerequisites
cd ..
mkdir build-gcc
cd build-gcc
../gcc-$GCCVERSION/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c --without-headers
make all-gcc
make all-target-libgcc
make install-gcc
make install-target-libgcc