|
.text /////////////////////////////////////////////////////////////////////////////// startup_32() { cld; cli; DS = ES = FS = GS = __KERNEL_DS; SS:ESP = *stack_start; // user_stack[] sonu, misc.c içinde tanımlı // korumalı kip etkinleştirildikten sonra // tüm bölüt kaydedicileri yeniden yüklenir // A20'nin gerçekten etkin olup olmadığını kontrol et EAX = 0; do { 1: DS:[0] = ++EAX; } while (DS:[0x100000]==EAX); EFLAGS = 0; clear BSS; // _edata'dan _end'e struct moveparams mp; // subl $16,%esp if (!decompress_kernel(&mp, ESI)) { // AX'deki değeri döndür ESI'yi yığıttan geri yükle; EBX = 0; goto __KERNEL_CS:100000; // bkz. linux/arch/i386/kernel/head.S:startup_32 } /* * Yüksek yüklediysek buraya geliriz. * move-in-place rutinini aşağı 0x1000'e taşımamız gerekir * ve sonra yığıttan aldığımız yazmaçlardaki * tampon adresleri ile başlatırız. */ 3: move_rountine_start..move_routine_end 0x1000'e taşı; // move_routine_start & move_routine_end aşağıda tanımlanmıştır // move_routine_start() parametrelerini hazırla EBX = real mode pointer; // ESI değeri setup.S'den geçer ESI = mp.low_buffer_start; ECX = mp.lcount; EDX = mp.high_buffer_star; EAX = mp.hcount; EDI = 0x100000; cli; // kesme almadığımızdan emin ol. goto __KERNEL_CS:1000; // move_routine_start(); } /* Eğer yüksek yüklediysek, yerinde çözülmüş çekirdeği taşımak için * yordam (şablon). Bu PIC kodu olmalı! */ /////////////////////////////////////////////////////////////////////////////// move_routine_start() { mp.low_buffer_start'ı 0x100000'a taşı, mp.lcount bayt, iki adımda: (lcount >> 2) kelime + (lcount & 3) bayt; move/append mp.high_buffer_start, ((mp.hcount + 3) >> 2) kelime // 1 kelime == 4 bayt, 32 bitlik kod/veri anlamında. ESI = EBX; // gerçek kip gösterici, setup.S'deki gibi EBX = 0; goto __KERNEL_CS:100000; // bkz. linux/arch/i386/kernel/head.S:startup_32() move_routine_end: }
#define LOW_BUFFER_START 0x2000 #define LOW_BUFFER_MAX 0x90000 #define HEAP_SIZE 0x3000 /////////////////////////////////////////////////////////////////////////////// asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode) |-- setup real_mode(=rmode), vidmem, vidport, lines and cols; |-- if (is_zImage) setup_normal_output_buffer() { | output_data = 0x100000; | free_mem_end_ptr = real_mode; | } else (is_bzImage) setup_output_buffer_if_we_run_high(mv) { | output_data = LOW_BUFFER_START; | low_buffer_end = MIN(real_mode, LOW_BUFFER_MAX) & ~0xfff; | low_buffer_size = low_buffer_end - LOW_BUFFER_START; | free_mem_end_ptr = &end + HEAP_SIZE; | // get mv->low_buffer_start and mv->high_buffer_start | mv->low_buffer_start = LOW_BUFFER_START; | /* To make this program work, we must have | * high_buffer_start > &end+HEAP_SIZE; | * As we will move low_buffer from LOW_BUFFER_START to 0x100000 | * (max low_buffer_size bytes) finally, we should have | * high_buffer_start > 0x100000+low_buffer_size; */ | mv->high_buffer_start = high_buffer_start | = MAX(&end+HEAP_SIZE, 0x100000+low_buffer_size); | mv->hcount = 0 if (0x100000+low_buffer_size > &end+HEAP_SIZE); | = -1 if (0x100000+low_buffer_size <= &end+HEAP_SIZE); | /* mv->hcount==0 : we need not move high_buffer later, | * as it is already at 0x100000+low_buffer_size. | * Used by close_output_buffer_if_we_run_high() below. */ | } |-- makecrc(); // create crc_32_tab[] | puts("Uncompressing Linux... "); |-- gunzip(); | puts("Ok, booting the kernel.\n"); |-- if (is_bzImage) close_output_buffer_if_we_run_high(mv) { | // get mv->lcount and mv->hcount | if (bytes_out > low_buffer_size) { | mv->lcount = low_buffer_size; | if (mv->hcount) | mv->hcount = bytes_out - low_buffer_size; | } else { | mv->lcount = bytes_out; | mv->hcount = 0; | } | } `-- return is_bzImage; // return value in AX
#ifdef __cplusplus #define CPP_ASMLINKAGE extern "C" #else #define CPP_ASMLINKAGE #endif #if defined __i386__ #define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0))) #elif defined __ia64__ #define asmlinkage CPP_ASMLINKAGE __attribute__((syscall_linkage)) #else #define asmlinkage CPP_ASMLINKAGE #endif
Bileşen | Açılımı | Bayt sayısı | Yorumu |
---|---|---|---|
ID1 | IDentification 1 (1. belirteç) | 1 | 31 (0x1f, \037) |
ID2 | IDentification 2 (2. belirteç) | 1 | 139 (0x8b, \213)[a] |
CM | Compression Method (Sıkıştırm Yöntemi) | 1 | 8 - "deflate" sıkıştırma yöntemini gösterir |
FLG | FLaGs (Seçenekler) | 1 | çoğu durumda 0 |
MTIME | Modification TIME (Değişiklik zamanı) | 4 | özgün dosyanın değişiklik zamanı |
XFL | eXtra FLags (ek seçenekler) | 1 | 2 - sıkıştırıcı en yavaş algoritmayı[b] kullanır, azami sıkıştırma yapar |
OS | Operating System (İşletim Sistemi) | 1 | 3 - Unix |
ek alanlar | - | - | değişken uzunluk, alan FLG ile belirtilir[c] |
sıkıştırılmış bloklar | - | - | değişken uzunluk |
CRC32 | - | 4 | sıkıştırılmamış verinin CRC değeri |
ISIZE | Input SIZE (Girdi uzunluğu)) | 4 | sıkıştırılmamış girdi verisi boyunun 2^32 ile bölümünden kalan |
[a] ID2 değeri gzip 0.5 için 158 (0x9e, \236) olabilir; [b] XFL değeri 4 olduğunda ise sıkıştırıcı en hızlı algoritmayı kullanacaktır. [c] FLG biti 0 olduğunda FTEXT, herhangi bir ek alan belirtmez. |
[root@localhost boot]# hexdump -C /boot/vmlinuz-2.4.20-28.9 | grep '1f 8b 08 00' 00004c50 1f 8b 08 00 01 f6 e1 3f 02 03 ec 5d 7d 74 14 55 |.......?...]}t.U| [root@localhost boot]# hexdump -C /boot/vmlinuz-2.4.20-28.9 -s 0x4c40 -n 64 00004c40 00 80 0b 00 00 fc 21 00 68 00 00 00 1e 01 11 00 |......!.h.......| 00004c50 1f 8b 08 00 01 f6 e1 3f 02 03 ec 5d 7d 74 14 55 |.......?...]}t.U| 00004c60 96 7f d5 a9 d0 1d 4d ac 56 93 35 ac 01 3a 9c 6a |......M.V.5..:.j| 00004c70 4d 46 5c d3 7b f8 48 36 c9 6c 84 f0 25 88 20 9f |MF\.{.H6.l..%. .| 00004c80 [root@localhost boot]# hexdump -C /boot/vmlinuz-2.4.20-28.9 | tail -n 4 00114d40 bd 77 66 da ce 6f 3d d6 33 5c 14 a2 9f 7e fa e9 |.wf..o=.3\...~..| 00114d50 a7 9f 7e fa ff 57 3f 00 00 00 00 00 d8 bc ab ea |..~..W?.........| 00114d60 44 5d 76 d1 fd 03 33 58 c2 f0 00 51 27 00 |D]v...3X...Q'.| 00114d6e
static uch *inbuf; /* girdi tamponu */ static unsigned insize = 0; /* inbuf içindeki geçerli baytlar*/ static unsigned inptr = 0; /* inbuf içinde işlenecek sonraki baytın indisi */ /////////////////////////////////////////////////////////////////////////////// static int gunzip(void) { Girdi tamponunu {ID1, ID2, CM} için kontrol et, şöyle olmalı: {0x1f, 0x8b, 0x08} (normal durum), veya {0x1f, 0x9e, 0x08} (gzip 0.5 için); FLG'yi (seçenek baytı) kontrol et, 1, 5, 6 ve 7. bitler atanmamalı; Ignore {MTIME, XFL, OS}; FLG biti 2,3 ve 4'e karşılık gelen seçimlik yapıları yönet; inflate(); // sıkıştırılmış blokları yönet Validate {CRC32, ISIZE}; }
// misc.c içindeki bazı önemli tanımlamalar #define WSIZE 0x8000 /* Pencere boyutu en azından 32k olmalı, * ve ikinin üssü olmalı */ static uch window[WSIZE]; /* Kayan pencere tamponu */ static unsigned outcnt = 0; /* çıktı tamponundaki bayt sayısı */ // linux/lib/inflate.c #define wp outcnt #define flush_output(w) (wp=(w),flush_window()) STATIC unsigned long bb; /* bit tamponu */ STATIC unsigned bk; /* bit tamponundaki bit sayısı */ STATIC unsigned hufts; /* belleği kullanımı izlemek*/ static long free_mem_ptr = (long)&end; /////////////////////////////////////////////////////////////////////////////// STATIC int inflate() { int e; /* son blok seçeneği */ int r; /* sonuç kod */ unsigned h; /* struct huft'un azami belleği */ void *ptr; wp = bb = bk = 0; // sıkıştırılmış blokları birer birer şişir (inflate) do { hufts = 0; gzip_mark() { ptr = free_mem_ptr; }; if ((r = inflate_block(&e)) != 0) { gzip_release() { free_mem_ptr = ptr; }; return r; } gzip_release() { free_mem_ptr = ptr; }; if (hufts > h) h = hufts; } while (!e); /* Çok fazla ileri bakmayı (lookahead) geri al. Sonraki okuma bayt hizalı * olacak böylece son anlamlı bayttaki kullanılmayan bitleri çıkarabileceğiz. */ while (bk >= 8) { bk -= 8; inptr--; } /* çıktı penceresini (window[0..outcnt-1]) çıktı verisine (output_data) yaz, * output_ptr/output_data, crc ve bytes_out'u da buna bağlı olarak güncelle * ve outcnt'yi 0'a ayarla. */ flush_output(wp); /* başarılı olduğunu döndür */ return 0; }
BFINAL (1 bit) 0 - son blok değil 1 - son blok BTYPE (2 bit) 00 - sıkıştırma yok bayt sınırına kadar kalan bitler; LEN (2 bayt); NLEN (2 bayt, LEN'in tamamlayıcısı); data (LEN bayt); 01 - düzeltilmiş Huffman kodu ile sıkıştırılmış { literal (7-9 bitleri, 256 hariç 0..287 kodunu temsil eder); // Bakınız RFC 1951, 3.2.6 paragrafındaki tablo. length (0-5 bitleri, literal > 256 ise 3..258 arasında bir uzunluktur); // Bkz. RFC 1951, 3.2.5 paragrafındaki 1. alfabe tablosu. data (literal < 256 ise literal baytlarının verileri); distance (literal == 257..285 ise 5 artı 0-13 ek bit, 1..32768 arasında bir mesafe belirtir; /* Bakınız RFC 1951, 3.2.5 paragrafındaki 2. alfabe tablosu, * 3.2.6 paragrafındaki deyim değil*/ /* Çıktı akımında "distance" bayt geri git * ve "length" baytı kopyala. */ }* // çok sayıda örnek olabilir literal (7 bit, tümü 0, literal == 256, blok sonu belirtir); 10 - Dinamik Huffman koduyla sıkıştırılmış HLIT (5 bit, Literal/Length kodlarının sayısı - 257, 257-286); HDIST (5 bit, Distance kodlarının sayısı - 1, 1-32); HCLEN (4 bit, Code Length kodlarının sayısı - 4, 4 - 19); Code Length dizisi ((HCLEN+4)*3 bit) /* Aşağıdaki 2 alfabe tablosu, önceki Code Length dizisinden üretilen * Huffman kod çözme tablosu kullanılarık çözülecektir. */ Literal/Length alfabesi (HLIT+257 kod) Distance alfabesi (HDIST+1 kod) // Kod çözme tabloları bu alfabe tablolarından oluşturur. /* Aşağıdaki, farklı kod çözme tabloları kullanmak dışında düzeltilmiş * Huffman kodları kısmı ile benzerlik gösterir. */ { literal/length (değişken uzunluk, Literal/Length alfabesine bağımlı); data (literal < 256 ise literal baytlarının verisi); distance (literal == 257..285 ise değişken uzunlukta, Distance alfabesine bağımlı); }* // çok sayıda örnek olabilir literal (literal değeri 256, blok sonu anlamında); 11 - reserved (hata)
|