2015년 6월 27일 토요일

[Linux Kernel] 107주차(2015.06.27)

ARM10C : 107 주차
일시 : 2015.06.27 (107 주차 스터디 진행)
모임명 : NAVER개발자커뮤니티지원_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 3명

107 주차 진도

  • start_kernel 1 init/main.c
    • console_init 783 init/main.c
      • tty_ldisc_begin 3493 ~/kernel/iamroot/linux-stable/drivers/tty/tty_io.c
        • tty_register_ldisc 831 (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
          • tty_ldisc_ops 66 int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)

main.c::main.c()

  • called: start_kernel()
asmlinkage void __init start_kernel(void)
{
...
    time_init();
    // timer 를 사용하기 위한 clk source, clk_table 메모리 할당 및 초기화,
    // timer event를 위한 timer irq (MCT) 초기화 수행

    sched_clock_postinit();
    // sched_clock_timer을 초기화 수행

    perf_event_init(); // null function
    profile_init(); // null function
    call_function_init();
    // 각 cpu core에서 사용할 call_single_queue를 맴버값 초기화
    // cfd_data 맴버값을 초기화하고 pcp에서 사용할 메모리 공간 할당
    // cpu_chain에 hotplug_cfd_notifier 를 등록함

    // irqs_disabled(): 1
    WARN(!irqs_disabled(), "Interrupts were enabled early\n");

    // early_boot_irqs_disabled: true
    early_boot_irqs_disabled = false;
    // early_boot_irqs_disabled: false

    local_irq_enable();
    // IRQ를 enable 함

    kmem_cache_init_late(); // null function

    /*
     * HACK ALERT! This is early. We're enabling the console before
     * we've done PCI setups etc, and console_init() must be aware of
     * this. But we do want output early, in case something goes wrong.
     */
    console_init();
  • call: start_kernel()->console_init()

tty_io.c::console_init()

  • called: start_kernel()->console_init()
// ARM10C 20150627
void __init console_init(void)
{
    initcall_t *call;

    /* Setup the default TTY line discipline. */
    tty_ldisc_begin();
  • call: start_kernel()->console_init()->tty_ldisc_begin()
    • tty_ldisc_begin();

tty_ldisc.c::tty_ldisc_begin()

  • called: start_kernel()->console_init()->tty_ldisc_begin()
    • tty_ldisc_begin();
// ARM10C 20150627
void tty_ldisc_begin(void)
{
    /* Setup the default TTY line discipline. */
    // N_TTY 0
    (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);

}
// tty_register_ldisc에서 한일: // tty_ldiscs[0]: &tty_ldisc_N_TTY // (&tty_ldisc_N_TTY)->num: 0 // (&tty_ldisc_N_TTY)->refcount: 0
  • call: start_kernel()->console_init()->tty_ldisc_begin()->tty_register_ldisc()

tty_ldisc.c::tty_register_ldisc()

  • called: start_kernel()->console_init()->tty_ldisc_begin()->tty_register_ldisc()
// ARM10C 20150627
// N_TTY: 0, &tty_ldisc_N_TTY
int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
{
    unsigned long flags;
    int ret = 0;
    // ret: 0

    // disc: 0, N_TTY: 0, NR_LDISCS: 30
    if (disc < N_TTY || disc >= NR_LDISCS)
        return -EINVAL;

    raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);

    // raw_spin_lock_irqsave에서 한일:
    // &tty_ldiscs_lock 을 사용하여 spin lock을 수행하고 cpsr을 flags에 저장함

    // disc: 0, new_ldisc: &tty_ldisc_N_TTY
    tty_ldiscs[disc] = new_ldisc;
    // tty_ldiscs[0]: &tty_ldisc_N_TTY

    // new_ldisc->num: (&tty_ldisc_N_TTY)->num, disc: 0
    new_ldisc->num = disc;
    // new_ldisc->num: (&tty_ldisc_N_TTY)->num: 0

    // new_ldisc->refcount: (&tty_ldisc_N_TTY)->refcount
    new_ldisc->refcount = 0;
    // new_ldisc->refcount: (&tty_ldisc_N_TTY)->refcount: 0

    raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);

    // raw_spin_unlock_irqrestore에서 한일:
    // &tty_ldiscs_lock 을 사용하여 spin unlock을 수행하고 flags에 저장된 cpsr을 복원함

    // ret: 0
    return ret;
    // return 0
}
EXPORT_SYMBOL(tty_register_ldisc);
  • return: start_kernel()->console_init()->tty_ldisc_begin()->tty_register_ldisc()

tty_ldisc.c::tty_ldisc_begin()

  • return: start_kernel()->console_init()->tty_ldisc_begin()->tty_register_ldisc()
