| ||||||
.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 */
| |||||||||