From 6819e313c8d799ab4f54feb2cbb6f3c1d91a07ea Mon Sep 17 00:00:00 2001 From: pjht Date: Tue, 19 Mar 2024 09:23:21 -0500 Subject: [PATCH] Initial commit --- Tupfile | 7 ++ cards.68k | 51 ++++++++++++ cards.i | 7 ++ init.68k | 29 +++++++ initrd.68k | 155 ++++++++++++++++++++++++++++++++++++ initrd.i | 17 ++++ os.dsk | 0 proglink.ld | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 488 insertions(+) create mode 100644 Tupfile create mode 100644 cards.68k create mode 100644 cards.i create mode 100644 init.68k create mode 100644 initrd.68k create mode 100644 initrd.i create mode 100644 os.dsk create mode 100644 proglink.ld diff --git a/Tupfile b/Tupfile new file mode 100644 index 0000000..23bb6a6 --- /dev/null +++ b/Tupfile @@ -0,0 +1,7 @@ +.gitignore + +LDFLAGS = -z max-page-size=4096 --orphan-handling=error -T proglink.ld +ASFLAGS = -m68010 -spaces -Felf -ldots -align -quiet -x -nowarn=62 + +: foreach *.68k | ../ |> vasmm68k_mot $(ASFLAGS) -I../sysroot/usr/include -o %o %f |> %B.o +: *.o | proglink.ld ../ |> m68k-elf-ld $(LDFLAGS) -o %o %f '%' |> init diff --git a/cards.68k b/cards.68k new file mode 100644 index 0000000..abd5bd3 --- /dev/null +++ b/cards.68k @@ -0,0 +1,51 @@ + include syscalls.i + section .text,text + public cards_init +cards_init: + move.l #$ffff0000, d0 + move.l #16, d1 + move.l #$2, d2 + jsr syscall_vmem_map_free_to + move.l a0, (io_space_start) + rts + +; 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 + public find_first_card +find_first_card: + move.l io_space_start, a0 ; a0 holds the address of the current card +ffc_loop: + lea ($100,a0), a0 ; Move to the next card + move.w ($fe,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 + +get_all_cards: +; Gets the indexes of the cards with the specified type +; a0 is a pointer to the buffer to store the results in +; d0 is the length of the buffer in 4 byte units +; d1 is the type of card to find + move.l io_space_start, a1 ; a0 holds the address of the current card +gac_loop: + lea ($100,a1), a1 ; Move to the next card + move.w ($fe,a1), d2 ; Load the type of the card into d1 + cmp.b d1, d2 ; Check whether the type of the current card is the type we want + bne.b gac_next ; Skip the card if it is not + move.l a1, (a0) ; Put the card base into the buffer + lea ($4,a0), a0 ; Move to the next buffer location + subq.w #1, d0 ; Decement the count of available buffer locations +gac_next: + cmpa.l #$ffff00, a1 ; Check if we have gone through all the cards + beq.b gac_done ; If so, return + cmpi.b #0, d0 ; Check if we have filled the buffer + beq.b gac_done ; If so, returm + bra.b gac_loop +gac_done: + rts + + section .bss,bss +io_space_start: ds.l 1 diff --git a/cards.i b/cards.i new file mode 100644 index 0000000..665d645 --- /dev/null +++ b/cards.i @@ -0,0 +1,7 @@ + ifnd CARDS_I +CARDS_I equ 1 + xref cards_init +; 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 + xref find_first_card + endif diff --git a/init.68k b/init.68k new file mode 100644 index 0000000..183e8c5 --- /dev/null +++ b/init.68k @@ -0,0 +1,29 @@ + include cards.i + include initrd.i + include syscalls.i + section .text,text + public _start +_start: + move.l #tmp_stack_top, a7 + ; set up a permanent stack + move.l #2, d0 + move.l #$2, d1 + jsr syscall_vmem_map_free + adda.l #(2*4096), a0 + move.l a0, a7 + move.l #msg, a0 + jsr syscall_println + jsr cards_init + jsr initrd_init + move.l #init_name, a0 + jsr initrd_find_file +dbg: + jsr syscall_exit + + section .data,data +msg: dc.b "Hello from init",0 +init_name: dc.b "init.elf",0 + + section .bss,bss +tmp_stack: ds.b 32 +tmp_stack_top: diff --git a/initrd.68k b/initrd.68k new file mode 100644 index 0000000..526f60a --- /dev/null +++ b/initrd.68k @@ -0,0 +1,155 @@ +STORAGE_SEC equ $0 +STORAGE_CNT equ $4 +STORAGE_CMD equ $8 +STORAGE_DMADR equ $C + + include cards.i + include memory.i + include string.i + section .text,text +; Initialize the initrd reader + public initrd_init +initrd_init: + move.w #$4, d0 ; Get the pointer to the MMU card + jsr find_first_card + move.l a0, storage_card_base + rts + +; Get the start byte for a specific file in the initrd +; Pointer to name in a0 +; Number returned in d0, or 0 if not found + public initrd_find_file +initrd_find_file: + movem.l d2/a2, -(a7) + move.l a0, a2 + move.l #512, d0 + jsr malloc + move.l a0, a1 + move.l #1, d0 +iff_loop: + movem.l d0/a0/a1, -(a7) + move.l storage_card_base, a0 + move.l #1, d1 + bsr.b read_sectors + movem.l (a7)+, d0/a0/a1 + move.l (a1), d2 + bne.b .1 + move.l #0, d0 + bra.b iff_done +.1: + ; File name at (12, a1) + ; Passed in name at a2 + movem.l d0/a0/a1, -(a7) + move.l a2, a0 + adda.l #12, a1 + jsr strcmp + movem.l (a7)+, d0/a0/a1 + bne.b .2 + addi.l #1, d0 + movem.l (a7)+, d2/a2 + lsl.l #8, d0 + lsl.l #1, d0 + rts +.2: + addi.l #1, d0 + move.l (4,a1), d2 + add.l d2, d0 + bra.b iff_loop +iff_done: + movem.l (a7)+, d2/a2 + rts + +; Reads bytes of a file from the initrd +; Start byte of file in d0 +; Offset in d1 +; Length in d2 +; Buffer in a0 + public initrd_read_bytes +initrd_read_bytes: + add.l d1, d0 + move.l d2, d1 + move.l a0, a1 + move.l storage_card_base, a0 + bra.b read_bytes + +; Reads sectors from a storage card +; Card base in a0 +; Destination in a1 +; Start sector in d0.l +; Sector count in d1.l +read_sectors: + cmpi.l #0, d1 + beq.b read_sectors_done + move.l d0, (STORAGE_SEC,a0) ; Set the sector number + move.l d1, (STORAGE_CNT,a0) ; Set the sector count + move.l a1, (STORAGE_DMADR,a0) ; Set the destination address + move.w #$1, (STORAGE_CMD,a0) ; Issue a DMA read command +read_sectors_done: + rts + +; Reads bytes off a storage card +; Card base in a0 +; Destination in a1 +; Start byte in d0.l +; Byte count in d1.l +read_bytes: + movem.l d2-d5/a2/a3,-(a7) ; Save callee preserved registers + move.l d0, d4 ; Save start byte in d4 + move.l d1, d5 ; Save byte count in d5 + move.l a1, a3 ; Save destination in a6 + lsr.l #8, d0 ; Divide start byte by 512 to compute starting sector + lsr.l #1, d0 + move.l d0, d3 ; Save the starting sector in d3 + move.l #1, d1 ; Read the starting sector into the sector buffer + move.l #sec_buf, a1 + bsr.b read_sectors + move.l a3, a2 ; Load the destination into a2 + move.l d4, d0 ; Load the start byte into d0 + andi.l #$1FF, d0 ; Modulus start byte by 512 to compute sector data offset + adda.l d0, a1 ; Add the offset to the start of the sector buffer + move.l #$200, d1 ; Compute the number of bytes to transfer by subtracting the offset from 512 + sub.l d0, d1 + cmp d5, d1 ; Compare the number of bytes to transfer with the byte count + ble.b count_ok ; If it was less than the byte count, do not adjust the bytes to transfer + move.l d5, d1 ; Otherwise, cap the transfer count to the total byte count +count_ok: + move.l d1, d4 ; Save the number of bytes in d4 + subi.l #1, d1 ; Subtract 1 from the number of bytes to account for the extra loop done by dbra +start_sec_loop: ; Transfer the required bytes from the start sector to the destination buffer + move.b (a1)+, (a2)+ + dbra d1, start_sec_loop + move.l d3, d0 ; Load the starting sector into d0 + addi #1, d0 ; Compute the start of the middle sectors by adding 1 to the starting sector + move.l d4, d2 ; Load the number of bytes transferred into d2 + move.l d5, d1 ; Load the byte count into d1 + sub.l d2, d1 ; Compute the number of remaining bytes by subtracting the number of transferred bytes from the byte count + cmpi.l #0, d1 ; If there are no more bytes to read, end early + beq.b read_bytes_done + move.l d1, d4 ; Save the number of remaining bytes in d4 + lsr.l #8, d1 ; Divide remaining bytes by 512 to compute the number of middle sectors + lsr.l #1, d1 + move.l a2, a1 ; Transfer the sector data to the end of the start sector bytes + bsr.b read_sectors ; Read the middle sectors + move.l d1, d3 ; Save the number of middle sectors in d3 + lsl.l #8, d1 ; Multiply the number of middle sectors by 512 to compute the number of bytes transferred + lsl.l #1, d1 + sub.l d1, d4 ; Subtract the number of transferred bytes from the number of remaining bytes + cmpi.l #0, d4 ; If there are no more bytes to read, end early + beq.b read_bytes_done + adda.l d1, a2 ; Add the number of bytes transferred to a2 + add.l d3, d0 ; Compute the end sector number by adding the start and count of the middle sectors + move.l #1, d1 ; Set the number of sectors to read to 1 + move.l #sec_buf, a1 ; Set the read address of the sector to the sector buffer + bsr.w read_sectors ; Read the end sector + move.l d4, d1 ; Load the number of remaining bytes into d1 +end_sec_loop: ; Transfer the required bytes from the start sector to the destination buffer + move.b (a1)+, (a2)+ + dbra d1, end_sec_loop +read_bytes_done: + movem.l (a7)+, d2-d5/a2/a3 ; Restore callee preserved registers + rts + + + section .bss,bss +storage_card_base: ds.b 4 +sec_buf: ds.b 512 diff --git a/initrd.i b/initrd.i new file mode 100644 index 0000000..b9379db --- /dev/null +++ b/initrd.i @@ -0,0 +1,17 @@ + ifnd INITRD_I +INITRD_I equ 1 +; Initialize the initrd reader + xref initrd_init + +; Get the start byte for a specific file in the initrd +; Pointer to name in a0 +; Number returned in d0, or 0 if not found + xref initrd_find_file + +; Reads bytes of a file from the initrd +; Start byte of file in d0 +; Offset in d1 +; Length in d2 +; Buffer in a0 + xref initrd_read_bytes + endif diff --git a/os.dsk b/os.dsk new file mode 100644 index 0000000..e69de29 diff --git a/proglink.ld b/proglink.ld new file mode 100644 index 0000000..c495430 --- /dev/null +++ b/proglink.ld @@ -0,0 +1,222 @@ +/* Script for -z combreloc */ +/* Copyright (C) 2014-2023 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.*) } + .sframe : ONLY_IF_RO { *(.sframe) *(.sframe.*) } + .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.*) } + .sframe : ONLY_IF_RW { *(.sframe) *(.sframe.*) } + .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 (INFO) : { *(.comment); LINKER_VERSION; } + .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_*) } +}