2014-02-22 13:44:55 sj723596076 阅读数 1113

时钟初始化

内核初始化部分( start_kernel 函数)和时钟相关的过程主要有以下几个:

  1. tick_init()
  2. init_timers()
  3. hrtimers_init()
  4. time_init()

 tick_init 函数

函数 tick_init() 很简单,调用 clockevents_register_notifier 函数向 clockevents_chain 通知链注册元素: tick_notifier。这个元素的回调函数指明了当时钟事件设备信息发生变化(例如新加入一个时钟事件设备等等)时,应该执行的操作,该回调函数为 tick_notify 。

/kernel/time/tick-common.c 依赖 CONFIG_GENERIC_CLOCKEVENTS
/**
 * tick_init - initialize the tick control
 *
 * Register the notifier with the clockevents framework
 */
void __init tick_init(void)
{
	clockevents_register_notifier(&tick_notifier);
}

!CONFIG_GENERIC_CLOCKEVENTS 
static inline void tick_init(void) { }
//内核通知链技术
/**
 * clockevents_register_notifier - register a clock events change listener
 */
int clockevents_register_notifier(struct notifier_block *nb)
{
    unsigned long flags;
    int ret;

    raw_spin_lock_irqsave(&clockevents_lock, flags);
    ret = raw_notifier_chain_register(&clockevents_chain, nb);
    raw_spin_unlock_irqrestore(&clockevents_lock, flags);

    return ret;
}


 init_timers 函数

void __init init_timers(void)
{
    int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE, 
                                        (void *)(long)smp_processor_id());
    ……
    register_cpu_notifier(&timers_nb);
    open_softirq(TIMER_SOFTIRQ,run_timer_softirq, NULL);
}

代码解释:

  • 初始化本 CPU 上的软件时钟相关的数据结构,参见3.2节
  • 向 cpu_chain 通知链注册元素 timers_nb ,该元素的回调函数用于初始化指定 CPU 上的软件时钟相关的数据结构
  • 初始化时钟的软中断处理函数

2.3.3 time_init 函数

void __init time_init(void)
{
    ……
    init_tsc_clocksource();
    late_time_init = choose_time_init();
}

函数 init_tsc_clocksource 初始化 tsc 时钟源。choose_time_init 实际是函数 hpet_time_init ,其代码清单2-3

清单2-3 hpet_time_init 函数
void __init hpet_time_init(void)
{
    if (!hpet_enable())
        setup_pit_timer();

    setup_irq(0, &irq0);
}

函数 hpet_enable 检测系统是否可以使用 hpet 时钟,如果可以则初始化 hpet 时钟。否则初始化 pit 时钟。最后设置硬件时钟发生时的处理函数(参见2.4节)。

初始化硬件时钟这个过程主要包括以下两个过程(参见 hpet_enable 的实现):

  1. 初始化时钟源信息( struct clocksource 类型的变量),并将其添加到时钟源链表中,即 clocksource_list 链表(参见图2-1)。
  2. 初始化时钟事件设备信息( struct clock_event_device 类型的变量),并向通知链 clockevents_chain 发布通知:一个时钟事件设备要被添加到系统中。在通知(执行回调函数)结束后,该时钟事件设备被添加到时钟事件设备链表中,即 clockevent_devices 链表(参见图2-1)。有关通知链的内容参见2.2节。

需要注意的是在初始化时钟事件设备时,全局变量 global_clock_event 被赋予了相应的值。该变量保存着系统中当前正在使用的时钟事件设备(保存了系统当前使用的硬件时钟中断发生时,要执行的中断处理函数的指针)。

2013-01-13 23:03:22 wzw88486969 阅读数 546

ARM-Linux时钟初始化

 

ARM-linux时钟初始化是从MACHINE_START中的map_io函数开始的,map_io函数中会调用s3c24xx_init_clocks(12000000);来进行,我们来看一下初始化过程

static struct cpu_table *cpu;

void__init s3c24xx_init_clocks(intxtal)

{

    if (xtal == 0)

       xtal= 12*1000*1000;

 

    if (cpu ==NULL)

       panic("s3c24xx_init_clocks:no cpu setup?\n");

 

    if (cpu->init_clocks ==NULL)

       panic("s3c24xx_init_clocks:cpu has no clock init\n");

    else

       (cpu->init_clocks)(xtal);

}

示例如下:

