First pass at bootloader

This commit is contained in:
pjht 2022-10-08 17:55:21 -05:00
parent cd3ef5abc7
commit 457fefb19f
14 changed files with 350 additions and 18 deletions

View File

@ -1 +1,8 @@
.gitignore
include_rules
export CARGO_HOME
export RUSTUP_HOME
: initrd_maker.rs |> rustc -C debuginfo=0 -C opt-level=3 --edition 2021 --crate-name initrd_maker -o %o %f |> bin/initrd_maker
: kernel/kernel.elf *.elf | bin/initrd_maker |> bin/initrd_maker %f |> initrd
: boot/boot.bin initrd |> cat %f > %o |> os.dsk

5
Tuprules.tup Normal file
View File

@ -0,0 +1,5 @@
.gitignore
LDFLAGS = -z max-page-size=1
!as = |> m68k-elf-as $(ASFLAGS) -o %o %f |> %B.o
!ld = |> m68k-elf-ld $(LDFLAGS) -o %o %f |>

Binary file not shown.

6
boot/Tupfile Normal file
View File

@ -0,0 +1,6 @@
include_rules
LDFLAGS += -T boot.ld
: foreach *.68k |> !as |>
: *.o | boot.ld |> !ld |> boot.elf
: boot.elf |> m68k-elf-objcopy -O binary %f %o |> boot.bin

77
boot/boot.68k Normal file
View File

@ -0,0 +1,77 @@
.global _start
_start:
move.b #0x4, %d0
bsr.w find_first_card
| Load the header sector for the kernel binary
move.l #0x1, (%a0) | Set the sector number to 1
| Transfer 0x100 (256) bytes from the storage card's data register to 0x100
move.w #0x100, %a1 | Load a1, the destination address register, with 0x100
move.w #0xFF, %d0 | Load d0 with the sector size - 1.
hdr_sector_loop:
move.b (4, %a0), (%a1)+ | Transfer a byte of sector data to the destination
dbra %d0, hdr_sector_loop | Loop back if there is more to transfer
move.w (0x102), %d0 | Load d0 with the number of sectors for the kernel - 1
subq #0x1, %d0
| load the ELF kernel binary off the disk
move.l #0x2, (%a0) | Set the sector number to 2
| Transfer 0x100 (256) * d0 bytes from the storage card's data register to 0xA000
move.l #0xA000, %a1 | Load a1, the destination address register, with 0xA000
sectors_loop:
move.w #0xFF, %d1 | Load d0 with the sector size - 1.
sector_loop:
move.b (4, %a0), (%a1)+ | Transfer a byte of sector data to the destination
dbra %d1, sector_loop | Loop back if there is more to transfer
dbra %d0, sectors_loop | Loop back if there are more sectors to transfer
move.l (0xA01C), %d0 | Load the offset of the program headers in the file
move.l #0xA000, %a0 | Put the address of the program headers in a0
adda.w %d0, %a0
move.w (0xA02C), %d0 | Put the number of program headers - 1 in d0
subq #0x1, %d0
phead_loop:
move.l (%a0), %d1 | If the type of the program header isn't 1 (LOAD), skip the header
cmpi.l #0x1, %d1
bne.b next_seg
| Zero the destination memory of the program header
move.l (20, %a0), %d1 | Put the memory size of the program header - 1 in d1
subq #0x1, %d1
move.l (8, %a0), %a1 | Put the starting memory address of the program header in a1
zero_loop:
move.b #0, (%a1)+ | Zero a byte of the destination memory
dbra %d1, zero_loop | Loop back if there is more to zero
| Copy the data of the program header from the loaded file into position
move.l (16, %a0), %d1 | Put the file size of the program header - 1 in d1
subq #0x1, %d1
move.l (4, %a0), %a1 | Put the address of the start of the loaded program header's data in a1
adda.l #0xA000, %a1
move.l (8, %a0), %a2 | Put the starting memory address of the program header in a2
load_loop:
move.b (%a1)+, (%a2)+ | Copy a byte of data into position
dbra %d1, load_loop | Loop back if there is more to copy
next_seg:
lea (0x20, %a0), %a0 | Advance a0 to point to the next program header
dbra %d0, phead_loop | If there are more program headers, loop back
move.l (0xA018), %a0 | Load the entry point of the program into a0
jmp (%a0) | Jump to the entry point of the program
| Finds the first card with the type in d0.b, and returns it's IO base address in a0, or 0 if not found
| Clobbers d1
find_first_card:
move.l #0xff0000, %a0 | a0 holds the address of the current card
ffc_loop:
lea (0x100, %a0), %a0 | adda.l #$100, %a0 | Move to the next card
move.b (0xff, %a0), %d1 | Load the type of the card into d1
beq.b ffc_done | If the type is 0 (empty slot), we have scanned all cards, so exit the loop
cmp.b %d0, %d1 | If the card is the type we want, return with the address in a0
beq.b ffc_done
bra.b ffc_loop | Loop back and check the next card
ffc_done:
rts
.if . != 256
.org 255
.byte 0
.endif

