initial_state.S stopped working...
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@
|
|||||||
*.o
|
*.o
|
||||||
*.so
|
*.so
|
||||||
*.tmp
|
*.tmp
|
||||||
|
tmp.S
|
||||||
|
|||||||
17
Makefile
17
Makefile
@@ -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' \
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
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.
|
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:
|
||||||
|
|||||||
@@ -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)
|
||||||
|
*/
|
||||||
|
|||||||
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`.
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
# 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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user