기존의 S3C2410 에 포팅되어 있는 SCV/OS 를 PXA255 아키텍처로 포팅하는 과정을 문서로 담고 있다.
s3c2410 의 경우, t32 같은 디버깅 장비가 있기 때문에 디버깅하기가 수월했지만, pxa255 의 경우에는 디버깅 장비가 없는 상태에서 디버깅해야 하기 때문에 어려운 점이 있다. 타겟보드로는 falinux 의 ez-x5 를 사용하였다. 보드의 사양은 http://falinux.com 을 참고하기 바란다.

수정할 것들

아무래도 칩 제조회사와 아키텍처가 다른 만큼, 비슷한 부분도 있지만 다른 부분도 있다. 때문에 기존의 SCV/OS 에서 수정해야할 부분이 있다.
수정이 필요한 부분은 hal 쪽 부분이다.
좀 더 구체적으로 얘기하자면, bootloader, serial, timer 이다.
차례대로 하나씩 설명해 보겠다.

cpu 와 sdram 을 초기화 해주고, 커널을 메모리 상에 올리는 작업을 해야 하기 때문에, 우선적으로 진행되어야 할 것들은 이 것들에 대한 설정이다.
여기서 한가지 염두해야 할 사항은 rtos 의 경우, cache 와 buffer 를 사용하지 않는다는 점과 현재 scv/os 는 mmu 를 사용하지 않는다는 점이다.
이에 대한 설정은 ezboot 를 참조했다.

#include <cpu.h>
 
	.global reset
 
	.text
 
reset:
	b start
	b undefined_instruction
	b swi_handler
	b abort_prefetch
	b abort_data
	b not_used
	b irq_handler
	b fiq_handler
 
start:	
  	//-------------------------------------------
	// change Supervisor mode & IRQ/FIQ Disable
	//-------------------------------------------
 
	  mrs     r0, CPSR               
    bic     r0, r0, #0x1f
    orr     r0, r0, #(0x13 | 0xc0)
    msr     CPSR, r0
 
		//-------------------------------------------
		// Change CPU SPEED
		//-------------------------------------------
 
		// CCCR 레지스터를 설정하여 CPU 속도를 맞춘다.
		ldr	r0, =PXA_REG_CCCR
		ldr	r1, =CPU_SPEED
		str	r1, [r0]
 
		// 동작속도를 변경한다.
		mov	r0, #PXA_COP_CCLKCFG_FCS
		mcr	p14, 0, r0, c6, c0, 0
 
		// 터보모드가 있는지 확인한다.
		and 	r1, r1, #(0x7 << 7)	// CCCR_BF_N Mask
		cmp	r1, #CCCR_BF_N_RUN_X10
		beq	10f
 
		// 터보모드를 활성화 한다.
		mov	r0, #PXA_COP_CCLKCFG_TURBO
		mcr	p14, 0, r0, c6, c0, 0