structcpu_table {

    unsigned long idcode;

    unsigned long idmask;

    void       (*map_io)(void);

    void       (*init_uarts)(structs3c2410_uartcfg *cfg,int no);

    void       (*init_clocks)(intxtal);

    int    (*init)(void);

    const char*name;

};

 

static structcpu_table cpu_ids[] __initdata = {

    //……

    {

       .idcode       = 0x32440000,

       .idmask       = 0xffffffff,

       .map_io       = s3c244x_map_io,

       .init_clocks  = s3c244x_init_clocks,

       .init_uarts   = s3c244x_init_uarts,

       .init      = s3c2440_init,

       .name      = name_s3c2440

    },

    {

       .idcode       = 0x32440001,

       .idmask       = 0xffffffff,

       .map_io       = s3c244x_map_io,

       .init_clocks  = s3c244x_init_clocks,

       .init_uarts   = s3c244x_init_uarts,

       .init      = s3c2440_init,

       .name      = name_s3c2440a

    },

    {

       .idcode       = 0x32440aaa,

       .idmask       = 0xffffffff,

       .map_io       = s3c244x_map_io,

       .init_clocks  = s3c244x_init_clocks,

       .init_uarts   = s3c244x_init_uarts,

       .init      = s3c2442_init,

       .name      = name_s3c2442

    },

    {

       .idcode       = 0x32440aab,

       .idmask       = 0xffffffff,

       .map_io       = s3c244x_map_io,

       .init_clocks  = s3c244x_init_clocks,

       .init_uarts   = s3c244x_init_uarts,

       .init      = s3c2442_init,

       .name      = name_s3c2442b

    },

    //……

};

 

void__init s3c244x_init_clocks(intxtal)

{

    /* initialise the clocks here, to allow other things like the

    * console to use them, and to add new ones after the initialisation

    */

    s3c24xx_register_baseclocks(xtal);

    s3c244x_setup_clocks();

    s3c2410_baseclk_add();

}

s3c24xx_register_baseclocks函数会向系统注册基本时钟,S3C2440A时钟链路:由外晶振OSC(或外部时钟)提供时钟输入,然后分成两路,一路由MPLL锁相环倍频出时钟FCK(核时钟),然后经分频出两路时钟HCLKAHB总线外设时钟)和PCLKAPB总线外设时钟),另一路由UPLL锁相环倍频出时钟UCLK,为USB外设提供时钟,以下基本时钟中,xtal为外部晶振时钟,clk_mpll为经过MPLL锁相环倍频出时钟,clk_upll为由UPLL锁相环倍频出时钟UCLKclk_f为内核时钟,即主频,clk_hHCLKAHB总线外设时钟)clk_pPCLKAPB总线外设时钟)

int__init s3c24xx_register_baseclocks(unsigned longxtal)

{

    printk(KERN_INFO"S3C24XX Clocks,(c) 2004 Simtec Electronics\n");

    clk_xtal.rate= xtal;

 

    /* register our clocks */

 

    if (s3c24xx_register_clock(&clk_xtal) < 0)

       printk(KERN_ERR"failed to register master xtal\n");

 

    if (s3c24xx_register_clock(&clk_mpll) < 0)

       printk(KERN_ERR"failed to register mpll clock\n");

 

    if (s3c24xx_register_clock(&clk_upll) < 0)

       printk(KERN_ERR"failed to register upll clock\n");

 

    if (s3c24xx_register_clock(&clk_f) < 0)

       printk(KERN_ERR"failed to register cpu fclk\n");

 

    if (s3c24xx_register_clock(&clk_h) < 0)

       printk(KERN_ERR"failed to register cpu hclk\n");

 

    if (s3c24xx_register_clock(&clk_p) < 0)

       printk(KERN_ERR"failed to register cpu pclk\n");

 

    return 0;

}

struct clk {

    struct list_head      list;

    struct module        *owner;

    struct clk           *parent;

    const char           *name;

    int          id;

    int          usage;

    unsigned long         rate;

    unsigned long         ctrlbit;

 

    int        (*enable)(struct clk *, int enable);

    int        (*set_rate)(struct clk *c, unsigned long rate);

    unsigned long     (*get_rate)(struct clk *c);

    unsigned long     (*round_rate)(struct clk *c, unsigned long rate);

    int        (*set_parent)(struct clk *c, struct clk *parent);

};

clock.c文件定义一个list_head的链表,s3c24xx_register_clock函数会将clk

构体的变量加入到这个链表中,函数定义如下

static LIST_HEAD(clocks);

ints3c24xx_register_clock(structclk *clk)

