mirror of
https://github.com/limine-bootloader/limine
synced 2024-12-24 14:56:49 +03:00
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:
parent
ea62cf37c7
commit
7bde0c80ca
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,5 +1,8 @@
|
||||
/**/*.o
|
||||
/**/*.a
|
||||
/**/*.bc
|
||||
/**/*.bin
|
||||
/**/*.elf
|
||||
/**/*.img
|
||||
/bochsout.txt
|
||||
/bx_enh_dbg.ini
|
||||
|
41
Makefile
41
Makefile
@ -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
|
||||
|
49
README.md
49
README.md
@ -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
|
||||
|
@ -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;
|
||||
|
BIN
limine.bin
BIN
limine.bin
Binary file not shown.
40
src/Makefile
40
src/Makefile
@ -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)
|
||||
|
@ -1,4 +1,4 @@
|
||||
OUTPUT_FORMAT(binary)
|
||||
OUTPUT_FORMAT(elf32-i386)
|
||||
ENTRY(main)
|
||||
|
||||
SECTIONS
|
||||
|
@ -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>
|
||||
|
3
toolchain/.gitignore
vendored
3
toolchain/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
||||
!make_toolchain.sh
|
@ -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
|
Loading…
Reference in New Issue
Block a user