'Linux/Boot'에 해당하는 글 8건

리눅스의 부팅과정을 분석해주고 이를 그림으로 만들어주는 프로그램이 있다.

이 것을 이용하면 현재 내 컴퓨터의 부팅 과정과 부팅시간을 알수 있고,
어느부분이 오래걸리는지 파악할 수 있다.

이 자료를 이용하여 부팅시간을 단축시키는 것도 가능하다.

인텔의 한 개발자는 아수스 eeePC로 리눅스를 5초만에 부팅하게 만들었다-_-

암튼..일단 설치를 해보자.


공식 홈페이지 : http://www.bootchart.org

1. 다운로드
  공식 홈페이지에서 bootchart-0.9-1.src.rpm 파일을 다운로드 한다.

2. 설치
  # rpmbuild --rebuild bootchart-0.9-1.src.rpm
  # rpm -Uvh /usr/src/redhat/RPMS/noarch/*.rpm

3. 확인
  /boot/grub/grub.conf 에 "Bootchart logging"이 추가되었는지 확인한다.

4. 재부팅
  로그정보 수집을 위하여 재부팅한다. 이때에 새로 생성된 "Bootchart logging"으로 부팅한다.

5. 로그파일 분석
  재부팅을 하고 나면 /var/log/bootchart.tgz 파일이 생성된다. 이 파일을 이용하여 svg, png로 변환한다.
  # bootchart
  Parsing /var/log/bootchart.tgz
  Wrote image: ./bootchart.svgz
 # rsvg-view bootchart.svg


출처 : http://juncon.tistory.com/27

'Linux > Boot' 카테고리의 다른 글

세번째head.S /arch/arm/kernel/head.S 분석 .  (0) 2009.06.05
여담...  (0) 2009.06.05
두번째head.S /arch/arm/kernel/head.S 분석 .  (0) 2009.06.05
/kernel/head.S  (0) 2009.06.05
head.S  (0) 2009.06.05

WRITTEN BY
RootFriend
개인적으로... 나쁜 기억력에 도움되라고 만들게되었습니다.

,

두번째 head.S가 끝나면 실질적으로 가상주소로 동작하는 커널이 된다.

여기선 섹션 단위로  process type, machine type에 정보가 많이 있다.

head.S 에 setup_mmu 라는 함수 0xA000 / 4000 에서 0xA000 / 8000 까지 제대로 동작하는지 알아보는함수 임의 의 값을 넣는다.

 

 
 
 vmlinux
 vmlinux
 vmlinux 4MB라고 여긴다.?
 vmlinux
 head.S
 


'Linux > Boot' 카테고리의 다른 글

Bootchart - 리눅스 부팅 과정 분석  (0) 2010.07.18
여담...  (0) 2009.06.05
두번째head.S /arch/arm/kernel/head.S 분석 .  (0) 2009.06.05
/kernel/head.S  (0) 2009.06.05
head.S  (0) 2009.06.05

WRITTEN BY
RootFriend
개인적으로... 나쁜 기억력에 도움되라고 만들게되었습니다.

,

여담...

Linux/Boot 2009. 6. 5. 05:17

ARM에서  특정 어셈 코드가 실행중일때 pc의 위치는 어디일까??

 

arm 9의 파이프라인을 보면 fetch -->decode -->excute -->memory -->access 의 다섯 단계로

이루어지므로 실행중인 코드가 있다면 다음 , 다음의 코드를 fetch 하고 있을것이다.

 

 

아래에 head.S의 분석이 있는데 /...../kernel/head.S 의 마지막에  _switched 함수가 실행된후 브렌치 되는곳이 start_kernel이다 여기서 부터는 C코드이고 가상주소로 동작하게 된다.

 

부팅시퀀스를 잘 알고 있으면 부팅이 안되더라도 적절한곳을 찾아 디버깅 할 수 있다.



[출처] 여담...|작성자 바다사랑


'Linux > Boot' 카테고리의 다른 글

Bootchart - 리눅스 부팅 과정 분석  (0) 2010.07.18
세번째head.S /arch/arm/kernel/head.S 분석 .  (0) 2009.06.05
두번째head.S /arch/arm/kernel/head.S 분석 .  (0) 2009.06.05
/kernel/head.S  (0) 2009.06.05
head.S  (0) 2009.06.05

WRITTEN BY
RootFriend
개인적으로... 나쁜 기억력에 도움되라고 만들게되었습니다.

,

/*
 *  linux/arch/arm/kernel/head.S
 *
 *  Copyright (C) 1994-2002 Russell King
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 *  Kernel startup code for all 32-bit CPUs
 */
#include <linux/config.h>
#include <linux/linkage.h>
#include <linux/init.h>

#include <asm/assembler.h>
#include <asm/domain.h>
#include <asm/mach-types.h>
#include <asm/procinfo.h>
#include <asm/ptrace.h>
#include <asm/constants.h>
#include <asm/system.h>

#define PROCINFO_MMUFLAGS 8
#define PROCINFO_INITFUNC 12

#define MACHINFO_PHYSRAM 4
#define MACHINFO_PHYSIO  8
#define MACHINFO_PGOFFIO 12

#ifndef CONFIG_XIP_KERNEL
/*
 * We place the page tables 16K below TEXTADDR.  Therefore, we must make sure
 * that TEXTADDR is correctly set.  Currently, we expect the least significant
 * 16 bits to be 0x8000, but we could probably relax this restriction to
 * TEXTADDR >= PAGE_OFFSET + 0x4000
 *
 * Note that swapper_pg_dir is the virtual address of the page tables, and
 * pgtbl gives us a position-independent reference to these tables.  We can
 * do this because stext == TEXTADDR
 */
#if (TEXTADDR & 0xffff) != 0x8000
#error TEXTADDR must start at 0xXXXX8000
#endif

 .globl swapper_pg_dir
 .equ swapper_pg_dir, TEXTADDR - 0x4000

 .macro pgtbl, rd, phys
 adr \rd, stext
 sub \rd, \rd, #0x4000
 .endm
#else
/*
 * XIP Kernel:
 *
 * We place the page tables 16K below DATAADDR.  Therefore, we must make sure
 * that DATAADDR is correctly set.  Currently, we expect the least significant
 * 16 bits to be 0x8000, but we could probably relax this restriction to
 * DATAADDR >= PAGE_OFFSET + 0x4000
 *
 * Note that pgtbl is meant to return the physical address of swapper_pg_dir.
 * We can't make it relative to the kernel position in this case since
 * the kernel can physically be anywhere.
 */
#if (DATAADDR & 0xffff) != 0x8000
#error DATAADDR must start at 0xXXXX8000
#endif

 .globl swapper_pg_dir
 .equ swapper_pg_dir, DATAADDR - 0x4000

 .macro pgtbl, rd, phys
 ldr \rd, =((DATAADDR - 0x4000) - VIRT_OFFSET)
 add \rd, \rd, \phys
 .endm
#endif

