| |||||||
Bu bölümü yazarken kendimi suçlu hissettim çünkü yeterince olmasa bile hakkında çok sayıda belge var. start_kernel() destekli işlevler, sürekli gelişen işletim sistemi dahili bileşenlerine bağımlı olduğu için, sürümden sürüme değişir. Sık sık belge güncellemek için vaktim olmadığından bu bölümü olabildiğince basit tutmaya karar verdim.
/////////////////////////////////////////////////////////////////////////////// asmlinkage void __init start_kernel(void) { char * command_line; extern char saved_command_line[]; /* * Kesmeler hala etkin değil. Gerekli kurulumu yap, sonra etkinleştir */ lock_kernel(); printk(linux_banner); /* Linux'da bellek yönetimi, esp. for setup_arch() * Linux-2.4.4 MM Başlangıç durumuna getirme */ setup_arch(&command_line); printk("Kernel command line: %s\n", saved_command_line); /* linux/Documentation/kernel-parameters.txt * The Linux BootPrompt-HowTo */ 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); // kurulum kapıları 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! Bu erken. PCI ve bunun gibi kurulumları bitirdikten * ve console_init()'in bunu farketmesinde önce konsolu etkinleştirmeliyiz. * Birşeylerin kötü gitmesi durumunda bunun erkenden çıktı olmasını isteriz. */ 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(); // BogoMips mini-Howto calibrate_delay(); // linux/Documentation/initrd.txt #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(); /* * Yüksek belleğe (highmem) sahip olan mimariler için, num_mappedpages * çekirdeğin kullanabileceği bellek miktarını ifade eder. Diğer mimariler için * toplam sayfa ile aynıdır. Her iki rakama da ihtiyaç duyarız çünkü bazı * altsistemler çekirdeğin ne kadar bellek kullanabileceğine dayanarak * başlangıç durumuna getirilir. */ 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"); /* * İlk işlemdeki (thread) iyi gidenleri sayarız * atıl (idlers) gibi init de kilitsiz bir çekirdek işlemidir, * sistem çağrısı yapar (ve böylece kilitlenir). */ smp_init() { #ifndef CONFIG_SMP # ifdef CONFIG_X86_LOCAL_APIC APIC_init_uniprocessor(); # else do { } while (0); # endif #else /* Check smp_init(). */ #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 } } |
start_kernel() "init" işlemi oluşturmak için rest_init()'i çağırır ve kendisi "idle" işlem durumuna geçer.
"Init" süreci:
///////////////////////////////////////////////////////////////////////////////
static int init(void * unused)
{
lock_kernel();
do_basic_setup();
prepare_namespace();
/*
* Tamam, ilk önyüklemeyi (bootup) tamamladık, ayakta ve
* çalışır durumdayız. initmem bölütlerinden kurtul ve
* kullanıcı kipini başlat...
*/
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
/*
* Biri başarılı olana kadar her birini deneyeceğiz
* Gerçekten bozuk bir makinayı toparlamaya çalışıyorsak
* init yerine Bourne kabuğu kullanılabilir.
*/
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.");
}
|
Kullanıcı kipi "init" süreciyle ilgili bilgiler için man init veya SysVinit'e bakınız.
"Idle" süreç:
/*
* Boşta bekleme (idle) evresi. Yapılacak yararlı bir iş yok,
* bu yüzden sadece gücü korumaya çalış ve düşük çıkış gecikmesine
* sahip ol (örn. birinin yeniden iş yapma isteği
* belirtmesini bekleyen bir döngü içinde kal)
*/
void cpu_idle (void)
{
/* hiç bir önceliği olmayan sonsuz atıl döngü */
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();
}
}
/* linux/include/asm-i386/system.h içinde tanımlı */
#define __cli() __asm__ __volatile__("cli": : :"memory")
#define __sti() __asm__ __volatile__("sti": : :"memory")
/* atıl döngü içinde kullanıldı; sti'nin tamamlanması bir komut süresi alır */
#define safe_halt() __asm__ __volatile__("sti; hlt": : :"memory")
|
İşlemci bir kesme eylemcisinden dönen "hlt"yi takip eden komut ile kod çalıştırmaya devam edecektir.
| ||||||||||