/[lkdp]/lkdp/pm/initial.tex
ViewVC logotype

Diff of /lkdp/pm/initial.tex

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2 by kdlinux2001, Thu Nov 21 13:08:15 2002 UTC revision 1.3 by kdlinux2001, Wed Feb 26 06:38:22 2003 UTC
# Line 1  Line 1 
1  \chapter{Initialization}  \chapter{Initialization}
2          \section{start\_kernel Function} \label{init:sk} \index{start\_kernel}          \section{start\_kernel Function} \label{init:sk} \index{start\_kernel}
3               When a PC is powered on, it initializes all the hardware present in the system and makes sure, every hardware is up and running. So, after initial hardware boot sequence, kernel comes into picture by trasfering control to \textit{start\_kernel} function. This function is defined in the file \url{init/main.c}. Only the first CPU calls start\_kernel(), while all others call function initialize\_secondary()\footnote{defined in \url{arch/i386/kernel/smpboot.c}}. Ihe start\_kernel function performs intialization of the all Operating Systems' Blocks and initializes the data structures used by the kernel. This function calls sub-functions to perform the initialization of IRQ requests, process scheduler, softirq systems, kernel timers, signal mechanism and SMP(symmetric multi-processing) machanism while the \textit{initialize\_secondary} function just copies the stack pointer and EIP values from the Task State Segment(TSS).               \textbf{\Large W}hen a PC is powered on, it initializes all the hardware present in the system and makes sure, every hardware is up and running. So, after initial hardware boot sequence, kernel comes into picture by transferring control to \textit{start\_kernel} function. This function is defined in the file \url{init/main.c}. Only the first CPU calls start\_kernel(), while all others call function initialize\_secondary()\footnote{defined in \url{arch/i386/kernel/smpboot.c}}. Ihe start\_kernel function performs initialization of the all Operating Systems' Blocks and initializes the data structures used by the kernel. This function calls sub-functions to perform the initialization of IRQ requests, process scheduler, softirq systems, kernel timers, signal mechanism and SMP(symmetric multi-processing) mechanism while the \textit{initialize\_secondary} function just copies the stack pointer and EIP values from the Task State Segment(TSS).
4                  \newline \par The code is explained below.                  \\ \par The code is explained below.
5    
6          \begin{verbatim}          \begin{verbatim}
7    
8              lock_kernel();              lock_kernel();
9              printk(linux_banner);              printk(linux_banner);
10              setup_arch(&command_line);              setup_arch(&command_line);
11              setup_per_cpu_areas();              setup_per_cpu_areas();
12              printk("Kernel command line: %s\n", saved_command_line);              printk("Kernel command line: %s\n", saved_command_line);
13              parse_options(command_line);              parse_options(command_line);
14              trap_init();              trap_init();
15              init_IRQ();              init_IRQ();
16              sched_init();              sched_init();
17              softirq_init();              softirq_init();
18              /* timer and memory initialization code */              /* timer and memory initialization code */
19              fork_init();              fork_init();
20              signals_init();              signals_init();
21              smp_init();              smp_init();
22    
23          \end{verbatim}          \end{verbatim}
24    
25                  \subsection{Macro lock\_kernel}                  \subsection{Macro lock\_kernel}
26               The macro lock\_kernel is defined in in the file \url{include/linux/smp_lock.h}. This is only defined for non-SMP systems, because there are no inter-CPU locks on single CPU systems. On i386 SMP systems, lock\_kernel is an inline function: \url{incllude/asm/i386/smplock.h}               The macro lock\_kernel is defined in the file \url{include/linux/smp_lock.h}. This is only defined for non-SMP systems, because there are no inter-CPU locks on single CPU systems. On i386 SMP systems, lock\_kernel is an inline function: \url{incllude/asm/i386/smplock.h}
27          \begin{verbatim}          \begin{verbatim}
28    
29              extern __inline__ void lock_kernel(void)              extern __inline__ void lock_kernel(void)
30              {              {
31                  if (!++current->lock_depth)                  if (!++current->lock_depth)
32                  spin_lock(&kernel_flag);                  spin_lock(&kernel_flag);
33              }              }
34    
35          \end{verbatim}          \end{verbatim}
36    
37                  So on a non-SMP system, the macro expands to 'do\{\}  while(0)' and gets optimised away.                  So on a non-SMP system, the macro expands to 'do\{\}  while(0)' and gets optimized away.
38    
39                  \subsection{Functions trap\_init,init\_IRQ}                  \subsection{Functions trap\_init,init\_IRQ}
40              The functions \textit{trap\_init} and \textit{init\_IRQ} are architecture dependant and perform the initilization of IRQ hardware. These functions are defined in the architecture dependant section of kernel code. Let us look at them one by one.              The functions \textit{trap\_init} and \textit{init\_IRQ} are architecture dependant and perform the initialization of IRQ hardware. These functions are defined in the architecture dependant section of kernel code. Let us look at them one by one.
41    
42                  Function trap\_init() \label{init:trap_init}                  Function trap\_init() \label{init:trap_init}
43                  \textit{File: }\url{arch/i386/kernel/traps.c}\\ \newline                  \textit{File: }\url{arch/i386/kernel/traps.c}\\ \newline
44              This function is used to initialize the IDT with an exception handler functions for each recognized exception. This job is accomplished through the set\_trap\_gate and set\_system\_gate macros. The x86 microprocessors issue 20 different exceptions(0 - 19). The kernel must provide a dedicated exception handler for each exception type. The table in appendix ~\ref{appendix1} shows the exception and its corresponding exception handler along with the signals sent by the exception handlers.              This function is used to initialize the IDT with an exception handler functions for each recognized exception. This job is accomplished through the set\_trap\_gate and set\_system\_gate macros. The x86 microprocessors issue 20 different exceptions(0 - 19). The kernel must provide a dedicated exception handler for each exception type. The table in appendix ~\ref{appendix1} shows the exception and its corresponding exception handler along with the signals sent by the exception handlers.
45    
46  % TODO appendix A          \\ \par The code is explained below.
47          \newline \par The code is explained below.  
48            \begin{verbatim}
49          \begin{verbatim}  
50                set_trap_gate(0,&divide_error);
51              set_trap_gate(0,&divide_error);              set_trap_gate(1,&debug);
52              set_trap_gate(1,&debug);              set_intr_gate(2,&nmi);
53              set_intr_gate(2,&nmi);              set_system_gate(3,&int3);       /* int3-5 can be called from all */
54              set_system_gate(3,&int3);       /* int3-5 can be called from all */              set_system_gate(4,&overflow);
55              set_system_gate(4,&overflow);              set_system_gate(5,&bounds);
56              set_system_gate(5,&bounds);              set_trap_gate(6,&invalid_op);
57              set_trap_gate(6,&invalid_op);              .
58              .              .
59              .              .
60              .              set_trap_gate(19,&simd_coprocessor_error);
61              set_trap_gate(19,&simd_coprocessor_error);              set_call_gate(&default_ldt[0],lcall7);
62              set_call_gate(&default_ldt[0],lcall7);              set_call_gate(&default_ldt[4],lcall27);
63              set_call_gate(&default_ldt[4],lcall27);  
64            \end{verbatim}
65          \end{verbatim}              All these functions map to \_set\_gate macro with appropriate parameters. Please refer to appendix ~\ref{appendix2} for details about different types of gates. The macro \_set\_gate is explained below:
66              All these functions map to \_set\_gate macro with appropriate parameters. Please refer to appendix ~\ref{appendix2} for details about different types of gates. The macro \_set\_gate is explained below:  
67            \\ \par \index{\_set\_gate}
68  %TODO : appendix B  
69          \newline \par \textbf{Function init\_IRQ()} \index{\_set\_gate}          \begin{verbatim}
70    
71          \begin{verbatim}              #define _set_gate(gate_addr,type,dpl,addr) \
72                do { \
73              #define _set_gate(gate_addr,type,dpl,addr) \                int __d0, __d1; \
74              do { \                  __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
75                int __d0, __d1; \                "movw %4,%%dx\n\t" \
76                  __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \                "movl %%eax,%0\n\t" \
77                "movw %4,%%dx\n\t" \                "movl %%edx,%1" \
78                "movl %%eax,%0\n\t" \                :"=m" (*((long *) (gate_addr))), \
79                "movl %%edx,%1" \                 "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
80                :"=m" (*((long *) (gate_addr))), \                :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
81                 "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \                 "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \
82                :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \              } while (0)
83                 "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \  
84              } while (0)          \end{verbatim}
85            % TODO Macro explanation
86          \end{verbatim}          First we shall explain the macro arguments.
87          % TODO Macro explaination          % TODO Setup TSS and LDT in GDT for each task in appendix 3.
88          First we shall explain the macro arguments.  
89          % Setup TSS and LDT in GDT for each task                  Function init\_IRQ() \label{init:init_IRQ}
90                    \textit{File: }\url{arch/i386/kernel/i8259.c}\\ \newline
91                  Function init\_IRQ() \label{init:init_IRQ}              This function is used to setup all interrupt vectors and interrupt gates. Linux kernel uses vectors 0 to 31 for exceptions and nonmaskable interrupts while remaining vectors are software interrupts. Precisely, vectors 32(0x20) to 47(0x2f) are maskable interrupts, caused by IRQs while the remaining vectors ranging from 48 to 255 may be used to identify software interrupts. Also, Linux uses only the 128(0x80) vector, which it uses to implement system calls.[SYSCALL\_VECTOR]. \index{SYSCALL\_VECTOR}
92                  \textit{File: }\url{arch/i386/kernel/i8259.c}\\ \newline  
93              This function is used to setup all interrupt vectors and interrupt gates. Linux kernel uses vectors 0 to 31 for exceptions and nonmaskable interrupts while remaining vectors are software interrupts. Precisely, vectors 32(0x20) to 47(0x2f) are maskable interrupts, caused by IRQs while the remaining vectors ranging from 48 to 255 may be used to identify software interrupts. Also, Linux uses only the 128(0x80) vector, which it uses to implement system calls.[SYSCALL\_VECTOR]. \index{SYSCALL\_VECTOR}          \\ \par The code is explained below.
94    
95          \newline \par The code is explained below.          \begin{verbatim}
96    
97          \begin{verbatim}              for (i = 0; i < NR_IRQS; i++) {
98                    /* NR_IRQS   224
99              for (i = 0; i < NR_IRQS; i++) {                     as per include/asm-i386/irq.h
100                  /* NR_IRQS   224                  /* FIRST_EXTERNAL_VECTOR = 0x20 ie. 32
101                     as per include/asm-i386/irq.h                     as per include/asm-i386/hw_irq.h  */
102                  /* FIRST_EXTERNAL_VECTOR = 0x20 ie. 32  
103                     as per include/asm-i386/hw_irq.h  */                  int vector = FIRST_EXTERNAL_VECTOR + i;
104                    if (vector != SYSCALL_VECTOR)
105                  int vector = FIRST_EXTERNAL_VECTOR + i;                      set_intr_gate(vector, interrupt[i]);
106                  if (vector != SYSCALL_VECTOR)              }
107                      set_intr_gate(vector, interrupt[i]);              set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
108              }              set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
109              set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);              set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
110              set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);              set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
111              set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);  
112              set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);          \end{verbatim}
113    
114          \end{verbatim}              The interrupts gates corresponding to FIRST\_DEVICE\_VECTOR, RESCHEDULE\_VECTOR, INVALIDATE\_TLB\_VECTOR, CALL\_FUNCTION\_VECTOR are set. These are special IRQ vectors used by the SMP architecture, generally ranging from 0xf0 to 0xff. Refer to \url{include/asm-i386/irq_vectors.h} for more details.
115    
116              The interrupts gates corresponding to FIRST\_DEVICE\_VECTOR, RESCHEDULE\_VECTOR, INVALIDATE\_TLB\_VECTOR, CALL\_FUNCTION\_VECTOR are set. These are special IRQ vectors used by the SMP architecture, generally ranging from 0xf0 to 0xff. Refer to \url{include/asm-i386/irq_vectors.h} for more details.                  \subsection{Function sched\_init}
117                Process is a basic entity in any unix based system. In a multitasking environment, number of processes are executing on single/multiple CPU/CPUs. Each process gets a fair chance to execute on the CPU depending on the process characteristics. This allocation is done by a special process known as "scheduler". The process scheduler is initialized by calling the function \textit{sched\_init} defined in \url{kernel/sched.c}
118                  \subsection{Function sched\_init}  
119              Process is a basic entity in any unix based system. In a multitasking environment, number of processes are executing on single/multiple CPU/CPUs. Each process gets a fair chance to execute on the CPU depending on the process characteristics. This allocation is done by a special process known as "scheduler". The process scheduler is initialized by calling the function \textit{sched\_init} defined in \url{kernel/sched.c}                  \subsubsection{runqueue data structure}
120                Linux Kernel 2.2 had a hardcoded limit on the number of processes. So, an array \textit{tasks} was used to store pointers to all process descriptors. This idea is deprecated in kernel 2.4 and separate lists of tasks in running state and tasks waiting for different O.S. resources are maintained. All the tasks in running state \textit{TASK\_RUNNING} are considered while scheduling. These tasks are defined using runqueues.
121                  \subsubsection{runqueue data structure}              \par The runqueue data structure is explained here in order to understand the initialization code. The scheduler uses an array of runqueues \index{runqueues} as basic data structure defined in \url{kernel/sched.c}. The NR\_CPUS\index{NR\_CPUS}\footnote{defined in \url{include/linux/threads.h}} represents the number of CPUs present in the system. Its value is 32 in SMP mode and 1 in non-SMP mode.
122              Linux Kernel 2.2 had a hardcoded limit on the number of processes. So, an array \textit{tasks} was used to store pointers to all process descriptors. This idea is deprecated in kernel 2.4 and separate lists of tasks in running state and tasks waiting for differnet O.S. resources are maintained. All the tasks in running state \textit{TASK\_RUNNING} are considered while scheduling. These tasks are defined using runqueues.          \begin{verbatim}
123              \par The runqueue data structure is explained here in order to understand the initialization code. The scheduler uses an array of runqueues \index{runqueues} as basic data structure defined in \url{kernel/sched.c}. The NR\_CPUS\index{NR\_CPUS}\footnote{defined in \url{include/linux/threads.h}} represents the number of CPUs present in the system. Its value is 32 in SMP mode and 1 in non-SMP mode.  
124          \begin{verbatim}          struct runqueue {
125                spinlock_t lock;
126          struct runqueue {              unsigned long nr_running, nr_switches, expired_timestamp;
127              spinlock_t lock;              signed long nr_uninterruptible;
128              unsigned long nr_running, nr_switches, expired_timestamp;              task_t *curr, *idle;
129              signed long nr_uninterruptible;              prio_array_t *active, *expired, arrays[2];
130              task_t *curr, *idle;              int prev_nr_running[NR_CPUS];
131              prio_array_t *active, *expired, arrays[2];              task_t *migration_thread;
132              int prev_nr_running[NR_CPUS];              list_t migration_queue;
133              task_t *migration_thread;          } ____cacheline_aligned;
134              list_t migration_queue;  
135          } ____cacheline_aligned;          static struct runqueue runqueues[NR_CPUS] __cacheline_aligned;
136    
137          static struct runqueue runqueues[NR_CPUS] __cacheline_aligned;          \end{verbatim}
138    
139          \end{verbatim}               The description of the elements of the above structure follows:
140            \begin{description}
141               The description of the elements of the above structure follows:          \item[lock] Spinlock used by the runqueue in order to gain atomic access of the CPU.
142          \begin{description}          \item[nr\_running] Total number of runnable processes i.e. in TASK\_RUNNING state.
143          \item[lock] Spinlock used by the runqueue in order to gain atomic access of the CPU.          \item[task\_t curr, idle] Tasks associated with the current runqueue.\footnote{task\_t is typedefinition of task\_struct \url{include/linux/sched.h}}
144          \item[nr\_running] Total number of runnable processes i.e. in TASK\_RUNNING state.          \item[prio\_array\_t arrays] Priority structure containing the priority bitmap of size BITMAP\_SIZE along with a linked list (queue) of size MAX\_PRIO.
145          \item[task\_t curr, idle] Tasks associated with the current runqueue.\footnote{task\_t is typedefinition of task\_struct \url{include/linux/sched.h}}          \item[migration\_thread] \index{migration\_thread} Migration thread associated with the runqueue.
146          \item[prio\_array\_t arrays] Priority structure containing the priority bitmap of size BITMAP\_SIZE along with a linked list (queue) of size MAX\_PRIO.          \item[migration\_queue] \index{migration\_queue} Migration queue associated with the runqueue.
147          \item[migration\_thread] \index{migration\_thread} Migration thread associated with the runqueue.Refer to section ~\ref{psched:structs} for more details.          \end{description}
148          \item[migration\_queue] \index{migration\_queue} Migration queue associated with the runqueue.Refer to section ~\ref{psched:structs} for more details.  
149          \end{description}          \par Each process has a process descriptor associated with it. This process information is stored in \textit{struct task\_struct} defined in \url{include/linux/sched.h}. All process descriptors are linked together by process list and the runqueue list links together process descriptors all the runnable processes. In both cases, the init\_task process descriptor acts as the list header.
150    
151          \par Each process has a process descriptor associated with it. This process information is stored in \textit{struct task\_struct} defined in \url{include/linux/sched.h}. All process descriptors are linked together by process list and the runqueue list links together process descriptors all the runnable processes. In both cases, the init\_task process descriptor acts as the list header.                  \subsubsection{Function sched\_init()} \label{init:sched_init}
152               \par The function sched\_init initializes the runqueue data structure for all the CPUs. It contains 2 copies of priority array structure which are initialized to active and expired priorities. The INIT\_LIST\_HEAD macro initializes the linked list (queue) of priority structure of size MAX\_PRIO, (value greater than any user task priority \url{include/sched.h} for details) and also clears the priority bitmap.
153                  \subsubsection{Function sched\_init()} \label{init:sched_init}  
154             \par The function sched\_init initializes the runqueue data structure for all the CPUs. It contains 2 copies of priority array structure which are initialized to active and expired priorities. The INIT\_LIST\_HEAD macro initializes the the linked list (queue) of priority structure of size MAX\_PRIO, (value greater than any user task priority \url{include/sched.h} for details) and also clears the priority bitmap.          \\ \par The code is explained below.
155            \begin{verbatim}
156          \newline \par The code is explained below.  
157          \begin{verbatim}              for (i = 0; i < NR_CPUS; i++) {
158                    prio_array_t *array;
159              for (i = 0; i < NR_CPUS; i++) {                  rq = cpu_rq(i);
160                  prio_array_t *array;                  rq->active = rq->arrays;
161                  rq = cpu_rq(i);                  rq->expired = rq->arrays + 1;
162                  rq->active = rq->arrays;                  spin_lock_init(&rq->lock);
163                  rq->expired = rq->arrays + 1;                  INIT_LIST_HEAD(&rq->migration_queue);
164                  spin_lock_init(&rq->lock);                  for (j = 0; j < 2; j++) {
165                  INIT_LIST_HEAD(&rq->migration_queue);                      array = rq->arrays + j;
166                  for (j = 0; j < 2; j++) {                      for (k = 0; k < MAX_PRIO; k++) {
167                      array = rq->arrays + j;                          INIT_LIST_HEAD(array->queue + k);
168                      for (k = 0; k < MAX_PRIO; k++) {                          __clear_bit(k, array->bitmap);
169                          INIT_LIST_HEAD(array->queue + k);                          /* refer to include\asm-i386/bitops.h */
170                          __clear_bit(k, array->bitmap);                      }
171                          /* refer to include\asm-i386/bitops.h */                  }
172                      }                  __set_bit(MAX_PRIO, array->bitmap);
173                  }              }
174                  __set_bit(MAX_PRIO, array->bitmap);  
175              }          \end{verbatim}
176                  The sched\_init function also starts a process in SMP mode by setting up the a runqueue on current CPU, its "curr" and "idle" pointers to itself. Then it initializes all the timers by calling the function init\_timervecs \footnote{init\_timervecs is defined in \url{kernel/timer.c}} and initializes the bottom halves associated with the task queue (TQUEUE\_BH) and immediate queue (IMMEDIATE\_BH). The function \textit{wake\_up\_process} is explained in the chapter ~\ref{sched:all}. The function init\_bh is used to install a bottom half handler into one of the 32 available slots. The bottom half is executed when mark\_bh is invoked. Refer to section ~\ref{int:bh} for more information about \texttt{bottom halves}.
177          \end{verbatim}  
178                The sched\_init function also starts a process in SMP mode by seting up the a runqueue on current CPU, its "curr" and "idle" pointers to itself. Then it initializes all the timers by calling the function init\_timervecs \footnote{init\_timervecs is defined in \url{kernel/timer.c}} and initializes the bottom halves associated with the task queue (TQUEUE\_BH) and immediate queue (IMMEDIATE\_BH). The function \textit{wake\_up\_process} is explained in the chapter ~\ref{sched:all}. The function init\_bh is used to install a bottom half handler into one of the 32 available slots. The bottom half is executed when mark\_bh is invoked. Refer to section ~\ref{int:bh} for more information about \texttt{bottom halves}.                  \\ \par The code is explained below.
179            \begin{verbatim}
180                  \newline \par The code is explained below.  
181          \begin{verbatim}              rq = this_rq();
182                rq->curr = current;
183              rq = this_rq();              rq->idle = current;
184              rq->curr = current;              wake_up_process(current);
185              rq->idle = current;  
186              wake_up_process(current);              init_timervecs();
187                init_bh(TQUEUE_BH, tqueue_bh);
188              init_timervecs();              init_bh(IMMEDIATE_BH, immediate_bh);
189              init_bh(TQUEUE_BH, tqueue_bh);  
190              init_bh(IMMEDIATE_BH, immediate_bh);          \end{verbatim}
191                    \subsection{Function softirq\_init}
192          \end{verbatim}              The concept of tasklets, softirqs are introduced from kernel version 2.4 and the primary tasklet\_struct is defined in \url{include/linux/interrupt.h}. Don't forget to read the properties of tasklets in the include file.
193                  \subsection{Function softirq\_init}              \par Softirqs were introduced that take advantage of multiple processors in an SMP, and allow each CPU to run a softirq. Softirqs are thus, multithreaded analogue of Bottom Halves\index{bottom half} which can run on multiple CPUs at once. The deprecated bottom-halves are re-implemented using softirqs. Both bottom-halves and softirqs are statically registered. The 2.4 Linux kernel also introduce tasklets, which are dynamically registrable softirqs, which are guaranteed to only run on one CPU at a time. Refer section ~\ref{int:tasklets} for more information about \texttt{Tasklets}.
194              The concept of tasklets, softirqs are introduced from kernel version 2.4 and the primary tasklet\_struct is defined in \url{include/linux/interrupt.h}. Don't forget to read the properties of tasklets in the include file.  
195              \par Softirqs were introduced that take advantage of multiple processors in an SMP, and allow each CPU to run a softirq. Softirqs are thus, multithreaded analogue of Bottom Halves\index{bottom half} which can run on multiple CPUs at once. The deprecated bottom-halves are reimplemented using softirqs. Both bottom-halves and softirqs are statically registered. The 2.4 Linux kernel also introduce tasklets, which are dynamically registrable softirqs, which are guaranteed to only run on one CPU at a time. Refer section ~\ref{int:tasklets} for more information about \texttt{Tasklets}.                  \subsubsection{Function softirq\_init()}  \label{init:softirq_init}
196                    \textit{File: }\url{kernel/softirq.c}\\ \newline
197                  \subsubsection{Function softirq\_init()}  \label{init:softirq_init}                  The softirq\_init function initializes all the tasklets \index{tasklets} by calling \textit{tasklet\_init} function. A global array \textbf{struct tasklet\_struct bh\_task\_vec[32]} is used to initialize all the tasklets. These tasklets are associated with first 32 (0x00-0x1F) IRQ(software interrupt) lines. The function \textit{tasklet\_init} associates the function bh\_action as the IRQ handler for all IRQs from 0 to 31.
198                  \textit{File: }\url{kernel/softirq.c}\\ \newline              \par The function open\_softirq initializes the softirqs related to TASKLET\_SOFTIRQ and HI\_SOFTIRQ. The function pointers tasklet\_action and tasklet\_hi\_action are stored in an array related to softirq action (consists of function and data).
199                  The softirq\_init function initializes all the tasklets \index{tasklets} by calling \textit{tasklet\_init} function. A global array \textbf{struct tasklet\_struct bh\_task\_vec[32]} is used to initialize all the tasklets. These tasklets are associated with first 32 (0x00-0x1F) IRQ(software interrupt) lines. The function \textit{tasklet\_init} associates the function bh\_action as the IRQ handler for all IRQs from 0 to 31.  
200              \par The function open\_softirq initializes the softirqs related to TASKLET\_SOFTIRQ and HI\_SOFTIRQ. The function pointers tasklet\_action and tasklet\_hi\_action are stored in an array related to softirq action (consists of function and data).              \\ \par The code is explained below. \index{softirq\_vec}
201    
202              \newline \par The code is explained below. \index{softirq\_vec}          \begin{verbatim}
203                static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp;
204          \begin{verbatim}          \end{verbatim}
205              static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp;  
206          \end{verbatim}          \begin{verbatim}
207    
208          \begin{verbatim}              for (i=0; i<32; i++)
209                    tasklet_init(bh_task_vec+i, bh_action, i);
210              for (i=0; i<32; i++)  
211                  tasklet_init(bh_task_vec+i, bh_action, i);              open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
212                open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);
213              open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);  
214              open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);          \end{verbatim}
215    
216          \end{verbatim}                  \subsection{Function fork\_init}
217                    Function fork\_init() \label{init:fork_init} \index{max\_threads}
218                  \subsection{Function fork\_init}                  \textit{File: }\url{kernel/fork.c}\\ \newline
219                  Function fork\_init() \label{init:fork_init} \index{max\_threads}               The fork\_init function calls \textit{kmem\_cache\_create} \footnote{Refer to \url{mm/slab.c} for more details of slab and memory allocation} to initialize the slab cache related to task\_structs. It also determines the maximum number of threads depending upon the physical memory available. The name parameter passed  is \texttt{task\_struct} which can be found in the file \url{/proc/slabinfo}. The \textit{max\_threads} value is used to set the resource limits for the \textit{init\_task}.\footnote{The init\_task is defined in a special file containing only data \url{arch/i386/kernel/init_task.c} which calls the macro \textit{INIT\_TASK} \index{init\_task} defined in \url{include/linux/init_task.h}}
220                  \textit{File: }\url{kernel/fork.c}\\ \newline  
221               The fork\_init function calls \textit{kmem\_cache\_create} \footnote{Refer to \url{mm/slab.c} for more detailes of slab and memory allocation} to initialize the slab cache related to task\_structs. It also determines the maximum number of threads depending upon the physical memory available. The name parameter passed  is \texttt{task\_struct} which can be found in the file \url{/proc/slabinfo}. The \textit{max\_threads} value is used to set the resource limits for the \textit{init\_task}.\footnote{The init\_task is defined in a special file containing only data \url{arch/i386/kernel/init_task.c} which calls the macro \textit{INIT\_TASK} \index{init\_task} defined in \url{include/linux/init_task.h}}          \begin{verbatim}
222    
223          \begin{verbatim}              task_struct_cachep =
224                   kmem_cache_create("task_struct",
225              task_struct_cachep =                            sizeof(struct task_struct),0,
226                 kmem_cache_create("task_struct",                            SLAB_HWCACHE_ALIGN, NULL, NULL);
227                            sizeof(struct task_struct),0,              if (!task_struct_cachep)
228                            SLAB_HWCACHE_ALIGN, NULL, NULL);                     panic("fork_init(): cannot create task_struct SLAB cache");
229              if (!task_struct_cachep)  
230                     panic("fork_init(): cannot create task_struct SLAB cache");              max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 8;
231    
232              max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 8;              init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
233                init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
234              init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;  
235              init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2;          \end{verbatim}
236    
237          \end{verbatim}          \begin{verbatim}
238    
239          \begin{verbatim}              /* Please, Note
240                 * value for mempages is set in the function setup_arch()
241              /* Please, Note               * in arch/i386/kernel/setup.c
242               * value for mempages is set in the function setup_arch()               */
243               * in arch/i386/kernel/setup.c              #define THREAD_SIZE (2*PAGE_SIZE)      /* include/asm-i386/thread_info.h */
244               */              /* Effectively, max_threads = mempages / 2*8 ; */
245              #define THREAD_SIZE (2*PAGE_SIZE)      /* include/asm-i386/thread_info.h */  
246              /* Effectively, max_threads = mempages / 2*8 ; */          \end{verbatim}
247    
248          \end{verbatim}                  \subsection{Function signals\_init}
249                 The signals\_init also calls function \textit{kmem\_cache\_create} to initialize the slab cache related to signals and to create a signals related cache. The code can be found in \url{kernel/signal.c}. The name parameter passed is \texttt{sigqueue} which can be found in the file \url{/proc/slabinfo}.
250                  \subsection{Function signals\_init}  
251               The signals\_init also calls function \textit{kmem\_cache\_create} to initialize the slab cache related to signals and to create a signals related cache. The code can be found in \url{kernel/signal.c}. The name parameter passed is \texttt{sigqueue} which can be found in the file \url{/proc/slabinfo}.          \begin{verbatim}
252    
253          \begin{verbatim}          sigqueue_cachep =
254                kmem_cache_create("sigqueue",
255          sigqueue_cachep =                        sizeof(struct sigqueue),
256              kmem_cache_create("sigqueue",                        __alignof__(struct sigqueue),
257                        sizeof(struct sigqueue),                        SIG_SLAB_DEBUG, NULL, NULL);
258                        __alignof__(struct sigqueue),          if (!sigqueue_cachep)
259                        SIG_SLAB_DEBUG, NULL, NULL);                  panic("signals_init(): cannot create sigqueue SLAB cache");
260          if (!sigqueue_cachep)  
261                  panic("signals_init(): cannot create sigqueue SLAB cache");          \end{verbatim}
262    
263          \end{verbatim}                  \subsection{Function init\_idle} \label{init:idle} \index{init\_idle}
264                  \subsection{Function smp\_init}               The init\_idle function is called to create idle task on the processor. The idle task has highest priority and runs with the TASK\_RUNNING state. The function is called here, for the processor performing the boot setup. The function is also called for all the secondary processors when they are initialized in the \textit{do\_boot\_cpu} function, called by \textit{smp\_init}.
265               The smp\_init is architecture dependant function used to perform SMP initialization of all CPUs. The function code invokes functions smp\_boot\_cpus, do\_boot\_cpus from \url{arch/i386/kernel/smpboot.c}. These functions perform basic SMP related initialization. Refer to section \ref{smp:boot} for more details on SMP initialization and scheduling.          \begin{verbatim}
266            void __init init_idle(task_t *idle, int cpu)
267          \begin{verbatim}          {
268                runqueue_t *idle_rq = cpu_rq(cpu), *rq = cpu_rq(idle->thread_info->cpu);
269          /*   From init/main.c for SMP mode  */              unsigned long flags;
270    
271          static void __init smp_init(void)              __save_flags(flags);
272          {              __cli();
273              smp_boot_cpus();              double_rq_lock(idle_rq, rq);
274              smp_threads_ready=1;  
275              smp_commence();              idle_rq->curr = idle_rq->idle = idle;
276          }              deactivate_task(idle, rq);
277                idle->array = NULL;
278          \end{verbatim}              idle->prio = MAX_PRIO;
279                idle->state = TASK_RUNNING;
280          \par   After completing all the initialization stuff, what does the kernel do? Correct, it sits idle. The function \textit{cpu\_idle}\label{init:idle} is architecture dependant and is defined in \url{arch/i386/kernel/process.c}. The kernel waits for some process to get scheduled using \textit{schedule()} function.              idle->thread_info->cpu = cpu;
281          \begin{verbatim}              double_rq_unlock(idle_rq, rq);
282                set_tsk_need_resched(idle);
283              while(1) {              __restore_flags(flags);
284                  while (!need_resched())  
285                          idle();              /* Set the preempt count _outside_ the spinlocks! */
286                  schedule();              idle->thread_info->preempt_count = (idle->lock_depth >= 0);
287              }          }
288            \end{verbatim}
289          \end{verbatim}          The interupts are disbled when the idle task is initialized and reenabled when the task is running. The idle task has following properties:
290            \begin{enumerate}
291            \item The idle task is not part of the processor runqueue.
292            \item The talk is removed from the list of running tasks.
293            \item The priority is set to MAX\_PRIO.
294            \item \textit{goodness()} [priority function] should be never run on the idle\_task.
295            \item The task as RUNNING state.
296            \item idle task in NOT part of pid hashing table.
297            \end{enumerate}
298            
299                    \subsection{Function smp\_init}
300                 The smp\_init is architecture dependant function used to perform SMP initialization of all CPUs. The function code invokes functions smp\_boot\_cpus, do\_boot\_cpus from \url{arch/i386/kernel/smpboot.c}. These functions perform basic SMP related initialization. Refer to section \ref{smp:boot} for more details on SMP initialization and scheduling.
301    
302            \begin{verbatim}
303    
304            /*   From init/main.c for SMP mode  */
305    
306            static void __init smp_init(void)
307            {
308                smp_boot_cpus();
309                smp_threads_ready=1;
310                smp_commence();
311            }
312    
313            \end{verbatim}
314    
315            \par   After completing all the initialization stuff, what does the kernel do? Correct, it sits idle. The function \textit{cpu\_idle} ~\ref{init:idle} is architecture dependant and is defined in \url{arch/i386/kernel/process.c}. The kernel waits for some process to get scheduled using \textit{schedule()} function.
316            \begin{verbatim}
317    
318                while(1) {
319                    while (!need_resched())
320                            idle();
321                    schedule();
322                }
323    
324            \end{verbatim}
325    

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.3

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26