356 lines
8.7 KiB
C
356 lines
8.7 KiB
C
/*******************************************************************************/
|
|
/* COS2000 - Compatible Operating System - LGPL v3 - Hordé Nicolas */
|
|
/* */
|
|
#include "types.h"
|
|
#include "asm.h"
|
|
#include "setup.h"
|
|
#include "gdt.h"
|
|
#include "memory.h"
|
|
|
|
struct params {
|
|
entrye820 *e820_table;
|
|
u32 e820_numbers;
|
|
u8 kbflag;
|
|
} params;
|
|
|
|
/* registre gdt */
|
|
static struct gdtr gdtreg;
|
|
|
|
/* table de GDT */
|
|
static gdtdes gdt[GDT_SIZE];
|
|
|
|
#define EFLAGS_CF 0x00000001
|
|
#define CR0_PE 0x00000001
|
|
#define LOOPS_8042 100000
|
|
#define FF_8042 32
|
|
#define LOOPS_A20_ENABLE 255
|
|
#define LOOPS_DELAY 32768
|
|
#define SMAP 0x534d4150
|
|
|
|
#define interrupt(num, regs) ({\
|
|
asm("pushal\n\
|
|
mov %[eflagsregs],%%eax\n\
|
|
pushl %%eax\n\
|
|
popfl\n\
|
|
mov %[eaxregs],%%eax\n\
|
|
mov %[ebxregs],%%ebx\n\
|
|
mov %[ecxregs],%%ecx\n\
|
|
mov %[edxregs],%%edx\n\
|
|
mov %[esiregs],%%esi\n\
|
|
mov %[ediregs],%%edi\n\
|
|
mov %[ebpregs],%%ebp\n\
|
|
int %[numregs]\n\
|
|
pushfl\n\
|
|
popl %%eax\n\
|
|
mov %%eax,%[eflagsregs]\n\
|
|
mov %%eax,%[eaxregs]\n\
|
|
mov %%ebx,%[ebxregs]\n\
|
|
mov %%ecx,%[ecxregs]\n\
|
|
mov %%edx,%[edxregs]\n\
|
|
mov %%esi,%[esiregs]\n\
|
|
mov %%edi,%[ediregs]\n\
|
|
mov %%ebp,%[ebpregs]\n\
|
|
popal":[eaxregs] "+m" (regs.eax),[ebxregs] "+m" (regs.ebx),[ecxregs] "+m" (regs.ecx),[edxregs] "+m" (regs.edx),[esiregs] "+m" (regs.esi),[ediregs] "+m" (regs.edi),[ebpregs] "+m" (regs.ebp),[eflagsregs] "+m" (regs.eflags):[numregs] "i" (num):);})
|
|
|
|
|
|
u8 initmemory(void)
|
|
{
|
|
u32 count = 0;
|
|
miniregs reg;
|
|
entrye820 *desc = params.e820_table;
|
|
static struct entrye820 buf;
|
|
do {
|
|
reg.ax = 0xe820;
|
|
reg.cx = sizeof(buf);
|
|
reg.edx = SMAP;
|
|
reg.di = &buf;
|
|
interrupt(0x15, reg);
|
|
if (reg.eflags & EFLAGS_CF)
|
|
break;
|
|
if (reg.eax != SMAP)
|
|
{
|
|
count = 0;
|
|
break;
|
|
}
|
|
*desc++ = buf;
|
|
count++;
|
|
} while (reg.ebx && count < ARRAY_SIZE(params.e820_table));
|
|
return params.e820_numbers= count;
|
|
}
|
|
|
|
void showchar(u8 achar)
|
|
{
|
|
miniregs reg;
|
|
reg.bx = 0x0007;
|
|
reg.cx = 0x0001;
|
|
reg.ah = 0x0e;
|
|
reg.al = achar;
|
|
interrupt(0x10, reg); /* INT 10 - VIDEO - TELETYPE OUTPUT */
|
|
}
|
|
|
|
void showstr(u8 *str)
|
|
{
|
|
while (*str!='\000')
|
|
showchar(*str++);
|
|
}
|
|
|
|
u8 gettime(void)
|
|
{
|
|
miniregs reg;
|
|
reg.ah = 0x02;
|
|
interrupt(0x1a, reg); /* TIME - GET REAL-TIME CLOCK TIME (AT,XT286,PS) */
|
|
return reg.dh;
|
|
}
|
|
|
|
u8 waitchar(void)
|
|
{
|
|
miniregs reg;
|
|
reg.ah = 0x00;
|
|
interrupt(0x16, reg); /* INT 16 - KEYBOARD - GET KEYSTROKE */
|
|
return reg.al;
|
|
}
|
|
|
|
void initkeyboard(void)
|
|
{
|
|
miniregs reg;
|
|
reg.ah = 0x02;
|
|
interrupt(0x16, reg); /* INT 16 - KEYBOARD - GET SHIFT FLAGS */
|
|
params.kbflag=reg.al;
|
|
reg.ah = 0x03;
|
|
reg.al = 0x05;
|
|
reg.bx = 0x00;
|
|
interrupt(0x16, reg); /* INT 16 - KEYBOARD - SET TYPEMATIC RATE AND DELAY */
|
|
}
|
|
|
|
u8 empty8042(void)
|
|
{
|
|
u8 status;
|
|
u32 loops = LOOPS_8042;
|
|
u8 ffs = FF_8042;
|
|
while (loops--) {
|
|
iodelay();
|
|
status = inb(0x64);
|
|
if (status == 0xff) {
|
|
if (!--ffs)
|
|
return NULL;
|
|
}
|
|
if (status & 1) {
|
|
io_delay();
|
|
(void)inb(0x60);
|
|
} else if (!(status & 2)) {
|
|
return 1;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void iodelay(void)
|
|
{
|
|
//asm("outb %%al,$0x80" ::);
|
|
for(u32 loop=LOOPS_DELAY;loop>0;loop--) nop();
|
|
}
|
|
|
|
|
|
u8 testA20(void)
|
|
{
|
|
asm("xorw %%cx, %%cx\n\
|
|
decw %%cx\n\
|
|
movw %%cx, %%gs\n\
|
|
movw $0x4000, %%cx\n\
|
|
movw %%fs:(0x200), %%ax\n\
|
|
pushw %%ax\n\
|
|
1:\n\
|
|
incw %%ax\n\
|
|
movw %%ax, %%fs:(0x200)\n\
|
|
call iodelay\n\
|
|
cmpw %%gs:(0x210), %%ax\n\
|
|
loope 1b\n\
|
|
popw %%fs:(0x200)\n\
|
|
xor %%ax,%%ax\n\
|
|
je 2f\n\
|
|
mov $0x1,%%ax\n\
|
|
2:":::"ax","cx");
|
|
}
|
|
|
|
void enableA20kbc(void)
|
|
{
|
|
empty8042();
|
|
outb(0xd1, 0x64);
|
|
empty8042();
|
|
outb(0xdf, 0x60);
|
|
empty8042();
|
|
outb(0xff, 0x64);
|
|
empty8042();
|
|
}
|
|
|
|
void enableA20fast(void)
|
|
{
|
|
u8 port;
|
|
port = inb(0x92);
|
|
port |= 0x02;
|
|
port &= ~0x01;
|
|
outb(port, 0x92);
|
|
}
|
|
|
|
u8 enableA20(void)
|
|
{
|
|
int loops = LOOPS_A20_ENABLE;
|
|
int kbcerr;
|
|
while (loops--) {
|
|
if (testA20())
|
|
return 1;
|
|
kbcerr = empty8042();
|
|
if (testA20())
|
|
return 1;
|
|
if (!kbcerr) {
|
|
enableA20kbc();
|
|
if (testA20())
|
|
return 1;
|
|
}
|
|
enableA20fast();
|
|
if (testA20())
|
|
return NULL;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
/* Copie un octet une ou plusieurs fois en mémoire */
|
|
|
|
void memset(void *dst, u8 val, u32 count, u32 size)
|
|
{
|
|
u8 *d = (u8 *) dst;
|
|
if (size > 0)
|
|
size--;
|
|
for (; count != 0; count--)
|
|
{
|
|
*(d++) = val;
|
|
d += size;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
/* Copie une portion de mémoire vers une autre */
|
|
|
|
void memcpy(void *src, void *dst, u32 count, u32 size)
|
|
{
|
|
u8 *s = (u8 *) src;
|
|
u8 *d = (u8 *) dst;
|
|
if (size > 0)
|
|
size--;
|
|
for (; count != 0; count--)
|
|
{
|
|
*(d++) = *(s++);
|
|
d += size;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************/
|
|
/* Initialise les selecteurs avec la GDT */
|
|
|
|
void initselectors(u32 executingoffset)
|
|
{
|
|
asm(" movl %%cr0, %%eax \n \
|
|
orb $CR0_PE, %%eax \n \
|
|
movl %%eax, %%cr0 \n \
|
|
ljmp %[code], $raz\n\
|
|
raz:\n \
|
|
.code32\n\
|
|
movw %[data], %%ax \n \
|
|
movw %%ax, %%ds \n \
|
|
movw %%ax, %%es \n \
|
|
movw %%ax, %%fs \n \
|
|
movw %%ax, %%gs \n \
|
|
movl %[offset], %%ebx \n \
|
|
movw %[stack], %%ax \n \
|
|
movw %%ax, %%ss \n \
|
|
movl %[stackoff], %%esp \n \
|
|
xor %%eax,%%eax\n\
|
|
xor %%ebx,%%ebx\n\
|
|
xor %%ecx,%%ecx\n\
|
|
xor %%edx,%%edx\n\
|
|
xor %%esi,%%esi\n\
|
|
xor %%edi,%%edi\n\
|
|
xor %%ebp,%%ebp\n\
|
|
jmp %%ebx"::[data] "i"(SEL_KERNEL_DATA),[code] "i"(SEL_KERNEL_CODE),[stack] "i"(SEL_KERNEL_STACK),[stackoff] "i"(KERNEL_STACK_ADDR),[offset] "m"(executingoffset));
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
/* Créé un descripteur GDT */
|
|
|
|
void makegdtdes(u32 base, u32 limite, u8 acces, u8 flags, gdtdes * desc)
|
|
{
|
|
desc->lim0_15 = (limite & 0xffff);
|
|
desc->base0_15 = (base & 0xffff);
|
|
desc->base16_23 = (base & 0xff0000) >> 16;
|
|
desc->acces = acces;
|
|
desc->lim16_19 = (limite & 0xf0000) >> 16;
|
|
desc->flags = (flags & 0xf);
|
|
desc->base24_31 = (base & 0xff000000) >> 24;
|
|
return;
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
/* Initialise la GDT */
|
|
|
|
void initgdt()
|
|
{
|
|
makegdtdes(0x0, 0x00000, 0x00, 0x00, &gdt[0]); /* descripteur nul */
|
|
makegdtdes(0x0, 0xFFFFF, SEG_PRESENT | SEG_NORMAL | SEG_CODE | SEG_RING0 | SEG_READ | SEG_ACCESSED, GRANULARITY_4K | OPSIZE_32B | SYS_AVAILABLE, &gdt[1]); /* code -> SEL_KERNEL_CODE */
|
|
makegdtdes(0x0, 0x00000, SEG_PRESENT | SEG_NORMAL | SEG_DATA | SEG_RING0 | SEG_EXPAND_DOWN | SEG_READ_WRITE | SEG_ACCESSED, GRANULARITY_4K | OPSIZE_32B | SYS_AVAILABLE, &gdt[2]); /* pile -> SEL_KERNEL_STACK */
|
|
makegdtdes(0x0, 0xFFFFF, SEG_PRESENT | SEG_NORMAL | SEG_CODE | SEG_RING3 | SEG_CONFORMING | SEG_READ | SEG_ACCESSED, GRANULARITY_4K | OPSIZE_32B | SYS_AVAILABLE, &gdt[3]); /* code -> SEL_USER_CODE */
|
|
makegdtdes(0x0, 0x00000, SEG_PRESENT | SEG_NORMAL | SEG_DATA | SEG_RING3 | SEG_EXPAND_DOWN | SEG_READ_WRITE | SEG_ACCESSED, GRANULARITY_4K | OPSIZE_32B | SYS_AVAILABLE, &gdt[4]); /* pile -> SEL_USER_STACK */
|
|
makegdtdes(0x0, 0xFFFFF, SEG_PRESENT | SEG_NORMAL | SEG_DATA | SEG_RING0 | SEG_READ_WRITE | SEG_ACCESSED, GRANULARITY_4K | OPSIZE_32B | SYS_AVAILABLE, &gdt[5]); /* data -> SEL_KERNEL_DATA */
|
|
makegdtdes(0x0, 0xFFFFF, SEG_PRESENT | SEG_NORMAL | SEG_DATA | SEG_RING3 | SEG_READ_WRITE | SEG_ACCESSED, GRANULARITY_4K | OPSIZE_32B | SYS_AVAILABLE, &gdt[6]); /* data -> SEL_USER_DATA */
|
|
makegdtdes(0x0, 0x67, SEG_PRESENT | SEG_CODE | SEG_RING3 | SEG_ACCESSED, 0x00, &gdt[7]); /* descripteur de tss */
|
|
/* initialise le registre gdt */
|
|
gdtreg.limite = GDT_SIZE * sizeof(gdtdes);
|
|
gdtreg.base = GDT_ADDR;
|
|
/* recopie de la GDT a son adresse */
|
|
memcpy(&gdt, (u8 *) gdtreg.base, gdtreg.limite, 1);
|
|
/* chargement du registre GDT */
|
|
lgdt(gdtreg);
|
|
}
|
|
|
|
void maskinterrupts(void)
|
|
{
|
|
cli();
|
|
outb(0x80, 0x70); /* Disable NMI */
|
|
iodelay();
|
|
outb(0xff, 0xa1); /* Mask all interrupts on the secondary PIC */
|
|
idelay();
|
|
outb(0xfb, 0x21); /* Mask all but cascade on the primary PIC */
|
|
iodelay();
|
|
}
|
|
|
|
void initcoprocessor(void)
|
|
{
|
|
outb(0, 0xf0);
|
|
iodelay();
|
|
outb(0, 0xf1);
|
|
iodelay();
|
|
}
|
|
|
|
void initpmode(u32 offset)
|
|
{
|
|
if (enableA20()) {
|
|
showstr("impossible d'ouvrir la ligne A20...\n");
|
|
hlt();
|
|
}
|
|
maskinterrupts();
|
|
initgdt();
|
|
initselectors(offset);
|
|
}
|
|
|
|
void main(void)
|
|
{
|
|
showstr("Chargement de COS2000 - mode reel");
|
|
/* initparams(); */
|
|
initmemory();
|
|
initkeyboard();
|
|
/* initvideo(); */
|
|
initcoprocessor();
|
|
initpmode(0x10000);
|
|
}
|