initial_state.S stopped working...
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@
|
||||
*.o
|
||||
*.so
|
||||
*.tmp
|
||||
tmp.S
|
||||
|
||||
17
Makefile
17
Makefile
@@ -1,17 +1,18 @@
|
||||
.POSIX:
|
||||
|
||||
IN_EXT ?= .S
|
||||
ASM_EXT ?= .asm
|
||||
S_EXT ?= .S
|
||||
LD ?= ld
|
||||
LINKER_SCRIPT ?= linker.ld
|
||||
# Use gcc so that the preprocessor will run first.
|
||||
MYAS ?= gcc
|
||||
GAS ?= gcc
|
||||
OBJ_EXT ?= .o
|
||||
OUT_EXT ?= .img
|
||||
QEMU ?= qemu-system-i386
|
||||
RUN ?= bios_hello_world
|
||||
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)
|
||||
|
||||
.PRECIOUS: %$(OBJ_EXT)
|
||||
@@ -22,8 +23,11 @@ all: $(OUTS)
|
||||
%$(OUT_EXT): %$(OBJ_EXT) $(LINKER_SCRIPT)
|
||||
$(LD) --oformat binary -o '$@' -T '$(LINKER_SCRIPT)' '$<'
|
||||
|
||||
%$(OBJ_EXT): %$(IN_EXT)
|
||||
$(MYAS) -c -o '$@' '$<'
|
||||
%$(OBJ_EXT): %$(S_EXT)
|
||||
$(GAS) -c -o '$@' '$<'
|
||||
|
||||
%$(OUT_EXT): %$(ASM_EXT)
|
||||
nasm -f bin -o '$@' '$<'
|
||||
|
||||
clean:
|
||||
rm -fr *$(OBJ_EXT) *$(OUT_EXT) *$(TMP_EXT)
|
||||
@@ -37,7 +41,8 @@ debug: all
|
||||
|
||||
bochs: all
|
||||
# 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))" && \
|
||||
bochs -qf /dev/null \
|
||||
'ata0-master: type=disk, path="$(RUN_FILE)", mode=flat, cylinders='"$$CYLINDERS"', heads=1, spt=1' \
|
||||
|
||||
@@ -22,6 +22,8 @@ Hello world programs that run without an operating system.
|
||||
1. [keyboard](bios_keyboard.S)
|
||||
1. [keyboard loop](bios_keyboard_loop.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. [Not testable in userland](not-testable-in-userland.md)
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
Grub 2.0 makes several calls to it under `grub-core/boot/i386/pc`
|
||||
|
||||
TODO: not working on:
|
||||
|
||||
- Bochs: `BOUND_GdMa: fails bounds test`.
|
||||
@@ -11,14 +13,15 @@ TODO: not working on:
|
||||
|
||||
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
|
||||
- https://en.wikipedia.org/wiki/INT_13H
|
||||
- https://thiscouldbebetter.wordpress.com/2011/03/15/creating-a-bootable-program-in-assembly-language/
|
||||
|
||||
TODO answer:
|
||||
|
||||
- https://en.wikipedia.org/wiki/INT_13H
|
||||
- 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
|
||||
*/
|
||||
@@ -67,13 +70,12 @@ just after the magic bytes.
|
||||
*/
|
||||
.section .stage2
|
||||
stage2:
|
||||
PUTC($0x0E40)
|
||||
PUTC($0x40)
|
||||
hlt
|
||||
|
||||
/*
|
||||
Fill up the second sector to 512 byte.
|
||||
|
||||
This should be on the linker script as well in decent programs,
|
||||
but let's just put it here to keep our other images smaller.
|
||||
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,
|
||||
so we use that instead.
|
||||
*/
|
||||
.org 512
|
||||
|
||||
/*.org 512*/
|
||||
|
||||
12
bios_disk_load2.S
Normal file
12
bios_disk_load2.S
Normal 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
|
||||
27
common.h
27
common.h
@@ -89,6 +89,8 @@ end:
|
||||
/*
|
||||
Print a byte as two hexadecimal digits.
|
||||
|
||||
reg: 1 byte register.
|
||||
|
||||
Clobbers: ax, dl
|
||||
*/
|
||||
#define PRINT_HEX(reg) \
|
||||
@@ -127,3 +129,28 @@ loop:
|
||||
jmp loop
|
||||
end:
|
||||
.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:
|
||||
|
||||
@@ -17,19 +17,39 @@ Could be done with GDB on the emulator, but this will also work on real hardware
|
||||
PRINT_HEX(x);\
|
||||
PRINT_NEWLINE
|
||||
|
||||
BEGIN
|
||||
|
||||
INITIAL_STORE(ax)
|
||||
INITIAL_STORE(bx)
|
||||
INITIAL_STORE(cx)
|
||||
INITIAL_STORE(dx)
|
||||
/*
|
||||
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(bx)
|
||||
INITIAL_PRINT(cx)
|
||||
INITIAL_PRINT(dx)
|
||||
/*
|
||||
TODO this breaks if I add more code here.
|
||||
Linked to STAGE2 load I imagine.
|
||||
*/
|
||||
/*
|
||||
INITIAL_PRINT(cs)
|
||||
INITIAL_PRINT(ds)
|
||||
INITIAL_PRINT(es)
|
||||
INITIAL_PRINT(fs)
|
||||
INITIAL_PRINT(gs)
|
||||
INITIAL_PRINT(ss)
|
||||
*/
|
||||
|
||||
hlt
|
||||
|
||||
@@ -37,4 +57,11 @@ INITIAL_DATA(ax)
|
||||
INITIAL_DATA(bx)
|
||||
INITIAL_DATA(cx)
|
||||
INITIAL_DATA(dx)
|
||||
/*
|
||||
INITIAL_DATA(cs)
|
||||
INITIAL_DATA(ds)
|
||||
INITIAL_DATA(es)
|
||||
INITIAL_DATA(fs)
|
||||
INITIAL_DATA(gs)
|
||||
INITIAL_DATA(ss)
|
||||
*/
|
||||
|
||||
14
linker.ld
14
linker.ld
@@ -29,6 +29,20 @@ SECTIONS
|
||||
e.g. by reading more disk than the default 512 bytes with BIOS `int 0x13`.
|
||||
*/
|
||||
*(.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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
1
nasm/Makefile
Symbolic link
@@ -0,0 +1 @@
|
||||
../Makefile
|
||||
@@ -1,6 +1,16 @@
|
||||
/*
|
||||
# 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.
|
||||
|
||||
- http://wiki.osdev.org/Journey_To_The_Protected_Land
|
||||
|
||||
@@ -9,10 +9,18 @@ On failure, trash is shows.
|
||||
|
||||
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.
|
||||
|
||||
## 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
|
||||
|
||||
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://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
|
||||
|
||||
@@ -43,7 +52,6 @@ The command:
|
||||
Shows that non ds encodings are achieved through a prefix, except for `ds`:
|
||||
|
||||
20: a0 63 7c mov 0x7c63,%al
|
||||
29: a0 63 7c mov 0x7c63,%al
|
||||
34: 26 a0 63 7c mov %es:0x7c63,%al
|
||||
40: 64 a0 63 7c mov %fs:0x7c63,%al
|
||||
4c: 65 a0 63 7c mov %gs:0x7c63,%al
|
||||
@@ -67,7 +75,10 @@ BEGIN
|
||||
mov %ds:msg, %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
|
||||
PUTC(%al)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user