From 04ed743042ce62ea481d13e54c68e24bdd8ba924 Mon Sep 17 00:00:00 2001 From: Bas Wijnen Date: Sun, 22 Aug 2010 22:03:06 +0200 Subject: [PATCH] booting from nand works --- init.config | 62 ++++---- invoke.ccp | 2 + iris.hhp | 10 +- kernel.hhp | 1 + mips/arch.hhp | 1 + mips/boot.S | 18 +-- mips/nand.hhp | 298 ++++++++++++++++++++++++++++++++++++ mips/nanonote/Makefile.arch | 66 ++++---- mips/nanonote/board.ccp | 20 ++- mips/nanonote/nand-boot.ccp | 233 ++++++++++------------------ mips/start.S | 64 ++++++-- panic.ccp | 1 + source/nand.ccp | 269 ++++---------------------------- 13 files changed, 564 insertions(+), 481 deletions(-) create mode 100644 mips/nand.hhp diff --git a/init.config b/init.config index e61f434..c77e59d 100644 --- a/init.config +++ b/init.config @@ -1,46 +1,52 @@ # driver = '' load a file into memory to be run priviledged. # program = '' load a file into memory to be run normally. - #driver driver_lcd = "lcd.elf" - #driver driver_buzzer = "buzzer.elf" - driver driver_gpio = "gpio.elf" - #program alarm = "alarm.elf" - #program gui = "gui.elf" - driver nand = "nand.elf" - #driver sdmmc = "sd+mmc.elf" - #program partition = "partition.elf" - #program fat = "fat.elf" - #program test = "test.elf" - #driver rtc = "rtc.elf" - # receive / [, ] = prepare to accept a capability from a named program. - #receive driver_lcd / Display = display - #receive driver_lcd / Setting = display_bright - #receive driver_buzzer / Buzzer = buzzer + # sysreq use a capability as the system request keyboard. + # give / [, ] = give this capability to this program when it requests it. + # include include a file as another config file. + # at end of file, the initial threads are killed and the drivers and programs are run as soon as all their dependencies are provided. + + driver driver_gpio = "gpio.elf" receive driver_gpio / Keyboard , 0 = keyboard receive driver_gpio / Keyboard , 1 = sysreq receive driver_gpio / Event = sdmmc_gpio - #receive alarm / UI = ui - #receive sdmmc / WString = sdmmc - #receive partition / WString, 0 = p0 - #receive partition / WString, 1 = p1 - #receive partition / WString, 2 = p2 - #receive partition / WString, 3 = p3 - #receive fat / Directory = root - - # sysreq use a capability as the system request keyboard. sysreq sysreq - # give / [, ] = give this capability to this program when it requests it. + driver nand = "nand.elf" + + #driver driver_lcd = "lcd.elf" + #receive driver_lcd / Display = display + #receive driver_lcd / Setting = display_bright + + #driver driver_buzzer = "buzzer.elf" + #receive driver_buzzer / Buzzer = buzzer + + #program alarm = "alarm.elf" + #receive alarm / UI = ui + + #program gui = "gui.elf" #give gui / UI = ui #give gui / Display = display #give gui / Setting = display_bright #give gui / Buzzer = buzzer #give gui / Keyboard = keyboard + + #driver sdmmc = "sd+mmc.elf" + #receive sdmmc / WString = sdmmc #give sdmmc / Event = sdmmc_gpio + + #program partition = "partition.elf" + #receive partition / WString, 0 = p0 + #receive partition / WString, 1 = p1 + #receive partition / WString, 2 = p2 + #receive partition / WString, 3 = p3 #give partition / WString = sdmmc + + #program fat = "fat.elf" + #receive fat / Directory = root #give fat / WString = p0 + + #program test = "test.elf" #give test / Directory = root - # include include a file as another config file. - - # at end of file, the initial threads are killed and the drivers and programs are run as soon as all their dependencies are provided. + #driver rtc = "rtc.elf" diff --git a/invoke.ccp b/invoke.ccp index 48bcd31..fac4df2 100644 --- a/invoke.ccp +++ b/invoke.ccp @@ -558,6 +558,8 @@ static void thread_invoke (unsigned cmd, unsigned target, Iris::Num protected_da arch_reboot () case Iris::Thread::PRIV_POWEROFF & REQUEST_MASK: arch_poweroff () + case Iris::Thread::PRIV_BOOT & REQUEST_MASK: + arch_boot (c->data[1].l) case Iris::Thread::PRIV_PANIC & REQUEST_MASK: if c->data[1].l == 0xdeaddead: dbg_code.l = 1 diff --git a/iris.hhp b/iris.hhp index 704cd5f..637b72f 100644 --- a/iris.hhp +++ b/iris.hhp @@ -323,6 +323,7 @@ namespace Iris: DBG_SEND PRIV_REBOOT PRIV_POWEROFF + PRIV_BOOT PRIV_PANIC // These get/set_info are not arch-specific. enum info_type: @@ -581,6 +582,8 @@ namespace Iris: my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REBOOT) inline void poweroff (): my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_POWEROFF) + inline void boot (unsigned address): + my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_BOOT, address) void Receiver::sleep (unsigned value): set_alarm (value) @@ -612,7 +615,6 @@ static void kdebug_num (unsigned n, unsigned digits = 8): namespace Iris: inline void panic (unsigned code, char const *message = NULL): if message: - kdebug ("**********************************************************************\n") kdebug_num (code) kdebug_char ('\n') kdebug (message) @@ -626,15 +628,15 @@ namespace Iris: inline void debug_num (unsigned num, unsigned base): char const *encode = "0123456789abcdef" unsigned digits = 1 - unsigned power = base - while power <= num: + unsigned power = 1 + while power <= num / base: power *= base ++digits for unsigned i = 0; i < digits; ++i: - power /= base unsigned d = num / power kdebug_char (encode[d]) num -= d * power + power /= base inline void debug (const char *f, ...): unsigned *last = (unsigned *)&f diff --git a/kernel.hhp b/kernel.hhp index 1b786b9..ba2d538 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -323,6 +323,7 @@ void kPage_arch_update_mapping (kPage *page) void arch_register_interrupt (unsigned num, kReceiverP r) void arch_reboot () void arch_poweroff () +void arch_boot (unsigned address) void arch_uncache_page (unsigned page) #define assert(x) do { if (!(x)) panic (__LINE__, "assertion failed"); } while (0) diff --git a/mips/arch.hhp b/mips/arch.hhp index abd86be..2169e79 100644 --- a/mips/arch.hhp +++ b/mips/arch.hhp @@ -88,6 +88,7 @@ #ifndef ASM void flush_tlb (unsigned asid) +void arch_flush_cache () struct kThread_arch: unsigned at, v[2], a[4], t[10], s[8], gp, fp, ra, hi, lo, k[2] diff --git a/mips/boot.S b/mips/boot.S index 75ef15d..1ccfaf9 100644 --- a/mips/boot.S +++ b/mips/boot.S @@ -25,8 +25,6 @@ .globl __start .set noreorder -// Note that this code starts at 0xa0000000, even though it is linked for -// 0x80000000. This means that until the jump below, it must be PIC. __start: bal 1f // For some reason the disassembler considers everything @@ -36,14 +34,15 @@ start_hack_for_disassembler: .word _gp 1: lw $gp, 0($ra) - la $sp, kernel_stack + KERNEL_STACK_SIZE - // Flush cache. + mtc0 $zero, $CP0_TAG_LO lui $v1, 0x8000 ori $v0, $v1, 0x8000 1: + // i-cache index invalidate. cache 0, 0($v1) - cache 1, 0($v1) + // d-cache store tag. TagLo has the valid bit cleared, so this clears the d-cache. + cache 9, 0($v1) bne $v1, $v0, 1b addiu $v1, $v1, 32 @@ -51,19 +50,14 @@ start_hack_for_disassembler: li $k0, 0x3 mtc0 $k0, $CP0_CONFIG, 0 - // Jump into cached code. - la $t9, 1f - jr $t9 - nop -1: - // From here, the code no longer needs to be PIC. + la $sp, kernel_stack + KERNEL_STACK_SIZE // Clear .bss la $a0, _edata la $a1, _end 1: sw $zero, 0($a0) bne $a1, $a0, 1b - addu $a0, 4 + addiu $a0, 4 // First argument is the memory size. la $t9, init diff --git a/mips/nand.hhp b/mips/nand.hhp new file mode 100644 index 0000000..35f1ff6 --- /dev/null +++ b/mips/nand.hhp @@ -0,0 +1,298 @@ +#pypp 0 +// Iris: micro-kernel for a capability-based operating system. +// mips/nand.hhp: NAND driver functions, split off to be used in two places. +// The functions are not inline, so this file must be included exactly once per executable that needs it. +// Copyright 2009 Bas Wijnen +// +// 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 . + +// The following defines are taken from mtd/nand.h in the Linux source. +// Everything not in the nand datasheet is thrown out. + +// Standard NAND flash commands +#define CMD_READ0 0 +#define CMD_READSTART 0x30 + +#define CMD_READID 0x90 + +#define CMD_RESET 0xff + +#define CMD_SEQIN 0x80 +#define CMD_PAGEPROG 0x10 + +#define CMD_ERASE1 0x60 +#define CMD_ERASE2 0xd0 + +#define CMD_RNDIN 0x85 + +#define CMD_RNDOUT 5 +#define CMD_RNDOUTSTART 0xe0 + +#define CMD_STATUS 0x70 + +// Status bits +#define STATUS_FAIL 0x01 +#define STATUS_READY 0x40 +#define STATUS_WRITABLE 0x80 + +static volatile char *command +static volatile char *address +static volatile char *data + +static unsigned page_bits +static unsigned redundant_bits +static unsigned block_bits +static unsigned word_size + +static void unbusy (): + while !(gpio_get_port (2) & (1 << 30)): + DELAY () + +static void addr (unsigned d): + unbusy () + *address = d + +static void cmd (unsigned d): + unbusy () + *command = d + +static void wdata (unsigned d): + unbusy () + *data = d + +static unsigned rdata (): + unbusy () + unsigned ret = *data + return ret + +static void reset (): + // Set up. + gpio_as_nand () + EMC_NFCSR = EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1 + + // Reset nand. + cmd (CMD_RESET) + + cmd (CMD_READID) + addr (0) + unsigned d = rdata () + //unsigned maker = d + d = rdata () + //unsigned device = d + d = rdata () + //unsigned internal_chip_number = 1 << (d & 0x3) + //unsigned cell_type = 2 << ((d >> 2) & 0x3) + //unsigned simultaneously_programmed_pages = 1 << ((d >> 4) & 0x3) + //bool can_interleave_program_between_chips = d & 0x40 + //bool can_cache_program = d & 0x80 + d = rdata () + page_bits = 10 + (d & 3) + debug ("page bits: %d\n", page_bits) + redundant_bits = (d & 4 ? 4 : 3) + debug ("redundant bits: %d\n", redundant_bits) + block_bits = 16 + ((d >> 4) & 3) + debug ("block bits: %d\n", block_bits) + word_size = (d & 0x40 ? 16 : 8) + debug ("word size: %d\n", word_size) + //unsigned serial_access_minimum = (d & 0x80 ? 25 : 50) + d = rdata () + //unsigned num_planes = 1 << ((d >> 2) & 3) + //unsigned plane_bits = 26 + ((d >> 4) & 7) + +static bool read (unsigned a, char *buffer): + unsigned column = a & ((1 << page_bits) - 1) + unsigned row = a >> page_bits + debug ("reading %x:", a) + // Read oob information first. + char error[12] + // Spare space (starts at 1 << page_bits) + // 0: unused + // 2: detect valid data (at least 1 byte == 0 means valid) + // 5: unused + // 6: 9-byte ecc of 1st 512 bytes + // 15: 9-byte ecc of 2nd 512 bytes + // 24: 9-byte ecc of 3rd 512 bytes + // 33: 9-byte ecc of 4th 512 bytes + // 42: unused + // 64: end of space + unsigned col = (1 << page_bits) + 2 + cmd (CMD_READ0) + addr (col) + addr (col >> 8) + addr (row) + addr (row >> 8) + addr (row >> 16) + cmd (CMD_READSTART) + bool valid = false + for unsigned t = 0; t < 3; ++t: + if rdata () == 0: + valid = true + break + if !valid: + debug ("invalid page for nand read: %x\n", a) + return false + col = (1 << page_bits) + 6 + 9 * (column >> 9) + cmd (CMD_RNDOUT) + addr (col) + addr (col >> 8) + cmd (CMD_RNDOUTSTART) + //debug ("parity data:") + for unsigned t = 0; t < 9; ++t: + error[t] = rdata () + //debug (" %x", error[t] & 0xff) + //debug ("\n") + cmd (CMD_RNDOUT) + addr (column) + addr (column >> 8) + cmd (CMD_RNDOUTSTART) + EMC_NFINTS = 0 + EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_ERST + for unsigned t = 0; t < 0x200; ++t: + buffer[t] = rdata () + for unsigned t = 0; t < 9; ++t: + ((volatile char *)&EMC_NFPAR (0))[t] = error[t] + EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_PRDY + while !(EMC_NFINTS & EMC_NFINTS_DECF): + DELAY () + unsigned ints = EMC_NFINTS + if ints & EMC_NFINTS_UNCOR: + debug ("uncorrectable error in nand at %x\n", a) + return false + unsigned errs = (ints & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT + for unsigned i = 0; i < errs; ++i: + unsigned err = EMC_NFERR (i) + unsigned index = (err >> 16) - 1 + unsigned mask = err & 0x1ff + unsigned bit = index * 9 + unsigned offset= bit & 7 + unsigned byte = bit / 8 + debug ("correcting %x on %x+%d\n", mask, byte, offset) + unsigned data = buffer[byte] | buffer[byte + 1] << 8 + data ^= mask << offset + buffer[byte] = data + buffer[byte + 1] = data >> 8 + for unsigned i = 0; i < 0x10; ++i: + if (buffer[i] & 0xff) < 0x10: + debug (" 0") + else: + debug (" ") + debug ("%x", buffer[i] & 0xff) + debug ("\n") + return true + +static void write (unsigned a, char *buffer): + unsigned row = a >> page_bits + //debug ("writing: %x/%x: ", a, row) + cmd (CMD_SEQIN) + addr (0) + addr (0) + addr (row) + addr (row >> 8) + addr (row >> 16) + char ecc[4][12] + for unsigned i = 0; i < 0x4; ++i: + bool all_ff = true + EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_ENCODING | EMC_NFECR_ERST + //debug ("writing data from %x\n", (unsigned)buffer + i * 0x200) + for unsigned j = 0; j < 0x200; ++j: + wdata (buffer[i * 0x200 + j]) + if all_ff && (buffer[i * 0x200 + j] & 0xff) != 0xff: + all_ff = false + if !all_ff: + while !(EMC_NFINTS & EMC_NFINTS_ENCF): + DELAY () + for unsigned t = 0; t < 9; ++t: + ecc[i][t] = ((volatile char *)&EMC_NFPAR (0))[t] + //debug ("parity for %x:", i * 0x200 + a) + //for unsigned t = 0; t < 9; ++t: + //debug (" %x", ecc[i][t] & 0xff) + //kdebug ("\n") + else: + for unsigned t = 0; t < 9; ++t: + ecc[i][t] = 0xff + // Spare space (starts at 1 << page_bits) + // 0: unused + // 2: detect valid data (at least 1 byte == 0 means valid) + // 5: unused + // 6: 9-byte ecc of 1st 512 bytes + // 15: 9-byte ecc of 2nd 512 bytes + // 24: 9-byte ecc of 3rd 512 bytes + // 33: 9-byte ecc of 4th 512 bytes + // 42: unused + // 64: end of space + for unsigned i = 0; i < 6; ++i: + wdata (0) + for unsigned i = 0; i < 4; ++i: + for unsigned j = 0; j < 9; ++j: + wdata (ecc[i][j]) + cmd (CMD_PAGEPROG) + // Wait at least 100 ns. + DELAY () + cmd (CMD_READ0) + addr (0) + addr (0) + addr (row) + addr (row >> 8) + addr (row >> 16) + cmd (CMD_READSTART) + for unsigned i = 0; i < 4; ++i: + EMC_NFINTS = 0 + EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_ERST + for unsigned t = 0; t < 0x200; ++t: + unsigned r = rdata () & 0xff + if r != (buffer[i * 0x200 + t] & 0xff): + debug ("program error at %x: %x != %x\n", i * 0x200 + t, buffer[i * 0x200 + t] & 0xff, r) + for unsigned t = 0; t < 9; ++t: + ((volatile char *)&EMC_NFPAR (0))[t] = ecc[i][t] + EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_PRDY + while !(EMC_NFINTS & EMC_NFINTS_DECF): + DELAY () + unsigned ints = EMC_NFINTS + if ints & EMC_NFINTS_UNCOR: + debug ("uncorrectable error during verify\n") + continue + unsigned errs = (ints & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT + for unsigned i = 0; i < errs; ++i: + unsigned err = EMC_NFERR (i) + unsigned index = (err >> 16) - 1 + unsigned mask = err & 0x1ff + unsigned bit = index * 9 + unsigned offset= bit & 7 + unsigned byte = bit / 8 + debug ("error detected by parity: %x on %x+%d\n", mask, byte, offset) + for unsigned i = 0; i < 6; ++i: + if rdata () != 0: + debug ("extra data not 0 at byte %d\n", i) + for unsigned i = 0; i < 4; ++i: + for unsigned j = 0; j < 9; ++j: + unsigned r = rdata () & 0xff + if r != (ecc[i][j] & 0xff): + debug ("ecc doesn't match: %x != %x\n", r, ecc[i][j] & 0xff) + debug ("nand program %x:", a) + for unsigned i = 0; i < 0x10; ++i: + if (buffer[i] & 0xff) < 0x10: + debug (" 0") + else: + debug (" ") + debug ("%x", buffer[i] & 0xff) + debug ("\n") + +static void erase (unsigned a): + unsigned row = a >> page_bits + cmd (CMD_ERASE1) + addr (row) + addr (row >> 8) + addr (row >> 16) + cmd (CMD_ERASE2) + debug ("nand erase %d done\n", a) diff --git a/mips/nanonote/Makefile.arch b/mips/nanonote/Makefile.arch index 77fe067..012c1e5 100644 --- a/mips/nanonote/Makefile.arch +++ b/mips/nanonote/Makefile.arch @@ -15,50 +15,54 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -start_load = 0xa0600000 +start_load = 0x80600000 load = 0x80000000 -UDC_BOOT = comment this out for nand boot - -ifdef UDC_BOOT -boot_threads = $(standard_boot_programs) $(udc_boot_programs) -threadlist = mips/nanonote/threadlist-udc -ARCH_CXXFLAGS = -DNUM_THREADS=2 -all: mips/nanonote/nand-boot.raw test -else -boot_threads = $(standard_boot_programs) $(sd_boot_programs) -threadlist = mips/nanonote/threadlist-sd -ARCH_CXXFLAGS = -DNUM_THREADS=4 -all: mips/nanonote/nand-boot.raw iris-sd.tar -iris-sd.tar: $(addprefix fs/,$(addsuffix .elf,$(programs))) mips/start.raw.gz fs/init.config - mkimage -A mips -T kernel -a $(start_load) -e a$(shell /bin/sh -c '$(OBJDUMP) -t mips/start.elf | grep __start$$ | cut -b2-8') -n Iris -d mips/start.raw.gz fs/uimage | sed -e 's/:/;/g' - cd fs && tar cvf ../$@ uimage init.config $(addsuffix .elf,$(programs)) --dereference -endif - -ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL -CROSS = mipsel-linux-gnu- -OBJDUMP = $(CROSS)objdump -junk = mdebug.abi32 reginfo comment pdr -OBJCOPYFLAGS = $(addprefix --remove-section=.,$(junk)) -iris.elf: LDFLAGS = --omagic -Ttext $(load) -mips/start.elf: LDFLAGS = --omagic -Ttext $(start_load) -mips/nanonote/nand-boot.elf: LDFLAGS = --omagic -Ttext 0x80000000 - -source/nand.o: mips/nanonote/nand-boot.raw +UDC_BOOT = comment this out for sd boot arch_iris_sources = mips/interrupts.cc mips/arch.cc boot_sources = mips/init.cc mips/nanonote/board.cc -arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh +arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh mips/nand.hh udc_boot_programs = udc sd_boot_programs = sd+mmc partition fat standard_boot_programs = bootinit programs = init gpio lcd bsquare ball buzzer metronome elfrun alarm rtc gui nand test $(udc_boot_programs) $(sd_boot_programs) $(standard_boot_programs) +ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL +CROSS = mipsel-linux-gnu- +OBJDUMP = $(CROSS)objdump +junk = mdebug.abi32 reginfo comment pdr +OBJCOPYFLAGS = $(addprefix --remove-section=.,$(junk)) + +ifdef UDC_BOOT +boot_threads = $(standard_boot_programs) $(udc_boot_programs) +threadlist = mips/nanonote/threadlist-udc +ARCH_CXXFLAGS = -DNUM_THREADS=2 +all: mips/nanonote/nand-boot.raw test +mips/start.o: TARGET = +else +boot_threads = $(standard_boot_programs) $(sd_boot_programs) +threadlist = mips/nanonote/threadlist-sd +ARCH_CXXFLAGS = -DNUM_THREADS=4 +all: mips/nanonote/nand-boot.raw iris-sd.tar +mips/start.o: TARGET = -DWRAPPED +iris-sd.tar: $(addprefix fs/,$(addsuffix .elf,$(programs))) mips/start.raw.gz fs/init.config + mkimage -A mips -T kernel -a $(start_load) -e $(shell /bin/sh -c '$(OBJDUMP) -t mips/start.elf | grep __start$$ | cut -b1-8') -n Iris -d mips/start.raw.gz fs/uimage | sed -e 's/:/;/g' + cd fs && tar cvf ../$@ uimage init.config $(addsuffix .elf,$(programs)) --dereference +endif + +iris.elf: LDFLAGS = --omagic -Ttext $(load) +mips/start.elf: LDFLAGS = --omagic -Ttext $(start_load) +mips/nanonote/nand-boot.elf: LDFLAGS = --omagic -Ttext 0x80000000 +mips/nanonote/nand-boot.o: mips/nand.hh + +source/nand.o: mips/nand.hh mips/nanonote/nand-boot.raw iris-sd.raw + mips/start.o:mips/start.S Makefile Makefile.arch iris.raw - $(CC) $(CPPFLAGS) -DSTART=0xa$(shell /bin/sh -c '$(OBJDUMP) -t iris.elf | grep __start$$ | cut -b2-8') -c $< -o $@ + $(CC) $(CPPFLAGS) $(TARGET) -DSTART=0x$(shell /bin/sh -c '$(OBJDUMP) -t iris.elf | grep __start$$ | cut -b1-8') -c $< -o $@ test: mips/start.raw mips/start.elf mips/nanonote/server/usb-server mips/nanonote/sdram-setup.raw $(addsuffix .elf,$(addprefix fs/,$(programs))) fs/init.config - echo "reboot $(start_load) 0xa$(shell /bin/sh -c '$(OBJDUMP) -t mips/start.elf | grep __start$$ | cut -b2-8') $<" | nc localhost 5050 + echo "reboot $(start_load) 0x$(shell /bin/sh -c '$(OBJDUMP) -t mips/start.elf | grep __start$$ | cut -b1-8') $<" | nc localhost 5050 mips/nanonote/server/usb-server: mips/nanonote/server/usb-server.ccp mips/nanonote/server/Makefile.am mips/nanonote/server/configure.ac devices.hh $(MAKE) -C mips/nanonote/server diff --git a/mips/nanonote/board.ccp b/mips/nanonote/board.ccp index e6edb64..8b59c08 100644 --- a/mips/nanonote/board.ccp +++ b/mips/nanonote/board.ccp @@ -72,10 +72,10 @@ void board_init (): UART0_MCR = 0 UART0_SIRCR = 0 UART0_UACR = 0 - UART0_UMR = 1 + UART0_UMR = 16 UART0_LCR = UARTLCR_WLEN_8 | UARTLCR_STOP1 | UARTLCR_DLAB unsigned const baud = 57600 - unsigned uart_div = 12000000 / baud + unsigned uart_div = 12000000 / 16 / baud UART0_DLHR = (uart_div >> 8) & 0xff UART0_DLLR = uart_div & 0xff UART0_LCR = UARTLCR_WLEN_8 | UARTLCR_STOP1 @@ -83,9 +83,14 @@ void board_init (): kdebug ("\n\nSerial port initialized\n") #endif -void arch_reboot (): +static void sync_serial (): + #ifndef NDEBUG // Wait for serial port to be done. while !(UART0_LSR & UARTLSR_TEMT): + #endif + +void arch_reboot (): + sync_serial () // Reboot. wdt_select_extalclk () wdt_select_clk_div1 () @@ -96,8 +101,7 @@ void arch_reboot (): while true: void arch_poweroff (): - // Wait for serial port to be done. - while !(UART0_LSR & UARTLSR_TEMT): + sync_serial () // Power off. // Make sure the rtc is running. cpm_start_rtc () @@ -113,3 +117,9 @@ void arch_poweroff (): // Fall back to reboot. kdebug ("Power down failed! Rebooting instead.\n") arch_reboot () + +void arch_boot (unsigned address): + sync_serial () + // Boot into another kernel. + arch_flush_cache () + return ((void (*)())address) () diff --git a/mips/nanonote/nand-boot.ccp b/mips/nanonote/nand-boot.ccp index 6609565..f379054 100644 --- a/mips/nanonote/nand-boot.ccp +++ b/mips/nanonote/nand-boot.ccp @@ -16,8 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// The following defines are taken from mtd/nand.h in the Linux source. - asm volatile ("\t.set noreorder\n" "\t.text\n" "\t.globl __start\n" @@ -28,6 +26,8 @@ asm volatile ("\t.set noreorder\n" "\tnop\n" "\t.word _gp\n" "1:\n" + "\tori $t0, $zero, 0x0006\n" + "\tmtc0 $t0, $12\n" "\tlw $gp, 0($ra)\n" "\tla $sp, stack + 0x1000\n" "\tla $t9, nandboot_start\n" @@ -38,160 +38,89 @@ asm volatile ("\t.set noreorder\n" #define __KERNEL__ #include -// Standard NAND flash commands -#define CMD_READ0 0 -#define CMD_READ1 1 -#define CMD_RNDOUT 5 -#define CMD_PAGEPROG 0x10 -#define CMD_READOOB 0x50 -#define CMD_ERASE1 0x60 -#define CMD_STATUS 0x70 -#define CMD_STATUS_MULTI 0x71 -#define CMD_SEQIN 0x80 -#define CMD_RNDIN 0x85 -#define CMD_READID 0x90 -#define CMD_ERASE2 0xd0 -#define CMD_RESET 0xff +#define DELAY() -// Extended commands for large page devices -#define CMD_READSTART 0x30 -#define CMD_RNDOUTSTART 0xE0 -#define CMD_CACHEDPROG 0x15 +static void debug (unsigned ch): + while !(UART0_LSR & UARTLSR_TDRQ): + UART0_TDR = ch -// Status bits -#define STATUS_FAIL 0x01 -#define STATUS_FAIL_N1 0x02 -#define STATUS_TRUE_READY 0x20 -#define STATUS_READY 0x40 -#define STATUS_WP 0x80 +static void debug_num (unsigned num, unsigned base, unsigned min_digits = 1): + char const *encode = "0123456789abcdef" + unsigned digits = 1 + unsigned power = 1 + while power <= num / base || min_digits > digits: + power *= base + ++digits + for unsigned i = 0; i < digits; ++i: + unsigned d = num / power + debug (encode[d]) + num -= d * power + power /= base -static volatile char *command -static volatile char *address -static volatile char *data +static void debug (char const *f, ...): + unsigned *last = (unsigned *)&f + while *f: + if *f == '%': + ++f + switch *f: + case '%': + debug ('%') + break + case 'd': + ++last + debug_num (*last, 10) + break + case 'x': + ++last + debug_num (*last, 0x10) + break + case 's': + ++last + char *str = (char*)*last + while *str: + debug (*str++) + break + default: + debug ("warning: invalid character in dbg format string\n") + break + else: + debug (*f) + ++f -static unsigned page_bits -static unsigned redundant_bits -static unsigned block_bits -static unsigned word_size +#define debug_line() debug ("nand-boot line %d\n", __LINE__) -static void unbusy (): - while !(gpio_get_port (2) & (1 << 30)): - // Do nothing. - // Delay. - for unsigned i = 0; i < 1000; ++i: - gpio_set (0, 0) +#include "nand.hh" -static void addr (unsigned d): - unbusy () - *address = d - unbusy () - -static void cmd (unsigned d): - unbusy () - *command = d - unbusy () - -static void wdata (unsigned d): - unbusy () - *data = d - unbusy () - -static unsigned rdata (): - unbusy () - unsigned ret = *data - unbusy () - return ret - -// Reset nand controller. -static void reset (): - unsigned base = 0xa0000000 + 0x18000000 - data = (volatile char *)base - command = (volatile char *)(base + 0x8000) - address = (volatile char *)(base + 0x10000) - - // Set up. - gpio_as_nand () - EMC_NFCSR = EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1 - - // Reset nand. - cmd (CMD_RESET) - - cmd (CMD_READID) - addr (0) - unsigned d = rdata () - //unsigned maker = d - d = rdata () - //unsigned device = d - d = rdata () - //unsigned internal_chip_number = 1 << (d & 0x3) - //unsigned cell_type = 2 << ((d >> 2) & 0x3) - //unsigned simultaneously_programmed_pages = 1 << ((d >> 4) & 0x3) - //bool can_interleave_program_between_chips = d & 0x40 - //bool can_cache_program = d & 0x80 - d = rdata () - page_bits = 10 + (d & 3) - redundant_bits = (d & 4 ? 4 : 3) - block_bits = 16 + ((d >> 4) & 3) - word_size = (d & 0x40 ? 16 : 8) - //unsigned serial_access_minimum = (d & 0x80 ? 25 : 50) - d = rdata () - //unsigned num_planes = 1 << ((d >> 2) & 3) - //unsigned plane_bits = 26 + ((d >> 4) & 7) - -// Read 512 bytes from nand and store them into buffer. a must be aligned. -// Return value is true if the oob claims there is valid data. -static bool read (unsigned a, char *buffer): - unsigned column = a & ((1 << page_bits) - 1) - unsigned row = a >> page_bits - cmd (CMD_READ0) - addr (column) - addr (column >> 8) - addr (row) - addr (row >> 8) - addr (row >> 16) - cmd (CMD_READSTART) - EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_ERST - for unsigned t = 0; t < 0x200; ++t: - buffer[t] = rdata () - EMC_NFECR = EMC_NFECR_RS | EMC_NFECR_RS_DECODING - char error[9] - // Spare space (starts at 1 << page_bits) - // 0: unused - // 2: detect valid data (at least 1 byte == 0 means valid) - // 5: unused - // 6: 9-byte ecc of 1st 512 bytes - // 15: 9-byte ecc of 2nd 512 bytes - // 24: 9-byte ecc of 3rd 512 bytes - // 33: 9-byte ecc of 4th 512 bytes - // 42: unused - // 64: end of space - unsigned validcol = (1 << page_bits) + 2 - bool valid = false - cmd (CMD_RNDOUT) - addr (validcol) - addr (validcol >> 8) - cmd (CMD_RNDOUTSTART) - for unsigned t = 0; t < 3; ++t: - valid = rdata () == 0 || valid - unsigned errcol = (1 << page_bits) + (column >> 9) * 9 + 6 - cmd (CMD_RNDOUT) - addr (errcol) - addr (errcol >> 8) - cmd (CMD_RNDOUTSTART) - for unsigned t = 0; t < 9; ++t: - error[t] = rdata () - EMC_NFPAR (0) = ((unsigned *)error)[0] - EMC_NFPAR (1) = ((unsigned *)error)[1] - EMC_NFPAR (2) = error[9] - EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_PRDY - while !(EMC_NFINTS & EMC_NFINTS_DECF): - // Do nothing. - unsigned errs = (EMC_NFINTS & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT - for unsigned i = 0; i < errs; ++i: - buffer[EMC_NFERR (i) >> 16] ^= EMC_NFERR (i) & 0xff +static void setup_uart (): + cpm_start_uart0 () + gpio_as_uart0 () + UART0_IER = 0 + UART0_FCR = 0 + UART0_MCR = 0 + UART0_SIRCR = 0 + UART0_UACR = 0 + UART0_UMR = 16 + UART0_LCR = UARTLCR_WLEN_8 | UARTLCR_STOP1 | UARTLCR_DLAB + unsigned const baud = 57600 + unsigned uart_div = 12000000 / 16 / baud + UART0_DLHR = (uart_div >> 8) & 0xff + UART0_DLLR = uart_div & 0xff + UART0_LCR = UARTLCR_WLEN_8 | UARTLCR_STOP1 + UART0_FCR = UARTFCR_UUE | UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS + debug ("\n\nNand-boot: serial port initialized\n") extern "C": void nandboot_start (): + unsigned base = 0x18000000 + 0xa0000000 + data = (volatile char *)base + command = (volatile char *)(base + 0x8000) + address = (volatile char *)(base + 0x10000) + pll_init () + cpm_start_all () + gpio_as_sdram_16bit () + gpio_as_nand () + setup_sdram () + setup_uart () reset () // Load contents of nand flash (from 0x4000) into 0xa0600000; unsigned a = 0x4000 @@ -199,8 +128,16 @@ extern "C": while read (a, (char *)target): a += 0x200 target += 0x200 + // Tell about what'll happen. + debug ("Jumping to a0600000:\n") + for unsigned d = 0; d < 0x40; ++d: + debug (" ") + debug_num (((char *)0xa0600000)[d] & 0xff, 16, 2) + debug ('\n') + // Wait for the serial port to finish. + while !(UART0_LSR & UARTLSR_TEMT): // Then jump to 0xa0600000. - return ((void (*)())0xa0600000) () + ((void (*)())0xa0600000) () unsigned char stack[0x1000] diff --git a/mips/start.S b/mips/start.S index 83f6db4..f9a5328 100644 --- a/mips/start.S +++ b/mips/start.S @@ -15,32 +15,70 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +// This program is a wrapper around the kernel. +// It is linked for loading at 0x80600000; however, it it position-independant and may be loaded anywhere. +// It does not use gp. This means that li and la must not be used. .globl __start .set noreorder __start: + // Set t0 to uart0 txd + lui $t0, 0xb003 + bal 1f // For some reason the disassembler considers everything // after __start non-code until the next label. So I add a label. start_hack_for_disassembler: - nop - .word _gp -1: lw $gp, 0($ra) + lui $a0, 0x8000 +base: + .word image_end - image +1: + // Set kseg0 to uncachable. + ori $t0, $zero, 2 + mtc0 $t0, $16, 0 - li $a0, 0xa0000000 - la $a1, image - la $a2, image_end + // Flush cache. + lui $v1, 0x8000 + ori $v0, $v1, 0x8000 +1: + // i-cache index invalidate. + cache 0, 0($v1) + // d-cache index write-back invalidate. + cache 1, 0($v1) + bne $v1, $v0, 1b + addiu $v1, $v1, 32 -1: lw $a3, 0($a1) - sw $a3, 0($a0) - addiu $a1, 4 - bne $a1, $a2, 1b - addiu $a0, 4 + // Set a1 to start address of image. + addiu $a1, $ra, image - base - li $t9, START - jr $t9 + // Set a2 to end address of image. + lw $a2, 0($ra) + add $a2, $a2, $a1 + + // Set t9 to the entry point. + lui $t9, START >> 16 + ori $t9, $t9, START & 0xffff + + // Put the copying code at the end, to prevent overwriting itself. + // The copy goes to the start of RAM, so the target is never larger than the source. + jr $a2 nop image: .incbin "iris.raw" image_end: + // Copy the image to the start of RAM. + // a0 is the destination: 0x80000000, counting up. + // a1 is the start of the image, counting up. + // a2 is the end of the image, not changing. + // a3 is the working register to do the move. +1: lw $a3, 0($a1) + addiu $a1, $a1, 4 + sw $a3, 0($a0) + bne $a1, $a2, 1b + addiu $a0, $a0, 4 + // Done copying. + + // Make the jump to the new code. + jr $t9 + nop diff --git a/panic.ccp b/panic.ccp index 84a010a..b998f4c 100644 --- a/panic.ccp +++ b/panic.ccp @@ -87,6 +87,7 @@ static void print_addr (char const *t, unsigned addr, bool last = false): #endif static void panic_message (unsigned n, const char *line, char const *name, char const *message): + kdebug ("**********************************************************************\n") unsigned vaddr, epc cp0_get (CP0_BAD_V_ADDR, vaddr) cp0_get (CP0_EPC, epc) diff --git a/source/nand.ccp b/source/nand.ccp index cd2b50e..e2c6d7f 100644 --- a/source/nand.ccp +++ b/source/nand.ccp @@ -16,74 +16,29 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#define DELAY Iris::schedule + #include "devices.hh" #define ARCH #include "arch.hh" +#define debug Iris::debug +#include "nand.hh" -// The following defines are taken from mtd/nand.h in the Linux source. +extern "C": + extern char file_start, file_mid, file_end -// Standard NAND flash commands -#define CMD_READ0 0 -#define CMD_READSTART 0x30 +Iris::Num start (): + //kdebug ("starting nand operation in 10 seconds\n") + //Iris::sleep (10 * HZ) -#define CMD_READID 0x90 + map_emc () + map_gpio () -#define CMD_RESET 0xff + // Arbitrary addresses where the pages are mapped. + command = (volatile char *)0x15000 + address = (volatile char *)0x16000 + data = (volatile char *)0x17000 -#define CMD_SEQIN 0x80 -#define CMD_PAGEPROG 0x10 - -#define CMD_ERASE1 0x60 -#define CMD_ERASE2 0xd0 - -#define CMD_RNDIN 0x85 - -#define CMD_RNDOUT 5 -#define CMD_RNDOUTSTART 0xE0 - -#define CMD_STATUS 0x70 - -// Status bits -#define STATUS_FAIL 0x01 -#define STATUS_READY 0x40 -#define STATUS_WRITABLE 0x80 - -static volatile char *command -static volatile char *address -static volatile char *data - -static unsigned page_bits -static unsigned redundant_bits -static unsigned block_bits -static unsigned word_size - -static void unbusy (): - while !(gpio_get_port (2) & (1 << 30)): - Iris::schedule () - Iris::schedule () - -static void addr (unsigned d): - unbusy () - *address = d - unbusy () - -static void cmd (unsigned d): - unbusy () - *command = d - unbusy () - -static void wdata (unsigned d): - unbusy () - *data = d - unbusy () - -static unsigned rdata (): - unbusy () - unsigned ret = *data - unbusy () - return ret - -static void reset (): Iris::Page data_page = Iris::my_memory.create_page () Iris::Page command_page = Iris::my_memory.create_page () Iris::Page address_page = Iris::my_memory.create_page () @@ -101,196 +56,27 @@ static void reset (): Iris::free_cap (command_page) Iris::free_cap (address_page) - // Set up. - gpio_as_nand () - EMC_NFCSR = EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1 - - // Reset nand. - cmd (CMD_RESET) - - cmd (CMD_READID) - addr (0) - unsigned d = rdata () - //unsigned maker = d - d = rdata () - //unsigned device = d - d = rdata () - //unsigned internal_chip_number = 1 << (d & 0x3) - //unsigned cell_type = 2 << ((d >> 2) & 0x3) - //unsigned simultaneously_programmed_pages = 1 << ((d >> 4) & 0x3) - //bool can_interleave_program_between_chips = d & 0x40 - //bool can_cache_program = d & 0x80 - d = rdata () - page_bits = 10 + (d & 3) - Iris::debug ("page bits: %d\n", page_bits) - redundant_bits = (d & 4 ? 4 : 3) - Iris::debug ("redundant bits: %d\n", redundant_bits) - block_bits = 16 + ((d >> 4) & 3) - Iris::debug ("block bits: %d\n", block_bits) - word_size = (d & 0x40 ? 16 : 8) - Iris::debug ("word size: %d\n", word_size) - //unsigned serial_access_minimum = (d & 0x80 ? 25 : 50) - d = rdata () - //unsigned num_planes = 1 << ((d >> 2) & 3) - //unsigned plane_bits = 26 + ((d >> 4) & 7) - -static bool read (unsigned a, char *buffer): - unsigned column = a & ((1 << page_bits) - 1) - unsigned row = a >> page_bits - //Iris::debug ("reading: %x/%x/%x: ", a, row, column) - // Read oob information first. - char error[12] - // Spare space (starts at 1 << page_bits) - // 0: unused - // 2: detect valid data (at least 1 byte == 0 means valid) - // 5: unused - // 6: 9-byte ecc of 1st 512 bytes - // 15: 9-byte ecc of 2nd 512 bytes - // 24: 9-byte ecc of 3rd 512 bytes - // 33: 9-byte ecc of 4th 512 bytes - // 42: unused - // 64: end of space - unsigned col = (1 << page_bits) + 2 - cmd (CMD_READ0) - addr (col) - addr (col >> 8) - addr (row) - addr (row >> 8) - addr (row >> 16) - cmd (CMD_READSTART) - bool valid = false - for unsigned t = 0; t < 3; ++t: - if rdata () == 0: - valid = true - break - if !valid: - return false - col = (1 << page_bits) + 6 + 9 * (column >> 9) - cmd (CMD_RNDOUT) - addr (col) - addr (col >> 8) - cmd (CMD_RNDOUTSTART) - for unsigned t = 0; t < 9; ++t: - error[t] = rdata () - cmd (CMD_RNDOUT) - addr (column) - addr (column >> 8) - cmd (CMD_RNDOUTSTART) - EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_ERST - for unsigned t = 0; t < 0x200; ++t: - buffer[t] = rdata () - EMC_NFPAR (0) = ((unsigned *)error)[0] - EMC_NFPAR (1) = ((unsigned *)error)[1] - EMC_NFPAR (2) = error[9] - EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_PRDY - while !(EMC_NFINTS & EMC_NFINTS_DECF): - Iris::schedule () - unsigned errs = (EMC_NFINTS & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT - for unsigned i = 0; i < errs; ++i: - Iris::debug ("correcting %x on %x\n", EMC_NFERR (i) & 0xff, EMC_NFERR (i) >> 16) - buffer[EMC_NFERR (i) >> 16] ^= EMC_NFERR (i) & 0xff - -static void write (unsigned a, char *buffer): - kdebug_line () - unsigned row = a >> page_bits - kdebug_line () - //Iris::debug ("writing: %x/%x: ", a, row) - cmd (CMD_SEQIN) - kdebug_line () - addr (0) - kdebug_line () - addr (0) - kdebug_line () - addr (row) - kdebug_line () - addr (row >> 8) - kdebug_line () - addr (row >> 16) - kdebug_line () - char ecc[4][12] - for unsigned i = 0; i < 0x4; ++i: - kdebug_line () - EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_ENCODING | EMC_NFECR_ERST - Iris::debug ("writing data from %x\n", (unsigned)buffer + i * 0x200) - for unsigned j = 0; j < 0x200; ++j: - wdata (buffer[i * 0x200 + j]) - kdebug_line () - while !(EMC_NFINTS & EMC_NFINTS_ENCF): - Iris::schedule () - kdebug_line () - ((unsigned *)ecc[i])[0] = EMC_NFPAR (0) - kdebug_line () - ((unsigned *)ecc[i])[1] = EMC_NFPAR (1) - kdebug_line () - ecc[i][9] = EMC_NFPAR (2) - kdebug_line () - // Spare space (starts at 1 << page_bits) - // 0: unused - // 2: detect valid data (at least 1 byte == 0 means valid) - // 5: unused - // 6: 9-byte ecc of 1st 512 bytes - // 15: 9-byte ecc of 2nd 512 bytes - // 24: 9-byte ecc of 3rd 512 bytes - // 33: 9-byte ecc of 4th 512 bytes - // 42: unused - // 64: end of space - for unsigned i = 0; i < 6; ++i: - wdata (0) - kdebug_line () - for unsigned i = 0; i < 4; ++i: - for unsigned j = 0; j < 9; ++j: - wdata (ecc[i][j]) - kdebug_line () - cmd (CMD_PAGEPROG) - kdebug_line () - Iris::debug ("nand program %d done\n", a) - -static void erase (unsigned a): - unsigned row = a >> page_bits - cmd (CMD_ERASE1) - addr (row) - addr (row >> 8) - addr (row >> 16) - cmd (CMD_ERASE2) - Iris::debug ("nand erase %d done\n", a) - -extern "C": - extern char file_start, file_end - -Iris::Num start (): - //kdebug ("starting nand operation in 10 seconds\n") - //Iris::sleep (10 * HZ) - map_emc () - map_gpio () - - // Arbitrary addresses where the pages are mapped. - command = (volatile char *)0x15000 - address = (volatile char *)0x16000 - data = (volatile char *)0x17000 - reset () - - #if 0 + #if 1 erase (0) - kdebug_line () char *source = &file_start - kdebug_line () - unsigned a = 0x0000 - kdebug_line () - while source < &file_end: - kdebug_line () + unsigned a = 0 + while source < &file_mid: + write (a, source) + a += 0x800 + source += 0x800 + source = &file_mid + a = 0x4000 + while source < &file_end: write (a, source) a += 0x800 source += 0x800 - kdebug_line () #endif - char buffer[0x800] - - kdebug_line () + char buffer[0x200] // Send nand contents to serial port. - for unsigned a = 0; a < 0x2000; a += 0x200: + for unsigned a = 0; a < 0x400; a += 0x200: read (a, buffer) for unsigned s = 0; s < 0x8; ++s: for unsigned t = 0; t < 0x40; ++t: @@ -303,9 +89,12 @@ Iris::Num start (): asm volatile ("\t.set noreorder\n" "\t.globl file_start\n" + "\t.globl file_mid\n" "\t.globl file_end\n" "\t.text\n" "file_start:\n" "\t.incbin \"mips/nanonote/nand-boot.raw\"\n" + "file_mid:\n" + "\t.incbin \"iris-sd.raw\"\n" "file_end:\n" ".set reorder")