/** * \file : reset.S * \date : 01/12/2012 * \author: Cesar FUGUET & Manuel BOUYER & Alain Greiner * * This is a boot code for a generic multi-clusters / multi-processors * TSAR architecture (up to 256 clusters / up to 4 processors per cluster). * There is one XICU, one TTY, one DMA and one stack segment per cluster. * segment base adresses = base + cluster_segment_increment*cluster_id * * - Each processor initializes the Status Register (SR) to disable interrupts. * - Each processor initializes the Count Register. * - Each processor initialises its private XICU Write Triggered Interruption * mask register. * - Only processor 0 initializes the stack pointer ($29). * - Only processor 0 (boot processor) executes the boot_load_elf function to * load in memory the boot loader stored in the block BOOT_LOADER_LBA of * the disk. * - All non-boot processors wait in a low power consumption mode that the * processor 0 wakes them using the IPI (Inter Processor Interruption) * functionality of the XICU device. */ #include #include .section .boot,"ax",@progbits .extern seg_stack_base .extern dtb_addr .extern boot_putc .extern boot_getc .extern boot_ioc_read .extern boot_elf_loader .extern memcpy .extern boot_puts .extern boot_putx .extern boot_putd .extern boot_ioc_init .globl boot /* Make reset an external symbol */ .ent boot .align 2 .set noreorder boot: b _boot /* 0xbfc0000 */ nop /* 0xbfc0004 */ /* Addresses of the functions provided by this pre-loader */ .word BOOT_VERSION /* 0xbfc0008 */ .word dtb_addr /* 0xbfc000c */ .word boot_putc /* 0xbfc0010 */ .word boot_getc /* 0xbfc0014 */ .word boot_ioc_read /* 0xbfc0018 */ .word boot_elf_loader /* 0xbfc001C */ .word memcpy /* 0xbfc0020 */ .word boot_puts /* 0xbfc0024 */ .word boot_putx /* 0xbfc0028 */ .word boot_putd /* 0xbfc002C */ _boot: /* Disable interruptions, keep STATUSbev enabled */ li k0, (1 << 22) mtc0 k0, CP0_STATUS /* Computes proc_id, local_id, cluster_id, and cluster_increment */ mfc0 k0, CP0_EBASE andi t0, k0, 0x3FF /* t0 <= proc_id (at most 1024 processors) */ move t3, t0 la k0, NB_PROCS /* k0 <= number of processors per cluster */ divu t3, k0 mfhi t1 /* t1 <= local_id = proc_id % NB_PROCS */ mflo t2 /* t2 <= cluster_id = proc_id / NB_PROCS */ la k0, NB_CLUSTERS li t3, 0x80000000 divu t3, k0 mflo t4 sll t4, 1 /* t4 <= cluster_increment = 4G / NB_CLUSTERS */ mult t4, t2 mflo t5 /* t5 <= cluster_id * cluster_increment */ /* Initialization of the count register in the coprocessor 0 */ mtc0 zero, CP0_COUNT /* In each cluster, the ICU base address depends on the cluster_id */ la t3, ICU_BASE addu t3, t3, t5 /* t3 <= ICU_BASE + */ /* (cluster_id * cluster_increment) */ /** * Compute the output index for the Write Triggered Interruption mask. * Each processor enable the WTI for its irq output * Each processor may have IRQ_PER_PROC private irq outputs from * the XICU */ move t4, t1 /* t4 <= local_id */ li t5, IRQ_PER_PROC /* t5 <= IRQ_PER_PROC */ multu t4, t5 mflo t6 /* t6 <= IRQ_PER_PROC * local_id */ sll t4, t6, 2 /* t4 <= OUT_INDEX = t6 * 4 */ li t5, (0xC << 7) /* t5 <= FUNC = XICU_MSK_WTI */ or t4, t4, t5 /* t4 <= FUNC | INDEX | 00 */ or t5, t3, t4 /* t5 <= &XICU[MSK_WTI][OUT_INDEX] */ /* Compute and set WTI mask */ li t4, 1 sllv t4, t4, t1 /* Set XICU[MSK_WTI][INDEX][local_id] */ sw t4, 0(t5) /* XICU[MSK_WTI][INDEX] <= t4 */ /** * We have: * t0: global id * t1: local id * t2: cluster id * t3: xicu base address * * Only processor 0 in cluster 0 executes the boot loader */ bne zero, t0, _reset_wait nop /* Initializes stack pointer */ la k1, seg_stack_base li k0, BOOT_STACK_SIZE addu sp, k1, k0 /* sp <= seg_stack_base + BOOT_STACK_SIZE */ #ifndef SOCLIB_IOC /* Initialize the block device */ la k0, boot_ioc_init jalr k0 nop #endif /** * Jump to the boot elf loader routine * Passing as argument the block number in which it must be * the executable elf file to load */ la k0, boot_elf_loader li a0, BOOT_LOADER_LBA jalr k0 nop /** * We jump to the entry point address defined in the * ELF file. This address is returned by boot_elf_loader function. * All function arguments are 0 */ move a0, zero move a1, zero move a2, zero move a3, zero jr v0 nop /** * Wait in low power consumption mode until the application wakes us. * The application wakes up the non-boot CPUs using a IPI with a non-0 * value in the mailbox. This non-0 value is the address to jump to. */ _reset_wait: /** * We have: * t0: global id * t1: local id * t2: cluster id * t3: xicu base address */ sll t4, t1, 2 /* t4 <= local_id * 4 */ addu t5, t4, t3 /* t5 <= &XICU[WTI_REG][local_id] */ wait lw k0, 0(t5) /* k0 <= XICU[WTI_REG][local_id] */ jr k0 nop /* Exception entry point */ .org 0x0380 _excep: mfc0 a0, CP0_STATUS /* first arg is status */ mfc0 a1, CP0_CAUSE /* second arg is cause */ mfc0 a2, CP0_EPC /* third argc is epc */ nop j handle_except nop .end boot .set reorder /* * vim: tabstop=4 : shiftwidth=4 : expandtab */