initial_state.S stopped working...

This commit is contained in:
Ciro Santilli
2015-10-06 12:27:24 +02:00
parent 61f0ad8dda
commit b9b4da0d1e
11 changed files with 139 additions and 56 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@
*.o *.o
*.so *.so
*.tmp *.tmp
tmp.S

View File

@@ -1,17 +1,18 @@
.POSIX: .POSIX:
IN_EXT ?= .S ASM_EXT ?= .asm
S_EXT ?= .S
LD ?= ld LD ?= ld
LINKER_SCRIPT ?= linker.ld LINKER_SCRIPT ?= linker.ld
# Use gcc so that the preprocessor will run first. # Use gcc so that the preprocessor will run first.
MYAS ?= gcc GAS ?= gcc
OBJ_EXT ?= .o OBJ_EXT ?= .o
OUT_EXT ?= .img OUT_EXT ?= .img
QEMU ?= qemu-system-i386 QEMU ?= qemu-system-i386
RUN ?= bios_hello_world RUN ?= bios_hello_world
TMP_EXT ?= .tmp TMP_EXT ?= .tmp
OUTS := $(patsubst %$(IN_EXT),%$(OUT_EXT),$(wildcard *$(IN_EXT))) OUTS := $(foreach IN_EXT,$(ASM_EXT) $(S_EXT),$(patsubst %$(IN_EXT),%$(OUT_EXT),$(wildcard *$(IN_EXT))))
RUN_FILE := $(RUN)$(OUT_EXT) RUN_FILE := $(RUN)$(OUT_EXT)
.PRECIOUS: %$(OBJ_EXT) .PRECIOUS: %$(OBJ_EXT)
@@ -22,8 +23,11 @@ all: $(OUTS)
%$(OUT_EXT): %$(OBJ_EXT) $(LINKER_SCRIPT) %$(OUT_EXT): %$(OBJ_EXT) $(LINKER_SCRIPT)
$(LD) --oformat binary -o '$@' -T '$(LINKER_SCRIPT)' '$<' $(LD) --oformat binary -o '$@' -T '$(LINKER_SCRIPT)' '$<'
%$(OBJ_EXT): %$(IN_EXT) %$(OBJ_EXT): %$(S_EXT)
$(MYAS) -c -o '$@' '$<' $(GAS) -c -o '$@' '$<'
%$(OUT_EXT): %$(ASM_EXT)
nasm -f bin -o '$@' '$<'
clean: clean:
rm -fr *$(OBJ_EXT) *$(OUT_EXT) *$(TMP_EXT) rm -fr *$(OBJ_EXT) *$(OUT_EXT) *$(TMP_EXT)
@@ -37,7 +41,8 @@ debug: all
bochs: all bochs: all
# Supposes size is already multiples of 512. # Supposes size is already multiples of 512.
# `grub-mkrescue` seems to respect that. # We force that with our linker script,
# and `grub-mkrescue` also seems to respect it as well.
CYLINDERS="$$(($$(stat -c '%s' '$(RUN_FILE)') / 512))" && \ CYLINDERS="$$(($$(stat -c '%s' '$(RUN_FILE)') / 512))" && \
bochs -qf /dev/null \ bochs -qf /dev/null \
'ata0-master: type=disk, path="$(RUN_FILE)", mode=flat, cylinders='"$$CYLINDERS"', heads=1, spt=1' \ 'ata0-master: type=disk, path="$(RUN_FILE)", mode=flat, cylinders='"$$CYLINDERS"', heads=1, spt=1' \

View File

@@ -22,6 +22,8 @@ Hello world programs that run without an operating system.
1. [keyboard](bios_keyboard.S) 1. [keyboard](bios_keyboard.S)
1. [keyboard loop](bios_keyboard_loop.S) 1. [keyboard loop](bios_keyboard_loop.S)
1. [disk load](bios_disk_load.S) 1. [disk load](bios_disk_load.S)
1. [disk load 2](bios_disk_load2.S)
1. [Initial state](initial_state.S)
1. [reboot](reboot.S) 1. [reboot](reboot.S)
1. [Not testable in userland](not-testable-in-userland.md) 1. [Not testable in userland](not-testable-in-userland.md)
1. [Segment registers real mode](segment_registers_real_mode.S) 1. [Segment registers real mode](segment_registers_real_mode.S)
@@ -58,7 +60,7 @@ Hello world programs that run without an operating system.
## Getting started ## Getting started
sudo apt-get install bochs bochs-sdl build-essential gnu-efi qemu nasm xorriso sudo apt-get install bochs bochs-sdl build-essential gdb gnu-efi qemu nasm xorriso
### Emulator ### Emulator

View File

