#endif
.endm
+ /*
+ * Display hexadecimal data value (if debugging is enabled)
+ */
+ .macro print_hex_data sym
+#ifndef NDEBUG
+ LOADN t1, \sym
+ li t2, __riscv_xlen
+ jal t0, print_hex_value_alt
+#endif
+ .endm
+
/*****************************************************************************
*
* Apply compressed relocation records
/* Loop until we have reached a terminator record (MSB=0, offset=0) */
bnez a3, apply_relocs_loop
+ /* Check that relocations were applied successfully
+ *
+ * Failure to apply relocations (if relocations were needed)
+ * is a fatal error.
+ */
+ la t0, _prefix
+ LOADN t1, prefix_virt
+ beq t0, t1, apply_relocs_done
+ progress " failed\n"
+ j reset_system
+
apply_relocs_done:
/* Return to caller */
+ progress " ok\n"
ret
.size apply_relocs, . - apply_relocs
.globl _max_align
.equ _max_align, ( 1 << VPN1_LSB )
+ /* Space for page table
+ *
+ * This can be used only once .bss is known to be writable.
+ */
+ .section ".bss.page_table", "a", @nobits
+ .balign PAGE_SIZE
+page_table:
+ .space PAGE_SIZE
+ .size page_table, . - page_table
+
+ /* Convert physical address to virtual address */
+ .macro phys_to_virt rd, rs:vararg
+ _C2 ( phys_to_virt_, __riscv_xlen ) \rd, \rs
+ .endm
+
/*****************************************************************************
*
* Disable paging
ret
.size enable_paging_64, . - enable_paging_64
+ /* Convert 64-bit physical address to virtual address */
+ .macro phys_to_virt_64 rd, rs:vararg
+ .ifnb \rs
+ mv \rd, \rs
+ .endif
+ .endm
+
/*****************************************************************************
*
* Disable 64-bit paging
.section ".bss.enable_paging_32_xcheck", "aw", @nobits
.org . + enable_paging_32_xalign - enable_paging_32_xlen
+ /* Convert 32-bit physical address to virtual address */
+ .macro phys_to_virt_32 rd, rs:vararg
+ .ifnb \rs
+ sub \rd, \rs, tp
+ .else
+ sub \rd, \rd, tp
+ .endif
+ .endm
+
/*****************************************************************************
*
* Disable 32-bit paging
.section ".bss.disable_paging_32_xcheck", "aw", @nobits
.org . + disable_paging_32_xalign - disable_paging_32_xlen
+/*****************************************************************************
+ *
+ * Install iPXE to a suitable runtime address
+ *
+ *****************************************************************************
+ *
+ * Identify a suitable runtime address for iPXE, relocate there, and
+ * set up for running normal C code.
+ *
+ * A valid temporary stack pointer is required. A 4kB space for a
+ * temporary page table may be provided, and must be provided if the
+ * iPXE image is running from read-only memory.
+ *
+ * Note that this function does not preserve the callee-save registers.
+ *
+ * Parameters:
+ *
+ * a0 - Boot hart ID
+ * a1 - Device tree physical address
+ * a2 - Optional temporary page table space (4kB, aligned to a 4kB boundary)
+ * sp - Valid temporary stack pointer
+ *
+ * Returns:
+ *
+ * pc - Updated to be within the relocated iPXE
+ * sp - Top of internal stack
+ * tp - Virtual address offset
+ *
+ */
+
+ .section ".prefix.install", "ax", @progbits
+ .globl install
+install:
+ /* Register usage:
+ *
+ * s0 - boot hart ID
+ * s1 - device tree physical address
+ * s2 - saved return address
+ * s3 - relocation records physical address
+ * s4 - accessible physical address limit
+ * s5 - relocation physical address
+ * s6 - relocation offset
+ * tp - virtual address offset
+ */
+ progress "\nSBI->iPXE hart:"
+ print_hex_reg a0
+ progress " temp:"
+ print_hex_reg a2
+ progress " fdt:"
+ print_hex_reg a1
+ progress "\nSBI->iPXE phys:"
+ print_hex_addr _prefix
+ progress " virt:"
+ print_hex_data prefix_virt
+ mv s0, a0
+ mv s1, a1
+ mv s2, ra
+ la s3, _edata
+
+ /* Initialise virtual address offset */
+ mv tp, zero
+
+ /* Attempt to enable paging, if we have temporary page table space */
+ mv a0, a2
+ beqz a2, 1f
+ call enable_paging
+1: mv s4, a0
+
+ /* Apply relocations, if still needed after enabling paging */
+ mv a0, s3
+ call apply_relocs
+
+ /* Find a suitable address for relocation (using temporary stack) */
+ phys_to_virt a0, s1
+ mv a1, s4
+ phys_to_virt sp
+ call fdtmem_relocate
+ mv s5, a0
+ progress "SBI->iPXE dest:"
+ print_hex_reg a0
+
+ /* Disable paging */
+ call disable_paging
+
+ /* Determine relocation offset */
+ la s6, _prefix
+ sub s6, s5, s6
+
+ /* Jump to relocated copy */
+ la t0, 1f
+ add t0, t0, s6
+ jr t0
+1:
+ /* Attempt to re-enable paging */
+ la a0, page_table
+ call enable_paging
+
+ /* Reapply relocations, if still needed after enabling paging */
+ phys_to_virt a0, s3
+ call apply_relocs
+
+ /* Load stack pointer */
+ la sp, _estack
+
+ /* Store boot hart */
+ STOREN s0, boot_hart, t0
+
+ /* Register copy of device tree as system device tree */
+ la a0, sysfdt
+ la a1, _end
+ li a2, -1
+ call fdt_parse
+
+ /* Return to a virtual address in the relocated copy */
+ add ra, s2, s6
+ sub ra, ra, tp
+ progress "\n"
+ ret
+ .size install, . - install
+
/*****************************************************************************
*
* Reset (or lock up) system
1: wfi
j 1b
.size reset_system, . - reset_system
+
+/*****************************************************************************
+ *
+ * File split information for the compressor
+ *
+ *****************************************************************************
+ */
+
+/* ELF machine type */
+#define EM_RISCV 243
+
+ .section ".zinfo", "a", @progbits
+ .org 0
+ /* Copy initialised-data portion of image */
+ .ascii "COPY"
+ .word 0
+ .word _filesz
+ .word 1
+ /* Notify compressor of link-time base address */
+ .ascii "BASE"
+ .word 0
+ .dword _base
+ /* Construct compressed relocation records */
+ .ascii "ZREL"
+ .word _reloc_offset
+ .word _reloc_filesz
+ .word EM_RISCV
.section ".note.GNU-stack", "", @progbits
.text
-/* ELF machine type */
-#define EM_RISCV 243
-
- /*
- * Display progress message via debug console
- */
- .macro progress message
-#ifndef NDEBUG
- .section ".rodata.progress_\@", "a", @progbits
-progress_\@:
- .asciz "\message"
- .size progress_\@, . - progress_\@
- .previous
- la t1, progress_\@
- call print_message
-#endif
- .endm
+/* Page size */
+#define PAGE_SIZE 4096
/*
* SBI entry point
.org 0
.globl _sbi_start
_sbi_start:
- /* Initialise virtual address offset */
- mv tp, zero
-
- /* Preserve arguments */
- mv s0, a0
- mv s1, a1
- progress "\nSBI->iPXE"
-
- /* Apply dynamic relocations */
- la a0, _edata
- call apply_relocs
- progress " .reloc"
-
- /* Zero the bss */
- la t0, _bss
- la t1, _ebss
-1: STOREN zero, (t0)
- addi t0, t0, ( __riscv_xlen / 8 )
- blt t0, t1, 1b
- progress " .bss"
-
- /* Set up stack */
- la sp, _estack
- progress " .stack"
-
- /* Store boot hart */
- STOREN s0, boot_hart, t0
+ /* Identify temporary page table and stack space
+ *
+ * Assume that there is sufficient writable memory (~8kB)
+ * directly below the device tree.
+ */
+ li t0, ~( PAGE_SIZE - 1 )
+ and sp, a1, t0
+ li t0, PAGE_SIZE
+ sub sp, sp, t0
+ mv a2, sp
- /* Register device tree */
- la a0, sysfdt
- mv a1, s1
- li a2, -1
- call fdt_parse
+ /* Install iPXE */
+ call install
/* Call main program */
- progress "\n\n"
call main
/* We have no return path, since the M-mode SBI implementation
*/
j reset_system
.size _sbi_start, . - _sbi_start
-
- /* File split information for the compressor */
- .section ".zinfo", "a", @progbits
- .ascii "COPY"
- .word 0
- .word _filesz
- .word 1
- .ascii "BASE"
- .word 0
- .dword _base
- .ascii "ZREL"
- .word _reloc_offset
- .word _reloc_filesz
- .word EM_RISCV
/** Start address of the iPXE image */
extern char _prefix[];
+/** Initialised-data size of the iPXE image (defined by linker) */
+extern size_t ABS_SYMBOL ( _filesz );
+static size_t filesz = ABS_VALUE_INIT ( _filesz );
+
/** In-memory size of the iPXE image (defined by linker) */
extern size_t ABS_SYMBOL ( _memsz );
static size_t memsz = ABS_VALUE_INIT ( _memsz );
physaddr_t new;
physaddr_t try;
size_t len;
+ void *dest;
int rc;
/* Sanity check */
/* Determine required length */
assert ( memsz > 0 );
assert ( ( memsz % FDT_MAX_ALIGN ) == 0 );
- assert ( ( fdt.len % FDT_MAX_ALIGN ) == 0 );
len = ( memsz + fdt.len );
assert ( len > 0 );
DBGC ( colour, "FDTMEM requires %#zx + %#zx => %#zx bytes for "
break;
}
+ /* Copy iPXE and device tree to new location */
+ if ( new != old ) {
+ dest = phys_to_virt ( new );
+ memset ( dest, 0, len );
+ memcpy ( dest, _prefix, filesz );
+ memcpy ( ( dest + memsz ), hdr, fdt.len );
+ }
+
DBGC ( colour, "FDTMEM relocating %#08lx => [%#08lx,%#08lx]\n",
old, new, ( ( physaddr_t ) ( new + len - 1 ) ) );
return new;