2015년 7월 18일 토요일

[Linux Kernel] 110주차(2015.07.18) console_init()

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

110 주차 진도

  • start_kernel 321 kernel/params.c
    • console_init 833 init/main.c
    • con_init 3512 drivers/tty/tty_io.c

main.c::main.c()

  • called: start_kernel()
asmlinkage void __init start_kernel(void)
{
...
    // 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();

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();

    // tty_ldisc_begin에서 한일:
    // tty_ldiscs[0]: &tty_ldisc_N_TTY
    // (&tty_ldisc_N_TTY)->num: 0
    // (&tty_ldisc_N_TTY)->refcount: 0

    /*
     * 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_con_init: con_init
        // call: __initcall_s3c24xx_serial_console_init:
        // s3c24xx_serial_console_init
        (*call)();
        call++;
    }
  • call: start_kernel()->console_init()->con_init()
    • call: con_init()
    • next call: s3c24xx_serial_console_init()

console.h::struct consw

// ARM10C 20150718
struct consw {
    struct module *owner;
    const char *(*con_startup)(void);
    void    (*con_init)(struct vc_data *, int);
    void    (*con_deinit)(struct vc_data *);
    void    (*con_clear)(struct vc_data *, int, int, int, int);
    void    (*con_putc)(struct vc_data *, int, int, int);
    void    (*con_putcs)(struct vc_data *, const unsigned short *, int, int, int);
    void    (*con_cursor)(struct vc_data *, int);
    int (*con_scroll)(struct vc_data *, int, int, int, int);
    void    (*con_bmove)(struct vc_data *, int, int, int, int, int, int);
    int (*con_switch)(struct vc_data *);
    int (*con_blank)(struct vc_data *, int, int);
    int (*con_font_set)(struct vc_data *, struct console_font *, unsigned);
    int (*con_font_get)(struct vc_data *, struct console_font *);
    int (*con_font_default)(struct vc_data *, struct console_font *, char *);
    int (*con_font_copy)(struct vc_data *, int);
    int     (*con_resize)(struct vc_data *, unsigned int, unsigned int,
                   unsigned int);
    int (*con_set_palette)(struct vc_data *, unsigned char *);
    int (*con_scrolldelta)(struct vc_data *, int);
    int (*con_set_origin)(struct vc_data *);
    void    (*con_save_screen)(struct vc_data *);
    u8  (*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8, u8);
    void    (*con_invert_region)(struct vc_data *, u16 *, int);
    u16    *(*con_screen_pos)(struct vc_data *, int);
    unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, int *);
    /*
     * Prepare the console for the debugger.  This includes, but is not
     * limited to, unblanking the console, loading an appropriate
     * palette, and allowing debugger generated output.
     */
    int (*con_debug_enter)(struct vc_data *);
    /*
     * Restore the console to its pre-debug state as closely as possible.
     */
    int (*con_debug_leave)(struct vc_data *);
};

vt.c::con_init()

  • called: start_kernel()->console_init()->con_init()
    • colsole_lock()
    • dummycon_startup()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
      • get_nohz_timer_target()
      • per_cpu()
      • internal_add_timer()
        • __internal_add_timer()
          • list_add_tail()
      • tbase_get_deferrable()
      • time_before()
    • INIT_WORK()
  • INIT_WORK에서 한일: // (&vc_cons[0].SAK_work)->data: { 0xFFFFFFE0 } // (&(&vc_cons[0].SAK_work)->entry)->next: &(&vc_cons[0].SAK_work)->entry // (&(&vc_cons[0].SAK_work)->entry)->prev: &(&vc_cons[0].SAK_work)->entry // (&vc_cons[0].SAK_work)->func: vc_SAK
