Compare commits

...

4 Commits

Author SHA1 Message Date
anna 2bcfd294be
add custom post-build script
Rust doesn't support those natively.
12 months ago
anna 43d454e9fe
stage1: add header 12 months ago
anna bfc2b5cb7c
stage0: fix assembler warning
This is hopefully the last edit to stage0
for a while.
12 months ago
anna fb36d1f949
add stage1 skeleton 12 months ago

6
Cargo.lock generated

@ -4,4 +4,8 @@ version = 3
[[package]]
name = "bussy"
version = "0.1.0"
version = "0.1.0"
[[package]]
name = "bussy-stage1"
version = "0.1.0"

@ -1,10 +1,30 @@
[package]
name = "bussy"
version = "0.1.0"
edition = "2021"
version.workspace = true
repository.workspace = true
[workspace]
members = [
"stage1"
]
[workspace.package]
version = "0.1.0"
repository = "https://git.bsd.gay/fef/bussy"
[profile.dev]
panic = "abort"
opt-level = "s"
lto = true
codegen-units = 1
debug = true
overflow-checks = true
[profile.release]
panic = "abort"
opt-level = "s"
lto = true
codegen-units = 1
debug = true
overflow-checks = false

@ -0,0 +1,53 @@
#!/usr/bin/env python3
# DISCLAIMER: I don't know python. And i don't like python.
# This is only written in python because pretty much everyone already has it
# installed and rust doesn't support post-build scripts for some reason.
import sys
from utils import crc32, run_sync
if len(sys.argv) >= 2:
PROFILE = sys.argv[1]
else:
PROFILE = "debug"
def finalize_stage1(filename: str):
run_sync(
"objcopy", "-O", "binary",
"target/x86-pc-none/" + PROFILE + "/bussy-stage1",
filename
)
with open(filename, "r+b") as file:
data = bytearray(file.read())
size = len(data)
if size > 0x8000:
print("stage1 is too big (greater than 32 K)")
exit(1)
data[2] = size & 0xff
data[3] = size >> 8
csum = crc32(data)
print("CRC32 checksum of stage1 is " + hex(csum))
data[4] = csum & 0xff
data[5] = (csum >> 8) & 0xff
data[6] = (csum >> 16) & 0xff
data[7] = csum >> 24
file.seek(2)
file.write(data[2:8])
print("Running cargo")
if PROFILE == "debug":
run_sync("cargo", "build", "--workspace")
elif PROFILE == "release":
run_sync("cargo", "build", "--workspace", "--release")
else:
run_sync("cargo", "build", "--workspace", "--profile", PROFILE)
print("Finalizing stage1")
finalize_stage1("target/x86-pc-none/" + PROFILE + "/stage1.bin")

@ -0,0 +1,49 @@
# Miscellaneous utilities, meant to be included from build.py
import os
# Do a fork/execl because that way all children get the same stdout,
# i.e. if it's a tty the executed program should behave appropriately.
# Python probably has an idiomatic way to do this, but frankly idc.
def run_sync(program: str, *args):
path = os.popen("which " + program).read().strip()
child = os.fork()
if child == 0:
os.execl(path, program, *args)
print("execl() failed")
exit(1)
elif child == -1:
print("fork() failed")
exit(1)
status = os.waitpid(child, 0)
if status[1] != 0:
print(program + " exited with status code " + str(status[1]))
exit(1)
def generate_crc_tab(poly_reverse: int):
tab = []
for crc in range(256):
for _ in range(8):
lsb = crc % 2
crc >>= 1
if lsb == 1:
crc ^= poly_reverse
tab.append(crc)
return tab
def do_crc(data, table):
crc = 0xffffffff
for byte in data:
crc = (crc >> 8) ^ table[(crc ^ byte) & 0xff]
return ~crc & 0xffffffff
CCITT32_TAB = generate_crc_tab(0xedb88320)
def crc32(data: bytes):
global CCITT32_TAB
return do_crc(data, CCITT32_TAB)

@ -389,7 +389,7 @@ LOCAL start2
*/
xor %si, %si
cmp $0xacab, %fs:(%si) /* offset 0x00: magic number */
cmpw $0xacab, %fs:(%si) /* offset 0x00: magic number */
jne err_bad_stage1_magic
mov %fs:0x02(%si), %cx /* offset 0x02: byte count for CRC */
xor %eax, %eax

7
stage1/Cargo.lock generated

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "stage1"
version = "0.1.0"

