From 7dc6e56e16966f383aae31571e0337dee95d77ea Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Fri, 18 Sep 2015 11:35:08 +0200 Subject: [PATCH] big-img, chainload self --- .gitignore | 1 + Makefile | 20 ++++++++++++++++- README.md | 21 +++++++++++++++++- bios_carriage_return.S | 26 ++++++++++++++++++++++ bios_clear_screen.S | 29 +++++++++++++++++++++++++ bios_newline.S | 26 ++++++++++++++++++++++ bios_one_char.S | 8 +++++-- grub/Makefile | 13 +++++++++++ grub/chainloader/README.md | 2 ++ grub/chainloader/iso/boot/grub/grub.cfg | 8 ++++--- 10 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 bios_carriage_return.S create mode 100644 bios_clear_screen.S create mode 100644 bios_newline.S create mode 100644 grub/Makefile diff --git a/.gitignore b/.gitignore index 04443a8..9c06510 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ *.iso *.o *.so +*.tmp diff --git a/Makefile b/Makefile index 01f18a4..0518791 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ MYAS ?= gcc OBJ_EXT ?= .o OUT_EXT ?= .img RUN ?= bios_hello_world +TMP_EXT ?= .tmp INS := $(wildcard *$(IN_EXT)) OUTS := $(patsubst %$(IN_EXT),%$(OUT_EXT),$(INS)) @@ -24,7 +25,24 @@ all: $(OUTS) $(MYAS) -c -o '$@' '$<' clean: - rm -f *$(OBJ_EXT) *$(OUT_EXT) + rm -fr *$(OBJ_EXT) *$(OUT_EXT) *$(TMP_EXT) run: all qemu-system-i386 '$(RUN)$(OUT_EXT)' + +BIG_IMG_DIR := big_img$(TMP_EXT) +BOOT_DIR := $(BIG_IMG_DIR)/boot +GRUB_DIR := $(BOOT_DIR)/grub +big-img: all + rm -rf '$(BIG_IMG_DIR)' + mkdir -p '$(GRUB_DIR)' + for out in $(OUTS); do\ + printf "menuentry \"$${out%.*}\" {\n chainloader /boot/$$out\n}\n" >> '$(GRUB_DIR)/grub.cfg';\ + cp "$$out" '$(BOOT_DIR)';\ + done + # TODO why does this fail to boot properly? + #make -C multiboot/hello-world + #mkdir -p '$(BOOT_DIR)/multiboot' + #printf "menuentry \"multiboot/hello-world\" {\n chainloader /boot/multiboot/hello-world.img\n}\n" >> '$(GRUB_DIR)/grub.cfg';\ + #cp multiboot/hello-world/main.img '$(BOOT_DIR)/multiboot/hello-world.img' + grub-mkrescue -o 'big.img' '$(BIG_IMG_DIR)' diff --git a/README.md b/README.md index e49e5be..23fb769 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,9 @@ Hello world programs that run without an operating system. 1. BIOS 1. [BIOS one char](bios_one_char.S) 1. [BIOS hello world](bios_hello_world.S) + 1. [BIOS newline](bios_newline.S) + 1. [BIOS carriage return](bios_carriage_return.S) + 1. [BIOS clear screen](bios_clear_screen.S) 1. APM 1. [APM shutdown](apm_shutdown.S) 1. [APM shutdown 2](apm_shutdown2.S) @@ -31,6 +34,8 @@ Hello world programs that run without an operating system. sudo apt-get install build-essential gnu-efi qemu nasm xorriso +### Emulator + Run the default program on QEMU: make run @@ -42,7 +47,9 @@ Run a given program: Tested on Ubuntu 14.04 AMD64. -To run on real hardware, insert an USB, determine its device (`/dev/sdX`) with: +### Real hardware + +Insert an USB, determine its device (`/dev/sdX`) with: sudo lsblk sudo fdisk -l @@ -58,3 +65,15 @@ Then: - choose to boot from the USB Tested on: ThinkPad T400. + +#### Big image + +Create a `big.img` that contains all examples that can be booted from GRUB: + + make big-img + +Now if you do: + + sudo dd if=big.img of=/dev/sdX + +you can test several examples with a single USB burn, which is much faster. diff --git a/bios_carriage_return.S b/bios_carriage_return.S new file mode 100644 index 0000000..ed0484c --- /dev/null +++ b/bios_carriage_return.S @@ -0,0 +1,26 @@ +/* +What happens when a newline is output with bios. + +Outcome: + + hello + world + +Carriage returns are needed just like in old days. +*/ + +#include "common.h" +BEGIN + mov $msg, %si + mov $0x0e, %ah +loop: + lodsb + or %al, %al + jz halt + int $0x10 + jmp loop +halt: + hlt +msg: + .asciz "hello\n\rworld" +END diff --git a/bios_clear_screen.S b/bios_clear_screen.S new file mode 100644 index 0000000..72e6d4a --- /dev/null +++ b/bios_clear_screen.S @@ -0,0 +1,29 @@ +/* +Clear screen by scrolling. +*/ + +#include "common.h" +BEGIN + +/* +Print one char to ensure that something will be claered. + +On some systems, BIOS messages get automatically cleared. Not the case for QEMU 2.0.0. +*/ +mov $0x0E40, %ax +int $0x10 + +/* Function ID. */ +mov $0x06, %ah +/* nr. of lines to scroll, 00 means clear window. */ +mov $0x0, %al +/* TODO: I think this is the style. */ +mov $0x7, %bh +/* CH,CL: row,column upper left corner (00:00) */ +mov $0x0, %cx +/* DH,DL: row,column lower right corner (24:79) */ +mov $0x184f, %dx +int $0x10 + +hlt +END diff --git a/bios_newline.S b/bios_newline.S new file mode 100644 index 0000000..081a180 --- /dev/null +++ b/bios_newline.S @@ -0,0 +1,26 @@ +/* +What happens when a newline is output with bios. + +Outcome: + + hello + world + +Carriage returns are needed just like in old days. +*/ + +#include "common.h" +BEGIN + mov $msg, %si + mov $0x0e, %ah +loop: + lodsb + or %al, %al + jz halt + int $0x10 + jmp loop +halt: + hlt +msg: + .asciz "hello\nworld" +END diff --git a/bios_one_char.S b/bios_one_char.S index 617fbe8..e0ac4fb 100644 --- a/bios_one_char.S +++ b/bios_one_char.S @@ -1,12 +1,16 @@ /* Print a single `@` character with the BIOS. + More minimal than the hello world. */ #include "common.h" BEGIN -mov $0x40, %al -mov $0x0e, %ah +/* +40 == ASCII for '@' +0E == BIOS function ID. +*/ +mov $0x0E40, %ax int $0x10 hlt END diff --git a/grub/Makefile b/grub/Makefile new file mode 100644 index 0000000..2f83334 --- /dev/null +++ b/grub/Makefile @@ -0,0 +1,13 @@ +.POSIX: + +.PHONY: clean run + +main.img: + make -C '../mbrs' && cp '../bios_hello_world.img.sym' 'iso/boot/main.img' + grub-mkrescue -o '$@' iso + +clean: + rm -f iso/boot/*.img *.img + +run: main.img + qemu-system-i386 -hda '$<' diff --git a/grub/chainloader/README.md b/grub/chainloader/README.md index d2e4a21..c35deda 100644 --- a/grub/chainloader/README.md +++ b/grub/chainloader/README.md @@ -11,3 +11,5 @@ This example uses a file, but the most common way to use it is with: chainloader +1 which uses the first sector of some partition instead of a file. + +TODO: why does it fail for hybrid ISO images? diff --git a/grub/chainloader/iso/boot/grub/grub.cfg b/grub/chainloader/iso/boot/grub/grub.cfg index 3f71355..12b61a9 100644 --- a/grub/chainloader/iso/boot/grub/grub.cfg +++ b/grub/chainloader/iso/boot/grub/grub.cfg @@ -1,5 +1,7 @@ -set timeout=0 -set default="0" -menuentry "main" { +menuentry "hello-world" { chainloader /boot/main.img } +# Reload ourselves again. +menuentry "self +1" { + chainloader +1 +}