{

    if (clk->enable ==NULL)

       clk->enable= clk_null_enable;

 

    /* add to the list of available clocks */

    /* Quick check to see if this clock has already been registered. */

    BUG_ON(clk->list.prev != clk->list.next);

 

    spin_lock(&clocks_lock);

    list_add(&clk->list, &clocks);

    spin_unlock(&clocks_lock);

 

    return 0;

}

各主时钟的定义如下:

struct clk clk_xtal = {

   .name      = "xtal",

   .id    = -1,

   .rate      = 0,

   .parent       = NULL,

   .ctrlbit   = 0,

};

 

struct clk clk_ext = {

   .name      = "ext",

   .id    = -1,

};

 

struct clk clk_epll = {

   .name      = "epll",

   .id    = -1,

};

 

struct clk clk_mpll = {

   .name      = "mpll",

   .id    = -1,

   .set_rate  = clk_default_setrate,

};

 

struct clk clk_upll = {

   .name      = "upll",

   .id    = -1,

   .parent       = NULL,

   .ctrlbit   = 0,

};

 

struct clk clk_f = {

   .name      = "fclk",

   .id    = -1,

   .rate      = 0,

   .parent       = &clk_mpll,

   .ctrlbit   = 0,

   .set_rate  = clk_default_setrate,

};

 

struct clk clk_h = {

   .name      = "hclk",

   .id    = -1,

   .rate      = 0,

   .parent       = NULL,

   .ctrlbit   = 0,

   .set_rate  = clk_default_setrate,

};

 

struct clk clk_p = {

   .name      = "pclk",

   .id    = -1,

   .rate      = 0,

   .parent       = NULL,

   .ctrlbit   = 0,

   .set_rate  = clk_default_setrate,

};

 

struct clk clk_usb_bus = {

   .name      = "usb-bus",

   .id    = -1,

   .rate      = 0,

   .parent       = &clk_upll,

};

 

 

 

struct clk s3c24xx_uclk = {

   .name      = "uclk",

   .id    = -1,

};

 

时钟注册进系统后便可以通过,内核的API来操作时钟了,struct clk *clk_get(struct device *dev, const char *id)函数来获取一个名为Idclk结构体指针,然后可以通过clk_get_rate来获取该时钟的频率,

:printk(KERN_DEBUG ”fclk=%d \n”,clk_get_rate(clk_get(NULL,”fclk”)));

s3c244x_setup_clocks(void)会设置系统的基本时钟

void__init_or_cpufreq s3c244x_setup_clocks(void)

{

    struct clk*xtal_clk;

    unsigned long clkdiv;

    unsigned long camdiv;

    unsigned long xtal;

    unsigned long hclk,fclk, pclk;

    int hdiv= 1;

 

    xtal_clk= clk_get(NULL, "xtal");

    xtal = clk_get_rate(xtal_clk);

    clk_put(xtal_clk);

 

    fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal)* 2;

 

    clkdiv= __raw_readl(S3C2410_CLKDIVN);

    camdiv= __raw_readl(S3C2440_CAMDIVN);

 

    /* work out clock scalings */

 

    switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {

    case S3C2440_CLKDIVN_HDIVN_1:

       hdiv= 1;

       break;

 

    case S3C2440_CLKDIVN_HDIVN_2:

       hdiv= 2;

       break;

 

    case S3C2440_CLKDIVN_HDIVN_4_8:

       hdiv= (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8: 4;

       break;

 

    case S3C2440_CLKDIVN_HDIVN_3_6:

       hdiv= (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6: 3;

       break;

    }

 

    hclk = fclk /hdiv;

    pclk = hclk /((clkdiv & S3C2440_CLKDIVN_PDIVN) ? 2 :1);

 

    /* print brief summary of clocks, etc */

 

    printk("S3C244X:core %ld.%03ld MHz,memory %ld.%03ld MHz,peripheral %ld.%03ld MHz\n",

           print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));

 

    s3c24xx_setup_clocks(fclk,hclk, pclk);

}

 

s3c24xx_setup_clocks(fclk,hclk, pclk);它向链表中的相关变量赋值,定义如下:

void__init_or_cpufreq s3c24xx_setup_clocks(unsigned longfclk,

                    unsigned long hclk,

                    unsigned long pclk)