/*
 * Kernel startup entry point.
 * ---------------------------
 *
 * This is normally called from the decompressor code.  The requirements
 * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
 * r1 = machine nr.
 *
 * This code is mostly position independent, so if you link the kernel at
 * 0xc0008000, you call this at __pa(0xc0008000).
 *
 * See linux/arch/arm/tools/mach-types for the complete list of machine
 * numbers for r1.
 *
 * We're trying to keep crap to a minimum; DO NOT add any machine specific
 * crap here - that's what the boot loader (or in extreme, well justified
 * circumstances, zImage) is for.
 */
 __INIT
 .type stext, %function
ENTRY(stext)     //<---------------------------------------------  여기부터 보자 99라인
 msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | MODE_SVC @ ensure svc mode 
      @ and irqs disabled//슈퍼바이저 모드 enable
 bl __lookup_processor_type  @ r5=procinfo r9=cpuid// 414 라인 으로점프!
 movs r10, r5    @ invalid processor (r5=0)?  //"P"라고 뜨면 프로세서 타입을 찾지 못한 것이다.
 moveq r0, #'p'   @ yes, error 'p'
 beq __error
 bl __lookup_machine_type  @ r5=machinfo  //다시 점프 462라인으로!
 movs r8, r5    @ invalid machine (r5=0)? // 타입이 맞지 않으면 r5번에 0 이들어가고 "LA"라는 에러 메세지 발동
 moveq r0, #'a'   @ yes, error 'a'
 beq __error
 bl __create_page_tables    //0xA000 / 4000 rhk 0xA000 / 8000 사이에 페이지 테이블을 생성하는 과정

 /*
  * The following calls CPU specific code in a position independent
  * manner.  See arch/arm/mm/proc-*.S for details.  r10 = base of
  * xxx_proc_info structure selected by __lookup_machine_type
  * above.  On return, the CPU will be ready for the MMU to be
  * turned on, and r0 will hold the CPU control register value.
  */
 ldr r13, __switch_data  @ address to jump to after
      @ mmu has been enabled
 adr lr, __enable_mmu  @ return (PIC) address
 add pc, r10, #PROCINFO_INITFUNC

 .type __switch_data, %object
__switch_data:
 .long __mmap_switched
 .long __data_loc   @ r4
 .long __data_start   @ r5
 .long __bss_start   @ r6
 .long _end    @ r7
 .long processor_id   @ r4
 .long __machine_arch_type  @ r5
 .long cr_alignment   @ r6
 .long init_thread_union+8192  @ sp

/*
 * The following fragment of code is executed with the MMU on, and uses
 * absolute addresses; this is not position independent.
 *
 *  r0  = cp#15 control register
 *  r1  = machine ID
 *  r9  = processor ID
 */
 .type __mmap_switched, %function
__mmap_switched:
 adr r3, __switch_data + 4

 ldmia r3!, {r4, r5, r6, r7}
 cmp r4, r5    @ Copy data segment if needed
1: cmpne r5, r6
 ldrne fp, [r4], #4
 strne fp, [r5], #4
 bne 1b

 mov fp, #0    @ Clear BSS (and zero fp)
1: cmp r6, r7
 strcc fp, [r6],#4
 bcc 1b

 ldmia r3, {r4, r5, r6, sp}
 str r9, [r4]   @ Save processor ID
 str r1, [r5]   @ Save machine type
 bic r4, r0, #CR_A   @ Clear 'A' bit
 stmia r6, {r0, r4}   @ Save control register values
 b start_kernel

 

/*
 * Setup common bits before finally enabling the MMU.  Essentially
 * this is just loading the page table pointer and domain access
 * registers.
 */
 .type __enable_mmu, %function
__enable_mmu:
#ifdef CONFIG_ALIGNMENT_TRAP
 orr r0, r0, #CR_A
#else
 bic r0, r0, #CR_A
#endif
#ifdef CONFIG_CPU_DCACHE_DISABLE
 bic r0, r0, #CR_C
#endif
#ifdef CONFIG_CPU_BPREDICT_DISABLE
 bic r0, r0, #CR_Z
#endif
#ifdef CONFIG_CPU_ICACHE_DISABLE
 bic r0, r0, #CR_I
#endif
 mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
        domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
        domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
        domain_val(DOMAIN_IO, DOMAIN_CLIENT))
 mcr p15, 0, r5, c3, c0, 0  @ load domain access register
 mcr p15, 0, r4, c2, c0, 0  @ load page table pointer
 b __turn_mmu_on

/*
 * Enable the MMU.  This completely changes the structure of the visible
 * memory space.  You will not be able to trace execution through this.
 * If you have an enquiry about this, *please* check the linux-arm-kernel
 * mailing list archives BEFORE sending another post to the list.
 *
 *  r0  = cp#15 control register
 *  r13 = *virtual* address to jump to upon completion
 *
 * other registers depend on the function called upon completion
 */
 .align 5
 .type __turn_mmu_on, %function
__turn_mmu_on:
 mov r0, r0
 mcr p15, 0, r0, c1, c0, 0  @ write control reg
 mrc p15, 0, r3, c0, c0, 0  @ read id reg
 mov r3, r3
 mov r3, r3
 mov pc, r13

 

/*
 * Setup the initial page tables.  We only setup the barest
 * amount which are required to get the kernel running, which
 * generally means mapping in the kernel code.
 *
 * r8  = machinfo
 * r9  = cpuid
 * r10 = procinfo
 *
 * Returns:
 *  r0, r3, r5, r6, r7 corrupted
 *  r4 = physical page table address
 */
 .type __create_page_tables, %function