// ARM10C 20150627
void tty_ldisc_begin(void)
{
    /* Setup the default TTY line discipline. */
    // N_TTY 0
    (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);

}
  • tty_register_ldisc에서 한일: >tty_ldiscs[0]: &tty_ldisc_N_TTY >(&tty_ldisc_N_TTY)->num: 0 >(&tty_ldisc_N_TTY)->refcount: 0

tty_io.c::console_init()

  • return: start_kernel()->console_init()->tty_ldisc_begin()->tty_register_ldisc()
// ARM10C 20150627
void __init console_init(void)
{
    initcall_t *call;

    /* Setup the default TTY line discipline. */
    tty_ldisc_begin();
  • tty_ldisc_begin에서 한일: > tty_ldiscs[0]: &tty_ldisc_N_TTY > (&tty_ldisc_N_TTY)->num: 0 > (&tty_ldisc_N_TTY)->refcount: 0
// ARM10C 20150627
void __init console_init(void)
{
    initcall_t *call;

    /* Setup the default TTY line discipline. */
    tty_ldisc_begin();

    /*
     * set up the console device so that later boot sequences can
     * inform about problems etc..
     */
    call = __con_initcall_start;
    // call: &__con_initcall_start

    // call: &__con_initcall_start
    while (call < __con_initcall_end) {
        // call:__initcall_s3c24xx_serial_console_init:
        // s3c24xx_serial_console_init
        (*call)();
        call++;
    }
}
  • __con_initcall_start
    • s3c24xx_serial_console_init() 를 호출한다.
      • init.h 에 외부함수로 선언해 놓았다.
    • 이것은 vmlinux.lds.h 에서 섹션이 할당된 부분을 링크해서 사용한다. 
#define CON_INITCALL                            \
        VMLINUX_SYMBOL(__con_initcall_start) = .;       \
        *(.con_initcall.init)                   \
        VMLINUX_SYMBOL(__con_initcall_end) = .;
extern initcall_t __con_initcall_start[], __con_initcall_end[];
  • 따라서 s3c24xx_serial_console_init()을 호출하게 된다.
struct console {
    char    name[16];
    void    (*write)(struct console *, const char *, unsigned);
    int (*read)(struct console *, char *, unsigned);
    struct tty_driver *(*device)(struct console *, int *);
    void    (*unblank)(void);
    int (*setup)(struct console *, char *);
    int (*early_setup)(void);
    short   flags;
    short   index;
    int cflag;
    void    *data;
    struct   console *next;
};
static struct console s3c24xx_serial_console;

static int __init s3c24xx_serial_console_init(void)
{
    register_console(&s3c24xx_serial_console);
    return 0;
}
  • call: start_kernel()->console_init()->s3c24xx_serial_console_init()->register_console()
    • register_console(&s3c24xx_serial_console); ## printk.c::register_console()
  • called: start_kernel()->console_init()->s3c24xx_serial_console_init()->register_console()
    • register_console(&s3c24xx_serial_console);
// ARM10C 20150627
// &s3c24xx_serial_console
void register_console(struct console *newcon)
{
    int i;
    unsigned long flags;
    struct console *bcon = NULL;
    struct console_cmdline *c;

    if (console_drivers)
        for_each_console(bcon)
            if (WARN(bcon == newcon,
                    "console '%s%d' already registered\n",
                    bcon->name, bcon->index))
                return;

  • call: start_kernel()->console_init()->s3c24xx_serial_console_init()->register_console()

    - register_console(&s3c24xx_serial_console);

static struct console s3c24xx_serial_console = {
    .name       = S3C24XX_SERIAL_NAME,
    .device     = uart_console_device,
    .flags      = CON_PRINTBUFFER,
    .index      = -1,
    .write      = s3c24xx_serial_console_write,
    .setup      = s3c24xx_serial_console_setup,
    .data       = &s3c24xx_uart_drv,
};
#endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */
  • call: start_kernel()->console_init()->s3c24xx_serial_console_init()->register_console()
    • register_console(&s3c24xx_serial_console);

samsung.c::s3c24xx_serial_console_setup()

  • called: start_kernel()->console_init()->s3c24xx_serial_console_init()->register_console()
    • register_console(&s3c24xx_serial_console);
static int __init
s3c24xx_serial_console_setup(struct console *co, char *options)
{
    struct uart_port *port;
    int baud = 9600;
    int bits = 8;
    int parity = 'n';
    int flow = 'n';

    dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
        co, co->index, options);

    /* is this a valid port */

    if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
        co->index = 0;

    port = &s3c24xx_serial_ports[co->index].port;

    /* is the port configured? */

    if (port->mapbase == 0x0)
        return -ENODEV;

    cons_uart = port;

    dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index);

    /*
     * Check whether an invalid uart number has been specified, and
     * if so, search for the first available port that does have
     * console support.
     */
    if (options)
        uart_parse_options(options, &baud, &parity, &bits, &flow);
    else
        s3c24xx_serial_get_options(port, &baud, &parity, &bits);

    dbg("s3c24xx_serial_console_setup: baud %d\n", baud);

    return uart_set_options(port, co, baud, parity, bits, flow);
}
  • return: start_kernel()->console_init()->s3c24xx_serial_console_init()->register_console()
    • register_console(&s3c24xx_serial_console);

