summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2010-11-16 02:47:03 (GMT)
committerH. Peter Anvin <hpa@zytor.com>2010-11-16 02:47:03 (GMT)
commit0f8777accdba45d8ec2e04e5905e4900c7ec9c34 (patch)
tree6095b3ea0f6bc5a08f7e5fe788c8ac0066625bab
parent301f1527ddff9951eff92d64b1f43a6aa23b4d5f (diff)
downloadabc8000-old-0f8777accdba45d8ec2e04e5905e4900c7ec9c34.zip
abc8000-old-0f8777accdba45d8ec2e04e5905e4900c7ec9c34.tar.gz
abc8000-old-0f8777accdba45d8ec2e04e5905e4900c7ec9c34.tar.bz2
abc8000-old-0f8777accdba45d8ec2e04e5905e4900c7ec9c34.tar.xz
sysrom: define a relocatable executable format and use it
Define a simple relocatable format for executables, and make abc8000.sys follow that format. We still load at 64K, but that can now be changed as necessary.
-rw-r--r--data/sysrom/.gitignore1
-rw-r--r--data/sysrom/Makefile17
-rw-r--r--data/sysrom/abc/init.asm17
-rw-r--r--data/sysrom/abc8000.ld4
-rw-r--r--data/sysrom/exec.c127
-rwxr-xr-xdata/sysrom/genrel.pl141
-rw-r--r--data/sysrom/sdcard.c49
-rw-r--r--data/sysrom/sysrom.h4
8 files changed, 286 insertions, 74 deletions
diff --git a/data/sysrom/.gitignore b/data/sysrom/.gitignore
index aca1f58..d33297e 100644
--- a/data/sysrom/.gitignore
+++ b/data/sysrom/.gitignore
@@ -1,6 +1,7 @@
*.bin
*.elf
*.map
+*.shr
*.sys
*.i
*.o
diff --git a/data/sysrom/Makefile b/data/sysrom/Makefile
index 831a344..09f7f98 100644
--- a/data/sysrom/Makefile
+++ b/data/sysrom/Makefile
@@ -7,6 +7,7 @@ STRIP = m68k-none-elf-strip
OBJCOPY = m68k-none-elf-objcopy
OBJDUMP = m68k-none-elf-objdump
RANLIB = m68k-none-elf-ranlib
+READELF = m68k-none-elf-readelf
PERL = perl
INCLUDE = -I./include -I./fat/src
@@ -19,7 +20,7 @@ CFLAGS = -m68000 -O2 -fomit-frame-pointer -ffreestanding \
$(INCLUDE) $(CCWARN)
LIBGCC := '$(shell $(CC) $(CFLAGS) -print-libgcc-file-name)'
-LDFLAGS =
+LDFLAGS = --emit-relocs
SYSOBJS = $(patsubst %.asm,%.o,$(wildcard *.asm)) \
$(patsubst %.c,%.o,$(wildcard *.c))
@@ -48,9 +49,8 @@ sysrom.elf: $(SYSOBJS) $(LIB) sysrom.ld
abc8000.elf: $(ABCOBJS) $(LIB) abc8000.ld
$(LD) $(LDFLAGS) -T abc8000.ld -o $@ $(ABCOBJS) $(LIB) $(LIBGCC)
-abc8000.sys: abc8000.elf
- $(OBJCOPY) -O binary $< $@
- $(PERL) padto.pl $@ 512
+abc8000.sys: abc8000.bin abc8000.shr genrel.pl
+ $(PERL) genrel.pl abc8000.bin abc8000.shr $@
$(LIB): $(LIBOBJS)
rm -f $@
@@ -77,10 +77,15 @@ MAKEDEPS = -Wp,-MT,$@,-MD,$(dir $@).$(notdir $@).d
$(CC) $(MAKEDEPS) $(CFLAGS) -D__ASSEMBLY__ \
-x assembler-with-cpp -E -o $@ $<
+%.shr: %.elf
+ $(READELF) -WShr $< > $@ || ( rm -f $@ ; false )
+%.bin: %.elf
+ $(OBJCOPY) -O binary $< $@
+
clean:
for d in . abc font lib fat/src; do \
- rm -f $$d/*.o $$d/*.i $$d/*.s $$d/*.bin $$d/*.map ; \
- rm -f $$d/*.elf $$d/*.a $$d/.*.d ; \
+ rm -f $$d/*.o $$d/*.i $$d/*.s $$d/*.bin $$d/*.map \
+ $$d/*.sys $$d/*.shr $$d/*.elf $$d/*.a $$d/.*.d ; \
done
rm -f font/sysfont.c
diff --git a/data/sysrom/abc/init.asm b/data/sysrom/abc/init.asm
index 33eaf0e..b080ed1 100644
--- a/data/sysrom/abc/init.asm
+++ b/data/sysrom/abc/init.asm
@@ -3,7 +3,7 @@
*/
#include <ioreg.h>
- .section ".init","ax"
+ .text
.globl _start
_start:
/* Show light on the LEDs */
@@ -22,21 +22,6 @@ _start:
bra 1b
2:
- /* Clear the BSS */
- clr.l %d0
- move.l #__bss_start, %a0
- move.w #__bss_clear_count - 1, %d1
-bss_clear_loop:
- move.l %d0, (%a0)+
- move.l %d0, (%a0)+
- move.l %d0, (%a0)+
- move.l %d0, (%a0)+
- move.l %d0, (%a0)+
- move.l %d0, (%a0)+
- move.l %d0, (%a0)+
- move.l %d0, (%a0)+
- dbf %d1, bss_clear_loop
-
jmp (main)
.section ".rodata","a"
diff --git a/data/sysrom/abc8000.ld b/data/sysrom/abc8000.ld
index c2c7cc9..75712e5 100644
--- a/data/sysrom/abc8000.ld
+++ b/data/sysrom/abc8000.ld
@@ -4,9 +4,9 @@ ENTRY(_start)
SECTIONS
{
/*
- * This is where we get loaded by the firmware
+ * Offset zero before relocation
*/
- . = 0x10000;
+ . = 0;
.init : {
*(.init)
} = 0x4e754e75
diff --git a/data/sysrom/exec.c b/data/sysrom/exec.c
new file mode 100644
index 0000000..f5d94a0
--- /dev/null
+++ b/data/sysrom/exec.c
@@ -0,0 +1,127 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010 H. Peter Anvin - All Rights Reserved
+ *
+ * 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, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * exec.c
+ *
+ * Run an executable
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <ioreg.h>
+#include "sysrom.h"
+#include "ff.h"
+
+#define EXEC_MAGIC 0x1ae475e6
+
+struct exec_header {
+ uint32_t magic;
+ uint32_t hdr_len;
+ uint32_t flags;
+ uint32_t entrypoint;
+ uint32_t totalsize;
+ uint32_t binsize;
+ uint32_t bsssize;
+ uint32_t nrelocs;
+};
+
+int exec_file(const char *filename, void *addr)
+{
+ FRESULT fr;
+ FIL file;
+ UINT bytesread;
+ struct exec_header hdr;
+ uint32_t nrel;
+ register const char *start asm("a1");
+
+ fr = f_open(&file, filename, FA_READ|FA_OPEN_EXISTING);
+ if (fr != FR_OK)
+ return fr;
+
+ fr = f_read(&file, &hdr, sizeof hdr, &bytesread);
+ if (fr != FR_OK || bytesread != sizeof hdr)
+ goto err;
+
+ fr = f_lseek(&file, hdr.hdr_len);
+ if (fr != FR_OK)
+ goto err;
+
+ if (hdr.magic != EXEC_MAGIC ||
+ (hdr.flags & 0xffff) || /* Incompatible flags */
+ hdr.binsize + hdr.bsssize > hdr.totalsize)
+ goto err;
+
+ fr = f_read(&file, addr, hdr.binsize, &bytesread);
+ if (fr != FR_OK || bytesread != hdr.binsize)
+ goto err;
+
+ /* Zero the BSS */
+ memset((char *)addr + hdr.binsize, 0, hdr.bsssize);
+
+ /* Process relocations */
+ nrel = hdr.nrelocs;
+ while (nrel) {
+ size_t reloc_buf[128];
+ size_t *relp = reloc_buf;
+ unsigned int xrel = (nrel < 128) ? nrel : 128;
+ unsigned int bytes = xrel * sizeof(size_t);
+
+ nrel -= xrel;
+
+ fr = f_read(&file, reloc_buf, bytes, &bytesread);
+ if (fr != FR_OK || bytesread != bytes)
+ goto err;
+
+ while (xrel--) {
+ uint32_t rel = *relp++;
+ if (rel + 4 > hdr.totalsize || (rel & 1))
+ goto err;
+ *(size_t *)((char *)addr + rel) += (size_t)addr;
+ }
+ }
+
+ f_close(&file);
+
+ start = (const char *)addr + hdr.entrypoint;
+ asm volatile("jsr (%0)\n"
+ : "+a" (start)
+ :
+ : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+ "a0", "a2", "a3", "a4", "a5", "a6",
+ "cc", "memory");
+ return 0;
+
+err:
+ f_close(&file);
+ return fr;
+}
+
+/*
+ * Try to load abc8000.sys, and run it if it exists
+ */
+static FATFS sd_fs;
+
+#define BOOT_ADDR 0x10000
+
+void disk_boot(void)
+{
+ static const char boot_filename[] = "abc8000.sys";
+
+ printf("Mounting SD card...\n");
+ f_mount(0, &sd_fs);
+
+ printf("Running boot file...\n");
+ exec_file(boot_filename, (void *)BOOT_ADDR);
+}
diff --git a/data/sysrom/genrel.pl b/data/sysrom/genrel.pl
new file mode 100755
index 0000000..b4b6b3a
--- /dev/null
+++ b/data/sysrom/genrel.pl
@@ -0,0 +1,141 @@
+#!/usr/bin/perl
+
+use bytes;
+
+($binfile, $shrfile, $out) = @ARGV;
+
+if (!defined($out)) {
+ die "Usage: $0 binfile Shrfile output\n";
+}
+
+open(BINFILE, '<', $binfile)
+ or die "$0: $binfile: $!\n";
+open(SHRFILE, '<', $shrfile)
+ or die "$0: $shrfile: $!\n";
+open(OUT, '>' , $out)
+ or die "$0: $out: $!\n";
+
+$binsize = (stat(BINFILE))[7];
+
+#
+# First, read the section header information
+#
+$entrypoint = 0;
+while (defined($line = <SHRFILE>)) {
+ if ($line =~ /^\s*Entry point address:\s*0x([0-9a-f]+)"/) {
+ $entrypoint = hex $1;
+ }
+ last if ($line =~ /^Section Headers/);
+}
+
+scalar <SHRFILE>; # Skip header
+
+$totalsize = 0;
+while (defined($line = <SHRFILE>)) {
+ ($nr, $name, $type, $addr, $off, $size, $es, $flg, $lk, $inf, $al) =
+ ($line =~ /^\s*\[\s*([0-9]+)\]\s(\S*)\s+(\S+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+([A-Z]*)\s*([0-9]+)\s+([0-9]+)\s+([0-9]+)/);
+ last unless (defined($al));
+
+ $addr = hex $addr;
+ $off = hex $off;
+ $size = hex $size;
+
+ $nr += 0;
+ $lk += 0;
+ $inf += 0;
+ $al += 0;
+
+ print "$nr $name $type $addr $off $size $es $flg $lk $inf $al\n";
+
+ $sec_nr{$name} = $nr;
+ $sec[$nr] = [$name, $type, $addr, $off, $size, $es, $flg, $lk, $inf, $al];
+
+ if ($flg =~ /A/) {
+ if ($addr + $size > $totalsize) {
+ $totalsize = $addr + $size;
+ }
+ }
+}
+
+if ($binsize > $totalsize) {
+ die "$0: binary size > total size\n";
+}
+
+#
+# Now actually parse relocations
+#
+undef $base;
+$relocs = '';
+$nrelocs = 0;
+while (defined($line = <SHRFILE>)) {
+ chomp $line;
+ if ($line =~ /^Relocation section '([^\']+)' /) {
+ $rs = $1; # Relocation section name
+ $as = ${$sec[$sec_nr{$rs}]}[8]; # Associated section (= real section)
+ if (!$as || !defined($sec[$as])) {
+ die "$0: cannot figure out base section for '$rs'\n";
+ }
+ if (${$sec[$as]}[6] =~ /A/) {
+ $base = ${$sec[$as]}[2]; # Base address of this section
+ } else {
+ undef $base; # Non-manifest section, ignore
+ }
+ } elsif (defined($base) &&
+ $line =~ /^([0-9a-f]+)\s+([0-9a-f]+)\s+(\S+)\s+([0-9a-f]+)/) {
+ $offset = hex $1;
+ $info = hex $2;
+ $type = $3;
+ $symval = hex $4;
+
+ if ($type ne 'R_68K_32') {
+ die "$0: unknown relocation: $line\n";
+ }
+ $addr = $base + $offset;
+
+ if ($addr+3 >= $totalsize) {
+ die "$0: relocation outside the file\n";
+ }
+ $relocs .= pack("N", $base + $offset);
+ $nrelocs++;
+ }
+}
+close(SHRFILE);
+
+#
+# Write executable header
+#
+
+# Pad the sizes to a multiple of 32
+$binsize = ($binsize + 31) & ~31;
+$totalsize = ($totalsize + 31) & ~31;
+$bsssize = $totalsize - $binsize;
+
+print OUT pack("N*",
+ 0x1ae475e6, # Magic number
+ 512, # Header length
+ 0, # Flags
+ $entrypoint, # Entry point
+ $totalsize, # Memory allocation size
+ $binsize, # Binary data size
+ $bsssize, # Size to be zeroed
+ $nrelocs); # Relocation count
+print OUT "\0" x (512 - 8*4);
+
+#
+# Copy the binary data
+#
+$raw_binsize = 0;
+while (read(BINFILE, $bindata, 4096) > 0) {
+ print OUT $bindata;
+ $raw_binsize += length($bindata);
+}
+close(BINFILE);
+
+#
+# Output the relocations
+#
+print OUT $relocs;
+
+exit 0;
+
+
diff --git a/data/sysrom/sdcard.c b/data/sysrom/sdcard.c
index 868e861..b2d6d5d 100644
--- a/data/sysrom/sdcard.c
+++ b/data/sysrom/sdcard.c
@@ -650,52 +650,3 @@ DSTATUS disk_status(BYTE drive)
return sdc.status;
}
-
-/*
- * Try to load abc8000.sys, and run it if it exists
- */
-static FATFS sd_fs;
-
-#define BOOT_ADDR 0x10000
-
-void disk_boot(void)
-{
- static const char boot_filename[] = "abc8000.sys";
- FRESULT fr;
- FIL file;
- UINT bytesread;
- uint32_t csum;
- const uint32_t *csump;
- unsigned int size, i;
-
- printf("Mounting SD card...\n");
- f_mount(0, &sd_fs);
-
- printf("Opening boot file...\n");
- fr = f_open(&file, boot_filename, FA_READ|FA_OPEN_EXISTING);
- if (fr != FR_OK)
- return;
-
- printf("Reading boot file...\n");
- size = file.fsize;
- fr = f_read(&file, (void *)BOOT_ADDR, size, &bytesread);
- f_close(&file);
-
- if (fr != FR_OK || bytesread != size)
- return;
-
- csum = 0;
- csump = (const uint32_t *)BOOT_ADDR;
- for (i = 0; i < size; i += 4)
- csum += *csump++;
-
- printf("Boot file checksum: 0x%08x\n", csum);
-
- printf("Jumping to boot file...\n");
-
- asm volatile("jsr %0\n"
- : : "m" (*(const char *)BOOT_ADDR)
- : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
- "a0", "a1", "a2", "a3", "a4", "a5", "a6",
- "cc", "memory");
-}
diff --git a/data/sysrom/sysrom.h b/data/sysrom/sysrom.h
index 1e0a1c4..ac90f31 100644
--- a/data/sysrom/sysrom.h
+++ b/data/sysrom/sysrom.h
@@ -15,8 +15,10 @@ void monitor(void);
__noreturn die(void);
void __spurious_irq(void);
-void disk_boot(void);
int sdcard_read_sectors(void *buf, uint32_t lba, int count);
int sdcard_write_sectors(const void *buf, uint32_t lba, int count);
+int exec_file(const char *filename, void *addr);
+void disk_boot(void);
+
#endif /* SYSROM_H */