강추


http://pubs.opengroup.org/onlinepubs/9699919799/

Posted by 쵸코케키

예제


원본 출처

http://www.mikrocontroller.net/attachment/143228/stm32_flash.ld




/*

*****************************************************************************

**

**  File        : stm32_flash.ld

**

**  Abstract    : Linker script for STM32F207 Device with

**                1MByte FLASH, 128KByte SRAM

**

**                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

**

**  Environment : Eclipse with CDT plugin and GCC compiler from CodeSourcery

**

** Author           Date        Comment

**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

**    T.Kamenicky      24/06/11    Upravil kod stazen z netu

** T.Kamenicky 13/10/11 Predelal na STM32F2

** T.Kamenicky 29/11/11    Pridal podporu externi SRAM

**

*****************************************************************************

*/


/* Entry Point */

/* This define entry point for linker, this address is used for CPU too as absolute first function */

ENTRY(Reset_Handler)


/* Highest address of the user mode stack, _estack is end of stack */

_estack = 0x20020000;    /* end of 128K RAM */


/* Generate a link error if heap and stack don't fit into RAM */

/* Heap is zero because we use own malloc implementation. The amount of heap is calculated 

 * from free space after compilation, see last section for RAM area */

_Min_Heap_Size = 0x0;      /* required amount of heap  */


/* This stack is used for main function. If FreeRTOS is used this stack is used by OS itself. */

/* The size of stack for tasks is defined in freertos config file and when creating the task. */

_Min_Stack_Size = 0x600; /* required amount of stack */


/* Specify the memory areas */

MEMORY

{

  FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 1022K  /* This is main program area */

  FACTORY_VAR(rx) : ORIGIN = 0x080FF800, LENGTH = 2K  /* This area is used for factory values, such as MAC address, ID...etc */

  RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 128K        /* This is RAM area */

  FSMC_SRAM (rx)  : ORIGIN = 0x64000000, LENGTH = 2048K       /* This is useful for external memory, like thru FSMC peripheral */

}


/* Define output sections */

SECTIONS

