| ||||||
.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)
| |||||||||