I have "Minimum System Development Board for ARM Microcontroller – STM32F103C8T6" with ST-LINK V2.
This is the main code followed by linker-script then startup:
1) main:
### Directives
.thumb # (same as saying '.code 16')
.syntax unified
.cpu cortex-m3
.fpu softvfp
.include "stm32f103.i"
.section .text
.org 0x00
.global main
.equ GPIOC_CRL ,GPIOC_BASE
.equ GPIOC_CRH ,GPIOC_BASE + 0x04
.equ GPIOC_ODR ,GPIOC_BASE + 0x0C
.equ RCC_APB2ENR ,RCC_BASE + 0x14
.equ LEDDELAY ,800000
main:
## Enable the Port C peripheral clock
ldr r6, = RCC_APB2ENR
mov r0, RCC_APB2ENR_IOPCEN
str r0, [r6]
## Set the config and mode bits for Port C bin 15 so it will
## be a push-pull output (up to 50 MHz)
## to '0011'.
ldr r6, = GPIOC_CRH
ldr r0, = 0x34444444
str r0, [r6]
## Load R2 and R3 with the "on" and "off" constants
mov r2, 0x8000 # value to turn on LED
mov r3, 0x0 # value to turn off LED
ldr r6, = GPIOC_ODR # point to Port C output data register
loop:
str r2, [r6] # clear Port C, pin 15, turning on LED
ldr r1, = LEDDELAY
delay1:
subs r1, 1
bne delay1
str r3, [r6] # set Port C, pin 15, turning off LED
ldr r1, = LEDDELAY
delay2:
subs r1, 1
bne delay2
b loop # continue forever
##st-flash write forth.bin 0x08000000
2) linker:
/*
*****************************************************************************
**
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32F103C8Tx Device with
** 64KByte FLASH, 20KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
/* Entry Point */
ENTRY(Reset_Handler)
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
}
/* The size of the stack used by the application. NOTE: you need to adjust */
STACK_SIZE = 256;
/* The size of the heap used by the application. NOTE: you need to adjust */
HEAP_SIZE = 0;
SECTIONS
{
.isr_vector : { /* the vector table goes FIRST into FLASH */
KEEP(*(.isr_vector)) /* vector table */
. = ALIGN(4);
} >FLASH
.text : { /* code and constants */
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
} >FLASH
.preinit_array : {
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array : {
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array : {
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array*))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
_etext = .; /* global symbols at end of code */
.stack : {
__stack_start__ = .;
. = . + STACK_SIZE;
. = ALIGN(4);
__stack_end__ = .;
} >RAM
.data : AT (_etext) {
__data_load = LOADADDR (.data);
__data_start = .;
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
__data_end__ = .;
_edata = __data_end__;
} >RAM
.bss : {
__bss_start__ = .;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = .;
} >RAM
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
PROVIDE ( __end__ = _ebss );
.heap : {
__heap_start__ = .;
. = . + HEAP_SIZE;
. = ALIGN(4);
__heap_end__ = .;
} >RAM
/* Remove information from the standard libraries
/DISCARD/ : {
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
/*.ARM.attributes 0 : { *(.ARM.attributes) }*/
}
3) startup:
/**
*************** (C) COPYRIGHT 2016 STMicroelectronics ************************
* #file startup_stm32f103xb.s
* #author MCD Application Team
* #version V4.1.0
* #date 29-April-2016
* #brief STM32F103xB Devices vector table for Atollic toolchain.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR address
* - Configure the clock system
* - Branches to main in the C library (which eventually
* calls main()).
* After Reset the Cortex-M3 processor is in Thread mode,
* priority is Privileged, and the Stack is set to Main.
******************************************************************************
*/
.syntax unified
.cpu cortex-m3
.fpu softvfp
.thumb
.global __stack_start__
.global __stack_end__
.global g_pfnVectors
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word __data_load
/* start address for the .data section. defined in linker script */
.word __data_start
/* end address for the .data section. defined in linker script */
.word __data_end__
/* start address for the .bss section. defined in linker script */
.word __bss_start__
/* end address for the .bss section. defined in linker script */
.word __bss_end__
.equ BootRAM, 0xF108F85F
/**
* #brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
* necessary set is performed, after which the application
* supplied main() routine is called.
* #param None
* #retval : None
*/
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =__data_load
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =__data_start
ldr r3, =__data_end__
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =__bss_start__
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, =__bss_end__
cmp r2, r3
bcc FillZerobss
/* Call the clock system intitialization function.*/
/*bl SystemInit*/
/* Call static constructors */
/*bl __libc_init_array*/
/* Call the application's entry point.*/
bl main
bx lr
.size Reset_Handler, .-Reset_Handler
/**
* #brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
*
* #param None
* #retval : None
*/
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex M3. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
******************************************************************************/
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word __stack_end__
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
.word WWDG_IRQHandler
.word PVD_IRQHandler
.word TAMPER_IRQHandler
.word RTC_IRQHandler
.word FLASH_IRQHandler
.word RCC_IRQHandler
.word EXTI0_IRQHandler
.word EXTI1_IRQHandler
.word EXTI2_IRQHandler
.word EXTI3_IRQHandler
.word EXTI4_IRQHandler
.word DMA1_Channel1_IRQHandler
.word DMA1_Channel2_IRQHandler
.word DMA1_Channel3_IRQHandler
.word DMA1_Channel4_IRQHandler
.word DMA1_Channel5_IRQHandler
.word DMA1_Channel6_IRQHandler
.word DMA1_Channel7_IRQHandler
.word ADC1_2_IRQHandler
.word USB_HP_CAN1_TX_IRQHandler
.word USB_LP_CAN1_RX0_IRQHandler
.word CAN1_RX1_IRQHandler
.word CAN1_SCE_IRQHandler
.word EXTI9_5_IRQHandler
.word TIM1_BRK_IRQHandler
.word TIM1_UP_IRQHandler
.word TIM1_TRG_COM_IRQHandler
.word TIM1_CC_IRQHandler
.word TIM2_IRQHandler
.word TIM3_IRQHandler
.word TIM4_IRQHandler
.word I2C1_EV_IRQHandler
.word I2C1_ER_IRQHandler
.word I2C2_EV_IRQHandler
.word I2C2_ER_IRQHandler
.word SPI1_IRQHandler
.word SPI2_IRQHandler
.word USART1_IRQHandler
.word USART2_IRQHandler
.word USART3_IRQHandler
.word EXTI15_10_IRQHandler
.word RTC_Alarm_IRQHandler
.word USBWakeUp_IRQHandler
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word BootRAM /* #0x108. This is for boot in RAM mode for
STM32F10x Medium Density devices. */
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak MemManage_Handler
.thumb_set MemManage_Handler,Default_Handler
.weak BusFault_Handler
.thumb_set BusFault_Handler,Default_Handler
.weak UsageFault_Handler
.thumb_set UsageFault_Handler,Default_Handler
.weak SVC_Handler
.thumb_set SVC_Handler,Default_Handler
.weak DebugMon_Handler
.thumb_set DebugMon_Handler,Default_Handler
.weak PendSV_Handler
.thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
.weak PVD_IRQHandler
.thumb_set PVD_IRQHandler,Default_Handler
.weak TAMPER_IRQHandler
.thumb_set TAMPER_IRQHandler,Default_Handler
.weak RTC_IRQHandler
.thumb_set RTC_IRQHandler,Default_Handler
.weak FLASH_IRQHandler
.thumb_set FLASH_IRQHandler,Default_Handler
.weak RCC_IRQHandler
.thumb_set RCC_IRQHandler,Default_Handler
.weak EXTI0_IRQHandler
.thumb_set EXTI0_IRQHandler,Default_Handler
.weak EXTI1_IRQHandler
.thumb_set EXTI1_IRQHandler,Default_Handler
.weak EXTI2_IRQHandler
.thumb_set EXTI2_IRQHandler,Default_Handler
.weak EXTI3_IRQHandler
.thumb_set EXTI3_IRQHandler,Default_Handler
.weak EXTI4_IRQHandler
.thumb_set EXTI4_IRQHandler,Default_Handler
.weak DMA1_Channel1_IRQHandler
.thumb_set DMA1_Channel1_IRQHandler,Default_Handler
.weak DMA1_Channel2_IRQHandler
.thumb_set DMA1_Channel2_IRQHandler,Default_Handler
.weak DMA1_Channel3_IRQHandler
.thumb_set DMA1_Channel3_IRQHandler,Default_Handler
.weak DMA1_Channel4_IRQHandler
.thumb_set DMA1_Channel4_IRQHandler,Default_Handler
.weak DMA1_Channel5_IRQHandler
.thumb_set DMA1_Channel5_IRQHandler,Default_Handler
.weak DMA1_Channel6_IRQHandler
.thumb_set DMA1_Channel6_IRQHandler,Default_Handler
.weak DMA1_Channel7_IRQHandler
.thumb_set DMA1_Channel7_IRQHandler,Default_Handler
.weak ADC1_2_IRQHandler
.thumb_set ADC1_2_IRQHandler,Default_Handler
.weak USB_HP_CAN1_TX_IRQHandler
.thumb_set USB_HP_CAN1_TX_IRQHandler,Default_Handler
.weak USB_LP_CAN1_RX0_IRQHandler
.thumb_set USB_LP_CAN1_RX0_IRQHandler,Default_Handler
.weak CAN1_RX1_IRQHandler
.thumb_set CAN1_RX1_IRQHandler,Default_Handler
.weak CAN1_SCE_IRQHandler
.thumb_set CAN1_SCE_IRQHandler,Default_Handler
.weak EXTI9_5_IRQHandler
.thumb_set EXTI9_5_IRQHandler,Default_Handler
.weak TIM1_BRK_IRQHandler
.thumb_set TIM1_BRK_IRQHandler,Default_Handler
.weak TIM1_UP_IRQHandler
.thumb_set TIM1_UP_IRQHandler,Default_Handler
.weak TIM1_TRG_COM_IRQHandler
.thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler
.weak TIM1_CC_IRQHandler
.thumb_set TIM1_CC_IRQHandler,Default_Handler
.weak TIM2_IRQHandler
.thumb_set TIM2_IRQHandler,Default_Handler
.weak TIM3_IRQHandler
.thumb_set TIM3_IRQHandler,Default_Handler
.weak TIM4_IRQHandler
.thumb_set TIM4_IRQHandler,Default_Handler
.weak I2C1_EV_IRQHandler
.thumb_set I2C1_EV_IRQHandler,Default_Handler
.weak I2C1_ER_IRQHandler
.thumb_set I2C1_ER_IRQHandler,Default_Handler
.weak I2C2_EV_IRQHandler
.thumb_set I2C2_EV_IRQHandler,Default_Handler
.weak I2C2_ER_IRQHandler
.thumb_set I2C2_ER_IRQHandler,Default_Handler
.weak SPI1_IRQHandler
.thumb_set SPI1_IRQHandler,Default_Handler
.weak SPI2_IRQHandler
.thumb_set SPI2_IRQHandler,Default_Handler
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
.weak USART2_IRQHandler
.thumb_set USART2_IRQHandler,Default_Handler
.weak USART3_IRQHandler
.thumb_set USART3_IRQHandler,Default_Handler
.weak EXTI15_10_IRQHandler
.thumb_set EXTI15_10_IRQHandler,Default_Handler
.weak RTC_Alarm_IRQHandler
.thumb_set RTC_Alarm_IRQHandler,Default_Handler
.weak USBWakeUp_IRQHandler
.thumb_set USBWakeUp_IRQHandler,Default_Handler
.align
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
When I try to flash this code with
st-flash write main.bin 0x08000000
I get the following :
st-flash 1.3.1
2017-07-03T21:42:39 INFO src/common.c: Loading device parameters....
2017-07-03T21:42:39 INFO src/common.c: Device connected is: F1 Medium-density device, id 0x20036410
2017-07-03T21:42:39 INFO src/common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x20000 bytes (128 KiB) in pages of 1024 bytes
2017-07-03T21:42:39 INFO src/common.c: Attempting to write 420 (0x1a4) bytes to stm32 address: 134217728 (0x8000000)
Flash page at addr: 0x08000000 erased
2017-07-03T21:42:40 INFO src/common.c: Finished erasing 1 pages of 1024 (0x400) bytes
2017-07-03T21:42:40 INFO src/common.c: Starting Flash write for VL/F0/F3 core id
2017-07-03T21:42:40 INFO src/flash_loader.c: Successfully loaded flash loader in sram
0/0 pages written
2017-07-03T21:42:40 INFO src/common.c: Starting verification of write complete
2017-07-03T21:42:40 INFO src/common.c: Flash written and verified! jolly good!
and the LED doesn't flash, but when I first upload any code using ARDUINO IDE(for this board) then I run the prevouis command, the led starts blinking, but if I pushed the reset button or unplug then plug st-link agian the LED stop blinking.
So I think the problem is with my linker or the startup code, but I don't know where it is.
What is wrong with startup code or linker script?
----- EDIT -----
result of disassembly:
arm-none-eabi-objdump -D main.elf > dump.S
main.elf: file format elf32-littlearm
Disassembly of section .isr_vector:
08000000 <g_pfnVectors>:
8000000: 20005000 andcs r5, r0, r0
8000004: 08000165 stmdaeq r0, {r0, r2, r5, r6, r8}
8000008: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
800000c: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000010: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000014: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000018: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
...
800002c: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000030: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000034: 00000000 andeq r0, r0, r0
8000038: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
800003c: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000040: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000044: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000048: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
800004c: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000050: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000054: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000058: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
800005c: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000060: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000064: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000068: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
800006c: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000070: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000074: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000078: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
800007c: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000080: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000084: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000088: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
800008c: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000090: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000094: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
8000098: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
800009c: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000a0: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000a4: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000a8: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000ac: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000b0: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000b4: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000b8: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000bc: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000c0: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000c4: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000c8: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000cc: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000d0: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000d4: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000d8: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000dc: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000e0: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000e4: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
80000e8: 080001a5 stmdaeq r0, {r0, r2, r5, r7, r8}
...
8000108: f108f85f ; <UNDEFINED> instruction: 0xf108f85f
Disassembly of section .text:
08000110 <main>:
8000110: 4e0a ldr r6, [pc, #40] ; (800013c <delay2+0x8>)
8000112: f04f 0010 mov.w r0, #16
8000116: 6030 str r0, [r6, #0]
8000118: 4e09 ldr r6, [pc, #36] ; (8000140 <delay2+0xc>)
800011a: 480a ldr r0, [pc, #40] ; (8000144 <delay2+0x10>)
800011c: 6030 str r0, [r6, #0]
800011e: f44f 4200 mov.w r2, #32768 ; 0x8000
8000122: f04f 0300 mov.w r3, #0
8000126: 4e08 ldr r6, [pc, #32] ; (8000148 <delay2+0x14>)
08000128 <loop>:
8000128: 6032 str r2, [r6, #0]
800012a: 4908 ldr r1, [pc, #32] ; (800014c <delay2+0x18>)
0800012c <delay1>:
800012c: 3901 subs r1, #1
800012e: d1fd bne.n 800012c <delay1>
8000130: 6033 str r3, [r6, #0]
8000132: 4906 ldr r1, [pc, #24] ; (800014c <delay2+0x18>)
08000134 <delay2>:
8000134: 3901 subs r1, #1
8000136: d1fd bne.n 8000134 <delay2>
8000138: e7f6 b.n 8000128 <loop>
800013a: bf00 nop
800013c: 40021014 andmi r1, r2, r4, lsl r0
8000140: 40011004 andmi r1, r1, r4
8000144: 34444444 strbcc r4, [r4], #-1092 ; 0xfffffbbc
8000148: 4001100c andmi r1, r1, ip
800014c: 000c3500 andeq r3, ip, r0, lsl #10
8000150: 080001a8 stmdaeq r0, {r3, r5, r7, r8}
8000154: 20005000 andcs r5, r0, r0
8000158: 20005000 andcs r5, r0, r0
800015c: 20005000 andcs r5, r0, r0
8000160: 20005000 andcs r5, r0, r0
08000164 <Reset_Handler>:
8000164: 2100 movs r1, #0
8000166: e003 b.n 8000170 <LoopCopyDataInit>
08000168 <CopyDataInit>:
8000168: 4b09 ldr r3, [pc, #36] ; (8000190 <LoopFillZerobss+0xc>)
800016a: 585b ldr r3, [r3, r1]
800016c: 5043 str r3, [r0, r1]
800016e: 3104 adds r1, #4
08000170 <LoopCopyDataInit>:
8000170: 4808 ldr r0, [pc, #32] ; (8000194 <LoopFillZerobss+0x10>)
8000172: 4b09 ldr r3, [pc, #36] ; (8000198 <LoopFillZerobss+0x14>)
8000174: 1842 adds r2, r0, r1
8000176: 429a cmp r2, r3
8000178: d3f6 bcc.n 8000168 <CopyDataInit>
800017a: 4a08 ldr r2, [pc, #32] ; (800019c <LoopFillZerobss+0x18>)
800017c: e002 b.n 8000184 <LoopFillZerobss>
0800017e <FillZerobss>:
800017e: 2300 movs r3, #0
8000180: f842 3b04 str.w r3, [r2], #4
08000184 <LoopFillZerobss>:
8000184: 4b06 ldr r3, [pc, #24] ; (80001a0 <LoopFillZerobss+0x1c>)
8000186: 429a cmp r2, r3
8000188: d3f9 bcc.n 800017e <FillZerobss>
800018a: f7ff ffc1 bl 8000110 <main>
800018e: 4770 bx lr
8000190: 080001a8 stmdaeq r0, {r3, r5, r7, r8}
8000194: 20005000 andcs r5, r0, r0
8000198: 20005000 andcs r5, r0, r0
800019c: 20005000 andcs r5, r0, r0
80001a0: 20005000 andcs r5, r0, r0
080001a4 <ADC1_2_IRQHandler>:
80001a4: e7fe b.n 80001a4 <ADC1_2_IRQHandler>
...
Disassembly of section .stack:
20000000 <__stack_start__>:
...
Disassembly of section .ARM.attributes:
00000000 <.ARM.attributes>:
0: 00002041 andeq r2, r0, r1, asr #32
4: 61656100 cmnvs r5, r0, lsl #2
8: 01006962 tsteq r0, r2, ror #18
c: 00000016 andeq r0, r0, r6, lsl r0
10: 726f4305 rsbvc r4, pc, #335544320 ; 0x14000000
14: 2d786574 cfldr64cs mvdx6, [r8, #-464]! ; 0xfffffe30
18: 0600334d streq r3, [r0], -sp, asr #6
1c: 094d070a stmdbeq sp, {r1, r3, r8, r9, sl}^
20: Address 0x0000000000000020 is out of bounds.
so.s
.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.thumb_func
reset:
b hang
.thumb_func
hang: b .
so.ld
MEMORY
{
rom : ORIGIN = 0x08000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
commands
arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m3 so.s -o so.o
arm-none-eabi-ld -o so.elf -T so.ld so.o
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy so.elf so.bin -O binary
so.list (partial)
Disassembly of section .text:
08000000 <_start>:
8000000: 20001000 andcs r1, r0, r0
8000004: 08000041 stmdaeq r0, {r0, r6}
8000008: 08000043 stmdaeq r0, {r0, r1, r6}
800000c: 08000043 stmdaeq r0, {r0, r1, r6}
8000010: 08000043 stmdaeq r0, {r0, r1, r6}
8000014: 08000043 stmdaeq r0, {r0, r1, r6}
8000018: 08000043 stmdaeq r0, {r0, r1, r6}
800001c: 08000043 stmdaeq r0, {r0, r1, r6}
8000020: 08000043 stmdaeq r0, {r0, r1, r6}
8000024: 08000043 stmdaeq r0, {r0, r1, r6}
8000028: 08000043 stmdaeq r0, {r0, r1, r6}
800002c: 08000043 stmdaeq r0, {r0, r1, r6}
8000030: 08000043 stmdaeq r0, {r0, r1, r6}
8000034: 08000043 stmdaeq r0, {r0, r1, r6}
8000038: 08000043 stmdaeq r0, {r0, r1, r6}
800003c: 08000043 stmdaeq r0, {r0, r1, r6}
08000040 <reset>:
8000040: e7ff b.n 8000042 <hang>
08000042 <hang>:
8000042: e7fe b.n 8000042 <hang>
with your linker script, added a label for Reset_Handler which doesnt do much since this is not being loaded from an operating system, but from flash (the vector table defines entry points not the elf, it isnt used in that form)
Disassembly of section .text:
08000000 <_start>:
8000000: 20001000 andcs r1, r0, r0
8000004: 08000041 stmdaeq r0, {r0, r6}
8000008: 08000043 stmdaeq r0, {r0, r1, r6}
800000c: 08000043 stmdaeq r0, {r0, r1, r6}
8000010: 08000043 stmdaeq r0, {r0, r1, r6}
8000014: 08000043 stmdaeq r0, {r0, r1, r6}
8000018: 08000043 stmdaeq r0, {r0, r1, r6}
800001c: 08000043 stmdaeq r0, {r0, r1, r6}
8000020: 08000043 stmdaeq r0, {r0, r1, r6}
8000024: 08000043 stmdaeq r0, {r0, r1, r6}
8000028: 08000043 stmdaeq r0, {r0, r1, r6}
800002c: 08000043 stmdaeq r0, {r0, r1, r6}
8000030: 08000043 stmdaeq r0, {r0, r1, r6}
8000034: 08000043 stmdaeq r0, {r0, r1, r6}
8000038: 08000043 stmdaeq r0, {r0, r1, r6}
800003c: 08000043 stmdaeq r0, {r0, r1, r6}
08000040 <reset>:
8000040: e7ff b.n 8000042 <hang>
08000042 <hang>:
8000042: e7fe b.n 8000042 <hang>
Then you can add more code to make it blink, I am not going to dig out an STM32F103 right now, could maybe cobble together something untested. will see.
Are you getting the 0x08000000 address with the vector table in the right place in your build seeing how to use the tools in this way?
from the way you dissassembled your file starts off okay
20000100
08000161
080001a1
080001a1
080001a1
080001a1
080001a1
that looks reasonable...I dont know if they are the correct addresses, but assume they are
this is working C code for the same chip but pin PC13 instead of 15.
void PUT32 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );
void dummy ( unsigned int );
#define GPIOCBASE 0x40011000
#define RCCBASE 0x40021000
int notmain ( void )
{
unsigned int ra;
unsigned int rx;
ra=GET32(RCCBASE+0x18);
ra|=1<<4; //enable port c
PUT32(RCCBASE+0x18,ra);
//config
ra=GET32(GPIOCBASE+0x04);
ra&=~(3<<20); //PC13
ra|=1<<20; //PC13
ra&=~(3<<22); //PC13
ra|=0<<22; //PC13
PUT32(GPIOCBASE+0x04,ra);
for(rx=0;;rx++)
{
PUT32(GPIOCBASE+0x10,1<<(13+0));
for(ra=0;ra<200000;ra++) dummy(ra);
PUT32(GPIOCBASE+0x10,1<<(13+16));
for(ra=0;ra<200000;ra++) dummy(ra);
}
return(0);
}
I am working through your disassembly to try to figure out what addresses you are using, they look wrong so far 0x40021014 instead of 0x40021018 to enable port c. (PUT32/GET32 are just store/load functions dummy just returns, used to prevent optimization)
I have spent multiple days trying to figure this out and I just can't. I have some C code. I have made the assembly code for this C program, copy pasted the assembly to someone else's project (that only contains a single assembly file) and assembled that. In these case things work. But if I try to compile from C directly to generate the binaries, it doesn't work. Even though everything else should be identical. This is my C code:
#include <stdint.h>
#define REGISTERS_BASE 0x3F000000
#define MAIL_BASE 0xB880 // Base address for the mailbox registers
// This bit is set in the status register if there is no space to write into the mailbox
#define MAIL_FULL 0x80000000
// This bit is set in the status register if there is nothing to read from the mailbox
#define MAIL_EMPTY 0x40000000
struct Message
{
uint32_t messageSize;
uint32_t requestCode;
uint32_t tagID;
uint32_t bufferSize;
uint32_t requestSize;
uint32_t pinNum;
uint32_t on_off_switch;
uint32_t end;
};
struct Message m =
{
.messageSize = sizeof(struct Message),
.requestCode =0,
.tagID = 0x00038041,
.bufferSize = 8,
.requestSize =0,
.pinNum = 130,
.on_off_switch = 1,
.end = 0,
};
/** Main function - we'll never return from here */
int _start(void)
{
uint32_t mailbox = MAIL_BASE + REGISTERS_BASE + 0x18;
volatile uint32_t status;
do
{
status = *(volatile uint32_t *)(mailbox);
}
while((status & 0x80000000));
*(volatile uint32_t *)(MAIL_BASE + REGISTERS_BASE + 0x20) = ((uint32_t)(&m) & 0xfffffff0) | (uint32_t)(8);
while(1);
}
This is a linker file I copied from the successful method:
/*
* Very simple linker script, combing the text and data sections
* and putting them starting at address 0x800.
*/
SECTIONS {
/* Put the code at 0x80000, leaving room for ARM and
* the stack. It also conforms to the standard expecations.
*/
.init 0x8000 : {
*(.init)
}
.text : {
*(.text)
}
/* Put the data after the code */
.data : {
*(.data)
}
}
And these is how I am compiling and linking everything:
arm-none-eabi-gcc -O0 -march=armv8-a PiTest.c -nostartfiles -o kernel.o
arm-none-eabi-ld kernel.o -o kernel.elf -T kernel.ld
arm-none-eabi-objcopy kernel.elf -O binary kernel.img
My target architecture is armv8 since that's what the pi model 3 uses.
I have no idea how the generated assembly works, but the C code directly does not. Please help I am on the verge of madness.
EDIT: The expected behaviour is for the pi's light to turn on. which it does with the first method I described. With the second method the light remains off.
EDIT4: Made some changes to files, deleted previous edits with outdated info to reduce post size
kernel.elf: file format elf32-littlearm
Disassembly of section .init:
00008000 <_start>:
8000: e3a0dd7d mov sp, #8000 ; 0x1f40
8004: eaffffff b 8008 <kernel_main>
Disassembly of section .text:
00008008 <kernel_main>:
8008: e52db004 push {fp} ; (str fp, [sp, #-4]!)
800c: e28db000 add fp, sp, #0
8010: e24dd00c sub sp, sp, #12
8014: e30b3898 movw r3, #47256 ; 0xb898
8018: e3433f00 movt r3, #16128 ; 0x3f00
801c: e50b3008 str r3, [fp, #-8]
8020: e51b3008 ldr r3, [fp, #-8]
8024: e5933000 ldr r3, [r3]
8028: e50b300c str r3, [fp, #-12]
802c: e51b300c ldr r3, [fp, #-12]
8030: e3530000 cmp r3, #0
8034: bafffff9 blt 8020 <kernel_main+0x18>
8038: e30b38a0 movw r3, #47264 ; 0xb8a0
803c: e3433f00 movt r3, #16128 ; 0x3f00
8040: e3082050 movw r2, #32848 ; 0x8050
8044: e3402001 movt r2, #1
8048: e3c2200f bic r2, r2, #15
804c: e3822008 orr r2, r2, #8
8050: e5832000 str r2, [r3]
8054: eafffffe b 8054 <kernel_main+0x4c>
Disassembly of section .data:
00008058 <__data_start>:
8058: 00000020 andeq r0, r0, r0, lsr #32
805c: 00000000 andeq r0, r0, r0
8060: 00038041 andeq r8, r3, r1, asr #32
8064: 00000008 andeq r0, r0, r8
8068: 00000000 andeq r0, r0, r0
806c: 00000082 andeq r0, r0, r2, lsl #1
8070: 00000001 andeq r0, r0, r1
8074: 00000000 andeq r0, r0, r0
Disassembly of section .ARM.attributes:
00000000 <_stack-0x80021>:
0: 00002e41 andeq r2, r0, r1, asr #28
4: 61656100 cmnvs r5, r0, lsl #2
8: 01006962 tsteq r0, r2, ror #18
c: 00000024 andeq r0, r0, r4, lsr #32
10: 412d3805 ; <UNDEFINED> instruction: 0x412d3805
14: 070e0600 streq r0, [lr, -r0, lsl #12]
18: 09010841 stmdbeq r1, {r0, r6, fp}
1c: 14041202 strne r1, [r4], #-514 ; 0xfffffdfe
20: 17011501 strne r1, [r1, -r1, lsl #10]
24: 1a011803 bne 46038 <__bss_end__+0x3dfc0>
28: 2a012201 bcs 48834 <__bss_end__+0x407bc>
2c: Address 0x000000000000002c is out of bounds.
Disassembly of section .comment:
00000000 <.comment>:
0: 3a434347 bcc 10d0d24 <_stack+0x1050d03>
4: 35312820 ldrcc r2, [r1, #-2080]! ; 0xfffff7e0
8: 392e343a stmdbcc lr!, {r1, r3, r4, r5, sl, ip, sp}
c: 732b332e ; <UNDEFINED> instruction: 0x732b332e
10: 33326e76 teqcc r2, #1888 ; 0x760
14: 37373131 ; <UNDEFINED> instruction: 0x37373131
18: 2029312d eorcs r3, r9, sp, lsr #2
1c: 2e392e34 mrccs 14, 1, r2, cr9, cr4, {1}
20: 30322033 eorscc r2, r2, r3, lsr r0
24: 35303531 ldrcc r3, [r0, #-1329]! ; 0xfffffacf
28: 28203932 stmdacs r0!, {r1, r4, r5, r8, fp, ip, sp}
2c: 72657270 rsbvc r7, r5, #112, 4
30: 61656c65 cmnvs r5, r5, ror #24
34: 00296573 eoreq r6, r9, r3, ror r5
kernel8.img
12345678
00000800
00080264
00000000
12345678
kernel8-32.img
12345678
00008320
00008224
200001DA
12345678
kernel7.img
12345678
00000700
00008224
200001DA
12345678
kernel.img
12345678
00000000
00008224
200001DA
12345678
when I wrote and posted this code this is what I got so if you name your file kernel.img then 0x8000 is your entry point the answer I gave in your other SO question is a complete raspberry pi starting point. You can simply add your mailbox stuff, although if you are struggling with this I thing the mailbox and video are not where you should start IMO.
if you name the file kernel8.img then the entry point is 0x80000 change the linker script to match.
I have a serial port based bootloader you can use to save on the sd card dance, can get a long way with that then simply use the binary version of what you are creating to write to the flash once your application is working.
EDIT
Okay this is incredibly disgusting and by posting it here maybe that means you cant use it in your classwork...you should really do this right and not use inline assembly for your bootstrap...
so.c
asm(
".globl _start\n"
"_start:\n"
"mov sp,#0x8000\n"
"bl centry\n"
"b .\n"
);
unsigned int centry ( void )
{
return(5);
}
build
arm-none-eabi-gcc -O2 -c so.c -o so.o
arm-none-eabi-ld -Ttext=0x8000 so.o -o so.elf
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy so.elf -O binary kernel.img
examine
Disassembly of section .text:
00008000 <_start>:
8000: e3a0d902 mov sp, #32768 ; 0x8000
8004: eb000000 bl 800c <centry>
8008: eafffffe b 8008 <_start+0x8>
0000800c <centry>:
800c: e3a00005 mov r0, #5
8010: e12fff1e bx lr
A complete raspberry pi C with bootstrap example that will work on any of the flavors of pi (so far as I know they might have changed the GPU bootloader in the last few months but assume the didnt).
There are a couple of things I see wrong here. The most obvious ones are:
You aren't leaving anything at address 0, so the CPU is left executing blank memory at startup. You need to put something (like a branch instruction!) at 0x0.
On ARM Cortex-A, the stack pointer is not initialized at startup. You have to initialize it yourself in _start -- which means you will need to write that function in assembly.
First, cudos to old timer for his patience helping me.
The mistakes were:
Wrong entry point for the program, fixed by creating an assembly file with the label _start to set the stack pointer and using the linker to put the init section at address 0x8000
The compilation line itself was also wrong, it was missing a -c argument
I am trying to get this tutorial to work as intended without success (Something fails after the bl main instruction).
According to the tutorial the command
(qemu) xp /1dw 0xa0000018
should result in the print 33 (But i get 0x00 instead)
a0000018: 33
This is the content of the registers after the main call (see startup.s)
(qemu) info registers
R00=a000001c R01=a000001c R02=00000006 R03=00000000
R04=00000000 R05=00000005 R06=00000006 R07=00000007
R08=00000008 R09=00000009 R10=00000000 R11=a3fffffc
R12=00000000 R13=00000000 R14=0000003c R15=00000004
PSR=800001db N--- A und32
FPSCR: 00000000
I have the following files
main.c
startup.s
lscript.ld
Makefile
And I am using the following toolchain
arm-2013.11-24-arm-none-eabi-i686-pc-linux-gnu
Makefile:
SRCS := main.c startup.s
LINKER_NAME := lscript.ld
ELF_NAME := program.elf
BIN_NAME := program.bin
FLASH_NAME := flash.bin
CC := arm-none-eabi
CFLAGS := -nostdlib
OBJFLAGS ?= -DS
QEMUFLAGS := -M connex -pflash $(FLASH_NAME) -nographic -serial /dev/null
# Allocate 16MB to use as a virtual flash for th qemu
# bs = blocksize -> 4KB
# count = number of block -> 4096
# totalsize = 16MB
setup:
dd if=/dev/zero of=$(FLASH_NAME) bs=4096 count=4096
# Compile srcs and write to virtual flash
all: clean setup
$(CC)-gcc $(CFLAGS) -o $(ELF_NAME) -T $(LINKER_NAME) $(SRCS)
$(CC)-objcopy -O binary $(ELF_NAME) $(BIN_NAME)
dd if=$(BIN_NAME) of=$(FLASH_NAME) bs=4096 conv=notrunc
objdump:
$(CC)-objdump $(OBJFLAGS) $(ELF_NAME)
mem-placement:
$(CC)-nm -n $(ELF_NAME)
qemu:
qemu-system-arm $(QEMUFLAGS)
clean:
rm -rf *.bin
rm -rf *.elf
main.c:
static int arr[] = { 1, 10, 4, 5, 6, 7 };
static int sum;
static const int n = sizeof(arr) / sizeof(arr[0]);
int main()
{
int i;
for (i = 0; i < n; i++){
sum += arr[i];
}
return 0;
}
startup.s:
.section "vectors"
reset: b _start
undef: b undef
swi: b swi
pabt: b pabt
dabt: b dabt
nop
irq: b irq
fiq: b fiq
.text
_start:
init:
## Copy data to RAM.
ldr r0, =flash_sdata
ldr r1, =ram_sdata
ldr r2, =data_size
## Handle data_size == 0
cmp r2, #0
beq init_bss
copy:
ldrb r4, [r0], #1
strb r4, [r1], #1
subs r2, r2, #1
bne copy
init_bss:
## Initialize .bss
ldr r0, =sbss
ldr r1, =ebss
ldr r2, =bss_size
## Handle bss_size == 0
cmp r2, #0
beq init_stack
mov r4, #0
zero:
strb r4, [r0], #1
subs r2, r2, #1
bne zero
init_stack:
## Initialize the stack pointer
ldr sp, =0xA4000000
## **this call dosent work as expected.. (r13/sp contains 0xA4000000)**
bl main
## Dosent return from main
## r0 should now contain 33
stop:
b stop
lscript.ld:
/*
* Linker for testing purposes
* (using 16 MB virtual flash = 0x0100_0000)
*/
MEMORY {
rom (rx) : ORIGIN = 0x00000000, LENGTH = 0x01000000
ram (rwx) : ORIGIN = 0xA0000000, LENGTH = 0x04000000
}
SECTIONS {
.text : {
* (vectors);
* (.text);
} > rom
.rodata : {
* (.rodata);
} > rom
flash_sdata = .;
ram_sdata = ORIGIN(ram);
.data : AT (flash_sdata) {
* (.data);
} > ram
ram_edata = .;
data_size = ram_edata - ram_sdata;
sbss = .;
.bss : {
* (.bss);
} > ram
ebss = .;
bss_size = ebss - sbss;
/DISCARD/ : {
*(.note*)
*(.comment)
*(.ARM*)
/*
*(.debug*)
*/
}
}
Disassembly of the executable (objdump):
program.elf: file format elf32-littlearm
Disassembly of section .text:
00000000 <reset>:
0: ea000023 b 94 <_start>
00000004 <undef>:
4: eafffffe b 4 <undef>
00000008 <swi>:
8: eafffffe b 8 <swi>
0000000c <pabt>:
c: eafffffe b c <pabt>
00000010 <dabt>:
10: eafffffe b 10 <dabt>
14: e320f000 nop {0}
00000018 <irq>:
18: eafffffe b 18 <irq>
0000001c <fiq>:
1c: eafffffe b 1c <fiq>
00000020 <main>:
20: e52db004 push {fp} ; (str fp, [sp, #-4]!)
24: e28db000 add fp, sp, #0
28: e24dd00c sub sp, sp, #12
2c: e3a03000 mov r3, #0
30: e50b3008 str r3, [fp, #-8]
34: ea00000d b 70 <main+0x50>
38: e3003000 movw r3, #0
3c: e34a3000 movt r3, #40960 ; 0xa000
40: e51b2008 ldr r2, [fp, #-8]
44: e7932102 ldr r2, [r3, r2, lsl #2]
48: e3003018 movw r3, #24
4c: e34a3000 movt r3, #40960 ; 0xa000
50: e5933000 ldr r3, [r3]
54: e0822003 add r2, r2, r3
58: e3003018 movw r3, #24
5c: e34a3000 movt r3, #40960 ; 0xa000
60: e5832000 str r2, [r3]
64: e51b3008 ldr r3, [fp, #-8]
68: e2833001 add r3, r3, #1
6c: e50b3008 str r3, [fp, #-8]
70: e3a02006 mov r2, #6
74: e51b3008 ldr r3, [fp, #-8]
78: e1530002 cmp r3, r2
7c: baffffed blt 38 <main+0x18>
80: e3a03000 mov r3, #0
84: e1a00003 mov r0, r3
88: e24bd000 sub sp, fp, #0
8c: e49db004 pop {fp} ; (ldr fp, [sp], #4)
90: e12fff1e bx lr
00000094 <_start>:
94: e59f004c ldr r0, [pc, #76] ; e8 <stop+0x4>
98: e59f104c ldr r1, [pc, #76] ; ec <stop+0x8>
9c: e59f204c ldr r2, [pc, #76] ; f0 <stop+0xc>
a0: e3520000 cmp r2, #0
a4: 0a000003 beq b8 <init_bss>
000000a8 <copy>:
a8: e4d04001 ldrb r4, [r0], #1
ac: e4c14001 strb r4, [r1], #1
b0: e2522001 subs r2, r2, #1
b4: 1afffffb bne a8 <copy>
000000b8 <init_bss>:
b8: e59f0034 ldr r0, [pc, #52] ; f4 <stop+0x10>
bc: e59f1034 ldr r1, [pc, #52] ; f8 <stop+0x14>
c0: e59f2034 ldr r2, [pc, #52] ; fc <stop+0x18>
c4: e3520000 cmp r2, #0
c8: 0a000003 beq dc <init_stack>
cc: e3a04000 mov r4, #0
000000d0 <zero>:
d0: e4c04001 strb r4, [r0], #1
d4: e2522001 subs r2, r2, #1
d8: 1afffffc bne d0 <zero>
000000dc <init_stack>:
dc: e3a0d329 mov sp, #-1543503872 ; 0xa4000000
e0: ebffffce bl 20 <main>
000000e4 <stop>:
e4: eafffffe b e4 <stop>
e8: 00000104 andeq r0, r0, r4, lsl #2
ec: a0000000 andge r0, r0, r0
f0: 00000018 andeq r0, r0, r8, lsl r0
f4: a0000018 andge r0, r0, r8, lsl r0
f8: a000001c andge r0, r0, ip, lsl r0
fc: 00000004 andeq r0, r0, r4
Disassembly of section .rodata:
00000100 <n>:
100: 00000006 andeq r0, r0, r6
Disassembly of section .data:
a0000000 <arr>:
a0000000: 00000001 andeq r0, r0, r1
a0000004: 0000000a andeq r0, r0, sl
a0000008: 00000004 andeq r0, r0, r4
a000000c: 00000005 andeq r0, r0, r5
a0000010: 00000006 andeq r0, r0, r6
a0000014: 00000007 andeq r0, r0, r7
Disassembly of section .bss:
a0000018 <sum>:
a0000018: 00000000 andeq r0, r0, r0
Can someone point me in the right direction to why this isn't working according to my expectations?
Thanks Henrik
Minimal examples that just work
https://github.com/cirosantilli/linux-kernel-module-cheat/tree/54e15e04338c0fecc0be139a0da2d0d972c21419#baremetal-setup-getting-started
The prompt.c example takes input from your host terminal and gives back output all through the simulated UART:
enter a character
got: a
new alloc of 1 bytes at address 0x0x4000a1c0
enter a character
got: b
new alloc of 2 bytes at address 0x0x4000a1c0
enter a character
It uses Newlib to expose a subset of the C standard library. This allows you to run existing programs written in C if the only use that restricted subset of the C standard library.
More details about Newlib at: https://electronics.stackexchange.com/questions/223929/c-standard-libraries-on-bare-metal/400077#400077
https://github.com/freedomtan/aarch64-bare-metal-qemu/tree/2ae937a2b106b43bfca49eec49359b3e30eac1b1 for -M virt, just the hello world on the repo. Compile with:
sudo apt-get install gcc-aarch64-linux-gnu
make CROSS_PREFIX=aarch64-linux-gnu-
Here is the example minimized to printing a single character from assembly: How to run a bare metal ELF file on QEMU?
https://github.com/bztsrc/raspi3-tutorial for -M raspi3. Quick getting started at: https://raspberrypi.stackexchange.com/questions/34733/how-to-do-qemu-emulation-for-bare-metal-raspberry-pi-images/85135#85135 Several other examples on the repo going to more advanced subjects.
Also does display output on 09_framebuffer.
Both write a hello world to the UART.
Tested in Ubuntu 18.04, gcc-aarch64-linux-gnu version 4:7.3.0-3ubuntu2.
Debugging!
First, look at the PC and PSR: You're in Undef mode, in the undefined instruction handler.
OK, in an exception mode, the LR tells you where you took the exception. There are some slightly complicated rules between the PC offset and the preferred return address determining exactly what it points at, but just eyeballing it it's clearly in the vicinity of the movw/movt pair.
The movw instruction effectively only exists in the ARMv7 ISA onwards. A brief investigation tells me the machine you're emulating is some old PXA255 thing, whose CPU only implements the ARMv5 ISA. Thus it's not surprising it faults on an instruction that it predates by many years.
Your compiler is apparently configured to target ARMv7 by default (which is not uncommon), so you need to add at least -march=armv5te to your CFLAGS to target the appropriate architecture version. The 'advanced' challenge would be to switch to a different, newer, machine, but that's going to involve adapting the linker script to a new memory map and rewriting any hardware-touching code for new peripherals, so I'd save that idea for the longer term, once you're comfortable with the basics of bare-metal code and slogging through hardware reference manuals.
for the same code on my ubuntu i got
arm-none-eabi-gcc -nostdlib -o sum.elf sum.lds startup.s -w
/usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/bin/ld: warning: cannot find entry symbol _start; defaulting to 00000000
/tmp/ccBthV7t.o: In function init_stack':
(.text+0x4c): undefined reference tomain'
collect2: error: ld returned 1 exit status
I'm starting to write a toy OS for the BeagleBone Black, which uses an ARM Cortex-A8-based TI Sitara AM3359 SoC and the U-Boot bootloader. I've got a simple standalone hello world app writing to UART0 that I can load through U-Boot so far, and now I'm trying to move on to interrupt handlers, but I can't get SWI to do anything but hang the device.
According to the AM335x TRM (starting on page 4099, if you're interested), the interrupt vector table is mapped in ROM at 0x20000. The ROM SWI handler branches to RAM at 0x4030ce08, which branches to the address stored at 0x4030ce28. (Initially, this is a unique dead loop at 0x20084.)
My code sets up all the ARM processor modes' SP to their own areas at the top of RAM, and enables interrupts in the CPSR, then executes an SWI instruction, which always hangs. (Perhaps jumping to some dead-loop instruction?) I've looked at a bunch of samples, and read whatever documentation I could find, and I don't see what I'm missing.
Currently my only interaction with the board is over serial connection on UART0 with my linux box. U-Boot initializes UART0, and allows loading of the binary over the serial connection.
Here's the relevant assembly:
.arm
.section ".text.boot"
.equ usr_mode, 0x10
.equ fiq_mode, 0x11
.equ irq_mode, 0x12
.equ svc_mode, 0x13
.equ abt_mode, 0x17
.equ und_mode, 0x1b
.equ sys_mode, 0x1f
.equ swi_vector, 0x4030ce28
.equ rom_swi_b_addr, 0x20008
.equ rom_swi_addr, 0x20028
.equ ram_swi_b_addr, 0x4030CE08
.equ ram_swi_addr, 0x4030CE28
.macro setup_mode mode, stackpointer
mrs r0, cpsr
mov r1, r0
and r1, r1, #0x1f
bic r0, r0, #0x1f
orr r0, r0, #\mode
msr cpsr_csfx, r0
ldr sp, =\stackpointer
bic r0, r0, #0x1f
orr r0, r0, r1
msr cpsr_csfx, r0
.endm
.macro disable_interrupts
mrs r0, cpsr
orr r0, r0, #0x80
msr cpsr_c, r0
.endm
.macro enable_interrupts
mrs r0, cpsr
bic r0, r0, #0x80
msr cpsr_c, r0
.endm
.global _start
_start:
// Initial SP
ldr r3, =_C_STACK_TOP
mov sp, r3
// Set up all the modes' stacks
setup_mode fiq_mode, _FIQ_STACK_TOP
setup_mode irq_mode, _IRQ_STACK_TOP
setup_mode svc_mode, _SVC_STACK_TOP
setup_mode abt_mode, _ABT_STACK_TOP
setup_mode und_mode, _UND_STACK_TOP
setup_mode sys_mode, _C_STACK_TOP
// Clear out BSS
ldr r0, =_bss_start
ldr r1, =_bss_end
mov r5, #0
mov r6, #0
mov r7, #0
mov r8, #0
b _clear_bss_check$
_clear_bss$:
stmia r0!, {r5-r8}
_clear_bss_check$:
cmp r0, r1
blo _clear_bss$
// Load our SWI handler's address into
// the vector table
ldr r0, =_swi_handler
ldr r1, =swi_vector
str r0, [r1]
// Debug-print out these SWI addresses
ldr r0, =rom_swi_b_addr
bl print_mem
ldr r0, =rom_swi_addr
bl print_mem
ldr r0, =ram_swi_b_addr
bl print_mem
ldr r0, =ram_swi_addr
bl print_mem
enable_interrupts
swi_call$:
swi #0xCC
bl kernel_main
b _reset
.global _swi_handler
_swi_handler:
// Get the SWI parameter into r0
ldr r0, [lr, #-4]
bic r0, r0, #0xff000000
// Save lr onto the stack
stmfd sp!, {lr}
bl print_uint32
ldmfd sp!, {pc}
Those debugging prints produce the expected values:
00020008: e59ff018
00020028: 4030ce08
4030ce08: e59ff018
4030ce28: 80200164
(According to objdump, 0x80200164 is indeed _swi_handler. 0xe59ff018 is the instruction "ldr pc, [pc, #0x20]".)
What am I missing? It seems like this should work.
The firmware on the board changes the ARM execution mode and the locations of
the vector tables associated with the various modes. In my own case (a bare-metal
snippet code executed at Privilege Level 1 and launched by BBB's uBoot) the active vector table is at address 0x9f74b000.
In general, you might use something like the following function to locate the
active vector table:
static inline unsigned int *get_vectors_address(void)
{
unsigned int v;
/* read SCTLR */
__asm__ __volatile__("mrc p15, 0, %0, c1, c0, 0\n"
: "=r" (v) : : );
if (v & (1<<13))
return (unsigned int *) 0xffff0000;
/* read VBAR */
__asm__ __volatile__("mrc p15, 0, %0, c12, c0, 0\n"
: "=r" (v) : : );
return (unsigned int *) v;
}
change
ldr r0, [lr, #-4]
bic r0, r0, #0xff000000
stmfd sp!, {lr}
bl print_uint32
ldmfd sp!, {pc}
to
stmfd sp!, {r0-r3, r12, lr}
ldr r0, [lr, #-4]
bic r0, r0, #0xff000000
bl print_uint32
ldmfd sp!, {r0-r3, r12, pc}^
PS: You don't restore SPSR into CPSR of interrupted task AND you also scratch registers which are not banked by the cpu mode switch.