printk.c::register_console()

  • return: start_kernel()->console_init()->s3c24xx_serial_console_init()->register_console()
    • register_console(&s3c24xx_serial_console);
// ARM10C 20150627
// &s3c24xx_serial_console
void register_console(struct console *newcon)
{
    int i;
    unsigned long flags;
    struct console *bcon = NULL;
    struct console_cmdline *c;

    if (console_drivers)
        for_each_console(bcon)
            if (WARN(bcon == newcon,
                    "console '%s%d' already registered\n",
                    bcon->name, bcon->index))
                return;
    /*
     * before we register a new CON_BOOT console, make sure we don't
     * already have a valid console
     */
    if (console_drivers && newcon->flags & CON_BOOT) {
        /* find the last or real console */
        for_each_console(bcon) {
            if (!(bcon->flags & CON_BOOT)) {
                pr_info("Too late to register bootconsole %s%d\n",
                    newcon->name, newcon->index);
                return;
            }
        }
    }

    if (console_drivers && console_drivers->flags & CON_BOOT)
        bcon = console_drivers;

    if (preferred_console < 0 || bcon || !console_drivers)
        preferred_console = selected_console;

    if (newcon->early_setup)
        newcon->early_setup();

    /*
     *  See if we want to use this console driver. If we
     *  didn't select a console we take the first one
     *  that registers here.
     */
    if (preferred_console < 0) {
        if (newcon->index < 0)
            newcon->index = 0;
        if (newcon->setup == NULL ||
            newcon->setup(newcon, NULL) == 0) {
            newcon->flags |= CON_ENABLED;
            if (newcon->device) {
                newcon->flags |= CON_CONSDEV;
                preferred_console = 0;
            }
        }
    }

    /*
     *  See if this console matches one we selected on
     *  the command line.
     */
    for (i = 0, c = console_cmdline;
         i < MAX_CMDLINECONSOLES && c->name[0];
         i++, c++) {
        if (strcmp(c->name, newcon->name) != 0)
            continue;
        if (newcon->index >= 0 &&
            newcon->index != c->index)
            continue;
        if (newcon->index < 0)
            newcon->index = c->index;

        if (_braille_register_console(newcon, c))
            return;

        if (newcon->setup &&
            newcon->setup(newcon, console_cmdline[i].options) != 0)
            break;
        newcon->flags |= CON_ENABLED;
        newcon->index = c->index;
        if (i == selected_console) {
            newcon->flags |= CON_CONSDEV;
            preferred_console = selected_console;
        }
        break;
    }

log

  • 1st log
4f4095e..99bc637  master     -> origin/master
Merge made by the 'recursive' strategy.
arch/arm/kernel/vmlinux.lds.S    |  3 +++
drivers/clocksource/exynos_mct.c |  9 +++++++++
drivers/tty/n_tty.c              |  1 +
drivers/tty/serial/samsung.c     |  4 +++-
drivers/tty/tty_io.c             | 11 +++++++++++
drivers/tty/tty_ldisc.c          | 32 ++++++++++++++++++++++++++++++++
include/linux/console.h          |  1 +
include/linux/hrtimer.h          |  2 +-
include/linux/init.h             |  3 +++
include/linux/ktime.h            |  6 ++----
include/linux/tty.h              |  2 +-
include/linux/tty_ldisc.h        |  1 +
include/uapi/linux/tty.h         |  4 ++++
init/main.c                      |  1 +
kernel/printk/printk.c           |  2 ++
kernel/time/clockevents.c        | 22 +++++++++++++++++-----
16 files changed, 92 insertions(+), 12 deletions(-)
  • 2nd log
87b829c..b4970f1  master     -> origin/master
Merge made by the 'recursive' strategy.
arch/arm/include/asm/io.h             |   2 ++
drivers/clocksource/exynos_mct.c      | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
drivers/tty/serial/samsung.c          |  25 +++++++++++++++++++++++--
drivers/tty/serial/samsung.h          |   2 ++
drivers/tty/tty_io.c                  |   2 ++
include/linux/console.h               |   6 ++++++
include/linux/serial_core.h           |   3 ++-
include/uapi/asm-generic/errno-base.h |   2 ++
kernel/hrtimer.c                      |  90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
kernel/printk/console_cmdline.h       |   3 ++-
kernel/printk/printk.c                |  27 +++++++++++++++++++++++++++
kernel/time/clockevents.c             |  21 ++++++++++++++++++++-
kernel/time/sched_clock.c             |  19 +++++++++++++++++++
kernel/time/tick-oneshot.c            |  22 ++++++++++++++++++++--
14 files changed, 314 insertions(+), 12 deletions(-)
  • 3th log
c4b416b..9b98f31  master     -> origin/master
Updating c4b416b..9b98f31
Fast-forward
drivers/tty/tty_io.c    |   1 +
init/main.c             |  47 ++++++++++++++
kernel/params.c         | 158 ++++++++++++++++++++++++++++++++++++++++++++++--
kernel/printk/braille.h |   6 +-
kernel/printk/printk.c  |  65 +++++++++++++++++++-
lib/vsprintf.c          |   3 +
6 files changed, 274 insertions(+), 6 deletions(-)

2015년 6월 25일 목요일

CentOS 7.x에서 MariaDB 서버 설치

CentOS 7.x에서 MariaDB 서버 설정

  • CentOS 7.x에서 데이터 베이스(DB)를 설치해 보자.

yum으로 mariadb-server 를 설치한다.

[root@localhost ~]# yum -y install maridb-server
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
...

Complete!

mariaDB 서버 환경을 설정

  • 환경 파일 위치
    /etc/my.cnf
  • 편집기로 화일을 수정하자.
    [root@localhost ~]# vi /etc/my.cnf
[mysqld]
# [mysqld]의 섹션에 문자셋(utf-8) 설정을 추가하자.
character-set-server=utf8

datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
# Settings user and group are ignored when systemd is used.
# If you need to run mysqld under a different user or group,
# customize your systemd unit file for mariadb according to the
# instructions in http://fedoraproject.org/wiki/Systemd

[mysqld_safe]
...

실행 및 서비스 등록

  • 서비스 실행
    [root@localhost ~]# systemctl start mariadb
  • 서비스 등록
    [root@localhost ~]# systemctl enable mariadb

MariaDB 초기 설정

[root@localhost ~]# mysql_secure_installation
/usr/bin/mysql_secure_installation: line 379: find_mysql_client: command not found

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MariaDB to secure it, we'll need the current
password for the root user.  If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none):
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.