5
boot/boot.ld Normal file
View File

@ -0,0 +1,5 @@
SECTIONS {
. = 0x0;
_etext = .;
.text : { *(.text) }
}

8
config.yaml Normal file
View File

@ -0,0 +1,8 @@
---
cards:
- type: rom
image: rom.bin
- type: ram
size: 65536
- type: storage
disk: os.dsk

View File

@ -22,11 +22,11 @@ fn main() {
.expect("File size greater than 64 KiB");
let file_num_blocks = (length / BLOCK_SIZE) + if length % BLOCK_SIZE != 0 { 1 } else { 0 };
let mut header_block = Vec::new();
header_block.extend_from_slice(&length.to_be_bytes());
header_block.extend_from_slice(&file_num_blocks.to_be_bytes());
header_block.push(file_name_len);
header_block.extend_from_slice(file_name.to_str().unwrap().as_bytes());
header_block.push(0);
header_block.extend_from_slice(&length.to_le_bytes());
header_block.extend_from_slice(&file_num_blocks.to_le_bytes());
header_block.resize(BLOCK_SIZE as usize, 0);
archive
.write_all(&header_block)

View File

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

View File

@ -1,8 +0,0 @@
[package]
name = "initrd_maker"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

5
kernel/Tupfile Normal file
View File

@ -0,0 +1,5 @@
include_rules
LDFLAGS += -T kernel.ld
: foreach *.68k |> !as |>
: *.o |> !ld |> kernel.elf

220
kernel/kernel.ld Normal file
View File

@ -0,0 +1,220 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2022 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf32-m68k", "elf32-m68k",
"elf32-m68k")
OUTPUT_ARCH(m68k)
ENTRY(_start)
SEARCH_DIR("/usr/m68k-elf/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x1000)); . = SEGMENT_START("text-segment", 0x1000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
.rela.plt :
{
*(.rela.plt)
}
.init :
{
KEEP (*(SORT_NONE(.init)))
} =0x4e714e71
.plt : { *(.plt) }
.iplt : { *(.iplt) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(SORT(.text.sorted.*))
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
} =0x4e714e71
.fini :
{
KEEP (*(SORT_NONE(.fini)))
} =0x4e714e71
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
/* Thread Local Storage sections */
.tdata :
{
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
. = DATA_SEGMENT_RELRO_END (0, .);
.got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we do not
pad the .data section. */
. = ALIGN(. != 0 ? 32 / 8 : 1);
}
. = ALIGN(32 / 8);
. = SEGMENT_START("ldata-segment", .);
. = ALIGN(32 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1. */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions. */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2. */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2. */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions. */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3. */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF 5. */
.debug_addr 0 : { *(.debug_addr) }
.debug_line_str 0 : { *(.debug_line_str) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_macro 0 : { *(.debug_macro) }
.debug_names 0 : { *(.debug_names) }
.debug_rnglists 0 : { *(.debug_rnglists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.debug_sup 0 : { *(.debug_sup) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}

14
kernel/main.68k Normal file
View File

@ -0,0 +1,14 @@
.global _start
_start:
lea src, %a0
move.w (%a0), %d0
move.w (0x2, %a0), %d1
addi.l #0x56947208, (0x4, %a0)
stop #0x2700
.data
src:
.word 0xAA55
.word 0x55AA
.word 0xBB66

BIN
rom.bin Normal file

Binary file not shown.