#include <kernel/kernel.h>
extern char scode[], stack_end[];
//! Adjusts the value of a pointer so that it can be used before the
//! initial kernel GDT is set up.
#define MANGLE_PTR(type, ptr) ((type) ((char*) ptr - scode))
#ifdef _MSC_VER
void i386_lidt(idtr_t* p)
{
__asm lidt [p]
}
void i386_lgdt(gdtr_t* p)
{
__asm lgdt [p]
}
void sysStart();
#else
#define i386_lidt(ptr) asm("lidt (%0)" : : "r" (ptr));
#define i386_lgdt(ptr) asm("lgdt (%0)" : : "r" (ptr));
#endif
//! GDT register used by the kernel
gdtr_t _gdtr;
//! GDT used by the kernel
descriptor_t _gdt[9];
//! Global system information block
sysinfo_t _sysinfo;
//! The first kernel function called by the startup code
/*!
* \param ramdisk_phys Location of the ramdisk in physical memory
* \param ramdisk_size The length of the ramdisk
* \param phys Location of the kernel in physical memory; the physical
* address of the start() function
* \param kernel_size The length of the kernel code and data, not
* including the bss
* \param mem_top The address of the top of physical memory
*/
int INIT_CODE _main(addr_t ramdisk_phys,
size_t ramdisk_size,
addr_t phys,
size_t kernel_size,
addr_t mem_top)
{
gdtr_t* gdtr = MANGLE_PTR(gdtr_t*, &_gdtr);
descriptor_t* gdt = MANGLE_PTR(descriptor_t*, _gdt);
sysinfo_t* sysinfo = MANGLE_PTR(sysinfo_t*, &_sysinfo);
idtr_t idtr = { 0, 0 };
i386_lidt(&idtr);
if (mem_top > 128 * 1048576)
mem_top = 128 * 1048576;
sysinfo->kernel_phys = phys;
sysinfo->kernel_size = kernel_size;
sysinfo->memory_top = mem_top;
sysinfo->ramdisk_phys = ramdisk_phys;
sysinfo->ramdisk_size = ramdisk_size;
// null descriptor = 0
i386_set_descriptor(gdt + 0, 0, 0, 0, 0);
// kernel code = 0x8
i386_set_descriptor(gdt + 1, phys - (addr_t) scode, 0xfffff,
ACS_CODE | ACS_DPL_0, ATTR_DEFAULT | ATTR_GRANULARITY);
// kernel data = 0x10
i386_set_descriptor(gdt + 2, phys - (addr_t) scode, 0xfffff,
ACS_DATA | ACS_DPL_0, ATTR_BIG | ATTR_GRANULARITY);
// flat kernel code = 0x18
i386_set_descriptor(gdt + 3, 0, 0xfffff,
ACS_CODE | ACS_DPL_0, ATTR_DEFAULT | ATTR_GRANULARITY);
// flat kernel data = 0x20
i386_set_descriptor(gdt + 4, 0, 0xfffff,
ACS_DATA | ACS_DPL_0, ATTR_BIG | ATTR_GRANULARITY);
// flat user code = 0x28
i386_set_descriptor(gdt + 5, 0, 0xfffff,
ACS_CODE | ACS_DPL_3, ATTR_DEFAULT | ATTR_GRANULARITY);
// flat user data = 0x30
i386_set_descriptor(gdt + 6, 0, 0xfffff,
ACS_DATA | ACS_DPL_3, ATTR_BIG | ATTR_GRANULARITY);
// TSS = 0x38 (set up in main)
i386_set_descriptor(gdt + 7, 0, 0, 0, 0);
// user-mode thread data = 0x40 (base set on context switch)
i386_set_descriptor(gdt + 8, 0, 1,
ACS_DATA | ACS_DPL_3, ATTR_BIG | ATTR_GRANULARITY);
gdtr->base = (addr_t) gdt + phys;
gdtr->limit = sizeof(_gdt) - 1;
i386_lgdt(gdtr);
#ifdef _MSC_VER
sysStart();
#else
asm("mov $0x10,%%eax ; "
"mov %%eax,%%ds ;"
"mov %%eax,%%ss ;": : : "eax");
asm("mov $0x20,%%eax ; "
"mov %%eax,%%es ;"
"mov %%eax,%%gs ;"
"mov %%eax,%%fs ;": : : "eax");
asm("mov $_stack_end,%%esp" : : : "esp");
asm("ljmp $8,$_main");
#endif
return 0;
}