{

    clk_upll.rate= s3c24xx_get_pll(__raw_readl(S3C2410_UPLLCON),

                  clk_xtal.rate);

 

    clk_mpll.rate= fclk;

    clk_h.rate= hclk;

    clk_p.rate= pclk;

    clk_f.rate= fclk;

}

 

 

    s3c24xx_register_baseclocks(xtal); //完成祖宗级别时钟的注册 
    s3c244x_setup_clocks();//填充祖宗级别时钟结构,方便以后调用
    s3c2410_baseclk_add();//添加一些外设时钟结构到list中,并且关闭它们方便省电

本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2012-03/56418.htm

2011-04-08 10:19:00 iteye_15968 阅读数 41

嵌入式Linux内核时钟初始化问题

首先搞清楚RTCkernel内的作用:

linux系统有两个时钟:一个是由主板电池驱动的“Real Time Clock”也叫做RTC或者叫CMOS时钟,硬件时钟。当操作系统关机的时候,用这个来记录时间,但是对于运行的系统是不用这个时间的。另一个时间是 “System clock”也叫内核时钟或者软件时钟,是由软件根据时间中断来进行计数的,内核时钟在系统关机的情况下是不存在的,所以,当操作系统启动的时候,内核时钟是要读取RTC时间来进行时间同步。并且在系统关机的时候将系统时间写回RTC中进行同步。

如前所述,Linux内核与RTC进行互操作的时机只有两个:
1) 内核在启动时从RTC中读取启动时的时间与日期;
2) 内核在需要时将时间与日期回写到RTC中。

系统启动时,内核通过读取RTC来初始化内核时钟,又叫墙上时间,该时间放在xtime变量中。
The current time of day (the wall time) is defined in kernel/timer.c:
struct timespec xtime;

The timespec data structure is defined in as:

struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};

问题1:系统启动时在哪读取RTC的值并设置内核时钟进行时间同步的呢?
最有可能读取RTC设置内核时钟的位置应该在arch/arm/kernel/time.c里的time_init函数内.

time.c为系统的时钟驱动部分.time_init函数会在系统初始化时,由init/main.c里的start_kernel函数内调用.X86架构就是在这里读RTC值并初始化系统时钟xtime的.

ARM架构的time_init代码如下:

/* arch/arm/kernel/time.c */

void __init time_init(void)
{
if (system_timer->offset == NULL)
system_timer->offset = dummy_gettimeoffset;
system_timer->init();

#ifdef CONFIG_NO_IDLE_HZ
if (system_timer->dyn_tick)
system_timer->dyn_tick->lock = SPIN_LOCK_UNLOCKED;
#endif
}

上面system_timer->init()实际执行的是时钟驱动体系架构相关(具体平台)部分定义的init函数,若是s3c2410平台,则执行的为arch/arm/mach-s3c2410/time.c里定义的s3c2410_timer_init函数.不过s3c2410_timer_init()也没有读RTC的代码.整个时钟驱动初始化的过程大致就执行这些代码.

既然在系统时钟驱动初始化的过程中没有读RTC值并设置内核时钟,那会在哪设置呢?

我搜了一下,发现内核好象只有在arch/cris/kernel/time.c里有RTC相关代码,如下:
/* arch/cris/kernel/time.c */
/* grab the time from the RTC chip */
//读RTC的函数
unsigned long get_cmos_time(void)
{
unsigned int year, mon, day, hour, min, sec;
sec = CMOS_READ(RTC_SECONDS);
min = CMOS_READ(RTC_MINUTES);
hour = CMOS_READ(RTC_HOURS);
day = CMOS_READ(RTC_DAY_OF_MONTH);
mon = CMOS_READ(RTC_MONTH);
…………
return mktime(year, mon, day, hour, min, sec);
}

这个函数会在update_xtime_from_cmos内被调用:
void update_xtime_from_cmos(void)
{
if(have_rtc) {
xtime.tv_sec = get_cmos_time();
xtime.tv_nsec = 0;
}
}

另外还有设置rtc的函数
int set_rtc_mmss(unsigned long nowtime); /* write time into RTC chip */

不过我加了printk测试了一下,好象arch/cris/kernel/time.c这个文件和这两个函数只是适用与X86?
ARM平台启动时并不走这边.因此执行不到这些函数。
那ARM平台启动时,系统是在哪读RTC的值并对内核时钟(WallTime)进行初始化的呢?

已解决:
嵌入式Linux内核(ARM)是在系统启动时执行/etc/init.d/hwclock.sh脚本,这个脚本会调用hwclock小程序读取RTC的值并设置系统时钟。
(换句话说,这要取决于你制作的文件系统里是否有这样的脚本)

