├── .gitignore ├── extra ├── raw-mmc-header.img ├── raw-mmc-header.txt └── dnsmasq.conf ├── prcm.h ├── start.S ├── bin └── mk-gpimage ├── gpio.h ├── init.S ├── asm-defs.h ├── Makefile ├── main.S ├── demo.ld ├── README.md └── vectors.S /.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | *.elf 3 | *.MLO 4 | *.img 5 | -------------------------------------------------------------------------------- /extra/raw-mmc-header.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mvduin/bbb-asm-demo/HEAD/extra/raw-mmc-header.img -------------------------------------------------------------------------------- /prcm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // power domain PER 4 | 5 | #define CLK_L4LS 0x000 6 | #define MOD_GPIO1 0x0ac // debounce clock enable in bit 18 7 | #define MOD_GPIO2 0x0b0 // debounce clock enable in bit 18 8 | #define MOD_GPIO3 0x0b4 // debounce clock enable in bit 18 9 | -------------------------------------------------------------------------------- /start.S: -------------------------------------------------------------------------------- 1 | #include "asm-defs.h" 2 | 3 | // place in special section to allow linker script to place it at beginning 4 | .section .text._start 5 | 6 | // force ARM mode (required by ROM booloader) 7 | .arm 8 | 9 | // entrypoint -> jump to reset vector 10 | .fun _start 11 | ldr pc, = vectors 12 | .done 13 | -------------------------------------------------------------------------------- /bin/mk-gpimage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use v5.14; 4 | use strict; 5 | use warnings qw( FATAL all ); 6 | use autodie; 7 | 8 | @ARGV == 3 or die "usage: $0 ADDRESS INFILE OUTFILE\n"; 9 | my( $address, $infile, $outfile ) = @ARGV; 10 | $address =~ /^(?:0x)?([0-9a-f]{1,8})\z/ or die "malformed address: $address\n"; 11 | $address = hex $1; 12 | 13 | open my $in, '<:raw', $infile; 14 | undef $/; 15 | my $data = <$in>; 16 | close $in; 17 | 18 | open my $out, '>:raw', $outfile; 19 | print {$out} pack "(LL)<", length $data, $address; 20 | print {$out} $data; 21 | close $out; 22 | -------------------------------------------------------------------------------- /gpio.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define IO_SYSCONFIG 0x010 4 | #define IO_SYSSTATUS 0x114 5 | #define IO_CONTROL 0x130 6 | 7 | #define IO_nOE 0x134 8 | #define IO_IN 0x138 9 | #define IO_OUT 0x13c 10 | #define IO_CLR 0x190 11 | #define IO_SET 0x194 12 | 13 | #define IO_FILTER_TIME 0x154 14 | #define IO_FILTER_EN 0x150 15 | 16 | #define IO_IRQ_ON_LOW 0x140 17 | #define IO_IRQ_ON_HIGH 0x144 18 | #define IO_IRQ_ON_RISE 0x148 19 | #define IO_IRQ_ON_FALL 0x14c 20 | 21 | #define IO_IRQ0 0x02c 22 | #define IO_IRQ0_SET 0x024 23 | #define IO_IRQ0_CLR 0x02c 24 | #define IO_IRQ0_EN 0x034 25 | #define IO_IRQ0_DIS 0x03c 26 | 27 | #define IO_IRQ1 0x030 28 | #define IO_IRQ1_SET 0x028 29 | #define IO_IRQ1_CLR 0x030 30 | #define IO_IRQ1_EN 0x038 31 | #define IO_IRQ1_DIS 0x040 32 | -------------------------------------------------------------------------------- /extra/raw-mmc-header.txt: -------------------------------------------------------------------------------- 1 | "raw MMC header" is basically a trivial version of the Configuration Header 2 | used e.g. on TI OMAP SoCs. 3 | 4 | The full configuration header ("CH") is always sector-aligned and must fit 5 | within a single sector. It consists of a TOC of the configuration sections 6 | and the configuration sections themselves. 7 | 8 | 9 | First the TOC: 10 | 11 | (entry 0) 12 | 00000000 u32 offset = 0x40 (relative to start of CH) 13 | 00000004 u32 size = 0x0c 14 | 00000008 00 00 00 00 00 00 00 00 00 00 00 00 (reserved) 15 | 00000014 char name[12] = "CHSETTINGS" (with nul-termination and padding byte) 16 | 17 | (entry 1) 18 | 00000020 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 19 | 00000030 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 20 | this indicates end of TOC 21 | 22 | 23 | Then config section 0 (CHSETTINGS): 24 | 25 | 00000040 u32 key = 0xc0c0c0c1 (required for CHSETTINGS) 26 | 00000044 u8 enabled = false (config section not used) 27 | 00000045 u8 version = 1 (required) 28 | 00000046 00 00 00 00 00 00 (reserved) 29 | 30 | 31 | The remaining bytes of the sector are ignored, hence this header can coexist 32 | with a partition table in sector 0 if desired. 33 | -------------------------------------------------------------------------------- /init.S: -------------------------------------------------------------------------------- 1 | #include "asm-defs.h" 2 | 3 | 4 | //-------------- Allocate stack ----------------------------------------------// 5 | 6 | .pushsection .noinit.stack, "aw", %nobits 7 | .balign 8 8 | .var stack 9 | .space 512 10 | .done 11 | .set stack_top, . 12 | .popsection 13 | 14 | 15 | //-------------- Initialization ----------------------------------------------// 16 | // 17 | // called with bl/blx from reset vector 18 | 19 | .fun init 20 | // minimalistic cortex-a8 initialization 21 | 22 | subs r4, lr, 4 // vector base, except bit 0 indicates thumb 23 | 24 | cpsid fia, MODE_THR // thread mode, mask all async exceptions 25 | 26 | ldr sp, = stack_top 27 | 28 | mcr p15, 0, r4, c12, c0, 0 // set vector base (bit 0 is ignored) 29 | 30 | mov r0, (3 << 11) // enable branch prediction and i-cache 31 | bfi r0, r4, 30, 1 // configure arm/thumb-mode exceptions 32 | mcr p15, 0, r0, c1, c0, 0 // system control register 33 | 34 | cpsie a // enable async aborts 35 | 36 | bl intc_init 37 | bl main 38 | 39 | // If main returns, go into infinite wfi-loop. This means that purely 40 | // irq-driven apps only have to do their initialization in main. 41 | 42 | .fun idle 43 | wfi 44 | b idle 45 | 46 | .done 47 | -------------------------------------------------------------------------------- /asm-defs.h: -------------------------------------------------------------------------------- 1 | // vim: ft=asm 2 | #pragma once 3 | 4 | .altmacro 5 | .syntax unified 6 | 7 | 8 | // return and conditional return 9 | .macro ret c= ; bx\c& lr ; .endm 10 | 11 | 12 | // more or less emulate the simplicity of the Cortex-M series on Cortex-A 13 | // 14 | // for handler mode can use: 15 | // 0b11111 system mode (same stack as thread mode) 16 | // 0b10011 supervisor mode (separate stack, not supported right now) 17 | // 18 | #define MODE_USR 0b10000 // thread-mode, unprivileged 19 | #define MODE_THR 0b11111 // thread-mode, privileged 20 | #define MODE_HND 0b11111 // handler-mode (always privileged) 21 | 22 | 23 | 24 | //-------- macros for defining functions and labeled data --------------------// 25 | 26 | 27 | // end the current function / data area 28 | .macro .done 29 | .endm 30 | 31 | // redefine .done to do nothing 32 | .macro .donedone 33 | .purgem .done 34 | .macro .done 35 | .endm 36 | .endm 37 | 38 | 39 | // start a function 40 | .macro .fun label 41 | .done 42 | 43 | .balign 4 44 | .global \label& 45 | .type \label&, "function" 46 | \label&: 47 | 48 | .purgem .done 49 | .macro .done 50 | .size \label&, . - \label& 51 | 52 | .donedone 53 | .endm 54 | .endm 55 | 56 | 57 | .macro .var label 58 | .done 59 | 60 | .balign 4 61 | .global \label& 62 | .type \label&, "object" 63 | \label&: 64 | 65 | .purgem .done 66 | .macro .done 67 | .size \label&, . - \label& 68 | 69 | .donedone 70 | .endm 71 | .endm 72 | -------------------------------------------------------------------------------- /extra/dnsmasq.conf: -------------------------------------------------------------------------------- 1 | # example config file for netbooting a BBB 2 | # use e.g. with: dnsmasq -d -C path/to/dnsmasq.conf 3 | # 4 | # you need to customize: 5 | # tftp-root: root dir of tftp service 6 | # dhcp-boot: path of demo.bin file (relative to tftp root) 7 | # dhcp-host and dhcp-range 8 | 9 | 10 | # disable all DNS functions 11 | port=0 12 | 13 | # enable TFTP service 14 | enable-tftp 15 | tftp-root=/path/to/tftproot 16 | 17 | # log extra information about DHCP transactions (optional) 18 | #log-dhcp 19 | 20 | # recognize and tag subarctic 2.x boot ROM 21 | # (note: 1.0 had wrong vendor class, see errata) 22 | dhcp-vendorclass=set:bbrom,AM335x ROM 23 | 24 | # ignore everything else 25 | dhcp-ignore=tag:!bbrom 26 | 27 | # secondary loader file (no MLO header!), relative to TFTP root 28 | dhcp-boot=tag:bbrom,/bbb/demo.bin 29 | 30 | # proxy DHCP -- XXX works for PXE, but not for bootp... no idea why 31 | #dhcp-range=192.168.1.0,proxy 32 | 33 | # manual DHCP -- make sure the IP you're handing out isn't already in use. if 34 | # you have a local DHCP server, give the beaglebone a fixed IP assignment there 35 | # and use the same IP here. Alternatively, set up a separate IP network, give 36 | # your machine an IP in that range, and then you can safely hand out IPs from 37 | # that range. Note that it'll only be used by the ROM bootloader, not by later 38 | # stages of netbooting (if any). 39 | dhcp-range=192.168.1.0,static 40 | dhcp-host=c8:a0:30:c2:d8:04,192.168.1.167,barebone 41 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # take your pick, pretty much any toolchain will do 2 | CROSS_COMPILE = arm-none-eabi- 3 | CROSS_COMPILE = arm-linux-gnueabihf- 4 | 5 | CC = ${CROSS_COMPILE}gcc 6 | CXX = ${CROSS_COMPILE}g++ 7 | OBJCOPY = ${CROSS_COMPILE}objcopy 8 | 9 | PATH := ${PATH}:/usr/local/sbin:/usr/sbin:/sbin 10 | 11 | target_flags = -mcpu=cortex-a8 12 | ifdef use_fpu 13 | # note that you need to enable it in the cpu before executing any C/C++ code 14 | # compiled with these flags. 15 | target_flags += -mfpu=neon -mfloat-abi=hard 16 | else 17 | target_flags += -mfloat-abi=soft 18 | endif 19 | 20 | # common for C/C++ 21 | ccflags += -Wall -Wextra -O -g 22 | ccflags += -static -ffreestanding -fbuiltin 23 | ifdef no_thumb 24 | ccflags += -marm 25 | else 26 | ccflags += -mthumb 27 | endif 28 | 29 | CFLAGS = ${target_flags} ${ccflags} 30 | CXXFLAGS = ${target_flags} ${ccflags} 31 | ASFLAGS = ${target_flags} ${flags} 32 | ifndef no_thumb 33 | ASFLAGS += -Wa,-mthumb 34 | endif 35 | 36 | LDFLAGS = -static -nostartfiles 37 | LDFLAGS += -Wl,--build-id=none 38 | 39 | 40 | all :: demo.elf demo.bin demo.MLO demo.img 41 | 42 | clean :: 43 | ${RM} *.elf *.bin *.MLO *.img *.o 44 | 45 | demo.elf: demo.ld *.S *.h 46 | ${LINK.S} -T ${^:%.h=} ${LOADLIBES} ${LDLIBS} ${OUTPUT_OPTION} 47 | 48 | 49 | %.bin: %.elf 50 | ${OBJCOPY} -O binary $< $@ 51 | 52 | %.MLO: %.bin 53 | bin/mk-gpimage 0x402f0400 $< $@ 54 | 55 | %.img: %.MLO 56 | cp extra/raw-mmc-header.img $@ 57 | dd if=$< of=$@ iflag=fullblock conv=sync seek=1 status=none 58 | echo 'label: dos' | /sbin/sfdisk --quiet $@ 59 | 60 | .DELETE_ON_ERROR: 61 | -------------------------------------------------------------------------------- /main.S: -------------------------------------------------------------------------------- 1 | #include "asm-defs.h" 2 | #include "gpio.h" 3 | #include "prcm.h" 4 | 5 | .cpu cortex-a8 6 | .text 7 | 8 | // r4 in interrupt controller (irq_unmask needs it in r4) 9 | .fun main 10 | push { lr } 11 | 12 | ldr r0, prcm_base 13 | 14 | movs r1, 2 15 | str r1, [ r0, CLK_L4LS ] 16 | orrs r1, 1 << 18 // debounce clock enable 17 | str r1, [ r0, MOD_GPIO1 ] 18 | str r1, [ r0, MOD_GPIO2 ] 19 | 20 | 1: ldr r1, [ r0, MOD_GPIO1 ] 21 | tst r1, 3 << 16 22 | bne 1b 23 | 1: ldr r1, [ r0, MOD_GPIO2 ] 24 | tst r1, 3 << 16 25 | bne 1b 26 | 27 | ldr r0, io1_base // leds are 1.21-24 28 | bl io_reset 29 | mvns r1, 0xf << 21 30 | str r1, [ r0, IO_nOE ] 31 | movs r1, 1 << 21 32 | str r1, [ r0, IO_SET ] 33 | 34 | ldr r0, io2_base // boot-button is 2.8 35 | bl io_reset 36 | movs r1, 1 << 8 37 | str r1, [ r0, IO_FILTER_EN ] // debounce 38 | str r1, [ r0, IO_IRQ_ON_RISE ] 39 | str r1, [ r0, IO_IRQ_ON_FALL ] 40 | str r1, [ r0, IO_IRQ0_EN ] 41 | 42 | movs r0, 32 43 | bl irq_unmask 44 | 45 | pop { pc } 46 | 47 | 48 | .fun io2_irq0 49 | ldr r0, io2_base // boot-button is 2.8 50 | movs r1, 1 << 8 51 | str r1, [ r0, IO_IRQ0_CLR ] 52 | ldr r1, [ r0, IO_IN ] 53 | tst r1, 1 << 8 54 | 55 | ldr r0, io1_base // leds are 1.21-24 56 | beq 1f 57 | 58 | movs r1, 1 << 22 59 | str r1, [ r0, IO_SET ] 60 | movs r1, 3 << 23 61 | str r1, [ r0, IO_CLR ] 62 | ret 63 | 64 | 1: movs r1, 3 << 23 65 | str r1, [ r0, IO_SET ] 66 | movs r1, 1 << 22 67 | str r1, [ r0, IO_CLR ] 68 | ret 69 | 70 | 71 | // r0 const gpio controller 72 | // r1 tmp 73 | .fun io_reset 74 | movs r1, 2 75 | str r1, [ r0, IO_SYSCONFIG ] 76 | 1: ldr r1, [ r0, IO_SYSSTATUS ] 77 | tst r1, 1 78 | beq 1b 79 | 80 | movs r1, 0x10 81 | str r1, [ r0, IO_SYSCONFIG ] 82 | 83 | movs r1, 0 84 | str r1, [ r0, IO_CONTROL ] 85 | 86 | ret 87 | 88 | 89 | .var prcm_base 90 | .word 0x44e00000 91 | .var io1_base 92 | .word 0x4804c000 93 | .var io2_base 94 | .word 0x481ac000 95 | -------------------------------------------------------------------------------- /demo.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | /* Cortex-A8 local RAM -- 64 KB (first 1 KB inaccessible) */ 4 | a8ram : org = 0x402F0000, len = 0x10000 5 | /* OCMC0 memory -- 64 KB */ 6 | ocmc : org = 0x40300000, len = 0x10000 7 | } 8 | 9 | /* ROM bootloader just loads a single contiguous segment, so make the ELF 10 | * program headers do the same */ 11 | PHDRS { 12 | image PT_LOAD; 13 | } 14 | 15 | /* entrypoint (in ARM mode, at start of image) */ 16 | ENTRY( _start ) 17 | 18 | SECTIONS 19 | { 20 | /* reserve secure memory in linker map */ 21 | .reserved 0x402f0000 (NOLOAD) : { . += 0x400; } >a8ram :NONE 22 | 23 | 24 | /********* output segment (peripheral boot image) *********************/ 25 | 26 | /* For peripheral boot, ROM places image at hardcoded addr 0x402f0400 */ 27 | /* For memory boot you can use a different address, e.g. 0x40300000 */ 28 | . = 0x402f0400; 29 | .text . : { 30 | KEEP( *( .text._start ) ) 31 | *( .text .text.* ) 32 | } :image 33 | 34 | .rodata : { 35 | *( .rodata .rodata.* ) 36 | /* 37 | HIDDEN( __init_array_start = . ); 38 | KEEP( *( SORT( .init_array.* ) ) ) 39 | KEEP( *( .init_array ) ) 40 | HIDDEN( __init_array_end = . ); 41 | */ 42 | } :image 43 | 44 | .data : { 45 | *( .data .data.* ) 46 | } :image 47 | 48 | . = .; 49 | 50 | /********* end of output segment **************************************/ 51 | 52 | 53 | /* uninitialized shared RAM */ 54 | .shared (NOLOAD) : { *( .shared .shared.* ) } >ocmc :NONE 55 | 56 | /* uninitialized private RAM */ 57 | .noinit (NOLOAD) : { *( .noinit .noinit.* ) } >a8ram :NONE 58 | 59 | /* zero-initialized private RAM */ 60 | /* 61 | .bss : { 62 | __bss_start = .; 63 | *( .bss .bss.* COMMON ) 64 | __bss_end = .; 65 | } >a8ram :NONE 66 | */ 67 | 68 | 69 | /* catch any unknown sections and yell loudly about them */ 70 | .orphan : { INPUT_SECTION_FLAGS (SHF_ALLOC) *(*) } :NONE 71 | ASSERT( SIZEOF(.orphan) == 0, "unassigned sections!" ) 72 | } 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #### Compiling 2 | 3 | Since this tiny application is written in assembly and make no use of any 4 | toolchain-provided header or libraries (not even startfiles), you can use 5 | basically any arm-gcc toolchain. By default it expects an arm-linux-gnueabihf 6 | toolchain to be installed, but you can override this in the makefile or using a 7 | ``CROSS_COMPILE=`` argument to make. 8 | 9 | Output files produced are: 10 | * ``demo.elf`` suitable for JTAG upload and debugging 11 | * ``demo.bin`` suitable for peripheral boot (UART, Ethernet, USB) and XIP 12 | * ``demo.MLO`` suitable for memory boot (μSD, eMMC, SPI, NAND) 13 | * ``demo.img`` suitable for writing directly to μSD or eMMC 14 | 15 | #### Booting: μSD/eMMC 16 | 17 | Boot ROM checks for the presence of a raw mmc boot header in sectors 0, 256, 18 | 512, and 768. If found, it expects the MLO to be located starting at the next 19 | sector. If none of the four locations have a valid image, ROM proceeds to check 20 | for a FAT filesystem (either whole-card or in a partition marked 21 | 'active'/bootable). The MLO should be located in a file named "MLO" in the root 22 | of the filesystem. 23 | 24 | **Note:** Contrary to what the AM335x TRM used to indicate (prior to rev M), 25 | raw MMC boot also works for SD cards, not just for eMMC. 26 | 27 | ##### Example (raw mmc boot, prefab image) 28 | 29 | **Caution:** This destroys existing contents of the card. 30 | 31 | ```bash 32 | dev=/dev/mmcblk0 33 | 34 | dd if=demo.img of=$dev 35 | ``` 36 | 37 | ##### Example (raw mmc boot) 38 | 39 | **Caution:** This overwrites sectors 1 and 2 of the card and may overwrite any 40 | existing bootloader. It should not affect any existing partitions that start 41 | at sector 3 or higher. 42 | 43 | ```bash 44 | dev=/dev/mmcblk0 45 | sector=0 46 | 47 | dd if=extra/raw-mmc-header.img of=$dev seek=$sector 48 | dd if=demo.MLO of=$dev seek=$(( $sector + 1 )) 49 | ``` 50 | 51 | Note: a raw MMC header in sector 0 can peacefully coexist with a partition 52 | table, provided adequate free space is available between the partition table 53 | and the first partition to accomodate the MLO data. The procedure above will 54 | not damage any existing partition table, nor should the raw mmc header get 55 | damaged by repartitioning. 56 | 57 | ##### Example (FAT partitioned) 58 | 59 | **Caution:** This destroys existing contents of the card. 60 | 61 | ```bash 62 | dev=/dev/mmcblk0 63 | mountpoint=/mnt/tmp 64 | 65 | echo "type=0c,bootable" | sfdisk $dev 66 | mkfs.fat ${dev}p1 67 | 68 | mount ${dev}p1 $mountpoint 69 | cp demo.MLO $mountpoint/MLO 70 | umount $mountpoint 71 | ``` 72 | #### Booting: Ethernet/USB 73 | 74 | Boot ROM tries to download a peripheral boot image using BOOTP and TFTP. See 75 | ``extra/dnsmasq.conf`` for an example configuration for dnsmasq, which can 76 | perform both functions at the same time. 77 | 78 | In case of USB, the device enumerates as an RNDIS network interface, after 79 | which it proceeds the same as Ethernet. 80 | -------------------------------------------------------------------------------- /vectors.S: -------------------------------------------------------------------------------- 1 | #include "asm-defs.h" 2 | 3 | .cpu cortex-a8 4 | .text 5 | 6 | 7 | .macro .handler name lradjust 8 | .fun \name& 9 | .if \lradjust& 10 | sub lr, \lradjust& // fix return address 11 | .endif 12 | srsfd sp!, MODE_HND // save { lr_irq, spsr_irq } to handler stack 13 | cps MODE_HND // change to handler mode 14 | .endm 15 | 16 | 17 | .macro hret 18 | rfefd sp! // pop { pc, cpsr } 19 | .endm 20 | 21 | 22 | // I use b.w to ensure a vector is 4 bytes exactly, but the assembler refuses 23 | // .w suffix in ARM mode (even though it parses it correctly and I see no good 24 | // reason to refuse it) hence this ugly workaround... 25 | 26 | .macro b.w args:vararg 27 | b \args& 28 | .align 29 | .endm 30 | 31 | 32 | 33 | .balign 32 34 | .fun vectors 35 | bl init 36 | b.w exc_undef 37 | b.w exc_syscall 38 | b.w exc_iabort // instruction-side fault and debug trap 39 | b.w exc_dabort // data-side fault (includes cache maintainance) 40 | b.w . // reserved for hypervisor (n/a on cortex-a8) 41 | // FIQ is unavailable so can have an inline IRQ handler instead 42 | 43 | .handler exc_irq, 4 44 | push { r0-r4, r12, lr } 45 | 46 | ldr r4, intc_base 47 | 48 | ldr r0, [ r4, 0x40 ] 49 | cmp r0, 128 50 | bhs 1f // invalid irq number (spurious irq) 51 | 52 | adr r12, irq_vectors 53 | ldr r12, [ r12, r0, lsl 2 ] 54 | blx r12 // invoke IRQ handler 55 | 56 | 1: bl eoi 57 | pop { r0-r4, r12, lr } 58 | hret 59 | 60 | 61 | // r0 tmp 62 | // r4 const interrupt controller 63 | .fun eoi 64 | movs r0, -1 65 | str r0, [ r4, 0x40 ] // set cur irq to -1 for diagnostic 66 | movs r0, 1 67 | str r0, [ r4, 0x48 ] // write eoi bit 68 | ldr r0, [ r4, 0x48 ] // make sure write has completed 69 | ret 70 | 71 | 72 | // r0 const irq 73 | // r1 tmp 74 | // r2 tmp 75 | // r4 const interrupt controller 76 | .fun irq_unmask 77 | ands r1, r0, 31 78 | movs r2, 1 79 | lsls r2, r1 80 | 81 | adds r1, r0, r4 82 | bics r1, r1, 31 83 | 84 | str r2, [ r1, 0x88 ] 85 | ret 86 | 87 | 88 | // r0 tmp 89 | // r4 tmp 90 | .fun intc_init 91 | push { lr } 92 | ldr r4, intc_base // interrupt controller 93 | 94 | movs r0, 2 // reset 95 | str r0, [ r4, 0x10 ] 96 | 1: ldr r0, [ r4, 0x14 ] // wait reset done 97 | tst r0, 1 98 | beq 1b 99 | 100 | bl eoi 101 | isb // XXX is this needed? 102 | cpsie i // enable interrupts 103 | 104 | pop { pc } 105 | 106 | 107 | .var intc_base 108 | .word 0x48200000 109 | 110 | 111 | .handler exc_undef, 0 112 | // Plain hret would retry the invalid instruction, which could be ok 113 | // if for example you'd implement task switching with lazy fpu/neon 114 | // register save/restore. Skipping over the instruction is trickier 115 | // since it depends on ARM/Thumb mode of the caller and in Thumb mode 116 | // the size of the instruction. 117 | b . 118 | 119 | 120 | .handler exc_iabort, 4 121 | b . 122 | 123 | 124 | .handler exc_dabort, 8 125 | b . 126 | 127 | 128 | .handler exc_syscall, 0 129 | // Syscalls are easy: save only lr and dispatch based on r12. 130 | // Register arguments r0-r3 and return value are transparently passed 131 | // through to/from the syscall handler. 132 | // Saving lr is not needed if you have separate handler/process stacks 133 | // and syscalls are only made by processes and never in handler mode. 134 | hret 135 | 136 | 137 | .var irq_vectors 138 | /* 0*/ .word 0 // Cortex-A8 ICECrusher 139 | /* 1*/ .word 0 // Cortex-A8 debug tx 140 | /* 2*/ .word 0 // Cortex-A8 debug rx 141 | /* 3*/ .word 0 // Cortex-A8 PMU 142 | /* 4*/ .word 0 // ELM 143 | /* 5*/ .word 0 // SSM WFI 144 | /* 6*/ .word 0 // SSM 145 | /* 7*/ .word 0 // External IRQ ("NMI") 146 | /* 8*/ .word 0 // L3 firewall error 147 | /* 9*/ .word 0 // L3 interconnect debug error 148 | /* 10*/ .word 0 // L3 interconnect non-debug error 149 | /* 11*/ .word 0 // PRCM MPU irq 150 | /* 12*/ .word 0 // EDMA client 0 151 | /* 13*/ .word 0 // EDMA protection error 152 | /* 14*/ .word 0 // EDMA CC error 153 | /* 15*/ .word 0 // Watchdog 0 154 | /* 16*/ .word 0 // ADC / Touchscreen controller 155 | /* 17*/ .word 0 // USB queue manager and CPPI 156 | /* 18*/ .word 0 // USB port 0 157 | /* 19*/ .word 0 // USB port 1 158 | /* 20*/ .word 0 // PRUSS host event 0 159 | /* 21*/ .word 0 // PRUSS host event 1 160 | /* 22*/ .word 0 // PRUSS host event 2 161 | /* 23*/ .word 0 // PRUSS host event 3 162 | /* 24*/ .word 0 // PRUSS host event 4 163 | /* 25*/ .word 0 // PRUSS host event 5 164 | /* 26*/ .word 0 // PRUSS host event 6 165 | /* 27*/ .word 0 // PRUSS host event 7 166 | /* 28*/ .word 0 // MMC/SD 1 167 | /* 29*/ .word 0 // MMC/SD 2 168 | /* 30*/ .word 0 // I²C 2 169 | /* 31*/ .word 0 // eCAP 0 170 | /* 32*/ .word io2_irq0 // GPIO 2 irq 0 171 | /* 33*/ .word 0 // GPIO 2 irq 1 172 | /* 34*/ .word 0 // USB wakeup 173 | /* 35*/ .word 0 // PCIe wakeup 174 | /* 36*/ .word 0 // LCD controller 175 | /* 37*/ .word 0 // SGX530 error in IMG bus 176 | /* 38*/ .word 0 // ? 177 | /* 39*/ .word 0 // ePWM 2 178 | /* 40*/ .word 0 // Ethernet core 0 rx low on bufs 179 | /* 41*/ .word 0 // Ethernet core 0 rx dma completion 180 | /* 42*/ .word 0 // Ethernet core 0 tx dma completion 181 | /* 43*/ .word 0 // Ethernet core 0 misc irq 182 | /* 44*/ .word 0 // UART 3 183 | /* 45*/ .word 0 // UART 4 184 | /* 46*/ .word 0 // UART 5 185 | /* 47*/ .word 0 // eCAP 1 186 | /* 48*/ .word 0 // PCIe irq 0 (legacy) 187 | /* 49*/ .word 0 // PCIe irq 1 (MSI) 188 | /* 50*/ .word 0 // PCIe irq 2 (error) 189 | /* 51*/ .word 0 // PCIe irq 3 (power management) 190 | /* 52*/ .word 0 // DCAN 0 irq 0 191 | /* 53*/ .word 0 // DCAN 0 irq 1 192 | /* 54*/ .word 0 // DCAN 0 parity 193 | /* 55*/ .word 0 // DCAN 1 irq 0 194 | /* 56*/ .word 0 // DCAN 1 irq 1 195 | /* 57*/ .word 0 // DCAN 1 parity 196 | /* 58*/ .word 0 // ePWM 0 TZ 197 | /* 59*/ .word 0 // ePWM 1 TZ 198 | /* 60*/ .word 0 // ePWM 2 TZ 199 | /* 61*/ .word 0 // eCAP 2 200 | /* 62*/ .word 0 // GPIO 3 irq 0 201 | /* 63*/ .word 0 // GPIO 3 irq 1 202 | /* 64*/ .word 0 // MMC/SD 0 203 | /* 65*/ .word 0 // SPI 0 204 | /* 66*/ .word 0 // Timer 0 205 | /* 67*/ .word 0 // Timer 1 206 | /* 68*/ .word 0 // Timer 2 207 | /* 69*/ .word 0 // Timer 3 208 | /* 70*/ .word 0 // I²C 0 209 | /* 71*/ .word 0 // I²C 1 210 | /* 72*/ .word 0 // UART 0 211 | /* 73*/ .word 0 // UART 1 212 | /* 74*/ .word 0 // UART 2 213 | /* 75*/ .word 0 // RTC periodic 214 | /* 76*/ .word 0 // RTC alarm 215 | /* 77*/ .word 0 // System mailbox irq 0 216 | /* 78*/ .word 0 // Wakeup-M3 217 | /* 79*/ .word 0 // eQEP 0 218 | /* 80*/ .word 0 // McASP 0 out 219 | /* 81*/ .word 0 // McASP 0 in 220 | /* 82*/ .word 0 // McASP 1 out 221 | /* 83*/ .word 0 // McASP 1 in 222 | /* 84*/ .word 0 // ? 223 | /* 85*/ .word 0 // ? 224 | /* 86*/ .word 0 // ePWM 0 225 | /* 87*/ .word 0 // ePWM 1 226 | /* 88*/ .word 0 // eQEP 1 227 | /* 89*/ .word 0 // eQEP 2 228 | /* 90*/ .word 0 // External DMA/IRQ pin 2 229 | /* 91*/ .word 0 // Watchdog 1 230 | /* 92*/ .word 0 // Timer 4 231 | /* 93*/ .word 0 // Timer 5 232 | /* 94*/ .word 0 // Timer 6 233 | /* 95*/ .word 0 // Timer 7 234 | /* 96*/ .word 0 // GPIO 0 irq 0 235 | /* 97*/ .word 0 // GPIO 0 irq 1 236 | /* 98*/ .word 0 // GPIO 1 irq 0 237 | /* 99*/ .word 0 // GPIO 1 irq 1 238 | /*100*/ .word 0 // GPMC 239 | /*101*/ .word 0 // EMIF 0 error 240 | /*102*/ .word 0 // ? 241 | /*103*/ .word 0 // ? 242 | /*104*/ .word 0 // ? 243 | /*105*/ .word 0 // ? 244 | /*106*/ .word 0 // ? 245 | /*107*/ .word 0 // ? 246 | /*108*/ .word 0 // ? 247 | /*109*/ .word 0 // ? 248 | /*110*/ .word 0 // ? 249 | /*111*/ .word 0 // ? 250 | /*112*/ .word 0 // EDMA TC 0 error 251 | /*113*/ .word 0 // EDMA TC 1 error 252 | /*114*/ .word 0 // EDMA TC 2 error 253 | /*115*/ .word 0 // Touchscreen Pen 254 | /*116*/ .word 0 // ? 255 | /*117*/ .word 0 // ? 256 | /*118*/ .word 0 // ? 257 | /*119*/ .word 0 // ? 258 | /*120*/ .word 0 // SmartReflex 0 (MPU) 259 | /*121*/ .word 0 // SmartReflex 1 (core) 260 | /*122*/ .word 0 // ? 261 | /*123*/ .word 0 // External DMA/IRQ pin 0 262 | /*124*/ .word 0 // External DMA/IRQ pin 1 263 | /*125*/ .word 0 // SPI 1 264 | /*126*/ .word 0 // ? 265 | /*127*/ .word 0 // ? 266 | 267 | .done 268 | --------------------------------------------------------------------------------