# root 패스워드 설정
Set root password? [Y/n] y
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
 ... Success!


By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

# 익명의 사용자 제거
Remove anonymous users? [Y/n] y
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

# 원격지 로그인 금지
Disallow root login remotely? [Y/n] y
 ... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.

# 테스트용 데이터베이스 제거
Remove test database and access to it? [Y/n] y
 - Dropping test database...
  ... Success!
   - Removing privileges on test database...
    ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

# 권한 정보 재설정
Reload privilege tables now? [Y/n] y
 ... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

동작확인

  • 설치한 MariaDB가 정상동작하는 지 확인해 보자.
    [root@localhost ~]# mysql -u root -p
# 앞에서 설정한 root 비밀번호를 입력하자.
Enter password:
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 16
Server version: 5.5.41-MariaDB MariaDB Server

Copyright (c) 2000, 2014, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

# 사용자 데이터 베이스를 확인해 보자.
MariaDB [(none)]> select user,host,password from mysql.user;
+------+-----------+-------------------------------------------+
| user | host      | password                                  |
+------+-----------+-------------------------------------------+
| root | localhost | *xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
| root | 127.0.0.1 | *xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
| root | ::1       | *xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
+------+-----------+-------------------------------------------+
3 rows in set (0.00 sec)

# 데이터베이스 확인 
MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)

MariaDB [(none)]> exit
Bye

2015년 6월 20일 토요일

[Linux Kernel] 106주차(2015.06.20)

ARM10C : 106 주차
일시 : 2015.06.20 (106 주차 스터디 진행)
모임명 : NAVER개발자커뮤니티지원_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 2명

106 주차 진도

  • start_kernel 1 ~/kernel/iamroot/linux-stable/init/main.c
    • sched_clock_postinit 750 ~/kernel/iamroot/linux-stable/init/main.c
      • hrtimer_start 364 ~/kernel/iamroot/linux-stable/kernel/time/sched_clock.c
        • __hrtimer_start_range_ns 1279 ~/kernel/iamroot/linux-stable/kernel/hrtimer.c
          • lock_hrtimer_base 1137 ~/kernel/iamroot/linux-stable/kernel/hrtimer.c
            • hrtimer_enqueue_reprogram 1223 ~/kernel/iamroot/linux-stable/kernel/hrtimer.c
              • hrtimer_reprogram 789 ~/kernel/iamroot/linux-stable/kernel/hrtimer.c
                • tick_program_event 753 ~/kernel/iamroot/linux-stable/kernel/hrtimer.c

main.c::main.c()

  • called: start_kernel()