/* /etc/init.d/hwclock.sh */

DAEMON1=/sbin/hwclock
start() {
local RET ERROR=

[ ! -f /etc/adjtime ] && echo "0.0 0 0.0" > /etc/adjtime
log_status_msg "Setting the System Clock using the Hardware Clock as reference..." -n

# Copies Hardware Clock time to System Clock using the correct
# timezone for hardware clocks in local time, and sets kernel
# timezone. DO NOT REMOVE.
[ "$HWCLOCKACCESS" != no ] && $DAEMON1 --hctosys $GMT $BADYEAR

#
# Now that /usr/share/zoneinfo should be available,
# announce the local time.
#
log_status_msg "System Clock set. Local time: `date`"
log_status_msg ""
return 0
}

hwclock最先读取的设备文件是 /dev/rtc ,busybox里面的hwclock是这样实现的:
static int xopen_rtc(int flags)
{
int rtc;

if (!rtcname) {
rtc = open("/dev/rtc", flags);
if (rtc >= 0)
return rtc;
rtc = open("/dev/rtc0", flags);
if (rtc >= 0)
return rtc;
rtcname = "/dev/misc/rtc";
}
return xopen(rtcname, flags);
}

2. 内核如何更新RTC时钟?
通过set_rtc函数指针指向的函数,set_rtc在arch/arm/kernel/time.c内
/* arch/arm/kernel/time.c */
/*
* hook for setting the RTC's idea of the current time.
*/
int (*set_rtc)(void);

但是set_rtc函数指针在哪初始化的呢?set_rtc应该是和RTC驱动相关的函数.

搜索kernel源码后发现,好象内核其他地方并没有对其初始化。待解决!

set_rtc在do_set_rtc内调用
static inline void do_set_rtc(void)
{
……
if (set_rtc())
/*
* rtc update failed. Try again in 60s
*/
next_rtc_update = xtime.tv_sec + 60;
else
next_rtc_update = xtime.tv_sec + 660; /* update every ~11 minutes by default*/
}

do_set_rtc在timer_tick里调用
/*
* Kernel system timer support.
*/
void timer_tick(struct pt_regs *regs)
{
profile_tick(CPU_PROFILING, regs);
do_leds();
do_set_rtc();
do_timer(1);
……
}
timer_tick为Kernel提供的体系架构无关的时钟中断处理函数,通常会在体系架构相关的时钟中断处理函数内调用它。如s3c2410是这样的:

在arch/arm/mach-s3c2410/time.c中
* IRQ handler for the timer
*/
static irqreturn_t
s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
write_seqlock(&xtime_lock);
timer_tick(regs);
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
}

2020-02-26 01:59:08 q116975174 阅读数 50

Linux主机初始化

  • 系统下载
  • 网络配置
  • 主机名配置
  • yum源更新
  • 时钟同步
  • 内核参数配置
  • 语言时区
  • 关闭SELINUX, 防火墙
  • SSH参数配置

实验环境

  • Hyper V, VMware, VirtualBox等任意一种虚拟机软件
  • Centos 7, 假设你已经会安装
  • XShell, gitbash, putty等任意一种远程软件

系统下载

https://developer.aliyun.com/mirror/ , 到国内的镜像站下载系统, 速度一般快点
在这里插入图片描述
点击进去后你能找到下载地址
在这里插入图片描述
一般而言, 路径如 https://mirrors.aliyun.com/centos/7.7.1908/isos/x86_64/, 选择最小的版本即可
在这里插入图片描述
至于是不是centos7无所谓, 目前最近已经到8了(建议用新不用旧)

网络配置

默认地刚安装好的Linux是动态获取(dhcp)ip地址的