{

   /* The startup code goes first into FLASH */

  .isr_vector :

  {

    . = ALIGN(4);

    KEEP(*(.isr_vector)) /* Startup code */

    . = ALIGN(4);

  } >FLASH


  /* The program code and other data goes into FLASH */

  .text :

    . = ALIGN(4);

  {

    *(.text)           /* .text sections (code) */

    *(.text*)          /* .text* sections (code) */

    *(.rodata)         /* .rodata sections (constants, strings, etc.) */

    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */

    *(.glue_7)         /* glue arm to thumb code */

    *(.glue_7t)        /* glue thumb to arm code */


    KEEP (*(.init))

    KEEP (*(.fini))


     . = ALIGN(4);

    _etext = .;        /* define a global symbols at end of code */

  } >FLASH


  /* .ARM.extab names a section that contains exception unwinding information.  See EHABI for details. */

  /* .ARM.exidx names a section that contains index entries for section unwinding.  See EHABI for details. */

   .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH

    .ARM : {

    __exidx_start = .;

      *(.ARM.exidx*)

      __exidx_end = .;

    } >FLASH


  /* Is used for compiler information, which is located only in elf file */

  .ARM.attributes 0 : { *(.ARM.attributes) }


  /* Those sections is used for initializing dynamic objects used in C++ */

 .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


  /* used by the startup as memory location to initialize data */

  /* from this point the content of flash is copied to ram */

  _sidata = .;


  /* Initialized data sections goes into RAM, load LMA copy after code */

  .data : AT ( _sidata )

  {

    . = ALIGN(4);

    _sdata = .;        /* create a global symbol at data start */

    *(.data)           /* .data sections */

    *(.data*)          /* .data* sections */


    . = ALIGN(4);

    _edata = .;       /* define a global symbol at data end */

  } >RAM


  _SRAM_data = _sidata + _edata - _sdata;


  /* Second part of inicialized section goes into SRAM conected thru FSMC */

  /* FSMC_SRAM section, code must be located here explicitly            */

  /* unsigned long int __attribute__ ((section (".sram_data"))) my_initialized_number = 0xAABBCCDD; */

  .fsmc_sram_data : AT ( _SRAM_data )

  {

  . = ALIGN(4);

    _iSRAM_data = .;        

    *(.sram_data)      

    *(.sram_data*)

    

    . = ALIGN(4);

    _iSRAM_data_end = .;   

  } >FSMC_SRAM

  

  .fsmc_sram_bss : AT ( _iSRAM_data_end )

  {

    _iSRAM_null_data = .;       

    *(.sram_bss)

    *(.sram_bss*)

    

    . = ALIGN(4);

    _iSRAM_null_data_end = .;

  } >FSMC_SRAM

  

  .fsmc_sram_perma : AT ( _iSRAM_null_data_end )

  {

    _iSRAM_perma_data = .;       

    *(.sram_perma)

    *(.sram_perma*)

    

    . = ALIGN(4);

    _iSRAM_perma_data_end = .;

  } >FSMC_SRAM

  

   /* Uninitialized data section */

  . = ALIGN(4);

  

  .bss : AT ( _edata )

  {

    /* This is used by the startup in order to initialize the .bss secion */

    _sbss = .;         /* define a global symbol at bss start */

    __bss_start__ = _sbss;

    *(.bss)

    *(.bss*)

    *(COMMON)


    . = ALIGN(4);

    _ebss = .;         /* define a global symbol at bss end */

    __bss_end__ = _ebss;

  } >RAM

  

  /* Those numbers are used for SRAM init */

  PROVIDE ( _linker_sram_start = _iSRAM_data );

  PROVIDE ( _linker_sram_data_end = _iSRAM_data_end );

  PROVIDE ( _linker_sram_end = _iSRAM_null_data_end );

  PROVIDE ( _linker_sram_inits = _SRAM_data );

  

  /* Those numbers are used for malloc and sbrk functions */

  PROVIDE ( _linker_memory_start = _sdata );

  PROVIDE ( _linker_heap_start = _ebss );

  PROVIDE ( _linker_heap_end = (_estack - _Min_Stack_Size) );

  PROVIDE ( _linker_memory_end = _estack );

  PROVIDE ( _end = _ebss );


   /* User_heap_stack section, used to check that there is enough RAM left */

  ._user_heap_stack : AT ( _linker_heap_end )

  {

    . = ALIGN(4);

    . = . + _Min_Heap_Size;

    . = . + _Min_Stack_Size;

    . = ALIGN(4);

  } >RAM


 /* FLASH memory area for factory default values                          */

  /* Example of usage: extern int foo(void) __attribute__ ((section (".fvtext"))); */

  /* unsigned long int my_factory_number_changed_in_production = 0xAABBCCDD __attribute__ ((section (".fvrodata"))); */ 

  .factory_values :

  {

    . = ALIGN(4);

    *(.fvtext)        /* .fvtext sections (code) */

    *(.fvtext*)       /* .fvtext* sections (code)  */

    *(.fvrodata)      /* read-only data (constants) */

    *(.fvrodata*)

    . = ALIGN(4);

  } >FACTORY_VAR


  /* Remove information from the standard libraries */

  /DISCARD/ :

  {

    libc.a ( * )

    libm.a ( * )

    libgcc.a ( * )

  }

}





'devel > man & example' 카테고리의 다른 글

man page 비슷한거  (0) 2016.11.30
gcc inline assembly  (0) 2016.08.11
arm stm32f4xx software interrupt handler 만들기  (0) 2016.08.09
arm assembly byte swap 예제 분석  (0) 2016.04.13
dev file  (0) 2015.08.04
Posted by 쵸코케키

arm gcc 기준

아주 좋은 참고 링크

http://www.joinc.co.kr/w/Site/Embedded/Documents/LinuxKernelStudyForSystemenginer/app3.basic.html

https://wiki.kldp.org/wiki.php/DocbookSgml/GCC_Inline_Assembly-KLDP


작성해주신 고마운 분들에게 감사를



cmsis 라이브러리 예제 파일들

cmsis_gcc.h

io.h

