오후 7:09 2006-04-27
kernel 영역으로 올리기
조경민 bro@shinbiro.com
http://neri.cafe24.com
============================================================
;=====================================================
; boot test
; by bro, bro@shinbiro.com 오전 10:23 2006-04-26
;=====================================================
; main.c의 커널 main 함수 심볼 쓰기 위해서
IMPORT main
IMPORT ||Image$$KERNEL$$ZI$$Limit||
EXPORT __user_initial_stackheap
EXPORT vector
; KERNEL region 복사를 위해 심볼 사용
IMPORT ||Image$$KERNEL$$Base||
IMPORT ||Image$$KERNEL$$Length||
IMPORT ||Load$$KERNEL$$Base||
AREA boot, CODE, READONLY
ENTRY
vector ; 인터럽트 벡터 테이블
b reset ; 주소 0번지에 reset 인터럽트가 오면 바로 reset레이블로 점프
b error ; undefined_instruction
b error ; software_interrupt
b error ; prefetch_abort
b error ; data_abort
b error ; not_used
b error ; IRQ
b error ; FIQ
error
b error
reset
; 현재 모드에서 IRQ|FIQ를 끈다.
mrs r0, CPSR
bic r0, r0, #0x1f
orr r0, r0, #(0x13 | 0xc0) ; 0x13(0001 0011) | 0xC0 (1101 0000) = 0xD3(1101 0011)
msr CPSR_cxsf, r0
; 스택 초기화 0x9000
mov sp, #0x00080000
; 커널 복사 (memory.map에서 커널영역은 0x10000에서 하겠다고 했으니 복사해야함;)
bl copy_kernel
ldr pc, =main
b end
__user_initial_stackheap
LDR r0, =||Image$$KERNEL$$ZI$$Limit||
MOV pc, lr
copy_kernel
ldr r0, =||Load$$KERNEL$$Base|| ; source (FLASH ROM같은 영역)
ldr r1, =||Image$$KERNEL$$Base|| ; destination (SDRAM 같은 영역)
ldr r2, =||Image$$KERNEL$$Length|| ; kernel length
mov r3, #0 ; counter
loop
ldr r4, [r0], #4
str r4, [r1], #4
add r3, r3, #4
cmp r3, r2
bne loop
mov pc, lr
end
END
-----------------------------------------------------------------------------
main.c
void main()
{
int a;
for( a = 0; a < 10; a = a + 1);
}
-----------------------------------------------------------------------------
memory.map
MEMORY_MAP 0x0
{
BOOT 0x0
{
boot.o (boot, +First)
* (+RO, +RW, +ZI)
}
KERNEL 0x10000
{
main.o (+RO, +RW, +ZI)
}
}
-----------------------------------------------------------------------------
armasm boot.s -G -o boot.o
armcc -c main.c --arm --debug -g -o main.o
armlink boot.o main.o --map --scatter memory.map --entry vector -o kernel.axf
scatter 파일
여러 object파일을 링크할때 각 object 파일이 실제 실행될때 어디로 로드될지 결정할 수 있다.
region이름 시작주소, [크기]
{
서브region이름 시작주소, [크기]
{
object.o (섹션명,+First) ;처음에 둔다는 의미
}
서브region이름 시작주소, [크기]
{
main.o (+RO, +RW) ; ReadOnly와 ReadWrite 섹션만 둔다고 설정가능
* (+RO, +RW, +ZI) ; main.o의 ZI (Zero Intilaize)와 다른 object들의 모든 섹션이 놓임
}
}
RO는 보통 실행코드 영역또는 const상수(text), RW는 데이터 영역, ZI는 0으로 초기화되는 변수(static변수)
처음에는 region으로 나누는 것을 시도했는데 잘 안되었다. 이유는 메모리 맵을 잡아주면
해당 main.o 모듈의 0x10000번지에서 시작되는것까지는 맞지만, kernel.axf를 AXD Debugger로
로드 하면 아직 0x13C 정도 번지에 boot.o 모듈의 다음 주소 공간에 로드되어 있을 뿐이었다.;
아래의 scatterload에 관한 ARM Limited의 문서를 읽어보면
http://www.arm.com/pdfs/DAI0048A_scatterload.pdf
armlink에 의해서 boot.s에서 사용 가능한 링킹 심볼 정보 몇개를 사용할 수 있다.
각 region의 로드 된 직후의 Base 주소, Length, 그리고 실제 실행되어야할 Base와 Length이다.
-----------------------------------------------------------------------
참고:위의 pdf문서에서 Initialization Code for Scatter Loading를 보면
커널 영역을 복사하는 것 외에도 ZI영역을 실제로 직접 0으로 초기화하는 코드도 필요하다.
일단 간단하게 하기 위해서 그 과정은 생략하였다.
아래 예에서는 RAM 이라는 이름의 region이 zi 초기화 되는 코드이다.
region을 둔 이유도 사실 0번지 ROM에 로드된 후 RAM이나 다른 주소 영역에 복사하여 실행하게
하기 위해서 존재한다.
; r0 contains the load address of the region RAM
LDR r0, = |Load$$RAM$$Base|
; r1 contains the execution address of the region RAM
LDR r1, = |Image$$RAM$$Base|
CMP r0, r1 ; check source & destination are different
BEQ do_zi_init ; if not, do not copy this region
do_zi_init
; r1 contains the execution address of the region
LDR r1, = |Image$$RAM$$ZI$$Base|
; r2 contains the address of the word beyond the end of this
; execution region
MOV r2, r1
LDR r4, = |Image$$RAM$$ZI$$length|
ADD r2, r2, r4
; r3 contains the value to be used to initialise area
MOV r3, #0
BL zi_init ; call subroutine zi_init
-----------------------------------------------------------------------
예를 들어
MEMORY_MAP 0x0
{
BOOT 0x0
{
boot.o (boot, +First)
* (+RO, +RW, +ZI)
}
KERNEL 0x10000
{
main.o (+RO, +RW, +ZI)
}
}
라면 각 region 마다 아래와 같은 심볼을 사용할 수 있다.
||Image$$BOOT$$Base|| : BOOT region의 실행 가능한 시작 주소
||Load$$BOOT$$Base|| : BOOT region이 로드 된 직후의 시작 주소
||Image$$BOOT$$Length|| : BOOT region의 길이
||Image$$KERNEL$$Base|| : KERNEL region의 실행 가능한 시작 주소
||Image$$KERNEL$$Length|| : KERNEL region 길이
||Load$$KERNEL$$Base|| : KERNEL region의 로드 된 직후의 시작 주소
참고: * (+RO, +RW, +ZI) 를 KERNEL region에 두면 root region이 아니라서 내부 라이브러리
오브젝 파일을 그 region에 둘 수 없다는 에러가 발생된다.
root region은 로드 후 바로 실행 가능한 region이고 non root region은 로드 후 복사를 해야
실행 가능한 region을 의미한다.
http://www.arm.com/support/faqdev/1462.html
만일 굳이 KERNEL region에 두고 싶다면, root region에 있어야하는 내부 라이브러리 모듈만
BOOT region에 두면 된다.
MEMORY_MAP 0x0
{
BOOT 0x0
{
boot.o (boot, +First)
* (InRoot$$Sections)
}
KERNEL 0x10000
{
main.o (+RO, +RW, +ZI)
* (+RO, +RW, +ZI)
}
}
이 중 BOOT region은 로드되었을 때의 시작 주소와, 실행 가능한 시작 주소가 이미 일치하기
때문에 할일이 없다. 하지만 KERNEL region은 로드되었을 때의 ||Load$$KERNEL$$Base||는
대충 0x13C 정도 뿐이라, 실제 실행 가능한 주소 ||Image$$KERNEL$$Base||가 가리키는 0x10000으로
로드된 KERNEL region을 복사해야한다.
따라서 boot.s에서는 아래와 같이 커널을 복사한다.
; 커널 복사 (memory.map에서 커널영역은 0x10000에서 하겠다고 했으니 복사해야함;)
bl copy_kernel
ldr pc, =main
b end
copy_kernel
ldr r0, =||Load$$KERNEL$$Base|| ; source (FLASH ROM같은 영역)
ldr r1, =||Image$$KERNEL$$Base|| ; destination (SDRAM 같은 영역)
ldr r2, =||Image$$KERNEL$$Length|| ; kernel length
mov r3, #0 ; counter
loop
ldr r4, [r0], #4 ; 4바이트를 읽어서 r0는 읽히고 4바이트 전진
str r4, [r1], #4 ; 4바이트 쓴다.
add r3, r3, #4 ; 카운터를 4바이트씩 증가
cmp r3, r2 ; 커널 길이만큼 복사했는지 검사
bne loop ; 같지 않다면 아직 덜 복사되었음 계속 복사
mov pc, lr ; 리턴
그런데 먼저 이런 링킹 심볼 정보를 사용하려면 외부 심볼이기 때문에 IMPORT로 선언해야한다.
; KERNEL region 복사를 위해 심볼 사용
IMPORT ||Image$$KERNEL$$Base||
IMPORT ||Image$$KERNEL$$Length||
IMPORT ||Load$$KERNEL$$Base||
kernel 영역으로 올리기
조경민 bro@shinbiro.com
http://neri.cafe24.com
============================================================
;=====================================================
; boot test
; by bro, bro@shinbiro.com 오전 10:23 2006-04-26
;=====================================================
; main.c의 커널 main 함수 심볼 쓰기 위해서
IMPORT main
IMPORT ||Image$$KERNEL$$ZI$$Limit||
EXPORT __user_initial_stackheap
EXPORT vector
; KERNEL region 복사를 위해 심볼 사용
IMPORT ||Image$$KERNEL$$Base||
IMPORT ||Image$$KERNEL$$Length||
IMPORT ||Load$$KERNEL$$Base||
AREA boot, CODE, READONLY
ENTRY
vector ; 인터럽트 벡터 테이블
b reset ; 주소 0번지에 reset 인터럽트가 오면 바로 reset레이블로 점프
b error ; undefined_instruction
b error ; software_interrupt
b error ; prefetch_abort
b error ; data_abort
b error ; not_used
b error ; IRQ
b error ; FIQ
error
b error
reset
; 현재 모드에서 IRQ|FIQ를 끈다.
mrs r0, CPSR
bic r0, r0, #0x1f
orr r0, r0, #(0x13 | 0xc0) ; 0x13(0001 0011) | 0xC0 (1101 0000) = 0xD3(1101 0011)
msr CPSR_cxsf, r0
; 스택 초기화 0x9000
mov sp, #0x00080000
; 커널 복사 (memory.map에서 커널영역은 0x10000에서 하겠다고 했으니 복사해야함;)
bl copy_kernel
ldr pc, =main
b end
__user_initial_stackheap
LDR r0, =||Image$$KERNEL$$ZI$$Limit||
MOV pc, lr
copy_kernel
ldr r0, =||Load$$KERNEL$$Base|| ; source (FLASH ROM같은 영역)
ldr r1, =||Image$$KERNEL$$Base|| ; destination (SDRAM 같은 영역)
ldr r2, =||Image$$KERNEL$$Length|| ; kernel length
mov r3, #0 ; counter
loop
ldr r4, [r0], #4
str r4, [r1], #4
add r3, r3, #4
cmp r3, r2
bne loop
mov pc, lr
end
END
-----------------------------------------------------------------------------
main.c
void main()
{
int a;
for( a = 0; a < 10; a = a + 1);
}
-----------------------------------------------------------------------------
memory.map
MEMORY_MAP 0x0
{
BOOT 0x0
{
boot.o (boot, +First)
* (+RO, +RW, +ZI)
}
KERNEL 0x10000
{
main.o (+RO, +RW, +ZI)
}
}
-----------------------------------------------------------------------------
armasm boot.s -G -o boot.o
armcc -c main.c --arm --debug -g -o main.o
armlink boot.o main.o --map --scatter memory.map --entry vector -o kernel.axf
scatter 파일
여러 object파일을 링크할때 각 object 파일이 실제 실행될때 어디로 로드될지 결정할 수 있다.
region이름 시작주소, [크기]
{
서브region이름 시작주소, [크기]
{
object.o (섹션명,+First) ;처음에 둔다는 의미
}
서브region이름 시작주소, [크기]
{
main.o (+RO, +RW) ; ReadOnly와 ReadWrite 섹션만 둔다고 설정가능
* (+RO, +RW, +ZI) ; main.o의 ZI (Zero Intilaize)와 다른 object들의 모든 섹션이 놓임
}
}
RO는 보통 실행코드 영역또는 const상수(text), RW는 데이터 영역, ZI는 0으로 초기화되는 변수(static변수)
처음에는 region으로 나누는 것을 시도했는데 잘 안되었다. 이유는 메모리 맵을 잡아주면
해당 main.o 모듈의 0x10000번지에서 시작되는것까지는 맞지만, kernel.axf를 AXD Debugger로
로드 하면 아직 0x13C 정도 번지에 boot.o 모듈의 다음 주소 공간에 로드되어 있을 뿐이었다.;
아래의 scatterload에 관한 ARM Limited의 문서를 읽어보면
http://www.arm.com/pdfs/DAI0048A_scatterload.pdf
armlink에 의해서 boot.s에서 사용 가능한 링킹 심볼 정보 몇개를 사용할 수 있다.
각 region의 로드 된 직후의 Base 주소, Length, 그리고 실제 실행되어야할 Base와 Length이다.
-----------------------------------------------------------------------
참고:위의 pdf문서에서 Initialization Code for Scatter Loading를 보면
커널 영역을 복사하는 것 외에도 ZI영역을 실제로 직접 0으로 초기화하는 코드도 필요하다.
일단 간단하게 하기 위해서 그 과정은 생략하였다.
아래 예에서는 RAM 이라는 이름의 region이 zi 초기화 되는 코드이다.
region을 둔 이유도 사실 0번지 ROM에 로드된 후 RAM이나 다른 주소 영역에 복사하여 실행하게
하기 위해서 존재한다.
; r0 contains the load address of the region RAM
LDR r0, = |Load$$RAM$$Base|
; r1 contains the execution address of the region RAM
LDR r1, = |Image$$RAM$$Base|
CMP r0, r1 ; check source & destination are different
BEQ do_zi_init ; if not, do not copy this region
do_zi_init
; r1 contains the execution address of the region
LDR r1, = |Image$$RAM$$ZI$$Base|
; r2 contains the address of the word beyond the end of this
; execution region
MOV r2, r1
LDR r4, = |Image$$RAM$$ZI$$length|
ADD r2, r2, r4
; r3 contains the value to be used to initialise area
MOV r3, #0
BL zi_init ; call subroutine zi_init
-----------------------------------------------------------------------
예를 들어
MEMORY_MAP 0x0
{
BOOT 0x0
{
boot.o (boot, +First)
* (+RO, +RW, +ZI)
}
KERNEL 0x10000
{
main.o (+RO, +RW, +ZI)
}
}
라면 각 region 마다 아래와 같은 심볼을 사용할 수 있다.
||Image$$BOOT$$Base|| : BOOT region의 실행 가능한 시작 주소
||Load$$BOOT$$Base|| : BOOT region이 로드 된 직후의 시작 주소
||Image$$BOOT$$Length|| : BOOT region의 길이
||Image$$KERNEL$$Base|| : KERNEL region의 실행 가능한 시작 주소
||Image$$KERNEL$$Length|| : KERNEL region 길이
||Load$$KERNEL$$Base|| : KERNEL region의 로드 된 직후의 시작 주소
참고: * (+RO, +RW, +ZI) 를 KERNEL region에 두면 root region이 아니라서 내부 라이브러리
오브젝 파일을 그 region에 둘 수 없다는 에러가 발생된다.
root region은 로드 후 바로 실행 가능한 region이고 non root region은 로드 후 복사를 해야
실행 가능한 region을 의미한다.
http://www.arm.com/support/faqdev/1462.html
만일 굳이 KERNEL region에 두고 싶다면, root region에 있어야하는 내부 라이브러리 모듈만
BOOT region에 두면 된다.
MEMORY_MAP 0x0
{
BOOT 0x0
{
boot.o (boot, +First)
* (InRoot$$Sections)
}
KERNEL 0x10000
{
main.o (+RO, +RW, +ZI)
* (+RO, +RW, +ZI)
}
}
이 중 BOOT region은 로드되었을 때의 시작 주소와, 실행 가능한 시작 주소가 이미 일치하기
때문에 할일이 없다. 하지만 KERNEL region은 로드되었을 때의 ||Load$$KERNEL$$Base||는
대충 0x13C 정도 뿐이라, 실제 실행 가능한 주소 ||Image$$KERNEL$$Base||가 가리키는 0x10000으로
로드된 KERNEL region을 복사해야한다.
따라서 boot.s에서는 아래와 같이 커널을 복사한다.
; 커널 복사 (memory.map에서 커널영역은 0x10000에서 하겠다고 했으니 복사해야함;)
bl copy_kernel
ldr pc, =main
b end
copy_kernel
ldr r0, =||Load$$KERNEL$$Base|| ; source (FLASH ROM같은 영역)
ldr r1, =||Image$$KERNEL$$Base|| ; destination (SDRAM 같은 영역)
ldr r2, =||Image$$KERNEL$$Length|| ; kernel length
mov r3, #0 ; counter
loop
ldr r4, [r0], #4 ; 4바이트를 읽어서 r0는 읽히고 4바이트 전진
str r4, [r1], #4 ; 4바이트 쓴다.
add r3, r3, #4 ; 카운터를 4바이트씩 증가
cmp r3, r2 ; 커널 길이만큼 복사했는지 검사
bne loop ; 같지 않다면 아직 덜 복사되었음 계속 복사
mov pc, lr ; 리턴
그런데 먼저 이런 링킹 심볼 정보를 사용하려면 외부 심볼이기 때문에 IMPORT로 선언해야한다.
; KERNEL region 복사를 위해 심볼 사용
IMPORT ||Image$$KERNEL$$Base||
IMPORT ||Image$$KERNEL$$Length||
IMPORT ||Load$$KERNEL$$Base||
'KB > embbeded sw' 카테고리의 다른 글
arm-6: TRACE32 사용법 익히기 (0) | 2006.05.03 |
---|---|
arm-5 : task switch 하기 (0) | 2006.05.02 |
arm-3 : c코드로 점프~ (0) | 2006.04.26 |
arm-2: boot 테스트 (0) | 2006.04.26 |
arm-1: ADS로 ARM 공부 add (0) | 2006.04.25 |