2013-04-22 6 views
2

ARM 기반 마이크로 컨트롤러에서 SVC 호출을 작성하는 올바른 방법을 알고 싶습니다.자신의 SVC 작성 ARM 어셈블리 호출

나의 이해는 지금까지 ARM은 모든 프로그램의 첫 번째 지침은 적절한 핸들러로 분기해야한다는 것을 의미, 예외 벡터 테이블을 가지고 있다는 것입니다 :

RESET   ;Handles reset 
UNDEFINED  ;Undefined instructions 
SVC    BL   SVC_Entry 
PRE_ABORT  ;Prefetch abort 
DAT_ABORT  ;Data abort 

그런 때마다이 SVC 명령어가 실행 된 것입니다 , 모드는 SVC와 함께 제공되는 수는 R0에 저장되고, 관리자로 전환되고 프로그램은 적절한 핸들러로 분기 것이다 :

;== Handling SVC calls ======================================================== 

Max_SVC  EQU 1 

SVC_Entry CMP R0, #Max_SVC   ;Check upper limit 
      BHI SVC_end     ;Does nothing if unknown  
      ADD R0, PC, R0, LSL #2  ;Calculate table address 
      LDR PC, [R0, #0]   

Jump_table DEFW SVC_0     ;Halt 
      DEFW SVC_1     ;Print string 

;== SVC calls ================================================================ 

SVC_1  B SVC_end 

SVC_end  MOVS PC, LR   ;Exiting 

그래서 우리는이 지침이있는 경우 :

프로그램은 감독자 모드로 전환하고 숫자 "1"을 R0에 저장 한 다음 점프 테이블 분기를 따라 SVC_1에 코드를 실행하고 사용자 모드로 다시 전환해야합니다.

이 정보가 맞습니까? 내가 제대로하고 있니? 지금까지이

문제는 내 컴파일러는이 라인을위한 "연산자 예상"라는 점이다 :이 주제에

SVC    BL   SVC_Entry 

정보는 인터넷에서 찾을 어렵다 난 그냥 알고 싶어

방법을 제대로 ARM 마이크로 컨트롤러에서 SVC 호출을 사용합니다.

대단히 감사합니다.

편집 : 기본 프로세서는 약 240MHz의 ARM9 클록 킹입니다. 이것은 AT91 마이크로 컨트롤러에 있습니다. 연구실 게시판은 내 대학의 필요에 맞게 수정되었습니다.

코드는 직렬 포트를 통해 맞춤식 프로그램을 사용하여 보드에로드됩니다. 이 프로그램은 또한 디버깅을 허용합니다.

+0

어떤 마이크로 컨트롤러 또는 제품군을 타겟팅합니까? arm7tdmi? 피질 -m? –

+0

'SVC : B SVC_Entry'와 같은 것이 필요합니다. ':'콜론은 그것을 레이블로 만든다. 'svc_vec : b SVC_Entry'와 같이 ** svc_vec **로 이름을 짓는 것이 좋습니다. 다른 문제는 ** BL **을 사용하면 * 사용자 * 반환 주소를 삭제합니다. 당신은'R0' 또는 당신이 수립하고자하는 컨벤션을 사용할 수 있습니다; 일반적으로 지침을 검토하는 것이 일반적으로 느립니다. ** 수퍼바이저 ** 스택 및 모드를 설정하는 것을 잊지 마십시오. * 사용자 * 레지스터를 변경하기 전에 저장하는 것이 좋습니다. * 호출 규칙 *에서 정의하지 않는 한. –

+0

@dwelch 전통적으로 SVC 호출 번호는 op 코드로 인코딩되었습니다 (이것이 ROSCOS에서 도토리가 사용했던 방법입니다). 그러나 ARM Linux와 iOS는 모두 레지스터로 전달합니다. Harvard 아키텍처를 사용하는 모든 ARM 장치의 성능 지점에서 4 바이트 만 읽을 가능성이있는 라인으로 D 캐시를 오염시키지 않아도됩니다. , 및 대응하는 캐시 - 라인 필을 포함한다. – marko

답변

4

마찬가지로 BL을 사용하여 SVC 항목으로 이동하고 B를 사용하십시오. 먼저 SVC 번호를 결정하는 루틴을 갖습니다. (제 이름은 SVC_dispatcher입니다.) 어떤 대학에 있습니까? 나는 당신이 얼마나 많이 모르고 있는지에 대해 아무런 가정을하지 않고 철저히 설명하려고 노력할 것입니다. 나는 정확한 설명을 넣었으므로 내 의견이 명확하지 않거나 더 깊이 알고 싶다면 더 많은 정보를 얻을 수 있습니다. 나는 콜론을 사용한 라벨링 방법을 확신 할 수 없다. 나는 오래된 명령어 세트에 익숙하다.

행운

SVC_dispatcher 
      PUSH {LR}    ; always save your LR 
      LDR  R14, [LR, #-4] ; its been stacked, so we can it (LR is R14) 
    ; the link register is the line after the SVC instruction 
    ; above, we load the instruction that is one before the 
    ; link register (#-4 preindexed load) means instruction (SVC 1) into R14.      

    ; Use bit clear to remove the mnemonic from the 32 bit instruction, 
    ; leaving the data (1)  
      BIC  R14, R14, #&FF000000 

SVC_entry 
      CMP  R14, #Max_SVC 
      BHI  SVC_unknown 
      ADR  R1, Jump_Table  ; use this format, never add to the PC 
      LDR  PC, [R1, R14, LSL #2] 
     ; Beware: PC can be changed by IRQs **AT ANY TIME** 

Jump_Table         ; you know the drill here 
      DEFW SVC_0    
      DEFW SVC_1 

SVC_0  B  SVC_end 

SVC_1  BL  printString  ; consider stacking registers that printString 
      B  SVC_end   ; will corrupt 

SVC_end  POP  {LR}   ; restore link register 
      MOV  PC, LR   
2

그냥 해명 위 Yoker의 대답 보완 : 당신이 언급 한대로 SVC 명령어에서 전통적으로 번호 R0에 저장되지 않습니다 Yoker의 대답 쇼의 예를 들어

을 (귀하의 질문에), 당신은 svc 명령에서 즉시 값을 직접 읽어 코드에서 검색해야합니다.이 지침이있는 경우

그렇게하려면, 예를 들어, 단지 리턴 어드레스하기 전에 명령에 대한 포인터를 얻을 필요가 :

0x800010: ADR R1, string  ;R1 points to the string 
0x800014: SVC 1    ;SVC_1 handles the printing 
0x800018: ADD R1, R2   ;The next instruction after the SVC where LR will point to 

반환 주소는 다음 LR = 0x800018 것을 우리 SVC 명령어 LR-4 = 0x800014의 주소를 검색하고 해당 주소 내용 (SVC 1 명령어)을 읽고 그 첫 번째 바이트 만 가져올 수 있습니다 (우리는 svc opcode를 무시하고 즉 치값 만 가져옵니다).

void SVC_Handler(void) 
{ 
    // Get stack pointer, assuming we the thread that generated 
    // the svc call was using the psp stack instead of msp 
    unsigned int *stack; 
    asm volatile ("MRS %0, psp\n\t" : "=rm" (stack)); 

    // Stack frame contains: 
    // r0, r1, r2, r3, r12, r14, the return address and xPSR 
    // - Stacked R0 = stack[0] 
    // - Stacked R1 = stack[1] 
    // - Stacked R2 = stack[2] 
    // - Stacked R3 = stack[3] 
    // - Stacked R12 = stack[4] 
    // - Stacked LR = stack[5] 
    // - Stacked PC = stack[6] 
    // - Stacked xPSR= stack[7] 

    // Thumb instructions have 2 bytes instead of 4, then get 
    // the first byte of the instruction right before the 
    // instruction pointed by the stacked PC 
    unsigned int svc_number = ((char *)svc_args[6])[-2]; 
    switch(svc_number) { 
     case 0: 
      ... 
      break; 
     case 1: 
      ... 
      break; 
    } 
: 여기
LDR  R14, [LR, #-4] 
BIC  R14, R14, #&FF000000 

는 피질 M0 예를 들어 (Thumb 명령어)에서 C 코드를 사용하여 또 다른 예이다 :

그래서, Yoker의 예에서 우리는 바로 그 일을 다음과 같은 지침을 볼 수 있습니다