Our kernel is a multiboot kernel, we take advantage of the bootloader(Grub),so we take no concern on A20 initialization. In booting phase, we setup a temporary GDT table, make a temporary paging table in pg0(the first page starts from the end of kernel) to map 0xC0000000-0xC03FFFFF to the first 4M physical memory,turn on paging bit, and then call kernel main function.
One thing we need to know is that we tell Grub in multiboot header to load us at physical address 0x100000(1M), our kernel linear address starts from 0xC0100000(specified in linker script),by the way, since kmain() is a c function, we need to setup esp properly so that the stack don-not mess me up. At this time, we can use pg0 again, we set esp to pg0+4096,and now, we need to choose a paging policy and initialize global_pg_dir as soon as possible. Ehh, i haven’t done the home work of PAE and for saving memory usage, kernel uses large page(4M) mapping, we should make sure that CPU must support PSE and PGE (if not, kernel hangs) if we take large page mapping policy.
The global_pg_dir is widely used in kernel space.
After the initialization of global_pg_dir is finished, the second step is initializing the idt, setup error handler for each vector, and 0x80 for system call gate.
Note 1:set 0-19, 0x20-0x2f as interrupt gate, _do_ not setup it to trap gate but system call. the intel spec says,for interrupt gate, the CPU will close the interrupt pin when one interrupt fires,for example, when timer interrupt fires, the disk interrupt will be blocked. This is quite important, for system call, we set it to trap gate, so, when we are in system call path, the timer interrupt will still fire, and this may cause a schedule, it’s ok, we allow it, but in timer interrupt handler, taking a reschedule will mess everything up.
Note 2:we ignore the ldt register, and do not initialize any ldt entry since we do not use it.