10:
		//-------------------------------------------
		// Disable I-Chache ( MMU, cache, buffer 를 사용하지 않음 )
		//-------------------------------------------
 
 
		ldr 	r0, =0x00000078				/* Disable MMU, caches, write buffer */
		mcr 	p15,0,r0,c1,c0,0		
		nop
		nop
		nop
 
		ldr 	r0, =0x00000000
		mcr     p15,0,r0,c8,c7,0   		/* flush TLB's */
		mcr     p15,0,r0,c7,c7,0   		/* flush Caches */
		mcr	p15,0,r0,c7,c10,4		/* Flush Write Buffer */
		nop
		nop
		nop
 
		//-------------------------------------------
		// GPIO Setting ( Uart 를 위한 설정 )
		//-------------------------------------------
 
		// GPIO Alternate function
		ldr	r0, =PXA_REG_GP_BASE
 
		ldr	r1, =GAFR0_L_VALUE
		str	r1, [r0, #PXA_REG_OFFSET_GAFR0_L]
		ldr	r1, =GAFR0_U_VALUE
		str	r1, [r0, #PXA_REG_OFFSET_GAFR0_U]
 
		ldr	r1, =GAFR1_L_VALUE
		str	r1, [r0, #PXA_REG_OFFSET_GAFR1_L]
		ldr	r1, =GAFR1_U_VALUE
		str	r1, [r0, #PXA_REG_OFFSET_GAFR1_U]
 
		ldr	r1, =GAFR2_L_VALUE
		str	r1, [r0, #PXA_REG_OFFSET_GAFR2_L]
		ldr	r1, =GAFR2_U_VALUE
		str	r1, [r0, #PXA_REG_OFFSET_GAFR2_U]
 
		ldr	r1, =GPDR0_VALUE
		str	r1, [r0, #PXA_REG_OFFSET_GPDR0]
		ldr	r1, =GPDR1_VALUE
		str	r1, [r0, #PXA_REG_OFFSET_GPDR1]
		ldr	r1, =GPDR2_VALUE
		str	r1, [r0, #PXA_REG_OFFSET_GPDR2]
 
		// PSSR 설정 - GPIO 입력 활성화
		ldr	r0, =PXA_REG_PSSR
		ldr	r1, =PSSR_VALUE
		str	r1, [r0]
 
		// debug led off
		ldr	r0, =PXA_REG_GP_BASE
		mov	r1, #(_LED_3|_LED_2|_LED_1|_LED_0)
		str	r1, [r0, #PXA_REG_OFFSET_GPSR0]
 
 
		//-------------------------------------------
		// SD Memory Setting
		//-------------------------------------------
 
 
		ldr	r0, =PXA_REG_OSCC
		ldr	r1, =OSCC_VALUE
		str	r1, [r0]
 
		// MSC 0 설정
		ldr	r0, =PXA_REG_MSC0
		ldr	r1, =MSC0_VALUE
		str	r1, [r0]
		ldr	r1, [r0]	// must be read after it is written
 
		// MSC 1 설정
		ldr	r0, =PXA_REG_MSC1
		ldr	r1, =MSC1_VALUE
		str	r1, [r0]
		ldr	r1, [r0]	// must be read after it is written
 
		// MSC 2 설정
		ldr	r0, =PXA_REG_MSC2
		ldr	r1, =MSC2_VALUE
		str	r1, [r0]
		ldr	r1, [r0]	// must be read after it is written
 
		// CKEN 설정
		ldr	r0, =PXA_REG_CKEN
		ldr	r1, =CKEN_VALUE
		str	r1, [r0]
 
	// Syncronous Static Memory  설정 ==========================
 
		ldr	r0, =PXA_REG_SXCNFG
		ldr	r1, =SXCNFG_VALUE
		str	r1, [r0]
 
	// SDRAM Clock 설정 ========================================
 
		ldr	r0, =PXA_REG_MDREFR
		ldr	r1, =MDREFR_VALUE
 
		// diable E1PIN
		bic	r1, r1, #MDREFR_E1PIN
		str	r1, [r0]
 
		// enable E1PIN
		orr	r1, r1, #MDREFR_E1PIN
		str	r1, [r0]
		nop
		nop
 
	// SDRAM Config 설정 =======================================
 
		ldr	r0, =PXA_REG_MDCNFG
		ldr	r1, =MDCNFG_VALUE
 
		// SDRAM Partition 0/1 disable
		bic	r1, r1, #(MDCNFG_DE0 | MDCNFG_DE1)
		str	r1, [r0]
 
		// CBR refresh cycles 8	
		ldr	r3, =SDRAM_BASE_ADDRESS
		.rept	8	
		str	r3, [r3]
		.endr
 
		// SDRAM Partition 0/1 enable
		ldr	r1, [r0]
		orr	r1, r1, #(MDCNFG_DE0|MDCNFG_DE1)
		str	r1, [r0]
 
	// SDRAM Burst length 설정 =================================
 
		ldr	r0, =PXA_REG_MDMRS
		ldr	r1, =MDMRS_VALUE
		str	r1, [r0]
 
 
	//-------------------------------------------
	// Loading Memory
	//-------------------------------------------
 
		ldr	r0,=SDRAM_BASE_ADDRESS
		ldr	r1,=LOAD_ADDRESS
		mov	r2,#0x00000000
 
memory_clean:
	str	r2,[r0],#4
	cmp	r0,r1
	bne	memory_clean
 
 
relocate:
	ldr	r0,=SDRAM_BASE_ADDRESS
	ldr 	r2,=KERNEL_BASE_ADDRESS
 
 
copy_loop:
	ldr	r3,[r2],#4
	str 	r3,[r0],#4
	cmp	r0, r1
	bne	copy_loop
 
jump_kernel:
	ldr	pc,=SDRAM_BASE_ADDRESS
 
 
undefined_instruction:
	ldr	pc,undefined_instruction_addr
swi_handler:
	ldr	pc,swi_handler_addr
abort_prefetch:
	ldr	pc,abort_prefetch_addr
abort_data:
	ldr	pc,abort_data_addr
not_used:
	ldr	pc,not_used_addr
irq_handler:
	ldr	pc,irq_handler_addr
fiq_handler:
	ldr	pc,fiq_handler_addr
 
 
 
.align 4
undefined_instruction_addr:
	.long SDRAM_Remapped_undef
swi_handler_addr:
	.long SDRAM_Remapped_swi
abort_prefetch_addr:
	.long SDRAM_Remapped_prefetch_abort
abort_data_addr:
	.long SDRAM_Remapped_data_abort
not_used_addr:
	.long SDRAM_Remapped_not_used
irq_handler_addr:
	.long SDRAM_Remapped_irq
fiq_handler_addr:
	.long SDRAM_Remapped_fiq

앞에서 언급한 내용을 제외하면, scvos bootloader 와 별반 다르지 않다.
그럼 여기서 cpu.h 를 보기로 하자! h/w 가 바뀌었기 때문에, 각 변수의 주소가 바뀌었다. 이 파일 역시, ezboot 를 부분 참조했다.
pxa255 의 경우, 메모리맵을 보면, 0xA0000000 에서 시작하기 때문에, SDRAM_BASE_ADDRESS 가 바뀐 것을 알 수 있다.
또한 s3c2410 에 해당하는 os timer 라는 것이 있어서 이에 대한 주소값들을 추가해주어야 한다.

...
/* basic */
#define 	SDRAM_BASE_ADDRESS 	0xA0000000
 
 
#define io_p2v(PhAdd)		(PhAdd)
 
#define __REG(x)			(*((volatile Word *) io_p2v (x))) 
#define __REG2(x,y)			(*(volatile Word *)((Word)&__REG(x) + (y)))
 
#define	BOOT_LOADER_SIZE		(1024*20)
#define 	LOAD_ADDRESS			SDRAM_BASE_ADDRESS + BOOT_LOADER_SIZE
#define	KERNEL_BASE_ADDRESS	0x400
 
#define SDRAM_Remapped_undef 	(SDRAM_BASE_ADDRESS + 0x04)
#define SDRAM_Remapped_swi 		(SDRAM_BASE_ADDRESS + 0x08)
#define SDRAM_Remapped_prefetch_abort (SDRAM_BASE_ADDRESS + 0x0c)
#define SDRAM_Remapped_data_abort 	(SDRAM_BASE_ADDRESS + 0x10)
#define SDRAM_Remapped_not_used 	(SDRAM_BASE_ADDRESS + 0x14)
#define SDRAM_Remapped_irq 		(SDRAM_BASE_ADDRESS + 0x18)
#define SDRAM_Remapped_fiq 		(SDRAM_BASE_ADDRESS + 0x1c)
 
// TIMER
#define INT_BASE   		0x40D00000      // Interrupt controller IRQ pending register
#define INT_ICMR       		0x04      		// Interrupt controller mask register
#define CLK_CCCR       		0x00          // Core Clock Configuration Register
 
#define TMR_BASE		0x40A00000   
 
#define CLK_BASE		0x41300000   
#define TMR_OSCR      		0x10          	// OS timer counter register
 
#define OSCR1		__REG(0x40A00010)  // OS Timer Counter Register  
 
#define vh_rSRCPND          (*(volatile unsigned *)0x40d00000) 
 
#define	ICCR			(*(volatile unsigned *)0x40d00014)
#define 	ICLR			(*(volatile unsigned *)0x40d00008)
#define 	ICMR			(*(volatile unsigned *)0x40d00004)
 
#define vh_BIT_TIMER		(0x1<<26)
 
#define OSMR0		(*(volatile unsigned *)0x40A00000)  //  
#define OSMR1		(*(volatile unsigned *)0x40A00004)  //  
#define OSMR2		(*(volatile unsigned *)0x40A00008)  //  
#define OSMR3		(*(volatile unsigned *)0x40A0000C)  //  
#define OSCR			(*(volatile unsigned *)0x40A00010)  // OS Timer Counter Register  
#define OSSR			(*(volatile unsigned *)0x40A00014)  // OS Timer Status Register  
#define OWER		(*(volatile unsigned *)0x40A00018)  // OS Timer Watchdog Enable Register  
#define OIER			(*(volatile unsigned *)0x40A0001C)  // OS Timer Interrupt Enable Register  
 
#define OSSR_M3		(1 << 3)	// Match status channel 3  
#define OSSR_M2		(1 << 2)	// Match status channel 2  
#define OSSR_M1		(1 << 1)	// Match status channel 1  
#define OSSR_M0		(1 << 0)	// Match status channel 0  
 
#define OWER_WME	(1 << 0)	// Watchdog Match Enable  
 
#define OIER_E3		(1 << 3)	// Interrupt enable channel 3  
#define OIER_E2		(1 << 2)	// Interrupt enable channel 2  
#define OIER_E1		(1 << 1)	// Interrupt enable channel 1  
#define OIER_E0		(1 << 0)	// Interrupt enable channel 0
...

메모리 주소가 바뀌었기때문에, 각 모드의 스택 영역도 바뀌어야 한다. 다음은 kernel_start.S 파일을 보자!

	.extern	HaltUndef
	.extern	HaltSwi
	.extern	HaltPabort
	.extern	HaltDabort
	.extern	HaltNouse
	.extern	HaltIrq
	.extern 	HaltFiq
	.extern 	vk_swi_classifier
	.extern 	vh_hwi_classifier
	.extern	my_bt_return_address
 
 
 
	.equ USERMODE, 		0x10
	.equ FIQMODE,    		0x11
	.equ IRQMODE,    		0x12
	.equ SVCMODE,    		0x13
	.equ ABORTMODE,  	0x17
	.equ UNDEFMODE,  	0x1b
	.equ MODEMASK,   	0x1f
	.equ NOINT,      		0xc0  
 
 
	.equ user_stack_size,	0xA0600000   // 수정
	.equ	svc_stack_size,	0xA0800000   // 수정
	.equ undef_stack_size,	0xA1000000   // 수정
	.equ abort_stack_size,	0xA1000000   // 수정
	.equ	irq_stack_size,	0xA0900000   // 수정
	.equ	fiq_stack_size,	0xA1100000   // 수정
 
 
 
	.global kernel_reset
	.global vk_save_swi_mode_stack_ptr
	.global vk_save_irq_mode_stack_ptr	
	.global vk_save_swi_current_tcb_bottom
	.global vk_save_irq_current_tcb_bottom
	.global vh_restore_thread_ctx
	.global scv_swi_handler
	.global scv_irq_handler
	.global vh_save_thread_ctx
 
 
	.text
 
kernel_reset:
	b scv_start
	b HaltUndef
	b scv_swi_handler
	b HaltPabort
	b HaltDabort
	b HaltNouse
	b scv_irq_handler
	b HaltFiq
 
 
scv_start:
 
	/* stack area setting */
 
	/* first change svc mode */
	bic r0,r0,#MODEMASK|NOINT
    	orr r1,r0,#SVCMODE|NOINT
    	msr cpsr_cxsf,r1
 
	/* under mode */
	mrs r0,cpsr
    	bic r0,r0,#MODEMASK|NOINT
    	orr r1,r0,#UNDEFMODE|NOINT
    	msr cpsr_cxsf,r1                
    	ldr sp,=undef_stack_size
 
	/* abort mode */    
    	bic r0,r0,#MODEMASK|NOINT
    	orr r1,r0,#ABORTMODE|NOINT
    	msr cpsr_cxsf,r1               
    	ldr sp,=abort_stack_size
 
	/* irq mode */
    	bic r0,r0,#MODEMASK|NOINT
    	orr r1,r0,#IRQMODE|NOINT
    	msr cpsr_cxsf,r1              
    	ldr sp,=irq_stack_size
 
	/* fiq mode */
    	bic r0,r0,#MODEMASK|NOINT
    	orr r1,r0,#FIQMODE|NOINT
    	msr cpsr_cxsf,r1             
    	ldr sp,=fiq_stack_size
 
	/* svc mode */
    	bic r0,r0,#MODEMASK|NOINT
    	orr r1,r0,#SVCMODE|NOINT
    	msr cpsr_cxsf,r1            
    	ldr sp,=svc_stack_size
 
	/* user mode */
	bic r0,r0,#MODEMASK|NOINT
    	orr r1,r0,#USERMODE|NOINT    
    	msr cpsr_cxsf,r1           
    	ldr sp,=user_stack_size
 
    	b	SCV_Main
 
scv_swi_handler:
	str	sp, vk_save_swi_mode_stack_ptr
	stmfd	sp!, {r0-r14}^
	mrs	r0, spsr_all
	stmfd	sp!, {r0, lr}
	mrs 	r0, cpsr_all
	orr	r0, r0, #0x80
	msr	cpsr_all, r0
	str	sp, vk_save_swi_current_tcb_bottom
	ldr	r0, [sp, #8]
	bl	vk_swi_classifier
 
vh_leaving_swi:
	ldmfd	sp!, {r0, lr}
//	msr	spsr_all, r0
	ldmfd	sp!, {r0-r14}^
	movs	pc, lr
 
scv_irq_handler:
	sub	lr, lr, #4
	str	sp, vk_save_irq_mode_stack_ptr
	stmfd	sp!, {r0-r14}^
	mrs	r0, spsr_all
	stmfd	sp!, {r0, lr}
	str	sp, vk_save_irq_current_tcb_bottom
	bl	vh_hwi_classifier
 
vh_leaving_interrupt:
	ldmfd	sp!, {r0, lr}
	msr	spsr_all, r0
	ldmfd	sp!, {r0-r14}^
	movs	pc, lr
 
vh_restore_thread_ctx:
	mrs	r1, cpsr_all
	bic	r1, r1, #0xfffffff0 
        mov	r2, #0x2
	cmps     r1, r2
	mov	sp, r0
	ldmfd	sp!, {r0, lr}
	msr	spsr_all, r0
	ldmfd	sp!, {r0-r14}^
	ldreq	sp, vk_save_irq_mode_stack_ptr
	ldrne	sp, vk_save_swi_mode_stack_ptr
	movs	pc, lr
 
vh_save_thread_ctx:
	mrs	r1, cpsr_all
	bic	r1, r1, #0xfffffff0 
        mov	r2, #0x2
	cmps     r1, r2
        ldreq	r2, vk_save_irq_current_tcb_bottom
	ldrne	r2, vk_save_swi_current_tcb_bottom
	.rept	17
	ldr	r1, [r2], #4
	str	r1, [r0], #4
	.endr
	mov	pc, lr
 
vk_save_swi_mode_stack_ptr:
				.long 0
vk_save_swi_current_tcb_bottom:
				.long 0
vk_save_irq_mode_stack_ptr:	
				.long 0
vk_save_irq_current_tcb_bottom:
				.long 0

다른 것들은 기존의 것과 동일하다.

타겟보드가 gpio 46, 47 을 사용하기 때문에 이에 대한 설정을 해야 한다.

void SCV_Serial_Init(void)
{	
 
	volatile unsigned int   *ClockEnableRegister = (volatile unsigned *)PXA_REG_CKEN; 
 
	// 포트를 선택한다. 
 
              	*ClockEnableRegister |= CKEN_STUART;
		set_GPIO_mode( GPIO46_STRXD_MD );
		set_GPIO_mode( GPIO47_STTXD_MD );
 
 
	// 모든 인터럽트를 금지 시킨다. 
	UART_IER = 0;
 
	// FIFO 를 정리한다. 
	UART_FCR = 7;					
	UART_FCR = 1;					
 
	// baud, 8BIT 1STOP NO PARITY 로 설정한다.
	UART_LCR = (LCR_WLS1|LCR_WLS0|LCR_DLAB);
 
    	UART_DLL = 8;
    	UART_DLH = 0x00;
 
    	UART_LCR = (LCR_WLS1|LCR_WLS0); 
 
    	// UART를 동작 시킨다. 
    	UART_IER = IER_UUE;
}

다음은 가장 중요한 timer 이다.

내가 가장 혼동했던 부분이 바로 타이머를 초기화 해주는 부분이었다. 타이머 초기화와 인터럽트를 등록시키는 부분이 s3c2410 과는 달랐기 때문이다.
s3c2410 의 경우, PWM TIMER 라고 해서 각각의 TIMER 의 주기를 지정할 수 있고, TIMER 의 특징(auto reload, start/stop) 을 레지스터로 직접 지정하는 방식이었다. 또한 카운터 레지스터에 값을 적으면, 값이 감소하면서 0 이 될 때 인터럽트가 발생하는 방식이었다.
하지만, pxa255 에서는 OS TIMER 라는 이름으로 TIMER 레지스터가 존재했다.

pxa255 에서는 총 4 개의 timer[0-3] 를 제공하는 데, 마지막 timer 3 은 watchdog 으로도 사용이 가능하다. 먼저 OSMR[0-3] 에 타이머 주기 값을 설정하면, OSCR(카운터 레지스터)가 증가하다가 OSMR 값과 같아지면 인터럽트가 발생한다.
코드에서는 timer 0 을 사용한다. 인터럽트 번호가 26 이다.

void Timer_init(void)
{
	int TIMER = 26;        // timer 0 사용
 
	vu_register_dev(0, "Timer", &timer_device_driver_fops, TIMER);
//	Interrupt_unmask(TIMER);
 
	OSCR = 0;   // 카운터 레지스터 초기화
 
	OSMR0= 36864;   // 타이머 주기 설정 (36864 = 10 ms)
 
	OIER = OIER_E0;    // timer 0 인터럽트 활성화
 
	OWER = 0x0;     // watchdog 으로는 사용하지 않음
 
	OSSR = OSSR_M0;     // OS TIMER 카운터가 OSMR[0] 과 match 된다. 
 
//	Interrupt handler
 
	ICCR = 0x0;   // 모든 활성화된 인터럽트는 idle mode 의 프로세서를 깨운다.
 
	ICLR = 0x0;   // TIMER 인터럽트가 발생하면, IRQ 모드로 설정한다.
 
	ICMR = vh_BIT_TIMER;   // TIMER 인터럽트를 CPU 로 전달한다.	
}

다음은 timer 인터럽트가 발생했을 때 수행되는 인터럽트 핸들러에 대한 코드를 보자!

void vh_hwi_classifier(void)
{ 
	unsigned long read = 0;
	unsigned int test = 0;
9
 
	read = rINTOFFSET;   // 0x40d00010 레지스터를 읽어서 read 에 저장, timer 인터럽트라면, 26 번째 bit 가 1 로 설정되어 있다
 
	if(read == vh_BIT_TIMER) test = 26;    // timer 인터럽트라면, test 에 26 저장
 
	vk_dd_table[vk_idt_table[test]].fop_list->vk_interrupt();   // 인터럽트 핸들러 호출
 
}
...
...
int vh_timer_interrupt_handler(void)
{
 
 
	OSSR = 0x01;    // OSMR[0] 과 OS 타이머 카운터가 match 되었음
 
	OSMR0 = OSCR1 + 36864;  // OSMR0 에 현재 타이머 카운터에 36864 를 더함으로서, 지금으로 부터 10 ms 후에 다시 인터럽트가 발생하도록 한다
 
 
	if(vk_sched_lock==0) vk_scheduler();  
 
//	printf("after\n");
 
	return 0;
}

타이머 인터럽트를 검출하는 부분도 약간 다르기 때문에, 기존의 코드를 수정했다.

문제점

이 문제는 이미 scv/os_디버깅 일지 에서 언급했던 내용이었다.
포팅하는 과정에서 이런 문제가 발생했을 때, 어떻게 해결해야 하는지 보여주겠다.
부트로더부분이 바뀌었기 때문에, bootloader 의 크기와 로딩할 주소를 확인해야 한다. cpu.h 파일에서

...
#define SDRAM_BASE_ADDRESS 0xA0000000
#define BOOT_LOADER_SIZE (1024*20)
#define KERNEL_BASE_ADDRESS 0X400
...

위의 항목을 확인한다.

다른 문서에서 예를 들었던 wiki.php?SCV/OS%EB%94%94%EB%B2%84%EA%B9%85%EC%9D%BC%EC%A7%80#s-10 코드]를 가지고 테스트 해본 결과, 다음과 같은 문제가 발생했다.

Command Help11111111111
 
Command Help2222222222

나 나름대로 추측하건데, 컨텍스트 스위칭이 2번(?) 이상 발생하지 않는 것 같다.
하지만, 문제는 아주 엉뚱하게 풀렸다.
컴파일 시에 '-fomit-frame-pointer' 를 제거해주면 된다.
makefile 을 아래와 같이 수정한다.

...
CFLAGS  = -g -O0 -Wall -Wall-Wstrict-prototypes -fPIC -mshort-load-bytes -nostdlib -nostartfiles -mcpu=arm920t -mtune=arm9tdmi -fno-builtin -fomit-frame-pointer -mapcs-32 -nostdinc $(INCLUDE)
...

여기서 '-fomit-frame-pointer' 옵션의 역할에 대해서 알아보자!

fomit-frame-pointer frame pointer가 필요없는 함수들을 컴파일할 때, frame pointer를 생략합니다. 따라서 frame-pointer를 저장하고, 다시 불러오는 부분에 해당하는 기계어를 만들지 않기 때문에 약간의 성능 향상을 기대할 수 있습니다.

해결되어야 할 것들

	++(vk_current_thread->sched_lock_counter);    // data abort
	vk_current_thread->saved_sched_lock = vk_sched_lock;	 // data abort
	vk_sched_lock = 1;

위의 루틴에서 앞에 2 줄 모두 또는 둘 중에 하나를 수행하면, 바로 data abort 가 발생한다. 다행히(?) 두 줄 모두 주석처리하면 정상동작을 하지만..
아무래도 전역변수에 대한 초기화가 문제인 듯 싶다.

  • computer/rtcclab/pxa255_포팅하기.txt
  • Last modified: 4 years ago
  • by likewind