554 lines
12 KiB
HTML
554 lines
12 KiB
HTML
<HTML
|
|
><HEAD
|
|
><TITLE
|
|
>linux/init/main.c</TITLE
|
|
><META
|
|
NAME="GENERATOR"
|
|
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
|
|
REL="HOME"
|
|
TITLE="Linux i386 Boot Code HOWTO"
|
|
HREF="index.html"><LINK
|
|
REL="PREVIOUS"
|
|
TITLE="linux/arch/i386/kernel/head.S"
|
|
HREF="kernel_head.html"><LINK
|
|
REL="NEXT"
|
|
TITLE="SMP Boot"
|
|
HREF="smpboot.html"></HEAD
|
|
><BODY
|
|
CLASS="sect1"
|
|
BGCOLOR="#FFFFFF"
|
|
TEXT="#000000"
|
|
LINK="#0000FF"
|
|
VLINK="#840084"
|
|
ALINK="#0000FF"
|
|
><DIV
|
|
CLASS="NAVHEADER"
|
|
><TABLE
|
|
SUMMARY="Header navigation table"
|
|
WIDTH="100%"
|
|
BORDER="0"
|
|
CELLPADDING="0"
|
|
CELLSPACING="0"
|
|
><TR
|
|
><TH
|
|
COLSPAN="3"
|
|
ALIGN="center"
|
|
>Linux i386 Boot Code HOWTO</TH
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="10%"
|
|
ALIGN="left"
|
|
VALIGN="bottom"
|
|
><A
|
|
HREF="kernel_head.html"
|
|
ACCESSKEY="P"
|
|
>Prev</A
|
|
></TD
|
|
><TD
|
|
WIDTH="80%"
|
|
ALIGN="center"
|
|
VALIGN="bottom"
|
|
></TD
|
|
><TD
|
|
WIDTH="10%"
|
|
ALIGN="right"
|
|
VALIGN="bottom"
|
|
><A
|
|
HREF="smpboot.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><HR
|
|
ALIGN="LEFT"
|
|
WIDTH="100%"></DIV
|
|
><DIV
|
|
CLASS="sect1"
|
|
><H1
|
|
CLASS="sect1"
|
|
><A
|
|
NAME="init_main"
|
|
></A
|
|
>7. linux/init/main.c</H1
|
|
><P
|
|
> I felt guilty writing this chapter as there are too many documents
|
|
about it, if not more than enough.
|
|
<EM
|
|
>start_kernel()</EM
|
|
> supporting functions
|
|
are changed from version to version, as they depend on
|
|
OS component internals, which are being improved all the time.
|
|
I may not have the time for frequent document updates,
|
|
so I decided to keep this chapter as simple as possible.
|
|
</P
|
|
><DIV
|
|
CLASS="sect2"
|
|
><H2
|
|
CLASS="sect2"
|
|
><A
|
|
NAME="start_kernel"
|
|
></A
|
|
>7.1. start_kernel()</H2
|
|
><P
|
|
> <TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="programlisting"
|
|
>///////////////////////////////////////////////////////////////////////////////
|
|
<A
|
|
HREF="http://kernelnewbies.org/faq/index.php3#asmlinkage"
|
|
TARGET="_top"
|
|
>asmlinkage</A
|
|
> void <A
|
|
HREF="http://www.tldp.org/LDP/lki/lki-1.html#ss1.8"
|
|
TARGET="_top"
|
|
>__init</A
|
|
> start_kernel(void)
|
|
{
|
|
char * command_line;
|
|
extern char saved_command_line[];
|
|
/*
|
|
* Interrupts are still disabled. Do necessary setups, then enable them
|
|
*/
|
|
lock_kernel();
|
|
printk(linux_banner);
|
|
|
|
/* <A
|
|
HREF="http://www.symonds.net/~abhi/files/mm/mm.html"
|
|
TARGET="_top"
|
|
>Memory Management in Linux</A
|
|
>, esp. for setup_arch()
|
|
* <A
|
|
HREF="http://linux-mm.org/docs/initialization.html"
|
|
TARGET="_top"
|
|
>Linux-2.4.4 MM Initialization</A
|
|
> */
|
|
setup_arch(&command_line);
|
|
printk("Kernel command line: %s\n", saved_command_line);
|
|
|
|
/* <TT
|
|
CLASS="filename"
|
|
>linux/Documentation/kernel-parameters.txt</TT
|
|
>
|
|
* <A
|
|
HREF="http://www.tldp.org/HOWTO/BootPrompt-HOWTO.html"
|
|
TARGET="_top"
|
|
>The Linux BootPrompt-HowTo</A
|
|
> */
|
|
parse_options(command_line);
|
|
|
|
trap_init() {
|
|
#ifdef CONFIG_EISA
|
|
if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24))
|
|
EISA_bus = 1;
|
|
#endif
|
|
#ifdef CONFIG_X86_LOCAL_APIC
|
|
init_apic_mappings();
|
|
#endif
|
|
set_xxxx_gate(x, &func); // setup gates
|
|
cpu_init();
|
|
}
|
|
init_IRQ();
|
|
sched_init();
|
|
softirq_init() {
|
|
for (int i=0; i<32: i++)
|
|
tasklet_init(bh_task_vec+i, bh_action, i);
|
|
open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
|
|
open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);
|
|
}
|
|
time_init();
|
|
|
|
/*
|
|
* 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();
|
|
#ifdef CONFIG_MODULES
|
|
init_modules();
|
|
#endif
|
|
if (prof_shift) {
|
|
unsigned int size;
|
|
/* only text is profiled */
|
|
prof_len = (unsigned long) &_etext - (unsigned long) &_stext;
|
|
prof_len >>= prof_shift;
|
|
size = prof_len * sizeof(unsigned int) + PAGE_SIZE-1;
|
|
prof_buffer = (unsigned int *) alloc_bootmem(size);
|
|
}
|
|
|
|
kmem_cache_init();
|
|
sti();
|
|
|
|
// <A
|
|
HREF="http://www.tldp.org/HOWTO/BogoMips.html"
|
|
TARGET="_top"
|
|
>BogoMips mini-Howto</A
|
|
>
|
|
calibrate_delay();
|
|
|
|
// <TT
|
|
CLASS="filename"
|
|
>linux/Documentation/initrd.txt</TT
|
|
>
|
|
#ifdef CONFIG_BLK_DEV_INITRD
|
|
if (initrd_start && !initrd_below_start_ok &&
|
|
initrd_start < min_low_pfn << PAGE_SHIFT) {
|
|
printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
|
|
"disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);
|
|
initrd_start = 0;
|
|
}
|
|
#endif
|
|
|
|
mem_init();
|
|
kmem_cache_sizes_init();
|
|
pgtable_cache_init();
|
|
|
|
/*
|
|
* For architectures that have highmem, num_mappedpages represents
|
|
* the amount of memory the kernel can use. For other architectures
|
|
* it's the same as the total pages. We need both numbers because
|
|
* some subsystems need to initialize based on how much memory the
|
|
* kernel can use.
|
|
*/
|
|
if (num_mappedpages == 0)
|
|
num_mappedpages = num_physpages;
|
|
|
|
fork_init(num_mempages);
|
|
proc_caches_init();
|
|
vfs_caches_init(num_physpages);
|
|
buffer_init(num_physpages);
|
|
page_cache_init(num_physpages);
|
|
#if defined(CONFIG_ARCH_S390)
|
|
ccwcache_init();
|
|
#endif
|
|
signals_init();
|
|
#ifdef CONFIG_PROC_FS
|
|
proc_root_init();
|
|
#endif
|
|
#if defined(CONFIG_SYSVIPC)
|
|
ipc_init();
|
|
#endif
|
|
check_bugs();
|
|
printk("POSIX conformance testing by UNIFIX\n");
|
|
|
|
/*
|
|
* We count on the initial thread going ok
|
|
* Like idlers init is an unlocked kernel thread, which will
|
|
* make syscalls (and thus be locked).
|
|
*/
|
|
smp_init() {
|
|
#ifndef CONFIG_SMP
|
|
# ifdef CONFIG_X86_LOCAL_APIC
|
|
APIC_init_uniprocessor();
|
|
# else
|
|
do { } while (0);
|
|
# endif
|
|
#else
|
|
/* Check <A
|
|
HREF="smpboot.html#smp_init"
|
|
>Section 8.2</A
|
|
>. */
|
|
#endif
|
|
}
|
|
|
|
rest_init() {
|
|
// init process, pid = 1
|
|
kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
|
|
unlock_kernel();
|
|
current->need_resched = 1;
|
|
// idle process, pid = 0
|
|
cpu_idle(); // never return
|
|
}
|
|
}</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
>
|
|
<EM
|
|
>start_kernel()</EM
|
|
> calls <EM
|
|
>rest_init()</EM
|
|
>
|
|
to spawn an "init" process and become "idle" process itself.
|
|
</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="sect2"
|
|
><H2
|
|
CLASS="sect2"
|
|
><A
|
|
NAME="init_proc"
|
|
></A
|
|
>7.2. init()</H2
|
|
><P
|
|
> "Init" process:
|
|
<TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="programlisting"
|
|
>///////////////////////////////////////////////////////////////////////////////
|
|
static int init(void * unused)
|
|
{
|
|
lock_kernel();
|
|
do_basic_setup();
|
|
|
|
prepare_namespace();
|
|
|
|
/*
|
|
* Ok, we have completed the initial bootup, and
|
|
* we're essentially up and running. Get rid of the
|
|
* initmem segments and start the user-mode stuff..
|
|
*/
|
|
free_initmem();
|
|
unlock_kernel();
|
|
|
|
if (open("/dev/console", O_RDWR, 0) < 0) // stdin
|
|
printk("Warning: unable to open an initial console.\n");
|
|
|
|
(void) dup(0); // stdout
|
|
(void) dup(0); // stderr
|
|
|
|
/*
|
|
* We try each of these until one succeeds.
|
|
*
|
|
* The Bourne shell can be used instead of init if we are
|
|
* trying to recover a really broken machine.
|
|
*/
|
|
|
|
if (execute_command)
|
|
execve(execute_command,argv_init,envp_init);
|
|
execve("/sbin/init",argv_init,envp_init);
|
|
execve("/etc/init",argv_init,envp_init);
|
|
execve("/bin/init",argv_init,envp_init);
|
|
execve("/bin/sh",argv_init,envp_init);
|
|
panic("No init found. Try passing init= option to kernel.");
|
|
}</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
>
|
|
Refer to "<B
|
|
CLASS="command"
|
|
>man init</B
|
|
>" or
|
|
<A
|
|
HREF="http://freshmeat.net/projects/sysvinit"
|
|
TARGET="_top"
|
|
>SysVinit</A
|
|
>
|
|
for further information on user-mode "init" process.
|
|
</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="sect2"
|
|
><H2
|
|
CLASS="sect2"
|
|
><A
|
|
NAME="idle_proc"
|
|
></A
|
|
>7.3. cpu_idle()</H2
|
|
><P
|
|
> "Idle" process:
|
|
<TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="programlisting"
|
|
>/*
|
|
* The idle thread. There's no useful work to be
|
|
* done, so just try to conserve power and have a
|
|
* low exit latency (ie sit in a loop waiting for
|
|
* somebody to say that they'd like to reschedule)
|
|
*/
|
|
void cpu_idle (void)
|
|
{
|
|
/* endless idle loop with no priority at all */
|
|
init_idle();
|
|
current->nice = 20;
|
|
current->counter = -100;
|
|
|
|
while (1) {
|
|
void (*idle)(void) = pm_idle;
|
|
if (!idle)
|
|
idle = default_idle;
|
|
while (!current->need_resched)
|
|
idle();
|
|
schedule();
|
|
check_pgt_cache();
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void __init init_idle(void)
|
|
{
|
|
struct schedule_data * sched_data;
|
|
sched_data = &aligned_data[smp_processor_id()].schedule_data;
|
|
|
|
if (current != &init_task && task_on_runqueue(current)) {
|
|
printk("UGH! (%d:%d) was on the runqueue, removing.\n",
|
|
smp_processor_id(), current->pid);
|
|
del_from_runqueue(current);
|
|
}
|
|
sched_data->curr = current;
|
|
sched_data->last_schedule = get_cycles();
|
|
clear_bit(current->processor, &wait_init_idle);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void default_idle(void)
|
|
{
|
|
if (current_cpu_data.hlt_works_ok && !hlt_counter) {
|
|
__cli();
|
|
if (!current->need_resched)
|
|
safe_halt();
|
|
else
|
|
__sti();
|
|
}
|
|
}
|
|
|
|
/* defined in linux/include/asm-i386/system.h */
|
|
#define __cli() __asm__ __volatile__("cli": : :"memory")
|
|
#define __sti() __asm__ __volatile__("sti": : :"memory")
|
|
|
|
/* used in the idle loop; sti takes one instruction cycle to complete */
|
|
#define safe_halt() __asm__ __volatile__("sti; hlt": : :"memory")</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
>
|
|
CPU will resume code execution with the instruction following "hlt"
|
|
on the return from an interrupt handler.
|
|
</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="sect2"
|
|
><H2
|
|
CLASS="sect2"
|
|
><A
|
|
NAME="main_ref"
|
|
></A
|
|
>7.4. Reference</H2
|
|
><P
|
|
> <P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><A
|
|
HREF="http://www.tldp.org/LDP/lki/index.html"
|
|
TARGET="_top"
|
|
> Linux Kernel 2.4 Internals</A
|
|
></P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
HREF="http://kernelnewbies.org/documents/"
|
|
TARGET="_top"
|
|
> Kerneldoc</A
|
|
></P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
HREF="http://www.tldp.org/HOWTO/HOWTO-INDEX/index.html"
|
|
TARGET="_top"
|
|
> LDP HOWTO-INDEX</A
|
|
></P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
HREF="http://www.xml.com/ldd/chapter/book"
|
|
TARGET="_top"
|
|
> Linux Device Drivers, 2nd Edition</A
|
|
></P
|
|
></LI
|
|
></UL
|
|
>
|
|
</P
|
|
></DIV
|
|
></DIV
|
|
><DIV
|
|
CLASS="NAVFOOTER"
|
|
><HR
|
|
ALIGN="LEFT"
|
|
WIDTH="100%"><TABLE
|
|
SUMMARY="Footer navigation table"
|
|
WIDTH="100%"
|
|
BORDER="0"
|
|
CELLPADDING="0"
|
|
CELLSPACING="0"
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="kernel_head.html"
|
|
ACCESSKEY="P"
|
|
>Prev</A
|
|
></TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="index.html"
|
|
ACCESSKEY="H"
|
|
>Home</A
|
|
></TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="smpboot.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
>linux/arch/i386/kernel/head.S</TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
> </TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
>SMP Boot</TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></BODY
|
|
></HTML
|
|
> |