asmlinkage void __init start_kernel(void)
{
...
    time_init();
    // timer 를 사용하기 위한 clk source, clk_table 메모리 할당 및 초기화,
    // timer event를 위한 timer irq (MCT) 초기화 수행

    sched_clock_postinit();
  • call: start_kernel()->sched_clock_postinit()

sched_clock.c::sched_clockinit()

  • called: start_kernel()->sched_clock_postinit()
// ARM10C 20150530
void __init sched_clock_postinit(void)
{
    /*
     * If no sched_clock function has been provided at that point,
     * make it the final one one.
     */
    // read_sched_clock: jiffy_sched_clock_read
    if (read_sched_clock == jiffy_sched_clock_read)
        // BITS_PER_LONG: 32, HZ: 100
        sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ);

        // sched_clock_register에서 한일:
        // read_sched_clock: jiffy_sched_clock_read
        // sched_clock_mask: 0xFFFFFFFF
        // cd.rate: 100
        // cd.epoch_ns: 0
        // cd.epoch_cyc: 0
        // cd.wrap_kt: 0x42C1D83B9ACA00
        // (&cd)->mult: 0x98968000
        // (&cd)->shift: 8
        // (&cd.seq)->sequence: 2

    update_sched_clock();

    // update_sched_clock에서 한일:
    // cd.epoch_ns: 0
    // cd.epoch_cyc: 0
    // (&cd.seq)->sequence: 4

    /*
     * Start the timer to keep sched_clock() properly updated and
     * sets the initial epoch.
     */
    // CLOCK_MONOTONIC: 1, HRTIMER_MODE_REL: 1
    hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);

    // hrtimer_init에서 한일:
    // sched_clock_timer의 값을 0으로 초기화
    // (&sched_clock_timer)->base: &hrtimer_bases->clock_base[0]
    // RB Tree의 &(&sched_clock_timer)->node 를 초기화

    sched_clock_timer.function = sched_clock_poll;
    // sched_clock_timer.function: sched_clock_poll

    // cd.wrap_kt: 0x42C1D83B9ACA00, HRTIMER_MODE_REL: 1
    hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);

sched_clock.c::sched_clock_register()

  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
// ARM10C 20150530
// &sched_clock_timer, cd.wrap_kt: 0x42C1D83B9ACA00, HRTIMER_MODE_REL: 1
int
hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
{
    // timer: &sched_clock_timer, tim: 0x42C1D83B9ACA00, mode: 1
    return __hrtimer_start_range_ns(timer, tim, 0, mode, 1);
}
EXPORT_SYMBOL_GPL(hrtimer_start);
  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()->__hrtimer_start_range_ns()
    • return __hrtimer_start_range_ns(timer, tim, 0, mode, 1);

hrtimer.c::__hrtimer_start_range_ns()

  • called: start_kernel()->sched_clock_postinit()->hrtimer_start()->__hrtimer_start_range_ns()