[root@localhost ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:15:5d:e9:01:6e brd ff:ff:ff:ff:ff:ff
    inet 172.23.39.154/28 brd 172.23.39.159 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::dfd4:bb10:afa6:20ef/64 scope link 
       valid_lft forever preferred_lft forever
       
[root@localhost ~]# ip route
default via 172.23.39.145 dev eth0  proto static  metric 100 
172.23.39.144/28 dev eth0  proto kernel  scope link  src 172.23.39.154  metric 10 

根据上述命令知道系统的ip地址, 子网掩码, 网关信息, 注意你看见的地址等信息应该和我是不一样的

  • ip addr/netmask 172.23.39.154/28 (子网掩码即255.255.255.240)
  • geteway 172.23.39.144/28

先备份网卡配置, 做错了可以重来

注意: 因为Centos版本不同, 你的网卡名字可能和我不一样

cp -a /etc/sysconfig/network-scripts/ifcfg-eth0{,.bak}

配置网络

编辑vi /etc/sysconfig/network-scripts/ifcfg-eth0, 默认地网卡配置是这样的

TYPE="Ethernet"
BOOTPROTO="dhcp"
DEFROUTE="yes"
PEERDNS="yes"
PEERROUTES="yes"
IPV4_FAILURE_FATAL="no"
IPV6INIT="yes"
IPV6_AUTOCONF="yes"
IPV6_DEFROUTE="yes"
IPV6_PEERDNS="yes"
IPV6_PEERROUTES="yes"
IPV6_FAILURE_FATAL="no"
IPV6_ADDR_GEN_MODE="stable-privacy"
NAME="eth0"
UUID="dbd5ee26-4d06-4684-beae-632ecbec8c97"
DEVICE="eth0"
ONBOOT="yes"

设置固定IP是必须的, 保留上述配置不要动(新手不要乱动, 有一定基础, 直接复制下面某云的网卡静态IP配置写法), 作如下修改

# 将DHCP修改为static
BOOTPROTO="static"
# ONBOOT下新增静态网络配置信息
IPADDR=172.23.39.154
NETMASK=255.255.255.240
GATEWAY=172.23.39.145

更新网络服务

[root@localhost ~]# systemctl restart network

# 查看地址是否正确, 路由是否正确, 对比一下
[root@localhost ~]# ip addr
[root@localhost ~]# ip route

# 测试网络连通性
[root@localhost ~]# ping 172.23.39.145

最后, 附上ali云的ECS静态IP配置

DEVICE=eth0
ONBOOT=yes
BOOTPROTO=static
IPADDR=172.18.249.206
NETMASK=255.255.240.0

配置域名解析

如果上一步可以Ping通外网, 这一步可以跳过

[root@localhost ~]# vi /etc/resolv.conf 

# google
#nameserver 8.8.8.8
# ali
#nameserver 100.100.2.138
#nameserver 100.100.2.136
options timeout:2 attempts:3 rotate single-request-reop

主机名配置

hostnamectl set-hostname --pretty centos01 很多云主机设置了这个主机名, 建议这条命令不用打

hostnamectl set-hostname centos-01
hostnamectl set-hostname --pretty centos01
vi /etc/hosts

127.0.0.1   centos01 centos-01 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

必须重新连接(可以不用重启), 此时主机名配置生效

验证

[root@centos-01 ~]# hostnamectl 
   Static hostname: centos-01
   Pretty hostname: centos01
         Icon name: computer-vm
           Chassis: vm
        Machine ID: f11f734cc1fb436281c55b315d831a93
           Boot ID: ee71a19bc67748b793fb5d2948e367d2
    Virtualization: microsoft
  Operating System: CentOS Linux 7 (Core)
       CPE OS Name: cpe:/o:centos:centos:7
            Kernel: Linux 3.10.0-1062.12.1.el7.x86_64
      Architecture: x86-64

yum源更新

官方教程非常详细, 此处不介绍, 云主机一般都有自己的源, 不需要设置, 实验环境需要

时钟同步

云主机一般用不上, 实验环境一般不用, 所以这个跳过吧

安装时钟同步软件

[root@centos-01 ~]# yum install -y ntpdate ntp-doc
timedatectl set-timezone Asia/Shanghai
/usr/sbin/ntpdate 0.cn.pool.ntp.org > /dev/null 2>&1
/usr/sbin/hwclock --systohc
/usr/sbin/hwclock -w

cat > /var/spool/cron/root << EOF
10 0 * * * /usr/sbin/ntpdate 0.cn.pool.ntp.org > /dev/null 2>&1
* * * * */1 /usr/sbin/hwclock -w > /dev/null 2>&1
EOF

chmod 600 /var/spool/cron/root
/usr/bin/systemctl restart crond 

内核参数配置

cp /etc/sysctl.conf /etc/sysctl.conf.bak

cat > /etc/sysctl.conf << EOF
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl =15
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_retries2 = 5
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_max_tw_buckets = 60000
net.ipv4.tcp_max_orphans = 32768
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_wmem = 4096 16384 13107200
net.ipv4.tcp_rmem = 4096 87380 17476000
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.route.gc_timeout = 100
net.core.somaxconn = 32768
net.core.netdev_max_backlog = 32768
net.nf_conntrack_max = 6553500
net.netfilter.nf_conntrack_max = 6553500
net.netfilter.nf_conntrack_tcp_timeout_established = 180
vm.overcommit_memory = 1
vm.swappiness = 1
fs.file-max = 65535
EOF

立即生效

sysctl -p

验证

sysctl -a

延申阅读

Linux实例常用内核网络参数介绍与常见问题处理

ECS做负载均衡需要用户做额外的配置吗?

语言时区

一般而言云主机都不需要设置,变更为英文, 验证ls -al显示的是全英文

echo "LANG=\"en_US.UTF-8\"">/etc/locale.conf
source  /etc/locale.conf

# timedatectl list-timezones
timedatectl set-timezone Asia/Shanghai

验证时区

[root@centos-01 ~]# date -R
Wed, 26 Feb 2020 10:26:55 +0800

[root@centos-01 ~]# timedatectl status
      Local time: Wed 2020-02-26 10:27:39 CST
  Universal time: Wed 2020-02-26 02:27:39 UTC
        RTC time: Wed 2020-02-26 02:27:39
       Time zone: Asia/Shanghai (CST, +0800)
     NTP enabled: yes
NTP synchronized: yes
 RTC in local TZ: no
      DST active: n/

关闭SELINUX, 防火墙

一般而言云主机都是关闭的, 可以跳过, 实验环境是必定关闭的,免去很多干扰

sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
setenforce 0

systemctl stop  firewalld.service
systemctl disable  firewalld.service

SSH参数配置

注意一下参数, 一般而言PermitRootLogin yes就可以用root远程连接了

...
ListenAddress 0.0.0.0
...
PermitRootLogin yes

systemctl restart sshd

2014-02-23 20:46:18 u010873914 阅读数 681

原博:http://www.embeddedlinux.org.cn/html/jishuzixun/201402/21-2755.html?bsh_bid=353686139


内核版本:Linux 2.6.18
平台: FOR ARM
 
搞清RTC在kernel内的作用:
 
linux系统有两个时钟:一个是由主板电池驱动的“Real Time Clock”也叫做RTC或者叫CMOS时钟,
硬件时钟。当操作系统关机的时候,用这个来记录时间,但是对于运行的系统是不用这个时间的。
另一个时间是 “System clock”也叫内核时钟或者软件时钟,是由软件根据时间中断来进行计数的,
内核时钟在系统关机的情况下是不存在的,所以,当操作系统启动的时候,内核时钟是要读取RTC时间
来进行时间同步。并且在系统关机的时候将系统时间写回RTC中进行同步。
 
如前所述,Linux内核与RTC进行互操作的时机只有两个:
1) 内核在启动时从RTC中读取启动时的时间与日期;
2) 内核在需要时将时间与日期回写到RTC中。
 
