부트 로더 (blob-2.0.5-pre2 중심 )
DESCRIPTION
부트 로더 (blob-2.0.5-pre2 중심 ). Lecture #8. 목 차. BLOB 소개 주요 명령 BLOB 컴파일 방법 이미지 파일 복사 경로 BLOB 메모리 맵 BLOB 구조 Makefile 및 로드 스크립트 start 부분 jump 벡터 (start.S) / 예외 처리 (start.S) rest 부분 bss 및 stack 설정 (trampoline.S) / 함수 main (main.c) - PowerPoint PPT PresentationTRANSCRIPT
부트 로더 (blob-2.0.5-pre2 중심 )
Lecture #8Lecture #8
2
목 차 BLOB 소개 주요 명령 BLOB 컴파일 방법 이미지 파일 복사 경로 BLOB 메모리 맵 BLOB 구조 Makefile 및 로드 스크립트 start 부분
jump 벡터 (start.S) / 예외 처리 (start.S) rest 부분
bss 및 stack 설정 (trampoline.S) / 함수 main (main.c) 주요 명령 처리 함수 : reboot, boot_linux, Flash, do_reload, reblob
3
BLOB 소개 네덜란드의 Delft University of Technology 에서 개발 LART(Linux Advanced Radio Terminal) 라는 리눅스
기반 공개 소스 내장형 컴퓨터 ( 인텔 SA-1100 마이크로 프로세서 사용 ) 에 사용된 부트 로더
현재 blob-2.0.5-pre2 가 가장 최근 버전임 URL: http://www.lart.tudelft.nl/lartware/blob
4
주요 명령 reset: 직렬 포트에 화면을 clear 하는 문자 (ESC-c) 를 보냄 reboot: 0x00000000 로 제어를 옮김 (=power on reset) boot: SDRAM 의 kernel 이 저장된 지점으로 제어를 옮김 download: 호스트에서 키트의 SDRAM 으로 이미지 파일 복사 (uuencode
사용 ) xdownload: 호스트에서 키트의 SDRAM 으로 이미지 파일 복사 (xmodem
사용 ) flash: SDRAM 에 있는 이미지 파일을 flash 메모리로 저장함 erase: flash 메모리의 특정 부분을 지움 speed: 키트의 직렬 포트의 baud rate 을 변경 status: 버전 , flash 메모리 상태 , IP 주소 , MAC 주소 등을 보여줌 reload: flash 메모리에 저장된 이미지를 SDRAM 으로 복사 tftp: 서버로 부터 tftp 를 사용하여 이미지 파일을 SDRAM 으로 복사 set: IP 주소 및 MAC 주소를 설정 reblob: 0xa0300000 으로 제어를 옮김 (=SDRAM 에 복사된 BLOB 수행 ) btp: BOOTP 서버로 부터 키트의 IP 주소를 받아옴 help: 도움말 출력
5
BLOB 컴파일 방법 리눅스 kernel 소스 트리 필요
"/home/et1/linux-2.4.19-pxa255_pro2" 에 만들어져 있다고 가정
BLOB 를 configure 한다$ sh configure --with-linux-prefix= /home/et1/linux-2.4.19-pxa
255_pro2 --with-board=pxa255_pro BLOB 를 make 한다
$ make( 주 : 파일 src/blob/blob 가 새로 만들어진 이미지임 )
6
이미지 파일 복사 경로 download {blob|param|kernel|ramdisk|root|
usr} 호스트 컴퓨터 -> SDRAM
flash {blob|param|kernel|ramdisk|root|usr} SDRAM -> flash 메모리
reload {blob|param|kernel|ramdisk} flash 메모리 -> SDRAM
7
BLOB 메모리 맵
8
boot_linux
run command
boot_linux () SetClock () Download() Flash() ......
Auto Boot Manual Boot
GetCommand ()
start.S
점프
명령어 모드
하드웨어초기화
시리얼 초기화
커널 , 램디스크를 램에 복사10초간가다린후실행 키가 10초안에누렸을때
main()
() () SetClock Download() Flash() ......
GetCommand ()
커널로
명령어 모드
메모리초기화
타임머 초기화
10 키가 10초안에누렸을때
BLOB 실행 흐름
9
BLOB 구조 BLOB 는 2 부분으로 나누어져 있다
start 부분 : flash 메모리 상에서 수행되는 부분 reset 부분 : flash 메모리에서 SDRAM 으로 복사된 후
SDRAM 상에서 수행되는 부분 BLOB 의 프로그램이 모두 flash 메모리에서 수행되지
않고 reset 부분이 SDRAM 으로 복사되어 SDRAM 상에서 수행되는 이유 flash 메모리 상에서 수행되면서 flash 명령을 수행할 수 없기
때문임 SDRAM 에서 수행하는 것이 flash 메모리에서 수행하는 것
보다 더 효율적임
10
start 부분 flash 메모리 0x00000000 번지부터 저장 start.S 파일에서 수행 시작됨 프로그램은 ARM 어셈블리 언어로 작성 하는 일
하드웨어 초기화 작업을 수행 Xscale, GPIO, SDRAM 등 초기화
BLOB 의 reset 부분을 SDRAM 에 있는 0xa0400400 번지(=BLOB_START) 로 복사
BLOB_START(rest 부분 ) 로 jump
11
rest 부분 flash 메모리 0x00000400 번지부터 저장 ( 주 : 저장만
여기에 되어있지 실제는 0xa0400400 번지에 로드되어 수행된다는 가정하에 링크되어 )
flash 메모리 상에서 수행되지 않고 SDRAM 을 복사되어 SDRAM 상에서 수행
trampoline.S 파일에서 수행이 시작되자마자 main.c 파일의 함수 main() 을 부름
프로그램은 C 언어로 작성되어 있음 BLOB 의 대부분의 기능을 수행
blob, kernel, ramdisk 를 flash 메모리에서 SDRAM 으로 복사 이더넷 초기화 직렬 포트에서 입력이 없으면 SDRAM 의 kernel 부분으로 jump
하고 그렇지 않으면 명령어 모드로 수행
12
Makefile - 1
blob_start_elf32_OBJECTS = start.o testmem.oblob_start_elf32_DEPENDENCIES = start-ld-scriptblob_rest_elf32_OBJECTS = trampoline.o flashasm.o stack.o testmem2.o \
bootldrpart.o commands.o flash.o initcalls.o linux.o main.o memory.o \param_block.o partition.o reboot.o uucodec.o scc.o net.o bootp.o tftp.o \xmodem.o
blob_start_elf32_DEPENDENCIES = rest-ld-script
blob-start-elf32: $(blob_start_elf32_OBJECTS) $(blob_start_elf32_DEPENDENCIES)$(LINK) $(blob_start_elf32_LDFLAGS) $(blob_start_elf32_OBJECTS) \
$(blob_start_elf32_LDADD) $(LIBS)
blob-rest-elf32: $(blob_rest_elf32_OBJECTS) $(blob_rest_elf32_DEPENDENCIES)$(LINK) $(blob_rest_elf32_LDFLAGS) $(blob_rest_elf32_OBJECTS) \
$(blob_rest_elf32_LDADD) $(LIBS)
13
Makefile - 2
OBJCOPY = arm-linux-objcopyOCFLAGS = -O binary -R .note -R .comment -S
blob: blob-start blob-rest dd if=blob-start of=$@ bs=1k conv=sync dd if=blob-rest of=$@ bs=1k seek=1 chmod +x $@
blob-start: blob-start-elf32 $(OBJCOPY) $(OCFLAGS) $< $@
blob-rest: blob-rest-elf32 $(OBJCOPY) $(OCFLAGS) $< $@
14
BLOB-start
(1Kbyte)
BLOB-rest
(63Kbyte)
BLOB
trampoline.o
flashasm.o stack.o
testmem2.o
bootldrpart.o
commands.o flash.o
initcalls.o linux.o
main.o memory.o
param_block.o
partition.o reboot.o
uucodec.o
scc.o net.o
bootp.o tftp.o
xmodem.o
start.o
testmem.o
BLOB 소스 구조
15
"start 부분 " 로드 스크립트ENTRY(_start)SECTIONS{ . = 0x00000000; // location counter = 0x00000000
. = ALIGN(4); // align 4 를 함 .text : { *(.text) } // 모든 text 를 여기에 모음
. = ALIGN(4); // align 4 를 함 .rodata : { *(.rodata) } // 모든 read only 데이터 모음
. = ALIGN(4); // align 4 를 함 .data : { *(.data) } // 모든 초기화된 데이터 모음
. = ALIGN(4); // align 4 를 함 .got : { *(.got) } // 모든 global offset table 을 모음
. = ALIGN(4); // align 4 를 함 .bss : { *(.bss) } // 모든 초기화 되지 않은 데이터 모음}
16
"rest 부분 " 로드 스크립트SECTIONS{ . = (0xa0400400); // location counter = 0xa0400400
. = ALIGN(4); // align 4 를 함 .text : { __text_start = .; // __text_start = 현재 location counter *(.text) // 모든 text 를 여기에 모음 __text_end = .; // __text_end = 현재 location counter } ...}
17
최종 blob 이미지 모습
"start 부분 " 에서 "rest 부분 " 으로 수행이 넘어가기 전에 flash 메모리의 1K ~ 64K 의 내용을 SDRAM 의 0xa0400400 에 복사한다
blob-start blob-restnull
0 1K
???
64Kblob 끝
18
jump 벡터 (start.S)
ARM 의 7 가지 예외 발생시 수행하여야 하는 명령어가 저장된 곳 메모리 0x00000000 번지 (flash 메모리 부분 ) 부터 32 바이트 저장됨 저장된 명령어는 예외 처리 루틴의 첫 주소로 jump 하는 명령어임
_start:b reset // resetb undefined_instruction // undefined instructionb software_interrupt // software interrupt (swi)b prefetch_abort // instruction fetch memory abortb data_abort // data access memory abortb not_used // not usedb irq // interruptb fiq // fast interrupt
19
reset 예외 처리 (start.S)
reset:bl init_xscalebl init_gpiobl init_mem...
relocate:// BLOB reset 부분 relocateadr r0, _startadd r2, r0, #(64*1024)add r0, r0, #0x0400ldr r1, BLOB_START
// r0 = source address// r1 = target address// r2 = source end addresscopy_loop:
ldmia r0!, {r3-r10}stmia r1!, {r3-r10}cmp r0, r2ble copy_loop
ldr r0, BLOB_STARTmov pc, r0
reset 예외는 init_xscale, init_gpio, init_mem 을 부르고 flash 메모리에 저장된 BLOB 의 "rest 부분 " 을 SDRAM 의
BLOB_START(=0xa0400400) 로 복사하고 이곳으로 jump
20
기타 예외 처리 (start.S)
undefined_instruction:b endless_blink
software_interrupt:b endless_blink
...
riq:b endless_blink
fiq:b endless_blink
endless_blink:bl waitbl flash_ledb endless_blink
wait: // busy wait loopmov r5, #0x1000000
wait0:subs r5, r5, #1bne wait0mov pc, lr
"reset 예외 " 를 제외한 다른 예외는 모두 endless_blink 로 jump 함 endless_blink 로 가면 LED 를 계속 깜박거리게 함
21
bss 및 stack 설정 (trampoline.S)
_trampoline:ldr r1, bss_startldr r0, bss_endsub r0, r0, r1mov r2, #0
// r0 = bss 바이트 수// r1 = bss start 주소// r2 = 0
clear_bss:// bss 부분을 clearstmia r1!, {r2}subs r0, r0, #4bne clear_bss// 스택 설정ldr r0, stack_endsub sp, r0, #4// C 코드 함수 main() call bl main
r0=bss 바이트 수 , r1=bss 시작 주소 , r2=0 을 설정한 후 , SDRAM 의 bss 영역을 r2 로 채우고 , SP=stack_end-4 로 설정하고 C 코드로 작성된 파일 main.c 에 정의된 함수 main 을 call
22
함수 main (main.c) - 1
int main(void){ ... serial_init(blob_status.terminalSpeed); ... SerialOutputString("\nConsider yourself LARTed!\n\n"); ... get_memory_map(); print_elf_sections(); EthInit(); ... do_reload("blob"); do_reload("kernel"); do_reload("ramdisk"); ...
직렬 포트 초기화 , 메시지 출력 , 메모리 크기 점검 , elf section 출력 , 이더넷 초기화 등의 일을 하고
blob, kernel, ramdisk 이미지를 flash 메모리에서 SDRAM 으로 복사
23
함수 main (main.c) - 2
SerialOutputString("Autoboot in progress, press any key to stop");
for(i = 0; i < blob_status.boot_delay; i++) // 키 입력 점검
if((retval=SerialInputBlock(commandline, ...)>0) break
if(retval == 0) parse_command("boot"); // 키 입력 없음
SerialOutputString("\nAutoboot aborted\n"); // 키 입력 있음
for(;;)
GetCommand(commandline, ...);
}
지정된 delay 동안 키 입력이 있는지 점검하고 키이 입력이 없으면 boot 를 불러서 SDRAM 의 kernel 번지로 jump 키이 입력이 있으면 함수 GetCommand 를 불러서 명령어 입력 받음
24
주요 명령 처리 함수
명령 reboot -> 함수 reboot (reboot.c)
명령 boot -> 함수 boot_linux (linux.c)
명령 flash -> 함수 Flash, flash_write_region (flash.c)
명령 reload -> 함수 do_reload (main.c)
명령 reblob -> 함수 reblob (reboot.c)
25
함수 reboot (reboot.c)
int reboot(int argc, char *argv[])
{
void (*Reboot)(void) = (void (*)(void))0x00000000;
SerialOutputString("Rebooting...\n\n");
Reboot();
}
함수 void Reboot(void) 를 flash 메모리의 0x00000000 번지로 정의하고 이 함수를 call 한다
power on reset 과 같은 효과가 있음
26
함수 boot_linux (linux.c)
static int boot_linux(int argc, char *argv[]) { void (*theKernel)(int zero, int arch)=(void(*)(int,int)) KERNEL_RAM_BASE;
SerialOutputString("\nStarting kernel ...\n\n"); theKernel(0, ARCH_NUMBER);}
함수 void theKernel(int,int) 를 SDRAM 의 KERNEL_RAM_BASE (=0xa0008000) 번지로 정의하고 이 함수를 call 한다 ( 인수는 0 과 ARCH_NUMBER=110)
27
함수 Flash (main.c)
static int Flash(int argc, char *argv[]) { u32 *src, *dst; u32 numBytes;
if(strncmp(argv[1], "blob", 5) == 0) { src = (u32 *)BLOB_RAM_BASE; dst = (u32 *)BLOB_FLASH_BASE; numBytes = blob_status.blobSize;}
argv[1] 의 값에 따라 blob, kernel, ramdisk, usr 등으로 인식하고 이에 따라 src, dst, numByte 를 결정한다
함수 flash_write_region 을 부른다
else if ... { ... }
nwords = (numBytes + sizeof(u32) - 1) / sizeof(u32);
flash_write_region(dst, src, nwords);}
28
함수 flash_write_region (flash.c)
int flash_write_region(u32 *dst, const u32 *src, u32 nwords)
{ int rv; u32 i = 0;
while(i < nwords) { if(dst[i] == src[i]) { i++; continue; }
SDRAM 의 주소 (=src) 에서 nword 만큼의 데이터를 flash 메모리의 주소 (=dst) 에 write 한다 . 함수 flash_write_intel32 를 부름
rv = flash_write_intel32(&dst[i], &src[i]); ... }}
29
Intel flash 메모리 (16bit 칩 *2) write 방법
PGM_SETUP(=0x00400040): 이 명령을 flash 메모리 ( 어떤 번지나 무방 ) 에 쓰면 flash 메모리가 write 될 준비를 한다
write 할 번지에 원하는 데이터를 쓴다 (*dst = *src; )
STATUS_READ(=0x00700070): 이 명령을 flash 메모리 ( 어떤 번지나 무방 ) 에 쓴 후 flash 메모리 ( 어떤 번지나 무방 ) 의 내용을 읽으면 현재 flash 메모리의 상태가 읽혀진다 . 현재 BLOB 에서 write 후 점검하는 상태는 STATUS_BUSY(=0x00800080) 및 STATUS_PGM_ ERR(=0x00100010) 이다
READ_ARRAY(=0x00ff00ff): 이 명령을 flash 메모리에 ( 어떤 번지나 무방함 ) 쓰면 flash 메모리가 read 할 수 있는 상태로 된다 . write 완료 후 필요한 명령임
30
함수 flash_write_intel32 (flash.c)
static int flash_write_intel32(u32 *dst, const u32* src){ *dst = data_to_flash(PGM_SETUP); // 쓰기 준비 *dst = *src; // 데이터 쓰기 do { *dst = data_to_flash(STATUS_READ); // 상태 읽기 준비 result = data_from_flash(*dst); // 상태 읽기 } while((~result & STATUS_BUSY) != 0); // 상태 점검 (STATUS_BUSY) *dst = data_to_flash(READ_ARRAY); // 정상 상태 (= 읽기 모드 ) 로 설정}
PGM_SETUP(=0x00400040), STATUS_READ(=0x00700070), READ_ARRAY(=0x00ff00ff) 명령을 사용하여 원하는 flash 메모리에 데이터를 write 한다
31
함수 do_reload (main.c)
static int do_reload(char *what) { u32 *dst = 0; *src = 0; int numWords;
if(strncmp(what, "blob", 5) == 0) { dst = (u32 *)BLOB_RAM_BASE; src = (u32 *)BLOB_FLASH_BASE; numWords = BLOB_FLASH_LEN / 4; SerialOutputString("Loading blob from flash "); } else if ... MyMemCpy(dst, src, numWords);}
what 이 무엇이냐에 따라 flash 메모리의 주소 , SDRAM 의 주소 , flash 메모리에서의 크기를 설정하고 함수 MyMemCpy 를 call 한다
함수 MyMemCpy 는 flash 메모리의 이미지를 SDRAM 으로 복사한다
32
함수 reblob (reboot.c)
static int reblob(int argc, char *argv[]){ void (*blob)(void) = (void (*)(void))BLOB_RAM_BASE;
SerialOutputString("Restarting blob from RAM...\n\n"); blob();}
함수 void blob(void) 를 SDRAM 의 BLOB_RAM_BASE (=0xa0300000) 번지로 정의하고 이 함수를 call 한다
SDRAM 의 BLOB_RAM_BASE 에 복사된 BLOB 가 수행 가능한 이유는 "start 부분 " 이 어셈블리 언어로 작성되어 있고 주소가 현재 PC 값에 대한 상대적인 값으로 지정되어 있기 때문