// ARM10C 20150530
// timer: &sched_clock_timer, tim: 0x42C1D83B9ACA00, 0, mode: 1, 1
int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
        unsigned long delta_ns, const enum hrtimer_mode mode,
        int wakeup)
{
    struct hrtimer_clock_base *base, *new_base;
    unsigned long flags;
    int ret, leftmost;

    // timer: &sched_clock_timer
    // lock_hrtimer_base(&sched_clock_timer, &flags): &hrtimer_bases->clock_base[0]
    base = lock_hrtimer_base(timer, &flags);
    // base: &hrtimer_bases->clock_base[0]

    // lock_hrtimer_base에서 한일:
    // (&sched_clock_timer)->base: &hrtimer_bases->clock_base[0] 을 리턴
    // flags에 cpsr값을 가져옴

    /* Remove an active timer from the queue: */
    // timer: &sched_clock_timer, base: &hrtimer_bases->clock_base[0]
    // remove_hrtimer(&sched_clock_timer, &hrtimer_bases->clock_base[0]): 0
    ret = remove_hrtimer(timer, base);
    // ret: 0

    /* Switch the timer base, if necessary: */
    // timer: &sched_clock_timer, base: &hrtimer_bases->clock_base[0], mode: 1,
    // HRTIMER_MODE_PINNED: 0x02
    // switch_hrtimer_base(&sched_clock_timer, &hrtimer_bases->clock_base[0], 0):
    // [pcp0] &(&hrtimer_bases)->clock_base[0]
    new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);
    // new_base: [pcp0] &(&hrtimer_bases)->clock_base[0]

    // mode: 1, HRTIMER_MODE_REL: 1
    if (mode & HRTIMER_MODE_REL) {
        // tim.tv64: 0x42C1D83B9ACA00,
        // new_base->get_time: [pcp0] (&(&hrtimer_bases)->clock_base[0])->get_time: &ktime_get,
        // ktime_get(): (ktime_t) { .tv64 = 0}
        // ktime_add_safe(0x42C1D83B9ACA00, (ktime_t) { .tv64 = 0}): (ktime_t) { .tv64 = 0x42C1D83B9ACA00}
        tim = ktime_add_safe(tim, new_base->get_time());
        // tim.tv64: 0x42C1D83B9ACA00

        /*
         * CONFIG_TIME_LOW_RES is a temporary way for architectures
         * to signal that they simply return xtime in
         * do_gettimeoffset(). In this case we want to round up by
         * resolution when starting a relative timer, to avoid short
         * timeouts. This will go away with the GTOD framework.
         */
#ifdef CONFIG_TIME_LOW_RES // CONFIG_TIME_LOW_RES=n
        tim = ktime_add_safe(tim, base->resolution);
#endif
    }

    // timer: &sched_clock_timer, tim: 0x42C1D83B9ACA00, delta_ns: 0
    hrtimer_set_expires_range_ns(timer, tim, delta_ns);

    // hrtimer_set_expires_range_ns에서 한일:
    // timer->_softexpires: (&sched_clock_timer)->_softexpires: 0x42C1D83B9ACA00
    // timer->node.expires: (&sched_clock_timer)->node.expires: 0x42C1D83B9ACA00

    // timer: &sched_clock_timer
    timer_stats_hrtimer_set_start_info(timer); // null function

    // timer: &sched_clock_timer, new_base: [pcp0] &(&hrtimer_bases)->clock_base[0]
    // enqueue_hrtimer(&sched_clock_timer, [pcp0] &(&hrtimer_bases)->clock_base[0]): 1
    leftmost = enqueue_hrtimer(timer, new_base);
    // leftmost: 1

    // enqueue_hrtimer에서 한일:
    // (&(&(&sched_clock_timer)->node)->node)->__rb_parent_color: NULL
    // (&(&(&sched_clock_timer)->node)->node)->rb_left: NULL
    // (&(&(&sched_clock_timer)->node)->node)->rb_right: NULL
    // [pcp0] (&(&(&hrtimer_bases)->clock_base[0])->active)->head.rb_node: &(&(&sched_clock_timer)->node)->node
    //
    // [pcp0] &(&(&(&hrtimer_bases)->clock_base[0])->active)->head 에 RB Tree 형태로
    // &(&(&sched_clock_timer)->node)->node 를 추가함
    //
    // [pcp0] &(&(&(&hrtimer_bases)->clock_base[0])->active)->next: &(&sched_clock_timer)->node
    // [pcp0] (&(&hrtimer_bases)->clock_base[0])->cpu_base->active_bases: 1
    //
    // (&sched_clock_timer)->state: 0x01

    // leftmost: 1, new_base->cpu_base: [pcp0] (&(&hrtimer_bases)->clock_base[0])->cpu_base: [pcp0] &hrtimer_bases,
    // &__get_cpu_var(hrtimer_bases): [pcp0] &hrtimer_bases
    // timer: &sched_clock_timer, new_base: [pcp0] &(&hrtimer_bases)->clock_base[0]
    if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases)
        && hrtimer_enqueue_reprogram(timer, new_base)) {
        if (wakeup) {
            /*
             * We need to drop cpu_base->lock to avoid a
             * lock ordering issue vs. rq->lock.
             */
            raw_spin_unlock(&new_base->cpu_base->lock);
            raise_softirq_irqoff(HRTIMER_SOFTIRQ);
            local_irq_restore(flags);
            return ret;
        } else {
            __raise_softirq_irqoff(HRTIMER_SOFTIRQ);
        }
    }


    unlock_hrtimer_base(timer, &flags);

    // ret: 0
    return ret;
    // return 0
}
  • return: start_kernel()->sched_clock_postinit()
    • hrtimer_start()
    • __hrtimer_start_range_ns()
    • return 0

hrtimer.c::hrtimer_start()

  • return: start_kernel()->sched_clock_postinit()
    • hrtimer_start()
    • __hrtimer_start_range_ns()
    • return 0
// ARM10C 20150530
// &sched_clock_timer, cd.wrap_kt: 0x42C1D83B9ACA00, HRTIMER_MODE_REL: 1
int
hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
{
    // timer: &sched_clock_timer, tim: 0x42C1D83B9ACA00, mode: 1
    return __hrtimer_start_range_ns(timer, tim, 0, mode, 1);
}
EXPORT_SYMBOL_GPL(hrtimer_start);

sched_clock.c::sched_clock_postinit()

