You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
3.5 KiB
C
162 lines
3.5 KiB
C
#include <stdint.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include "stdio.h"
|
|
|
|
#include "io.h"
|
|
#include "microwatt_soc.h"
|
|
#include "console.h"
|
|
#include "elf64.h"
|
|
|
|
#define DTB_ADDR 0x01000000UL
|
|
#define DTBIMAGE_ADDR 0x00500000UL
|
|
|
|
#ifdef DEBUG
|
|
#define debug(...) printf(__VA_ARGS__)
|
|
#else
|
|
#define debug(...) do {} while(0)
|
|
#endif
|
|
|
|
int _printf(const char *fmt, ...)
|
|
{
|
|
int count;
|
|
char buffer[128];
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
count = vsnprintf(buffer, sizeof(buffer), fmt, ap);
|
|
va_end(ap);
|
|
puts(buffer);
|
|
return count;
|
|
}
|
|
|
|
static inline void flush_cpu_icache(void)
|
|
{
|
|
__asm__ volatile ("icbi 0,0; isync" : : : "memory");
|
|
}
|
|
|
|
static void print_hex(unsigned long val)
|
|
{
|
|
int i, nibbles = sizeof(val)*2;
|
|
char buf[sizeof(val)*2+1];
|
|
|
|
for (i = nibbles-1; i >= 0; i--) {
|
|
buf[i] = (val & 0xf) + '0';
|
|
if (buf[i] > '9')
|
|
buf[i] += ('a'-'0'-10);
|
|
val >>= 4;
|
|
}
|
|
buf[nibbles] = '\0';
|
|
puts(buf);
|
|
}
|
|
|
|
static void fl_read(void *dst, uint32_t offset, uint32_t size)
|
|
{
|
|
memcpy(dst, (void *)(unsigned long)(SPI_FLASH_BASE + offset), size);
|
|
}
|
|
|
|
static unsigned long boot_flash(unsigned int offset)
|
|
{
|
|
Elf64_Ehdr ehdr;
|
|
Elf64_Phdr ph;
|
|
unsigned int i, poff, size, off;
|
|
void *addr;
|
|
|
|
fl_read(&ehdr, offset, sizeof(ehdr));
|
|
if (!IS_ELF(ehdr) || ehdr.e_ident[EI_CLASS] != ELFCLASS64) {
|
|
puts("Doesn't look like an elf64\n");
|
|
return -1UL;
|
|
}
|
|
if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB ||
|
|
ehdr.e_machine != EM_PPC64) {
|
|
puts("Not a ppc64le binary\n");
|
|
return -1UL;
|
|
}
|
|
|
|
poff = offset + ehdr.e_phoff;
|
|
for (i = 0; i < ehdr.e_phnum; i++) {
|
|
fl_read(&ph, poff, sizeof(ph));
|
|
if (ph.p_type != PT_LOAD)
|
|
continue;
|
|
|
|
/* XXX Add bound checking ! */
|
|
size = ph.p_filesz;
|
|
addr = (void *)ph.p_vaddr;
|
|
off = offset + ph.p_offset;
|
|
debug("Copy segment %d (0x%x bytes) to %p\n", i, size, addr);
|
|
fl_read(addr, off, size);
|
|
poff += ehdr.e_phentsize;
|
|
}
|
|
|
|
if (poff == offset + ehdr.e_phoff) {
|
|
puts("Did not find any loadable sections\n");
|
|
return -1UL;
|
|
}
|
|
|
|
debug("Found entry point: %x\n", ehdr.e_entry);
|
|
|
|
flush_cpu_icache();
|
|
return ehdr.e_entry;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
unsigned long fl_off = 0;
|
|
potato_uart_init();
|
|
unsigned long payload, dtb;
|
|
void __attribute__((noreturn)) (*enter_kernel)(unsigned long fdt,
|
|
unsigned long entry,
|
|
unsigned long of);
|
|
|
|
|
|
puts("\nMicrowatt Loader ("__DATE__" "__TIME__"\n\n");
|
|
|
|
writeq(SYS_REG_CTRL_DRAM_AT_0, SYSCON_BASE + SYS_REG_CTRL);
|
|
flush_cpu_icache();
|
|
|
|
puts("Load binaries into SDRAM and select option to start:\n\n");
|
|
puts("vmlinux.bin and dtb:\n");
|
|
puts(" mw_debug -b jtag stop load vmlinux.bin load microwatt.dtb 0x1000000 start\n");
|
|
puts(" press 'l' to start'\n\n");
|
|
|
|
puts("dtbImage.microwatt:\n");
|
|
puts(" mw_debug -b jtag stop load dtbImage.microwatt 0x500000 start\n");
|
|
puts(" press 'w' to start'\n\n");
|
|
|
|
if (readq(SYSCON_BASE + SYS_REG_INFO) & SYS_REG_INFO_HAS_SPI_FLASH) {
|
|
unsigned long val = readq(SYSCON_BASE + SYS_REG_SPI_INFO);
|
|
fl_off = val & SYS_REG_SPI_INFO_FLASH_OFF_MASK;
|
|
|
|
puts("Flash:\n");
|
|
puts(" To boot a binary from flash, write it to "); print_hex(fl_off); puts("\n");
|
|
puts(" press 'f' to start'\n\n");
|
|
}
|
|
|
|
while (1) {
|
|
switch (getchar()) {
|
|
case 'l':
|
|
payload = 0;
|
|
dtb = DTB_ADDR;
|
|
goto load;
|
|
case 'w':
|
|
payload = DTBIMAGE_ADDR;
|
|
goto load;
|
|
case 'f':
|
|
payload = boot_flash(fl_off);
|
|
if (payload == -1UL)
|
|
continue;
|
|
goto load;
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
|
|
load:
|
|
puts("Entering payload at "); print_hex(payload); puts("...\n");
|
|
|
|
enter_kernel = (void *)payload;
|
|
|
|
enter_kernel(dtb, 0, 0);
|
|
}
|