diff --git a/README.md b/README.md index d8d45b6..67ff2f3 100644 --- a/README.md +++ b/README.md @@ -52,16 +52,27 @@ where: - `` is the kernel file to boot - `` is the command line to pass to the kernel - don't forget to pass `root=` as `mlbinstall` will not calculate the root device. Currently - the command line cannot be longer than 40 characters (more just won't fit in - the MBR). + the command line cannot be longer than 80 bytes (more just won't fit in the + MBR). - `[-vbr]` will make `mlbinstall` ignore the space for the partition table, - giving you more space for the command line. You can safely use it if you're - installing to a Volume Boot Record (partition) and not the Master Boot - Record, e.g. for using with another bootloader in multi-OS setups. + giving you 144 bytes for the command line. You can safely use it if you're + installing to a Volume Boot Record (partition), e.g. for using with another + bootloader in multi-OS setups. `mlbinstall` is quite noisy if it detects any problems. Restore your MBR from backup, fix the problems, and try again. If it succeeds, it won't say anything. +Error codes +----------- + +If MLB fails to boot your kernel, it will print a one-letter error code. +Currently, there are two error codes: + + Error What it means + ----- ---------------------------------------- + R Failed reading data from disk + M Failed moving data to its final location + Contact ------- diff --git a/mlb.asm b/mlb.asm index 9fcaeec..dc4c80d 100644 --- a/mlb.asm +++ b/mlb.asm @@ -68,13 +68,6 @@ read_kernel_setup: mov cx, 0x1000 call read_from_hdd -check_version: - - cmp word [es:0x206], 0x204 ; we need protocol version >= 2.04 - jb error - test byte [es:0x211], 1 - jz error - set_header_fields: mov byte [es:0x210], 0xe1 ; set type_of_loader @@ -149,6 +142,7 @@ read_from_hdd: mov si, dap mov dl, 0x80 ; first hard disk int 0x13 + mov al, 'R' jc error pop edx ret @@ -162,6 +156,7 @@ do_move: mov ah, 0x87 mov si, gdt int 0x15 + mov al, 'M' jc error pop es pop edx @@ -169,24 +164,12 @@ do_move: error: - mov si, error_msg - -msg_loop: - - lodsb - and al, al - jz reboot mov ah, 0xe - mov bx, 7 + xor bh, bh int 0x10 - jmp short msg_loop - -reboot: - - xor ax, ax - int 0x16 - int 0x19 - jmp 0xf000:0xfff0 ; BIOS reset code +.hlt: + hlt + jmp error.hlt ; Global Descriptor Table @@ -223,6 +206,5 @@ dap: dd 0 ; low bytes of LBA address dd 0 ; high bytes of LBA address -error_msg db 'err', 0 current_lba dd 0xefbeadde ; mlbinstall replaces this with the kernel LBA cmd_line db 0 diff --git a/mlbinstall.c b/mlbinstall.c index 3e90da4..793d7cd 100644 --- a/mlbinstall.c +++ b/mlbinstall.c @@ -19,12 +19,16 @@ * along with mlbinstall. If not, see . */ +#define _BSD_SOURCE #define _POSIX_C_SOURCE 200809L #define _XOPEN_SOURCE 500 #include -#include +#include +#include #include +#include +#include #include #include #include @@ -32,12 +36,40 @@ #include #include #include -#include #include #include #include "mlb_bin.h" +/* Checks if the kernel boot protocol is supported */ +void check_version(const char *kernel) +{ + int fd = open(kernel, O_RDONLY); + if (fd == -1) + err(1, "Failed opening %s", kernel); + + long ps = sysconf(_SC_PAGESIZE); + size_t mlength = (512 / ps + 1) * ps; + uint8_t *m = mmap(NULL, mlength, PROT_READ, MAP_PRIVATE, fd, 0); + if (m == MAP_FAILED) + err(1, "Failed mapping %s", kernel); + + uint32_t header = *(uint32_t *)(m + 0x202); + uint16_t version = be16toh(*(uint16_t *)(m + 0x206)); + uint8_t loadflags = m[0x211]; + + if (header != 0x53726448) + errx(1, "%s is missing a Linux kernel header", kernel); + if (version < 0x204) + errx(1, "Kernel too old, boot protocol version >= 0x204/\ +kernel version >= 2.6.14 required, but %s is 0x%x", kernel, version); + if (!(loadflags & 0x01)) + errx(1, "Kernel needs to be loaded high"); + + munmap(m, mlength); + close(fd); +} + /* Returns the length of cmdline, including the terminating null. */ uint16_t cmdlen(const char *cmdline, size_t mlblen, size_t mbrlen) { @@ -171,6 +203,8 @@ argument to not reserve space for a partition table and gain an extra\n\ const char *kernel = argv[2]; const char *cmdline = argv[3]; + check_version(kernel); + size_t mbr_len = vbr ? 510 : 446; uint16_t cmdline_len = cmdlen(cmdline, mlb_bin_len, mbr_len); uint32_t kernel_lba = lba(kernel);