Compare commits
99 Commits
86d966811b
...
fat_v2
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a944bc493 | |||
| 137735431a | |||
| 6caaf6aa6d | |||
| 1e9de446f0 | |||
| 5f2ca55af7 | |||
| 11656c2827 | |||
| f87f88a0dc | |||
| 7baa53178a | |||
| 8002d1cb54 | |||
| d8a89cfd2b | |||
| 6c402b5c4f | |||
| a3c9897291 | |||
| 831d45c33c | |||
| 918e94689f | |||
| 8d2cde0a31 | |||
| 8d3788a76e | |||
| 4a27e09872 | |||
| 59bc1afb7c | |||
| 8b0b73d8a4 | |||
| 803be58c10 | |||
| 528e3d69fe | |||
| 51bd250925 | |||
| 460165a8d1 | |||
| 935cbd1089 | |||
| 7f1b4fa632 | |||
| 14f6788a22 | |||
| 526c3e7ea5 | |||
| 721ff2e62d | |||
| a50af35abd | |||
| 7cd6baa74d | |||
| 40fa4062ce | |||
| a8b24c7b01 | |||
| 58fc4a08dd | |||
| 3da2af2d2d | |||
| 75d77e92e1 | |||
| 8e6c823a00 | |||
| fca8a5d573 | |||
| f341a50b78 | |||
| ef22bc9cd3 | |||
| 507a05949f | |||
| caed66a243 | |||
| d5cd8d6c45 | |||
| b0f118b139 | |||
| 71d50cdbd8 | |||
| 3c654b1be0 | |||
| 0d90b3efd6 | |||
| b08605f295 | |||
| aa0efe5ff8 | |||
| 700148a2f6 | |||
| 14ef0151ca | |||
| 1d696371d2 | |||
| d30abe7a27 | |||
| d6f6076d45 | |||
| 4e05efaa6b | |||
| 7cc0b4a392 | |||
| 9a6fea658d | |||
| 891bff9509 | |||
| 1e181bc22c | |||
| 68c8200aa4 | |||
| 766c67c041 | |||
| 49d82be0e8 | |||
| 69bd7d8f56 | |||
| 875527aa98 | |||
| c0d47d4db0 | |||
| 81a3442ac5 | |||
| 3ec55f5a39 | |||
| 9493aefa68 | |||
| 6f2fc627be | |||
| 20c715fadd | |||
| 920c623a93 | |||
| af8e7d74d3 | |||
| fde7abc544 | |||
| 69223a1ad2 | |||
| 130cd22ff1 | |||
| 4e5112b45b | |||
| 66e8e3c7fc | |||
| b0bd4b27b0 | |||
| cd316afdd1 | |||
| 9a478aa4d4 | |||
| 31d05c35e5 | |||
| 534e04ef34 | |||
| f58bf93507 | |||
| b5ae11f850 | |||
| b9b3e92632 | |||
| 5fac10f02c | |||
| fa4524aa59 | |||
| 01ec6da0cc | |||
| 2e2b4f991d | |||
| d7b29d9113 | |||
| 69d82dc0c2 | |||
| a53534acd2 | |||
| c3871d2b7d | |||
| d824493ba2 | |||
| cb089681cf | |||
| d868008726 | |||
| 935427509a | |||
| f5e4927d70 | |||
| b106eae066 | |||
| f2657fdc01 |
2
.github/workflows/daily.yaml
vendored
2
.github/workflows/daily.yaml
vendored
@@ -3,7 +3,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: [ $default-branch ]
|
branches: [ $default-branch ]
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 7 * * *" # daily 07:00
|
- cron: "0 7 * * 1" # mondays at 07:00
|
||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -9,3 +9,6 @@ stevia-log
|
|||||||
.vscode/
|
.vscode/
|
||||||
*.map
|
*.map
|
||||||
compose-dev.yaml
|
compose-dev.yaml
|
||||||
|
eth_null-tx.log
|
||||||
|
eth_null-txdump.txt
|
||||||
|
*.log
|
||||||
140
Makefile
140
Makefile
@@ -13,74 +13,108 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
include := './include'
|
INCDIR := include
|
||||||
|
BUILD_DIR := build
|
||||||
mbr_source_files := $(wildcard src/mbr/*.nasm)
|
IMG := $(BUILD_DIR)/disk.img
|
||||||
vbr_source_files := $(wildcard src/vbr/*.nasm)
|
IMGZ := $(BUILD_DIR)/disk.img.gz
|
||||||
stage2_source_files := $(wildcard src/stage2/*.nasm)
|
DEP_DIR := $(BUILD_DIR)/deps
|
||||||
boottest_source_files := $(wildcard src/miniboot32/*.nasm)
|
|
||||||
|
|
||||||
mbr_binary_files := $(patsubst src/mbr/%.nasm, build/%.bin, $(mbr_source_files))
|
|
||||||
vbr_binary_files := $(patsubst src/vbr/%.nasm, build/%.bin, $(vbr_source_files))
|
|
||||||
stage2_binary_files := $(patsubst src/stage2/%.nasm, build/%.bin, $(stage2_source_files))
|
|
||||||
boottest_binary_files := $(patsubst src/miniboot32/%.nasm, build/%.bin, $(boottest_source_files))
|
|
||||||
|
|
||||||
build_dir := 'build'
|
|
||||||
|
|
||||||
# Get current Git version (tag) and hash
|
# Get current Git version (tag) and hash
|
||||||
GIT_VERSION := $(shell git describe --tags)
|
GIT_VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo unknown)
|
||||||
GIT_HASH := $(shell git rev-parse HEAD)
|
GIT_HASH := $(shell git rev-parse HEAD 2>/dev/null || echo unknown)
|
||||||
GIT_NASM_DEFINES := -D __GIT_VER__='"$(GIT_VERSION)"' -D __GIT_HASH__='"$(GIT_HASH)"'
|
GIT_NASM_DEFINES := -D __GIT_VER__='"$(GIT_VERSION)"' -D __GIT_HASH__='"$(GIT_HASH)"'
|
||||||
|
|
||||||
iso := 'build/disk.img'
|
NASMFLAGS := -Wall -f bin -i$(INCDIR)/ $(GIT_NASM_DEFINES)
|
||||||
isoz := 'build/output/disk.img.gz'
|
|
||||||
|
|
||||||
qemu_args := -L ./bin/ -bios bios.bin -cpu pentium3 -m 128 -S -s -monitor stdio -nic none
|
QEMU ?= qemu-system-i386
|
||||||
.PHONY: all mbr vbr stage2 boottest clean run run_bochs iso isoz
|
QEMU_ARGS := \
|
||||||
|
-M pc-i440fx-8.2,accel=tcg \
|
||||||
|
-cpu pentium3 \
|
||||||
|
-m 64M \
|
||||||
|
-rtc base=localtime \
|
||||||
|
-boot c \
|
||||||
|
-vga std \
|
||||||
|
-display gtk,gl=off \
|
||||||
|
-device e1000,netdev=n0,mac=52:54:00:12:34:56 \
|
||||||
|
-netdev user,id=n0 \
|
||||||
|
-device piix3-usb-uhci \
|
||||||
|
-parallel null \
|
||||||
|
-serial null -serial none -serial none -serial none \
|
||||||
|
-chardev file,id=dbg,path=bochs-e9.log,append=on \
|
||||||
|
-device isa-debugcon,iobase=0xe9,chardev=dbg \
|
||||||
|
-msg timestamp=on
|
||||||
|
|
||||||
all: $(iso) $(isoz) $(mbr_binary_files) $(vbr_binary_files) $(stage2_binary_files)
|
MBR_SRCS := $(wildcard src/mbr/*.nasm)
|
||||||
mbr: $(mbr_binary_files)
|
VBR_SRCS := $(wildcard src/vbr/*.nasm)
|
||||||
vbr: $(vbr_binary_files)
|
STAGE2_SRCS := $(wildcard src/stage2/*.nasm)
|
||||||
stage2: $(stage2_binary_files)
|
BOOTTEST_SRCS := $(wildcard src/miniboot32/*.nasm)
|
||||||
boottest: $(boottest_binary_files)
|
|
||||||
|
|
||||||
clean:
|
MBR_BINS := $(patsubst src/mbr/%.nasm, $(BUILD_DIR)/mbr/%.bin, $(MBR_SRCS))
|
||||||
@rm -v $(build_dir)/*.bin
|
VBR_BINS := $(patsubst src/vbr/%.nasm, $(BUILD_DIR)/vbr/%.bin, $(VBR_SRCS))
|
||||||
@rm -v $(build_dir)/*.map
|
STAGE2_BINS := $(patsubst src/stage2/%.nasm, $(BUILD_DIR)/stage2/%.bin, $(STAGE2_SRCS))
|
||||||
@rm -v $(build_dir)/*.img
|
BOOTTEST_BINS := $(patsubst src/miniboot32/%.nasm, $(BUILD_DIR)/miniboot32/%.bin, $(BOOTTEST_SRCS))
|
||||||
@rm -v $(build_dir)/output/*.img.gz
|
|
||||||
@rm -v $(build_dir)/output/*.tar.gz
|
|
||||||
|
|
||||||
run: $(iso)
|
ALL_BINS := $(MBR_BINS) $(VBR_BINS) $(STAGE2_BINS) $(BOOTTEST_BINS)
|
||||||
@sudo qemu-system-i386 $(qemu_args) -hda $(iso)
|
|
||||||
|
|
||||||
run_bochs: $(iso)
|
.DEFAULT_GOAL := all
|
||||||
@bochs -q
|
.DELETE_ON_ERROR:
|
||||||
|
|
||||||
iso: $(iso)
|
.PHONY: all mbr vbr stage2 boottest clean run run_qemu run_bochs img imgz help
|
||||||
@file $(iso)
|
all: $(IMG) $(IMGZ) $(ALL_BINS)
|
||||||
|
mbr: $(MBR_BINS)
|
||||||
|
vbr: $(VBR_BINS)
|
||||||
|
stage2: $(STAGE2_BINS)
|
||||||
|
boottest: $(BOOTTEST_BINS)
|
||||||
|
|
||||||
isoz: $(isoz)
|
# Build Rules
|
||||||
@file $(isoz)
|
|
||||||
|
|
||||||
build/%.bin: src/mbr/%.nasm
|
$(BUILD_DIR)/mbr/%.bin: src/mbr/%.nasm | $(DEP_DIR)
|
||||||
@mkdir -p $(shell dirname $@)
|
@mkdir -p $(@D)
|
||||||
@nasm -i$(include) -Wall -f bin $(GIT_NASM_DEFINES) $< -o $@
|
@nasm $(NASMFLAGS) -MD $(DEP_DIR)/$*.d -MT $@ $< -o $@
|
||||||
|
|
||||||
build/%.bin: src/vbr/%.nasm
|
$(BUILD_DIR)/vbr/%.bin: src/vbr/%.nasm | $(DEP_DIR)
|
||||||
@mkdir -p $(shell dirname $@)
|
@mkdir -p $(@D)
|
||||||
@nasm -i$(include) -Wall -f bin $(GIT_NASM_DEFINES) $< -o $@
|
@nasm $(NASMFLAGS) -MD $(DEP_DIR)/$*.d -MT $@ $< -o $@
|
||||||
|
|
||||||
build/%.bin: src/stage2/%.nasm
|
$(BUILD_DIR)/stage2/%.bin: src/stage2/%.nasm | $(DEP_DIR)
|
||||||
@mkdir -p $(shell dirname $@)
|
@mkdir -p $(@D)
|
||||||
@nasm -i$(include) -Wall -f bin $(GIT_NASM_DEFINES) $< -o $@
|
@nasm $(NASMFLAGS) -MD $(DEP_DIR)/$*.d -MT $@ $< -o $@
|
||||||
|
|
||||||
build/%.bin: src/miniboot32/%.nasm
|
$(BUILD_DIR)/miniboot32/%.bin: src/miniboot32/%.nasm | $(DEP_DIR)
|
||||||
@mkdir -p $(shell dirname $@)
|
@mkdir -p $(@D)
|
||||||
@nasm -i$(include) -Wall -f bin $(GIT_NASM_DEFINES) $< -o $@
|
@nasm $(NASMFLAGS) -MD $(DEP_DIR)/$*.d -MT $@ $< -o $@
|
||||||
|
|
||||||
$(iso): $(mbr_binary_files) $(vbr_binary_files) $(stage2_binary_files) $(boottest_binary_files)
|
|
||||||
|
$(DEP_DIR):
|
||||||
|
@mkdir -p $@
|
||||||
|
|
||||||
|
# Disk image's
|
||||||
|
|
||||||
|
$(IMG): $(ALL_BINS) | scripts/create-disk.sh
|
||||||
@scripts/create-disk.sh
|
@scripts/create-disk.sh
|
||||||
|
|
||||||
$(isoz): $(iso)
|
$(IMGZ): $(IMG)
|
||||||
@gzip -9kc $(iso) > $(isoz)
|
@gzip -9kc $(IMG) > $(IMGZ)
|
||||||
|
|
||||||
|
img: $(IMG)
|
||||||
|
@file $(IMG)
|
||||||
|
|
||||||
|
imgz: $(IMGZ)
|
||||||
|
@file $(IMGZ)
|
||||||
|
|
||||||
|
# Helpers
|
||||||
|
|
||||||
|
run: $(IMG)
|
||||||
|
@$(QEMU) $(QEMU_ARGS) -drive file=$(IMG),if=ide,index=0,media=disk,format=raw \
|
||||||
|
|
||||||
|
run_bochs: $(IMG)
|
||||||
|
@bochs -q
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@$(RM) -rv $(BUILD_DIR)/
|
||||||
|
|
||||||
|
help:
|
||||||
|
@awk '/^[A-Za-z0-9_%-]+:/{print $$1}' $(MAKEFILE_LIST) | sed 's/:$$//' | sort -u
|
||||||
|
|
||||||
|
# Include header deps
|
||||||
|
-include $(wildcard $(DEP_DIR)/*.d)
|
||||||
47
README.md
47
README.md
@@ -1,6 +1,8 @@
|
|||||||
# Stevia Bootloader
|
# Stevia Bootloader
|
||||||
|
|
||||||
Stevia is a lightweight, hobby bootloader written in Assembly and C, designed for educational purposes. It targets x86 (Pentium III era) and aims to be simple, approachable, and understandable, focusing on minimalism and core functionality.
|
Stevia is a lightweight, hobby bootloader written in Assembly (NASM) and is designed for educational purposes. It targets 686+ and aims to be simple, approachable, and understandable, focusing on minimalism and core functionality.
|
||||||
|
|
||||||
|
Please note: **Most development currently takes place in Bochs (and maybe is tested on QEMU), due to this, the code in this repo has not been tested throughly aginist real hardware. As with most projects of this nature, there is a risk of damage due to improper programing of hardware, while careful effort is taken to not break the computer...accidents and mistakes can/do happen.**
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -10,18 +12,13 @@ Stevia is a lightweight, hobby bootloader written in Assembly and C, designed fo
|
|||||||
- **Stage 2 Bootloader**: Loads the kernel into memory and passes control.
|
- **Stage 2 Bootloader**: Loads the kernel into memory and passes control.
|
||||||
- **Basic Filesystem Support**: Initial filesystem recognition (details depend on implemented filesystem support).
|
- **Basic Filesystem Support**: Initial filesystem recognition (details depend on implemented filesystem support).
|
||||||
- **Memory Map Parsing**: Detects available memory regions via BIOS interrupts.
|
- **Memory Map Parsing**: Detects available memory regions via BIOS interrupts.
|
||||||
- **GDT Initialization**: Sets up the Global Descriptor Table for protected mode.
|
- **GDT Initialization**: Sets up the Global Descriptor Table for protected/unreal mode.
|
||||||
|
|
||||||
### In Progress
|
|
||||||
|
|
||||||
- **Interrupt Descriptor Table (IDT) Setup**: Setting up basic interrupt handling.
|
|
||||||
- **Basic Keyboard Input**: Initial support for capturing keystrokes.
|
|
||||||
|
|
||||||
### Planned Features
|
### Planned Features
|
||||||
|
|
||||||
- **Task Scheduling**: Basic round-robin task switching.
|
- **Interrupt Descriptor Table (IDT) Setup**: Setting up basic interrupt handling.
|
||||||
|
- **Basic Keyboard Input**: Initial support for capturing keystrokes.
|
||||||
- **Filesystem Expansion**: Support for additional filesystems.
|
- **Filesystem Expansion**: Support for additional filesystems.
|
||||||
- **More Robust Driver Support**: Additional hardware drivers, such as for storage devices.
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -29,41 +26,39 @@ Stevia is a lightweight, hobby bootloader written in Assembly and C, designed fo
|
|||||||
|
|
||||||
To build and run Stevia, you will need the following tools installed on your system:
|
To build and run Stevia, you will need the following tools installed on your system:
|
||||||
|
|
||||||
- **Assembler**: NASM for assembling bootloader components.
|
- **Assembler**: NASM for assembling bootloader components, you could use a compatible assembler but YMMV.
|
||||||
- **C Compiler**: GCC (cross-compiler recommended).
|
- **GNU make**: For building the project.
|
||||||
- **Emulator**: Bochs or QEMU for testing.
|
- **mtools**: To access the FAT partition
|
||||||
- **GNU Make**: For building the project.
|
- **fdisk**: To create disk images and setup partition tables
|
||||||
- **Utilities**:
|
- **dosfstools**: FAT32 creation
|
||||||
- **dd**: For creating raw disk images.
|
- **an x86 Emulator**: Bochs is the primary dev target, but stevia should run on any x86 emulator/hardware with at least a Pentium 3 and 640KiB of memory.
|
||||||
- **losetup** (Linux only): For associating loop devices with disk images.
|
|
||||||
- **sfdisk**: For creating DOS disk partitions.
|
|
||||||
- **mkfs.fat**: For formatting partitions as FAT32.
|
|
||||||
- **hdiutil** (macOS only): For attaching disk images.
|
|
||||||
- **newfs\_msdos** (macOS only): For formatting FAT32 partitions.
|
|
||||||
|
|
||||||
### Building and Running
|
### Building and Running
|
||||||
|
|
||||||
1. **Clone the repository**:
|
1. **Clone the repository**:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone https://github.com/Nivirx/stevia.git
|
git clone https://github.com/Nivirx/stevia.git
|
||||||
cd stevia
|
cd stevia
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Build the bootloader and create a bootable disk image**:
|
2. **Build the bootloader and create a bootable disk image**:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo make
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Run using Bochs**:
|
3. **Run using Bochs**:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
bochs -f bochsrc.txt
|
bochs -q -f bochsrc.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
## Project Goals
|
## Project Goals
|
||||||
|
|
||||||
Stevia is intended to be a learning tool for those interested in low-level programming, focusing on understanding the basics of how a computer starts up and manages early system resources. Contributions and forks are welcome, especially from those interested in expanding the functionality.
|
Stevia is intended to be a learning tool for those interested in low-level programming, focusing on understanding the basics of how a computer starts up and manages early system resources.
|
||||||
|
|
||||||
## Contributing
|
You are welcome to fork/review the code base but I am generally not accepting PR's/Contributions to the code at this time.
|
||||||
|
|
||||||
We welcome contributions! Feel free to open issues for bugs or feature requests, and submit pull requests for any improvements. Please ensure that your code follows the existing style and includes appropriate comments.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
66
bochsrc.txt
66
bochsrc.txt
@@ -1,44 +1,44 @@
|
|||||||
# configuration file generated by Bochs
|
#
|
||||||
plugin_ctrl: voodoo=false, unmapped=true, biosdev=true, speaker=true, extfpuirq=true, parallel=true, serial=true, busmouse=false, e1000=false, es1370=false, gameport=true, ne2k=false, sb16=false, usb_uhci=false, usb_ohci=false, usb_ehci=false, usb_xhci=false
|
# Bochs config
|
||||||
|
#
|
||||||
config_interface: textconfig
|
config_interface: textconfig
|
||||||
display_library: x, options=gui_debug
|
display_library: x, options=gui_debug
|
||||||
memory: guest=64, host=64, block_size=128
|
plugin_ctrl: voodoo=false, unmapped=true, biosdev=true, speaker=true, extfpuirq=true, parallel=true, serial=true, busmouse=false, e1000=true, es1370=false, gameport=true, ne2k=false, sb16=false, usb_uhci=true, usb_ohci=false, usb_ehci=false, usb_xhci=false
|
||||||
romimage: file="/usr/share/bochs/BIOS-bochs-legacy", address=0x00000000, options=none, flash_data=none
|
print_timestamps: enabled=1
|
||||||
vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest"
|
|
||||||
boot: disk
|
|
||||||
floppy_bootsig_check: disabled=0
|
|
||||||
floppya: type=1_44
|
|
||||||
# no floppyb
|
|
||||||
ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
|
|
||||||
ata0-master: type=disk, path="./build/disk.img", mode=flat, cylinders=0, heads=0, spt=0, sect_size=512, model="Stevia Disk", biosdetect=auto, translation=lba
|
|
||||||
ata0-slave: type=none
|
|
||||||
ata1: enabled=false
|
|
||||||
ata1-master: type=none
|
|
||||||
ata1-slave: type=none
|
|
||||||
ata2: enabled=false
|
|
||||||
ata3: enabled=false
|
|
||||||
optromimage1: file=none
|
|
||||||
optromimage2: file=none
|
|
||||||
optromimage3: file=none
|
|
||||||
optromimage4: file=none
|
|
||||||
optramimage1: file=none
|
|
||||||
optramimage2: file=none
|
|
||||||
optramimage3: file=none
|
|
||||||
optramimage4: file=none
|
|
||||||
pci: enabled=1, chipset=i440fx, slot1=none, slot2=none, slot3=none, slot4=none, slot5=none
|
|
||||||
vga: extension=vbe, update_freq=10, realtime=1, ddc=builtin
|
|
||||||
cpu: count=1, ips=1000000, model=p3_katmai, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
|
|
||||||
print_timestamps: enabled=0
|
|
||||||
port_e9_hack: enabled=false, all_rings=false
|
|
||||||
private_colormap: enabled=0
|
private_colormap: enabled=0
|
||||||
clock: sync=none, time0=local, rtc_sync=0
|
|
||||||
# no cmosimage
|
|
||||||
log: -
|
log: -
|
||||||
logprefix: %t%e%d
|
logprefix: %t%e%d
|
||||||
debug: action=ignore
|
debug: action=ignore
|
||||||
info: action=report
|
info: action=report
|
||||||
error: action=report
|
error: action=report
|
||||||
panic: action=ask
|
panic: action=ask
|
||||||
|
magic_break: enabled=1
|
||||||
|
port_e9_hack: enabled=1, all_rings=false
|
||||||
|
#
|
||||||
|
# Machine Spec
|
||||||
|
# 1x Pentium 3 @ (1M IPS) w/ 64MiB of System memory on the i440fx
|
||||||
|
cpu: count=1, ips=1000000, model=p3_katmai, reset_on_triple_fault=0, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
|
||||||
|
memory: guest=64, host=64, block_size=128
|
||||||
|
romimage: file="/usr/share/bochs/BIOS-bochs-legacy", address=0x00000000, options=none, flash_data=none
|
||||||
|
vgaromimage: file="/usr/share/vgabios/vgabios-stdvga.bin"
|
||||||
|
pci: enabled=1, chipset=i440fx
|
||||||
|
vga: extension=vbe, update_freq=10, realtime=1, ddc=builtin
|
||||||
|
clock: sync=none, time0=local, rtc_sync=0
|
||||||
|
#
|
||||||
|
# Disks
|
||||||
|
#
|
||||||
|
boot: disk
|
||||||
|
floppy_bootsig_check: disabled=0
|
||||||
|
floppya: type=1_44
|
||||||
|
floppyb: type=1_44
|
||||||
|
ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
|
||||||
|
ata0-master: type=disk, path="./build/disk.img", mode=flat, cylinders=0, heads=0, spt=0, sect_size=512, model="Stevia Disk", biosdetect=auto, translation=lba
|
||||||
|
ata0-slave: type=none
|
||||||
|
#
|
||||||
|
# Other hardware
|
||||||
|
#
|
||||||
|
usb_ehci: enabled=1, companion=ohci
|
||||||
|
e1000: enabled=1, mac=52:54:00:12:34:56, ethmod=null
|
||||||
keyboard: type=mf, serial_delay=150, paste_delay=100000, user_shortcut=none
|
keyboard: type=mf, serial_delay=150, paste_delay=100000, user_shortcut=none
|
||||||
mouse: type=none, enabled=false, toggle=ctrl+mbutton
|
mouse: type=none, enabled=false, toggle=ctrl+mbutton
|
||||||
sound: waveoutdrv=dummy, waveout=none, waveindrv=dummy, wavein=none, midioutdrv=dummy, midiout=none
|
sound: waveoutdrv=dummy, waveout=none, waveindrv=dummy, wavein=none, midioutdrv=dummy, midiout=none
|
||||||
@@ -49,5 +49,3 @@ com1: enabled=true, mode=null
|
|||||||
com2: enabled=false
|
com2: enabled=false
|
||||||
com3: enabled=false
|
com3: enabled=false
|
||||||
com4: enabled=false
|
com4: enabled=false
|
||||||
magic_break: enabled=1
|
|
||||||
port_e9_hack: enabled=1, all_rings=false
|
|
||||||
|
|||||||
@@ -207,24 +207,45 @@ Each GDT entry is 8 bytes:
|
|||||||
|
|
||||||
## **5. Memory Layout Example**
|
## **5. Memory Layout Example**
|
||||||
|
|
||||||
### **Low Memory (First MiB)**
|
### **Low Memory/Upper Memory map (<= 1MiB)**
|
||||||
|
|
||||||
| Start | End | Size | Type | Description |
|
| Start | End | Size | Type | Description |
|
||||||
|-------------|-------------|-----------------|-----------------------|----------------------------------|
|
|-------------|-------------|-----------------|----------------------|--------------------------------|
|
||||||
| 0x00000000 | 0x000003FF | 1 KiB | RAM (partially unusable) | Real Mode IVT (Interrupt Vector Table) |
|
| 0x00000000 | 0x000003FF | 1 KiB | RAM reclaimable~1~ | Real Mode IVT |
|
||||||
| 0x00000400 | 0x000004FF | 256 bytes | RAM (partially unusable) | BDA (BIOS data area) |
|
| 0x00000400 | 0x000004FF | 256 bytes | RAM reclaimable~1~ | BDA |
|
||||||
| 0x00000500 | 0x00007BFF | almost 30 KiB | RAM - free for use | Conventional memory |
|
| 0x00000500 | 0x00007BFF | 29 KiB + 767b | RAM - free | Conventional memory |
|
||||||
| 0x00007C00 | 0x00007DFF | 512 bytes | RAM (partially unusable) | OS BootSector |
|
| 0x00007C00 | 0x00007DFF | 512 bytes | RAM reclaimable~2~ | OS BootSector |
|
||||||
| 0x00007E00 | 0x0007FFFF | 480.5 KiB | RAM - free for use | Conventional memory |
|
| 0x00007E00 | 0x0007FFFF | 480.5 KiB | RAM - free | Conventional memory |
|
||||||
| 0x00080000 | 0x0009FFFF | 128 KiB | RAM (partially unusable) | EBDA (Extended BIOS Data Area) |
|
| 0x00080000 | 0x0009FFFF | 128 KiB | RAM (unusable)~1~ | EBDA (Extended BIOS Data Area) |
|
||||||
| 0x000A0000 | 0x000FFFFF | 384 KiB | various (unusable) | Video memory, ROM Area |
|
| 0x000A0000 | 0x000FFFFF | 384 KiB | Upper RAM (unusable) | Video memory, ROM Area |
|
||||||
|
|
||||||
### **Extended Memory (Above 1 MiB)**
|
1. Reclaimable in the event that you *never* need the BIOS again & once the CPU is in protected mode.
|
||||||
|
2. Reclaimable after you are done with with the MBR/VBR stages.
|
||||||
|
|
||||||
|
### **Extended Memory (> 1 MiB)**
|
||||||
|
|
||||||
|
This is only an example, you should always check the memory map.
|
||||||
|
|
||||||
| Start | End | Size | Description |
|
| Start | End | Size | Description |
|
||||||
|-------------|-------------|-----------------|------------------------|
|
|-------------|-------------|-----------------|---------------------------------------|
|
||||||
| 0x00100000 | 0x00EFFFFF | 14 MiB | RAM - free for use |
|
| 0x00100000 | 0x00EFFFFF | 14 MiB | RAM(?) - free for use |
|
||||||
| 0x00F00000 | 0x00FFFFFF | 1 MiB | Possible memory-mapped hardware (ISA) |
|
| 0x00F00000 | 0x00FFFFFF | 1 MiB | Possible memory-mapped hardware (ISA) |
|
||||||
| 0x01000000 | ? | ? | More extended memory |
|
| 0x01000000 | ? | ? | More extended memory |
|
||||||
| 0xC0000000 | 0xFFFFFFFF | 1 GiB | Memory mapped PCI devices, BIOS, etc. |
|
| 0xC0000000 | 0xFFFFFFFF | 1 GiB | Memory mapped PCI devices, BIOS, etc. |
|
||||||
| 0x0000000100000000 | ? | ? | RAM - usable in PAE/64-bit mode |
|
| 0x0000000100000000 | ? | ? | RAM(?) - usable in PAE/64-bit mode |
|
||||||
|
|
||||||
|
|
||||||
|
## **6. Stage2 Memory Layout **
|
||||||
|
|
||||||
|
Overall, Tiny (64 KiB page) Code/Data, Flat 4GiB mapping in gs/fs after unreal switch
|
||||||
|
|
||||||
|
| Start | End | Size (Bytes) | Type | Description |
|
||||||
|
|-------------|-------------|--------------|--------------------|----------------------------|
|
||||||
|
| 0x00000000 | 0x000003FF | 0x400 | RAM - (BIOS) | Real Mode IVT |
|
||||||
|
| 0x00000400 | 0x000004FF | 0x100 | RAM - (BIOS) | BDA |
|
||||||
|
| 0x00000500 | 0x000042FF | 0x3E00 | RAM - .text/.data | Code and constants/strings |
|
||||||
|
| 0x00004300 | 0x000044FF | 0x100 | RAM - .sign | EOF marker/signature |
|
||||||
|
| 0x00004500 | 0x000074FF | 0x3000 | RAM - bss | Runtime data/stack |
|
||||||
|
| 0x00007500 | 0x00007FFF | 0xB00 | RAM - reserved | Reserved |
|
||||||
|
| 0x00008000 | 0x0000DFFF | 0x6000 | RAM - heap | Conventional memory |
|
||||||
|
| 0x0000F000 | 0x0000FFFF | 0x1000 | RAM - reserved | Reserved |
|
||||||
24
docs/okteta/structures/mbr/main.osd
Normal file
24
docs/okteta/structures/mbr/main.osd
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<data>
|
||||||
|
<struct name="MBR">
|
||||||
|
<!-- 446 bytes: bootstrap code -->
|
||||||
|
<array name="bootCode" length="446">
|
||||||
|
<primitive type="UInt8"/>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<!-- 4 x 16-byte partition entries -->
|
||||||
|
<array name="partitions" length="4">
|
||||||
|
<struct name="PartitionEntry">
|
||||||
|
<primitive name="status" type="UInt8"/> <!-- 0x80=bootable -->
|
||||||
|
<array name="chsFirst" length="3"><primitive type="UInt8"/></array>
|
||||||
|
<primitive name="type" type="UInt8"/>
|
||||||
|
<array name="chsLast" length="3"><primitive type="UInt8"/></array>
|
||||||
|
<primitive name="lbaStart" type="UInt32"/>
|
||||||
|
<primitive name="lbaSectors" type="UInt32"/>
|
||||||
|
</struct>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<!-- Signature 0x55AA (little-endian UInt16 == 0xAA55 on disk) -->
|
||||||
|
<primitive name="signature" type="UInt16"/>
|
||||||
|
</struct>
|
||||||
|
</data>
|
||||||
12
docs/okteta/structures/mbr/metadata.desktop
Normal file
12
docs/okteta/structures/mbr/metadata.desktop
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Icon=application-x-executable
|
||||||
|
Type=Service
|
||||||
|
ServiceTypes=KPluginInfo
|
||||||
|
Name=Stevia MBR Structure
|
||||||
|
X-KDE-PluginInfo-Author=Elaina Claus
|
||||||
|
X-KDE-PluginInfo-Name=mbr
|
||||||
|
X-KDE-PluginInfo-Version=1.0
|
||||||
|
X-KDE-PluginInfo-Website=https://chtm.me
|
||||||
|
X-KDE-PluginInfo-Category=structure
|
||||||
|
X-KDE-PluginInfo-License=MIT
|
||||||
|
X-KDE-PluginInfo-EnabledByDefault=false
|
||||||
57
docs/okteta/structures/vbr/main.osd
Normal file
57
docs/okteta/structures/vbr/main.osd
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<data>
|
||||||
|
<struct name="VBR">
|
||||||
|
<!-- 3 bytes: jmp over bpb code -->
|
||||||
|
<array name="jmpcode" length="3">
|
||||||
|
<primitive name="opcode" type="UInt8"/>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<array name="bs_ident" length="8">
|
||||||
|
<primitive type="Char"/>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<struct name="FAT32_bpb">
|
||||||
|
<primitive name="BytesPerSector" type="UInt16"/>
|
||||||
|
<primitive name="SectorsPerCluster" type="UInt8"/>
|
||||||
|
<primitive name="ReservedSectors" type="UInt16"/>
|
||||||
|
<primitive name="FatCount" type="UInt8"/>
|
||||||
|
<primitive name="RootEntryCount16" type="UInt16"/>
|
||||||
|
<primitive name="TotalSectors16" type="UInt16"/>
|
||||||
|
<primitive name="MediaDesc" type="UInt8"/>
|
||||||
|
<primitive name="FATSize16" type="UInt16"/>
|
||||||
|
<primitive name="SectorsPerTrack" type="UInt16"/>
|
||||||
|
<primitive name="HeadCount" type="UInt16"/>
|
||||||
|
<primitive name="HiddenSectors" type="UInt32"/>
|
||||||
|
<primitive name="TotalSectors32" type="UInt32"/>
|
||||||
|
</struct>
|
||||||
|
|
||||||
|
<struct name="FAT32_ebpb">
|
||||||
|
<primitive name="FATSize32" type="UInt32"/>
|
||||||
|
<primitive name="ExtFlags" type="UInt16"/>
|
||||||
|
<primitive name="FSVersion" type="UInt16"/>
|
||||||
|
<primitive name="RootDirCluster" type="UInt32"/>
|
||||||
|
<primitive name="FSInfoSector" type="UInt16"/>
|
||||||
|
<primitive name="BkBootSector" type="UInt16"/>
|
||||||
|
<array name="reserved0" length="12">
|
||||||
|
<primitive type="uint8"/>
|
||||||
|
</array>
|
||||||
|
<primitive name="DriveNumber" type="UInt8"/>
|
||||||
|
<primitive name="NtFlags" type="UInt8"/>
|
||||||
|
<primitive name="Signature" type="UInt8"/>
|
||||||
|
<primitive name="VolumeId" type="UInt32"/>
|
||||||
|
<array name="VolumeLabel" length="11">
|
||||||
|
<primitive type="Char"/>
|
||||||
|
</array>
|
||||||
|
<array name="FilesystemIdent" length="8">
|
||||||
|
<primitive type="Char"/>
|
||||||
|
</array>
|
||||||
|
</struct>
|
||||||
|
|
||||||
|
<array name="BootCode" length="420">
|
||||||
|
<primitive type="UInt8"/>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<!-- Signature 0xAA55 -->
|
||||||
|
<primitive name="signature" type="UInt16"/>
|
||||||
|
</struct>
|
||||||
|
</data>
|
||||||
12
docs/okteta/structures/vbr/metadata.desktop
Normal file
12
docs/okteta/structures/vbr/metadata.desktop
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Icon=application-x-executable
|
||||||
|
Type=Service
|
||||||
|
ServiceTypes=KPluginInfo
|
||||||
|
Name=Stevia FAT32 VBR Structure
|
||||||
|
X-KDE-PluginInfo-Author=Elaina Claus
|
||||||
|
X-KDE-PluginInfo-Name=vbr32
|
||||||
|
X-KDE-PluginInfo-Version=1.0
|
||||||
|
X-KDE-PluginInfo-Website=https://chtm.me
|
||||||
|
X-KDE-PluginInfo-Category=structure
|
||||||
|
X-KDE-PluginInfo-License=MIT
|
||||||
|
X-KDE-PluginInfo-EnabledByDefault=false
|
||||||
@@ -33,34 +33,27 @@ struc AddressRangeDescStruct_t
|
|||||||
.ExtType resd 1
|
.ExtType resd 1
|
||||||
endstruc
|
endstruc
|
||||||
|
|
||||||
|
; !!! this procedure changes ES !!!
|
||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
GetMemoryMap:
|
GetMemoryMap:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
push es ; save segment register
|
push es ; save segment register
|
||||||
.func:
|
.func:
|
||||||
mov dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries], 0
|
mov word [SteviaInfo + SteviaInfoStruct_t.u16_E820MMapEntryCount], 0
|
||||||
|
|
||||||
|
|
||||||
xor ebx, ebx ; Continuation value, 0 for the first call
|
xor ebx, ebx ; Continuation value, 0 for the first call
|
||||||
|
mov di, BIOSMemoryMap ; destination is es:di, es should == ds
|
||||||
mov dx, BIOSMemoryMap
|
|
||||||
shr dx, 4
|
|
||||||
mov es, dx
|
|
||||||
xor di, di ; (BIOSMemoryMap >> 4):0 makes di an index into BIOSMemoryMap
|
|
||||||
|
|
||||||
mov ecx, AddressRangeDescStruct_t_size ; hard request ACPI 3.0 table versions (24 bytes)
|
mov ecx, AddressRangeDescStruct_t_size ; hard request ACPI 3.0 table versions (24 bytes)
|
||||||
|
|
||||||
.loop_L1:
|
.loop_L1:
|
||||||
mov eax, 0x0000E820 ; select 0xE820 function
|
mov eax, 0x0000E820 ; select 0xE820 function
|
||||||
mov edx, 0x534D4150 ; 'SMAP' magic
|
mov edx, 0x534D4150 ; 'SMAP' magic
|
||||||
int 0x15
|
clc ; clear carry
|
||||||
|
int 0x15 ; data will be stored at es:di by e820 call
|
||||||
jc GetMemoryMap.error
|
jc GetMemoryMap.error
|
||||||
cmp eax, 0x534D4150
|
cmp eax, 0x534D4150
|
||||||
jne GetMemoryMap.no_smap_returned
|
jne GetMemoryMap.no_smap_returned
|
||||||
.no_error:
|
.no_error:
|
||||||
mov eax, dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries]
|
inc word [SteviaInfo + SteviaInfoStruct_t.u16_E820MMapEntryCount]
|
||||||
add eax, 1
|
|
||||||
mov dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries], eax
|
|
||||||
|
|
||||||
cmp ecx, 20 ; TODO: maybe this could be handled better than just panicing
|
cmp ecx, 20 ; TODO: maybe this could be handled better than just panicing
|
||||||
jb GetMemoryMap.nonstandard_e820 ; non-standard entry found
|
jb GetMemoryMap.nonstandard_e820 ; non-standard entry found
|
||||||
@@ -82,13 +75,13 @@ GetMemoryMap:
|
|||||||
ERROR STAGE2_MM_E820_NO_SMAP
|
ERROR STAGE2_MM_E820_NO_SMAP
|
||||||
.endp:
|
.endp:
|
||||||
pop es
|
pop es
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
PrintMemoryMap:
|
PrintMemoryMap:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.func:
|
||||||
mov eax, dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries]
|
mov eax, dword [SteviaInfo + SteviaInfoStruct_t.u16_E820MMapEntryCount]
|
||||||
cmp eax, 0
|
cmp eax, 0
|
||||||
je PrintMemoryMap.endp ; if entries == 0, exit
|
je PrintMemoryMap.endp ; if entries == 0, exit
|
||||||
|
|
||||||
@@ -105,15 +98,15 @@ PrintMemoryMap:
|
|||||||
; print_string strformat_buffer
|
; print_string strformat_buffer
|
||||||
|
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
FormatMemoryMapEntry:
|
FormatMemoryMapEntry:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.func:
|
||||||
; create a string buffer somewhere and return address to result string in ax
|
; create a string buffer somewhere and return address to result string in ax
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
; Bits 6-7 - 00: HDD activity LED off; any other value is "on"
|
; Bits 6-7 - 00: HDD activity LED off; any other value is "on"
|
||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
EnableA20:
|
EnableA20:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
push ds
|
push ds
|
||||||
push es
|
push es
|
||||||
.a20_check:
|
.a20_check:
|
||||||
@@ -105,6 +105,7 @@ EnableA20:
|
|||||||
je EnableA20.endp ; A20 is already enabled
|
je EnableA20.endp ; A20 is already enabled
|
||||||
|
|
||||||
mov ax, 0x2403
|
mov ax, 0x2403
|
||||||
|
clc ; clear carry
|
||||||
int 0x15
|
int 0x15
|
||||||
jc EnableA20.do_fallback_a20 ; carry = error...not supported?
|
jc EnableA20.do_fallback_a20 ; carry = error...not supported?
|
||||||
cmp ah, 0
|
cmp ah, 0
|
||||||
@@ -121,6 +122,7 @@ EnableA20:
|
|||||||
ERROR STAGE2_A20_FAILED
|
ERROR STAGE2_A20_FAILED
|
||||||
.do_bios_a20:
|
.do_bios_a20:
|
||||||
mov ax, 0x2401
|
mov ax, 0x2401
|
||||||
|
clc ; clear carry
|
||||||
int 0x15
|
int 0x15
|
||||||
jmp EnableA20.a20_check
|
jmp EnableA20.a20_check
|
||||||
.do_fast_a20:
|
.do_fast_a20:
|
||||||
@@ -132,7 +134,7 @@ EnableA20:
|
|||||||
.endp:
|
.endp:
|
||||||
pop es
|
pop es
|
||||||
pop ds
|
pop ds
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
%endif
|
%endif
|
||||||
|
|||||||
@@ -31,29 +31,6 @@ struc LBAPkt_t
|
|||||||
.lower_lba resd 1
|
.lower_lba resd 1
|
||||||
.upper_lba resd 1
|
.upper_lba resd 1
|
||||||
endstruc
|
endstruc
|
||||||
; call_read_disk_raw <word segment> <word offset> <dword lba> <word count> <word drive_num>
|
|
||||||
%macro call_read_disk_raw 5
|
|
||||||
movzx ax, %5
|
|
||||||
push ax ; drive_num
|
|
||||||
|
|
||||||
movzx ax, %4
|
|
||||||
push ax ; count
|
|
||||||
|
|
||||||
movzx dword eax, %3
|
|
||||||
push dword eax ; lba
|
|
||||||
|
|
||||||
movzx ax, %2
|
|
||||||
push ax ; offset
|
|
||||||
|
|
||||||
movzx ax, %1
|
|
||||||
push ax ; segment = 0
|
|
||||||
|
|
||||||
; uint8_t read_stage2_raw(uint16_t buf_segment, uint16_t buf_offset,
|
|
||||||
; uint32_t lba,
|
|
||||||
; uint16_t count, uint16_t drive_num)
|
|
||||||
call read_disk_raw
|
|
||||||
add sp, 0xC
|
|
||||||
%endmacro
|
|
||||||
|
|
||||||
; Wrapper for AH=0x42 INT13h (Extended Read)
|
; Wrapper for AH=0x42 INT13h (Extended Read)
|
||||||
;
|
;
|
||||||
@@ -70,21 +47,17 @@ endstruc
|
|||||||
; disk address packet's block count field set to number of blocks
|
; disk address packet's block count field set to number of blocks
|
||||||
; successfully transferred
|
; successfully transferred
|
||||||
;
|
;
|
||||||
;
|
|
||||||
; uint8_t read_stage2_raw(uint16_t buf_segment, uint16_t buf_offset,
|
; uint8_t read_stage2_raw(uint16_t buf_segment, uint16_t buf_offset,
|
||||||
; uint32_t lba,
|
; uint32_t lba,
|
||||||
; uint16_t count, uint8_t drive_num)
|
; uint16_t count, uint8_t drive_num)
|
||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
read_disk_raw:
|
BIOS_int13h_ext_read:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.func:
|
||||||
mov ax, LBAPkt_t_size
|
push LBAPkt_t_size ; len
|
||||||
push ax ; len
|
push 0x00 ; val = 0
|
||||||
xor ax, ax
|
push lba_packet ; dest = lba_packet address
|
||||||
push ax ; val = 0
|
call kmemset ; kmemset(dst, val, len)
|
||||||
mov ax, lba_packet
|
|
||||||
push ax ; dest = lba_packet address
|
|
||||||
call kmemset
|
|
||||||
add sp, 0x06
|
add sp, 0x06
|
||||||
|
|
||||||
mov bx, lba_packet
|
mov bx, lba_packet
|
||||||
@@ -97,7 +70,8 @@ read_disk_raw:
|
|||||||
mov dword [bx + LBAPkt_t.lower_lba], eax
|
mov dword [bx + LBAPkt_t.lower_lba], eax
|
||||||
|
|
||||||
; upper_lba is zero from kmemset
|
; upper_lba is zero from kmemset
|
||||||
; TODO: possiblly support >32bit LBA addresses in the future, this limits us to 4GiB
|
; TODO: possiblly support >32bit LBA addresses in the future
|
||||||
|
; this will limit us to (4GiB * sector size) of readable lba's from the disk
|
||||||
|
|
||||||
mov ax, [bp + 6]
|
mov ax, [bp + 6]
|
||||||
mov word [bx + LBAPkt_t.offset], ax
|
mov word [bx + LBAPkt_t.offset], ax
|
||||||
@@ -111,6 +85,7 @@ read_disk_raw:
|
|||||||
mov ah, 0x42 ; call #
|
mov ah, 0x42 ; call #
|
||||||
mov dl, byte [bp + 14] ; drive #
|
mov dl, byte [bp + 14] ; drive #
|
||||||
|
|
||||||
|
clc ; clear carry
|
||||||
int 0x13
|
int 0x13
|
||||||
jnc .endf
|
jnc .endf
|
||||||
|
|
||||||
@@ -119,10 +94,10 @@ read_disk_raw:
|
|||||||
%elifdef __STEVIA_VBR
|
%elifdef __STEVIA_VBR
|
||||||
ERROR VBR_ERROR_DISK_READ_ERR
|
ERROR VBR_ERROR_DISK_READ_ERR
|
||||||
%else
|
%else
|
||||||
ERROR STAGE2_MBR_DISK_READ_ERROR
|
ERROR STAGE2_INT13_DISK_READ_ERR
|
||||||
%endif
|
%endif
|
||||||
.endf:
|
.endf:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
%endif
|
%endif
|
||||||
|
|||||||
@@ -20,25 +20,27 @@
|
|||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
SetTextMode:
|
SetTextMode:
|
||||||
.prolog:
|
.prolog:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
pushf
|
pushf
|
||||||
.func:
|
.func:
|
||||||
xor ah, ah ; Set Video mode BIOS function
|
xor ah, ah ; Set Video mode BIOS function
|
||||||
mov al, 0x02 ; 16 color 80x25 Text mode
|
mov al, 0x03 ; 16 color 80x25 Text mode
|
||||||
int 0x10 ; Call video interrupt
|
int 0x10 ; Call video interrupt
|
||||||
|
|
||||||
|
|
||||||
mov ah, 0x05 ; Select active display page BIOS function
|
mov ah, 0x05 ; Select active display page BIOS function
|
||||||
xor al, al ; page 0
|
xor al, al ; page 0
|
||||||
int 0x10 ; call video interrupt
|
int 0x10 ; call video interrupt
|
||||||
.endp:
|
.endp:
|
||||||
popf
|
popf
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; disables blinking text mode cursor
|
; disables blinking text mode cursor via crtc pokes
|
||||||
|
; 0x3D4/0x3D5 for color, mono at 0x3B4/0x3B5
|
||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
disable_cursor:
|
disable_cursor_crtc:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.func:
|
||||||
mov dx, 0x3D4
|
mov dx, 0x3D4
|
||||||
mov al, 0xA ; low cursor shape register
|
mov al, 0xA ; low cursor shape register
|
||||||
@@ -48,8 +50,126 @@ disable_cursor:
|
|||||||
mov al, 0x20 ; bits 6-7 unused, bit 5 disables the cursor, bits 0-4 control the cursor shape
|
mov al, 0x20 ; bits 6-7 unused, bit 5 disables the cursor, bits 0-4 control the cursor shape
|
||||||
out dx, al
|
out dx, al
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
; disables blinking text mode cursor via BIOS int 10h, ah = 01
|
||||||
|
ALIGN 4, db 0x90
|
||||||
|
disable_cursor_bios:
|
||||||
|
__CDECL16_PROC_ENTRY
|
||||||
|
.func:
|
||||||
|
push bx
|
||||||
|
mov ah, 03h ; read cursor pos & shape
|
||||||
|
xor bh, bh
|
||||||
|
int 10h ; CH=top scanline, CL=bottom
|
||||||
|
|
||||||
|
or ch, 20h ; set bit 5 = disable
|
||||||
|
mov ah, 01h ; set leaf 01h
|
||||||
|
int 10h
|
||||||
|
pop bx
|
||||||
|
.endp:
|
||||||
|
__CDECL16_PROC_EXIT
|
||||||
|
ret
|
||||||
|
|
||||||
|
; Prints a C-Style string (null terminated) using BIOS vga teletype call
|
||||||
|
; void PrintString(char* buf)
|
||||||
|
ALIGN 4, db 0x90
|
||||||
|
PrintString:
|
||||||
|
__CDECL16_PROC_ENTRY
|
||||||
|
mov di, [bp + 4] ; first arg is char[]
|
||||||
|
.str_len:
|
||||||
|
xor cx, cx ; ECX = 0
|
||||||
|
not cx ; ECX = -1 == 0xFFFF
|
||||||
|
xor ax, ax ; search for al = 0x0
|
||||||
|
|
||||||
|
cld
|
||||||
|
repne scasb ; deincrement cx while searching for al
|
||||||
|
|
||||||
|
not cx ; the inverse of a neg number = abs(x) - 1
|
||||||
|
dec cx ; CX contains the length of the string - nul byte at end
|
||||||
|
.print:
|
||||||
|
mov si, [bp + 4] ; source string
|
||||||
|
.print_L0:
|
||||||
|
movzx ax, byte [si]
|
||||||
|
%ifdef __STEVIA_DEV_DEBUG
|
||||||
|
out 0xe9, byte al ; bochs magic debug port
|
||||||
|
%endif
|
||||||
|
push ax
|
||||||
|
call PrintCharacter
|
||||||
|
add sp, 0x2
|
||||||
|
|
||||||
|
inc si
|
||||||
|
dec cx
|
||||||
|
|
||||||
|
jcxz PrintString.endp
|
||||||
|
jmp PrintString.print_L0 ; Fetch next character from string
|
||||||
|
.endp:
|
||||||
|
__CDECL16_PROC_EXIT
|
||||||
|
ret ; Return from procedure
|
||||||
|
|
||||||
|
; Prints a single character
|
||||||
|
; void PrintCharacter(char c);
|
||||||
|
ALIGN 4, db 0x90
|
||||||
|
PrintCharacter:
|
||||||
|
__CDECL16_PROC_ENTRY
|
||||||
|
.func:
|
||||||
|
mov al, byte [bp + 4] ; AL = character c
|
||||||
|
mov ah, 0x0E ; INT 0x10, AH=0x0E call
|
||||||
|
mov bx, 0x0007 ; BH = page no. BL =Text attribute
|
||||||
|
int 0x10 ; call video interrupt
|
||||||
|
; TODO: check for carry and clear carry before call
|
||||||
|
.endp:
|
||||||
|
__CDECL16_PROC_EXIT
|
||||||
|
ret
|
||||||
|
|
||||||
|
; TODO: fix the prolog, epilog and stack usage to confirm with cdecl16
|
||||||
|
; prints the hex representation of of val
|
||||||
|
; void PrintDWORD(uint32_t val);
|
||||||
|
ALIGN 4, db 0x90
|
||||||
|
PrintDWORD:
|
||||||
|
__CDECL16_PROC_ENTRY
|
||||||
|
.func:
|
||||||
|
mov si, IntToHex_table
|
||||||
|
mov ebx, 16 ; base-16
|
||||||
|
|
||||||
|
mov eax, dword [bp + 4] ;val
|
||||||
|
|
||||||
|
xor edx, edx
|
||||||
|
xor cx, cx
|
||||||
|
.next_digit:
|
||||||
|
div ebx ; dividend in edx:eax -> quotient in eax, remainder in edx
|
||||||
|
push dx ; save remainder
|
||||||
|
inc cx
|
||||||
|
|
||||||
|
xor dx, dx
|
||||||
|
test eax, eax
|
||||||
|
jnz PrintDWORD.next_digit
|
||||||
|
|
||||||
|
.zero_pad:
|
||||||
|
cmp cx, 0x0008
|
||||||
|
je PrintDWORD.print_stack
|
||||||
|
xor ax, ax
|
||||||
|
push ax
|
||||||
|
inc cx
|
||||||
|
jmp PrintDWORD.zero_pad
|
||||||
|
|
||||||
|
.print_stack:
|
||||||
|
pop bx
|
||||||
|
dec cx
|
||||||
|
push cx
|
||||||
|
|
||||||
|
movzx ax, byte [bx+si+0] ; bx = index into Hex lookup table
|
||||||
|
push ax
|
||||||
|
call PrintCharacter
|
||||||
|
add sp, 0x2
|
||||||
|
|
||||||
|
pop cx
|
||||||
|
|
||||||
|
jcxz PrintDWORD.endp
|
||||||
|
jmp PrintDWORD.print_stack
|
||||||
|
|
||||||
|
.endp:
|
||||||
|
__CDECL16_PROC_EXIT
|
||||||
|
ret
|
||||||
%endif
|
%endif
|
||||||
%define __INC_VIDEO
|
%define __INC_VIDEO
|
||||||
@@ -13,20 +13,23 @@
|
|||||||
; You should have received a copy of the GNU General Public License
|
; You should have received a copy of the GNU General Public License
|
||||||
; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
%ifnmacro __CDECL16_ENTRY
|
%ifnmacro __CDECL16_PROC_ENTRY
|
||||||
%macro __CDECL16_ENTRY 0
|
%macro __CDECL16_PROC_ENTRY 0-1
|
||||||
push bp
|
push bp
|
||||||
mov bp, sp
|
mov bp, sp
|
||||||
sub sp, 0x10
|
|
||||||
|
|
||||||
push si
|
push si
|
||||||
push di
|
push di
|
||||||
push bx
|
push bx
|
||||||
|
|
||||||
|
%if %0 = 1
|
||||||
|
sub sp, %1 ; reserve locals only when needed
|
||||||
|
%endif
|
||||||
%endmacro
|
%endmacro
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%ifnmacro __CDECL16_EXIT
|
%ifnmacro __CDECL16_PROC_EXIT
|
||||||
%macro __CDECL16_EXIT 0
|
%macro __CDECL16_PROC_EXIT 0
|
||||||
pop bx
|
pop bx
|
||||||
pop di
|
pop di
|
||||||
pop si
|
pop si
|
||||||
@@ -36,29 +39,108 @@
|
|||||||
%endmacro
|
%endmacro
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%ifnmacro __CDECL16_CALLER_SAVE
|
; __CDECL16_PROC_ARGS nargs
|
||||||
%macro __CDECL16_CALLER_SAVE 0
|
; Creates %$arg1 .. %$argN as [bp+4], [bp+6], ...
|
||||||
push ax
|
; for use inside of function bodies
|
||||||
push cx
|
; BUG: still needs to be tested
|
||||||
push dx
|
%ifnmacro __CDECL16_PROC_ARGS
|
||||||
|
%macro __CDECL16_PROC_ARGS 1
|
||||||
|
%push __CDECL16_PROC_ARGS
|
||||||
|
%assign %$__i 1
|
||||||
|
%rep %1
|
||||||
|
%xdefine %$arg%$__i [bp + 4 + 2*(%$__i-1)]
|
||||||
|
%assign %$__i %$__i + 1
|
||||||
|
%endrep
|
||||||
|
%pop
|
||||||
%endmacro
|
%endmacro
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%ifnmacro __CDECL16_CALLER_RESTORE
|
; __CDECL16_CALL_ARGS a,b,c ==> push c / push b / push a
|
||||||
%macro __CDECL16_CALLER_RESTORE 0
|
; handles pushing values to the stack in the correct order
|
||||||
pop dx
|
%ifnmacro __CDECL16_CALL_ARGS
|
||||||
pop cx
|
%macro __CDECL16_CALL_ARGS 1-*
|
||||||
pop ax
|
%rep %0
|
||||||
|
%rotate -1 ; move the last argument into %1
|
||||||
|
push %1 ; push last, then next-to-last, ...
|
||||||
|
%endrep
|
||||||
%endmacro
|
%endmacro
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
; __CDECL16_CALL func, nargs ; adds sp by nargs*2 after call
|
||||||
|
; adds up word pushes to restore stack frame
|
||||||
|
; WARNING: if you push a dword it will only count 2, use __CDECL16_CALL_ARGS_SIZED
|
||||||
|
%ifnmacro __CDECL16_CALL
|
||||||
|
%macro __CDECL16_CALL 2
|
||||||
|
call %1
|
||||||
|
add sp, %2*2
|
||||||
|
%endmacro
|
||||||
|
%endif
|
||||||
|
|
||||||
|
; __CDECL16_CALL_ARGS_SIZED func, size1[, size2 ...] ; sizes in BYTES
|
||||||
|
; if you *need* to pass dword sized args in 16-bit mode, use this to properly
|
||||||
|
; count the stack frame to restore later!
|
||||||
|
; BUG: still needs to be tested
|
||||||
|
%ifnmacro __CDECL16_CALL_ARGS_SIZED
|
||||||
|
%macro __CDECL16_CALL_ARGS_SIZED 2-*
|
||||||
|
%push __CDECL16_CALL_ARGS_SIZED
|
||||||
|
call %1
|
||||||
|
%assign %$__sum 0
|
||||||
|
%assign %$__i 2
|
||||||
|
%rep %0-1
|
||||||
|
%assign %$__sum %$__sum + %[%$__i] ; sizes may be expressions
|
||||||
|
%assign %$__i %$__i + 1
|
||||||
|
%endrep
|
||||||
|
%if %$__sum & 1
|
||||||
|
%error "__CDECL16_CALL_ARGS_SIZED: total size is odd; pushes must sum to whole bytes actually pushed (usually even)."
|
||||||
|
%endif
|
||||||
|
add sp, %$__sum
|
||||||
|
%pop
|
||||||
|
%endmacro
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%ifnmacro __CDECL16_CLOB
|
||||||
|
; Save registers in the order listed. Supports "flags" as a pseudo-reg.
|
||||||
|
%macro __CDECL16_CLOB 1-*
|
||||||
|
%rep %0
|
||||||
|
%ifidni %1, flags
|
||||||
|
pushf
|
||||||
|
%else
|
||||||
|
push %1
|
||||||
|
%endif
|
||||||
|
%rotate 1
|
||||||
|
%endrep
|
||||||
|
%endmacro
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%ifnmacro __CDECL16_UNCLOB
|
||||||
|
; Restore in reverse order of CLOB. Supports "flags".
|
||||||
|
%macro __CDECL16_UNCLOB 1-*
|
||||||
|
%rep %0
|
||||||
|
%rotate -1
|
||||||
|
%ifidni %1, flags
|
||||||
|
popf
|
||||||
|
%else
|
||||||
|
pop %1
|
||||||
|
%endif
|
||||||
|
%endrep
|
||||||
|
%endmacro
|
||||||
|
%endif
|
||||||
|
|
||||||
|
;
|
||||||
|
; Only setup the minimum stack frame
|
||||||
|
; unlike the above, everything is caller save
|
||||||
|
;
|
||||||
%ifnmacro __FASTCALL16_ENTRY
|
%ifnmacro __FASTCALL16_ENTRY
|
||||||
%macro __FASTCALL16_ENTRY 0
|
%macro __FASTCALL16_ENTRY 0-1
|
||||||
push bp
|
push bp
|
||||||
mov bp, sp
|
mov bp, sp
|
||||||
|
%if %0 = 1
|
||||||
|
sub sp, %1 ; reserve locals only when needed
|
||||||
|
%endif
|
||||||
%endmacro
|
%endmacro
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
; restore minimum stack frame, all regs are caller save
|
||||||
%ifnmacro __FASTCALL16_EXIT
|
%ifnmacro __FASTCALL16_EXIT
|
||||||
%macro __FASTCALL16_EXIT 0
|
%macro __FASTCALL16_EXIT 0
|
||||||
mov sp, bp
|
mov sp, bp
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
%ifndef __INC_STEVIA_CONFIG
|
%ifndef __INC_STEVIA_CONFIG
|
||||||
|
|
||||||
%define SECTOR_SIZE 512
|
%define SECTOR_SIZE 0x200
|
||||||
%define STAGE2_SECTOR_COUNT 0x20
|
%define STAGE2_SECTOR_COUNT 0x20
|
||||||
; 16 KiB
|
; 16 KiB
|
||||||
%define MAX_STAGE2_BYTES (SECTOR_SIZE * STAGE2_SECTOR_COUNT)
|
%define MAX_STAGE2_BYTES (SECTOR_SIZE * STAGE2_SECTOR_COUNT)
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
; Copyright (C) 2025 Elaina Claus
|
|
||||||
;
|
|
||||||
; This program is free software: you can redistribute it and/or modify
|
|
||||||
; it under the terms of the GNU General Public License as published by
|
|
||||||
; the Free Software Foundation, either version 3 of the License, or
|
|
||||||
; (at your option) any later version.
|
|
||||||
;
|
|
||||||
; This program is distributed in the hope that it will be useful,
|
|
||||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
; GNU General Public License for more details.
|
|
||||||
;
|
|
||||||
; You should have received a copy of the GNU General Public License
|
|
||||||
; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
%ifndef __INC_EARLY_MEM
|
|
||||||
|
|
||||||
;PhysicalAddress = Segment * 16 + Offset
|
|
||||||
%define SEG_TO_LINEAR(s,o) ((s << 4) + o)
|
|
||||||
|
|
||||||
; Offset = physical / (Segment * 16)
|
|
||||||
%define LINEAR_TO_OFFSET(p,s) ((p / (s << 4)))
|
|
||||||
|
|
||||||
; Seg = (physical - offset) / 16
|
|
||||||
%define LINEAR_TO_SEGMENT(p,o) ((p - o) >> 4)
|
|
||||||
|
|
||||||
%endif
|
|
||||||
%define __INC_EARLY_MEM
|
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
%ifndef __INC_ENTRY
|
%ifndef __INC_ENTRY
|
||||||
|
|
||||||
%define MBR_ENTRY 0x8C00
|
%define MBR_ENTRY 0x6C00
|
||||||
%define VBR_ENTRY 0x7C00
|
%define VBR_ENTRY 0x7C00
|
||||||
%define STAGE2_ENTRY 0x0500
|
%define STAGE2_ENTRY 0x0500
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,7 @@
|
|||||||
|
|
||||||
%ifndef __INC_ERROR_CODES
|
%ifndef __INC_ERROR_CODES
|
||||||
|
|
||||||
; Errors
|
; MBR Error codes
|
||||||
; 12 Errors, 5 in use
|
|
||||||
%define MBR_ERROR_DISK_T_ERR 'a'
|
%define MBR_ERROR_DISK_T_ERR 'a'
|
||||||
%define MBR_ERROR_NO_INT32E 'b'
|
%define MBR_ERROR_NO_INT32E 'b'
|
||||||
%define MBR_ERROR_NO_NO_BOOT_PART 'c'
|
%define MBR_ERROR_NO_NO_BOOT_PART 'c'
|
||||||
@@ -30,7 +29,7 @@
|
|||||||
%define MBR_ERROR_RESERVED_k 'k'
|
%define MBR_ERROR_RESERVED_k 'k'
|
||||||
%define MBR_ERROR_INT13h_EREAD_ERR 'l'
|
%define MBR_ERROR_INT13h_EREAD_ERR 'l'
|
||||||
|
|
||||||
; 12 Error
|
; VBR Error codes
|
||||||
%define VBR_ERROR_WRONG_FAT_SIZE 'm'
|
%define VBR_ERROR_WRONG_FAT_SIZE 'm'
|
||||||
%define VBR_ERROR_NO_SIGNATURE 'n'
|
%define VBR_ERROR_NO_SIGNATURE 'n'
|
||||||
%define VBR_ERROR_DISK_READ_ERR 'o'
|
%define VBR_ERROR_DISK_READ_ERR 'o'
|
||||||
@@ -44,31 +43,31 @@
|
|||||||
%define VBR_ERROR_RESERVED_w 'w'
|
%define VBR_ERROR_RESERVED_w 'w'
|
||||||
%define VBR_ERROR_RESERVED_x 'x'
|
%define VBR_ERROR_RESERVED_x 'x'
|
||||||
|
|
||||||
; 22 errors, 8 in use
|
; Stage2 Error codes
|
||||||
%define STAGE2_A20_FAILED 'A'
|
%define STAGE2_A20_FAILED 'A'
|
||||||
%define STAGE2_SIGNATURE_MISSING 'B'
|
%define STAGE2_SIGNATURE_MISSING 'B'
|
||||||
%define STAGE2_MM_E820_NO_SUPPORT 'C'
|
%define STAGE2_MM_E820_NO_SUPPORT 'C'
|
||||||
%define STAGE2_MM_E820_MISC_ERR 'D'
|
%define STAGE2_MM_E820_MISC_ERR 'D'
|
||||||
%define STAGE2_MM_E820_NONSTANDARD 'E'
|
%define STAGE2_MM_E820_NONSTANDARD 'E'
|
||||||
%define STAGE2_MM_E820_NO_SMAP 'F'
|
%define STAGE2_MM_E820_NO_SMAP 'F'
|
||||||
%define STAGE2_MBR_DISK_READ_ERROR 'G'
|
%define STAGE2_INT13_DISK_READ_ERR 'G'
|
||||||
%define STAGE2_FAT32_INIT_ERROR 'H'
|
%define STAGE2_FAT32_E_FMT 'H'
|
||||||
%define STAGE2_FAT32_NO_FILE 'I'
|
%define STAGE2_FAT32_E_RANGE 'I'
|
||||||
%define STAGE2_FAT32_END_OF_CHAIN 'J'
|
%define STAGE2_FAT32_E_NOSUCH 'J'
|
||||||
%define STAGE2_FAT32_NCLUS_CFDIVZ 'K'
|
%define STAGE2_FAT32_E_ISDIR 'K'
|
||||||
%define STAGE2_FAT32_CLS2LBA_CF 'L'
|
%define STAGE2_FAT32_E_TOOLONG 'L'
|
||||||
%define STAGE2_FAT32_INIT_CF 'M'
|
%define STAGE2_FAT32_E_UNSUPPORTED 'M'
|
||||||
%define STAGE2_ERROR_INFOPRINTER 'N'
|
%define STAGE2_FAT32_E_UNIMPLEMENTED 'N'
|
||||||
%define STAGE2_ERROR_RESERVED_O 'O'
|
%define STAGE2_ERROR_BAD_MBR 'O'
|
||||||
%define STAGE2_ERROR_RESERVED_P 'P'
|
%define STAGE2_VBR_E_ACTIVE 'P'
|
||||||
%define STAGE2_ERROR_RESERVED_Q 'Q'
|
%define STAGE2_VBR_E_SIGN 'Q'
|
||||||
%define STAGE2_ERROR_RESERVED_R 'R'
|
%define STAGE2_VBR_E_TOT 'R'
|
||||||
%define STAGE2_ERROR_RESERVED_S 'S'
|
%define STAGE2_VBR_E_FATSZ 'S'
|
||||||
%define STAGE2_ERROR_RESERVED_T 'T'
|
%define STAGE2_VBR_E_DIRENT 'T'
|
||||||
%define STAGE2_ERROR_RESERVED_U 'U'
|
%define STAGE2_VBR_E_PARTTYPE 'U'
|
||||||
%define STAGE2_ERROR_RESERVED_V 'V'
|
%define STAGE2_RESERVED_E_V 'V'
|
||||||
|
|
||||||
; for development only, specific errors should be above.
|
; Debug error codes
|
||||||
%define STEVIA_DEBUG_OK 'W'
|
%define STEVIA_DEBUG_OK 'W'
|
||||||
%define STEVIA_DEBUG_ERR 'X'
|
%define STEVIA_DEBUG_ERR 'X'
|
||||||
%define STEVIA_DEBUG_UNIMPLEMENTED 'Y'
|
%define STEVIA_DEBUG_UNIMPLEMENTED 'Y'
|
||||||
|
|||||||
290
include/fat32/FAT32_SYS.nasm
Normal file
290
include/fat32/FAT32_SYS.nasm
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
; Copyright (C) 2025 Elaina Claus
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
%ifndef __INC_FAT32_SYS
|
||||||
|
|
||||||
|
%include "partition_table.inc"
|
||||||
|
%include "fat32/fat32_structures.inc"
|
||||||
|
|
||||||
|
; int read_mbr(int boot_drive, void* dst)
|
||||||
|
; destination buffer needs 512 bytes of space
|
||||||
|
FAT32_load_mbr:
|
||||||
|
__CDECL16_PROC_ENTRY
|
||||||
|
.proc:
|
||||||
|
; read mbr on boot drive to memory (for the partition table)
|
||||||
|
movzx ax, byte [bp + 4]
|
||||||
|
push ax ; drive_num (2)
|
||||||
|
push 0x01 ; count (2)
|
||||||
|
|
||||||
|
push dword 0x0 ; lba (4)
|
||||||
|
|
||||||
|
push word [bp + 6] ; offset = dst
|
||||||
|
push __STAGE2_SEGMENT ; this segment
|
||||||
|
call BIOS_int13h_ext_read
|
||||||
|
add sp, 0xC
|
||||||
|
.check_sig:
|
||||||
|
mov bx, [bp + 6]
|
||||||
|
cmp word [bx + 0x1FE], 0xAA55 ; check for bytes at end
|
||||||
|
jne .error_nosign
|
||||||
|
; TODO: this needs more error checking, zero checking, check the sig a bunch of stuff...
|
||||||
|
.endp:
|
||||||
|
__CDECL16_PROC_EXIT
|
||||||
|
ret
|
||||||
|
.error_nosign:
|
||||||
|
ERROR STAGE2_ERROR_BAD_MBR
|
||||||
|
|
||||||
|
; int read_vbr(int boot_drive, void* buf)
|
||||||
|
; read vbr on boot partition to memory (for fat bpb/ebpb)
|
||||||
|
; TODO: seperate validation and loading the sector, just check the 0xAA55 at the end here...
|
||||||
|
FAT32_load_vbr:
|
||||||
|
__CDECL16_PROC_ENTRY
|
||||||
|
.proc:
|
||||||
|
mov bx, SteviaInfo
|
||||||
|
mov ax, word [bx + SteviaInfoStruct_t.p16_MbrPtr]
|
||||||
|
add ax, DISK_PARTITION_TABLE_OFFSET
|
||||||
|
mov bx, ax ; offset to part table
|
||||||
|
mov cx, 4 ; only checking 4 entries
|
||||||
|
|
||||||
|
.find_active_L0:
|
||||||
|
mov al, [bx + PartEntry_t.attributes]
|
||||||
|
cmp al, 0x80 ; 0x80 == 1000_0000b
|
||||||
|
je .check_fstype
|
||||||
|
add bx, PartEntry_t_size ; next part entry's attributes
|
||||||
|
loop .find_active_L0
|
||||||
|
jmp .error_noactive
|
||||||
|
.check_fstype:
|
||||||
|
; check for part_type = 0x0C (DOS 7.1+/W95 FAT32 w/ LBA) or 0x1C (Hidden 0x0C)
|
||||||
|
__BOCHS_MAGIC_DEBUG
|
||||||
|
mov al, [bx + PartEntry_t.part_type]
|
||||||
|
cmp al, 0x0C
|
||||||
|
je .active_ok
|
||||||
|
; *or*
|
||||||
|
cmp al, 0x1C
|
||||||
|
je .active_ok
|
||||||
|
|
||||||
|
jmp .error_badparttype ; error if part_type != 0x1C or 0x0C
|
||||||
|
.active_ok:
|
||||||
|
movzx ax, byte [bp + 4]
|
||||||
|
push ax ; drive_num (2)
|
||||||
|
push 0x01 ; count (2)
|
||||||
|
|
||||||
|
mov eax, dword [bx + PartEntry_t.lba_start]
|
||||||
|
push dword eax ; lba (4)
|
||||||
|
|
||||||
|
push word [bp + 6] ; offset = dst
|
||||||
|
push __STAGE2_SEGMENT ; this segment
|
||||||
|
call BIOS_int13h_ext_read
|
||||||
|
add sp, 0xC
|
||||||
|
; vbr (with fat bpb/ebpb) is at the buffer now
|
||||||
|
.check_sig:
|
||||||
|
mov bx, [bp + 6]
|
||||||
|
cmp word [bx + 0x1FE], 0xAA55 ; check for bytes at end
|
||||||
|
jne .error_nosign
|
||||||
|
.check_FAT_sanity:
|
||||||
|
; we only quickly validate that this is *probably* a FAT32 volume
|
||||||
|
|
||||||
|
add bx, 11 ; point bx at start of bpb (skip jmp code and ident)
|
||||||
|
cmp word [bx + FAT32_bpb_t.u16_TotalSectors16], 0 ; TotalSectors16 should be 0 (use TotalSectors32 in bpb)
|
||||||
|
jne .error_totsectors
|
||||||
|
|
||||||
|
cmp word [bx + FAT32_bpb_t.u16_FATSize16], 0 ; FatSize16 will be 0 if FAT32 (use FATSize32 in ebpb)
|
||||||
|
jne .error_fatsz
|
||||||
|
|
||||||
|
cmp word [bx + FAT32_bpb_t.u16_RootEntryCount16], 0 ; root dir info is in data clusters on fat32
|
||||||
|
jne .error_rootdir
|
||||||
|
.endp:
|
||||||
|
__CDECL16_PROC_EXIT
|
||||||
|
ret
|
||||||
|
.error_noactive:
|
||||||
|
ERROR STAGE2_VBR_E_ACTIVE
|
||||||
|
.error_nosign:
|
||||||
|
ERROR STAGE2_VBR_E_SIGN
|
||||||
|
.error_totsectors:
|
||||||
|
ERROR STAGE2_VBR_E_TOT
|
||||||
|
.error_fatsz:
|
||||||
|
ERROR STAGE2_VBR_E_FATSZ
|
||||||
|
.error_rootdir:
|
||||||
|
ERROR STAGE2_VBR_E_DIRENT
|
||||||
|
.error_badparttype:
|
||||||
|
ERROR STAGE2_VBR_E_PARTTYPE
|
||||||
|
|
||||||
|
; what a 'mount' should probably do at this point...
|
||||||
|
; - read VBR at partition_lba
|
||||||
|
; - validate FAT32 signatures
|
||||||
|
; - fill fat32_bpb_t and compute derived fields
|
||||||
|
; - read FSInfo (free count/next free)
|
||||||
|
; - ???
|
||||||
|
; int fat32_mount(FAT32_State_t* state, uint32_t partition_lba);
|
||||||
|
FAT32_mountfs:
|
||||||
|
__CDECL16_PROC_ENTRY
|
||||||
|
.proc:
|
||||||
|
; mount: parse BPB, derive fat0_lba, data_lba, cluster0_lba.
|
||||||
|
|
||||||
|
.endp:
|
||||||
|
__CDECL16_PROC_EXIT
|
||||||
|
ret
|
||||||
|
.error:
|
||||||
|
ERROR STEVIA_DEBUG_ERR
|
||||||
|
|
||||||
|
|
||||||
|
; int fat32_read_fat(FAT32_State_t* state, uint32_t clus, uint32_t* out);
|
||||||
|
FAT32_read_fat:
|
||||||
|
__CDECL16_PROC_ENTRY
|
||||||
|
.proc:
|
||||||
|
; Read 32-bit FAT entry for cluster n
|
||||||
|
.endp:
|
||||||
|
__CDECL16_PROC_EXIT
|
||||||
|
ret
|
||||||
|
.error:
|
||||||
|
ERROR STEVIA_DEBUG_ERR
|
||||||
|
|
||||||
|
; FAT32 entry is 32-bits; only low 28 bits are meaningful.
|
||||||
|
; EOC if (val & 0x0FFFFFFF) >= 0x0FFFFFF8.
|
||||||
|
; bad if == 0x0FFFFFF7.
|
||||||
|
; free if == 0x00000000.
|
||||||
|
; int fat32_next_clus(FAT32_State_t* state, uint32_t clus, uint32_t* out_next);
|
||||||
|
FAT32_next_cluster:
|
||||||
|
__CDECL16_PROC_ENTRY
|
||||||
|
.proc:
|
||||||
|
; Walk to next cluster in chain (validates EOC/bad)
|
||||||
|
.endp:
|
||||||
|
__CDECL16_PROC_EXIT
|
||||||
|
ret
|
||||||
|
.error:
|
||||||
|
ERROR STEVIA_DEBUG_ERR
|
||||||
|
|
||||||
|
; e.g:
|
||||||
|
; uint64_t clus_to_lba(FAT32_State_t* state, uint32_t clus) {
|
||||||
|
; return v->data_lba + (uint64_t)(clus - 2) * v->secs_per_clus;
|
||||||
|
; }
|
||||||
|
FAT32_clus_to_lba:
|
||||||
|
__CDECL16_PROC_ENTRY
|
||||||
|
.proc:
|
||||||
|
; Convert cluster -> LBA of first sector of that cluster
|
||||||
|
.endp:
|
||||||
|
__CDECL16_PROC_EXIT
|
||||||
|
ret
|
||||||
|
.error:
|
||||||
|
ERROR STEVIA_DEBUG_ERR
|
||||||
|
|
||||||
|
; Prototyping for now...
|
||||||
|
|
||||||
|
; TODO:
|
||||||
|
; - bio_read_sectors (BIOS int13h LBA or CHS) + tiny sector cache.
|
||||||
|
; - mount: parse BPB, derive fat0_lba, data_lba, cluster0_lba.
|
||||||
|
; - FAT read: fat32_read_fat, fat32_next_clus.
|
||||||
|
; - dir iterator (SFN only) + path lookup.
|
||||||
|
; - file reader (fopen/fread) with cluster crossing.
|
||||||
|
; - contiguity probe for speed (optional).
|
||||||
|
; - (later) LFN support & code page handling.
|
||||||
|
|
||||||
|
|
||||||
|
; keep count <= 127
|
||||||
|
; int bio_read_sectors(uint64_t lba, uint16_t count, void* dst);
|
||||||
|
; will also need a bio_bios_int13h() (refactor ext_disk_read?)
|
||||||
|
; to abstract the backend 'sector getter'
|
||||||
|
|
||||||
|
; Error codes
|
||||||
|
|
||||||
|
; FS_OK 0
|
||||||
|
; FS_E_IO 1 (bio read failed)
|
||||||
|
; FS_E_FMT 2 (not FAT32 or bad BPB)
|
||||||
|
; FS_E_RANGE 3 (bad cluster or out of range)
|
||||||
|
; FS_E_END 4 (iterator end)
|
||||||
|
; FS_E_NOSUCH 5 (file/dir not found)
|
||||||
|
; FS_E_ISDIR 6 (opened dir as file)
|
||||||
|
; FS_E_TOOLONG 7 (path segment too long for 8.3)
|
||||||
|
; FS_E_UNSUPPORTED 8 (LFN present but disabled)
|
||||||
|
; FS_E_UNIMPLEMENTED 0xffff (procedure call unimplmented)
|
||||||
|
|
||||||
|
;
|
||||||
|
; Cache methods
|
||||||
|
;
|
||||||
|
; TODO: make a cache for ~4-8 disk sectors
|
||||||
|
; TODO: make a cache for FATs to avoid having to re-read the FAT
|
||||||
|
;
|
||||||
|
; // uses bio_read_sectors + cache
|
||||||
|
; int cache_read_sector(uint64_t lba, void* dst);
|
||||||
|
; int cache_invalidate_all(void);
|
||||||
|
|
||||||
|
;
|
||||||
|
; SFN directories
|
||||||
|
;
|
||||||
|
|
||||||
|
; typedef struct {
|
||||||
|
; char name83[12]; // "FILENAMEEXT" (no dot), NUL-terminated
|
||||||
|
; uint8_t attr; // ATTR_DIRECTORY=0x10, ATTR_VOLUME=0x08
|
||||||
|
; uint32_t first_clus; // (hi<<16)|lo
|
||||||
|
; uint32_t size; // bytes
|
||||||
|
; } fat32_dirent_sfn_t;
|
||||||
|
|
||||||
|
; typedef struct { // iterator
|
||||||
|
; fat32_bpb_t* v;
|
||||||
|
; uint32_t cur_clus;
|
||||||
|
; uint32_t offs_in_clus; // byte offset
|
||||||
|
; } fat32_dir_iter_t;
|
||||||
|
|
||||||
|
;int fat32_dir_iter_open_root(fat32_bpb_t* v, fat32_dir_iter_t* it);
|
||||||
|
;int fat32_dir_iter_open(fat32_bpb_t* v, uint32_t first_clus, fat32_dir_iter_t* it);
|
||||||
|
;int fat32_dir_iter_next(fat32_dir_iter_t* it, fat32_dirent_sfn_t* out); // FS_OK or FS_E_END
|
||||||
|
|
||||||
|
; typedef struct {
|
||||||
|
; uint32_t first_clus;
|
||||||
|
; uint32_t size;
|
||||||
|
; uint8_t attr; // dir or file
|
||||||
|
; } fat32_node_t;
|
||||||
|
|
||||||
|
; split by / or \.
|
||||||
|
; start at root (v->root_clus).
|
||||||
|
; for each component:
|
||||||
|
; iterate directory with dir_iter_* to find case-insensitive 8.3 match (fold to upper and space-pad during compare).
|
||||||
|
; if final component: return file’s cluster & size.
|
||||||
|
; if intermediate: ensure ATTR_DIRECTORY and descend.
|
||||||
|
;
|
||||||
|
; int fat32_path_lookup(fat32_bpb_t* v, const char* path, fat32_node_t* out);
|
||||||
|
|
||||||
|
; an example 'do the thing' proc to load a file to a location
|
||||||
|
;
|
||||||
|
; // loads file at path into dst, up to max_bytes; returns size read.
|
||||||
|
; int fat32_load_file(fat32_bpb_t* v, const char* path, void* dst,
|
||||||
|
; uint32_t max_bytes, uint32_t* out_size);
|
||||||
|
|
||||||
|
; streamed reads
|
||||||
|
;
|
||||||
|
; typedef struct {
|
||||||
|
; fat32_bpb_t* v;
|
||||||
|
; uint32_t first_clus;
|
||||||
|
; uint32_t cur_clus;
|
||||||
|
; uint32_t cur_clus_index; // which cluster within file we’re on
|
||||||
|
; uint32_t size; // total bytes
|
||||||
|
; uint32_t pos; // current byte position
|
||||||
|
; } fat32_file_t;
|
||||||
|
;
|
||||||
|
;
|
||||||
|
; int fat32_fopen(fat32_bpb_t* v, const char* path, fat32_file_t* f);
|
||||||
|
; int fat32_fread(fat32_file_t* f, void* dst, uint32_t nbytes, uint32_t* out_read);
|
||||||
|
; int fat32_fseek(fat32_file_t* f, uint32_t new_pos); // forward seeks only is fine
|
||||||
|
; int fat32_fclose(fat32_file_t* f);
|
||||||
|
|
||||||
|
|
||||||
|
; an example 'do the thing' proc to load a file to a location
|
||||||
|
;
|
||||||
|
; // loads file at path into dst, up to max_bytes; returns size read.
|
||||||
|
; int fat32_load_file(fat32_bpb_t* v, const char* path, void* dst,
|
||||||
|
; uint32_t max_bytes, uint32_t* out_size);
|
||||||
|
|
||||||
|
|
||||||
|
%endif
|
||||||
|
%define __INC_FAT32_SYS
|
||||||
@@ -58,20 +58,18 @@
|
|||||||
; resulting in a value which does not fit in the Number of Sectors entry at 0x13.
|
; resulting in a value which does not fit in the Number of Sectors entry at 0x13.
|
||||||
|
|
||||||
struc FAT32_bpb_t
|
struc FAT32_bpb_t
|
||||||
.reserved_jmpboot resb 3
|
.u16_BytesPerSector resw 1
|
||||||
.ident resb 8
|
.u8_SectorsPerCluster resb 1
|
||||||
.bytes_per_sector_word resb 2
|
.u16_ReservedSectors resw 1
|
||||||
.sectors_per_cluster_byte resb 1
|
.u8_FatCount resb 1
|
||||||
.reserved_sectors_word resb 2
|
.u16_RootEntryCount16 resw 1 ; Root dir entry count field, 0 on fat32
|
||||||
.fat_count_byte resb 1
|
.u16_TotalSectors16 resw 1 ; total number of sectors size, 0 on fat32
|
||||||
.unused1_ZERO_word resb 2 ; Root entry count field, 0 on fat32
|
.u8_MediaDesc resb 1
|
||||||
.unused2_ZERO_word resb 2 ; total sectors size 16, 0 on fat32
|
.u16_FATSize16 resw 1 ; FAT size 16, 0 on fat32
|
||||||
.media_desc_byte resb 1
|
.u16_SectorsPerTrack resw 1
|
||||||
.unused3_ZERO_word resb 2 ; FAT size 16, 0 on fat32
|
.u16_HeadCount resw 1
|
||||||
.sectors_per_track_word resb 2
|
.u32_HiddenSectors resd 1
|
||||||
.head_count_word resb 2
|
.u32_TotalSectors32 resd 1
|
||||||
.hidden_sectors_dword resb 4
|
|
||||||
.total_sectors_dword resb 4
|
|
||||||
endstruc
|
endstruc
|
||||||
|
|
||||||
; EBPB Information (FAT32)
|
; EBPB Information (FAT32)
|
||||||
@@ -91,19 +89,19 @@ endstruc
|
|||||||
; 8 System identifier string. Always "FAT32 ". The spec says never to trust the contents of this string for any use.
|
; 8 System identifier string. Always "FAT32 ". The spec says never to trust the contents of this string for any use.
|
||||||
|
|
||||||
struc FAT32_ebpb_t
|
struc FAT32_ebpb_t
|
||||||
.FATSz_dword resb 4
|
.u32_FATSize32 resd 1 ; size of *each* fat in sectors, total = FATSz * (# of FATs)
|
||||||
.extflags_word resb 2
|
.u16_ExtFlags resw 1
|
||||||
.FSVersion_word resb 2
|
.u16_FSVersion resw 1
|
||||||
.root_clus_dword resb 4
|
.u32_RootDirCluster resd 1
|
||||||
.FSInfo_word resb 2
|
.u16_FSInfoSector resw 1
|
||||||
.BkBootSec_word resb 2
|
.u16_BkBootSector resw 1
|
||||||
.reserved1 resb 12
|
.reserved0 resb 12
|
||||||
.drive_number_byte resb 1
|
.u8_DriveNumber resb 1
|
||||||
.nt_flags_byte resb 1
|
.u8_NtFlags resb 1
|
||||||
.signature_byte resb 1
|
.u8_Signature resb 1
|
||||||
.volume_id_dword resb 4
|
.u32_VolumeId resd 1
|
||||||
.volume_label_bytea resb 11
|
.volume_label resb 11
|
||||||
.system_ident_bytea resb 8
|
.system_ident resb 8 ; Should always be 'FAT32 '
|
||||||
endstruc
|
endstruc
|
||||||
|
|
||||||
; ## Standard 8.3 structure ###
|
; ## Standard 8.3 structure ###
|
||||||
@@ -197,20 +195,11 @@ endstruc
|
|||||||
|
|
||||||
; 32 bytes
|
; 32 bytes
|
||||||
struc FAT32_State_t
|
struc FAT32_State_t
|
||||||
.first_data_sector_32 resd 1
|
.u32_TotalClusters resd 1
|
||||||
.first_fat_sector_32 resd 1
|
.u32_DataAreaStartSector resd 1
|
||||||
.fat_size_32 resd 1
|
.u32_FATAreaStartSector resd 1
|
||||||
.curr_FAT_cluster_32 resd 1
|
.p16_FATBuffer resw 1
|
||||||
.curr_dir_cluster_32 resd 1
|
.p16_ClustBuffer resw 1
|
||||||
.curr_drive_lba_32 resd 1
|
|
||||||
endstruc
|
|
||||||
|
|
||||||
; 16 bytes
|
|
||||||
struc FAT32_NextClusterData_t
|
|
||||||
.fat_offset resd 1
|
|
||||||
.fat_sector resd 1
|
|
||||||
.entry_offset resd 1
|
|
||||||
.reserved_1 resd 1
|
|
||||||
endstruc
|
endstruc
|
||||||
|
|
||||||
; FAT32 Attributes
|
; FAT32 Attributes
|
||||||
|
|||||||
@@ -23,16 +23,11 @@
|
|||||||
; returns: none
|
; returns: none
|
||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
InitFATDriver:
|
InitFATDriver:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.func:
|
||||||
mov ax, FAT32_State_t_size
|
|
||||||
push ax ; length of fat32_state structure
|
__CDECL16_CALL_ARGS fat32_state, 0x0000, FAT32_State_t_size
|
||||||
xor ax, ax
|
__CDECL16_CALL kmemset, 3
|
||||||
push ax ; init fat32_state with zero
|
|
||||||
mov ax, fat32_state
|
|
||||||
push ax ; address of structure
|
|
||||||
call kmemset
|
|
||||||
sub sp, 0x6
|
|
||||||
|
|
||||||
.calc_active_part:
|
.calc_active_part:
|
||||||
mov ax, word [partition_offset]
|
mov ax, word [partition_offset]
|
||||||
@@ -70,14 +65,14 @@ InitFATDriver:
|
|||||||
mov eax, dword [bx + FAT32_ebpb_t.root_clus_dword]
|
mov eax, dword [bx + FAT32_ebpb_t.root_clus_dword]
|
||||||
mov dword [di + FAT32_State_t.curr_dir_cluster_32], eax
|
mov dword [di + FAT32_State_t.curr_dir_cluster_32], eax
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
.error:
|
.error:
|
||||||
ERROR STAGE2_FAT32_INIT_CF
|
ERROR STAGE2_FAT32_INIT_CF
|
||||||
|
|
||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
FSInfoPrinter:
|
FSInfoPrinter:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.func:
|
||||||
;info we want to print to validate we are loading stuff from the disk correctly
|
;info we want to print to validate we are loading stuff from the disk correctly
|
||||||
; boot_drive # (i.e 0x80)
|
; boot_drive # (i.e 0x80)
|
||||||
@@ -88,7 +83,7 @@ FSInfoPrinter:
|
|||||||
; print entire FAT32 state
|
; print entire FAT32 state
|
||||||
;
|
;
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
.error:
|
.error:
|
||||||
ERROR STAGE2_ERROR_INFOPRINTER
|
ERROR STAGE2_ERROR_INFOPRINTER
|
||||||
@@ -104,18 +99,19 @@ FSInfoPrinter:
|
|||||||
; uint32_t SearchFATDIR(uint8_t* SFN);
|
; uint32_t SearchFATDIR(uint8_t* SFN);
|
||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
SearchFATDIR:
|
SearchFATDIR:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.file_lookup:
|
.file_lookup:
|
||||||
print_string SearchFATDIR_info
|
__CDECL16_CALL_ARGS SearchFATDIR_info
|
||||||
|
__CDECL16_CALL PrintString, 1
|
||||||
|
|
||||||
mov bx, fat32_state
|
mov bx, fat32_state
|
||||||
.load_first_dir:
|
.load_first_dir:
|
||||||
mov eax, dword [bx + FAT32_State_t.curr_dir_cluster_32]
|
|
||||||
push dword eax ; cluster
|
; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster)
|
||||||
mov ax, dir_buffer
|
push dword [bx + FAT32_State_t.curr_dir_cluster_32] ; cluster
|
||||||
push ax ; offset
|
push dir_buffer ; offset
|
||||||
xor ax, ax
|
push 0x0000 ; segment
|
||||||
push ax ; segment
|
call ReadFATCluster
|
||||||
call ReadFATCluster ; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster)
|
|
||||||
add sp, 0x8
|
add sp, 0x8
|
||||||
|
|
||||||
mov si, dir_buffer
|
mov si, dir_buffer
|
||||||
@@ -125,9 +121,9 @@ SearchFATDIR:
|
|||||||
; if eax >= 0x0FFFFFF8 then there are no more clusters (end of chain)
|
; if eax >= 0x0FFFFFF8 then there are no more clusters (end of chain)
|
||||||
; if eax == 0x0FFFFFF7 then this is a cluster that is marked as bad
|
; if eax == 0x0FFFFFF7 then this is a cluster that is marked as bad
|
||||||
|
|
||||||
mov eax, dword [bx + FAT32_State_t.curr_dir_cluster_32]
|
; uint32_t NextCluster(uint32_t active_cluster);
|
||||||
push dword eax
|
push dword [bx + FAT32_State_t.curr_dir_cluster_32]
|
||||||
call NextCluster ; uint32_t NextCluster(uint32_t active_cluster);
|
call NextCluster
|
||||||
add sp, 0x4
|
add sp, 0x4
|
||||||
|
|
||||||
cmp eax, 0x0fff_fff7
|
cmp eax, 0x0fff_fff7
|
||||||
@@ -137,16 +133,14 @@ SearchFATDIR:
|
|||||||
|
|
||||||
.load_next_dir_next_OK:
|
.load_next_dir_next_OK:
|
||||||
; load 512 bytes of directory entries from data sector
|
; load 512 bytes of directory entries from data sector
|
||||||
mov eax, [bx + FAT32_State_t.curr_dir_cluster_32]
|
|
||||||
push dword eax ; cluster
|
|
||||||
|
|
||||||
mov ax, dir_buffer
|
; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster)
|
||||||
push ax ; offset
|
push dword [bx + FAT32_State_t.curr_dir_cluster_32] ; cluster
|
||||||
|
push dir_buffer ; offset
|
||||||
|
push 0x0000 ; segment
|
||||||
|
call ReadFATCluster
|
||||||
|
add sp, 0x8
|
||||||
|
|
||||||
xor ax, ax
|
|
||||||
push ax ; segment
|
|
||||||
call ReadFATCluster ; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster)
|
|
||||||
sub sp, 0x8
|
|
||||||
.empty_dir_entry:
|
.empty_dir_entry:
|
||||||
; check for 0x0 in first byte, if true then there are no more files
|
; check for 0x0 in first byte, if true then there are no more files
|
||||||
; if true we did not find the file, we should error here
|
; if true we did not find the file, we should error here
|
||||||
@@ -176,7 +170,9 @@ SearchFATDIR:
|
|||||||
|
|
||||||
; TODO: move this to a seperate string search function
|
; TODO: move this to a seperate string search function
|
||||||
.parse_dir:
|
.parse_dir:
|
||||||
print_string MaybeFound_Boot_info
|
__CDECL16_CALL_ARGS MaybeFound_Boot_info
|
||||||
|
__CDECL16_CALL PrintString, 1
|
||||||
|
|
||||||
.lfn_check:
|
.lfn_check:
|
||||||
; check for ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID (0x0F) in offset 11
|
; check for ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID (0x0F) in offset 11
|
||||||
; TODO: going to skip LFN for now, since all valid volumes will have SFN's
|
; TODO: going to skip LFN for now, since all valid volumes will have SFN's
|
||||||
@@ -201,7 +197,7 @@ SearchFATDIR:
|
|||||||
mov ax, [si + FAT32_SFN_t.cluster_16_low]
|
mov ax, [si + FAT32_SFN_t.cluster_16_low]
|
||||||
; eax == first cluster of file
|
; eax == first cluster of file
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; BUG: this function needs review
|
; BUG: this function needs review
|
||||||
@@ -210,20 +206,15 @@ SearchFATDIR:
|
|||||||
; if eax == 0x0FFFFFF7 then this is a cluster that is marked as bad
|
; if eax == 0x0FFFFFF7 then this is a cluster that is marked as bad
|
||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
NextCluster:
|
NextCluster:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.func:
|
||||||
print_string NextFATCluster_info
|
__CDECL16_CALL_ARGS NextFATCluster_info
|
||||||
|
__CDECL16_CALL PrintString, 1
|
||||||
|
|
||||||
mov ax, FAT32_NextClusterData_t_size
|
__CDECL16_CALL_ARGS fat32_nc_data, 0x0000, FAT32_NextClusterData_t_size
|
||||||
push ax ; length
|
__CDECL16_CALL kmemset, 3
|
||||||
xor ax, ax
|
|
||||||
push ax ; init with zero
|
|
||||||
mov ax, fat32_nc_data
|
|
||||||
push ax ; address of structure
|
|
||||||
call kmemset
|
|
||||||
sub sp, 0x6
|
|
||||||
|
|
||||||
mov edx, dword [bp + 4]
|
mov edx, dword [bp + 4] ; active_cluster
|
||||||
mov si, fat32_nc_data ; instead of push/pop and moving the data back
|
mov si, fat32_nc_data ; instead of push/pop and moving the data back
|
||||||
mov di, fat32_bpb ; load si & di then use xchg
|
mov di, fat32_bpb ; load si & di then use xchg
|
||||||
mov bx, fat32_state
|
mov bx, fat32_state
|
||||||
@@ -274,8 +265,9 @@ NextCluster:
|
|||||||
mov ebx, dword [si + FAT32_NextClusterData_t.entry_offset]
|
mov ebx, dword [si + FAT32_NextClusterData_t.entry_offset]
|
||||||
mov si, fat_buffer
|
mov si, fat_buffer
|
||||||
mov eax, dword [bx+si+0]
|
mov eax, dword [bx+si+0]
|
||||||
|
; BUG: ???
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
.error_cfdivz:
|
.error_cfdivz:
|
||||||
ERROR STAGE2_FAT32_NCLUS_CFDIVZ
|
ERROR STAGE2_FAT32_NCLUS_CFDIVZ
|
||||||
@@ -283,9 +275,10 @@ NextCluster:
|
|||||||
; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster)
|
; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster)
|
||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
ReadFATCluster:
|
ReadFATCluster:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.func:
|
||||||
print_string ReadFATCluster_info
|
__CDECL16_CALL_ARGS ReadFATCluster_info
|
||||||
|
__CDECL16_CALL PrintString, 1
|
||||||
|
|
||||||
mov bx, fat32_bpb
|
mov bx, fat32_bpb
|
||||||
mov si, fat32_ebpb
|
mov si, fat32_ebpb
|
||||||
@@ -318,7 +311,7 @@ ReadFATCluster:
|
|||||||
call read_disk_raw
|
call read_disk_raw
|
||||||
add sp, 0xC
|
add sp, 0xC
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
.error:
|
.error:
|
||||||
ERROR STAGE2_FAT32_CLS2LBA_CF
|
ERROR STAGE2_FAT32_CLS2LBA_CF
|
||||||
228
include/fat32/old/fat32_structures.inc
Executable file
228
include/fat32/old/fat32_structures.inc
Executable file
@@ -0,0 +1,228 @@
|
|||||||
|
; Copyright (C) 2025 Elaina Claus
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
%ifndef __INC_FAT32_STRUCT
|
||||||
|
|
||||||
|
; ## FAT32 Info ##
|
||||||
|
; total_sectors = bsSectorsHuge
|
||||||
|
; fat_size = bsSectorsPerFat
|
||||||
|
;
|
||||||
|
; first_data_sector = bsResSectors + (bsFATs * bsSectPerFAT);
|
||||||
|
; total_data_sectors = bsSectorsHuge - (bsResSectors + (bsFATs * bsSectPerFAT));
|
||||||
|
; total_clusters = total_data_sectors / bsSectsPerClust
|
||||||
|
; first_fat_sector = bsResSectors
|
||||||
|
;
|
||||||
|
; ## FAT32 Table information ##
|
||||||
|
;
|
||||||
|
; fat_offset = active_cluster * 4
|
||||||
|
; fat_sector = first_fat_sector + (fat_offset / sector_size)
|
||||||
|
; entry_offset = fat_offset % sector_size
|
||||||
|
;
|
||||||
|
; table_value = fat_table[entry_offset] & 0x0FFF_FFFF
|
||||||
|
;
|
||||||
|
; ## FAT32 Directory Entries ##
|
||||||
|
; root_dir_cluster = bsRootDirCluster
|
||||||
|
; root_dir_sectors = ? (this is varible on FAT32 since the root dir is a cluster chain)
|
||||||
|
; first_sector_of_cluster = ((cluster - 2) * bsSectPerClust) + first_data_sector;
|
||||||
|
|
||||||
|
; BPB Information
|
||||||
|
; Size Description
|
||||||
|
; 8 OEM identifier.
|
||||||
|
; 2 The number of Bytes per sector (remember, all numbers are in the little-endian format).
|
||||||
|
; 1 Number of sectors per cluster.
|
||||||
|
; 2 Number of reserved sectors. The boot record sectors are included in this value.
|
||||||
|
; 1 Number of File Allocation Tables (FAT's) on the storage media. Often this value is 2.
|
||||||
|
; 2 Number of directory entries (must be set so that the root directory occupies entire sectors).
|
||||||
|
; 2 The total sectors in the logical volume.
|
||||||
|
; If this value is 0, it means there are more than 65535 sectors in the volume,
|
||||||
|
; and the actual count is stored in the Large Sector Count entry at 0x20.
|
||||||
|
;
|
||||||
|
; 1 This Byte indicates the media descriptor type.
|
||||||
|
; 2 Number of sectors per FAT. FAT12/FAT16 only.
|
||||||
|
; 2 Number of sectors per track.
|
||||||
|
; 2 Number of heads or sides on the storage media.
|
||||||
|
; 4 Number of hidden sectors. (i.e. the LBA of the beginning of the partition.)
|
||||||
|
; 4 Large sector count. This field is set if there are more than 65535 sectors in the volume,
|
||||||
|
; resulting in a value which does not fit in the Number of Sectors entry at 0x13.
|
||||||
|
|
||||||
|
struc FAT32_bpb_t
|
||||||
|
.reserved_jmpboot resb 3
|
||||||
|
.ident resb 8
|
||||||
|
.bytes_per_sector_word resb 2
|
||||||
|
.sectors_per_cluster_byte resb 1
|
||||||
|
.reserved_sectors_word resb 2
|
||||||
|
.fat_count_byte resb 1
|
||||||
|
.unused1_ZERO_word resb 2 ; Root entry count field, 0 on fat32
|
||||||
|
.unused2_ZERO_word resb 2 ; total sectors size 16, 0 on fat32
|
||||||
|
.media_desc_byte resb 1
|
||||||
|
.unused3_ZERO_word resb 2 ; FAT size 16, 0 on fat32
|
||||||
|
.sectors_per_track_word resb 2
|
||||||
|
.head_count_word resb 2
|
||||||
|
.hidden_sectors_dword resb 4
|
||||||
|
.total_sectors_dword resb 4
|
||||||
|
endstruc
|
||||||
|
|
||||||
|
; EBPB Information (FAT32)
|
||||||
|
; Size Description
|
||||||
|
; 4 Sectors per FAT. The size of the FAT in sectors.
|
||||||
|
; 2 Flags.
|
||||||
|
; 2 FAT version number. The high byte is the major version and the low byte is the minor version. FAT drivers should respect this field.
|
||||||
|
; 4 The cluster number of the root directory. Often this field is set to 2.
|
||||||
|
; 2 The sector number of the FSInfo structure.
|
||||||
|
; 2 The sector number of the backup boot sector.
|
||||||
|
; 12 Reserved. When the volume is formated these bytes should be zero.
|
||||||
|
; 1 Drive number. The values here are identical to the values returned by the BIOS interrupt 0x13. 0x00 for a floppy disk and 0x80 for hard disks.
|
||||||
|
; 1 Flags in Windows NT. Reserved otherwise.
|
||||||
|
; 1 Signature (must be 0x28 or 0x29).
|
||||||
|
; 4 Volume ID 'Serial' number. Used for tracking volumes between computers. You can ignore this if you want.
|
||||||
|
; 11 Volume label string. This field is padded with spaces.
|
||||||
|
; 8 System identifier string. Always "FAT32 ". The spec says never to trust the contents of this string for any use.
|
||||||
|
|
||||||
|
struc FAT32_ebpb_t
|
||||||
|
.FATSz_dword resb 4
|
||||||
|
.extflags_word resb 2
|
||||||
|
.FSVersion_word resb 2
|
||||||
|
.root_clus_dword resb 4
|
||||||
|
.FSInfo_word resb 2
|
||||||
|
.BkBootSec_word resb 2
|
||||||
|
.reserved1 resb 12
|
||||||
|
.drive_number_byte resb 1
|
||||||
|
.nt_flags_byte resb 1
|
||||||
|
.signature_byte resb 1
|
||||||
|
.volume_id_dword resb 4
|
||||||
|
.volume_label_bytea resb 11
|
||||||
|
.system_ident_bytea resb 8
|
||||||
|
endstruc
|
||||||
|
|
||||||
|
; ## Standard 8.3 structure ###
|
||||||
|
; Offset Length (Bytes) Description
|
||||||
|
; 0 11 8.3 file name. The first 8 characters are the name and the last 3 are the extension.
|
||||||
|
; 11 1 File Atrributes
|
||||||
|
; READ_ONLY=0x01
|
||||||
|
; HIDDEN=0x02
|
||||||
|
; SYSTEM=0x04
|
||||||
|
; VOLUME_ID=0x08
|
||||||
|
; DIRECTORY=0x10
|
||||||
|
; ARCHIVE=0x20
|
||||||
|
; LFN=READ_ONLY|HIDDEN|SYSTEM|VOLUME_ID == 0x0F
|
||||||
|
;
|
||||||
|
; 12 1 NT Reserved
|
||||||
|
; 13 1 Creation time in tenths of a second.
|
||||||
|
; 14 2 File creation time, Hour 5 bits, Minutes 6 bits, Seconds 5 Bits, multiply seconds by 2
|
||||||
|
; 16 2 File creation date, Year 7 bits, month 4 bits, day 5 bits
|
||||||
|
; 18 2 Last Accessed date. same format at creation date
|
||||||
|
; 20 2 High 16 bits of entry's first cluster
|
||||||
|
; 22 2 Last modification time. same format at creation time
|
||||||
|
; 24 2 Last modification date. same format as creation date
|
||||||
|
; 26 2 Low 16 bits of entry's first cluster
|
||||||
|
; 28 4 File size in bytes
|
||||||
|
|
||||||
|
; FSInfo
|
||||||
|
; 0 0x0 4 Lead signature (must be 0x41615252 to indicate a valid FSInfo structure)
|
||||||
|
; 4 0x4 480 Reserved, these bytes should never be used
|
||||||
|
; 484 0x1E4 4 Another signature (must be 0x61417272)
|
||||||
|
; 488 0x1E8 4 Contains the last known free cluster count on the volume. If the value is 0xFFFFFFFF, then the free count is unknown and must be computed.
|
||||||
|
; However, this value might be incorrect and should at least be range checked (<= volume cluster count)
|
||||||
|
;
|
||||||
|
; 492 0x1EC 4 Indicates the cluster number at which the filesystem driver should start looking for available clusters.
|
||||||
|
; If the value is 0xFFFFFFFF, then there is no hint and the driver should start searching at 2.
|
||||||
|
; Typically this value is set to the last allocated cluster number. As the previous field, this value should be range checked.
|
||||||
|
;
|
||||||
|
; 496 0x1F0 12 Reserved
|
||||||
|
; 508 0x1FC 4 Trail signature (0xAA550000)
|
||||||
|
|
||||||
|
struc FAT32_FSInfo_t
|
||||||
|
.head_sig_dword resd 1 ; 0x41615252
|
||||||
|
.reserved1 resb 480 ; fill zero
|
||||||
|
.body_sig_dword resd 1 ; 0x61417272
|
||||||
|
.free_count_dword resd 1
|
||||||
|
.next_free_dword resd 1
|
||||||
|
.reserved2 resb 12 ; fill zero
|
||||||
|
.tail_sig_dword resd 1 ; 0xAA550000
|
||||||
|
endstruc
|
||||||
|
|
||||||
|
struc FAT32_SFN_t
|
||||||
|
.label_83 resb 11
|
||||||
|
.attributes_byte resb 1
|
||||||
|
.nt_res_byte resb 1
|
||||||
|
.csec_byte resb 1
|
||||||
|
.ctime_word resb 2
|
||||||
|
.cdate_word resb 2
|
||||||
|
.adate_word resb 2
|
||||||
|
.cluster_16_high resb 2
|
||||||
|
.mtime_word resb 2
|
||||||
|
.mdate_word resb 2
|
||||||
|
.cluster_16_low resb 2
|
||||||
|
.size_dword resb 4
|
||||||
|
endstruc
|
||||||
|
|
||||||
|
; ## Long file name (LFN) structure format ##
|
||||||
|
;
|
||||||
|
; 0 1 The order of this entry in the sequence of long file name entries. This value helps you to know where in the file's name the characters from this entry should be placed.
|
||||||
|
; 1 10 The first 5, 2-byte characters of this entry.
|
||||||
|
; 11 1 Attribute. Always equals 0x0F. (the long file name attribute)
|
||||||
|
; 12 1 Long entry type. Zero for name entries.
|
||||||
|
; 13 1 Checksum generated of the short file name when the file was created. The short filename can change without changing the long filename in cases where the partition is mounted on a system which does not support long filenames.
|
||||||
|
; 14 12 The next 6, 2-byte characters of this entry.
|
||||||
|
; 26 2 Always zero.
|
||||||
|
; 28 4 The final 2, 2-byte characters of this entry.
|
||||||
|
;
|
||||||
|
; LFN entries are always placed immediately before their respective 8.3 entry
|
||||||
|
;
|
||||||
|
; LAST_LFN_ENTRY == 0x40
|
||||||
|
; Max of 20 in sequence == 0x14
|
||||||
|
|
||||||
|
struc FAT32_LFN_t
|
||||||
|
.order resb 1
|
||||||
|
.lfn_first5 resb 10
|
||||||
|
.attributes_8 resb 1
|
||||||
|
.zero1 resb 1
|
||||||
|
.checksum resb 1
|
||||||
|
.lfn_next6 resb 12
|
||||||
|
.zero2 resb 2
|
||||||
|
.lfn_last2 resb 4
|
||||||
|
endstruc
|
||||||
|
|
||||||
|
; 32 bytes
|
||||||
|
struc FAT32_State_t
|
||||||
|
.first_data_sector_32 resd 1
|
||||||
|
.first_fat_sector_32 resd 1
|
||||||
|
.fat_size_32 resd 1
|
||||||
|
.curr_FAT_cluster_32 resd 1
|
||||||
|
.curr_dir_cluster_32 resd 1
|
||||||
|
.curr_drive_lba_32 resd 1
|
||||||
|
endstruc
|
||||||
|
|
||||||
|
; 16 bytes
|
||||||
|
struc FAT32_NextClusterData_t
|
||||||
|
.fat_offset resd 1
|
||||||
|
.fat_sector resd 1
|
||||||
|
.entry_offset resd 1
|
||||||
|
.reserved_1 resd 1
|
||||||
|
endstruc
|
||||||
|
|
||||||
|
; FAT32 Attributes
|
||||||
|
%define FAT32_ATTR_RO 0x01
|
||||||
|
%define FAT32_ATTR_HIDDEN 0x02
|
||||||
|
%define FAT32_ATTR_SYSTEM 0x04
|
||||||
|
%define FAT32_ATTR_VOLID 0x08
|
||||||
|
%define FAT32_ATTR_DIR 0x10
|
||||||
|
%define FAT32_ATTR_ARC 0x20
|
||||||
|
|
||||||
|
; LFN == RO | HIDDEN | SYSTEM | VOLID == 0x0F
|
||||||
|
%define FAT32_ATTR_LFN 0x0F
|
||||||
|
|
||||||
|
%endif
|
||||||
|
%define __INC_FAT32_STRUCT
|
||||||
@@ -15,6 +15,9 @@
|
|||||||
|
|
||||||
%ifndef __INC_PART_TABLE
|
%ifndef __INC_PART_TABLE
|
||||||
|
|
||||||
|
%define DISK_SIGNATURE_OFFSET 0x1B8
|
||||||
|
%define DISK_PARTITION_TABLE_OFFSET 0x1BE
|
||||||
|
|
||||||
; Partition table entry format
|
; Partition table entry format
|
||||||
; Off. Size. Description
|
; Off. Size. Description
|
||||||
;0x00 1 Drive attributes (bit 7 set = active or bootable)
|
;0x00 1 Drive attributes (bit 7 set = active or bootable)
|
||||||
@@ -34,8 +37,6 @@ struc PartEntry_t
|
|||||||
endstruc
|
endstruc
|
||||||
|
|
||||||
struc PartTable_t
|
struc PartTable_t
|
||||||
.signature resb 4
|
|
||||||
.reserved resb 2
|
|
||||||
.partition1 resb PartEntry_t_size
|
.partition1 resb PartEntry_t_size
|
||||||
.partition2 resb PartEntry_t_size
|
.partition2 resb PartEntry_t_size
|
||||||
.partition3 resb PartEntry_t_size
|
.partition3 resb PartEntry_t_size
|
||||||
|
|||||||
@@ -9,57 +9,155 @@ struc ArenaStateStruc_t
|
|||||||
.mark resw 1
|
.mark resw 1
|
||||||
endstruc
|
endstruc
|
||||||
|
|
||||||
; void arena_init(void *mem, size_t bytes)
|
; void arena_init(ArenaState *a)
|
||||||
;
|
;
|
||||||
arena_init:
|
ArenaInit:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.proc:
|
||||||
|
mov ax, word [bp + 4] ; ptr to state structure
|
||||||
|
mov di, ax
|
||||||
|
|
||||||
|
xor ax, ax
|
||||||
|
mov word [di + ArenaStateStruc_t.mark], ax
|
||||||
|
mov word [di + ArenaStateStruc_t.end], word (__ARENA_HEAP_START + __ARENA_HEAP_SIZE)
|
||||||
|
mov word [di + ArenaStateStruc_t.start], __ARENA_HEAP_START
|
||||||
|
|
||||||
|
; zero out heap area on init
|
||||||
|
; void* kmemset_byte(void* dst, uint8_t val, uint16_t len);
|
||||||
|
; TODO: use word or qword spacing at least to speed this up
|
||||||
|
push __ARENA_HEAP_SIZE ; len
|
||||||
|
push 0x0 ; val = 0
|
||||||
|
push __ARENA_HEAP_START ; dst
|
||||||
|
call kmemset
|
||||||
|
add sp, 0x6
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; size_t align_up(size_t x, size_t a)
|
; size_t align_up(size_t x, size_t a)
|
||||||
arena_align_up:
|
; ax, bx. cx are all clobbered
|
||||||
__CDECL16_ENTRY
|
; align x up to the nearest specified alignment (a), a should be a power of 2
|
||||||
|
; (x + (a-1)) & ~(a-1)
|
||||||
|
; return value in ax
|
||||||
|
ArenaAlignUp:
|
||||||
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.func:
|
||||||
; align the mark to the nearest specified alignment
|
; if a == 0 return x
|
||||||
.endp:
|
mov ax, [bp + 4] ; x
|
||||||
__CDECL16_EXIT
|
mov bx, [bp + 6] ; a
|
||||||
|
|
||||||
|
test bx, bx
|
||||||
|
jz .endf
|
||||||
|
|
||||||
|
; enforce power-of-two for alignment, return x
|
||||||
|
; for example...
|
||||||
|
; alignment = 0x0010,
|
||||||
|
; 0x0010 & (0x0010 - 0x0001)
|
||||||
|
; 0x0010 & 0x000F -> 1_0000000b & 0_11111111b => 0b == zero
|
||||||
|
;
|
||||||
|
; alignment = 0x0006
|
||||||
|
; 0x0006 & (0x0006 - 0x0001)
|
||||||
|
; 0x0006 & 0x0005 -> 00000110b & 00000101b => 00000100b != 0
|
||||||
|
;
|
||||||
|
; i.e any power of 2 has only 1 bit set in binary (2 = 0010b, 4 = 0100b, 8 = 1000b and so on)
|
||||||
|
; subtracting 1 from a power of 2 'flips' lower bits ( 7 = 0111b, 15 = 1111b ...)
|
||||||
|
; so 'and'ing a power of two with (itself - 1) will result in none of the bit's being set
|
||||||
|
mov cx, bx
|
||||||
|
dec cx
|
||||||
|
test bx, cx
|
||||||
|
jnz .endf
|
||||||
|
|
||||||
|
dec bx ; a - 1
|
||||||
|
|
||||||
|
mov cx, ax
|
||||||
|
add cx, bx ; x + (a-1)
|
||||||
|
not bx ; ~(a-1)
|
||||||
|
|
||||||
|
and cx, bx ; and with the inverse
|
||||||
|
|
||||||
|
mov ax, cx ; move to ax and return
|
||||||
|
.endf:
|
||||||
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; void* arena_alloc(void* a, size_t bytes, size_t align)
|
; void* arena_alloc(size_t bytes, size_t align)
|
||||||
arena_alloc:
|
; bp-2 - current used arena (i.e 'highmark')
|
||||||
__CDECL16_ENTRY
|
; bp-4 - aligned_ptr
|
||||||
.func:
|
; bp-6 - new_end
|
||||||
|
ArenaAlloc:
|
||||||
|
__CDECL16_PROC_ENTRY 0x10
|
||||||
|
.proc:
|
||||||
; remove bytes from pool and increment mark to the new cursor location
|
; remove bytes from pool and increment mark to the new cursor location
|
||||||
; return a pointer to the begining of allocated segment
|
; return a pointer to the begining of allocated segment
|
||||||
|
mov bx, early_heap_state
|
||||||
|
|
||||||
|
mov ax, word [bx + ArenaStateStruc_t.start]
|
||||||
|
mov dx, word [bx + ArenaStateStruc_t.mark]
|
||||||
|
add ax, dx ; i.e the total used arena
|
||||||
|
mov word [bp - 2], ax ; save as a local
|
||||||
|
|
||||||
|
push bx ; save heap_state pointer
|
||||||
|
|
||||||
|
|
||||||
|
push word [bp + 6] ; requested next allocation alignment
|
||||||
|
push word [bp - 2] ; current arena 'highmark'
|
||||||
|
call ArenaAlignUp
|
||||||
|
add sp, 0x4
|
||||||
|
mov word [bp - 4], ax ; save return value
|
||||||
|
|
||||||
|
pop bx ; restore heap_state pointer
|
||||||
|
|
||||||
|
; new_end = aligned_ptr + bytes
|
||||||
|
add ax, word [bp + 4] ; add to total (so current aligned mark + bytes)
|
||||||
|
mov word [bp - 6], ax ; save as local
|
||||||
|
|
||||||
|
mov dx, word [bx + ArenaStateStruc_t.end]
|
||||||
|
cmp ax, dx
|
||||||
|
ja .error ; if our heap end is < the requested throw an error, heap is full
|
||||||
|
; else update the mark to the new value & return the aligned pointer
|
||||||
|
|
||||||
|
; mark_delta = new_end - curr_used
|
||||||
|
mov dx, word [bp - 6]
|
||||||
|
sub dx, word [bp - 2]
|
||||||
|
|
||||||
|
; mark += mark_delta
|
||||||
|
mov ax, word [bx + ArenaStateStruc_t.mark]
|
||||||
|
add ax, dx
|
||||||
|
mov word [bx + ArenaStateStruc_t.mark], ax
|
||||||
|
|
||||||
|
; return aligned_ptr
|
||||||
|
mov ax, word [bp - 4]
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
.error:
|
||||||
|
ERROR STEVIA_DEBUG_ERR
|
||||||
|
|
||||||
arena_mark:
|
arena_mark:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.proc:
|
||||||
; return the current location of the 'cursor' in the allocator
|
; return the current location of the 'cursor' in the allocator
|
||||||
|
ERROR STEVIA_DEBUG_UNIMPLEMENTED
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
arena_reset_to:
|
arena_reset_to:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.proc:
|
||||||
; rewind the arena to a previously marked point
|
; rewind the arena to a previously marked point
|
||||||
|
ERROR STEVIA_DEBUG_UNIMPLEMENTED
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
arena_reset:
|
arena_reset:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.proc:
|
||||||
; reset the entire heap to a fresh state
|
; reset the entire heap to a fresh state
|
||||||
|
ERROR STEVIA_DEBUG_UNIMPLEMENTED
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
%endif
|
%endif
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
; void* kmemset_byte(void* dst, uint8_t val, uint16_t len);
|
; void* kmemset_byte(void* dst, uint8_t val, uint16_t len);
|
||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
kmemset:
|
kmemset:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.func:
|
||||||
mov cx, [bp + 8] ; uint16_t len
|
mov cx, [bp + 8] ; uint16_t len
|
||||||
mov al, byte [bp + 6] ; uint8_t val
|
mov al, byte [bp + 6] ; uint8_t val
|
||||||
@@ -29,14 +29,14 @@ kmemset:
|
|||||||
rep stosb
|
rep stosb
|
||||||
mov ax, di ; return pointer to dest + len (last elem of dest)
|
mov ax, di ; return pointer to dest + len (last elem of dest)
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; uint8_t* kmemset(uint16_t* dest, uint16_t* src, uint16_t len);
|
; uint8_t* kmemset(uint16_t* dest, uint16_t* src, uint16_t len);
|
||||||
; not overlap safe
|
; not overlap safe
|
||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
kmemcpy:
|
kmemcpy:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.func:
|
.func:
|
||||||
mov cx, [bp + 8] ; len
|
mov cx, [bp + 8] ; len
|
||||||
mov si, [bp + 6] ; src
|
mov si, [bp + 6] ; src
|
||||||
@@ -46,7 +46,7 @@ kmemcpy:
|
|||||||
rep movsb
|
rep movsb
|
||||||
mov ax, di ; return pointer to dest
|
mov ax, di ; return pointer to dest
|
||||||
.endf:
|
.endf:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
%endif
|
%endif
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
; not overlap safe, only for
|
; not overlap safe, only for
|
||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
kmemcpy5:
|
kmemcpy5:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
push ds
|
push ds
|
||||||
push es
|
push es
|
||||||
.setup_segments:
|
.setup_segments:
|
||||||
@@ -41,7 +41,7 @@ kmemcpy5:
|
|||||||
pop es
|
pop es
|
||||||
pop ds
|
pop ds
|
||||||
.endf:
|
.endf:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
%define __INC_KMEMCPY5_FUNC
|
%define __INC_KMEMCPY5_FUNC
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
; word kmemset_byte(word segment, word dst, byte val, word len);
|
; word kmemset_byte(word segment, word dst, byte val, word len);
|
||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
kmemset4:
|
kmemset4:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_PROC_ENTRY
|
||||||
.setup_segment:
|
.setup_segment:
|
||||||
push es
|
push es
|
||||||
mov ax, [bp + 4]
|
mov ax, [bp + 4]
|
||||||
@@ -35,7 +35,7 @@ kmemset4:
|
|||||||
.restore_segments:
|
.restore_segments:
|
||||||
pop es
|
pop es
|
||||||
.endf:
|
.endf:
|
||||||
__CDECL16_EXIT
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
|
|
||||||
%endif
|
%endif
|
||||||
|
|||||||
@@ -17,15 +17,14 @@ set -euo pipefail
|
|||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
if [ $(id -u) = 0 ]; then
|
if [ $(id -u) = 0 ]; then
|
||||||
echo "Script should not be run as root, it could break something! Exiting!" >&2
|
echo "Script should not be run as root, it could break something!" >&2
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# paths to bootcode
|
# paths to bootcode
|
||||||
mbr_file=build/mbr.bin
|
mbr_file=build/mbr/mbr.bin
|
||||||
vbr_file=build/vbr.bin
|
vbr_file=build/vbr/vbr.bin
|
||||||
stage2_file=build/stage2.bin
|
stage2_file=build/stage2/stage2.bin
|
||||||
boottest_file=build/BOOTi686.bin
|
boottest_file=build/miniboot32/BOOTi686.bin
|
||||||
|
|
||||||
# Disk creation options
|
# Disk creation options
|
||||||
disk_img=build/disk.img
|
disk_img=build/disk.img
|
||||||
@@ -125,8 +124,11 @@ if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
|||||||
echo "[2/7] Write DOS partition table (single FAT32 LBA @ 2048)"
|
echo "[2/7] Write DOS partition table (single FAT32 LBA @ 2048)"
|
||||||
"$SF" --no-reread "$disk_img" < /tmp/pt.sfdisk
|
"$SF" --no-reread "$disk_img" < /tmp/pt.sfdisk
|
||||||
|
|
||||||
echo "[3/7] Make FAT32 filesystem in partition image"
|
# BUG: the default disk img is 256MiB which mkfs.fat wants to create
|
||||||
"$MKFS" -v -F32 -s 1 -n 'STEVIAFS' "$part_img"
|
# a FAT16 FS by default. it needs to be at least 2GiB to to 'lock out'
|
||||||
|
# FAT16 as an option. Force FAT32 here, might(?) break some things.
|
||||||
|
echo "[3/7] Make FAT filesystem in partition image"
|
||||||
|
"$MKFS" -F32 -v -n 'STEVIAFS' "$part_img"
|
||||||
|
|
||||||
echo "[4/7] Patch VBR inside partition image (preserve BPB)"
|
echo "[4/7] Patch VBR inside partition image (preserve BPB)"
|
||||||
|
|
||||||
@@ -159,9 +161,14 @@ if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
|||||||
dd if="$part_img" of="$disk_img" bs=$disk_sector_size seek=$part_start conv=notrunc
|
dd if="$part_img" of="$disk_img" bs=$disk_sector_size seek=$part_start conv=notrunc
|
||||||
|
|
||||||
echo " *** Outputing disk images will be in ./build/output/* *** "
|
echo " *** Outputing disk images will be in ./build/output/* *** "
|
||||||
|
|
||||||
|
if [ ! -d ./build/output ]; then
|
||||||
|
echo "./build/output does not exist. creating"
|
||||||
|
mkdir -p ./build/output
|
||||||
|
fi
|
||||||
gzip -9c "$disk_img" > "$disk_img_final"
|
gzip -9c "$disk_img" > "$disk_img_final"
|
||||||
gzip -9c "$part_img" > "$part_img_final"
|
gzip -9c "$part_img" > "$part_img_final"
|
||||||
tar caf "$artifacts_archive" build/*.bin build/*.map
|
tar caf "$artifacts_archive" --exclude ./build/output ./build/
|
||||||
else
|
else
|
||||||
# Unknown.
|
# Unknown.
|
||||||
echo "Unknown OS type! Supported build hosts systems are GNU/Linux (& WSL)"
|
echo "Unknown OS type! Supported build hosts systems are GNU/Linux (& WSL)"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
[BITS 16]
|
[BITS 16]
|
||||||
[ORG 0x8C00]
|
[ORG 0x6C00]
|
||||||
[CPU KATMAI]
|
[CPU KATMAI]
|
||||||
[WARNING -reloc-abs-byte]
|
[WARNING -reloc-abs-byte]
|
||||||
[WARNING -reloc-abs-word] ; Yes, we use absolute addresses. surpress these warnings.
|
[WARNING -reloc-abs-word] ; Yes, we use absolute addresses. surpress these warnings.
|
||||||
@@ -33,10 +33,10 @@ nop
|
|||||||
%include "config.inc"
|
%include "config.inc"
|
||||||
%include "error_codes.inc"
|
%include "error_codes.inc"
|
||||||
%include "partition_table.inc"
|
%include "partition_table.inc"
|
||||||
%include "fat32/fat32_structures.inc"
|
|
||||||
|
|
||||||
%undef __STEVIA_DEV_DEBUG
|
%undef __STEVIA_DEV_DEBUG
|
||||||
|
|
||||||
|
; BIOS will load 1st sector of boot drive to 0x7c00, init and relocate
|
||||||
ALIGN 4
|
ALIGN 4
|
||||||
init:
|
init:
|
||||||
cli ; We do not want to be interrupted
|
cli ; We do not want to be interrupted
|
||||||
@@ -58,14 +58,14 @@ init:
|
|||||||
cld
|
cld
|
||||||
rep stosb ; zero bss section
|
rep stosb ; zero bss section
|
||||||
|
|
||||||
sub sp, 0x20 ; local varible space
|
sub sp, 0x10 ; local varible space (32 bytes)
|
||||||
push bp ; setup top of stack frame
|
push bp ; setup top of stack frame
|
||||||
|
|
||||||
xor cx, cx
|
xor cx, cx
|
||||||
mov ch, 0x02 ; 0x0200 in cx
|
mov ch, 0x02 ; 0x0200 in cx
|
||||||
mov si, 0x7C00 ; Current MBR Address (loaded here by BIOS)
|
mov si, 0x7C00 ; Current MBR Address (loaded here by BIOS)
|
||||||
mov di, MBR_ENTRY ; New MBR Address (our new relocation address)
|
mov di, MBR_ENTRY ; New MBR Address (our new relocation address)
|
||||||
rep movsb ; copy 512 bytes from 0x0000:7c00 to 0x0000:MBR_ENTRY (7A00 as of writing)
|
rep movsb ; copy 512 bytes from 0x0000:7c00 to 0x0000:MBR_ENTRY (6C00 as of writing)
|
||||||
|
|
||||||
sti
|
sti
|
||||||
|
|
||||||
@@ -96,6 +96,8 @@ main:
|
|||||||
mov ah, 0x41
|
mov ah, 0x41
|
||||||
mov bx, 0x55AA
|
mov bx, 0x55AA
|
||||||
mov dl, 0x80
|
mov dl, 0x80
|
||||||
|
|
||||||
|
clc
|
||||||
int 0x13
|
int 0x13
|
||||||
jnc main.find_active
|
jnc main.find_active
|
||||||
ERROR MBR_ERROR_NO_INT32E ; no extended function support
|
ERROR MBR_ERROR_NO_INT32E ; no extended function support
|
||||||
@@ -107,7 +109,7 @@ main:
|
|||||||
mov al, byte [bx + PartEntry_t.attributes]
|
mov al, byte [bx + PartEntry_t.attributes]
|
||||||
test al, 0x80 ; 0x80 == 1000_0000b
|
test al, 0x80 ; 0x80 == 1000_0000b
|
||||||
jnz main.active_found
|
jnz main.active_found
|
||||||
add bx, 0x10 ; add 16 bytes to offset
|
add bx, PartEntry_t_size ; add 16 bytes to offset
|
||||||
loop main.find_active_L0
|
loop main.find_active_L0
|
||||||
|
|
||||||
ERROR MBR_ERROR_NO_NO_BOOT_PART
|
ERROR MBR_ERROR_NO_NO_BOOT_PART
|
||||||
@@ -119,42 +121,26 @@ main:
|
|||||||
mov word [bp - 4], ax ; update part_offset
|
mov word [bp - 4], ax ; update part_offset
|
||||||
.read_data:
|
.read_data:
|
||||||
movzx ax, byte [bp - 2]
|
movzx ax, byte [bp - 2]
|
||||||
push ax ; drive_num
|
push ax ; drive_num (2)
|
||||||
|
push 0x01 ; count (2)
|
||||||
mov ax, 0x1
|
|
||||||
push ax ; count
|
|
||||||
|
|
||||||
mov dword eax, dword [bx + PartEntry_t.lba_start]
|
mov dword eax, dword [bx + PartEntry_t.lba_start]
|
||||||
push dword eax ; lba
|
push dword eax ; lba (4)
|
||||||
|
|
||||||
mov ax, VBR_ENTRY
|
push word 0x7C00 ; offset = 0x7c00 (2)
|
||||||
push ax ; offset = 0x7c00
|
push 0x00 ; segment = 0 (2)
|
||||||
|
|
||||||
xor ax, ax
|
|
||||||
push ax ; segment = 0
|
|
||||||
|
|
||||||
; uint8_t read_stage2_raw(uint16_t buf_segment, uint16_t buf_offset,
|
; uint8_t read_stage2_raw(uint16_t buf_segment, uint16_t buf_offset,
|
||||||
; uint32_t lba,
|
; uint32_t lba,
|
||||||
; uint16_t count, uint16_t drive_num)
|
; uint16_t count, uint16_t drive_num)
|
||||||
call read_disk_raw
|
call BIOS_int13h_ext_read
|
||||||
add sp, 0xC
|
add sp, 0xC
|
||||||
.goto_vbr:
|
.goto_vbr:
|
||||||
cmp word [VBR_ENTRY + 0x1FE], 0xAA55
|
cmp word [VBR_ENTRY + 0x1FE], 0xAA55
|
||||||
je main.sig_ok
|
je main.sig_ok
|
||||||
ERROR MBR_ERROR_NO_VBR_SIG ; no signature present
|
ERROR MBR_ERROR_NO_VBR_SIG ; no signature present
|
||||||
.sig_ok:
|
.sig_ok:
|
||||||
mov ax, PartTable_t_size
|
mov dl, byte [bp - 2] ; pass drive # from BIOS to VBR in dl
|
||||||
push ax
|
|
||||||
mov ax, DiskSig ; start of partition table
|
|
||||||
push ax
|
|
||||||
mov ax, partition_table
|
|
||||||
push ax
|
|
||||||
call kmemcpy ; copy partition table to bss
|
|
||||||
add sp, 0x6
|
|
||||||
|
|
||||||
mov si, word [bp - 4]
|
|
||||||
mov dl, byte [bp - 2]
|
|
||||||
mov bx, partition_table
|
|
||||||
jmp word 0x0000:VBR_ENTRY
|
jmp word 0x0000:VBR_ENTRY
|
||||||
|
|
||||||
; ###############
|
; ###############
|
||||||
@@ -183,18 +169,15 @@ PartEntry4:
|
|||||||
times 16 db 0x00
|
times 16 db 0x00
|
||||||
BootSig:
|
BootSig:
|
||||||
dw 0xAA55 ; Add boot signature at the end of bootloader
|
dw 0xAA55 ; Add boot signature at the end of bootloader
|
||||||
|
; !!! end of MBR !!!
|
||||||
section .bss follows=.text
|
section .bss follows=.text
|
||||||
begin_bss:
|
begin_bss:
|
||||||
|
|
||||||
align 16, resb 1
|
|
||||||
partition_table resb PartTable_t_size
|
|
||||||
|
|
||||||
align 16, resb 1
|
align 16, resb 1
|
||||||
lba_packet resb LBAPkt_t_size
|
lba_packet resb LBAPkt_t_size
|
||||||
|
|
||||||
align 512, resb 1
|
align 512, resb 1
|
||||||
stack_bottom resb 512 ; 512 byte stack early on
|
stack_bottom resb 1024 - 16 ; 512 byte stack early on
|
||||||
stack_top:
|
stack_top:
|
||||||
mbr_redzone resb 32
|
mbr_redzone resb 16
|
||||||
end_bss:
|
end_bss:
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
[BITS 16]
|
[BITS 16]
|
||||||
[ORG 0x0500] ; IF YOU CHANGE ORG CHANGE THE SIGN OFFSET AT THE END
|
[ORG 0x0500] ; IF YOU CHANGE ORG CHANGE THE SIGN OFFSET AT THE END
|
||||||
[CPU KATMAI]
|
[CPU 686]
|
||||||
[map all build/stage2.map]
|
[map all build/stage2.map]
|
||||||
[WARNING -reloc-abs-byte]
|
[WARNING -reloc-abs-byte]
|
||||||
[WARNING -reloc-abs-word]
|
[WARNING -reloc-abs-word]
|
||||||
@@ -31,31 +31,15 @@
|
|||||||
%include "cdecl16.inc"
|
%include "cdecl16.inc"
|
||||||
%include "entry.inc"
|
%include "entry.inc"
|
||||||
%include "config.inc"
|
%include "config.inc"
|
||||||
%include "early_mem.inc"
|
|
||||||
%include "error_codes.inc"
|
%include "error_codes.inc"
|
||||||
|
|
||||||
%macro print_string 1
|
|
||||||
mov ax, %1
|
|
||||||
push ax
|
|
||||||
call PrintString
|
|
||||||
add sp, 0x2
|
|
||||||
%endmacro
|
|
||||||
|
|
||||||
section .text
|
section .text
|
||||||
begin_text:
|
begin_text:
|
||||||
; dl = byte boot_drive
|
; dl = byte boot_drive
|
||||||
; ax = word part_offset (active partition offset)
|
ALIGN 16, db 0x90
|
||||||
; si = ptr PartTable_t partition_table
|
|
||||||
; di = ptr FAT32_bpb_t fat32_bpb
|
|
||||||
ALIGN 4, db 0x90
|
|
||||||
init:
|
init:
|
||||||
cli ; We do not want to be interrupted
|
cli ; We do not want to be interrupted
|
||||||
|
mov [u8_BootDrive], dl ; copy boot_drive to globals
|
||||||
; these 4 are stored in the .data section and are effectivly const types
|
|
||||||
mov [vbr_part_table_ptr], si ; pointer to partition_table
|
|
||||||
mov [vbr_fat32_bpb_ptr], di ; pointer to fat32_bpb
|
|
||||||
mov [boot_drive], dl ; copy boot_drive to globals
|
|
||||||
mov [partition_offset], ax ; copy partition_offset to globals
|
|
||||||
|
|
||||||
mov ax, __STAGE2_SEGMENT ; set all our segments to the configured segment, except es
|
mov ax, __STAGE2_SEGMENT ; set all our segments to the configured segment, except es
|
||||||
mov ds, ax ; *
|
mov ds, ax ; *
|
||||||
@@ -88,7 +72,7 @@ init:
|
|||||||
jmp word __STAGE2_SEGMENT:main
|
jmp word __STAGE2_SEGMENT:main
|
||||||
|
|
||||||
; ###############
|
; ###############
|
||||||
; Functions
|
; Core Functions
|
||||||
; ###############
|
; ###############
|
||||||
|
|
||||||
%include "util/kmem_func.nasm"
|
%include "util/kmem_func.nasm"
|
||||||
@@ -96,11 +80,18 @@ init:
|
|||||||
%include "util/kmemset4_func.nasm"
|
%include "util/kmemset4_func.nasm"
|
||||||
%include "util/error_func.nasm"
|
%include "util/error_func.nasm"
|
||||||
|
|
||||||
|
; ###############
|
||||||
|
; Functions
|
||||||
|
; ###############
|
||||||
|
%include "util/arena_alloc.nasm"
|
||||||
|
|
||||||
; ###############
|
; ###############
|
||||||
; FAT32 Driver
|
; FAT32 Driver
|
||||||
; ###############
|
; ###############
|
||||||
|
|
||||||
%include 'fat32/FAT32_SYS.inc'
|
%include "partition_table.inc"
|
||||||
|
%include "fat32/fat32_structures.inc"
|
||||||
|
%include 'fat32/FAT32_SYS.nasm'
|
||||||
|
|
||||||
; ###############
|
; ###############
|
||||||
; BIOS functions
|
; BIOS functions
|
||||||
@@ -111,14 +102,10 @@ init:
|
|||||||
; structures
|
; structures
|
||||||
|
|
||||||
struc SteviaInfoStruct_t
|
struc SteviaInfoStruct_t
|
||||||
.MemoryMapPtr resd 1
|
.p16_E820MemoryMapPtr resw 1
|
||||||
.MemoryMapEntries resd 1
|
.u16_E820MMapEntryCount resw 1
|
||||||
endstruc
|
.p16_MbrPtr resw 1
|
||||||
|
.p16_VbrPtr resw 1
|
||||||
struc EarlyBootStruct_t
|
|
||||||
.partition_table resb PartTable_t_size
|
|
||||||
.fat32_bpb resb FAT32_bpb_t_size
|
|
||||||
.fat32_ebpb resb FAT32_ebpb_t_size
|
|
||||||
endstruc
|
endstruc
|
||||||
|
|
||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
@@ -130,55 +117,71 @@ main:
|
|||||||
je main.stage2_main
|
je main.stage2_main
|
||||||
ERROR STAGE2_SIGNATURE_MISSING
|
ERROR STAGE2_SIGNATURE_MISSING
|
||||||
.stage2_main:
|
.stage2_main:
|
||||||
mov ax, PartTable_t_size
|
|
||||||
push ax ; len = PartTable_t_size
|
|
||||||
mov ax, word [vbr_part_table_ptr] ; src = ptr to vbr partition_table
|
|
||||||
push ax
|
|
||||||
mov ax, partition_table ; dst
|
|
||||||
push ax
|
|
||||||
call kmemcpy ; copy partition table data to .data section in stage2
|
|
||||||
add sp, 0x6
|
|
||||||
|
|
||||||
mov ax, (FAT32_bpb_t_size + FAT32_ebpb_t_size) ; len
|
|
||||||
push ax
|
|
||||||
mov ax, word [vbr_fat32_bpb_ptr] ; src
|
|
||||||
push ax
|
|
||||||
mov ax, fat32_bpb ; dst
|
|
||||||
push ax
|
|
||||||
call kmemcpy ; copy bpb & ebpb to memory
|
|
||||||
add sp, 0x6
|
|
||||||
|
|
||||||
call SetTextMode
|
call SetTextMode
|
||||||
call disable_cursor
|
call disable_cursor_bios
|
||||||
print_string HelloPrompt_info
|
|
||||||
|
; setup the early heap
|
||||||
|
__CDECL16_CALL_ARGS early_heap_state
|
||||||
|
__CDECL16_CALL ArenaInit, 1
|
||||||
|
|
||||||
|
__CDECL16_CALL_ARGS pszHelloPrompt
|
||||||
|
__CDECL16_CALL PrintString, 1
|
||||||
|
|
||||||
|
; setup heap space for mbr data
|
||||||
|
__CDECL16_CALL_ARGS 0x200, 0x10
|
||||||
|
__CDECL16_CALL ArenaAlloc, 2
|
||||||
|
mov word [SteviaInfo + SteviaInfoStruct_t.p16_MbrPtr], ax
|
||||||
|
|
||||||
|
push ax ; dst
|
||||||
|
movzx ax, byte [u8_BootDrive]
|
||||||
|
push ax ; boot_drive
|
||||||
|
__CDECL16_CALL FAT32_load_mbr, 2 ; fill/validate mbr buffer
|
||||||
|
|
||||||
|
; setup heap space for vbr data
|
||||||
|
__CDECL16_CALL_ARGS 0x200, 0x10
|
||||||
|
__CDECL16_CALL ArenaAlloc, 2
|
||||||
|
mov word [SteviaInfo + SteviaInfoStruct_t.p16_VbrPtr], ax
|
||||||
|
|
||||||
|
push ax ; dst
|
||||||
|
movzx ax, byte [u8_BootDrive]
|
||||||
|
push ax ; boot_drive
|
||||||
|
__CDECL16_CALL FAT32_load_vbr, 2 ; fill/validate vbr buffer
|
||||||
|
|
||||||
; enable A20 gate
|
; enable A20 gate
|
||||||
call EnableA20
|
call EnableA20
|
||||||
print_string A20_Enabled_OK_info
|
__CDECL16_CALL_ARGS pszA20EnabledOk
|
||||||
|
__CDECL16_CALL PrintString, 1
|
||||||
|
|
||||||
; get system memory map
|
; get system memory map
|
||||||
call GetMemoryMap
|
call GetMemoryMap
|
||||||
print_string MemoryMap_OK_info
|
__CDECL16_CALL_ARGS pszMemoryMapOk
|
||||||
|
__CDECL16_CALL PrintString, 1
|
||||||
|
|
||||||
; enter unreal mode
|
; enter unreal mode (enter PM w/ 16 bit code, 32 bit flat memory model & return to real)
|
||||||
|
; ds, es will be set to the 64KiB STAGE2_SEGMENT, fs/gs will be flat/huge memory (4GiB)
|
||||||
|
; use __REFLAT macros to re-flat ds/es for easy transfers to >1MiB
|
||||||
|
; NOTE: if you modify a segment register you will need to re-unreal it
|
||||||
call EnterUnrealMode
|
call EnterUnrealMode
|
||||||
print_string UnrealMode_OK_info
|
__CDECL16_CALL_ARGS pszUnrealModeOk
|
||||||
|
__CDECL16_CALL PrintString, 1
|
||||||
|
|
||||||
; FAT Driver setup
|
; FAT Driver setup
|
||||||
call InitFATDriver
|
;call InitFATDriver
|
||||||
print_string InitFATSYS_OK_info
|
;__CDECL16_CALL_ARGS pszInitFAT32Ok
|
||||||
|
;__CDECL16_CALL PrintString, 1
|
||||||
|
|
||||||
;
|
;
|
||||||
; Find first cluster of bootable file
|
; Find first cluster of bootable file
|
||||||
call SearchFATDIR
|
;call SearchFATDIR
|
||||||
push dword eax ; save first cluster of bootable file
|
;push dword eax ; save first cluster of bootable file
|
||||||
|
|
||||||
print_string FileFound_OK_info
|
;__CDECL16_CALL_ARGS pszFileFoundMsg
|
||||||
|
;__CDECL16_CALL PrintString, 1
|
||||||
|
|
||||||
pop dword eax
|
;pop dword eax
|
||||||
push dword eax ; print Cluster of boot file
|
;push dword eax ; print Cluster of boot file
|
||||||
call PrintDWORD ; void PrintDWORD(uint32_t dword)
|
;call PrintDWORD ; void PrintDWORD(uint32_t dword)
|
||||||
add sp, 0x4
|
;add sp, 0x4
|
||||||
|
|
||||||
; TODO: using first cluster information, start loading the kernel to memory
|
; TODO: using first cluster information, start loading the kernel to memory
|
||||||
; TODO: going to need an elf parser, some unreal mode file buffer functions to move the data
|
; TODO: going to need an elf parser, some unreal mode file buffer functions to move the data
|
||||||
@@ -187,171 +190,109 @@ hcf:
|
|||||||
|
|
||||||
; ##############################
|
; ##############################
|
||||||
;
|
;
|
||||||
; SYSTEM CONFIGURATION FUNCTIONS
|
; SYSTEM CONFIGURATION FUNCTIONS & MACROS
|
||||||
;
|
;
|
||||||
; ##############################
|
; ##############################
|
||||||
|
|
||||||
; Prints a C-Style string (null terminated) using BIOS vga teletype call
|
; set ds and es segments back to the base of the loader
|
||||||
; void PrintString(char* buf)
|
%ifnmacro __TINY_DS_ES
|
||||||
ALIGN 4, db 0x90
|
%macro __TINY_DS_ES 0
|
||||||
PrintString:
|
mov ax, __STAGE2_SEGMENT
|
||||||
__CDECL16_ENTRY
|
mov ds, ax
|
||||||
mov di, [bp + 4] ; first arg is char[]
|
mov es, ax
|
||||||
.str_len:
|
%endmacro
|
||||||
xor cx, cx ; ECX = 0
|
%endif
|
||||||
not cx ; ECX = -1 == 0xFFFF
|
|
||||||
xor ax, ax ; search for al = 0x0
|
|
||||||
|
|
||||||
cld
|
; for copying between locations in high memory
|
||||||
repne scasb ; deincrement cx while searching for al
|
%ifnmacro __REFLAT_DS_ES
|
||||||
|
%macro __REFLAT_DS_ES 0
|
||||||
not cx ; the inverse of a neg number = abs(x) - 1
|
|
||||||
dec cx ; CX contains the length of the string - nul byte at end
|
|
||||||
.print:
|
|
||||||
mov si, [bp + 4] ; source string
|
|
||||||
.print_L0:
|
|
||||||
movzx ax, byte [si]
|
|
||||||
push ax
|
|
||||||
call PrintCharacter
|
|
||||||
add sp, 0x2
|
|
||||||
|
|
||||||
inc si
|
|
||||||
dec cx
|
|
||||||
|
|
||||||
jcxz PrintString.endp
|
|
||||||
jmp PrintString.print_L0 ; Fetch next character from string
|
|
||||||
.endp:
|
|
||||||
__CDECL16_EXIT
|
|
||||||
ret ; Return from procedure
|
|
||||||
|
|
||||||
; Prints a single character
|
|
||||||
; void PrintCharacter(char c);
|
|
||||||
ALIGN 4, db 0x90
|
|
||||||
PrintCharacter:
|
|
||||||
__CDECL16_ENTRY
|
|
||||||
.func:
|
|
||||||
movzx ax, byte [bp + 4] ; AL = character c
|
|
||||||
mov ah, 0x0E ; INT 0x10, AH=0x0E call
|
|
||||||
mov bx, 0x0007 ; BH = page no. BL =Text attribute 0x07 is lightgrey font on black background
|
|
||||||
int 0x10 ; call video interrupt
|
|
||||||
.endp:
|
|
||||||
__CDECL16_EXIT
|
|
||||||
ret
|
|
||||||
|
|
||||||
; TODO: fix the prolog, epilog and stack usage to confirm with cdecl16
|
|
||||||
; prints the hex representation of of val
|
|
||||||
; void PrintDWORD(uint32_t val);
|
|
||||||
ALIGN 4, db 0x90
|
|
||||||
PrintDWORD:
|
|
||||||
__CDECL16_ENTRY
|
|
||||||
.func:
|
|
||||||
mov si, IntToHex_table
|
|
||||||
mov ebx, 16 ; base-16
|
|
||||||
|
|
||||||
mov eax, dword [bp + 4] ;val
|
|
||||||
|
|
||||||
xor edx, edx
|
|
||||||
xor cx, cx
|
|
||||||
.next_digit:
|
|
||||||
div ebx ; dividend in edx:eax -> quotient in eax, remainder in edx
|
|
||||||
push dx ; save remainder
|
|
||||||
inc cx
|
|
||||||
|
|
||||||
xor dx, dx
|
|
||||||
test eax, eax
|
|
||||||
jnz PrintDWORD.next_digit
|
|
||||||
|
|
||||||
.zero_pad:
|
|
||||||
cmp cx, 0x0008
|
|
||||||
je PrintDWORD.print_stack
|
|
||||||
xor ax, ax
|
|
||||||
push ax
|
|
||||||
inc cx
|
|
||||||
jmp PrintDWORD.zero_pad
|
|
||||||
|
|
||||||
.print_stack:
|
|
||||||
pop bx
|
|
||||||
dec cx
|
|
||||||
push cx
|
|
||||||
|
|
||||||
movzx ax, byte [bx+si+0] ; bx = index into Hex lookup table
|
|
||||||
push ax
|
|
||||||
call PrintCharacter
|
|
||||||
add sp, 0x2
|
|
||||||
|
|
||||||
pop cx
|
|
||||||
|
|
||||||
jcxz PrintDWORD.endp
|
|
||||||
jmp PrintDWORD.print_stack
|
|
||||||
|
|
||||||
.endp:
|
|
||||||
__CDECL16_EXIT
|
|
||||||
ret
|
|
||||||
|
|
||||||
; ##############################
|
|
||||||
;
|
|
||||||
; SYSTEM CONFIGURATION FUNCTIONS
|
|
||||||
;
|
|
||||||
; ##############################
|
|
||||||
ALIGN 4, db 0x90
|
|
||||||
EnterUnrealMode:
|
|
||||||
__CDECL16_ENTRY
|
|
||||||
.func:
|
|
||||||
cli ; no interrupts
|
cli ; no interrupts
|
||||||
push ds ; save real mode data/stack selectors
|
lgdt [((__STAGE2_SEGMENT << 4) + UnrealGdtInfo)] ; load unreal gdt
|
||||||
push es
|
|
||||||
push fs
|
|
||||||
push gs
|
|
||||||
push ss
|
|
||||||
|
|
||||||
push cs ; save real mode code selector
|
|
||||||
xor ax, ax ;
|
|
||||||
pop ax ; save cs to ax to setup far jump
|
|
||||||
mov word [__UNREAL_SEGMENT], ax
|
|
||||||
|
|
||||||
lgdt [((__STAGE2_SEGMENT << 4) + unreal_gdt_info)] ; load unreal gdt
|
|
||||||
|
|
||||||
mov eax, cr0
|
mov eax, cr0
|
||||||
or al,1 ; set pmode bit
|
or eax, 1 ; set pmode bit
|
||||||
mov cr0, eax ; switch to pmode
|
mov cr0, eax ; switch to pmode
|
||||||
jmp short $+2
|
jmp short $+2 ; i-cache flush
|
||||||
|
|
||||||
;jmp far 0x0008:EnterUnrealMode.load_cs
|
mov ax, 0x10 ; select descriptor 2
|
||||||
db 0xEA ; jmp far imm16:imm16
|
mov ds, ax
|
||||||
dw EnterUnrealMode.load_cs ; error_far_ptr
|
mov es, ax
|
||||||
dw 0x0008 ; error_far_seg
|
|
||||||
.load_cs:
|
|
||||||
mov bx, 0x10 ; select descriptor 2
|
|
||||||
mov ds, bx ; 10h = 0001_0000b
|
|
||||||
|
|
||||||
mov ss, bx
|
mov eax, cr0
|
||||||
mov es, bx
|
and eax, ~1 ; toggle bit 1 of cr0
|
||||||
mov fs, bx
|
|
||||||
mov gs, bx ; other data/stack to index 2 (off 0x10)
|
|
||||||
|
|
||||||
and al,0xFE ; toggle bit 1 of cr0
|
|
||||||
mov cr0, eax ; back to realmode
|
mov cr0, eax ; back to realmode
|
||||||
jmp short $+2
|
jmp short $+2 ; i-cache flush
|
||||||
|
|
||||||
;jmp far 0x0008:EnterUnrealMode.unload_cs
|
|
||||||
db 0xEA ; jmp far imm16:imm16
|
|
||||||
dw EnterUnrealMode.unload_cs ; error_far_ptr
|
|
||||||
__UNREAL_SEGMENT:
|
|
||||||
dw 0x0000 ; error_far_seg
|
|
||||||
EnterUnrealMode.unload_cs:
|
|
||||||
pop ss
|
|
||||||
pop gs
|
|
||||||
pop fs
|
|
||||||
pop es
|
|
||||||
pop ds ; get back old segments
|
|
||||||
sti
|
sti
|
||||||
|
|
||||||
|
%endmacro
|
||||||
|
%endif
|
||||||
|
|
||||||
|
; for copying from low memory to high memory (ds on a real segment, es in flat mode)
|
||||||
|
%ifnmacro __REFLAT_ES
|
||||||
|
%macro __REFLAT_ES 0
|
||||||
|
cli ; no interrupts
|
||||||
|
lgdt [((__STAGE2_SEGMENT << 4) + UnrealGdtInfo)] ; load unreal gdt
|
||||||
|
|
||||||
|
mov eax, cr0
|
||||||
|
or eax, 1 ; set pmode bit
|
||||||
|
mov cr0, eax ; switch to pmode
|
||||||
|
jmp short $+2 ; i-cache flush
|
||||||
|
|
||||||
|
mov ax, 0x10 ; select descriptor 2
|
||||||
|
mov es, ax
|
||||||
|
|
||||||
|
mov eax, cr0
|
||||||
|
and eax, ~1 ; toggle bit 1 of cr0
|
||||||
|
mov cr0, eax ; back to realmode
|
||||||
|
jmp short $+2 ; i-cache flush
|
||||||
|
sti
|
||||||
|
|
||||||
|
%endmacro
|
||||||
|
%endif
|
||||||
|
|
||||||
|
ALIGN 4, db 0x90
|
||||||
|
EnterUnrealMode:
|
||||||
|
__CDECL16_PROC_ENTRY
|
||||||
|
cli ; no interrupts
|
||||||
|
.proc:
|
||||||
|
lgdt [((__STAGE2_SEGMENT << 4) + UnrealGdtInfo)] ; load unreal gdt
|
||||||
|
|
||||||
|
mov eax, cr0
|
||||||
|
or eax, 1 ; set pmode bit
|
||||||
|
mov cr0, eax ; switch to pmode
|
||||||
|
|
||||||
|
; set cs to a pm code segment (0x8) w/ the following
|
||||||
|
jmp 0x0008:EnterUnrealMode.set_segs
|
||||||
|
.set_segs:
|
||||||
|
mov ax, 0x10 ; select descriptor 2
|
||||||
|
mov ds, ax ; 10h = 0001_0000b
|
||||||
|
mov es, ax ; es to big data
|
||||||
|
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax ; extra segments to big data as well
|
||||||
|
.pm_start:
|
||||||
|
; code here is running in protected mode w/ descriptor 0x8
|
||||||
|
; insert any PM test code needed here
|
||||||
|
.pm_end:
|
||||||
|
mov eax, cr0
|
||||||
|
and eax, ~1 ; toggle bit 1 of cr0
|
||||||
|
mov cr0, eax ; back to realmode
|
||||||
|
jmp __STAGE2_SEGMENT:EnterUnrealMode.endp
|
||||||
.endp:
|
.endp:
|
||||||
__CDECL16_EXIT
|
sti ; re-enable interupts
|
||||||
|
|
||||||
|
; set ds, es to the STAGE2_SEGMENT, for our model (generally) ds == es == cs
|
||||||
|
; fs, gs & ss are all still huge data model, and the macro(s) "__REFLAT_xxx" exists
|
||||||
|
; to easily access data outside of 64KiB boundries using ds/es addressing
|
||||||
|
__TINY_DS_ES
|
||||||
|
|
||||||
|
__CDECL16_PROC_EXIT
|
||||||
ret
|
ret
|
||||||
end_text:
|
end_text:
|
||||||
|
|
||||||
section .data follows=.text
|
section .data follows=.text
|
||||||
align 512
|
align 16, db 0
|
||||||
|
|
||||||
begin_data:
|
begin_data:
|
||||||
; #############
|
; #############
|
||||||
;
|
;
|
||||||
@@ -360,90 +301,70 @@ begin_data:
|
|||||||
; #############
|
; #############
|
||||||
%define CRLF 0Dh, 0Ah
|
%define CRLF 0Dh, 0Ah
|
||||||
|
|
||||||
%macro define_cstr 2
|
%macro define_cstr 2-*
|
||||||
ALIGN 16
|
%if %0 > 2
|
||||||
%1_cstr:
|
align 16
|
||||||
|
%1:
|
||||||
|
db %{2:-1}, 00h
|
||||||
|
%else
|
||||||
|
align 16
|
||||||
|
%1:
|
||||||
db %2, 00h
|
db %2, 00h
|
||||||
|
%endif
|
||||||
%endmacro
|
%endmacro
|
||||||
|
|
||||||
%macro define_info 2
|
define_cstr pszHelloPrompt, "Hello from Stevia Stage2!", CRLF
|
||||||
ALIGN 16
|
define_cstr pszA20EnabledOk, "A20 Enabled OK", CRLF
|
||||||
%1_info:
|
define_cstr pszMemoryMapOk, "Memory map OK", CRLF
|
||||||
db %2, CRLF, 00h
|
define_cstr pszUnrealModeOk, "Unreal mode OK", CRLF
|
||||||
%endmacro
|
define_cstr pszInitFAT32Ok, "FAT32 Driver Init OK", CRLF
|
||||||
|
|
||||||
define_info HelloPrompt, "Hello from Stevia Stage2!"
|
define_cstr pszFileFoundMsg, "Found SFN entry for bootable binary, first cluster -> ", CRLF
|
||||||
define_info A20_Enabled_OK, "A20 Enabled OK"
|
define_cstr pszSearchFAT32DirMsg, "Searching FAT fs for bootable file...", CRLF
|
||||||
define_info MemoryMap_OK, "Memory map OK"
|
define_cstr pszReadFAT32ClusterMsg, "Attempting to load next FAT", CRLF
|
||||||
define_info UnrealMode_OK, "Unreal mode OK"
|
define_cstr pszMaybeFoundBootMsg, "Maybe found a file...checking...", CRLF
|
||||||
define_info FileFound_OK, "Found SFN entry for bootable binary, first cluster -> "
|
|
||||||
define_info InitFATSYS_OK, "FAT32 Driver Init..."
|
|
||||||
|
|
||||||
define_info SearchFATDIR, "Searching FAT DIR for bootable file..."
|
|
||||||
define_info NextFATCluster, "Attempting to find next FAT cluster..."
|
|
||||||
define_info ReadFATCluster, "Attempting to load next FAT"
|
|
||||||
define_info MaybeFound_Boot, "Maybe found a file...checking..."
|
|
||||||
|
|
||||||
define_cstr BootTarget, "BOOT BIN"
|
define_cstr BootTarget, "BOOT BIN"
|
||||||
|
|
||||||
ALIGN 16, db 0
|
; set to boot_drive passed from BIOS almost first thing in init
|
||||||
BootTarget:
|
align 4, db 0
|
||||||
db 'BOOT BIN'
|
u8_BootDrive:
|
||||||
|
|
||||||
;
|
|
||||||
; pre-bss init globals (generally const...but there are exceptions)
|
|
||||||
;
|
|
||||||
|
|
||||||
align 8, db 0x00
|
|
||||||
boot_drive:
|
|
||||||
db 0x00
|
db 0x00
|
||||||
|
|
||||||
align 8, db 0x00
|
align 16, db 0
|
||||||
partition_offset:
|
|
||||||
dw 0x0000
|
|
||||||
|
|
||||||
align 8, db 0x00
|
|
||||||
vbr_fat32_bpb_ptr:
|
|
||||||
dw 0x0000
|
|
||||||
|
|
||||||
align 8, db 0x00
|
|
||||||
vbr_part_table_ptr:
|
|
||||||
dw 0x0000
|
|
||||||
|
|
||||||
ALIGN 16
|
|
||||||
IntToHex_table:
|
IntToHex_table:
|
||||||
db '0123456789ABCDEF'
|
db '0123456789ABCDEF'
|
||||||
|
|
||||||
; see docs/gdt.txt for a quick refresher on GDT
|
; see docs/gdt.txt for a quick refresher on GDT
|
||||||
ALIGN 16, db 0
|
align 16, db 0
|
||||||
unreal_gdt_info:
|
UnrealGdtInfo:
|
||||||
unreal_gdt_size: dw (unreal_gdt_end - unreal_gdt_start) - 1
|
u16_UnrealGdt_size: dw (UnrealGdtEnd - UnrealGdtStart) - 1
|
||||||
unreal_gdt_ptr: dd ((__STAGE2_SEGMENT << 4) + unreal_gdt_start)
|
pF_UnrealGdtPtr: dd ((__STAGE2_SEGMENT << 4) + UnrealGdtStart)
|
||||||
unreal_gdt_start:
|
UnrealGdtStart:
|
||||||
; entry 0 (null descriptor)
|
; entry 0 (null descriptor)
|
||||||
dq 0 ; first entry is null
|
dq 0 ; first entry is null
|
||||||
|
|
||||||
; entry 1 (16bit code 64KiB limit)
|
; entry 1 (0x8) (16bit code 64KiB limit)
|
||||||
dd 0x0000FFFF ; Base Address(15:0) 31:16, Segment Limit(15:0) 15:0
|
dd 0x0000FFFF ; Base Address(15:0) 31:16, Segment Limit(15:0) 15:0
|
||||||
db 0x00 ; Base Address 23:16
|
db 0x00 ; Base Address 23:16
|
||||||
db 1001_1010b ; Access Byte: Present, ring0, S = 1, executable (1), non-conforming, readable, Accessed
|
db 1001_1010b ; Access Byte: Present, ring0, S = 1, executable (1), non-conforming, readable, Accessed
|
||||||
db 0000_0000b ; Flags: GR = 4KiB, attr = <DB/L/Avl>, Granularity = 4KiB & 16:19 of limit
|
db 0000_0000b ; Flags: GR = 4KiB, attr = <DB/L/Avl>, Granularity = 4KiB & 16:19 of limit
|
||||||
db 0x00 ; Base Address 31:24
|
db 0x00 ; Base Address 31:24
|
||||||
|
|
||||||
; entry 2 (16bit data segment with 4 GiB flat mapping)
|
; entry 2 (0x10) (16bit data segment with 4 GiB flat mapping)
|
||||||
dd 0x0000FFFF ; Base Address(15:0) 31:16, Segment Limit(15:0) 15:0
|
dd 0x0000FFFF ; Base Address(15:0) 31:16, Segment Limit(15:0) 15:0
|
||||||
db 0x00 ; Base Address(23:16)
|
db 0x00 ; Base Address(23:16)
|
||||||
db 1001_0010b ; Access Byte: Present, ring0, S = 1, data (0), non-confirming, writable, present
|
db 1001_0010b ; Access Byte: Present, ring0, S = 1, data (0), non-confirming, writable, present
|
||||||
db 1000_1111b ; Flags: GR = 4KiB, attr = <16-bit/?/?>, Granularity = 4KiB & 16:19 of limit
|
db 1000_1111b ; Flags: GR = 4KiB, attr = <16-bit/?/?>, Granularity = 4KiB & 16:19 of limit
|
||||||
db 0x00 ; Base Address(31:24)
|
db 0x00 ; Base Address(31:24)
|
||||||
unreal_gdt_end:
|
UnrealGdtEnd:
|
||||||
|
|
||||||
ALIGN 16, db 0
|
align 16, db 0
|
||||||
gdt32_info:
|
Gdt32Info:
|
||||||
gdt32_size: dw (gdt32_end - gdt32_start) - 1
|
gdt32_size: dw (Gdt32End - Gdt32Start) - 1
|
||||||
gdt32_ptr: dd ((__STAGE2_SEGMENT << 4) + gdt32_start)
|
gdt32_ptr: dd ((__STAGE2_SEGMENT << 4) + Gdt32Start)
|
||||||
gdt32_start:
|
Gdt32Start:
|
||||||
dq 0
|
dq 0 ; null segment
|
||||||
.gdt32_code:
|
.gdt32_code:
|
||||||
dw 0xFFFF ; code segment (RX)
|
dw 0xFFFF ; code segment (RX)
|
||||||
dw 0x0000
|
dw 0x0000
|
||||||
@@ -472,82 +393,79 @@ gdt32_start:
|
|||||||
db 1001_0000b ; Access: readable, not writable
|
db 1001_0000b ; Access: readable, not writable
|
||||||
db 1100_1111b ; 4KB granularity, 32-bit
|
db 1100_1111b ; 4KB granularity, 32-bit
|
||||||
db 0x00
|
db 0x00
|
||||||
gdt32_end:
|
Gdt32End:
|
||||||
|
|
||||||
ALIGN 8,db 0x00
|
align 16,db 0
|
||||||
BUILD_NASM_VER:
|
BuildNasmVer:
|
||||||
db "Stevia Stage2 built with NASM - ", __NASM_VER__, 00h
|
db "Stevia Stage2 built with NASM - ", __NASM_VER__, 00h
|
||||||
|
|
||||||
ALIGN 8,db 0x00
|
align 16,db 0
|
||||||
BUILD_DATETIME:
|
BuildDateTime:
|
||||||
db 'Assembled - ', __DATE__, ' ', __TIME__, 00h
|
db 'Assembled - ', __DATE__, ' ', __TIME__, 00h
|
||||||
|
|
||||||
ALIGN 8,db 0x00
|
align 16,db 0
|
||||||
BUILD_GIT_VER:
|
BuildGitVer:
|
||||||
db __GIT_VER__, 00h
|
db __GIT_VER__, 00h
|
||||||
|
|
||||||
ALIGN 8,db 0x00
|
align 16,db 0
|
||||||
BUILD_GIT_HASH:
|
BuildGitHash:
|
||||||
db __GIT_HASH__, 00h
|
db __GIT_HASH__, 00h
|
||||||
end_data:
|
end_data:
|
||||||
|
|
||||||
%assign bytes_remaining ((MAX_STAGE2_BYTES - 4) - (($ - $$) + (end_text - begin_text)))
|
%define SIG_BYTES 0x4
|
||||||
%warning STAGE2 has bytes_remaining bytes remaining for code/data (MAX: MAX_STAGE2_BYTES)
|
|
||||||
|
; Optional: fail fast if we overflowed
|
||||||
|
%if ((MAX_STAGE2_BYTES - 512) - (($ - $$) + (end_text - begin_text))) < 0
|
||||||
|
%error "Stage2 overflow: code+data exceed MAX_STAGE2_BYTES - SIG_BYTES"
|
||||||
|
%endif
|
||||||
|
|
||||||
; section start location needs to be a 'critical expression'
|
; section start location needs to be a 'critical expression'
|
||||||
; i.e resolvable at build time, we are setting 0x7E00 as the offset since
|
; i.e resolvable at build time, we are setting 0x0500 as the offset since
|
||||||
section .sign start=((MAX_STAGE2_BYTES - 512) + 0x0500)
|
section .sign start=((MAX_STAGE2_BYTES - 512) + 0x0500)
|
||||||
times ((512 - 4) - ($ -$$) ) db 0x90 ; nop
|
times ((512 - 4) - ($ -$$) ) db 0x90 ; nop
|
||||||
STAGE2_SIG: dd 0xDEADBEEF ; Signature to mark the end of the stage2
|
STAGE2_SIG: dd 0xDEADBEEF ; Signature to mark the end of the stage2
|
||||||
|
; !!! END Stage2 .text/.data !!!
|
||||||
|
align 16, resb 1
|
||||||
section .bss follows=.sign
|
section .bss follows=.sign
|
||||||
begin_bss:
|
begin_bss:
|
||||||
|
|
||||||
; structures
|
; structures
|
||||||
|
align 16, resb 1
|
||||||
alignb 16
|
|
||||||
partition_table resb PartTable_t_size
|
|
||||||
|
|
||||||
alignb 16
|
|
||||||
fat32_bpb resb FAT32_bpb_t_size
|
|
||||||
fat32_ebpb resb FAT32_ebpb_t_size
|
|
||||||
|
|
||||||
alignb 16
|
|
||||||
fat32_nc_data resb 16
|
|
||||||
|
|
||||||
alignb 16
|
|
||||||
lba_packet resb LBAPkt_t_size
|
|
||||||
|
|
||||||
alignb 16
|
|
||||||
fat32_state:
|
|
||||||
resb FAT32_State_t_size
|
|
||||||
|
|
||||||
alignb 16
|
|
||||||
SteviaInfo:
|
SteviaInfo:
|
||||||
resd 4
|
resd SteviaInfoStruct_t_size
|
||||||
;
|
|
||||||
; post-bss init globals
|
align 16, resb 1
|
||||||
;
|
early_heap_state:
|
||||||
|
resb ArenaStateStruc_t_size
|
||||||
|
|
||||||
|
align 16, resb 1
|
||||||
|
lba_packet:
|
||||||
|
resb LBAPkt_t_size
|
||||||
|
|
||||||
;
|
;
|
||||||
; large continuous allocations
|
; large continuous allocations
|
||||||
;
|
;
|
||||||
alignb 16
|
|
||||||
disk_buffer:
|
|
||||||
resb 512
|
|
||||||
fat_buffer:
|
|
||||||
resb 512
|
|
||||||
dir_buffer:
|
|
||||||
resb 512
|
|
||||||
fat_fsinfo:
|
|
||||||
resb 512
|
|
||||||
|
|
||||||
alignb 16
|
; TODO: this will hold 42 entries from the map function
|
||||||
|
; the e820 function needs to check that it doesn't overflow
|
||||||
|
; but realisticly 42 entries is enough for dev work
|
||||||
|
align 16, resb 1
|
||||||
%define BIOSMemoryMap_SIZE 1024
|
%define BIOSMemoryMap_SIZE 1024
|
||||||
BIOSMemoryMap:
|
BIOSMemoryMap:
|
||||||
resb BIOSMemoryMap_SIZE
|
resb BIOSMemoryMap_SIZE
|
||||||
|
|
||||||
alignb 512
|
|
||||||
stack_bottom:
|
|
||||||
resb 1024
|
|
||||||
stack_top:
|
|
||||||
end_bss:
|
end_bss:
|
||||||
|
; !!! End bss data !!!
|
||||||
|
%define STACK_SIZE 0x1000 ; 4 KiB
|
||||||
|
|
||||||
|
; Pad to the cap (emits nothing in the file; only increases .bss virtual size).
|
||||||
|
; If BSS_SIZE > BSS_MAX_BYTES, this becomes negative and NASM errors out.
|
||||||
|
%define BSS_MAX_BYTES (0x2000 - STACK_SIZE)
|
||||||
|
resb (BSS_MAX_BYTES - (end_bss - begin_bss))
|
||||||
|
|
||||||
|
align 16, resb 1
|
||||||
|
stack_bottom:
|
||||||
|
resb STACK_SIZE
|
||||||
|
stack_top:
|
||||||
|
|
||||||
|
; Optional: keep a label for later math:
|
||||||
|
bss_cap_end:
|
||||||
@@ -21,14 +21,21 @@
|
|||||||
%define __STEVIA_VBR
|
%define __STEVIA_VBR
|
||||||
section .text
|
section .text
|
||||||
__ENTRY:
|
__ENTRY:
|
||||||
|
; try to force encode a short jmp nop: i.e 0xEB 0x5A 0x90
|
||||||
|
; will jump right 0x5A (90 bytes) after the end of the ebpb
|
||||||
|
; this could also be encoded as 0xE9 0x?? 0x?? for a near jump
|
||||||
|
; if init ends up being >= 128 bytes from entry.
|
||||||
jmp short (init - $$)
|
jmp short (init - $$)
|
||||||
nop
|
nop
|
||||||
|
|
||||||
; fill BPB area with 0x00 since we skip writing this part to disk
|
; 8 ascii bytes, "MSWIN 4.1", ""
|
||||||
; but we need it for the 'jmp short entry; nop' above
|
phy_bs_ident:
|
||||||
times 33 db 0x00
|
times 8 db 0x00
|
||||||
|
|
||||||
|
phy_bpb_start:
|
||||||
|
times 25 db 0x00
|
||||||
|
|
||||||
phy_ebpb_start:
|
phy_ebpb_start:
|
||||||
; fill eBPB area with 0x00 since we skip writing this part to disk
|
|
||||||
times 54 db 0x00
|
times 54 db 0x00
|
||||||
|
|
||||||
; ###############
|
; ###############
|
||||||
@@ -41,7 +48,6 @@ times 54 db 0x00
|
|||||||
%include "cdecl16.inc"
|
%include "cdecl16.inc"
|
||||||
%include "entry.inc"
|
%include "entry.inc"
|
||||||
%include "config.inc"
|
%include "config.inc"
|
||||||
%include "early_mem.inc"
|
|
||||||
%include "error_codes.inc"
|
%include "error_codes.inc"
|
||||||
%include "partition_table.inc"
|
%include "partition_table.inc"
|
||||||
%include "fat32/fat32_structures.inc"
|
%include "fat32/fat32_structures.inc"
|
||||||
@@ -72,7 +78,7 @@ init:
|
|||||||
cld
|
cld
|
||||||
rep stosb
|
rep stosb
|
||||||
|
|
||||||
sub sp, 0x20 ; local varible space
|
sub sp, 0x10 ; local varible space (32 bytes)
|
||||||
push bp
|
push bp
|
||||||
|
|
||||||
sti ; all done with inital setup and relocation, reenable interupts
|
sti ; all done with inital setup and relocation, reenable interupts
|
||||||
@@ -86,10 +92,6 @@ init:
|
|||||||
%include "util/kmem_func.nasm"
|
%include "util/kmem_func.nasm"
|
||||||
%include "util/error_func.nasm"
|
%include "util/error_func.nasm"
|
||||||
|
|
||||||
; ###############
|
|
||||||
; End Section
|
|
||||||
; ###############
|
|
||||||
|
|
||||||
;
|
;
|
||||||
; byte boot_drive @ bp - 2
|
; byte boot_drive @ bp - 2
|
||||||
; word part_offset @ bp - 4
|
; word part_offset @ bp - 4
|
||||||
@@ -97,31 +99,9 @@ init:
|
|||||||
ALIGN 4, db 0x90
|
ALIGN 4, db 0x90
|
||||||
main:
|
main:
|
||||||
mov byte [bp - 2], dl ; boot_drive
|
mov byte [bp - 2], dl ; boot_drive
|
||||||
mov word [bp - 4], si ; part_offset
|
|
||||||
mov word [bp - 6], bx ; partition_table
|
|
||||||
|
|
||||||
.load_fs_data:
|
|
||||||
mov ax, PartTable_t_size ; count=
|
|
||||||
push ax
|
|
||||||
mov ax, [bp - 6] ; src= ptr partition_table
|
|
||||||
push ax
|
|
||||||
mov ax, partition_table ; dst=
|
|
||||||
push ax
|
|
||||||
call kmemcpy ; copy partition table data
|
|
||||||
add sp, 0x6
|
|
||||||
|
|
||||||
mov ax, (FAT32_bpb_t_size + FAT32_ebpb_t_size) ; size in byte, should be 90 bytes
|
|
||||||
push ax
|
|
||||||
mov ax, __ENTRY
|
|
||||||
push ax
|
|
||||||
mov ax, fat32_bpb ;
|
|
||||||
push ax
|
|
||||||
call kmemcpy ; copy bpb & ebpb to memory
|
|
||||||
add sp, 0x6
|
|
||||||
|
|
||||||
.check_FAT_size: ; we only support a very specific setup of FAT32
|
.check_FAT_size: ; we only support a very specific setup of FAT32
|
||||||
mov bx, fat32_bpb
|
mov bx, phy_bpb_start
|
||||||
test word [bx + FAT32_bpb_t.unused2_ZERO_word], 0 ; TotSectors16 will not be set if FAT32
|
test word [bx + FAT32_bpb_t.u16_TotalSectors16], 0 ; TotSectors16 will not be set if FAT32
|
||||||
jz main.load_stage2
|
jz main.load_stage2
|
||||||
ERROR VBR_ERROR_WRONG_FAT_SIZE
|
ERROR VBR_ERROR_WRONG_FAT_SIZE
|
||||||
.load_stage2:
|
.load_stage2:
|
||||||
@@ -129,28 +109,21 @@ main:
|
|||||||
movzx ax, byte [bp - 2]
|
movzx ax, byte [bp - 2]
|
||||||
push ax ; drive_num
|
push ax ; drive_num
|
||||||
|
|
||||||
mov ax, STAGE2_SECTOR_COUNT
|
push STAGE2_SECTOR_COUNT ; count
|
||||||
push ax ; count
|
|
||||||
|
|
||||||
mov dword eax, 0x1
|
mov dword eax, 0x1
|
||||||
push dword eax ; lba
|
push dword eax ; lba
|
||||||
|
|
||||||
mov ax, STAGE2_ENTRY
|
push STAGE2_ENTRY ; offset
|
||||||
push ax ; offset
|
push 0x00 ; segment = 0
|
||||||
|
|
||||||
xor ax, ax
|
|
||||||
push ax ; segment = 0
|
|
||||||
|
|
||||||
; uint8_t read_stage2_raw(uint16_t buf_segment, uint16_t buf_offset,
|
; uint8_t read_stage2_raw(uint16_t buf_segment, uint16_t buf_offset,
|
||||||
; uint32_t lba,
|
; uint32_t lba,
|
||||||
; uint16_t count, uint16_t drive_num)
|
; uint16_t count, uint16_t drive_num)
|
||||||
call read_disk_raw
|
call BIOS_int13h_ext_read
|
||||||
add sp, 0xC
|
add sp, 0xC
|
||||||
.enter_stage2:
|
.enter_stage2:
|
||||||
mov dl, byte [bp - 2] ; byte boot_drive
|
mov dl, byte [bp - 2] ; byte boot_drive
|
||||||
mov ax, word [bp - 4] ; word part_offset
|
|
||||||
mov si, partition_table ; ptr partition_table
|
|
||||||
mov di, fat32_bpb ; ptr fat32_bpb
|
|
||||||
jmp word 0x0000:STAGE2_ENTRY
|
jmp word 0x0000:STAGE2_ENTRY
|
||||||
|
|
||||||
; ###############
|
; ###############
|
||||||
@@ -166,25 +139,16 @@ times (510 - ($ - $$)) nop ; Fill the rest of sector with nop
|
|||||||
|
|
||||||
BootSig:
|
BootSig:
|
||||||
dw 0xAA55 ; Add boot signature at the end of bootloader
|
dw 0xAA55 ; Add boot signature at the end of bootloader
|
||||||
|
; !!! END VBR !!!
|
||||||
|
|
||||||
section .bss follows=.text
|
section .bss follows=.text
|
||||||
begin_bss:
|
begin_bss:
|
||||||
|
|
||||||
align 16, resb 1
|
|
||||||
partition_table resb PartTable_t_size
|
|
||||||
|
|
||||||
align 16, resb 1
|
|
||||||
fat32_bpb resb FAT32_bpb_t_size
|
|
||||||
fat32_ebpb resb FAT32_ebpb_t_size
|
|
||||||
|
|
||||||
align 16, resb 1
|
|
||||||
fat32_nc_data resb 16
|
|
||||||
|
|
||||||
align 16, resb 1
|
align 16, resb 1
|
||||||
lba_packet resb LBAPkt_t_size
|
lba_packet resb LBAPkt_t_size
|
||||||
|
|
||||||
align 512, resb 1
|
align 512, resb 1
|
||||||
stack_bottom resb 512 ; 512b stack early on
|
stack_bottom resb (1024 - 16) ; 512b stack early on
|
||||||
stack_top:
|
stack_top:
|
||||||
vbr_redzone resb 32
|
vbr_redzone resb 16
|
||||||
end_bss:
|
end_bss:
|
||||||
Reference in New Issue
Block a user