// ARM10C 20150530
void __init sched_clock_postinit(void)
{
    /*
     * If no sched_clock function has been provided at that point,
     * make it the final one one.
     */
    // read_sched_clock: jiffy_sched_clock_read
    if (read_sched_clock == jiffy_sched_clock_read)
        // BITS_PER_LONG: 32, HZ: 100
        sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ);

        // sched_clock_register에서 한일:
        // read_sched_clock: jiffy_sched_clock_read
        // sched_clock_mask: 0xFFFFFFFF
        // cd.rate: 100
        // cd.epoch_ns: 0
        // cd.epoch_cyc: 0
        // cd.wrap_kt: 0x42C1D83B9ACA00
        // (&cd)->mult: 0x98968000
        // (&cd)->shift: 8
        // (&cd.seq)->sequence: 2

    update_sched_clock();

    // update_sched_clock에서 한일:
    // cd.epoch_ns: 0
    // cd.epoch_cyc: 0
    // (&cd.seq)->sequence: 4

    /*
     * Start the timer to keep sched_clock() properly updated and
     * sets the initial epoch.
     */
    // CLOCK_MONOTONIC: 1, HRTIMER_MODE_REL: 1
    hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);

    // hrtimer_init에서 한일:
    // sched_clock_timer의 값을 0으로 초기화
    // (&sched_clock_timer)->base: &hrtimer_bases->clock_base[0]
    // RB Tree의 &(&sched_clock_timer)->node 를 초기화

    sched_clock_timer.function = sched_clock_poll;
    // sched_clock_timer.function: sched_clock_poll

    // cd.wrap_kt: 0x42C1D83B9ACA00, HRTIMER_MODE_REL: 1
    hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
}
  • sched_clock_postinit(); 에서 한일
    • sched_clock_timer을 초기화 수행

main.c::main.c()

  • return: start_kernel()->sched_clock_postinit()
asmlinkage void __init start_kernel(void)
{
...
    time_init();
    // timer 를 사용하기 위한 clk source, clk_table 메모리 할당 및 초기화,
    // timer event를 위한 timer irq (MCT) 초기화 수행

    sched_clock_postinit();
    // sched_clock_timer을 초기화 수행    

    perf_event_init();
    // null function.
    profile_init();
    // null function.

    call_function_init();
  • call: start_kernel()->call_function_init()

smp.c::call_function_init()

  • called: start_kernel()->call_function_init()
void __init call_function_init(void)
{
    void *cpu = (void *)(long)smp_processor_id();
    // cpu: NULL

    int i;

    for_each_possible_cpu(i) {
        struct call_single_queue *q = &per_cpu(call_single_queue, i);

        raw_spin_lock_init(&q->lock);
        INIT_LIST_HEAD(&q->list);
    }

    // &hotplug_cfd_notifier, CPU_UP_PREPARE: 0x0003, cpu
    hotplug_cfd(&hotplug_cfd_notifier, CPU_UP_PREPARE, cpu);
  • call: start_kernel()->call_function_init()->hotplug_cfd()

smp.c::hotplug_cfd()

  • called: start_kernel()->call_function_init()->hotplug_cfd()
  • ipi: interl processor interupt
  • csd call single data
static int
hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)
{
    long cpu = (long)hcpu;
    struct call_function_data *cfd = &per_cpu(cfd_data, cpu);

    switch (action) {
    case CPU_UP_PREPARE:
    case CPU_UP_PREPARE_FROZEN:
        if (!zalloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL,
                cpu_to_node(cpu)))
            return notifier_from_errno(-ENOMEM);
        if (!zalloc_cpumask_var_node(&cfd->cpumask_ipi, GFP_KERNEL,
                cpu_to_node(cpu))) {
            free_cpumask_var(cfd->cpumask);
            return notifier_from_errno(-ENOMEM);
        }

        cfd->csd = alloc_percpu(struct call_single_data);
        if (!cfd->csd) {
            free_cpumask_var(cfd->cpumask_ipi);
            free_cpumask_var(cfd->cpumask);
            return notifier_from_errno(-ENOMEM);
        }
        break;

#ifdef CONFIG_HOTPLUG_CPU
    case CPU_UP_CANCELED:
    case CPU_UP_CANCELED_FROZEN:

    case CPU_DEAD:
    case CPU_DEAD_FROZEN:
        free_cpumask_var(cfd->cpumask);
        free_cpumask_var(cfd->cpumask_ipi);
        free_percpu(cfd->csd);
        break;
#endif
    };

    return NOTIFY_OK;
}
  • return: start_kernel()->call_function_init()->hotplug_cfd()

smp.c::call_function_init()

  • return: start_kernel()->call_function_init()->hotplug_cfd()