__create_page_tables: // 235 라인 여기로 점프
 ldr r5, [r8, #MACHINFO_PHYSRAM] @ physram
 pgtbl r4, r5    @ page table address // 매크로 이다. 이런 명령어는 없죠..

adr 은 레이블이 값을 읽는 명령어

 

.macro pgtbl  rd phys

adr   Wrd, siext   (0xa000 / 8000)

sub  Wrd,  Wrd, #0x4000

.end                                                               <-----이렇게 생긴 매크로 이다.

 

 /*
  * Clear the 16K level 1 swapper page table
  */
 mov r0, r4
 mov r3, #0
 add r6, r0, #0x4000
1: str r3, [r0], #4
 str r3, [r0], #4
 str r3, [r0], #4
 str r3, [r0], #4
 teq r0, r6
 bne 1b

 ldr r7, [r10, #PROCINFO_MMUFLAGS] @ mmuflags

 

/arch/arm/mm/proc-xscale.S 에 보게 되면 r7에 값이 어떻게 들어가는지 알 수 있다. (0xC0E)

__pxa270_proc_info:
.long 0x69054110
.long 0xfffffff0
.long   PMD_TYPE_SECT | \
PMD_SECT_BUFFERABLE | \
PMD_SECT_CACHEABLE | \
PMD_SECT_AP_WRITE | \
PMD_SECT_AP_READ
b __xscale_setup

 /*
  * Create identity mapping for first MB of kernel to
  * cater for the MMU enable.  This identity mapping
  * will be removed by paging_init().  We use our current program
  * counter to determine corresponding section base address.
  */
 mov r6, pc, lsr #20   @ start of kernel section
 orr r3, r7, r6, lsl #20  @ flags + kernel base 
 str r3, [r4, r6, lsl #2]  @ identity mapping

 /* // r3 에는 결국 0xA000 / 0C0E 가 들어가게 된다.

  * Now setup the pagetables for our kernel direct
  * mapped region.  We round TEXTADDR down to the
  * nearest megabyte boundary.  It is assumed that
  * the kernel fits within 4 contigous 1MB sections.
  */

//TEXTADDR = A0008000 이 들어감
 add r0, r4,  #(TEXTADDR & 0xff000000) >> 18 @ start of kernel
 str r3, [r0, #(TEXTADDR & 0x00f00000) >> 18]! //r0 에는 0xA000 / 7000이 들어감 

//  /arch/arm/kernel/vmlinux.lds.S 에 TEXTADDR 이 정의 되어있다.
 add r3, r3, #1 << 20   // r3 에는 0xA010 / 0C0E 가 들어가는데

// 섹션단위로 다룬다. 1 mega단위로 다루는것이 섹션 그래서 1mega를 추가해 주는것이지요....

 후에 페이지 단위로 바꾸겠지만 서도~~

압축 풀린 커널을 4mega로 보기 때문에 0xA000 / 7000 부터 0xA000 / 7004 ....4개의 주소에 1mega에

해당하는 메모리 할당;; 잘 이해가 안감 ㄷㄷ;;
 str r3, [r0, #4]!   @ KERNEL + 1MB
 add r3, r3, #1 << 20
 str r3, [r0, #4]!   @ KERNEL + 2MB
 add r3, r3, #1 << 20
 str r3, [r0, #4]   @ KERNEL + 3MB

 /*
  * Then map first 1MB of ram in case it contains our boot params.
  */
 add r0, r4, #VIRT_OFFSET >> 18
 orr r6, r5, r7 //r6에는 0xA000 / 0C0E 요 값이 들어감
tr r6, [r0]

#ifdef CONFIG_XIP_KERNEL//  ↓얘네들은 실행 안되는 것들임↓
 /*
  * Map some ram to cover our .data and .bss areas.
  * Mapping 3MB should be plenty.
  */
 sub r3, r4, r5
 mov r3, r3, lsr #20 

 add r0, r0, r3, lsl #2
 add r6, r6, r3, lsl #20
 str r6, [r0], #4
 add r6, r6, #(1 << 20)
 str r6, [r0], #4
 add r6, r6, #(1 << 20)
 str r6, [r0]
#endif

 bic r7, r7, #0x0c   @ turn off cacheable
      @ and bufferable bits
#ifdef CONFIG_DEBUG_LL
 /*
  * Map in IO space for serial debugging.
  * This allows debug messages to be output
  * via a serial console before paging_init.
  */
 ldr r3, [r8, #MACHINFO_PGOFFIO]
 add r0, r4, r3
 rsb r3, r3, #0x4000   @ PTRS_PER_PGD*sizeof(long)
 cmp r3, #0x0800   @ limit to 512MB
 movhi r3, #0x0800
 add r6, r0, r3
 ldr r3, [r8, #MACHINFO_PHYSIO]
 orr r3, r3, r7
1: str r3, [r0], #4
 add r3, r3, #1 << 20
 teq r0, r6
 bne 1b
#if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS)
 /*
  * If we're using the NetWinder, we need to map in
  * the 16550-type serial port for the debug messages
  */
 teq r1, #MACH_TYPE_NETWINDER
 teqne r1, #MACH_TYPE_CATS
 bne 1f
 add r0, r4, #0x3fc0   @ ff000000
 mov r3, #0x7c000000
 orr r3, r3, r7
 str r3, [r0], #4
 add r3, r3, #1 << 20
 str r3, [r0], #4
1:
#endif
#endif
#ifdef CONFIG_ARCH_RPC
 /*
  * Map in screen at 0x02000000 & SCREEN2_BASE
  * Similar reasons here - for debug.  This is
  * only for Acorn RiscPC architectures.
  */
 add r0, r4, #0x80   @ 02000000
 mov r3, #0x02000000
 orr r3, r3, r7
 str r3, [r0]
 add r0, r4, #0x3600   @ d8000000
 str r3, [r0]
#endif
 mov pc, lr
 .ltorg

 

/*
 * Exception handling.  Something went wrong and we can't proceed.  We
 * ought to tell the user, but since we don't have any guarantee that
 * we're even running on the right architecture, we do virtually nothing.
 *
 * r0 = ascii error character:
 * a = invalid architecture
 * p = invalid processor
 * i = invalid calling convention
 *
 * Generally, only serious errors cause this.
 */
 .type __error, %function
__error:
#ifdef CONFIG_DEBUG_LL
 mov r8, r0    @ preserve r0
 adr r0, err_str
 bl printascii
 mov r0, r8
 bl printch
#endif
#ifdef CONFIG_ARCH_RPC
/*
 * Turn the screen red on a error - RiscPC only.
 */
 mov r0, #0x02000000
 mov r3, #0x11
 orr r3, r3, r3, lsl #8
 orr r3, r3, r3, lsl #16
 str r3, [r0], #4
 str r3, [r0], #4
 str r3, [r0], #4
 str r3, [r0], #4
#endif
1: mov r0, r0
 b 1b

#ifdef CONFIG_DEBUG_LL
 .type err_str, %object
err_str:
 .asciz "\nError: "
 .align
#endif

/*
 * Read processor ID register (CP#15, CR0), and look up in the linker-built
 * supported processor list.  Note that we can't use the absolute addresses
 * for the __proc_info lists since we aren't running with the MMU on
 * (and therefore, we are not in the correct address space).  We have to
 * calculate the offset.
 *
 * Returns:
 * r3, r4, r6 corrupted
 * r5 = proc_info pointer in physical address space
 * r9 = cpuid
 */    //끝@@
 .type __lookup_processor_type, %function
__lookup_processor_type: // 여기가 두번째로 보는곳 414 라인 실행 되고있는 머신의 프로세서 타입을 찾는다.

 ldmda r3, {r5, r6, r9}
 sub r3, r3, r9   @ get offset between virt&phys
 add r5, r5, r3   @ convert virt addresses to
 add r6, r6, r3   @ physical address space
 mrc p15, 0, r9, c0, c0  @ get processor id // 코프로세서 15번에서 프로세서 id를 읽어옴1: ldmia r5, {r3, r4}   @ value, mask
 and r4, r4, r9   @ mask wanted bits
 teq r3, r4  //exclusive OR   r3 = 0x69054110  r4 = 0xffffffff 가 나올때 까지 계속 br
 beq 2f
 add r5, r5, #PROC_INFO_SZ  @ sizeof(proc_info_list)
 cmp r5, r6
 blt 1b
 mov r5, #0    @ unknown processor
2: mov pc, lr

/*
 * This provides a C-API version of the above function.
 */
ENTRY(lookup_processor_type) stmfd sp!, {r4 - r6, r9, lr}
 bl __lookup_processor_type
 mov r0, r5
 ldmfd sp!, {r4 - r6, r9, pc}

/*
 * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for

 * more information about the __proc_info and __arch_info structures.
 */
 .long __proc_info_begin
 .long __proc_info_end
3: .long .
 .long __arch_info_begin
 .long __arch_info_end

/*
 * Lookup machine architecture in the linker-build list of architectures.
 * Note that we can't use the absolute addresses for the __arch_info
 * lists since we aren't running with the MMU on (and therefore, we are
 * not in the correct address space).  We have to calculate the offset.
 *
 *  r1 = machine architecture number
 * Returns:
 *  r3, r4, r6 corrupted
 *  r5 = mach_info pointer in physical address space
 */
 .type __lookup_machine_type, %function
__lookup_machine_type: //462라인 머신 타입을 로드한다.
 adr r3, 3b
 ldmia r3, {r4, r5, r6}
 sub r3, r3, r4   @ get offset between virt&phys
 add r5, r5, r3   @ convert virt addresses to
 add r6, r6, r3   @ physical address space
1: ldr r3, [r5]   @ get machine type
 teq r3, r1    @ matches loader number?

//  r1에는 /arch/arm/tools/mach-type 이란 파일에 정의 되어있으며 head-xscale.S에서 r7번 레지스터로 넘겨준 값 아키텍쳐 아이디

 


 beq 2f    @ found
 add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
 cmp r5, r6
 blt 1b
 mov r5, #0    @ unknown machine
2: mov pc, lr

/*
 * This provides a C-API version of the above function.
 */
ENTRY(lookup_machine_type)
 stmfd sp!, {r4 - r6, lr}
 mov r1, r0
 bl __lookup_machine_type
 mov r0, r5
 ldmfd sp!, {r4 - r6, pc}




'Linux > Boot' 카테고리의 다른 글

세번째head.S /arch/arm/kernel/head.S 분석 .  (0) 2009.06.05
여담...  (0) 2009.06.05
/kernel/head.S  (0) 2009.06.05
head.S  (0) 2009.06.05
head.S  (0) 2009.06.05

WRITTEN BY
RootFriend
개인적으로... 나쁜 기억력에 도움되라고 만들게되었습니다.

,

/kernel/head.S

Linux/Boot 2009. 6. 5. 05:15

 
( relocation code)(2)
 decompressed_kernel
 
 heap
 stack

head.S

 1차 vm linux

( relocation code)(1)

 

 

1차 vmlinux 가 생성 되기전 압축된 커널을 보면 세가지 파일이 합쳐져 있는데 piggy.o head.S misc.c

로 구성 된다. 이때 까지는 물리주소로 동작(mmu 가 동작하지 않으므로)하는데

 

앞선 head.S로 인해 압축이 풀리고 재배치가 끝나게 되면 진정한 1차 vmlinux 가 나오게 된다.

이제부터 볼 kernel/head.S 는 mmu를 동작시켜 가상주소에서 동작할 수 있게 해줄것이다.

페이지테이블 생성한다는데 뭔말인지...;; 커널의 시작 물리 번지 0xA000 / 8000 은 가상주소 0xC000 / 8000 으로 교체될 것이다 .


[출처] /kernel/head.S|작성자 바다사랑


'Linux > Boot' 카테고리의 다른 글

여담...  (0) 2009.06.05
두번째head.S /arch/arm/kernel/head.S 분석 .  (0) 2009.06.05
head.S  (0) 2009.06.05
head.S  (0) 2009.06.05
부트로더 분석  (0) 2009.06.05

WRITTEN BY
RootFriend
개인적으로... 나쁜 기억력에 도움되라고 만들게되었습니다.

,

head.S

Linux/Boot 2009. 6. 5. 05:14

실제 커널을 담고 있는 것 은 pyggi.o 이다. 이것은 1차 vmlinux에서 압축된 상태이다.

 

커널의 텍스트 어드레스 (시작주소) 0xA000 / 8000

   
   
 decompress_kernel (1.)여기에 압축된 커널을 풀고나서
 heap  
 stack  
 piggy.o  
 0xA000 / 8000 (2.)여기로 재배치(relocation)한다.
   
 0xA000 / 0000  

decompressed_kernel 을 이용하여 압축풀린곳의 위치가 (1.)자리

이것을 정말 동작할 위치인 0xA000 / 0000 의 자리에 옮겨와야 한다.

그러므로 압축된 거널안에 잇었던 relocation code를  (1.)

의 위치에 옮기 고  478라인의 reloc_start로 br

이때 r5번은 압축풀린 커널의 시작 주소를 가지고 있고 r8은 압축풀린 커널의 마지막 주소를

그리고 r1번은 커널이 실제 동작할 위치인 (2.) 의 주소를 가지고 있다.

 

arch/arm/boot/compressed/head.S 의 할 일은 거의 끝나가고....

 

arch/arm/kernel/head.S 의 할 일(페이지 테이블 만들기, 가상주소와 물리주소의 변환)

시작

 

세개의 레지스터를 두번째 head.S에 넘겨주게 되는데 r7(아키텍쳐 아이디) 

r0 (;;잊어버렷다)     r4(a000/8000) 레지스터의 값을 프로그램카운터에 넘겨주고 운명한다.


[출처] head.S|작성자 바다사랑

'Linux > Boot' 카테고리의 다른 글

여담...  (0) 2009.06.05
두번째head.S /arch/arm/kernel/head.S 분석 .  (0) 2009.06.05
/kernel/head.S  (0) 2009.06.05
head.S  (0) 2009.06.05
부트로더 분석  (0) 2009.06.05

WRITTEN BY
RootFriend
개인적으로... 나쁜 기억력에 도움되라고 만들게되었습니다.

,

head.S

Linux/Boot 2009. 6. 5. 05:13

lsl , lsr 로지컬 시프트

 

램의 시작 주소 0xA000/0000 을 알아내기위해 orr

 

r0, r0, #0x000d @ Write buffer, mmu enable

mov r1, #-1          r1 = ffffffff;

page table 의 시작 주소 0xA000/4000

 

실제 user_stack의 주소0x0018/c91c + 0xA000/0000 + 4096

전역변수 중에 초기화 되지 않은건 BSS영역에 있어야 한다.

 

 

 

 

not_relocated: mov r0, #0
1: str r0, [r2], #4 @ clear bss
str r0, [r2], #4
str r0, [r2], #4
str r0, [r2], #4
cmp r2, r3
blo 1b

/*
* The C runtime environment should now be setup
* sufficiently.  Turn the cache on, set up some
* pointers, and start decompressing.
*/
bl cache_on

mov r1, sp @ malloc space above stack
add r2, sp, #0x10000 @ 64k max

 

 r1에는 0xA000/8000 + 0x0018/d91c   -->  sp

r2 에는 sp + 64 kbyte

 heap
 stack
 
   0xA000/8000

 

r0를 통해서 넘어오는 값은 압축을 풀어야 할 piggy.o의 시작 주소.

 

r1, r2를 이용해서 free 메모리의 시작과 끝을 잡는다.

 

 

 

 

 

 

 

 

/*
* All code following this line is relocatable.  It is relocated by
* the above code to the end of the decompressed kernel image and
* executed there.  During this time, we have no stacks.
*
* r0     = decompressed kernel length
* r1-r3  = unused
* r4     = kernel execution address
* r5     = decompressed kernel start
* r6     = processor ID
* r7     = architecture ID
* r8-r14 = unused
*/
여기까지 실행 하면 piggy.o가 다른 메모리 영역에 풀린 상태

 

 

 

 

 

 

 

여기부터 시작  head.S*********************************************************************

/*
 *  linux/arch/arm/boot/compressed/head.S
 *
 *  Copyright (C) 1996-2002 Russell King
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/config.h>
#include <linux/linkage.h>

/*
 * Debugging stuff
 *
 * Note that these macros must not contain any code which is not
 * 100% relocatable.  Any attempt to do so will result in a crash.
 * Please select one of the following when turning on debugging.
 */
#ifdef DEBUG
#if defined(CONFIG_DEBUG_DC21285_PORT)
  .macro loadsp, rb
  mov \rb, #0x42000000
  .endm
  .macro writeb, rb
  str \rb, [r3, #0x160]
  .endm
#elif defined(CONFIG_DEBUG_ICEDCC)
  .macro loadsp, rb
  .endm
  .macro writeb, rb
  mcr p14, 0, \rb, c0, c1, 0
  .endm
#elif defined(CONFIG_FOOTBRIDGE)
  .macro loadsp, rb
  mov \rb, #0x7c000000
  .endm
  .macro writeb, rb
  strb \rb, [r3, #0x3f8]
  .endm
#elif defined(CONFIG_ARCH_RPC)
  .macro loadsp, rb
  mov \rb, #0x03000000
  orr \rb, \rb, #0x00010000
  .endm
  .macro writeb, rb
  strb \rb, [r3, #0x3f8 << 2]
  .endm
#elif defined(CONFIG_ARCH_INTEGRATOR)
  .macro loadsp, rb
  mov \rb, #0x16000000
  .endm
  .macro writeb, rb
  strb \rb, [r3, #0]
  .endm
#elif defined(CONFIG_ARCH_PXA) /* Xscale-type */
  .macro  loadsp, rb
  mov \rb, #0x40000000
  orr \rb, \rb, #0x00100000
  .endm
  .macro writeb, rb
  strb \rb, [r3, #0]
  .endm
#elif defined(CONFIG_ARCH_SA1100)
  .macro loadsp, rb
  mov \rb, #0x80000000 @ physical base address
#  if defined(CONFIG_DEBUG_LL_SER3)
  add \rb, \rb, #0x00050000 @ Ser3
#  else
  add \rb, \rb, #0x00010000 @ Ser1
#  endif
  .endm
  .macro writeb, rb
  str \rb, [r3, #0x14] @ UTDR
  .endm
#elif defined(CONFIG_ARCH_IXP4XX)
  .macro loadsp, rb
  mov \rb, #0xc8000000
  .endm
  .macro writeb, rb
  str \rb, [r3, #0]
#elif defined(CONFIG_ARCH_IXP2000)
  .macro loadsp, rb
  mov \rb, #0xc0000000
  orr \rb, \rb, #0x00030000
  .endm
  .macro writeb, rb
  str \rb, [r3, #0]
  .endm
#elif defined(CONFIG_ARCH_LH7A40X)
  .macro loadsp, rb
  ldr \rb, =0x80000700 @ UART2 UARTBASE
  .endm
  .macro writeb, rb
  strb \rb, [r3, #0]
  .endm
#elif defined(CONFIG_ARCH_OMAP)
  .macro  loadsp, rb
  mov \rb, #0xff000000 @ physical base address
  add \rb, \rb, #0x00fb0000
#if defined(CONFIG_OMAP_LL_DEBUG_UART2) || defined(CONFIG_OMAP_LL_DEBUG_UART3)
  add \rb, \rb, #0x00000800
#endif
#ifdef CONFIG_OMAP_LL_DEBUG_UART3
  add \rb, \rb, #0x00009000
#endif
  .endm
  .macro writeb, rb
  strb \rb, [r3]
  .endm
#elif defined(CONFIG_ARCH_IOP331)
  .macro loadsp, rb
                mov    \rb, #0xff000000
                orr     \rb, \rb, #0x00ff0000
                orr     \rb, \rb, #0x0000f700   @ location of the UART
  .endm
  .macro writeb, rb
  str \rb, [r3, #0]
  .endm
#elif defined(CONFIG_ARCH_S3C2410)
   .macro loadsp, rb
  mov \rb, #0x50000000
  add \rb, \rb, #0x4000 * CONFIG_S3C2410_LOWLEVEL_UART_PORT
  .endm
  .macro writeb, rb
  strb \rb, [r3, #0x20]
  .endm
#else
#error no serial architecture defined
#endif
#endif

  .macro kputc,val
  mov r0, \val
  bl putc
  .endm

  .macro kphex,val,len
  mov r0, \val
  mov r1, #\len
  bl phex
  .endm

  .macro debug_reloc_start
#ifdef DEBUG
  kputc #'\n'
  kphex r6, 8  /* processor id */
  kputc #':'
  kphex r7, 8  /* architecture id */
  kputc #':'
  mrc p15, 0, r0, c1, c0
  kphex r0, 8  /* control reg */
  kputc #'\n'
  kphex r5, 8  /* decompressed kernel start */
  kputc #'-'
  kphex r8, 8  /* decompressed kernel end  */
  kputc #'>'
  kphex r4, 8  /* kernel execution address */
  kputc #'\n'
#endif
  .endm

  .macro debug_reloc_end
#ifdef DEBUG
  kphex r5, 8  /* end of kernel */
  kputc #'\n'
  mov r0, r4
  bl memdump  /* dump 256 bytes at start of kernel */
#endif
  .endm

  .section ".start", #alloc, #execinstr
/*
 * sort out different calling conventions
 */
  .align
start:
  .type start,#function
  .rept 8
  mov r0, r0
  .endr

  b 1f
  .word 0x016f2818  @ Magic numbers to help the loader
  .word start   @ absolute load/run zImage address
  .word _edata   @ zImage end address
1:  mov r7, r1   @ save architecture ID
  mov r8, #0   @ save r0

#ifndef __ARM_ARCH_2__
  /*
   * Booting from Angel - need to enter SVC mode and disable
   * FIQs/IRQs (numeric definitions from angel arm.h source).
   * We only do this if we were in user mode on entry.
   */
  mrs r2, cpsr  @ get current mode
  tst r2, #3   @ not user?
  bne not_angel
  mov r0, #0x17  @ angel_SWIreason_EnterSVC
  swi 0x123456  @ angel_SWI_ARM
not_angel:
  mrs r2, cpsr  @ turn off interrupts to
  orr r2, r2, #0xc0  @ prevent angel from running
  msr cpsr_c, r2
#else
  teqp pc, #0x0c000003  @ turn off interrupts
#endif

  /*
   * Note that some cache flushing and other stuff may
   * be needed here - is there an Angel SWI call for this?
   */

  /*
   * some architecture specific code can be inserted
   * by the linker here, but it should preserve r7 and r8.
   */

  .text
  adr r0, LC0
  ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp}
  subs r0, r0, r1  @ calculate the delta offset

      @ if delta is zero, we are
  beq not_relocated  @ running at the address we
      @ were linked at.

  /*
   * We're running at a different address.  We need to fix
   * up various pointers:
   *   r5 - zImage base address
   *   r6 - GOT start
   *   ip - GOT end
   */
  add r5, r5, r0
  add r6, r6, r0
  add ip, ip, r0

#ifndef CONFIG_ZBOOT_ROM
  /*
   * If we're running fully PIC === CONFIG_ZBOOT_ROM = n,
   * we need to fix up pointers into the BSS region.
   *   r2 - BSS start
   *   r3 - BSS end
   *   sp - stack pointer
   */
  add r2, r2, r0
  add r3, r3, r0
  add sp, sp, r0

  /*
   * Relocate all entries in the GOT table.
   */
1:  ldr r1, [r6, #0]  @ relocate entries in the GOT
  add r1, r1, r0  @ table.  This fixes up the
  str r1, [r6], #4  @ C references.
  cmp r6, ip
  blo 1b
#else

  /*
   * Relocate entries in the GOT table.  We only relocate
   * the entries that are outside the (relocated) BSS region.
   */
1:  ldr r1, [r6, #0]  @ relocate entries in the GOT
  cmp r1, r2   @ entry < bss_start ||
  cmphs r3, r1   @ _end < entry
  addlo r1, r1, r0  @ table.  This fixes up the
  str r1, [r6], #4  @ C references.
  cmp r6, ip
  blo 1b
#endif

not_relocated: mov r0, #0
1:  str r0, [r2], #4  @ clear bss
  str r0, [r2], #4
  str r0, [r2], #4
  str r0, [r2], #4
  cmp r2, r3
  blo 1b

  /*
   * The C runtime environment should now be setup
   * sufficiently.  Turn the cache on, set up some
   * pointers, and start decompressing.
   */
  bl cache_on

  mov r1, sp   @ malloc space above stack
  add r2, sp, #0x10000 @ 64k max

/*
 * Check to see if we will overwrite ourselves.
 *   r4 = final kernel address
 *   r5 = start of this image
 *   r2 = end of malloc space (and therefore this image)
 * We basically want:
 *   r4 >= r2 -> OK
 *   r4 + image length <= r5 -> OK
 */
  cmp r4, r2
  bhs wont_overwrite
  add r0, r4, #4096*1024 @ 4MB largest kernel size
  cmp r0, r5
  bls wont_overwrite

  mov r5, r2   @ decompress after malloc space
  mov r0, r5
  mov r3, r7
  bl decompress_kernel

  add r0, r0, #127
  bic r0, r0, #127  @ align the kernel length
/*
 * r0     = decompressed kernel length
 * r1-r3  = unused
 * r4     = kernel execution address
 * r5     = decompressed kernel start
 * r6     = processor ID
 * r7     = architecture ID
 * r8-r14 = unused
 */
  add r1, r5, r0  @ end of decompressed kernel
  adr r2, reloc_start
  ldr r3, LC1
  add r3, r2, r3
1:  ldmia r2!, {r8 - r13}  @ copy relocation code
  stmia r1!, {r8 - r13}    압축풀린 커널이 시작하는 주소
  ldmia r2!, {r8 - r13}    릴로케이션 코드를 압축되지 않은 커널이 올라간 곳의 바로 윗주소에 넣는다.
  stmia r1!, {r8 - r13}
  cmp r2, r3
  blo 1b

  bl cache_clean_flush
  add pc, r5, r0  @ call relocation code

/*
 * We're not in danger of overwriting ourselves.  Do this the simple way.
 *
 * r4     = kernel execution address
 * r7     = architecture ID
 */
wont_overwrite: mov r0, r4
  mov r3, r7
  bl decompress_kernel
  b call_kernel

  .type LC0, #object
LC0:  .word LC0   @ r1
  .word __bss_start  @ r2
  .word _end   @ r3
  .word zreladdr  @ r4
  .word _start   @ r5
  .word _got_start  @ r6
  .word _got_end  @ ip
  .word user_stack+4096  @ sp
LC1:  .word reloc_end - reloc_start
  .size LC0, . - LC0

#ifdef CONFIG_ARCH_RPC
  .globl params
params:  ldr r0, =params_phys
  mov pc, lr
  .ltorg
  .align
#endif

/*
 * Turn on the cache.  We need to setup some page tables so that we
 * can have both the I and D caches on.
 *
 * We place the page tables 16k down from the kernel execution address,
 * and we hope that nothing else is using it.  If we're using it, we
 * will go pop!
 *
 * On entry,
 *  r4 = kernel execution address
 *  r6 = processor ID
 *  r7 = architecture number
 *  r8 = run-time address of "start"
 * On exit,
 *  r1, r2, r3, r8, r9, r12 corrupted
 * This routine must preserve:
 *  r4, r5, r6, r7
 */
  .align 5
cache_on: mov r3, #8   @ cache_on function
  b call_cache_fn

__setup_mmu: sub r3, r4, #16384  @ Page directory size
  bic r3, r3, #0xff  @ Align the pointer
  bic r3, r3, #0x3f00
/*
 * Initialise the page tables, turning on the cacheable and bufferable
 * bits for the RAM area only.
 */
  mov r0, r3
  mov r8, r0, lsr #18
  mov r8, r8, lsl #18  @ start of RAM
  add r9, r8, #0x10000000 @ a reasonable RAM size
  mov r1, #0x12
  orr r1, r1, #3 << 10
  add r2, r3, #16384
1:  cmp r1, r8   @ if virt > start of RAM
  orrhs r1, r1, #0x0c  @ set cacheable, bufferable
  cmp r1, r9   @ if virt > end of RAM
  bichs r1, r1, #0x0c  @ clear cacheable, bufferable
  str r1, [r0], #4  @ 1:1 mapping
  add r1, r1, #1048576
  teq r0, r2
  bne 1b
/*
 * If ever we are running from Flash, then we surely want the cache
 * to be enabled also for our execution instance...  We map 2MB of it
 * so there is no map overlap problem for up to 1 MB compressed kernel.
 * If the execution is in RAM then we would only be duplicating the above.
 */
  mov r1, #0x1e
  orr r1, r1, #3 << 10
  mov r2, pc, lsr #20
  orr r1, r1, r2, lsl #20
  add r0, r3, r2, lsl #2
  str r1, [r0], #4
  add r1, r1, #1048576
  str r1, [r0]
  mov pc, lr

__armv4_cache_on:
  mov r12, lr
  bl __setup_mmu
  mov r0, #0
  mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
  mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
  mrc p15, 0, r0, c1, c0, 0 @ read control reg
  orr r0, r0, #0x5000  @ I-cache enable, RR cache replacement
  orr r0, r0, #0x0030
  bl __common_cache_on
  mov r0, #0
  mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
  mov pc, r12

__arm6_cache_on:
  mov r12, lr
  bl __setup_mmu
  mov r0, #0
  mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3
  mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3
  mov r0, #0x30
  bl __common_cache_on
  mov r0, #0
  mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3
  mov pc, r12

__common_cache_on:
#ifndef DEBUG
  orr r0, r0, #0x000d  @ Write buffer, mmu
#endif
  mov r1, #-1
  mcr p15, 0, r3, c2, c0, 0 @ load page table pointer
  mcr p15, 0, r1, c3, c0, 0 @ load domain access control
  mcr p15, 0, r0, c1, c0, 0 @ load control register
  mov pc, lr

/*
 * All code following this line is relocatable.  It is relocated by
 * the above code to the end of the decompressed kernel image and
 * executed there.  During this time, we have no stacks.
 *
 * r0     = decompressed kernel length
 * r1-r3  = unused
 * r4     = kernel execution address
 * r5     = decompressed kernel start
 * r6     = processor ID
 * r7     = architecture ID
 * r8-r14 = unused
 */
  .align 5
reloc_start: add r8, r5, r0
  debug_reloc_start
  mov r1, r4
1:
  .rept 4
  ldmia r5!, {r0, r2, r3, r9 - r13} @ relocate kernel
  stmia r1!, {r0, r2, r3, r9 - r13}
  .endr

  cmp r5, r8
  blo 1b
  debug_reloc_end

call_kernel: bl cache_clean_flush
  bl cache_off
  mov r0, #0
  mov r1, r7   @ restore architecture number
  mov pc, r4   @ call kernel

/*
 * Here follow the relocatable cache support functions for the
 * various processors.  This is a generic hook for locating an
 * entry and jumping to an instruction at the specified offset
 * from the start of the block.  Please note this is all position
 * independent code.
 *
 *  r1  = corrupted
 *  r2  = corrupted
 *  r3  = block offset
 *  r6  = corrupted
 *  r12 = corrupted
 */

call_cache_fn: adr r12, proc_types
  mrc p15, 0, r6, c0, c0 @ get processor ID  69054110??
1:  ldr r1, [r12, #0]  @ get value
  ldr r2, [r12, #4]  @ get mask
  eor r1, r1, r6  @ (real ^ match)
  tst r1, r2   @       & mask  // r2=f , r1=0;
  addeq pc, r12, r3  @ call cache function  r3 = 16 이었다.  16을 더하면 캐시를 플러시 하는 함수를 호출하는것이 된다.
  add r12, r12, #4*5
  b 1b

/*
 * Table for cache operations.  This is basically:
 *   - CPU ID match
 *   - CPU ID mask
 *   - 'cache on' method instruction
 *   - 'cache off' method instruction
 *   - 'cache flush' method instruction
 *
 * We match an entry using: ((real_id ^ match) & mask) == 0
 *
 * Writethrough caches generally only need 'on' and 'off'
 * methods.  Writeback caches _must_ have the flush method
 * defined.
 */
  .type proc_types,#object
proc_types:
  .word 0x41560600  @ ARM6/610
  .word 0xffffffe0
  b __arm6_cache_off @ works, but slow
  b __arm6_cache_off
  mov pc, lr
@  b __arm6_cache_on  @ untested
@  b __arm6_cache_off
@  b __armv3_cache_flush

  .word 0x00000000  @ old ARM ID
  .word 0x0000f000
  mov pc, lr
  mov pc, lr
  mov pc, lr

  .word 0x41007000  @ ARM7/710
  .word 0xfff8fe00
  b __arm7_cache_off
  b __arm7_cache_off
  mov pc, lr

  .word 0x41807200  @ ARM720T (writethrough)
  .word 0xffffff00
  b __armv4_cache_on
  b __armv4_cache_off
  mov pc, lr

  .word 0x00007000  @ ARM7 IDs
  .word 0x0000f000
  mov pc, lr
  mov pc, lr
  mov pc, lr

  @ Everything from here on will be the new ID system.

  .word 0x4401a100  @ sa110 / sa1100
  .word 0xffffffe0
  b __armv4_cache_on
  b __armv4_cache_off
  b __armv4_cache_flush

  .word 0x6901b110  @ sa1110
  .word 0xfffffff0
  b __armv4_cache_on
  b __armv4_cache_off
  b __armv4_cache_flush

  @ These match on the architecture ID

  .word 0x00020000  @ ARMv4T
  .word 0x000f0000
  b __armv4_cache_on
  b __armv4_cache_off
  b __armv4_cache_flush

  .word 0x00050000  @ ARMv5TE
  .word 0x000f0000
  b __armv4_cache_on
  b __armv4_cache_off
  b __armv4_cache_flush

  .word 0x00060000  @ ARMv5TEJ
  .word 0x000f0000
  b __armv4_cache_on
  b __armv4_cache_off
  b __armv4_cache_flush

  .word 0x00070000  @ ARMv6
  .word 0x000f0000
  b __armv4_cache_on
  b __armv4_cache_off
  b __armv6_cache_flush

  .word 0   @ unrecognised type
  .word 0
  mov pc, lr
  mov pc, lr
  mov pc, lr

  .size proc_types, . - proc_types

/*
 * Turn off the Cache and MMU.  ARMv3 does not support
 * reading the control register, but ARMv4 does.
 *
 * On entry,  r6 = processor ID
 * On exit,   r0, r1, r2, r3, r12 corrupted
 * This routine must preserve: r4, r6, r7
 */
  .align 5
cache_off: mov r3, #12   @ cache_off function
  b call_cache_fn

__armv4_cache_off:
  mrc p15, 0, r0, c1, c0
  bic r0, r0, #0x000d
  mcr p15, 0, r0, c1, c0 @ turn MMU and cache off
  mov r0, #0
  mcr p15, 0, r0, c7, c7 @ invalidate whole cache v4
  mcr p15, 0, r0, c8, c7 @ invalidate whole TLB v4
  mov pc, lr

__arm6_cache_off:
  mov r0, #0x00000030  @ ARM6 control reg.
  b __armv3_cache_off

__arm7_cache_off:
  mov r0, #0x00000070  @ ARM7 control reg.
  b __armv3_cache_off

__armv3_cache_off:
  mcr p15, 0, r0, c1, c0, 0 @ turn MMU and cache off
  mov r0, #0
  mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3
  mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3
  mov pc, lr

/*
 * Clean and flush the cache to maintain consistency.
 *
 * On entry,
 *  r6 = processor ID
 * On exit,
 *  r1, r2, r3, r11, r12 corrupted
 * This routine must preserve:
 *  r0, r4, r5, r6, r7
 */
  .align 5
cache_clean_flush:
  mov r3, #16
  b call_cache_fn

__armv6_cache_flush:
  mov r1, #0
  mcr p15, 0, r1, c7, c14, 0 @ clean+invalidate D
  mcr p15, 0, r1, c7, c5, 0 @ invalidate I+BTB
  mcr p15, 0, r1, c7, c15, 0 @ clean+invalidate unified
  mcr p15, 0, r1, c7, c10, 4 @ drain WB
  mov pc, lr

__armv4_cache_flush:
  mov r2, #64*1024  @ default: 32K dcache size (*2)
  mov r11, #32  @ default: 32 byte line size
  mrc p15, 0, r3, c0, c0, 1 @ read cache type
  teq r3, r6   @ cache ID register present?
  beq no_cache_id
  mov r1, r3, lsr #18
  and r1, r1, #7
  mov r2, #1024
  mov r2, r2, lsl r1  @ base dcache size *2
  tst r3, #1 << 14  @ test M bit
  addne r2, r2, r2, lsr #1 @ +1/2 size if M == 1
  mov r3, r3, lsr #12
  and r3, r3, #3
  mov r11, #8
  mov r11, r11, lsl r3 @ cache line size in bytes
no_cache_id:
  bic r1, pc, #63  @ align to longest cache line
  add r2, r1, r2
1:  ldr r3, [r1], r11  @ s/w flush D cache
  teq r1, r2
  bne 1b

  mcr p15, 0, r1, c7, c5, 0 @ flush I cache
  mcr p15, 0, r1, c7, c6, 0 @ flush D cache
  mcr p15, 0, r1, c7, c10, 4 @ drain WB
  mov pc, lr

__armv3_cache_flush:
  mov r1, #0
  mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3
  mov pc, lr

/*
 * Various debugging routines for printing hex characters and
 * memory, which again must be relocatable.
 */
#ifdef DEBUG
  .type phexbuf,#object
phexbuf: .space 12
  .size phexbuf, . - phexbuf

phex:  adr r3, phexbuf
  mov r2, #0
  strb r2, [r3, r1]
1:  subs r1, r1, #1
  movmi r0, r3
  bmi puts
  and r2, r0, #15
  mov r0, r0, lsr #4
  cmp r2, #10
  addge r2, r2, #7
  add r2, r2, #'0'
  strb r2, [r3, r1]
  b 1b

puts:  loadsp r3
1:  ldrb r2, [r0], #1
  teq r2, #0
  moveq pc, lr
2:  writeb r2
  mov r1, #0x00020000
3:  subs r1, r1, #1
  bne 3b
  teq r2, #'\n'
  moveq r2, #'\r'
  beq 2b
  teq r0, #0
  bne 1b
  mov pc, lr
putc:
  mov r2, r0
  mov r0, #0
  loadsp r3
  b 2b

memdump: mov r12, r0
  mov r10, lr
  mov r11, #0
2:  mov r0, r11, lsl #2
  add r0, r0, r12
  mov r1, #8
  bl phex
  mov r0, #':'
  bl putc
1:  mov r0, #' '
  bl putc
  ldr r0, [r12, r11, lsl #2]
  mov r1, #8
  bl phex
  and r0, r11, #7
  teq r0, #3
  moveq r0, #' '
  bleq putc
  and r0, r11, #7
  add r11, r11, #1
  teq r0, #7
  bne 1b
  mov r0, #'\n'
  bl putc
  cmp r11, #64
  blt 2b
  mov pc, r10
#endif

reloc_end:

  .align
  .section ".stack", "w"
user_stack: .space 4096

[출처] head.S|작성자 바다사랑

'Linux > Boot' 카테고리의 다른 글

여담...  (0) 2009.06.05
두번째head.S /arch/arm/kernel/head.S 분석 .  (0) 2009.06.05
/kernel/head.S  (0) 2009.06.05
head.S  (0) 2009.06.05
부트로더 분석  (0) 2009.06.05

WRITTEN BY
RootFriend
개인적으로... 나쁜 기억력에 도움되라고 만들게되었습니다.

,

부트로더 분석

Linux/Boot 2009. 6. 5. 05:11

arch/arm/boot/compressed/Head.S  ---> 처음 실행되어 압축 풀어주는 역할

 

arch/arm/kernel/Head.S  ---> 가상 주소를 쓸수 있게 하고, start_kernel 로 제어권을 넘긴다.

 

start_kernel 에서는 로그인까지 담당

 

 

커널이 압축이 되는것은 makefile을 쫓아가면 알 수 있다. (커널 스스로 압축을 풀 수 있는 코드를 붙인다.)

 

플래시에 올라간 압축된 커널 이미지는 다시 램으로 옮겨지고 부트로더 에서 커널 압축을 풀어준다

 

vmlinux(start_kernel 부터의 커널은 여기 다있다.) head.S추가  - 가상주소를 쓸 수 있게 하고(MMU)

 

vmlinuxlds.in  ---> 컴파일 ---> vmlinux.lds (링커 스크립트)  오브젝트 파일을 합칠때 필요한 파일

 

head.o, misc.o, piggy.o를 합치면.---> 2차 vmlinux

(piggy.o는 실제 커널 소스 , head.o는 압축을 풀수있는 소스)

 

그걸 다시 obj copy 하게 되면 zImage 생성 !!

 

misc.c 안에 있는 c로 된소스  decompress_kernel()  그 안에 g_unzip() 요게 압축 풀어주는 역할

c소스가 실행 되려면 스택영역 BSS영역이 필요하다.

      

relocationcode

▶여기에 커널의 압축을 풀고

 h   

 i   

 p   

 s t a c k

 4K

 piggy.o        실제 커널

 misc.o         실제 커널 zImage

 head.o (relocation code 를 갖고있다.)  실제 커널

0xA000 8000

 

0xA000 0000

4k떨어진 곳에 스택 64k떨어진 곳에 힙! 그 이후에다 커널 압축을 푼다.

relocation code :재배치 코드  ▶압축푼 커널을 다시 제 위치로



[출처] 부트로더 분석|작성자 바다사랑


'Linux > Boot' 카테고리의 다른 글

여담...  (0) 2009.06.05
두번째head.S /arch/arm/kernel/head.S 분석 .  (0) 2009.06.05
/kernel/head.S  (0) 2009.06.05
head.S  (0) 2009.06.05
head.S  (0) 2009.06.05

WRITTEN BY
RootFriend
개인적으로... 나쁜 기억력에 도움되라고 만들게되었습니다.

,