- 论坛徽章:
- 0
|
看到好文章为什么不能跟大家分享呢?
下面是我整理过的出自http://www.linuxforum.net/的好文章。
原文作者:feiyunw 和 raoxianhong
---------------------------------------------------------------------------
读代码前先看看 raoxianhong 的中文版setup.txt :
---------------------------------------------------------------------------
1、按规定得有个头,所以一开始是惯用的JMP;
2、头里边内容很丰富,具体用法走着瞧;
3、自我检测,不知道有什么用,防伪造?防篡改?
4、如果装载程序不对,只好死掉!以下终于走入正题;
5、获取内存容量(使用了三种办法,其中的E820和E801看不明白,int 15倒是老朋友了--应该是上个世纪80年代末认识的了,真佩服十年过去了,情意依旧,不过遇上一些不守规矩的BIOS,不知道还行不行);
6、将键盘重复键的重复率设为最大,灵敏一点?
7、检测硬盘,不懂,放这里干什么?
8、检测MCA总线(不要问我这是什么);
9、检测PS/2鼠标,用int 11,只是不知道为何放这里;
10、检测电源管理BIOS;唉,书到用时方恨少,不懂的太多了,真不好意思;不过也没有关系, 不懂的就别去动它就行了;以下要进入内核了;
11、 在进入保护模式之前,可以调用一个你提供的试模式下的过程,让你最后在看她一眼,当然你要是不提供,那就有个默认的,无非是塞住耳朵闭上眼睛禁止任何中断,包括著名的NMI ;
12、设置保护模式起动后的例程地址, 你可以写自己的例程,但不是代替而是把它加在setup提供的例程的前面(显示一个小鸭子?);
13、如果内核是zImage, 将它移动到0x10000处;
14、如果自己不在0x90000处,则移动到0x90000处;
15、建立idt, gdt表;
16、启动A20;
17、屏住呼吸,屏闭所有中断;
18、启动!movw $1, %ax ; lmsw %ax; 好已经进入保护模式下,马上进行局部调整;
19、jmpi 0x100000, __KERNEL_CS,终于进入内核;
---------------------------------------------------------------------------
下面是 feiyunw 的代码分析:
---------------------------------------------------------------------------
- ////////////////////////////////////////////////////////////////////
- // setup.txt
- // Copyright(C) 2001, Feiyun Wang
- ////////////////////////////////////////////////////////////////////
- // analysis on linux/arch/i386/boot/setup.S (for Linux 2.2.17)
- ////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////
- // export the margin tags for .text, .data and .bss
- {
- .text
- begtext:
- .data
- begdata:
- .bss
- begbss:
- }
- ////////////////////////////////////////////////////////////////////
- .text
- start()
- SYSSEG = 0x1000
- SETUPSEG = 0x9020
- modelist = end of .text:
- {
- // if loaded by bootsect.S,
- // you can assume CS=SETUPSEG (=0x9020), otherwise...
- goto start_of_setup();
- /*
- http://lxr.linux.no/source/Documentation/i386/boot.txt
- Offset/Size Proto Name Meaning
- 01F1/1 ALL setup_sects The size of the setup in sectors
- 01F2/2 ALL root_flags If set, the root is mounted readonly
- 01F4/2 ALL syssize DO NOT USE - for bootsect.S use only
- 01F6/2 ALL swap_dev DO NOT USE - obsolete
- 01F8/2 ALL ram_size DO NOT USE - for bootsect.S use only
- 01FA/2 ALL vid_mode Video mode control
- 01FC/2 ALL root_dev Default root device number
- 01FE/2 ALL boot_flag 0xAA55 magic number
- 0200/2 2.00+ jump Jump instruction
- 0202/4 2.00+ header Magic signature "HdrS"
- 0206/2 2.00+ version Boot protocol version supported
- 0208/4 2.00+ realmode_swtch Boot loader hook
- 020C/4 2.00+ start_sys_seg Points to kernel version string
- 0210/1 2.00+ type_of_loader Boot loader identifier
- 0211/1 2.00+ loadflags Boot protocol option flags
- 0212/2 2.00+ setup_move_size Move to high memory size (used with hooks)
- 0214/4 2.00+ code32_start Boot loader hook
- 0218/4 2.00+ ramdisk_image initrd load address (set by boot loader)
- 021C/4 2.00+ ramdisk_size initrd size (set by boot loader)
- 0220/4 2.00+ bootsect_kludge DO NOT USE - for bootsect.S use only
- 0224/4 2.01+ heap_end_ptr Free memory after setup end
- 0226/2 N/A pad1 Unused
- 0228/4 2.02+ cmd_line_ptr 32-bit pointer to the kernel command line
- */
- .ascii "HdrS"
- .word 0x0201
- realmode_swtch: // boot loader hook
- .word 0, 0
- start_sys_seg: // pointer to kernel version string
- .word SYSSEG
- .word kernel_version
- type_of_loader:
- .byte 0
- loadflags:
- #ifndef __BIG_KERNEL__
- .byte 0x00
- #else
- .byte LOADED_HIGH = 1
- #endif
- setup_move_size:
- .word 0x8000
- code32_start: // boot loader hook
- #ifndef __BIG_KERNEL__
- .long 0x1000
- #else
- .long 0x100000
- #endif
- ramdisk_image: // initrd load address (set by boot loader)
- .long 0
- ramdisk_size: // initrd size (set by boot loader)
- .long 0
- bootsect_kludge: // DO NOT USE - for bootsect.S use only
- .word bootsect_helper(), SETUPSEG
- heap_end_ptr: // free memory after setup end
- .word modelist+1024
- }
- ////////////////////////////////////////////////////////////////////
- // check signature to see if all code loaded
- start_of_setup()
- {
- // get disk type, bootlin depends on this
- // http://www.ctyme.com/intr/rb-0639.htm
- int13h/AH=15h(AL=0, DL=0x81);
- #ifdef SAFE_RESET_DISK_CONTROLLER
- int13h/AH=0(AL=0, DL=0x80); // reset hd0
- #endif
- // check signature at the end of setup code
- if (setup_sig1!=SIG1 || setup_sig2!=SIG2) {
- // since size of setup may >; 4 sectors,
- // the rest code may be loaded at SYSSEG
- goto bad_sig;
- }
- goto goodsig1;
- }
- ////////////////////////////////////////////////////////////////////
- // some small functions
- prtstr() { /* ... print ASCIIz string at DS:SI */}
- prtsp2() { /* ... print double space */ }
- prtspc() { /* ... print single space */ }
- prtchr() { /* ... print ASCII AL */ }
- beep() { /* ... beep */ }
- ////////////////////////////////////////////////////////////////////
- goodsig1() { goto goodsig; } // making near jumps
- ////////////////////////////////////////////////////////////////////
- // move rest setup code from SYSSEG:0 to CS:0800
- // TODO: it won't work if image loaded at 0x100000?
- bad_sig()
- DELTA_INITSEG = 0x0020 (= SETUPSEG - INITSEG)
- SYSSEG = 0x1000
- {
- BX = (CS-DELTA_INITSEG):[497]; // i.e. setup_sects
- // first 4 sectors have been loaded
- CX = (BX - 4) << 8; // rest code in words
- start_sys_seg = (CX >;>; 3) + SYSSEG; // real system code start
- move SYSSEG:0 to CS:0800 (CX*2 bytes);
- if (setup_sig1!=SIG1 || setup_sig2!=SIG2) {
- prtstr("No setup signature found ...");
- halt;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // check if loader compatible with image
- good_sig()
- LOADHIGH = 1
- {
- if ((loadflags & LOADHIGH) && (!type_of_loader)) {
- // Nope, old loader want to load big kernel
- prtstr("Wrong loader: giving up.");
- halt;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // get memory size
- // set the keyboard repeat rate to max
- // check video adapter
- // get hd0 & hd1 data
- // check for Micro Channel (MCA) bus
- // check for PS/2 pointing device
- // check for APM BIOS
- // move code to INITSEG/SETUPSEG
- // load IDT and GDT
- // enable and test A20
- // reset coprocessor
- // reprogram the interrupts
- // switch to protected mode
- // goto KERNEL
- loader_ok()
- SETUPSET = 0x9020
- INITSEG = 0x9000
- DELTA_INITSEG = 0x20
- {
- // DS = CS - DELTA_INITSEG when entering this function
- // get memory size
- #ifndef STANDARD_MEMORY_BIOS_CALL
- (double word)DS:[0x1E0] = 0;
- try {
- // get memory size for >;64M configurations
- // http://www.ctyme.com/intr/rb-1739.htm
- int15h/AX=E801h;
- // AX = extended memory between 1M and 16M, in KB
- // BX = extended memory above 16M, in 64K blocks
- (double word)DS:[0x1E0] = ((EBX & 0xFFFF) << 6)
- + (EAX & 0xFFFF);
- }
- #else
- (double word)DS:[0x1E0] = 0;
- #endif
- // get extended memory size
- // http://www.ctyme.com/intr/rb-1529.htm
- int15h/AH=88h;
- DS:[2] = AX; // KB of contiguous memory from 100000h
- // set the keyboard repeat rate to max
- // http://www.ctyme.com/intr/rb-1757.htm
- int16h/AX=0305h(BX=0);
- // check video adapter and its parameters, see video.S
- video();
- // get hd0 & hd1 data
- // http://www.ctyme.com/intr/rb-6135.htm
- // http://www.ctyme.com/intr/rb-6184.htm
- // pointers in 0:0104 & 0:0118 respectively
- move hd0 data to CS-DELTA_INITSEG:0080 (16 bytes);
- move hd1 data to CS-DELTA_INITSEG:0090 (16 bytes);
- // get disk type, check if hd1 exists
- // http://www.ctyme.com/intr/rb-0639.htm
- int13h/AH=15h(AL=0, DL=0x81);
- if (failed || AH!=03h) { // AH=03h if is a hard disk
- clear CS-DELTA_INITSEG:0090 (16 bytes);
- }
- // check for Micro Channel (MCA) bus
- DS:[0xA0] = 0; // set table length to 0
- try {
- // get system configuration
- // http://www.ctyme.com/intr/rb-1594.htm
- int15h/AH=C0h; // ES:BX = ROM configuration table
- move ROM configuration table to CS-DELTA_INITSEG:00A0;
- // first 16 bytes only
- }
- // check PS/2 pointing device
- DS:[0x1FF] = 0;
- // get equipment list
- // http://www.ctyme.com/intr/rb-0575.htm
- int11h();
- if (has psmouse) {
- DS:[0x1FF] = 0xAA;
- }
- #ifdef CONFIG_APM
- // check for APM BIOS
- DS:[0x40] = 0;
- // Advanced Power Management v1.0+ - installation check
- // http://www.ctyme.com/intr/rb-1394.htm
- int15h/AX=5300h(BX=0);
- // check both CF and BX for APM support
- if (APM && 32-bit protected mode interface supported) {
- int15h/AX=5304h(BX=0); // disconnect interface
- try {
- // clear return values first
- clear EBX, CX, DX, ESI, DI;
- // connect 32bit protect mode APM interface
- // http://www.ctyme.com/intr/rb-1397.htm
- int15h/AX=5303h(BX=0);
- if (supported) {
- DS:[0x42] = 32-bit code segment base address;
- DS:[0x44] = offset of entry point;
- DS:[0x48] = 16-bit code segment base address;
- DS:[0x4A] = 16-bit data segment base address;
- DS:[0x4E] = APM BIOS code segment length;
- DS:[0x52] = APM BIOS data segment length;
- int15h/AX=5300h(BX=0); // check again
- if (APM supported) {
- INITSET:[0x40] = APM version;
- INITSET:[0x4C] = APM flags;
- }
- else { // should not happen
- // disconnect interface
- int15h/AX=5304h(BX=0);
- }
- }
- else {
- // clear 32bit support
- INITSET:[0x4C] &= ~0x0002;
- }
- }
- }
- #endif
- // call mode switch
- if (realmode_swtch) {
- far realmode_swtch(); // mode switch hook
- }
- else {
- far default_switch(); // see below
- }
- // set code32: 0x100000 for big kernel, otherwise 0x1000
- (double word) code32 = code32_start;
- if (!(loadflags & LOADED_HIGH)) {
- // normal low loaded zImage
- move start_sys_seg:0 to (0100:0 ... CS-DELTA_INITSEG:0);
- // move 0x1000 bytes each time
- }
- if (CS!=SETUPSEG) {
- cli; // disable interrupts
- // store new SS in DX
- DX = SS;
- AX = CS - DELTA_INITSEG;
- if (DX>;=AX) {
- DX = DX + INITSEG - AX; // i.e. SS-CS+SETUPSEG
- }
- // move CS-DELTA_INITSEG:0 to INITSEG:0 (setup_move_size bytes)
- // TODO: why not do this in one step?
- ES = INITSEG;
- move _DOWNWARD_ from CS-DELTA_INITSEG:setup_move_size-1 to
- (INITSEG:setup_move_size-1
- ... INITSEG:move_self_here+0x200);
- // setup_move_size-move_self_here-0x200 bytes
- // INITSEG:move_self_here+0x200 = SETUPSEG:move_self_here
- goto SETUPSEG:move_self_here;
- move_self_here:
- move the rest to INITSEG:move_self_here+0x200-1 ... INITSEG:0;
- // move_self_here+0x200 bytes
- DS = SETUPSEG;
- SS = DX;
- }
- // CS==SETUPSEG is true now
- // Protected Mode Basics
- // http://x86.ddj.com/articles/pmbasics/tspec_a1_doc.htm
- lidt idt_48; // load idt with 0, 0;
- // new code added here in Linux 2.4
- lgdt gdt_48; // load gdt with whatever appropriate;
- // enable A20
- empty_8042();
- outportb(0x64, 0xD1); // command write
- empty_8042();
- outportb(0x60, 0xDF); // A20 on
- empty_8042();
- #define TEST_ADDR 0x7C
- // test A20
- GS = AX = 0xFFFF;
- BX = 0:[TEST_ADDR];
- do {
- 0:[TEST_ADDR] = ++AX;
- } while (AX==GS:[TEST_ADDR+0x10]);
- 0:[TEST_ADDR] = BX;
- // reset coprocessor
- outportb(0xF0, 0);
- delay();
- outportb(0xF1, 0);
- delay();
- // reprogram the interrupts
- outportb(0x20, 0x11); // initialize 8259A-1
- delay();
- outportb(0xA0, 0x11); // initialize 8259A-2
- delay();
- outportb(0x21, 0x20); // start of hardware int's (0x20)
- delay();
- outportb(0xA1, 0x28); // start of hardware int's 2 (0x28)
- delay();
- outportb(0x21, 0x04); // 8259-1 is master
- delay();
- outportb(0xA1, 0x02); // 8259-2 is slave
- delay();
- outportb(0x21, 0x01); // 8086 mode
- delay();
- outportb(0xA1, 0x01); // 8086 mode
- delay();
- outportb(0xA1, 0xFF); // mask off all interrupts for now
- delay();
- outportb(0x21, 0xFB); // mask all irq's but irq2, which is cascaded
- // protected mode!
- mov ax, #1;
- lmsw ax;
- jmp flush_instr;
- flush_instr:
- xor bx, bx;
- }
- ////////////////////////////////////////////////////////////////////
- {
- db 0x66, 0xea
- code32:
- dd 0x1000
- dw __KERNEL_CS // 0x10, defined in asm-i386/segment.h
- // goto 10:1000 or 10:100000
- kernel_version:
- .ascii UTS_RELEASE // defined in makefile
- .ascii "("
- .ascii LINUX_COMPILE_BY
- .ascii "@"
- .ascii LINUX_COMPILE_HOST
- .ascii ")"
- .ascii UTS_VERSION
- db 0
- }
- ////////////////////////////////////////////////////////////////////
- // default real mode switch routine
- far default_switch()
- {
- cli;
- outportb(0x70, 0x80); // disable NMI
- }
- ////////////////////////////////////////////////////////////////////
- // get called when using bootsect loader _AND_ have bzImage to load
- far bootsect_helper(ES)
- {
- if (bootsect_es==0) {
- type_of_loader = 0x20; // bootsect-loader, version 0
- AX = ES >;>; 4;
- CS:[bootsect_src_base+2] = AH;
- bootsect_es = ES;
- AX = ES - SYSSEG;
- }
- else {
- if (BX==0) { // 64K aligned
- // copy extended memory
- // http://www.ctyme.com/intr/rb-1527.htm
- try {
- int15h/AX=87h(CX=0x8000,
- ES:SI=CS:bootsect_gdt);
- }
- catch {
- bootsect_panic:
- prtstr("INT15 refuses to access high memory."
- " Giving up.");
- halt;
- }
- ES = bootsect_es;
- CS:[bootsect_dst_base+2]++;
- }
- AH = CS:[bootsect_dst_base+2] << 4;
- AL = 0;
- }
- }
- ////////////////////////////////////////////////////////////////////
- {
- bootsect_gdt:
- .word 0, 0, 0, 0
- .word 0, 0, 0, 0
- bootsect_src:
- .word 0xFFFF
- bootsect_src_base:
- .byte 0, 0, 1 ! base = 0x010000
- .byte 0x93 ! typbyte
- .word 0 ! limit16, base24 =0
- bootsect_dst:
- .word 0xFFFF
- bootsect_dst_base:
- .byte 0, 0, 0x10 ! base = 0x100000
- .byte 0x93 ! typbyte
- .word 0 ! limit16, base24 =0
- .word 0, 0, 0, 0 ! used by BIOS
- .word 0, 0, 0, 0
- bootsect_es:
- .word 0
- }
- ////////////////////////////////////////////////////////////////////
- // check that the keyboard command queue is empty
- empty_8042()
- {
- timeout = 0xFFFFFF; // local variable
- for (;;) {
- if (--timeout==0) return;
- delay();
- inportb(0x64, AL); // 8042 status port
- if (AL & 1) { // output buffer
- delay();
- inportb(0x60, .);
- continue;
- }
- if (!(AL & 2)) return; // input buffer
- }
- }
- ////////////////////////////////////////////////////////////////////
- // read the CMOS clock, return the seconds in AL
- gettime()
- {
- // get real-time clock time
- // http://www.ctyme.com/intr/rb-2273.htm
- int1Ah/AH=02h(); // DH = seconds (in BCD)
- AL = DH & 0x0F;
- AH = DH >;>; 4;
- AAD;
- }
- ////////////////////////////////////////////////////////////////////
- delay() { /* needed after doing I/O */ }
- ////////////////////////////////////////////////////////////////////
- {
- gdt:
- .word 0,0,0,0 ! dummy
- .word 0,0,0,0 ! unused
- .word 0xFFFF ! 4Gb - (0x100000*0x1000 = 4Gb)
- .word 0x0000 ! base address=0
- .word 0x9A00 ! code read/exec
- .word 0x00CF ! granularity=4096, 386 (+5th nibble of limit)
- .word 0xFFFF ! 4Gb - (0x100000*0x1000 = 4Gb)
- .word 0x0000 ! base address=0
- .word 0x9200 ! data read/write
- .word 0x00CF ! granularity=4096, 386 (+5th nibble of limit)
- idt_48:
- .word 0 ! idt limit=0
- .word 0, 0 ! idt base=0L
- gdt_48:
- .word 0x800 ! gdt limit=2048, 256 GDT entries
- .word 512+gdt, 0x9 ! gdt base = 0x9XXXX
- // +512 because of bootsect
- }
- ////////////////////////////////////////////////////////////////////
- // Included video setup & detection code "video.S"
- /*
- Positions of various video parameters passed to the kernel
- (see also include/linux/tty.h)
- CS-DELTA_INITSEG segment
- #define PARAM_CURSOR_POS 0x00
- #define PARAM_VIDEO_PAGE 0x04
- #define PARAM_VIDEO_MODE 0x06
- #define PARAM_VIDEO_COLS 0x07
- #define PARAM_VIDEO_EGA_BX 0x0a
- #define PARAM_VIDEO_LINES 0x0e
- #define PARAM_HAVE_VGA 0x0f
- #define PARAM_FONT_POINTS 0x10
- #define PARAM_LFB_WIDTH 0x12
- #define PARAM_LFB_HEIGHT 0x14
- #define PARAM_LFB_DEPTH 0x16
- #define PARAM_LFB_BASE 0x18
- #define PARAM_LFB_SIZE 0x1c
- #define PARAM_LFB_LINELENGTH 0x24
- #define PARAM_LFB_COLORS 0x26
- #define PARAM_VESAPM_SEG 0x2e
- #define PARAM_VESAPM_OFF 0x30
- #define PARAM_LFB_PAGES 0x32
- */
- video()
- {
- FS = DS;
- DS = ES = CS;
- GS = 0;
- basic_detect();
- #ifdef CONFIG_VIDEO_SELECT
- if (FS:[0x1FA]!=ASK_VGA) {
- // ASK_VGA=0xFFFD, defined in asm-i386/boot.h
- mode_set();
- if (failed) {
- prtstr("You passed an undefined mode number.");
- }
- }
- else {
- mode_menu();
- }
- #ifdef CONFIG_VIDEO_RETAIN
- restore_screen();
- #endif
- #endif
- mode_params();
- }
- ////////////////////////////////////////////////////////////////////
- SIG1 = 0xAA55
- SIG2 = 0x5A5A
- {
- setup_sig1: .word SIG1
- setup_sig2: .word SIG2
- modelist:
- .text
- endtext:
- .data
- enddata:
- .bss
- endbss:
- }
- ////////////////////////////////////////////////////////////////////
- // end of file
复制代码
---------------------------------------------------------------------------
再看 feiyunw 的代码分析:
---------------------------------------------------------------------------
- ////////////////////////////////////////////////////////////////////
- // head.txt
- // Copyright(C) 2001, Feiyun Wang
- ////////////////////////////////////////////////////////////////////
- // analysis on linux/arch/i386/kernel/head.S (for Linux 2.2.17)
- ////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////
- startup_32()
- __KERNEL_DS = 0x18;
- CL_MAGIC = 0xA33F;
- CL_MAGIC_ADDR = 0x90020;
- CL_BASE_ADDR = 0x90000;
- CL_OFFSET = 0x90022;
- {
- cld;
- DS = ES = FS = GS = __KERNEL_DS (= 0x18);
- #ifdef __SMP__
- if (BX) {
- CR4 |= mmu_cr4_features-__PAGE_OFFSET;
- // mmu_cr4_features defined in arch/i386/mm/init.c
- // __PAGE_OFFSET defined in include/asm-i386/page.h
- }
- #endif
- CR3 = 0x101000; // page table pointer
- CR0 |= 0x80000000; // set PG bit
- SS:ESP = stack_start;
- #ifdef __SMP__
- if (BX) {
- EFLAG = 0;
- goto checkCPUtype;
- }
- #endif
- clear BSS (__bss_start .. _end);
- setup_idt();
- EFLAGS = 0;
- move 0x90000 to empty_zero_page (i.e. 0x5000) (2 KByte);
- clear empty_zero_page+2K (2 KByte);
- if (CL_MAGIC==*(CL_MAGIC_ADDR)) {
- move *(CL_OFFSET)+CL_BASE_ADDR to empty_zero_page+2K (2 KByte);
- }
- }
- ////////////////////////////////////////////////////////////////////
- checkCPUtype()
- global variables: ready
- // see include/asm-i386/processor.h struct cpuinfo_x86
- // boot_cpu_data defined in arch/i386/kernel/setup.c
- struct cpuinfo_x86 boot_cpu_data;
- __KERNEL_DS = 0x18;
- {
- X86_CPUID = -1;
- X86 = 3;
- save original EFLAGS;
- check AC bit in EFLAGS;
- if (AC bit not changed) goto is386;
- X86 = 4;
- check ID bit in EFLAGS;
- restore original EFLAGS;
- if (ID bit not changed) goto is486;
- // get CPU info,
- // <>; Vol.2 P.3-110
- CPUID(EAX=0);
- X86_CPUID = EAX;
- X86_VENDOR_ID = EBX;
- *((&X86_VENDOR_ID)+4) = ECX;
- *((&X86_VENDOR_ID)+8) = EDX;
- if (!EAX) goto is486;
- CPUID(EAX=1);
- CL = AL;
- X86 = AH & 0x0f; // family
- X86_MODEL = (AL & 0xf0) >;>; 4; // model
- X86_MASK = AL & 0x0f; // stepping id
- X86_CAPABILITY = EDX; // feature
- is486:
- // save PG, PE & ET, set AM, WP, NE & MP
- EAX = (CR0 & 0x80000011) | 0x50022;
- goto 2f;
- is386:
- restore original EFLAGS;
- // save PG, PE & ET, set MP
- EAX = (CR0 & 0x80000011) | 0x02;
- 2f:
- CR0 = EAX;
- check_x87();
- #ifdef __SMP__
- if (ready) {
- CR4 |= 0x10; // set PSE, turn on 4 MByte pages
- CR3 = CR3;
- }
- ready++;
- #endif;
- lgdt gdt_descr;
- lidt idt_descr;
- DS = ES = FS = GS = __KERNEL_DS (= 0x18);
- #ifdef __SMP__
- SS = __KERNEL_DS (= 0x18);
- #else
- SS:ESP = stack_start;
- #endif
- lldt 0;
- cld;
- start_kernel();
- halt;
- }
- ////////////////////////////////////////////////////////////////////
- {
- #ifdef __SMP__
- ready: .byte 0;
- #endif
- }
- ////////////////////////////////////////////////////////////////////
- check_x87()
- {
- X86_HARD_MATH = 0;
- clts;
- fninit;
- fstsw ax;
- if (al) {
- // no coprocessor, set EM;
- // TODO; why not use |=?
- cr0 ^= 0x04;
- }
- else {
- X86_HARD_MATH = 1;
- fsetpm; // 0xDB, 0xE4
- }
- }
- ////////////////////////////////////////////////////////////////////
- setup_idt()
- {
- edx = &ignore_int;
- eax = __KERNEL_CS << 16;
- ax = dx;
- dx = 0x8E00; // interrupt gate, dpl = 0, present
- set all entries in idt_table to eax:edx; // 256*8 Bytes
- }
- ////////////////////////////////////////////////////////////////////
- {
- stack_start:
- .long init_task_union+8192;
- .long __KERNEL_DS;
- }
- ////////////////////////////////////////////////////////////////////
- ignore_init()
- {
- printk("Unknown interrupt\n");
- }
- ////////////////////////////////////////////////////////////////////
- {
- NR_TASKS = 512; // defined in include/linux/tasks.h
- IDT_ENTRIES = 256;
- GDT_ENTRIES = 12+2*NR_TASKS;
- .word 0;
- idt_descr:
- .word IDT_ENTRIES*8-1;
- idt:
- .long idt_table;
- .word 0;
- gdt_descr:
- .word GDT_ENTRIES*8-1;
- gdt:
- .long gdt_table;
- }
- ////////////////////////////////////////////////////////////////////
- {
- .org 0x1000;
- swapper_pg_dir:
- .long 0x00102007;
- .fill __USER_PGD_PTRS-1, 4, 0; // 767 entries
- .long 0x00102007;
- .fill __KERNEL_PGD_PTRS-1, 4, 0; // 255 entries
- .org 0x2000;
- pg0:
- // ...
- .org 0x3000;
- empty_bad_page:
- .org 0x4000;
- empty_bad_page_table:
- .org 0x5000;
- empty_zero_page:
- .org 0x6000;
- .data
- gdt_table:
- .quad 0x0000000000000000; // null
- .quad 0x0000000000000000; // not used
- .quad 0x00cf9a000000ffff; // 0x10 kernel 4GB code at 0x00000000
- .quad 0x00cf92000000ffff; // 0x18 kernel 4GB data at 0x00000000
- .quad 0x00cffa000000ffff; // 0x20 user 4GB code at 0x00000000
- .quad 0x00cff2000000ffff; // 0x28 user 4GB data at 0x00000000
- .quad 0x0000000000000000; // not used
- .quad 0x0000000000000000; // not used
- .quad 0x0040920000000000; // 0x40 APM setup for bad BIOS
- .quad 0x00409a0000000000; // 0x48 APM CS code
- .quad 0x00009a0000000000; // 0x50 APM CS 16 code (16 bit)
- .quad 0x0040920000000000; // 0x58 APM DS data
- .fill 2*NR_TASKS, 8, 0;
- .section .text.lock
- stext_lock:
- }
- ////////////////////////////////////////////////////////////////////
- // end of file
复制代码 |
|