diff options
Diffstat (limited to 'roms/skiboot/external/memboot/memboot.c')
-rw-r--r-- | roms/skiboot/external/memboot/memboot.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/roms/skiboot/external/memboot/memboot.c b/roms/skiboot/external/memboot/memboot.c new file mode 100644 index 000000000..8298aed2c --- /dev/null +++ b/roms/skiboot/external/memboot/memboot.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* + * The old way of booting a temporary f/w image. + * These days, use mboxd on a BMC. + * + * Copyright 2013-2015 IBM Corp. + */ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/mman.h> + +/* Where to put the firmware image if booting from memory */ +#define MEM_IMG_BASE (0x5c000000) + +/* Start of flash memory if booting from flash */ +#define FLASH_IMG_BASE (0x30000000) + +/* LPC registers */ +#define LPC_BASE 0x1e789000 +#define LPC_HICR6 0x80 +#define LPC_HICR7 0x88 +#define LPC_HICR8 0x8c +#define LPC_SCR0SIO 0x170 + +#define MEMBOOT_SIO_VERSION_FLAG 0x42 +#define MEMBOOT_SIO_FLAG (0x10 << 8) + +uint32_t readl(void *addr) +{ + asm volatile("" : : : "memory"); + return *(volatile uint32_t *)addr; +} + +void writel(uint32_t val, void *addr) +{ + asm volatile("" : : : "memory"); + *(volatile uint32_t *)addr = val; +} + +void copy_flash_img(int mem_fd, int flash_fd, unsigned int size) +{ + static void *memimg, *fwimg; + size_t pagesize = getpagesize(); + + memimg = mmap(NULL, ((size/pagesize)+1)*pagesize, + PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, MEM_IMG_BASE); + if (memimg == MAP_FAILED) { + perror("Unable to map image destination memory"); + exit(1); + } + + fwimg = mmap(NULL,size, PROT_READ, MAP_SHARED, flash_fd, 0); + if (fwimg == MAP_FAILED) { + perror("Unable to open image source memory"); + exit(1); + } + + /* Copy boot image */ + memcpy(memimg, fwimg, size); +} + +void boot_firmware_image(int mem_fd, char *filename) +{ + int fw_fd; + struct stat st; + + fw_fd = open(filename, O_RDONLY); + if (fw_fd < 0) { + perror("Unable to open flash image\n"); + exit(1); + } + + if (stat(filename, &st)) { + perror("Unable to determine size of firmware image"); + exit(1); + } + + if (st.st_size > 32*1024*1024) { + fprintf(stderr, "Flash too large (> 32MB)"); + exit(1); + } + + copy_flash_img(mem_fd, fw_fd, st.st_size); + close(fw_fd); +} + +int main(int argc, char *argv[]) +{ + int mem_fd; + void *lpcreg; + uint32_t lpc_scr0sio_val; + uint32_t lpc_hicr7_val = (FLASH_IMG_BASE | 0xe00); + + if (argc > 2) { + printf("Usage: %s <flash image>\n", argv[0]); + exit(1); + } + + mem_fd = open("/dev/mem", O_RDWR | O_SYNC); + if (mem_fd < 0) { + perror("Unable to open /dev/mem"); + exit(1); + } + + lpcreg = mmap(NULL, getpagesize(), + PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, LPC_BASE); + if (lpcreg == MAP_FAILED) { + perror("Unable to map LPC register memory"); + exit(1); + } + + lpc_scr0sio_val = readl(lpcreg+LPC_SCR0SIO); + lpc_scr0sio_val &= ~0xff; + lpc_scr0sio_val |= MEMBOOT_SIO_VERSION_FLAG; + lpc_scr0sio_val &= ~MEMBOOT_SIO_FLAG; + + if (argc == 2) { + boot_firmware_image(mem_fd, argv[1]); + lpc_hicr7_val = (MEM_IMG_BASE | 0xe00); + + /* Set the boot mode scratch register to indicate a memboot */ + lpc_scr0sio_val |= MEMBOOT_SIO_FLAG; + printf("Booting from memory after power cycle\n"); + } + + if (readl(lpcreg + LPC_HICR7) != lpc_hicr7_val) { + printf("Resetting LPC_HICR7 to 0x%x\n", lpc_hicr7_val); + writel(lpc_hicr7_val, lpcreg+LPC_HICR7); + } + + /* Set the magic value */ + writel(0x42, lpcreg+LPC_SCR0SIO); + + writel(lpc_scr0sio_val, lpcreg+LPC_SCR0SIO); + printf("LPC_HICR7 = 0x%x\n", lpc_hicr7_val); + return 0; +} |