系统启动时,内核通过读取RTC来初始化内核时钟,又叫墙上时间,该时间放在xtime变量中。
The current time of day (the wall time) is defined in kernel/timer.c:
struct timespec xtime;

The timespec data structure is defined in <linux/time.h> as:
struct timespec {
        time_t tv_sec;               /* seconds */
        long tv_nsec;                /* nanoseconds */
};

问题1:系统启动时在哪读取RTC的值并设置内核时钟进行时间同步的呢?
最有可能读取RTC设置内核时钟的位置应该在arch/arm/kernel/time.c里的time_init函数内.
time.c为系统的时钟驱动部分.time_init函数会在系统初始化时,由init/main.c里的start_kernel函数内调用.X86架构就是在这里读RTC值并初始化系统时钟xtime的.
 
ARM架构的time_init代码如下:
/* arch/arm/kernel/time.c */
void __init time_init(void)
{
 if (system_timer->offset == NULL)
  system_timer->offset = dummy_gettimeoffset;
 system_timer->init();
#ifdef CONFIG_NO_IDLE_HZ
 if (system_timer->dyn_tick)
  system_timer->dyn_tick->lock = SPIN_LOCK_UNLOCKED;
#endif
}
 
上面system_timer->init()实际执行的是时钟驱动体系架构相关(具体平台)部分定义的init函数,若是s3c2410平台,则执行的为arch/arm/mach-s3c2410/time.c里定义的s3c2410_timer_init函数.不过s3c2410_timer_init()也没有读RTC的代码.整个时钟驱动初始化的过程大致就执行这些代码.
既然在系统时钟驱动初始化的过程中没有读RTC值并设置内核时钟,那会在哪设置呢?
 