@@ -1,9 +1,11 @@
/* /*
Load one more sector from the disk Load one more sector from the disk
besides the first 512 bytes and do something with it.. besides the first 512 bytes and do something with it.
Expected outcome: `@` gets printed to the screen. Expected outcome: `@` gets printed to the screen.
Grub 2.0 makes several calls to it under `grub-core/boot/i386/pc`
TODO: not working on: TODO: not working on:
- Bochs: `BOUND_GdMa: fails bounds test`. - Bochs: `BOUND_GdMa: fails bounds test`.
@@ -11,14 +13,15 @@ TODO: not working on:
Does work on QEMU and Thinkpad T400. Does work on QEMU and Thinkpad T400.
Bibliography: ## int 13
BIOS call used for disk operations.
## Bibliography
- http://wiki.osdev.org/ATA_in_x86_RealMode_%28BIOS%29 - http://wiki.osdev.org/ATA_in_x86_RealMode_%28BIOS%29
- https://en.wikipedia.org/wiki/INT_13H
- https://thiscouldbebetter.wordpress.com/2011/03/15/creating-a-bootable-program-in-assembly-language/ - https://thiscouldbebetter.wordpress.com/2011/03/15/creating-a-bootable-program-in-assembly-language/
- https://en.wikipedia.org/wiki/INT_13H
TODO answer:
- http://stackoverflow.com/questions/19381434/cannot-read-disk-sectors-in-assembly-language - http://stackoverflow.com/questions/19381434/cannot-read-disk-sectors-in-assembly-language
- http://stackoverflow.com/questions/15497842/read-a-sector-from-hard-drive-with-int-13h - http://stackoverflow.com/questions/15497842/read-a-sector-from-hard-drive-with-int-13h
*/ */
@@ -67,13 +70,12 @@ just after the magic bytes.
*/ */
.section .stage2 .section .stage2
stage2: stage2:
PUTC($0x0E40) PUTC($0x40)
hlt hlt
/* /*
Fill up the second sector to 512 byte. We could use `.org` here to fill up the second sector to a multiple of 512 bytes.
But the linker does that beautifully with `. = ALIGN(512)` for any size of stage2,
This should be on the linker script as well in decent programs, so we use that instead.
but let's just put it here to keep our other images smaller.
*/ */
.org 512 /*.org 512*/

12
bios_disk_load2.S Normal file
View File

@@ -0,0 +1,12 @@
/* Test loading 2 sectors instead of 1. */
#include "common.h"
BEGIN
CLEAR
STAGE2
PUTC($0x61)
jmp sector3
.org 512
sector3:
PUTC($0x62)
hlt

View File

@@ -89,6 +89,8 @@ end:
/* /*
Print a byte as two hexadecimal digits. Print a byte as two hexadecimal digits.
reg: 1 byte register.
Clobbers: ax, dl Clobbers: ax, dl
*/ */
#define PRINT_HEX(reg) \ #define PRINT_HEX(reg) \
@@ -127,3 +129,28 @@ loop:
jmp loop jmp loop
end: end:
.endm .endm
/*
Load stage2 from disk to memory, and jump to it.
TODO not working?
To be used when the program does not fit in the 512 bytes.
Sample usage:
STAGE2
Stage 2 code here.
*/
#define STAGE2 \
mov $2, %ah;\
mov __stage2_size, %al;\
mov $0x80, %dl;\
mov $0, %ch;\
mov $0, %dh;\
mov $2, %cl;\
mov $1f, %bx;\
int $0x13;\
jmp 1f;\
.section .stage2;\
1:

View File

@@ -17,19 +17,39 @@ Could be done with GDB on the emulator, but this will also work on real hardware
PRINT_HEX(x);\ PRINT_HEX(x);\
PRINT_NEWLINE PRINT_NEWLINE
BEGIN
INITIAL_STORE(ax) INITIAL_STORE(ax)
INITIAL_STORE(bx) INITIAL_STORE(bx)
INITIAL_STORE(cx) INITIAL_STORE(cx)
INITIAL_STORE(dx) INITIAL_STORE(dx)
/*
INITIAL_STORE(cs) INITIAL_STORE(cs)
INITIAL_STORE(ds)
INITIAL_STORE(es)
INITIAL_STORE(fs)
INITIAL_STORE(gs)
INITIAL_STORE(ss)
*/
BEGIN
STAGE2
INITIAL_PRINT(ax) INITIAL_PRINT(ax)
INITIAL_PRINT(bx) INITIAL_PRINT(bx)
INITIAL_PRINT(cx) INITIAL_PRINT(cx)
INITIAL_PRINT(dx) INITIAL_PRINT(dx)
/*
TODO this breaks if I add more code here.
Linked to STAGE2 load I imagine.
*/
/*
INITIAL_PRINT(cs) INITIAL_PRINT(cs)
INITIAL_PRINT(ds)
INITIAL_PRINT(es)
INITIAL_PRINT(fs)
INITIAL_PRINT(gs)
INITIAL_PRINT(ss)
*/
hlt hlt
@@ -37,4 +57,11 @@ INITIAL_DATA(ax)
INITIAL_DATA(bx) INITIAL_DATA(bx)
INITIAL_DATA(cx) INITIAL_DATA(cx)
INITIAL_DATA(dx) INITIAL_DATA(dx)
/*
INITIAL_DATA(cs) INITIAL_DATA(cs)
INITIAL_DATA(ds)
INITIAL_DATA(es)
INITIAL_DATA(fs)
INITIAL_DATA(gs)
INITIAL_DATA(ss)
*/

