Fundamentals ::: First stepping stones of making an embedded system. BARE METALS.
BARE METAL
METAL
http://www.wiki.xilinx.com/Linux+Drivers
BARE METAL
METAL
http://www.wiki.xilinx.com/Linux+Drivers
IDEAS for future projects
OS development
- Applications:
Simple OS with scheduler algorithm. When too many interrupts (or other stuff) -> does not respect deadlines, misses deadlines.
- Languages (for bare-metal development of OS):
Goes baremetal?
http://www.embedded.com/design/programming-languages-and-tools/4428704/2/Alternatives-to-C-C--for-system-programming-in-a-distributed-multicore-world http://www.slideshare.net/xen_com_mgr/next-generation-cloud-rise-of-the-unikernel-v2-updated?next_slideshow=1 http://programmers.stackexchange.com/questions/274927/is-functional-language-without-runtime-written-in-c-possible http://www.reddit.com/r/haskell/comments/29tgjd/ideal_programming_language_for_a_new_modern_os/ https://www.reddit.com/r/rust/comments/2web3t/is_rust_going_to_replace_cc_when_it_comes_to/ http://www.reddit.com/r/haskell/comments/2sahpi/why_no_embedded_systems/
- Projects:
http://repetae.net/computer/jhc/manual.html https://zinc.rs/
Good for multicore?
http://www.embedded.com/design/programming-languages-and-tools/4438718/Programming-languages-for-multicore-systems-
- Very good reading:
Educating Embedded Systems Hackers: https://www.kth.se/polopoly_fs/1.580282!/wese2014.pdf http://elib.dlr.de/96449/1/Thesis_report_Wei_final.pdf
MULTICORE RASPI 2
https://www.raspberrypi.org/forums/viewtopic.php?f=72&t=98904&start=25 https://github.com/PeterLemon/RaspberryPi/tree/master/SMP/SMPINIT (smp)
OPENCORES:
- K7 Gtx sim model. 8b10 from opencores, what about rx_align?
- Rchitecture
EYE OPEN ON:
- opencl openmp for embedded
- xen hypervisor
- functional haskell/erlang/rust
ARM Linux Exception handlers implementationAborts Exception Handling
Aborts can be generated either on failed instruction fetches (prefetch aborts) or failed data accesses (data aborts). They can come from the external memory system giving an error response on a memory access (indicating perhaps that the specified address does not correspond to real memory in the system).
Alternatively, the abort can be generated by the Memory Management Unit (MMU) of the processor. An operating system can use MMU aborts to dynamically allocate memory to applications. Prefetch Abort Implementation1. After getting prefetch abort exception, current mode PC will store in exception_LR and CPSR into exception_SPSR, then PC will point to prefetch abort vector address. __vectors_start: ... W(b) vector_pabt + stubs_offset
2. So when ARM refers to the vector table it follows the branch and lands up here. At this moment ARM is in Abort mode, IRQs are disabled, LR contains PC of when abort occurred and SPSR contains CPSR of when abort occurred. Since we are in abort mode, so r13 (SP) is banked, so load SP with address of a small stack frame (size of 3 words) that we have created at cpu_init(). This is abort exception stack
.macro vector_stub, name, mode, correction=0
vector_\name: (in this case vector_pabt)
...@ @ Save r0, lr_ @ (parent CPSR) @ stmia sp, {r0, lr} @ save r0, lr mrs lr, spsr str lr, [sp, #8] @ save spsr @ @ Prepare for SVC32 mode. IRQs remain disabled. @ mrs r0, cpsr eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE) msr spsr_cxsf, r0
movs pc, lr @ branch to handler in SVC mode
3. After this basic setup is done, depending on the mode, in which ARM was, when exception occurred
we switch to specific handler. We'll assume that ARM was executing in SVC mode, so we'll look into the details of __pabt_svc
/*
* Prefetch abort dispatcher
* Enter in ABT mode, spsr = USR CPSR, lr = USR PC
*/
vector_stub pabt, ABT_MODE, 4
.long __pabt_usr @ 0 (USR_26 / USR_32)
.long __pabt_invalid @ 1 (FIQ_26 / FIQ_32)
.long __pabt_invalid @ 2 (IRQ_26 / IRQ_32)
.long __pabt_svc @ 3 (SVC_26 / SVC_32)
4. __pabt_svc saves r0-12 on SVC mode stack (i.e kernel stack of process which was interrupted), reads
LR and SPSR from temporary IRQ stack and saves them on SVC mode stack. After that it will call pabt_helper and increments the preempt count. _pabt_svc:
svc_entry
mov r2, sp @ regs
pabt_helper
5.
.macro pabt_helper
@ PABORT handler takes pt_regs in r2, fault address in r4 and psr in r5
#ifdef MULTI_PABORT
ldr ip, .LCprocfns
mov lr, pc
ldr pc, [ip, #PROCESSOR_PABT_FUNC]
#else
bl CPU_PABORT_HANDLER
#endif
.endm
6.
arch/arm/include/asm/glue-pf.h
#define CPU_PABORT_HANDLER v7_pabort
arch/arm/mm/pabort-v7.S
.align 5
ENTRY(v7_pabort)
mrc p15, 0, r0, c6, c0, 2 @ get IFAR
mrc p15, 0, r1, c5, c0, 1 @ get IFSR
b do_PrefetchAbort
ENDPROC(v7_pabort)
7. here r0 contains Fault Addr Reg and r1 contains Fault Status Reg, based on status, respective function
will be called arch/arm/mm/fault.c
asmlinkage void __exception
do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
arch/arm/mm/fsr-2level.c
static struct fsr_info ifsr_info[] = {
...
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" },
{ do_bad, SIGSEGV, SEGV_ACCERR, "page access flag fault" },
{ do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" },
{ do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" },
{ do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" },
...
}
8. On error case will do Unhandled prefetch abort and broadcast die notification
if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
return;
printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",
inf->name, ifsr, addr);
arm_notify_die("", regs, &info, ifsr, 0);
9. if we are in user mode will just send SIGSEGV and kill that process, or in SVC mode will trigger oops
arch/arm/kernel/traps.c
arm_notify_die:
if (user_mode(regs)) {
force_sig_info(info->si_signo, info, current);
} else {
die(str, regs, err);
}
Data Abort ImplementationData abort and prefetch abort implementation is almost same. Only do_DataAbort() is get called. Interrupt handler implementation
When a IRQ is raised, ARM stops what it is processing ( Asuming it is not processing a FIQ!),
disables further IRQs (not FIQs), puts CPSR in SPSR, puts current PC to LR and swithes to IRQ mode, refers to the vector table and jumps to the exception handler. In our case it jumps to the exception handler of IRQ. ARM Linux Interrupt Handling When a IRQ is raised, ARM stops what it is processing ( Asuming it is not processing a FIQ!), disables further IRQs (not FIQs), puts CPSR in SPSR, puts current PC to LR and swithes to IRQ mode, refers to the vector table and jumps to the exception handler. In our case it jumps to the exception handler of IRQ. following is the snippet of code for exception handler code for IRQ (again from arch/arm/kernel/entry-armV.S file): __vectors_start: ARM( swi SYS_ERROR0 ) THUMB( svc #0 ) THUMB( nop ) W(b) vector_und + stubs_offset W(ldr) pc, .LCvswi + stubs_offset W(b) vector_pabt + stubs_offset W(b) vector_dabt + stubs_offset W(b) vector_addrexcptn + stubs_offset W(b) vector_irq + stubs_offset W(b) vector_fiq + stubs_offset .globl __vectors_end __vectors_end: /* * Vector stubs. * * This code is copied to 0xffff0200 so we can use branches in the * vectors, rather than ldr's. Note that this code must not * exceed 0x300 bytes. * * Common stub entry macro: * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC * * SP points to a minimal amount of processor-private memory, the address * of which is copied into r0 for the mode specific abort handler. */ .macro vector_stub, name, mode, correction=0 .align 5 1. In our case vector_irq vector_\name: 2. .if \correction sub lr, lr, #\correction .endif 3. So when ARM refers to the vector table it follows the branch and lands up here At this moment ARM is in IRQ mode, IRQs are disabled, LR contains PC of when interrupt occured and SPSR contains CPSR of when interrupt occured. Since we are in IRQ mode so r13 (SP) is banked, so we load SP with address of a small stack frame that we have created at cpu_init(). This stack is only used when we are in IRQ mode. @ @ Save r0, lr_ @ (parent CPSR) @ stmia sp, {r0, lr} @ save r0, lr mrs lr, spsr str lr, [sp, #8] @ save spsr 4. We save LR_ @ @ Prepare for SVC32 mode. IRQs remain disabled. @ mrs r0, cpsr eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE) msr spsr_cxsf, r0 @ @ the branch table must immediately follow this code @ and lr, lr, #0x0f THUMB( adr r0, 1f ) THUMB( ldr lr, [r0, lr, lsl #2] ) mov r0, sp ARM( ldr lr, [pc, lr, lsl #2] ) 5. After this basic setup is done depending on the mode in which ARM was there when interrupt occured we switch to specific handler. We'll assume that ARM was executing in SVC mode, so we'll look ino the details of __irq_svc /* * Interrupt dispatcher */ vector_stub irq, IRQ_MODE, 4 .long __irq_usr @ 0 (USR_26 / USR_32) .long __irq_invalid @ 1 (FIQ_26 / FIQ_32) .long __irq_invalid @ 2 (IRQ_26 / IRQ_32) .long __irq_svc @ 3 (SVC_26 / SVC_32) 6. __irq_svc saves r0-12 on SVC mode stack (i.e kernel stack of process which was interrupted), reads LR and SPSR from temporary IRQ stack and saves them on SVC mode stack. After that it will call irq_handler and increments the preemt count. __irq_svc: svc_entry irq_handler #ifdef CONFIG_PREEMPT get_thread_info tsk ldr r8, [tsk, #TI_PREEMPT] @ get preempt count ldr r0, [tsk, #TI_FLAGS] @ get flags teq r8, #0 @ if preempt count != 0 movne r0, #0 @ force flags to 0 tst r0, #_TIF_NEED_RESCHED blne svc_preempt #endif #ifdef CONFIG_TRACE_IRQFLAGS @ The parent context IRQs must have been enabled to get here in @ the first place, so there's no point checking the PSR I bit. bl trace_hardirqs_on #endif svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__irq_svc) 7. After this arch specific handler get called. /* * Interrupt handling. */ .macro irq_handler #ifdef CONFIG_MULTI_IRQ_HANDLER ldr r1, =handle_arch_irq mov r0, sp adr lr, BSYM(9997f) ldr pc, [r1] #else arch_irq_handler_default #endif 9997: .endm 8. For the SoCs which are using ARM GIC: arch/arm/kernel/setup.c: handle_arch_irq = mdesc->handle_irq arch/arm/mach-ux500/board-mop500.c: .handle_irq = gic_handle_irq, arch/arm/kernel/irq.c: handle_IRQ:generic_handle_irq kernel/irq/irqdesc.c: generic_handle_irq:generic_handle_irq_desc include/linux/irqdesc.h: generic_handle_irq_desc:desc->handle_irq 9. handle_irq is the actual call for the flow handler which we registered as handle_fasteoi_irq kernel/irq/chip.c handle_fasteoi_irq:handle_irq_event kernel/irq/handle.c handle_irq_event:handle_irq_event_percpu kernel/irq/handle.c handle_irq_event_percpu do { res = action->handler(irq, action->dev_id); action = action->next; } while (action); |