|
.text /////////////////////////////////////////////////////////////////////////////// startup_32() { /* bölütleri bilinen değerlere ata */ cld; DS = ES = FS = GS = __KERNEL_DS; #ifdef CONFIG_SMP #define cr4_bits mmu_cr4_features-__PAGE_OFFSET /* long mmu_cr4_features linux/arch/i386/kernel/setup.c içinde tanımlı * __PAGE_OFFSET = 0xC0000000, örn. 3G */ // CR4 desteği ile ApP (> Intel 486) CR'ü BSP'den kopyalayacak if (BX && cr4_bits) { // sayfalama seçeneklerini aç (turn on) (PSE, PAE, ...) CR4 |= cr4_bits; } else #endif { /* sayfa tablolarını (pg0..empty_zero_page-1) sadece BSP ilklendirir * .org 0x2000'de pg0 * .org 0x4000'de empty_zero_page * toplam (0x4000-0x2000)/4 = 0x0800 girdi */ pg0 = { 0x00000007, // 7 = PRESENT + RW + USER 0x00001007, // 0x1000 = 4096 = 4K 0x00002007, ... pg1: 0x00400007, ... 0x007FF007 // toplam 8M empty_zero_page: }; }
. = 0xC0000000 + 0x100000; _text = .; /* Metin ve salt-okunur veri */ .text : { *(.text) ...
[root@localhost boot]# nm --defined /boot/vmlinux-2.4.20-28.9 | \ grep 'startup_32\|mmu_cr4_features\|pg0\|\<empty_zero_page\>' | sort c0100000 t startup_32 c0102000 T pg0 c0104000 T empty_zero_page c0376404 B mmu_cr4_features
// sayfa dizini temel göstericisini ata, fiziksel adres CR3 = swapper_pg_dir - __PAGE_OFFSET; // sayfalama etkin! CR0 |= 0x80000000; // PG bitini ayarla goto 1f; // flush prefetch-queue 1: EAX = &1f; // sonraki komutu takip eden adres goto *(EAX); // EIP'yi yeniden konumla 1: SS:ESP = *stack_start;
#define OLD_CL_MAGIC_ADDR 0x90020 #define OLD_CL_MAGIC 0xA33F #define OLD_CL_BASE_ADDR 0x90000 #define OLD_CL_OFFSET 0x90022 #define NEW_CL_POINTER 0x228 /* Gerçek kip veriye göreli */ #ifdef CONFIG_SMP if (BX) { EFLAGS = 0; // AP EFLAGS'leri temizler } else #endif { // İlk CPU BSS'yi temizler clear BSS; // örn. __bss_start .. _end setup_idt() { /* idt_table[256]; arch/i386/kernel/traps.c içinde tanımlı * .data.idt bölümüne yerleştirilmiş EAX = __KERNEL_CS << 16 + ignore_int; DX = 0x8E00; // kesme kapısı, dpl = 0, mevcut idt_table[0..255] = {EAX, EDX}; } EFLAGS = 0; /* * Önyükleme parametrelerini yolun dışına kopyala (ayak altından al). * _empty_zero_page'in ilk 2kB'lık bölümü önyükleme parametreleri için, * ikinci 2kB'lık bölümü komut satırı içindir. */ taşı *ESI (gerçek kip başlık)'dan empty_zero_page'e, 2KB; temizle empty_zero_page+2K, 2KB; ESI = empty_zero_page[NEW_CL_POINTER]; if (!ESI) { // 32 bitlik komut satırı göstericisi if (OLD_CL_MAGIC==(uint16)[OLD_CL_MAGIC_ADDR]) { ESI = [OLD_CL_BASE_ADDR] + (uint16)[OLD_CL_OFFSET]; taşı *ESI'dan empty_zero_page+2K'ya, 2KB; } } else { // 2.02+'da geçerli taşı *ESI'dan empty_zero_page'e, 2KB; } } }
struct cpuinfo_x86; // bakınız: include/asm-i386/processor.h struct cpuinfo_x86 boot_cpu_data; // bakınız: arch/i386/kernel/setup.c #define CPU_PARAMS SYMBOL_NAME(boot_cpu_data) #define X86 CPU_PARAMS+0 #define X86_VENDOR CPU_PARAMS+1 #define X86_MODEL CPU_PARAMS+2 #define X86_MASK CPU_PARAMS+3 #define X86_HARD_MATH CPU_PARAMS+6 #define X86_CPUID CPU_PARAMS+8 #define X86_CAPABILITY CPU_PARAMS+12 #define X86_VENDOR_ID CPU_PARAMS+28 checkCPUtype: { X86_CPUID = -1; // CPUID yok X86 = 3; // en azından 386 save original EFLAGS to ECX; flip AC bit (0x40000) in EFLAGS; if (AC bit not changed) goto is386; X86 = 4; // en azından 486 flip ID bit (0X200000) in EFLAGS; restore original EFLAGS; // AC ve ID seçenekleri için if (ID bit değişemez) goto is486; // işlemci bilgilerini al CPUID(EAX=0); X86_CPUID = EAX; X86_VENDOR_ID = {EBX, EDX, ECX}; if (!EAX) goto is486; CPUID(EAX=1); CL = AL; X86 = AH & 0x0f; // aile X86_MODEL = (AL & 0xf0) >> 4; // model X86_MASK = CL & 0x0f; // adımlama kimliği (stepping id) X86_CAPABILITY = EDX; // özellik
is486: // PG, PE, ET'yi kaydet AM, WP, NE, MP'yi ise ayarla EAX = (CR0 & 0x80000011) | 0x50022; goto 2f; // "is386:" işlemeyi atla is386: orjinal EFLAGS'ları ECX'den yeniden al; // PG, PE, ET'yi kaydet MP'yi ayarla EAX = (CR0 & 0x80000011) | 0x02; /* ET: Eklenti Türü (Extension Type) (CR0'ın 4 biti). * Intel 386 ve Intel 486 işlemcilerde bu seçenek atandığı (set) zaman * Intel 387 DX aritmetik işlemcisi komutlarının desteklendiğini gösterir. * Pentium 4, Intel Xeon ve P6 ailesi işlemcilerde ise * bu seçenek sabit 1 olur. * -- IA-32 Manual Vol.3. Ch.2.5. Control Registers (p.2-14) */ 2: CR0 = EAX; check_x87() { /* Doğru olması için ET'ye bağımlıyız. * Bu 287/387 için sınar. */ X86_HARD_MATH = 0; clts; // CR0.TS = 0; fninit; // Init FPU; fstsw AX; // AX = ST(0); if (AL) { CR0 ^= 0x04; // yardımcı işlemci (coprocessor) yok, EM'i ata } else { ALIGN 1: X86_HARD_MATH = 1; /* IA-32 Manual Vol.3. Ch.18.14.7.14. FSETPM komutu * 287 işlemcisinin korumalı kipte olduğunu söyler * 387 tarafından dikkate alınmaz*/ fsetpm; } } }
ready: .byte 0; // global değişken { ready++; // kaç işlemci hazır lgdt gdt_descr; // yeni betimleme tablosunu güvenli yerde kullan lidt idt_descr; goto __KERNEL_CS:$1f; // "lgdt"den sonra bölüt yazmaçlarını yeniden yükle 1: DS = ES = FS = GS = __KERNEL_DS; #ifdef CONFIG_SMP SS = __KERNEL_DS; // sadece bölütü yeniden yükle #else SS:ESP = *stack_start; /* init_task_union'ın sonu, * linux/arch/i386/kernel/init_task.c'de tanımlı */ #endif EAX = 0; lldt AX; cld; #ifdef CONFIG_SMP if (1!=ready) { // ilk işlemci değil initialize_secondary(); // bakınız: linux/arch/i386/kernel/smpboot.c } else #endif { start_kernel(); // bakınız: linux/init/main.c } L6: goto L6; }
ENTRY(stack_start) .long init_task_union+8192; .long __KERNEL_DS; #ifndef INIT_TASK_SIZE # define INIT_TASK_SIZE 2048*sizeof(long) #endif union task_union { struct task_struct task; unsigned long stack[INIT_TASK_SIZE/sizeof(long)]; }; /* INIT_TASK ilk görev tablosunu kurmak için kullanıldı, * riski göze alarak kullanın! Base=0, limit=0x1fffff (=2MB) */ union task_union init_task_union __attribute__((__section__(".data.init_task"))) = { INIT_TASK(init_task_union.task) };
/////////////////////////////////////////////////////////////////////////////// // öntanımlı kesme yöneticisi ("handler") ignore_int() { printk("Unknown interrupt\n"); iret; } /* * Kesme belirtici tablosu 256 idt için odaya (room) sahiptir, * global belirtici tablosu sahip olabileceğimiz * görev sayısına bağımlıdır... */ #define IDT_ENTRIES 256 #define GDT_ENTRIES (__TSS(NR_CPUS)) .globl SYMBOL_NAME(idt) .globl SYMBOL_NAME(gdt) ALIGN .word 0 idt_descr: .word IDT_ENTRIES*8-1 # idt 256 girdi içerir SYMBOL_NAME(idt): .long SYMBOL_NAME(idt_table) .word 0 gdt_descr: .word GDT_ENTRIES*8-1 SYMBOL_NAME(gdt): .long SYMBOL_NAME(gdt_table) /* * Bu, 0-8M'de (önyükleme amaçları için) bir kimlik eşleşmesi ve * PAGE_OFFSET sanal adresinde başka bir 0-8M eşleşmesi oluşturmak * üzere ilklendirilir. */ .org 0x1000 ENTRY(swapper_pg_dir) // "ENTRY" linux/include/linux/linkage.h'da tanımlı .long 0x00102007 .long 0x00103007 .fill BOOT_USER_PGD_PTRS-2,4,0 /* öntanımlı: 766 girdi */ .long 0x00102007 .long 0x00103007 /* öntanımlı: 254 girdi */ .fill BOOT_KERNEL_PGD_PTRS-2,4,0 /* * Sayfa tablolarının burada sadece 8MB'ı ilklendirilir * - sonuncu sayfa tabloları bellek boyutuna bağlı * olarak daha sonra ayarlanır. */ .org 0x2000 ENTRY(pg0) .org 0x3000 ENTRY(pg1) /* * empty_zero_page hemen sayfa tablosunu takip etmelidir ! * (İlklendirme döngüsü empty_zero_page'e kadar sayar) */ .org 0x4000 ENTRY(empty_zero_page) /* * normal "text" bölütünün gerçek başlangıcı */ .org 0x5000 ENTRY(stext) ENTRY(_stext) /////////////////////////////////////////////////////////////////////////////// /* * Bu veri bölümünü başlatır. Dikkat ederseniz yukarıda tümü * text bölümündedir çünkü bu bizim başka bir şekilde * gideremeyeceğimiz hizalama gereksinimidir. */ .data ALIGN /* * Tipik olarak 140 "quadwords" içerir; NR_CPUS'a bağlı olarak. * * DİKKAT! Herhangi bir şeyi değiştirirseniz, bunun head.S'deki * gdt belirticisiyle eşleştiğinden emin olun. */ ENTRY(gdt_table) .quad 0x0000000000000000 /* NULL belirtici */ .quad 0x0000000000000000 /* kullanılmadı */ .quad 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 */ .quad 0x00cf92000000ffff /* 0x18 kernel 4GB data at 0x00000000 */ .quad 0x00cffa000000ffff /* 0x23 user 4GB code at 0x00000000 */ .quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 */ .quad 0x0000000000000000 /* kullanılmadı */ .quad 0x0000000000000000 /* kullanılmadı */ /* * APM bölütleri bayt taneciklilik özelliğine sahiptir ve * tabanları ile sınırları çalışma zamanında atanır. */ .quad 0x0040920000000000 /* 0x40 kötü BIOS'lar için APM ataması */ .quad 0x00409a0000000000 /* 0x48 APM CS kod */ .quad 0x00009a0000000000 /* 0x50 APM CS 16 kod (16 bit) */ .quad 0x0040920000000000 /* 0x58 APM DS veri */ .fill NR_CPUS*4,8,0 /* TSS'ler ve LDT'ler için boşluk */
|