1 / 10

if (!irqs_disabled())

Irq 가 disable 되어 있는지 확인하고 이미 enable 되어있다면 “start_kernel(): bug: interrupts were enabled *very* early, fixing it” 을 출력하고 local_irq_disable 함수를 호출하여 인터럽트를 disable 시킨다. init/main.c. if (!irqs_disabled()).

ziv
Download Presentation

if (!irqs_disabled())

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Irq 가 disable 되어 있는지 확인하고 이미 enable 되어있다면 “start_kernel(): bug: interrupts were enabled *very* early, fixing it” 을 출력하고 local_irq_disable 함수를 호출하여 인터럽트를 disable 시킨다. init/main.c if (!irqs_disabled()) CONFIG_MMU 가 정의 될경우 __ex_table 섹션에 저장된 주소(어떤 명령어의 주소가 담겨있음) 를 기준으로 정렬한다. CONFIG_MMU 가 정의 안되어있을경우 의미 없음.- 예) copy_from_user.S 에서 섹션 정의 하는 부분 찾을수 있음. sort_main_extable() ARM 에서는 아무 것도 하지 않음. trap_init rcu_barrier_cpu_hotplug에 대한 notifier block 을 하나 만들고 해당 block에 rcu_barrier_cpu_hotplug 함수를 등록 하고 priority를 0으로 셋팅한다. 마지막으로 notifier block을 cpu_chain의 알맞은 위치에 추가한다. rcu_init __rcu_init rcu_online_cpu를 호출해서 해당 cpu의 rcu자료구조를 초기화하고 RCU_SOFTIRQ에 대한 콜백함수를 등록한다. 마지막으로 cpu_chain의 알맞은 위치에 notifier block 인 nb를 추가 한다. hotcpu_notifier early_irq_init

  2. Memory Types Todo: RCU 개념 정리

  3. 전역 변수인 struct irq_desc irq_desc{[NR_IRQS] 를 초기화 하는 작업을 한다. 전역 변수 irq_default_affinity 에 메모리를 할당 하고 nr_cpu_ids-1 만큼의 비트를 모두 set 한다. irq_desc 를 ARRAY_SIZE 만큼 순회 하면서 멤버변수 affinity 에 필요한 메모리를 할당 받고 kstat_irqs 를 이미 정적으로 선언한 kstat_irqs_all 로 설정 한다. init/main.c early_irq_init irq_desc 를 NR_IRQ 만큼순회하면서 status 를 IRQ_NOREQUEST IRQ_NOPROBE 로 설정하고 CONFIG_SMP 가 설정 되어 있을 경우 bad_irq_desc.affnity 를 nr_cpu_ids-1 비트만큼 set 한다. 그리고 setup_arch 에서 mdesc->init_irq 가 설정된 init_arch_irq 를 호출 하여 각 해당 플랫폼에 맞는 인터럽트 초기화 과정을 거친다. init_IRQ init_arch_irq 인터럽트 컨트롤러를 초기화하고 각 irq에 해당 하는 irq_desc[irq] 의 멤버 변수 handle_irq (핸들러 함수) 를 플랫폼에 맞는 함수로 설정 한다. s3c6410 의 경우 s3c6410_init_irq To Do 하드웨어 의존적이기는 하나 좀더 자세한 분석 필요. pid_hash_init

  4. irq_desc 구조체와 irq_desc[NR_IRQS]_ 정적 구조체 배열 include/linux/irq.h kernel/handle.c struct irq_desc { unsigned int irq; struct timer_rand_state *timer_rand_state; unsigned int *kstat_irqs; #ifdef CONFIG_INTR_REMAP struct irq_2_iommu *irq_2_iommu; #endif irq_flow_handler_t handle_irq; struct irq_chip *chip; struct msi_desc *msi_desc; void *handler_data; void *chip_data; struct irqaction *action; /* IRQ action list */ unsigned int status; /* IRQ status */ unsigned int depth; /* nested irq disables */ unsigned int wake_depth; /* nested wake enables */ unsigned int irq_count; /* For detecting broken IRQs */ unsigned long last_unhandled; /* Aging timer for unhandled count */ unsigned int irqs_unhandled; spinlock_t lock; #ifdef CONFIG_SMP cpumask_var_t affinity; unsigned int cpu; #ifdef CONFIG_GENERIC_PENDING_IRQ cpumask_var_t pending_mask; #endif #endif atomic_t threads_active; wait_queue_head_t wait_for_threads; #ifdef CONFIG_PROC_FS struct proc_dir_entry *dir; #endif const char *name; } ____cacheline_internodealigned_in_smp; struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { [0 ... NR_IRQS-1] = { .status = IRQ_DISABLED, .chip = &no_irq_chip, .handle_irq = handle_bad_irq, .depth = 1, .lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock), } }; early_irq_init 함수와 init_IRQ 함수에서 참조되는 구조체 이다. 인터럽트 처리를 위해 중요한 자료 구조 이다.

  5. 1.커널 페이지의 크기를 megabyte단위로 구함 2. 시스템의 메모리를 기준으로 해쉬테이블의 slot 개수를 16~4096개로 설정한다. 1기가 바이트 이상이면 해쉬테이블의 slot 을 4096 개로 설정. 3. 해쉬테이블을 위해 메모리를 할당하고 각 엔트리의 first 멤버들을 NULL 로 초기화 init/main.c pid_hash_init 4가지의 action 타입에 따라 처리하는 일이 달라진다. init_timers CPU_UP_PREFARE: CPU_UPPREFARE_FROZEN: CPU_DEAD: CPU_DEAD_FROZEN: timer_cpu_notify register_cpu_notifier init_timer_cpu migrate_timers struct tvec_base { spinlock_t lock; struct timer_list *running_timer; unsigned long timer_jiffies; // 타이머에 등록된 핸들러는 타이머 간격에 따라 // 시간별로 분류하여 다섯 개의 타이머 벡터에 // 분할해서 등록한다 tv1는 타이머 간격이 1초 // 이내인, tv2는 1분 이내인 핸들러가 등록되는 // 방식이다 struct tvec_root tv1; // 약 1초 struct tvec tv2; // 약 1분 struct tvec tv3; // 약 1시간 struct tvec tv4; // 약 3일 struct tvec tv5; // 약 199일 } ____cacheline_aligned; boot_done을 1로 초기화하고 전역 으로 선언된 struct tvec_base boot_tvec_bases 의 timer_jiffies 값을 시스템의 jiffies 값으로 설정하고 구조체내의 값들을 초기화함.boot time이 아닐 때 호출된 경우에는 base를 할당 받아서 동일 과정을 처리한다. 주어진 cpu의 tvec_base를 현재 cpu의 tvec_base로 migration

  6. init/main.c init_timers timer_cpu_notify init_timer_cpu migrate_timers static struct notifier_block __cpuinitdata timers_nb = { .notifier_call = timer_cpu_notify, }; 전역으로 선언된 위 구조체 timers_nb를 notify_block 의 헤더인 cpu_chain 에 추가한다. register_cpu_notifier open_softirq 전역 자료구조 softirq_vec 배열에서 TIMER_SOFTIRQ 번째 엔트리 값의 action 변수를 runtimer_softirq로 설정한다. TIMER_SOFTIRQ 발생시 설정한 함수가 호출 될 것이다. include/linux/interrupt.h struct softirq_action { void (*action)(struct softirq_action *); }; kernel/softirq.c struct softirq_action softirq_vec[NR_SOFTIRQS] ; hrtimers_init

  7. init/main.c 6가지의 action 타입에 따라 처리하는 일이 달라진다. init_hrtimers CPU_UP_PREFARE: CPU_UPPREFARE_FROZEN: CPU_DYING: : CPU_DYING_FROZEN: CPU_DEAD: CPU_DEAD_FROZEN: hrtimer_cpu_notify 2개의 clock base(CLOCK_REALTIME과 CLOCK_MONOTONIC)를 초기화 high resolution mode를 비활성화, 만료시간 설정 CLOCK_REALTIME:현재 시간을 기준으로 하여 시간을 계산(시스템 시간 변경 시 영향을 받음) CLOCK_MONOTONIC:커널이 동작한 시간을 기준으로 하여 시간을 계산(외부의 영향을 받지 않음) init_hrtimer_cpu clockevents_notify clockevents_notify checkevent_chain에 등록된 모든 콜백함수를 호출한다 그 중 tick_notify()는 reason이 CLOCK_EVT_NOTIFY_CPU_DYING일 경우 tick_handover_do_timer()를 호출한다. 이 함수는 tick_do_timer_cpu변수를 세팅하여 online되어 있는 가장첫번째 cpu가 jiffies값을 업데이트하도록 한다 (jiffies 업데이트를 담당하던 cpu가 죽으면 다른 cpu가 맡도록 한다) migrate_hrtimers sched_timer가 수행이 끝날 때까지 기다렸다가 rbtree에서 삭제하고 상태를 inactive로 변경한다 그리고 expired time을 재설정한다 timer의 state를 Migrate로 바꾸고 base를 new_base로 바꾼다 base를 바꾸면 타이머를 처리할 cpu가 바뀐다 timer를 rb tree에 추가하고 state에 HRTIMER_STATE_ENQUEUED를 추가한다 state에서 migrate를 제거한다 rb-tree에서 soft expired된 timer들의 노드를 삭제하고 타이머의 이벤트핸들러를 호출해서 처리한다 register_cpu_notifier

  8. init/main.c init_hrtimers hrtimer_cpu_notify init_hrtimer_cpu clockevents_notify clockevents_notify register_cpu_notifier migrate_hrtimers static struct notifier_block __cpuinitdata timers_nb = { .notifier_call = hrtimer_cpu_notify, }; 전역으로 선언된 위 구조체 hrtimers_nb를 notify_block 의 헤더인 cpu_chain 에 추가한다. open_softirq HRTIMER_SOFTIRQ가 raise되면 run_hrtimer_softirq를 호출하도록 등록한다 softirq_init

  9. init/main.c 해당 CPU의 tasklet_vec,tasklet_hi_vec, softirq_work_list를 초기화 cpu_chain의 알맞은 위치에 remote_softirq_cpu_notifier를 추가한다. 각각 해당 softirq발생시 호출될 콜백함수를 등록한다 softirq_init NTP 상태 변수를 초기화하고 leap_timer가 현재시간을 기준으로 시간을 계산하는 CLOCK_REALTIME에 기반하여 절대시간을 사용하도록 초기화한다 timekeeping_init ntp_init clocksource_register()를 호출하여 next_clocksource를 초기화하기 전까지는 계속 clocksource_jiffies를 리턴한다 clocksource_get_next clocksource_enable clock_source가 jiffies일 경우 이미 jffies값이 동작하고 있으므로 enable할 필요가 없다. clocksource_calculate_interval NTP_INTERVAL_LENGTH를 이용해서 clock의 멤버변수인 xtime_interval, low_interval, cycle_interval을 세팅한다. NTP_INTERVAL_LENGTH -> jiffies값이 1증가될 때 걸리는 nano sec단위 값 set_normalized_timespec time_init wall_to_monotonic은시스템부팅완료시에 0이 된다. 현재는 부팅중이므로 음수값을 가진다 . 세번째 인자가 음수가 넘겨지더라도 wall_to_monotonic의 멤버변수인 tv_nsec은 양수값을 가진다

  10. init/main.c time_init setup_arch 에서 system_timer 에 설정한 함수를 호출한다. 각 플랫폼 마다 다르게 정의 되어있다. hardware timer 클럭 초기화 하고 인터럽트를 등록한다. s3c6410 의 경우 s3c2410_timer_init To Do 하드웨어 의존적이기는 하나 좀더 자세한 분석 필요. sched_clock_init

More Related