그 외 linux kernel /arch/arm/include/asm/*

arch/x86/include/asm/*

들이 있다


__attribute__((always_inline)) static inline uint32_t test_return(void)
{
    uint32_t    ret;

    __asm volatile (
        "MOV %0, #41 \n"
        : "=r" (ret)                    //return value
    );

    return ret;
}

uint32_t test_return(void)
{
    uint32_t ret;

    ret = 41;

    return ret;
}
__attribute__((always_inline)) static inline uint32_t test_arg_return(uint32_t arg)
{
    uint32_t    ret;

    __asm volatile (
        "MOV %0, %1 \n"
        : "=r" (ret)                    //write only, return value
        : "r"    (arg)
    );

    return ret;
}

uint32_t test_arg_return(uint32_t arg)
{
    uint32_t ret;

    ret = arg;

    return ret;
}
__attribute__((always_inline)) static inline uint32_t test_arg_return(uint32_t arg, uint8_t *addr)
{
    uint32_t    ret;

#if 0
    //이런식으로 r3 레지스터를 직접 지정할 수 있다, 그리고 인자도 여러개 쓸 수 있다    
    __asm volatile (
            "LDRB    r3, %2 \n"
            "MOV %0, r3 \n"
            : "=r" (ret)                    //return value?"
            : "r" (value), "Q" (*addr)
    );

#else
    //포인터에서 값을 읽어 변수에 대입할 수도 있다
    uint32_t    tmp;

    __asm volatile (
            "LDREXB    %1, %3 \n"
            "MOV %0, %1 \n"
            : "=r" (ret), "+r" (tmp)                    //return value?"
            : "r" (value), "Q" (*addr)
    );
#endif


    return ret;
}


uint32_t test_arg_return(uint32_t arg, uint8_t *addr)
{
    uint32_t ret;

#if 0
    ret = *addr;
#else
    uint32_t tmp;

    tmp = *addr;
    ret = tmp;
#endif

    return ret;
}
__attribute__((always_inline)) static inline uint32_t core_test(uint8_t value, volatile uint8_t *addr)
{
    uint32_t    ret;
#if 1
    __asm volatile (
            "LDRB r3, %2 \n"
            "MOV %0, r3 "
            : "=r" (ret)                    //return value?"
            : "r" ((uint32_t) value), "Q" (*addr)
    );
#else
    //uint32_t    tmp;

    __asm volatile (
            "STREXB %0, %2, %1"
            : "=r" (ret), "=Q" (*addr)
            : "r" ((uint32_t) value));
#endif

    return ret;
}


Posted by 쵸코케키

소프트 인터럽트 핸들러

software interrupt

SVCall을 사용해서 구현


#0. 구현 부터 시작

- a. linker script 확인

section 정의에 interrupt vector 가 잘 정의 되어있는지 체크

/* Sections */

SECTIONS