void __init call_function_init(void)
{
    void *cpu = (void *)(long)smp_processor_id();
    // cpu: NULL

    int i;

    for_each_possible_cpu(i) {
        struct call_single_queue *q = &per_cpu(call_single_queue, i);

        raw_spin_lock_init(&q->lock);
        INIT_LIST_HEAD(&q->list);
    }

    // &hotplug_cfd_notifier, CPU_UP_PREPARE: 0x0003, cpu
    hotplug_cfd(&hotplug_cfd_notifier, CPU_UP_PREPARE, cpu);
    register_cpu_notifier(&hotplug_cfd_notifier);
  • return: start_kernel()->call_function_init()

main.c::main.c()

  • called: start_kernel()->call_function_init()
asmlinkage void __init start_kernel(void)
{
...
    time_init();
    // timer 를 사용하기 위한 clk source, clk_table 메모리 할당 및 초기화,
    // timer event를 위한 timer irq (MCT) 초기화 수행

    sched_clock_postinit();
sched_clock_postinit();
// sched_clock_timer을 초기화 수행

perf_event_init();
profile_init();
call_function_init();

// irqs_disabled()
WARN(!irqs_disabled(), "Interrupts were enabled early\n");
early_boot_irqs_disabled = false;

local_irq_enable();

* call: start_kernel()->local_irq_enable()

## irqflags.h::local_irq_enable()
* called: start_kernel()->local_irq_enable()

```irqflags.h
#define local_irq_enable() \
    do { trace_hardirqs_on(); raw_local_irq_enable(); } while (0)
# define trace_hardirqs_on()        do { } while (0)    // ARM10C this
#define raw_local_irq_enable()      arch_local_irq_enable()
  • call: start_kernel()->local_irq_enable()->arch_local_irq_enable()

irqflags.h::arch_local_irq_enable()

  • call: start_kernel()->local_irq_enable()->arch_local_irq_enable()
static inline void arch_local_irq_enable(void)
{
    asm volatile(
        "   cpsie i         @ arch_local_irq_enable"
        :
        :
        : "memory", "cc");
}
  • return: start_kernel()->local_irq_enable()->arch_local_irq_enable()

main.c::main.c()

  • called: start_kernel()->call_function_init()
asmlinkage void __init start_kernel(void)
{
...
    time_init();
    // timer 를 사용하기 위한 clk source, clk_table 메모리 할당 및 초기화,
    // timer event를 위한 timer irq (MCT) 초기화 수행

    sched_clock_postinit();
    // sched_clock_timer을 초기화 수행

    perf_event_init();
    // null funciton
    profile_init();
    // null funciton
    call_function_init();

        irqs_disabled()
    WARN(!irqs_disabled(), "Interrupts were enabled early\n");
    early_boot_irqs_disabled = false;

    local_irq_enable();

    kmem_cache_init_late();
    // null funciton

log

  • 1st log
1829c7c..d1c31fb  master     -> origin/master
Merge made by the 'recursive' strategy.
include/linux/clockchips.h       |   4 ++
include/linux/err.h              |   1 +
include/linux/hrtimer.h          |  10 ++++
include/linux/ktime.h            |   6 ++
include/linux/percpu.h           |   1 +
include/linux/spinlock.h         |   1 +
include/linux/time.h             |   1 +
include/uapi/asm-generic/errno.h |   2 +
init/main.c                      |   2 +
kernel/hrtimer.c                 | 123 +++++++++++++++++++++++++++------------
kernel/sched/core.c              |  17 +++++-
kernel/sched/rt.c                |   3 +-
kernel/time/clockevents.c        |  15 +++++
kernel/time/sched_clock.c        |  19 +++++-
kernel/time/tick-internal.h      |   2 +
kernel/time/tick-oneshot.c       |   7 +++
kernel/time/timekeeping.c        |   1 +
17 files changed, 173 insertions(+), 42 deletions(-)
  • 2nd log
d1c31fb..4f4095e  master     -> origin/master
Merge made by the 'recursive' strategy.
arch/arm/include/asm/irqflags.h       |   1 +
arch/arm/include/asm/spinlock_types.h |   3 +
include/asm-generic/topology.h        |   1 +
include/linux/bitmap.h                |   4 ++
include/linux/cpu.h                   |  22 ++++++++
include/linux/cpumask.h               |  21 +++++++
include/linux/gfp.h                   |   1 +
include/linux/irqflags.h              |   3 +
include/linux/list.h                  |   2 +
include/linux/notifier.h              |   2 +
include/linux/percpu-defs.h           |  12 ++++
include/linux/percpu.h                |   3 +
include/linux/perf_event.h            |   3 +-
include/linux/profile.h               |   3 +-
include/linux/smp.h                   |   8 ++-
include/linux/spinlock.h              |   5 +-
include/linux/spinlock_types.h        |   3 +
init/main.c                           |  23 ++++++--
kernel/cpu.c                          |  13 +++++
kernel/locking/spinlock_debug.c       |  23 ++++++--
kernel/notifier.c                     |  11 ++++
kernel/smp.c                          | 102 +++++++++++++++++++++++++++++++---
mm/percpu.c                           |   2 +
mm/slub.c                             |   1 +
24 files changed, 251 insertions(+), 21 deletions(-)