我搜了一下,发现内核好象只有在arch/cris/kernel/time.c里有RTC相关代码,如下: 
/* arch/cris/kernel/time.c */
/* grab the time from the RTC chip */
//读RTC的函数
unsigned long get_cmos_time(void)
{
unsigned int year, mon, day, hour, min, sec;
sec = CMOS_READ(RTC_SECONDS);
min = CMOS_READ(RTC_MINUTES);
hour = CMOS_READ(RTC_HOURS);
day = CMOS_READ(RTC_DAY_OF_MONTH);
mon = CMOS_READ(RTC_MONTH);
…………
return mktime(year, mon, day, hour, min, sec);
}
 
这个函数会在update_xtime_from_cmos内被调用:
void update_xtime_from_cmos(void)
{
if(have_rtc) {
  xtime.tv_sec = get_cmos_time();
  xtime.tv_nsec = 0;
}
}
 
另外还有设置rtc的函数
int set_rtc_mmss(unsigned long nowtime); /* write time into RTC chip */
 
不过我加了printk测试了一下,好象arch/cris/kernel/time.c这个文件和这两个函数只是适用与X86?
ARM平台启动时并不走这边.因此执行不到这些函数。
那ARM平台启动时,系统是在哪读RTC的值并对内核时钟(WallTime)进行初始化的呢?
 
已解决:
嵌入式Linux内核(ARM)是在系统启动时执行/etc/init.d/hwclock.sh脚本,这个脚本会调用hwclock小程序读取RTC的值并设置系统时钟。
(换句话说,这要取决于你制作的文件系统里是否有这样的脚本)

/* /etc/init.d/hwclock.sh */
DAEMON1=/sbin/hwclock
start() {
    local RET ERROR=
    [ ! -f /etc/adjtime ] &&  echo "0.0 0 0.0" > /etc/adjtime
    log_status_msg "Setting the System Clock using the Hardware Clock as reference..." -n
    # Copies Hardware Clock time to System Clock using the correct
    # timezone for hardware clocks in local time, and sets kernel
    # timezone. DO NOT REMOVE.
    [ "$HWCLOCKACCESS" != no ] && $DAEMON1 --hctosys $GMT $BADYEAR
    #
    # Now that /usr/share/zoneinfo should be available,
    # announce the local time.
    #
    log_status_msg "System Clock set. Local time: `date`"
    log_status_msg ""
    return 0
}

hwclock最先读取的设备文件是 /dev/rtc  ,busybox里面的hwclock是这样实现的:
static int xopen_rtc(int flags)
{
 int rtc;
 if (!rtcname) {
  rtc = open("/dev/rtc", flags);
  if (rtc >= 0)
   return rtc;
  rtc = open("/dev/rtc0", flags);
  if (rtc >= 0)
   return rtc;
  rtcname = "/dev/misc/rtc";
 }
 return xopen(rtcname, flags);
}
 
2. 内核如何更新RTC时钟?
通过set_rtc函数指针指向的函数,set_rtc在arch/arm/kernel/time.c内
/* arch/arm/kernel/time.c */
/*
 * hook for setting the RTC's idea of the current time.
 */
int (*set_rtc)(void);
但是set_rtc函数指针在哪初始化的呢?set_rtc应该是和RTC驱动相关的函数.
搜索kernel源码后发现,好象内核其他地方并没有对其初始化。待解决!

set_rtc在do_set_rtc内调用
static inline void do_set_rtc(void)
{
 ……
 if (set_rtc())
  /*
   * rtc update failed.  Try again in 60s
   */
  next_rtc_update = xtime.tv_sec + 60;
 else
  next_rtc_update = xtime.tv_sec + 660; /* update every ~11 minutes by default*/
}
 
do_set_rtc在timer_tick里调用
/*
 * Kernel system timer support. 
 */
void timer_tick(struct pt_regs *regs)
{
 profile_tick(CPU_PROFILING, regs);
 do_leds();
 do_set_rtc();
 do_timer(1);
 ……
}
timer_tick为Kernel提供的体系架构无关的时钟中断处理函数,通常会在体系架构相关的时钟中断处理函数内调用它。如s3c2410是这样的:
在arch/arm/mach-s3c2410/time.c中
 * IRQ handler for the timer
 */
static irqreturn_t
s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
 write_seqlock(&xtime_lock);
 timer_tick(regs);
 write_sequnlock(&xtime_lock);
 return IRQ_HANDLED;
}

没有更多推荐了,返回首页