Linux Boot-go_to_protected_mode

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.
/* * Prepare the transition to protected mode. * from the actual mode to protected mode * Document: */arch/x86/include/asm/segment.h "1" * arch/x86/boot/pm.c "2" this article * arch/x86/boot/a20.c "3" */#include "b Oot.h "#include <asm/segment.h>/** Invoke the realmode switch hook if present; otherwise* Disable all interrupts.** boot loader hooks* when the loader is running in an environment that cannot lay out a standard memory layout, the loader hooks is used. This kind of hooks try not to use. * Realmode_swtch: Last time before going to protected mode, it is 16 bits (the default routine is to disable the nmi,* non-blocking interrupt). * Code32_start: This field can be used as a hook, executed at the first time after the switch to protected mode, and is 32 bits, * its execution before the kernel decompression. Real mode starts at offset 512 at the beginning of the kernel. At this time ds=es=ss= real mode code plus * Load address. The recommendation is Fs=gs=ds=es=ss. In general, the loader will point it at normal, compressed kernel code.    */static inline void Io_delay (void) {//boot.h: Writes an AL value to the 0x80 port to consume the time const u16 Delay_port = 0x80; ASM volatile ("Outb%%al,%0":: "DN" (Delay_port));} static void Realmode_switch_hook (void) {/* * calls the hook, the general hook is not set, so go to the else process * to 0x70 merchandise write 0x80-off nmi */if (boot_ Params.hdr.realmode_swtch) {asm volatile ("Lcallw *%0":: "M" (boot_params.hdr.realmode_swtch): "EAX", "ebx", "ecx", "edx ");} else {ASM volatile ("CLI"); Outb (0x80, 0x70); /* Disable NMI */io_delay ();}} /* * Disable all interrupts at the legacy PIC. * PIC-related * Port range: 0x20-0x3f 8259 Programmable Interrupt Controller 1 * port range: 0XA0-0XBF 8259 Programmable Interrupt Controller 2 * */static void mask_all_interrupts (void) {O       UTB (0xFF, 0XA1);       /* Mask all interrupts on the secondary PIC */io_delay (); Outb (0XFB, 0x21); /* Mask all but cascade on the primary PIC */io_delay ();} /* * Reset ignne# if asserted in the FPU. * Port range: 0X0F0-0X0FF math coprocessor access port */static void Reset_coprocessor (void) {OUTB (0, 0xf0); Io_delay (); Outb (0, 0xf1); Io_delay () ;}  /** Set up the gdt*/struct gdt_ptr {U16 len;//0-15:gdt lmit size u32 ptr;//16-47:base address base} __attribute__ ((packed));/* * The GDT used at startup is set to only 3 Cs,ds,tss, and the segment base of the code snippet CS and data segment DS is set to 0 * The task status segment base address is set to 4096 * by the document "1": *gdt_entry_boot_cs=2 *gdt_entry_boot_ Ds=3 *gdt_entry_boot_tss=4 * These values represent indexes in the table, respectively, in the index 2, 3, 4 of the temporary GDT * respectively __boot_cs=16,__boot_ds=24,__boot_tss=32, etc. * Segment selector corresponds to segment descriptor */static void Setup_gdt (void) {/* There is machines which is known to ' boot with the gdtbeing 8-byte Unali GnEd. Intel recommends byte alignment. */static Const U64 boot_gdt[] __ATTRIBUTE__ ((aligned ()) = {/* Cs:code, Read/execute, 4 GB, base 0 */[gdt_entry_boot_cs ] = Gdt_entry (0xc09b, 0, 0XFFFFF),/* Ds:data, Read/write, 4 GB, base 0 */[gdt_entry_boot_ds] = gdt_entry (0xc093, 0, 0XFFF FF),/* tss:32-bit TSS, 104 bytes, base 4096 *//* We only has a TSS here to keep Intel VT happy;we don ' t actually use it For anything. */[GDT_ENTRY_BOOT_TSS] = Gdt_entry (0x0089, 4096, 103),};/* Xen HVM incorrectly stores a pointer to the GDT_PTR, insteadof  The gdt_ptr contents. Thus, make it static so it willstay in memory, at least long enough, the we switch to Theproper kernel GDT. */static struct Gdt_ptr gdt;gdt.len = sizeof (BOOT_GDT) -1;gdt.ptr = (u32) &boot_gdt + (DS () << 4);//via LGDTL 48-bit G DT puts the GDTR register ASM volatile ("Lgdtl%0":: "M" (GDT));} /** Set up the idt* Interrupt descriptor descriptor is initialized to 0, first without using */static void Setup_idt (void) {static const struct Gdt_ptr Null_idt = {0, 0};asm Volati Le ("Lidtl%0":: "M" (Null_idt));} /* * Actual invocation sequence * This function jumps from Boot/main (), which is the most important function in PM.C, which controls the order in which protection mode * related functions are called. Its main work is: * 1. Call Loader hook * 2 when leaving real mode. Open A20gate * 3. Reset the math coprocessor * 4. Block all interrupts * 5. Set up IDT * 6. Set GDT * 7. Execute Protected_mode_jump (code 32_start Hook) * for Code32_start (Document/x86/boot.txt), as mentioned earlier, it can also be used as the loader hook, but it is in the first time to enter the protection mode * execution. But in general, the loader will point it to the uncompressed kernel address, the hook is less used. */void Go_to_protected_mode (void) {/* Hook before leaving real mode, also disables interrupts */realmode_switch_hook ();/* Enable the A20 Gate */if (enable_a20 ()) {puts ("A20 Gate not responding, unable to boot...\n");d ie (); /* Reset coprocessor (ignne#) */reset_coprocessor ();/* Mask all interrupts in the PIC */mask_all_interrupts ();/* Actual TR Ansition to Protected mode ... */setup_idt (); Setup_gdt ();/* * Boot_params defined in BOOT/MAIN.C * ds from header. S has not changed yet, or points to the kernel loading the segment where base x resides. * Ds<<4+boot_params is to find the actual address for boot_params. * The function in the kernel is fastcall, then parameter 1 is placed in eax, and parameter 2 is placed in edx. */protected_mode_jump (Boot_params.hdr.code32_start, (u32) &boot_params + (DS () << 4));} a20.c///////////////////////////////////////////* * Enable A20 Gate (return-1 on Failure) * Before 80286, Intel's CPU had only 20 address lines, with access to the highest address f000:ffff=fffff, in which case 20 address lines were all 1. 80286, there are 24 address lines, access to FFFF:FFFF=10FFEFH address (address format does not change, only the range is large), 1M or more is extend MEMORY,1M~10FFEFH for high memory. Before 80268 * If the address given is greater than f000:ffff, such as FFFF:FFFF=10FFEFH, then because the address line only 20, more than 20 * of the address portion will be discarded, so access is higher than ffff:ffff actually access 0FFEF. 20 Address Line Maximum * is 1 m memory address, so to access the logical address above 1M, will access the address below 1M, this situation is called * wraparound. and 80286 can access more than 1M address. In 80286 real mode access to the high-end address is not consistent with 8086, which is like a bug. So for them to be consistent, people introduced the A20gate: using the keyboard controller 8042 empty * out of a pin and the 20th Address line phase to control the 20th root. In 80286 real mode, this * pin of the keyboard controller is 0. * Note that the maximum logical address is FFFF:FFFF=FFFF0+FFFF=10FFEFH, in 80286 real mode, even if the interview * ask this address, because it was artificially set 0, and 80,861 like. Up to 4 bits, because of the logical address limit, the maximum value is 0001, so as long as the maximum 4 bits of the minimum 1 bits (A20) can be controlled, because the highest 3 bits beyond the logical address * expression range, they are always 0. Of course, the CPU after 80286 also retains the true pattern (with 8088) consistency, * so a20gate always exists. * But for 80286 and later CPUs, there is a protection mode, the addressing range becomes larger, such as the 32-bit cpu,20 bit more than the * address is no longer only the 20th bit is 1, the other bit is 0. And A20 has become a legacy problem, after the protection mode, if * A20 still maintain the true mode value---0, it will result in an address range can not be found. So you need to set A20gate to 1 between switching to real * mode. * A20 Open Method not limited to 80421 kinds, with the development of technology, the manufacturers have designed several ways to open A20 * below will use 8042, 0x92 port, Bois (int15 ax=240x) */#include "boot.h" #define MAX_8042_LOOPS 100000 #define MAX_8042_FF 32/* * 0x64: status Register, Command Register * 0x60: Data register * If you want to read 8042 status, read the 0x64 port directly, write the command to 0x64 if you want to write, write the parameter * to 0x60, and then read the 0x60 port Gets the return value. * 0x60r Read Output buffer * 0x60w Write input buffer (8042 data&8048 command) * 0x64r Read status register * 0x64w write input buffer (8042 Command) * Port 0x64 Readout status (8-bit): * 0 0X60 Port has data, the system should read it out * 1 in the input register to 8042 have input, from 0x60 or 0x64 * 2 0:reset * 3 Input Register value is the command (1) or data (0) * 4 keyboard enable (1) disabled (0) * 5 Transmission Timeout * 6 receive Super When * 7 parity bit 1= even, 0= odd, should be odd */static int empty_8042 (void) {U8 Status;int loops = max_8042_loops;int ffs = Max_8042_ff;while (loops--) {Io_delay (); status = INB (0x64), if (status = = 0xFF) {/* FF is a plausible, but very unlikely status *///return FF description 8042 controller may not exist I F (!--FFS) return-1; /* Assume no KBC present */}/* * Lowest bit is 1 description 60h port has data, read it out */if (status & 1) {/* Read and discard input data */io_delay (); (void) inb (0x60);} else if (! ( Status & 2)) {/* buffers empty, finished! *//* * If clause filter lowest bit 1, to this note no data to read, lowest bit =0 * This sentence also filtered out the Bit1 1, the status of the lowest 2 bits should be 00 * 00 means that the 0x60 port has no data to read, the system also did not go to 8042 input * data or command, 8042empty. */return 0;}} return-1;}  /* Returns Nonzero if the A20 is enabled. The memory addressused as a test is the Int. $0x80 vector, which should be safe. */#define A20_TEST_ADDR (4*0x80) #define A20_test_short 32#define a20_test_long 2097152/* 2^21 */static int a20_test ( int loops) {int ok = 0;int saved, ctr;set_fs (0x0000); Set_gs (0XFFFF);/* * fs:a20_test_addr=00000+4*0x80 =0000:0200 * gs:a20 _test_addr+0x10=ffff0+4*0x80+0x10=0x100200 * Wrfs32 Write 32-bit value to FS, Rdfs32 read value from FS:ADDR * WRFS32,RDGS32 similar to * * Above said 80286 real mode wraparound phenomenon, is to visit high-end address *, because of A20, the highest bit of 1 will be discarded. So, the above two ground * address, if the A20 is not open, read the data should be the same, XOR * result is equal to 0 (ok=0). For the following code, read from these two addresses respectively * according to, if XOR is not 0, the description A20 has opened ok!=0, if ok=0, description * A20 not open. When Ok!=0, will try to loops times, to ensure that it is not accidental phenomenon, generation * code would require loops every time to ensure that ok!=0 (A20 open).     */saved = CTR = Rdfs32 (A20_TEST_ADDR), while (loops--) {wrfs32 (++ctr, a20_test_addr); Io_delay (); /* Serialize and make delay constant */ok = rdgs32 (a20_test_addr+0x10) ^ ctr;if (OK)break;} Restore the value of the RDFS32 at the original wrfs32 (saved, a20_test_addr); return OK;} /* * Quick test to see if A20 is already enabled * uses a shorter loop to probe */static int a20_test_short (void) {return a20_test (a20_test _short);} /* * Longer test, actually waits for A20 to come on line;  This * was useful when dealing with the KBC or other slow external circuitry. * With a long loop to detect, when using a slow device (8042) to open A20, it is necessary to use this method to detect */static int A20_test_long (void) {return a20_test (A20_test_long);} /* * int15 can also be used to open A20, * ax=0x2401 Disable * ax=0x2402 enable * ax=0x2403 query A20 status * ax=0x2404 query A20 support case (8042 or 0x92 port) */static void E Nable_a20_bios (void) {struct Biosregs ireg;initregs (&ireg); ireg.ax = 0x2401;intcall (0x15, &ireg, NULL);}       static void Enable_a20_kbc (void) {empty_8042 (); Outb (0xd1, 0x64);       /* command write to write commands */empty_8042 (); Outb (0XDF, 0x60);       /* A20 on, write command value on 0x60 port (open a20gate) */empty_8042 (); Outb (0xFF, 0x64); /* Null command, but UHCI wants it */empty_8042 ();} /* * 0x92 port is fast a20gate, when the system does not have a keyboard controller, use this port * bit 1:1,enable; 0,disable * bit 0:1 reset;     0,no reset */static void Enable_a20_fast (void) {U8 port_a;port_a = INB (0x92);        /* Configuration Port A */port_a |= 0x02;        /* Enable A20 */port_a &= ~0x01; /* Don't reset machine */outb (port_a, 0x92);} /** Actual routine to enable A20; return 0 on OK, 1 on failure*/#define A20_ENABLE_LOOPS 255/* Number of times to try *//* * This function will attempt to open a20gate in three ways there is a Open as */int enable_a20 (void) {int loops = A20_enable_loops;int Kbc_err;while (loops--) {/* First, check to see if A20 is ALR Eady enabled (Legacy free, etc) */if (A20_test_short ()) return 0;/* Next, try the BIOS (INT 0x15, ax=0x2401) */enable_a20_b iOS (); if (A20_test_short ()) return 0;/* Try enabling A20 through the keyboard controller */kbc_err = empty_8042 ();//This test is to prevent The BIOS turns on the A20 delay if (A20_test_short ()) return 0; /* BIOS worked, but with delayed reaction */if (!kbc_err) {ENABLE_A20_KBC (); if (A20_test_long ()) return 0;} /* Finally, try enabling the "Fast A20 Gate" */enable_a20_fast (); if (A20_test_long ()) return0;} return-1;} //////////////////////////////////////////////////////////////////////////

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.