// ARM10C 20150704
static int __init con_init(void)
{
    const char *display_desc = NULL;
    // display_desc: NULL

    struct vc_data *vc;
    unsigned int currcons = 0, i;
    // currcons: 0

    console_lock();

    // console_lock에서 한일:
    // (&console_sem)->count: 0
    // console_locked: 1
    // console_may_schedule: 1

    // conswitchp: &dummy_con
    if (conswitchp)
        // conswitchp->con_startup: (&dummy_con)->con_startup: dummycon_startup
        // dummycon_startup(): &"dummy device"
        display_desc = conswitchp->con_startup();
        // display_desc: &"dummy device"

    // display_desc: &"dummy device"
    if (!display_desc) {
        fg_console = 0;
        console_unlock();
        return 0;
    }

    // MAX_NR_CON_DRIVER: 16
    for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
        // i: 0
        struct con_driver *con_driver = &registered_con_driver[i];
        // con_driver: &registered_con_driver[0]

        // con_driver->con: (&registered_con_driver[0])->con: NULL
        if (con_driver->con == NULL) {
            // con_driver->con: (&registered_con_driver[0])->con, conswitchp: &dummy_con
            con_driver->con = conswitchp;
            // con_driver->con: (&registered_con_driver[0])->con: &dummy_con

            // con_driver->desc: (&registered_con_driver[0])->desc, display_desc: &"dummy device"
            con_driver->desc = display_desc;
            // con_driver->desc: (&registered_con_driver[0])->desc: &"dummy device"

            // con_driver->flag: (&registered_con_driver[0])->flag, CON_DRIVER_FLAG_INIT: 2
            con_driver->flag = CON_DRIVER_FLAG_INIT;
            // con_driver->flag: (&registered_con_driver[0])->flag: 2

            // con_driver->first: (&registered_con_driver[0])->first
            con_driver->first = 0;
            // con_driver->first: (&registered_con_driver[0])->first: 0

            // con_driver->last: (&registered_con_driver[0])->last, MAX_NR_CONSOLES: 63
            con_driver->last = MAX_NR_CONSOLES - 1;
            // con_driver->last: (&registered_con_driver[0])->last: 62

            break;
            // break 수행
        }
    }

    // MAX_NR_CONSOLES: 63
    for (i = 0; i < MAX_NR_CONSOLES; i++)
        // i: 0, conswitchp: &dummy_con
        con_driver_map[i] = conswitchp;
        // con_driver_map[0]: &dummy_con

        // i: 1...62 loop 수행

    // blankinterval: 600
    if (blankinterval) {
        // blank_normal_wait: 1
        blank_state = blank_normal_wait;
        // blank_state: 1

        // jiffies은 interrupt enable이 되었기 때문에
        // 실시간으로 변하는 값이므로 현재 시간값을 알수 없음
        // jiffiex: xx_64 로 주석을 작성하도록 함
        // jiffies: xx_64, blankinterval: 600, HZ: 100
        // mod_timera(&console_timer, xx_64 + 60000): 0
        mod_timer(&console_timer, jiffies + (blankinterval * HZ));

        // mod_timer에서 한일:
        // (&console_timer)->expires: xx_64 + 60000
        //
        // NOTE:
        // idx의 값을 가정하고 분석, xx_64은 0이라 보고
        // idx값이 90000의 값을 가진것으로 분석 진행
        // 계산값 xx_64 + 90000 0 보다 크다고 가정하고 분석 진행
        // FIXME:
        // TVR_SIZE: 256 값이 왜 256 인지??
        //
        // &(&boot_tvec_bases)->tv3.vec[3]에 &(&console_timer)->entry을 tail에 연결
        // (&boot_tvec_bases)->active_timers: 1
    }

    // MIN_NR_CONSOLES: 1
    for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
        // currcons: 0, sizeof(struct vc_data): 653 bytes, GFP_NOWAIT: 0
        // kzalloc(653, GFP_NOWAIT: 0): kmem_cache#25-oX
        vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
        // vc_cons[0].d: kmem_cache#25-oX, vc: kmem_cache#25-oX

        // currcons: 0,
        INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);

        // &vc->port: &(kmem_cache#25-oX)->port
        tty_port_init(&vc->port);

tty_port.c::tty_port_init()

  • called: start_kernel()->console_init()->con_init()
    • colsole_lock()
    • dummycon_startup()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
      • get_nohz_timer_target()
      • per_cpu()
      • internal_add_timer()
        • __internal_add_timer()
          • list_add_tail()
      • tbase_get_deferrable()
      • time_before()
    • INIT_WORK()
    • tty_port_init()
