内核版本2.4.18
一、linux2.4内核启动流程
arch/arm/boot/compressed/head.s ----->调用arch/arm/boot/compressed/misc.c的decompress_kernel()
函数解压内核。---->arch/arm/kernel/head-armv.s 初始化 --->
init/main.c的asmlinkage void __init start_kernel(void)
二、修改2410linux主频
(1)代码修改
在内核启动之时切换CPU主频arch/arm/boot/compressed/head.S,代码如下(主频设为264M):
ldr r8, =0x4C000000
ldr r9, =0xffffff
str r9, [r8]
ldr r8, =0x4C000014
mov r9, #3
str r9, [r8]
ldr r8, =0x4C000004
ldr r9, =0xa8021
str r9, [r8]
ldr r8, =0x50000028
ldr r9, =0x23
str r9, [r8]
(2)问题及bug。若将2410的主频设为266M等其他,内核启动都会停在:
Uncompressing Linux......................................................................................................................... done, booting the kernel.
网上很多人遇到的情况与此不同,很多都是启动参数配置错误导致或CPU的id与内核不匹配导致。
此因修改了2410的主频原因导致,根本原因不是2410(尾数为20)不能支持这么高的频率
也不是内存clk频率过高而导致的不稳定。而是kernel的start_kernel()函数中对timer的
初始化有bug。
./arch/arm/kernel/time.c:void __init time_init(void)
include/asm-arm/arch-s3c2410/time.h:static inline void setup_timer(void)
在第二个函数中代码修改如下:
-----------------
static inline void setup_timer(void)
{
struct timer_counts *timer_count = count_values;
unsigned long pclk;
gettimeoffset = s3c2410_gettimeoffset;
set_rtc = s3c2410_set_rtc;
xtime.tv_sec = s3c2410_get_rtc_time();
/* set timer interrupt */
/*TCFG0 = (TCFG0_DZONE(0) | TCFG0_PRE1(15) | TCFG0_PRE0(0));*/
TCFG0 = (15<<8)|32;
pclk = s3c2410_get_bus_clk(GET_PCLK)/1000;
/*(TCFG0_DZONE(0) | TCFG0_PRE1(30) | TCFG0_PRE0(((pclk/2000000)-1)));*/
//while (timer_count != 0) { //---------------fix bug------------leaven
while(timer_count->freq != 0){
if (pclk == timer_count->freq) {
printk("DEBUG: timer count %d\n", timer_count->count);
TCNTB4 = timer_count->count;
break;
}
timer_count++;
}
//if (timer_count == 0) { //------------------fix bug---------leaven
if(timer_count->freq==0){
/* Error, assume that PCLK is 50 Mhz */
TCNTB4 = 15626; /* down-counter, maximum value is 65535 (2^16) */
}
TCON = (TCON_4_AUTO | TCON_4_UPDATE | COUNT_4_OFF);
timer_irq.handler = s3c2410_timer_interrupt;
setup_arm_irq(IRQ_TIMER4, &timer_irq);
TCON = (TCON_4_AUTO | COUNT_4_ON);
}
-----------------
从如下代码中可以看到linux2410默认支持的主频是有限的,如要设置自己的频率需要加入新的成员至数组中:
-----------------
/*
* priod = (prescaler value + 1) * (divider value) * buffer count / PCLK = 10 ms
*
* e.g.; PCLK = 50 Mhz
* 10 ms = (15 + 1) * 2 * 15625 / (50000 * 1000)
* 15626 = 10 ms * (50000 * 1000) / 2 / (15 + 1)
*
* Other values
* 5156 = 10 ms * ( 16.5 * 1,000,000) / 2 / (15+1)
* 6250 = 10 ms * ( 20 * 1,000,000) / 2 / (15+1)
* 10312 = 10 ms * ( 33 * 1,000,000) / 2 / (15+1)
* 20625 = 10 ms * ( 66 * 1,000,000) / 2 / (15+1) //for 264M
* 21875 = 10 ms * ( 70 * 1,000,000) / 2 / (15+1)
* 23437 = 10 ms * ( 75 * 1,000,000) / 2 / (15+1)
* 25000 = 10 ms * ( 80 * 1,000,000) / 2 / (15+1)
* 28125 = 10 ms * ( 90 * 1,000,000) / 2 / (15+1)
* 31250 = 10 ms * ( 100 * 1,000,000) / 2 / (15+1)
*/
struct timer_counts count_values[] = {
{ 16500, 5156 },
{ 20000, 6250 },
{ 33000, 10312 },
{ 50000, 15626 },
{ 66000, 20625 },
{ 70000, 21875 },
{ 75000, 23437 },
{ 80000, 25000 },
{ 90000, 28125 },
{ 100000, 31250 },
{ 0, 0 } /* last entry */
};
-----------------
arch/arm/kernel/Makefile中对time.c的编译十分特别,别的都是*.o 而其为time.module