View File

@@ -29,6 +29,20 @@ SECTIONS
e.g. by reading more disk than the default 512 bytes with BIOS `int 0x13`. e.g. by reading more disk than the default 512 bytes with BIOS `int 0x13`.
*/ */
*(.stage2) *(.stage2)
/*
Number of sectors in stage 2. Used by the `int 13`.
The value gets put into memory as the very last thing
in the `.stage` section if it exists.
We must put it *before* the final `. = ALIGN(512)`,
or else it would fall out of the loaded memory.
*/
__stage2_size = (ALIGN(.) / 512) - 1;
/* Ensure that the generated image is a multiple of 512. */
. = ALIGN(512);
} }
} }

View File

@@ -1,29 +0,0 @@
.POSIX:
RUN ?= bios_hello_world
IN_EXT ?= .asm
OUT_EXT ?= .img
OUTS := $(patsubst %$(IN_EXT),%$(OUT_EXT),$(wildcard *$(IN_EXT)))
RUN_FILE := $(RUN)$(OUT_EXT)
.PHONY: clean run
all: $(OUTS)
%$(OUT_EXT): %$(IN_EXT)
nasm -f bin -o '$@' '$<'
clean:
rm -f *'$(OUT_EXT)'
run: all
qemu-system-i386 '$(RUN_FILE)'
bochs: all
CYLINDERS="$$(($$(stat -c '%s' '$(RUN_FILE)') / 512))" && \
bochs -qf /dev/null \
'ata0-master: type=disk, path="$(RUN_FILE)", mode=flat, cylinders='"$$CYLINDERS"', heads=1, spt=1' \
'boot: disk' \
'display_library: sdl' \
'megs: 128'

1
nasm/Makefile Symbolic link
View File

@@ -0,0 +1 @@
../Makefile

View File

@@ -1,6 +1,16 @@
/* /*
# Protected mode # Protected mode
Major changes:
- BIOS cannot be used anymore
- GDT takes effect immediately so we *have* to deal with it now,
and we will later turn on paging
- we have to encode instructions differently.
Note that in 16-bit 32-bit instructions were encodable, but with a prefix.
TODO get working. TODO get working.
- http://wiki.osdev.org/Journey_To_The_Protected_Land - http://wiki.osdev.org/Journey_To_The_Protected_Land

View File

@@ -9,10 +9,18 @@ On failure, trash is shows.
I think their goal was to implement process virtualization in the past. I think their goal was to implement process virtualization in the past.
FS and GS are general purpose: they don't generate or are affected implicitly by instructions.
The special semantics of other registers will be covered in other files. The special semantics of other registers will be covered in other files.
## ES
TODO: this does seem to have special properties as used by string instructions.
## FS
## GS
FS and GS are general purpose: they don't generate or are affected implicitly by instructions.
## Vs protected mode ## Vs protected mode
In protected mode, the segment registers point to entries on the GDT: In protected mode, the segment registers point to entries on the GDT:
@@ -20,7 +28,8 @@ In protected mode, the segment registers point to entries on the GDT:
- http://reverseengineering.stackexchange.com/questions/2006/how-are-the-segment-registers-fs-gs-cs-ss-ds-es-used-in-linux - http://reverseengineering.stackexchange.com/questions/2006/how-are-the-segment-registers-fs-gs-cs-ss-ds-es-used-in-linux
- http://wiki.osdev.org/Segmentation - http://wiki.osdev.org/Segmentation
Those entries still contain an analogous offset to the real mode offset, but also much more data, like segment width and permission. Those entries still contain an analogous offset to the real mode offset,
but also much more data, like segment width and permission.
## How they work ## How they work
@@ -43,7 +52,6 @@ The command:
Shows that non ds encodings are achieved through a prefix, except for `ds`: Shows that non ds encodings are achieved through a prefix, except for `ds`:
20: a0 63 7c mov 0x7c63,%al 20: a0 63 7c mov 0x7c63,%al
29: a0 63 7c mov 0x7c63,%al
34: 26 a0 63 7c mov %es:0x7c63,%al 34: 26 a0 63 7c mov %es:0x7c63,%al
40: 64 a0 63 7c mov %fs:0x7c63,%al 40: 64 a0 63 7c mov %fs:0x7c63,%al
4c: 65 a0 63 7c mov %gs:0x7c63,%al 4c: 65 a0 63 7c mov %gs:0x7c63,%al
@@ -67,7 +75,10 @@ BEGIN
mov %ds:msg, %al mov %ds:msg, %al
PUTC(%al) PUTC(%al)
/* %ds is the default segment for GAS if we don't write it. */ /*
%ds is the default segment for GAS memory operations
if we don't write it explicitly.
*/
mov msg, %al mov msg, %al
PUTC(%al) PUTC(%al)