/*******************************************************************************/ /* 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); }