{

/* The startup code into ROM memory */

.isr_vector :

{

. = ALIGN(4);

KEEP(*(.isr_vector)) /* Startup code */

. = ALIGN(4);

} >ROM

...

	/* Sections */
	SECTIONS
	{
		/* The startup code into ROM memory */
		.isr_vector :
		{
		. = ALIGN(4);
		KEEP(*(.isr_vector)) /* Startup code */
		. = ALIGN(4);
		} >ROM

- b. interrupt vector 잘 선언되어 있는지 확인

Drivers/CMSIS/ST/STM32xxxx/Source/Templates/gcc/startup_stm32xxxxxx.s

  .section  .isr_vector,"a",%progbits

.type  g_pfnVectors, %object

.size  g_pfnVectors, .-g_pfnVectors 


g_pfnVectors:

.word  _estack

.word  Reset_Handler

.word  NMI_Handler

... 생략 ...

.word  0

.word  SVC_Handler

Vector Table :D022708, 39p 표 참조

@@

offset이 역순으로 나와있는 것에 주의

SVC_Handler가 정확한 위치에 잘 선언되어 있다

- c. SVC_Handler 구현

stm32f4xx_it.h 에 void SVC_Handler(void); 선언

stm32f4xx_it.c 에 void SVC_Handler(void) 정의

이 파일을 보면 각종 interrupt/Exception handler 들이 정의되어 있다

인제 SVC 명령이 호출되면 이 핸들러가 실행이 된다~!!

궁금하면 핸들러에 led 점멸이나 uart 메세지 보내는 것을 사용해서 시험이 가능하다

Exception 발생하면 core 하드웨어가 자동으로 stack에 일부 register들을 백업한다

그 후 exception handler가 실행된다

그와 동시에 EXEC_RETURN 값이 LR에 기록된다

EXEC_RETURN는 Exception이전에 어떤 mode 상태에서 돌고 있다가 handler로 들어왔는지 알 수 있는데

적당히 모드 보고 MSP를 참조하든 PSP를 참조하든 알아서 해라라는 소리

이하의 내용은 'd. svc 호출' 항목을 참조한 뒤 보면 좋다

stack에는 r0-r3, r12, LR, PC, xPSR 이 들어가 있다

r0에는 우리가 필요한 void* data 가 들어가 있다

svc와 함께 전달되는 imm 8bit 숫자는 r1에서 읽어도 되고 다른 방법으로 추출 해도 된다

일단 필요한게 r0 인자값이랑 SVC와 같이 넘어온 imm값

이 두가지를 알기 위해 r0가 잠들어 있는 stack pointer가 필요하다

그런데 sp를 알기 위해선 arm core가 thread mode에서 넘어왔는지 process mode에서 넘어왔는지 구분을 해야 한다

(간단하게 설명하면 os 유/무 mode 구분) 

위에서 이걸 EXEC_RETURN으로 알 수 있다는 것을 안다

참고 : http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0203ik/BABFGEFG.html

참고 : ITE 구문 http://trace32.com/wiki/index.php/If-Then


아래의 코드를 보면 이해가 될꺼다 

msp - 0xFFFF FFF9, 9(1001)

psp - 0xFFFF FFFD, D(1101)

그래서 TST로 LR을 4(0100) 와 비교한다

void SVC_Handler(void)

{

__asm volatile(

"TST lr, #4 \n" //if(LR & 0x4) { Z=1 } else { Z=0 } update C, N flag

"ITE EQ \n" //if then else(ITE) if(Z==1 /*EQ*/) { MRSEQ } else { MRSNE }

"MRSEQ r0, MSP \n" //conditional execution (Z==1) - for thread mode

"MRSNE r0, PSP \n" //conditional execution (Z==0) - for process mode

"B SVC_Handler_main"

);

}


	void SVC_Handler(void)
	{
		__asm volatile(
				"TST lr, #4 \n"			//if(LR & 0x4) { Z=1 } else { Z=0 } update C, N flag
				"ITE EQ \n"			//if then else(ITE) if(Z==1 /*EQ*/) { MRSEQ } else { MRSNE }
				"MRSEQ r0, MSP \n"		//conditional execution (Z==1) - for thread mode
				"MRSNE r0, PSP \n"		//conditional execution (Z==0) - for process mode
				"B SVC_Handler_main"
		);
	}

process mode 자체를 안 쓴다면 아예 그냥 MRS r0, MSP랑 B svc_main_handler 구문만 남겨도 ok

SVC_Handler_main 구현은 뒷쪽에 이어서

- d. SVC 호출 : DDI0403EB, 455p 

SVC<c><q> #<imm8>

cq는 일단 생략

imm8 - immediate 8bit 즉 8bit 숫자

gcc inline assembly 기준

__asm volatile (

"SVC #2"

);

이런식으로 호출 가능, handler 쪽에서는 숫자2를 같이 건네 받음

인자로 imm 값을 건네고 싶을 때 다음과 같이 구현가능

__attribute__((always_inline)) static inline void invoke_exception(uint8_t value)

{

__asm volatile (

"SVC %0"

:

: "i" (value) //imm

);

}

만약 인자 1개를 추가로 같이 보내고 싶다고 가정하면 형태가 많이 변경된다

exception이 발생하면 하드웨어적으로 아래의 register들을 stack에 백업한다

@@ D022708, 42p

그리고 함수를 호출하면 인자 4개 까지는 r0 - r3 레지스터에 들어간다

예를 들면 void test(int a, unsigned char b, char* c, void* d)

r0 = a, r1 = b, r2 = c, r3 = d

이렇게 들어간채로 함수가 불리는데 이게 바로 calling convention

Parameter Passing, AAPCS(Arm Architecture Procedure Call Standard) 18p 

그래서 SVC 호출과 함께 맘대로 인자를 보내고 싶다면 함수내에서 SVC 호출을 하면 된다

뭔소린고 하니

#define svc(code) asm volatile ("svc %[immediate]"::[immediate] "i" (code))

#define SVC_TYPE1 0x01

#define SVC_TYPE2 0x02

__attribute__ ((noinline)) int invoke_exception(void *data, uint8_t immnum)

{

switch(immnum)

{

case SVC_TYPE1:

svc(SVC_TYPE1);

break;

case SVC_TYPE2:

svc(SVC_TYPE2);

break;

default:

return -1;

}


return 0;

}

아름다운 구현 방법이 있다면 좋겠는데 이 이상의 방법을 찾지 못하겠다

참고

https://falstaff.agner.ch/2013/02/18/cortex-m3-supervisor-call-svc-using-gcc/

같은 고민을 하는 분들

http://stackoverflow.com/questions/11377453/using-gcc-inline-assembly-with-instructions-that-take-immediate-values

inline mode는 함수를 풀어버리기 때문에 함수를 통해 인자를 받아야 하는 우리는 __attribute__((noinline))을 꼭 선언해줘야 한다

invoke_exception 함수를 호출하면 r0에 void* data 가 들어가게 되고

이 후 svc 호출로 r0는 stack에 들어가게 된다

svc와 함께 전달되는 imm 8bit 숫자는 r1에서 읽어도 되고 다른 방법으로 추출 해도 된다

호출은 일단 했으니 이 후의 내용은 '이전 c. SVC_handler' 항목을 참조

- e. SVC_Handler_main 상세 구현

SVC_Handler를 통해 r0에 MSP(stack pointer)를 얻어왔다

그리고 B SVC_Handler_main을 통해 다시 함수로 이동해 왔다

void SVC_Handler_main(void *svc_args)

{

unsigned int svc_number;


if(svc_args == NULL)

return ;


svc_number = ((char *) ((unsigned int*)svc_args)[6])[-2]; //imm

void* arg = (void*) ((unsigned int*)svc_args)[0];

}


현재 상태

r0 == void *svc_args == MSP

우리가 필요한 건 MSP에 저장되어 있는 r0(void *data)

그러므로 

void *arg = (void *) ((unsigned int*) svc_args)[0];

unsigned int*로 type casting 하는 이유는 register 크기가 32bit 니까

만약에 r1을 얻고 싶다면 ((unsigned int*) svc_args)[1]; 하면 된다

svc_number 즉 svc 랑 같이 보낸 imm 추출은 좀 더 많이 복잡하다

svc 명령 중 하위 8bit가 imm 이다

일단 svc 명령이 어떻게 내려졌는지 그걸 가져오고 그 다음 하위 8bit 를 구해서 imm을 획득하자

svc 명령이 불려지면 핸들러가 실행되기 전에 레지스터들이 백업 되는데 PC값에는 return address 

다시 말해 svc 명령 다음 실행 위치가 들어가 있다

그럼 PC - 2 하면 svc 명령 위치가 나오겠네?

PC = ((unsigned int *) svc_args)[6]

SVC 명령 위치 = ((unsigned int*) svc_args)[6] - 2

SVC 명령 = *(uint16_t *) (((unsigned int*) svc_args)[6] - 2)

svc 명령이 16bit 니까 (uint16_t *)로 type casting

이 값을 16진수로 뽑으면 0xDF## 이 된다

imm = SVC 명령 & 0xff

실제 연산하기 위해서는 16bit 포인터로 변환

unsigned int* pc_address = ((unsigned int*) svc_args)[6];

uint16_t* svc_address = pc_address - 2;

uint16_t svc = *(uint16_t *) svc_address; 

uint8_t svc_number = svc & 0xff;

이렇게 해도 되는데 이걸 짧게 줄이면

svc_number = ((char *) ((unsigned int*) svc_args)[6])[-2];

svc_number = ((char*) pc_address)[-2]

대충 메모리 구조 보면

[   ...    pc   ]

[  svc  \  imm  ]

\       \       \-->  svc 시작 주소값 == pc 시작 주소값 - sizeof(uint8_t)x2 == &((char*) pc_address)[-2]

\       \-->  svc 시작 주소값 + sizeof(uint8_t) == svc 주소값 + 1 

\-->  pc 주소값 == svc 끝 주소값 == svc 시작 주소값 + sizeof(uint8_t)x2



가능하면 쉽게 쓰려고 노력했는데 가독성이 영 꽝인거 같다




기타 관련 개념들


# ARMv7에는 A시리즈도 있고 R 시리즈도 있고 M 시리즈도 있는데 이놈들이 거의 같긴 한데 다른 부분들이 있다

그래서 예제같은거를 대충 가져와서 쓴다고해서 돌아가는게 아니라 정확하게 맞는 시리즈에 적용해야 된다


좋은 예제 리스트

linux kernel source의 

arch/arm/include/asm/io.h 등 기타 여러가지

arch/x86/include/asm/io.h



ARMv7-M Architecture Reference Manual - dmIO403E_B, 569p

Supervisor call(SVCall)

An exception caused explicitly by the SVC instruction. Application software uses the SVC instruction

to make a call to an underlying operating system. This is called a Supervisor call. The SVC instruction

enables the application to issue a Supervisor call that requires privileged access to the system and

executes in program order with respect to the application. ARMv7-M also supports an

interrupt-driven Supervisor-calling mechanism



579p

Interrupt Control and State Register - ICSR, 655p


# The Vector Table - 581p

The vector table contains the initialization value for the stack pointer, and the entry point addresses of each

exception handler

word offset in table - Exception using that Exception Number


그래서 linker descriptor 파일 보면

section에 isr_vector 정의했고 startup_stm32f479xx.s 파일 보면

.section  .isr_vector,"a",%progbits

  .type  g_pfnVectors, %object

  .size  g_pfnVectors, .-g_pfnVectors 

  

  g_pfnVectors:

  .word  _estack

  .word  Reset_Handler

  .word  BusFault_Handler

   ... 생략

  .word  SVC_Handler

  .word  DebugMon_Handler

  .word  0

  .word  PendSV_Handler

  .word  SysTick_Handler

  

  할당은 이렇게 해놓았고

  stm32f4xx_it.c 여기에 void BusFault_Handler(void); 함수 정의 

  stm32f4xx_it.h 여기에도 선언 추가

  


  http://egloos.zum.com/recipes/v/5037342

  http://www.thewireframecommunity.com/writing-a-basic-multitasking-os-for-arm-cortex-m3-processor

  http://stackoverflow.com/questions/24162109/arm-assembly-code-and-svc-numbering

  https://falstaff.agner.ch/2013/02/18/cortex-m3-supervisor-call-svc-using-gcc/

  

  ARMv7m pdf, 455p SVC 상세 이용법

  svc<c><q> #<imm>

  <c><q> - 

  imm - immediate constant

  

#Exception entry behavior 587p




이해하기 앞서 선행 정보 간단 요약

엄청 기니까 대충 넘겼다가 나중에 봐도 ok


Processor Mode : D022708 16p

thread mode

기본 사용 모드

handler mode

exception 처리할 때 사용된다. 처리 끝나면 다시 thread mode로 복귀


STACK

full descending stack

아래 방향으로 증가한다고 생각하면 편할듯

새 아이템을 스택에 넣으면 sp는 되려 감소한다

그리고 새 메모리 위치에 아이템을 기록한다

stack에는 2가지 종류가 있는데 main stack, process stack이 있다

thread mode 에서는 core가 어떤 stack을 쓸지 CONTROL register에 의해 결정할 수 있다

handler mode 에서는 항상 main stack을 사용한다(msp)


SP(R13) - Stack Pointer : D022708 18p

MSP(main stack pointer)

PSP(process stack pointer) - os 있을 때 context switching 용도로 사용

위의 내용들 참고


LR(R14) - Link Register 

subroutine이나 함수 호출, exception 에서 돌아갈 정보를 저장한다


PC(R15) - Program Counter

현재 프로그램 주소를 담고 있음


APSR - Application Program Status Register : 20p

명령어 실행하는 동안 발생한 상태 정보에 대해 나와있음. 표 참조

@@


Exception Priority : 37p, DDI0403EB 584p

SVC의 우선 순위는 SHPRx(System Handler Priority Register) 에서 설정 가능

exception 순위가 낮으면 높은 handler에게 preemption 선점 당할 수 있음

그 와중에 낮은 순위의 exception이 들어오면 pending 된 상태로 대기

 

Exception 종류 및 IRQ와의 관계 - D022708 36-39p

Vector Table


SHPRx - System Handler Priority Register : D022708 323p

exception 들의 priority 를 설정 가능

아마도 작을 수록 높은 우선 순위를 갖는 것 같다

(명시 되어있는 것은 못 찾겠으나 IRQ의 경우도 그렇고 37p의 Table. 16을 보면 -3 reset이 highest priority다)

 

Exception Entry - Exception이 발동하면? : 41p

Stack Frame Layout : 42p

@@ 


Exception return - EXEC_RETURN : D022708, 43p 

EXEC_RETURN은 exception 진입할 때 LR에 들어가는 값이다

@@



'devel > man & example' 카테고리의 다른 글

gcc __attribute__ section 지정으로 직접 변수 기록될 영역 고정하기  (0) 2016.08.11
gcc inline assembly  (0) 2016.08.11
arm assembly byte swap 예제 분석  (0) 2016.04.13
dev file  (0) 2015.08.04
ioctl  (0) 2012.07.26
Posted by 쵸코케키

arm 어셈블리 코드 선행 지식

대충 아는 분들은 아래로 죽 넘겨버리면 ok


c code

val = *addr;


gcc inline assembly

asm (

"ldr %0, [%1]"

: "=r"(val)

: "r" (addr)

);


':'이게 뭘까? 

: output operand list(register to memory)

: input operand list(memory to register)

: clobber list(temporary variables, 컴파일러가 맘대로 못 쓰게 할 수 있음, 생략가능)


%0, %1, %2 .... output 부터 시작해 input에 나열된 변수 순서 대로 번호가 할당된다

예를 들어

: "=d (res)", "=&c" (d0), "=&D" (d1), "=&a" (d2) 이런게 가능


Constraints(info gcc 해서 ::Constraints 로 확인 가능)

: "0"(val) - src랑 dst를 같은 register쓰도록 강제(input, output)

0~9 등등 가능 아마도 %0을 같이 쓴다 이런 의미일듯

= output only variables(write only)

r  register

등등 많다


Operand 2(Flexible second operand)

예제

mov r0, r1, lsl #3

r0 = r1<<3;



바이트 스왑 어셈블리 코드 

0x12345678 -> 0x78563412

unsigned long ByteSwap(unsigned long val)

{

asm volatile (

"eor     r3, %1, %1, ror #16        \n\t"

"bic     r3, r3, #0x00FF0000        \n\t"

"mov     %0, %1, ror #8            \n\t"

"eor     %0, %0, r3, lsr #8          \n\t"

: "=r" (val)

: "0"(val)

: "r3"

);


return val;

}

 

%0 -> 함수 인자 val변수 (ldr r0, &val 대충 이런 느낌)

%1 -> %0과 동일


eor r3, %1, %1, ror #16

r3 = 12345678 ^ 56781234

= 444C444C


bic r3, r3, #0x00FF0000

r3 = r3 & 0xFF00FFFF

r3 = 444C444C & 0xFF00FFFF

= 4400444C


mov %0, %1, ror #8

%0 = 78123456 

  

eor %0, %0, r3, lsr #8

%0 = %0 ^ (r3 >> 8)

= 78123456 ^ 00440044

= 78563412



이게 가능한 이유?

XOR의 특징 : a ^ b = c -> c ^ b = a


일단 byte swap의 규칙을 찾아보자

0x1234ABCD -> 0xCDAB3412

34랑 CD는 ror 8회 하면 된다

AB랑 12는 rol 8회 하면 된다

걍 ror 8회 하고 0xFF00FF00 이랑

rol 8회 하고 0x00FF00FF랑 or 하면 안되나요?

-> operand 2 에 constant 제약 때문에 안될듯? 아닌데 제약 범위 이내던데???



처음 eor 코드에서 일종의 백업을 한다 이제 r3는 원본인 %1과 ^를 하면 언제든지 ror 16회 된 데이터를 뽑아올 수 있다


bic(not and)를 사용해 체를 걸러낸다 왜 굳이 not을 하고 and를 해야했을까?

이제 FF00FFFF 에서 00 부분을 제외했기 때문에 ror 16회 한 56781234에서 56xx1234만 복원이 가능하다


FF00FF00 혹은 00FF00FF 형태로 만든 것과 ror 8 혹은 rol 8 한 값과 

으메 모르겠다........



기타 추천 링크

http://xenostudy.tistory.com/206



'devel > man & example' 카테고리의 다른 글

gcc inline assembly  (0) 2016.08.11
arm stm32f4xx software interrupt handler 만들기  (0) 2016.08.09
dev file  (0) 2015.08.04
ioctl  (0) 2012.07.26
const  (0) 2012.07.21
Posted by 쵸코케키

2015. 8. 4. 14:29 devel/man & example

dev file

 

 

'devel > man & example' 카테고리의 다른 글

arm stm32f4xx software interrupt handler 만들기  (0) 2016.08.09
arm assembly byte swap 예제 분석  (0) 2016.04.13
ioctl  (0) 2012.07.26
const  (0) 2012.07.21
#define function macro  (0) 2012.07.15
Posted by 쵸코케키

2012. 7. 26. 17:13 devel/man & example

ioctl

ioctl이 뭐하는 녀석이지? 하는 궁금증이 많았는데 친절하고 구체적으로 나와있는글이 거의 없더라

http://wiki.kldp.org/KoreanDoc/html/EmbeddedKernel-KLDP/device-understanding.html

그러다가 위의 링크를 읽어보니 아하~ 하고 깨닫게 되었다

 

int main()
{
int fd; char buf[256];

fd = open("/dev/hdd_info", O_RDWR);
ioctl(fd, 0, buf);

printf("buf : %s\n", buf);
close(fd);
return 0;
}

 

위의 kldp 링크 중에 나와있는 소스코드이다(살짝 수정을 했다 좀...)

open으로 장치 하나 열어서

ioctl로 장치에게 동작 명령 내리고

출력하고 다시 장치 닫는다

 

 

ioctl은 장치에게 그냥 이미 정의되어있는 명령을 내리는(함수를 호출하는) 놈이라는 것을 알게 되었다

대신 장치를 우선 open으로 열고 인자로 그 file descriptor랑 가운데 request number를 넣어서 어떤 함수를 호출할지를 정하는듯

 

그런데 동일한 ioctl을 사용하는데 어떻게 장치마다 각기 다른 function을 호출 할 수 있지?

예를 들면 A파일을 열어서 ioctl에 0req#을 넣어서 하는 행위랑 B파일을 열어서 ioctl에 0req#을 넣어서 하는 행위가 어떻게 다르게 되는거지? (혹은 같게)

 

 

 

미리 device driver에 그런거 등록해놓는듯

 

 

가장 위의 링크를 보니까 struct file_operations에 미리 여러가지 말 그대로 file operation들을 등록할 수 있는데

struct file_operations Fops = {
NULL,
NULL,
hddinfo_read,
NULL,
NULL,
NULL,
hddinfo_ioctl,
NULL,
hddinfo_open,
NULL,
hddinfo_release
};
이런식으로 자기가 쓰고 싶은 놈들을 function 등록 ㅇㅇ

struct니까 멤버 위치당 역할은 고정

위의 코드를 디바이스 드라이버에 작성하고

(Fops와 Fops structure에 포함 등록 되어있는 function들을 정의)

 

insmod한 다음에 이제 유져 프로그램에서 ioctl 하면 그게 인쟈 잘 된다 이런 내용인듯

그렇다면 dd에는 하드웨어 접근 코드들을 넣으면 되겠구나 하는 생각이 들기도 하고

어느정도 권한까지 있으려나

 

여튼 kldp가 짱!짱!

'devel > man & example' 카테고리의 다른 글

arm assembly byte swap 예제 분석  (0) 2016.04.13
dev file  (0) 2015.08.04
const  (0) 2012.07.21
#define function macro  (0) 2012.07.15
#define 문자열 치환 및 합치기  (0) 2012.07.15
Posted by 쵸코케키

2012. 7. 21. 07:13 devel/man & example

const

int test=70;

const int* ptr = &test;

test=30;

 

*ptr = 30 -> x

 

 

 

int* const ptr=&test;

*ptr = 70

 

ptr=&date -> x

'devel > man & example' 카테고리의 다른 글

dev file  (0) 2015.08.04
ioctl  (0) 2012.07.26
#define function macro  (0) 2012.07.15
#define 문자열 치환 및 합치기  (0) 2012.07.15
strstr  (0) 2012.01.28
Posted by 쵸코케키

#define SQUARE(X) ((X)*(X))

괄호를 마구 치는 이유

 

-> #define sq(x) (x)*(x) 라고 가정하면

 

int num = 120 / sq(2)

-> 120 / 2 * 2

연산자 우선 순위에 의하여 차례로 들어간다

그런고로 120이 num에 저장된다

 

 

크기가 작은 함수, 그리고 호출의 빈도수가 매우 높은 함수를 macro로 정의하는 것이 좋다고 한다

 

 

출처 : 윤성우의 열혈 C 프로그래밍

 

'devel > man & example' 카테고리의 다른 글

ioctl  (0) 2012.07.26
const  (0) 2012.07.21
#define 문자열 치환 및 합치기  (0) 2012.07.15
strstr  (0) 2012.01.28
arm inline assembly  (0) 2011.12.24
Posted by 쵸코케키

출처 : 윤성우의 열혈강의

Preprocessor 항목 부분

 

책을 친구에게 주려고 필요한 부분은 발췌해서 정리 헤헷

 

 

#include <stdio.h>

#define STRING_JOB(A, B) #A "의 직업은 " #B "입니다."

 

int main()

{

printf("%s, \n", STRING_JOB(으아아아, 떨어진드아아아아));

return 0;

}

 

 

 

# operator 역할

#define STRCAT(ABC) #ABC

STRCAT의 argument ABC를 문자열ABC로 치환한다

 

more tip

문자열은 나란히 선언하면, 하나의 문자열로 간주가 된다.

따라서 다음과 같이 문자열을 선언하는 것도 가능하다.

char* str="ABC" "DEF";

이는 다음과 동일하다

char* str="ABCDEF";

char* str=STRCAT(12) STRCAT(34);

 

 

 

문자열을 잇고 싶습니다

## operator

 

#define CON(UPP, LOW) UPP ## 00 ## LOW

int num = CON(22, 77);

-> 선행처리기에 의하여 컴파일 이전에 다음과 같이 치환된다

 

 

int num = 220077;

data type이 int형임을 유의깊게 보시오

 

 

'devel > man & example' 카테고리의 다른 글

const  (0) 2012.07.21
#define function macro  (0) 2012.07.15
strstr  (0) 2012.01.28
arm inline assembly  (0) 2011.12.24
thread starvation  (0) 2011.12.09
Posted by 쵸코케키
이전버튼 1 2 이전버튼

블로그 이미지
chocokeki
쵸코케키

공지사항

Yesterday
Today
Total

달력

 « |  » 2024.5
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

최근에 올라온 글

최근에 달린 댓글

글 보관함