edk

BootLoader, user jump

xilinx 2012. 2. 2. 05:06

 

2.               요구사항

FPGA 외부에서 microblaze 프로그램을 SREC 형태로 다운로드하고 나면 microblaze 부트로더를 이용해 해당 프로그램을 다시 원하는 위치에 재배치함으로써 프로그램을 실행 시켜야 합니다.

새로운 요구사항으로 다운로드된 프로그램의 실행이 끝나면 다시 부트로더로 돌아갈 있도록 유저 프로그램을 수정해야 합니다.

3.               bootloader 분석

다음 리스트는 edk91에서 제공하는 부트로더의 소스 코드의 일부분 입니다.

static int8_t load_exec ()

{

    int8_t ret;

    void (*laddr)();

    int8_t done = 0;

    int32_t i;

   

    srinfo.sr_data = sr_data_buf;

   

    while (!done) {

        if ((ret = flash_get_srec_line (sr_buf)) != 0)

            return ret;

       

        if ((ret = decode_srec_line (sr_buf, &srinfo)) != 0)

            return ret;

       

#ifdef DISPLAY_PROGRESS

        display_progress (srec_line);

#endif

        switch (srinfo.type) {

            case SREC_TYPE_0:

                 break;

            case SREC_TYPE_1:

            case SREC_TYPE_2:

            case SREC_TYPE_3:

                 memcpy ((void*)srinfo.addr, (void*)srinfo.sr_data, srinfo.dlen);

                 break;

            case SREC_TYPE_5:

                 break;

            case SREC_TYPE_7:

            case SREC_TYPE_8:

            case SREC_TYPE_9:

                 laddr = (void*)srinfo.addr;

                 done = 1;

                 ret = 0;

                 break;

        }

    }

 

    print ("\r\nExecuting program starting at address: ");

    putnum ((uint32_t)laddr);

    print ("\r\n");

    (*laddr)();                

 

    /* We will be dead at this point */

}

Load_exec() 함수에는 함수형 포인터가 선언되어 있습니다.

void (*laddr)();

함수형 포인터는 SREC 디코딩 하는 도중에서 다음과 같은 코드로 초기화 됩니다.

laddr = (void*)srinfo.addr;

Load_exe() 함수 마지막 부분에 함수형 포인터가 지정된 함수를 실행 합니다.

print ("\r\n");

    (*laddr)();    

다음 리스트는 부트로더를 컴파일하고 역어셈블한 결과 입니다. 여기서 보면 microblaze 리셋벡터 값인 0x0에서 0xb80800050이라는 코드가 실행되는되 이것은 0x50번지로 점프하라는 의미 입니다.

 

executable.elf:     file format elf32-microblaze

 

Disassembly of section .vectors.reset:

 

00000000 <_start>:

   0:    b8080050         brai    80      // 50 <_TEXT_START_ADDR>

Disassembly of section .vectors.sw_exception:

 

00000008 <_vector_sw_exception>:

   8:    b80801b0         brai    432     // 1b0 <_exception_handler>

Disassembly of section .vectors.interrupt:

 

00000010 <_vector_interrupt>:

  10:    b80801a8         brai    424     // 1a8 <_interrupt_handler>

Disassembly of section .vectors.hw_exception:

 

00000020 <_vector_hw_exception>:

  20:    b80801b8         brai    440     // 1b8 <_hw_exception_handler>

Disassembly of section .text:

 

00000050 <_start1>:

  50:    31a00ca0         addik   r13, r0, 3232    // ca0 <_SDA_BASE_>

  54:    30400b90         addik   r2, r0, 2960     // b90 <_SDA2_BASE_>

  58:    30201240         addik   r1, r0, 4672

  5c:    b9f400c0         brlid   r15, 192 // 11c <_crtinit>

  60:    80000000         or      r0, r0, r0

  64:    b9f4075c         brlid   r15, 1884        // 7c0 <exit>

  68:    30a30000         addik   r5, r3, 0   

4.               user application 분석

다음 리스트는 일반적으로 사용되는 프로그램 입니다.

void main()

{

 print("xxxxxxxx -- Exiting main() --\r\n");

}

프로그램은 외부 메모리에서 실행되기 위해 링커스크립트가 만들어져 있습니다. 다음 리스트는 컴파일하고 역어셈블한 결과 입니다.

executable.elf:     file format elf32-microblaze

 

Disassembly of section .vectors.reset:

 

00000000 <_start>:

   0:    b0008c00         imm     -29696

   4:    b8080000         brai    0

Disassembly of section .vectors.sw_exception:

 

00000008 <_vector_sw_exception>:

   8:    b0008c00         imm     -29696

   c:    b8080a7c         brai    2684

Disassembly of section .vectors.interrupt:

 

00000010 <_vector_interrupt>:

  10:    b0008c00         imm     -29696

  14:    b8080a98         brai    2712

Disassembly of section .vectors.hw_exception:

 

00000020 <_vector_hw_exception>:

  20:    b0008c00         imm     -29696

  24:    b8080a94         brai    2708

Disassembly of section .text:

 

8c000000 <_start1>:

8c000000:        b0008c00         imm     -29696

8c000004:        31a01d70         addik   r13, r0, 7536

8c000008:        b0008c00         imm     -29696

8c00000c:        30401c20         addik   r2, r0, 7200

8c000010:        b0008c00         imm     -29696

8c000014:        30205da8         addik   r1, r0, 23976

8c000018:        b9f400e4         brlid   r15, 228 // 8c0000fc <_crtinit>

8c00001c:        80000000         or      r0, r0, r0

8c000020:        b9f41254         brlid   r15, 4692        // 8c001274 <exit>

8c000024:        30a30000         addik   r5, r3, 0

앞에서 살펴본 부트로더의 분석결과와 비슷해 보이지만 0x0 번지와 0x04번지를 보면 0xb0008c00 0xb80800000 명령어가 있습니다. Microblaze offset번지가 0xffff 넘어가면 2개의 32비트 코드를 조합해서 명령어를 만드는데 이것을 분석해 보면 0x8c00_0000 번지로 점프하라는 의미 입니다.

그러면 0x00번지 저장되는 값은 부트로더에 의해서는 0xb8080050 이지만 부트로딩이 이루어지고 나면 0xb0008c00으로 바뀌게 됩니다

따라서 유저프로그램이 종료된 다시 부트로더로 돌아가기 위해서는 다음과 같이 수정된 리스트가 필요 합니다.

void main()

{

   void (*laddr)();

   print("xxxxxxxx -- Exiting main() --\r\n");

        laddr = (void (*)())0x50;

        (*laddr)(); 

}

코드가 보여주는 것은 처음 0x0 번지에 저장된 0xb8080050 jump 번지인 0x50번지로 강제로 jump 하라는 입니다. 그러면 부트로더는 다시 동작을 하게 됩니다.

다음 그림은 부트로더가 유저 어플리케이션을 실행한 다시 부트로더를 실행하는 것을 보여주고 있습니다.