// ARM10C 20150718
// &vc->port: &(kmem_cache#25-oX)->port
void tty_port_init(struct tty_port *port)
{
    // port: &(kmem_cache#25-oX)->port, sizeof(struct tty_port): 313 bytes
    memset(port, 0, sizeof(*port));
  • memset에서 한일: // &(kmem_cache#25-oX)->port의 맴버 값을 전부 0으로 초기화함

tty_port.c::tty_port_init()

  • called: start_kernel()->console_init()->con_init()
    • colsole_lock()
    • dummycon_startup()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
      • get_nohz_timer_target()
      • per_cpu()
      • internal_add_timer()
        • __internal_add_timer()
          • list_add_tail()
      • tbase_get_deferrable()
      • time_before()
    • INIT_WORK()
    • tty_port_init()
    • memset()
    • tty_buffer_init()
// ARM10C 20150718
// &vc->port: &(kmem_cache#25-oX)->port
void tty_port_init(struct tty_port *port)
{
    // port: &(kmem_cache#25-oX)->port, sizeof(struct tty_port): 313 bytes
    memset(port, 0, sizeof(*port));

    // port: &(kmem_cache#25-oX)->port
    tty_buffer_init(port);

tty_buffer.c::tty_buffer_init()

  • called: start_kernel()->console_init()->con_init()
    • colsole_lock()
    • dummycon_startup()
    • mod_timer()
    • INIT_WORK()
    • tty_port_init()
    • memset()
    • tty_buffer_init()
// ARM10C 20150718
// port: &(kmem_cache#25-oX)->port
void tty_buffer_init(struct tty_port *port)
{
    // &port->buf: &(&(kmem_cache#25-oX)->port)->buf
    struct tty_bufhead *buf = &port->buf;
    // buf: &(&(kmem_cache#25-oX)->port)->buf

    // &buf->lock: &(&(&(kmem_cache#25-oX)->port)->buf)->lock
    mutex_init(&buf->lock);

mutex-debug.h

  • called: start_kernel()->console_init()->con_init()
    • colsole_lock()
    • dummycon_startup()
    • mod_timer()
    • INIT_WORK()
    • tty_port_init()
    • memset()
    • tty_buffer_init()
// ARM10C 20150718
// &port->buf_mutex: &(&(kmem_cache#25-oX)->port)->buf_mutex
#define mutex_init(mutex)                       \
do {                                    \
    static struct lock_class_key __key;             \
                                    \
    __mutex_init((mutex), #mutex, &__key);              \
} while (0)

extern void mutex_destroy(struct mutex *lock);

mutex.c::__mutex_init()

  • called: start_kernel()->console_init()->con_init()
    • colsole_lock()
    • dummycon_startup()
    • mod_timer()
    • INIT_WORK()
    • tty_port_init()
    • memset()
    • tty_buffer_init()
    • mutex_init()
      • __mutex_init()
// ARM10C 20150718
// &port->buf_mutex: &(&(kmem_cache#25-oX)->port)->buf_mutex, "&port->buf_mutex", &__key
void
__mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
{
    // &lock->count: &(&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->count
    atomic_set(&lock->count, 1);

    // atomic_set에서 한일:
    // (&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->count: 1

    // &lock->wait_lock: &(&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->wait_lock
    spin_lock_init(&lock->wait_lock);

    // spin_lock_init에서 한일:
    // (&(&(&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->wait_lock)->rlock)->raw_lock: { { 0 } }
    // (&(&(&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->wait_lock)->rlock)->magic: 0xdead4ead
    // (&(&(&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->wait_lock)->rlock)->owner: 0xffffffff
    // (&(&(&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->wait_lock)->rlock)->owner_cpu: 0xffffffff

    // &lock->wait_list: &(&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->wait_list
    INIT_LIST_HEAD(&lock->wait_list);

    // INIT_LIST_HEAD에서 한일:
    // (&(&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->wait_list)->next: &(&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->wait_list
    // (&(&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->wait_list)->prev: &(&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->wait_list

    // lock: &(&(&(kmem_cache#25-oX)->port)->buf)->lock
    mutex_clear_owner(lock);

    // mutex_clear_owner에서 한일:
    // (&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->onwer: NULL

#ifdef CONFIG_MUTEX_SPIN_ON_OWNER // CONFIG_MUTEX_SPIN_ON_OWNER=n
    lock->spin_mlock = NULL;
#endif

    // lock: &(&(&(kmem_cache#25-oX)->port)->buf)->lock, name: "&buf->lock", key: &__key
    debug_mutex_init(lock, name, key);

    // debug_mutex_init에서 한일:
    // (&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->magic: &(&(&(kmem_cache#25-oX)->port)->buf)->lock
}
  • atomic_set()
// &lock->count: &(&(&(&(kmem_cache#25-oX)->port)->buf)->lock)->count
atomic_set(&lock->count, 1);
  • call: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()

tty_buffer.c::tty_buffer_init()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
void tty_buffer_init(struct tty_port *port)
{
    struct tty_bufhead *buf = &port->buf;

    mutex_init(&buf->lock);
  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()

mutex-debug.h::mutex_init()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()
#define mutex_init(mutex)                       \
do {                                    \
    static struct lock_class_key __key;             \
                                    \
    __mutex_init((mutex), #mutex, &__key);              \
} while (0)
  • return: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()

tty_buffer.c::tty_buffer_init()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()
void tty_buffer_init(struct tty_port *port)
{
    struct tty_bufhead *buf = &port->buf;

    mutex_init(&buf->lock);
    tty_buffer_reset(&buf->sentinel, 0);
  • call: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()
      • tty_buffer_reset()

tty_buffer.c::tty_buffer_reset()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()
      • tty_buffer_reset()
static void tty_buffer_reset(struct tty_buffer *p, size_t size)
{
    p->used = 0;
    p->size = size;
    p->next = NULL;
    p->commit = 0;
    p->read = 0;
}
  • return: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()
      • tty_buffer_reset()

tty_buffer.c::tty_buffer_init()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()
void tty_buffer_init(struct tty_port *port)
{
    struct tty_bufhead *buf = &port->buf;

    mutex_init(&buf->lock);
    tty_buffer_reset(&buf->sentinel, 0);
    buf->head = &buf->sentinel;
    buf->tail = &buf->sentinel;
    init_llist_head(&buf->free);
    atomic_set(&buf->memory_used, 0);
    atomic_set(&buf->priority, 0);
    INIT_WORK(&buf->work, flush_to_ldisc);
}
  • call: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()
      • tty_buffer_reset()
      • init_llist_head()
      • atomic_set()
      • atomic_set()
      • INIT_WORK()

tty_buffer_init()에서 한 일

...

tty_port.c::tty_port_init()

  • call: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()
      • tty_buffer_reset()
      • init_llist_head()
      • atomic_set()
      • atomic_set()
      • INIT_WORK()
void tty_port_init(struct tty_port *port)
{
    memset(port, 0, sizeof(*port));
    tty_buffer_init(port);
    init_waitqueue_head(&port->open_wait);
    init_waitqueue_head(&port->close_wait);
    init_waitqueue_head(&port->delta_msr_wait);
    mutex_init(&port->mutex);
    mutex_init(&port->buf_mutex);
    spin_lock_init(&port->lock);
    port->close_delay = (50 * HZ) / 100;
    port->closing_wait = (3000 * HZ) / 100;
    kref_init(&port->kref);
}
EXPORT_SYMBOL(tty_port_init);
  • call: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()
      • tty_buffer_reset()
      • init_llist_head()
      • atomic_set()
      • atomic_set()
      • INIT_WORK()
    • init_waitqueue_head()
    • init_waitqueue_head()
    • init_waitqueue_head()
    • mutex_init()
    • mutex_init()
    • spin_lock_init()
    • kref_init()

kref.h::kref_init()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()
      • tty_buffer_reset()
      • init_llist_head()
      • atomic_set()
      • atomic_set()
      • INIT_WORK()
    • init_waitqueue_head()
    • init_waitqueue_head()
    • init_waitqueue_head()
    • mutex_init()
    • mutex_init()
    • spin_lock_init()
    • kref_init()
static inline void kref_init(struct kref *kref)
{
    atomic_set(&kref->refcount, 1);
}
  • return: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()
      • tty_buffer_reset()
      • init_llist_head()
      • atomic_set()
      • atomic_set()
      • INIT_WORK()
    • init_waitqueue_head()
    • init_waitqueue_head()
    • init_waitqueue_head()
    • mutex_init()
    • mutex_init()
    • spin_lock_init()
    • kref_init()

vt.c::con_init()

  • return: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()
      • tty_buffer_reset()
      • init_llist_head()
      • atomic_set()
      • atomic_set()
      • INIT_WORK()
    • init_waitqueue_head()
    • init_waitqueue_head()
    • init_waitqueue_head()
    • mutex_init()
    • mutex_init()
    • spin_lock_init()
    • kref_init()
// ARM10C 20150704
static int __init con_init(void)
{
...
    for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
        vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
        INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
        tty_port_init(&vc->port);
        visual_init(vc, currcons, 1);       
  • call: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • tty_buffer_init()
      • mutex_init()
      • tty_buffer_reset()
      • init_llist_head()
      • atomic_set()
      • atomic_set()
      • INIT_WORK()
    • init_waitqueue_head()
    • init_waitqueue_head()
    • init_waitqueue_head()
    • mutex_init()
    • mutex_init()
    • spin_lock_init()
    • kref_init()
    • visual_init()

vt.c::visual_init()

  • call: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
static void visual_init(struct vc_data *vc, int num, int init)
{
    /* ++Geert: vc->vc_sw->con_init determines console size */
    // vc->vc_sw:(kmem_cache#25-Ox)->vc_sw:  NULL
    if (vc->vc_sw)
        module_put(vc->vc_sw->owner);
    // vc->vc_sw:(kmem_cache#25-Ox)->vc_sw:  NULL, conswitchp: &dummy_con
    vc->vc_sw = conswitchp;
    // vc->vc_sw:(kmem_cache#25-Ox)->vc_sw: conswitchp: &dummy_con

#ifndef VT_SINGLE_DRIVER // VT_SINGLE_DRIVER: Not defined
    // con_driver_map[num: 0] : &dummy_con (index 0~62 에 모두 &dummy_con)
    if (con_driver_map[num])
        vc->vc_sw = con_driver_map[num];
        // vc->vc_sw:(kmem_cache#25-Ox)->vc_sw: con_driver_map[0] : &dummy_con          
#endif
    // vc->vc_sw->owner:(kmem_cache#25-Ox)->vc_sw->owner: (&dummy_con)->owner: NULL
    __module_get(vc->vc_sw->owner);

module.c::__module_get()

  • call: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
    • __module_get()
void __module_get(struct module *module)
{
    // module: NULL
    if (module) {
        preempt_disable();
        __this_cpu_inc(module->refptr->incs);
        trace_module_get(module, _RET_IP_);
        preempt_enable();
    }
}
EXPORT_SYMBOL(__module_get);

vt.c::visual_init()

  • return : start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
      • __module_get()
static void visual_init(struct vc_data *vc, int num, int init)
{
...
    // vc->vc_sw->owner:(kmem_cache#25-Ox)->vc_sw->owner: (&dummy_con)->owner: NULL
    __module_get(vc->vc_sw->owner);
    vc->vc_num = num;
    vc->vc_display_fg = &master_display_fg;
    vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
    vc->vc_uni_pagedir = 0;
    vc->vc_hi_font_mask = 0;
    vc->vc_complement_mask = 0;
    vc->vc_can_do_color = 0;
    vc->vc_panic_force_write = false;
    vc->vc_sw->con_init(vc, init);
    // dummycon_init()  

dummycon.c:dummycon_init()

  • return : start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
      • __module_get()
    • dummycon_init()
static void dummycon_init(struct vc_data *vc, int init)
{
    vc->vc_can_do_color = 1;
    if (init) {
    vc->vc_cols = DUMMY_COLUMNS;
    vc->vc_rows = DUMMY_ROWS;
    } else
    vc_resize(vc, DUMMY_COLUMNS, DUMMY_ROWS);
}

vt.c::visual_init()

  • return : start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
      • __module_get()
    • dummycon_init()
static void visual_init(struct vc_data *vc, int num, int init)
{
...
    vc->vc_sw->con_init(vc, init);
    // dummy_con_init() 
    vc->vc_s_complement_mask = vc->vc_complement_mask;
    vc->vc_size_row = vc->vc_cols << 1;
    vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
}

vt.c::con_init()

  • return : start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
      • __module_get()
    • dummycon_init()
// ARM10C 20150704
static int __init con_init(void)
{
...
    for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
        vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
        INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
        tty_port_init(&vc->port);
        visual_init(vc, currcons, 1);
        vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
        vc_init(vc, vc->vc_rows, vc->vc_cols,
            currcons || !vc->vc_sw->con_save_screen);
    }

vt.c::vc_init()

  • call : start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
      • __module_get()
    • dummycon_init()
    • vc_init()
vc_init( kmem_cache#25-oX, 30, 80, 1)
static void vc_init(struct vc_data *vc, unsigned int rows,
            unsigned int cols, int do_clear)
{
    int j, k ;

    vc->vc_cols = cols;
    vc->vc_rows = rows;
    vc->vc_size_row = cols << 1;
    vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;

    set_origin(vc);

vt.c::set_origin()

  • call: start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
      • __module_get()
    • dummycon_init()
    • vc_init()
      • set_origin()
static void set_origin(struct vc_data *vc)
{
    WARN_CONSOLE_UNLOCKED();

    if (!CON_IS_VISIBLE(vc) ||
        !vc->vc_sw->con_set_origin ||
        !vc->vc_sw->con_set_origin(vc))
        vc->vc_origin = (unsigned long)vc->vc_screenbuf;
    vc->vc_visible_origin = vc->vc_origin;
    vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
    vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
}
  • CON_IS_VISIBLE(vc)
#define CON_IS_VISIBLE(conp) (*conp->vc_display_fg == conp)

vt.c::vc_init()

  • return : start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
      • __module_get()
    • dummycon_init()
    • vc_init()
      • set_origin()
    set_origin(vc);
    vc->vc_pos = vc->vc_origin;
    reset_vc(vc);

vt_ioctl.c::reset_vc()

  • call : start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
      • __module_get()
    • dummycon_init()
    • vc_init()
      • set_origin()
    • reset_vc()
void reset_vc(struct vc_data *vc)
{
    vc->vc_mode = KD_TEXT;
    vt_reset_unicode(vc->vc_num);

vt_ioctl.c::reset_vc()

  • call : start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
      • __module_get()
    • dummycon_init()
    • vc_init()
      • set_origin()
    • reset_vc()
      • vt_reset_unicode()
void reset_vc(struct vc_data *vc)
{
...
    vt_reset_unicode(vc->vc_num);
    vc->vt_mode.mode = VT_AUTO;
    vc->vt_mode.waitv = 0;
    vc->vt_mode.relsig = 0;
    vc->vt_mode.acqsig = 0;
    vc->vt_mode.frsig = 0;
    put_pid(vc->vt_pid);
    vc->vt_pid = NULL;
    vc->vt_newvt = -1;
    if (!in_interrupt())    /* Via keyboard.c:SAK() - akpm */
        reset_palette(vc);
}
void vt_reset_unicode(int console)
{
    unsigned long flags;

    spin_lock_irqsave(&kbd_event_lock, flags);
    kbd_table[console].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
    spin_unlock_irqrestore(&kbd_event_lock, flags);
}
void put_pid(struct pid *pid)
{
    struct pid_namespace *ns;

    if (!pid)
        return;

    ns = pid->numbers[pid->level].ns;
    if ((atomic_read(&pid->count) == 1) ||
         atomic_dec_and_test(&pid->count)) {
        kmem_cache_free(ns->pid_cachep, pid);
        put_pid_ns(ns);
    }
}
EXPORT_SYMBOL_GPL(put_pid);

vt.c::reset_palette()

  • call : start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
      • __module_get()
    • dummycon_init()
    • vc_init()
      • set_origin()
    • reset_vc()
    • vt_reset_unicode()
    • put_pid()
    • reset_palette()
void reset_palette(struct vc_data *vc)
{
    int j, k;
    for (j=k=0; j<16; j++) {
        vc->vc_palette[k++] = default_red[j];
        vc->vc_palette[k++] = default_grn[j];
        vc->vc_palette[k++] = default_blu[j];
    }
    set_palette(vc);
}

vt.c::set_palette()

  • call : start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
      • __module_get()
    • dummycon_init()
    • vc_init()
      • set_origin()
    • reset_vc()
    • vt_reset_unicode()
    • put_pid()
    • reset_palette()
      • set_palette()
static void set_palette(struct vc_data *vc)
{
    WARN_CONSOLE_UNLOCKED();

    if (vc->vc_mode != KD_GRAPHICS)
        vc->vc_sw->con_set_palette(vc, color_table);
}

vt.c::vc_init()

  • return : start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
      • __module_get()
    • dummycon_init()
    • vc_init()
      • set_origin()
    • reset_vc()
    • vt_reset_unicode()
    • put_pid()
    • reset_palette()
      • set_palette()
    reset_vc(vc);
    for (j=k=0; j<16; j++) {
        vc->vc_palette[k++] = default_red[j] ;
        vc->vc_palette[k++] = default_grn[j] ;
        vc->vc_palette[k++] = default_blu[j] ;
    }
    vc->vc_def_color       = default_color;
    vc->vc_ulcolor         = default_underline_color;
    vc->vc_itcolor         = default_italic_color;
    vc->vc_halfcolor       = 0x08;   /* grey */
    init_waitqueue_head(&vc->paste_wait);
    reset_terminal(vc, do_clear);
}

vt.c::reset_terminal()

  • call : start_kernel()->console_init()->con_init()
    • mod_timer()
    • tty_port_init(&vc->port);
    • visual_init()
      • __module_get()
    • dummycon_init()
    • vc_init()
      • set_origin()
    • reset_vc()
    • vt_reset_unicode()
    • put_pid()
    • reset_palette()
      • set_palette()
    • init_waitqueue_head()
    • reset_terminal()
static void reset_terminal(struct vc_data *vc, int do_clear)
{
    vc->vc_top      = 0;
    vc->vc_bottom       = vc->vc_rows;
    vc->vc_state        = ESnormal;
    vc->vc_ques     = 0;
    vc->vc_translate    = set_translate(LAT1_MAP, vc);
    vc->vc_G0_charset   = LAT1_MAP;
    vc->vc_G1_charset   = GRAF_MAP;
    vc->vc_charset      = 0;
    vc->vc_need_wrap    = 0;
    vc->vc_report_mouse = 0;
    vc->vc_utf              = default_utf8;
    vc->vc_utf_count    = 0;

    vc->vc_disp_ctrl    = 0;
    vc->vc_toggle_meta  = 0;

    vc->vc_decscnm      = 0;
    vc->vc_decom        = 0;
    vc->vc_decawm       = 1;
    vc->vc_deccm        = global_cursor_default;
    vc->vc_decim        = 0;

    vt_reset_keyboard(vc->vc_num);

    vc->vc_cursor_type = cur_default;
    vc->vc_complement_mask = vc->vc_s_complement_mask;

    default_attr(vc);
    update_attr(vc);

    vc->vc_tab_stop[0]  = 0x01010100;
    vc->vc_tab_stop[1]  =
    vc->vc_tab_stop[2]  =
    vc->vc_tab_stop[3]  =
    vc->vc_tab_stop[4]  =
    vc->vc_tab_stop[5]  =
    vc->vc_tab_stop[6]  =
    vc->vc_tab_stop[7]  = 0x01010101;

    vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
    vc->vc_bell_duration = DEFAULT_BELL_DURATION;

    gotoxy(vc, 0, 0);
    save_cur(vc);
    if (do_clear)
        csi_J(vc, 2);
}

timer.c::mod_timer()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
  • apply_slack에서 한일: // timer의 expires 값을 효율적으로 보정하여 리턴
  • The first if, checking for timer->slack >= 0 fails,
  • so the else part is applied.
  • In that part the difference between expires and jiffies is slightly less than HZ
  • (you just did t.expires = jiffies + HZ.
  • Therefore, the delta in the function (with your data) is most likely about 4
  • and delta / 4 is non zero.
  • This in turn implies that mask (which is expires ^ expires_limit) is not zero.
  • The rest really depends on the value of expires, but for sure, it gets changed.
  • So there you have it, since slack is automatically set to -1,
  • the apply_slack function is changing your expires time to align with,
  • I guess, the timer ticks.
  • If you don't want this slack, you can set t.slack = 0;
  • when you are initializing the timer in timer_init.
  • 0.4% 이내의 expires를 적용하기 위해서 timer slack이라는 개념을 가져왔다.
// ARM10C 20150704
// &console_timer, jiffies: xx_64 + 60000
int mod_timer(struct timer_list *timer, unsigned long expires)
{
    // timer: &console_timer, expires: xx_64 + 60000
    // apply_slack(&console_timer, xx_64 + 60000): xx_64 + 60000
    expires = apply_slack(timer, expires);
    // expires: xx_64 + 60000


    /*
     * This is a common optimization triggered by the
     * networking code - if the timer is re-modified
     * to be the same thing then just return:
     */
    // timer: &console_timer, timer_pending(&console_timer): 0,
    // timer->expires: (&console_timer)->expires: 0, expires: xx_64 + 60000
    if (timer_pending(timer) && timer->expires == expires)
        return 1;

log

  • 1st log
b10182f..d3618f3  master     -> origin/master
Updating b10182f..d3618f3
Fast-forward
arch/arm/include/asm/atomic.h     |   6 +
arch/arm/kernel/setup.c           |   3 +-
drivers/tty/tty_buffer.c          |  73 ++++++++++
drivers/tty/tty_port.c            |  96 ++++++++++++++
drivers/tty/vt/keyboard.c         |  15 +++
drivers/tty/vt/vt.c               | 272 ++++++++++++++++++++++++++++++++++++++
drivers/tty/vt/vt_ioctl.c         |  42 ++++++
drivers/video/console/dummycon.c  |  24 ++++
include/asm-generic/atomic-long.h |   1 +
include/asm-generic/param.h       |   1 +
include/linux/console.h           |   3 +
include/linux/console_struct.h    |  12 ++
include/linux/export.h            |   2 +
include/linux/gfp.h               |   1 +
include/linux/kbd_kern.h          |   5 +
include/linux/kref.h              |   4 +
include/linux/list.h              |   4 +
include/linux/llist.h             |   5 +
include/linux/lockdep.h           |   1 +
include/linux/module.h            |   1 +
include/linux/mutex-debug.h       |   6 +
include/linux/mutex.h             |   5 +-
include/linux/pid.h               |   1 +
include/linux/pid_namespace.h     |   5 +-
include/linux/preempt_mask.h      |   1 +
include/linux/slab.h              |   4 +
include/linux/spinlock.h          |   8 ++
include/linux/tty.h               |   7 +
include/linux/types.h             |   2 +
include/linux/wait.h              |   9 ++
include/linux/workqueue.h         |  45 ++++++-
include/uapi/linux/kd.h           |   6 +
include/uapi/linux/screen_info.h  |   1 +
include/uapi/linux/vt.h           |   7 +
kernel/locking/mutex-debug.c      |   8 +-
kernel/locking/mutex-debug.h      |   4 +
kernel/locking/mutex.c            |  37 +++++-
kernel/locking/spinlock_debug.c   |  11 ++
kernel/module.c                   |   3 +
kernel/pid.c                      |   4 +
kernel/printk/printk.c            |   3 +
kernel/sched/wait.c               |  11 ++
42 files changed, 752 insertions(+), 7 deletions(-)

댓글 없음:

댓글 쓰기