@ -0,0 +1,5 @@
[package]
name = "bussy-stage1"
edition = "2021"
version.workspace = true
repository.workspace = true

@ -0,0 +1,19 @@
use std::ffi::OsStr;
use std::path::Path;
fn main() {
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let ld_script_path = manifest_dir.join("stage1.ld");
println!("cargo:rustc-link-arg=--script={}", ld_script_path.display());
println!("cargo:rerun-if-changed={}", ld_script_path.display());
let asm_dir = manifest_dir.join("src").join("asm");
let files = asm_dir.read_dir().unwrap();
for entry in files {
let path = entry.unwrap().path();
if path.extension() == Some(OsStr::new("s")) {
println!("cargo:rerun-if-changed={}", path.display());
}
}
}

@ -0,0 +1,19 @@
/*
* This is the first file to be included in mod.rs,
* which exposes its contents to all following files
*/
.macro LOCAL name, type=function
.type \name , @\type
\name :
.endm
.macro GLOBL name, type=function
.global \name
.type \name , %\type
\name :
.endm
.macro END name
.size \name , . - \name
.endm

@ -0,0 +1,57 @@
/*
* This sits at the very beginning of the stage1 image, which in turn is
* located at the beginning of the bussy boot partition. stage0 always reads
* the first 32 K of that partition to 0x0500, validates the magic number and
* checksum, and then jumps to the entry point at 0x0510.
*
* ATTENTION: if you change the structure of this header, you must
* also change the (hardcoded) offsets in stage0.s and build.py!
*/
.extern _stage1_start /* stage1.ld */
.extern _stage1_end /* stage1.ld */
.section .header, "awx"
.code16
/*
* offset 0x00 (loaded at 0x0500)
* stage1 magic number. stage0 checks this.
*/
GLOBL _stage1_magic, object
.word 0xacab
END _stage1_magic
/*
* offset 0x02 (loaded at 0x0502)
* Length of the entire stage1 image in bytes, excluding bss.
* Hardcoded during image build. Must not exceed 32 K.
*/
GLOBL _stage1_len, object
.word 0x8000
END _stage1_len
/*
* offset 0x04 (loaded at 0x0504)
* CRC32 (polynomial 0x04c11db7) checksum of the entire stage1 image
* as defined by the length field at offset 0x02. Must be zeroed for
* checksum calculation. stage0 checks AND CLEARS this.
* Hardcoded during image build.
*/
GLOBL _stage1_csum, object
.long 0
END _stage1_csum
/*
* offset 0x08 (loaded at 0x0508)
* Reserved; MUST be set to 0. stage0 ignores this.
*/
.quad 0
/*
* offset 0x10 (loaded at 0x0510)
* stage1 entry point. stage0 jumps here.
*/
GLOBL _start
1: jmp 1b
END _start

@ -0,0 +1,21 @@
macro_rules! include_asm {
($name:literal) => {
::core::arch::global_asm!(
::core::concat!(".file \"", $name, "\""), // for better debugging
::core::include_str!($name),
::core::concat!(".file \"", ::core::file!(), "\""),
options(raw, att_syntax),
);
};
}
// common macros for the other assembly files, keep at the beginning
include_asm!("common.s");
// stage1 header containing its magic, size, checksum, and entry point
include_asm!("header.s");
extern "C" {
pub static _stage1_magic: u16;
pub static _stage1_len: u16;
pub static _stage1_csum: u32;
}

@ -0,0 +1,21 @@
#![no_std]
#![no_main]
use core::arch::asm;
use core::panic::PanicInfo;
mod asm;
#[no_mangle]
pub extern "C" fn main() -> ! {
loop {}
}
#[panic_handler]
pub fn rust_panic(_info: &PanicInfo) -> ! {
loop {
unsafe {
asm!("cli", "hlt");
}
}
}

@ -0,0 +1,32 @@
OUTPUT_FORMAT(elf32-i386)
ENTRY(_start)
SECTIONS {
. = 0x0500;
_stage1_start = .;
.header : {
KEEP(*(.header))
}
.text : ALIGN(8) {
*(.text .text.*)
}
.data : ALIGN(8) {
*(.data .data.*)
}
.rodata : ALIGN(8) {
*(.rodata .rodata.*)
}
_stage1_end = .;
.bss(NOLOAD) : ALIGN(8) {
_bss_start = .;
*(.bss .bss.*)
_bss_end = .;
}
}
Loading…
Cancel
Save