46 static struct GDTEntry *gdtTableEntries;
50 static struct IDTEntry *idtTableEntries;
72 #define INTJMP_ENTRY_SIZE 8 73 #define INTJMP_ENTRY_MASK 7 74 #define INTJMP_ENTRY_BITS 3 79 #define KERNEL_IDLE_BEGIN ((uint32_t)&__kernelIdleBegin) 80 #define KERNEL_IDLE_END ((uint32_t)&__kernelIdleEnd) 82 static const char *error_outOfGDTEntries[] =
85 " No more GDT entries left!",
89 static const char *error_unhandledKernelInterrupt[] =
92 " Unable to handle kernel interrupt! ",
96 static const char *error_usermodeInterruptInvalid[] =
98 " USERMODE INTERRUPT ",
99 " Unable to recover from usermode interrupt! ",
104 asm(
".text\n.align 4\n" 106 " movl 4(%esp), %eax\n" 111 void __attribute__((cdecl)) __setSegments(uint32_t code, uint32_t data);
112 asm(
".text\n.align 4\n" 114 " movw 8(%esp), %ax\n" 127 asm(
".text\n.align 4\n" 129 " movw 4(%esp), %ax\n" 134 uint32_t
__attribute__((cdecl)) __runUserModeTask(uint16_t task);
135 asm(
".text\n.align 4\n" 136 "__runUserModeTask:\n" 145 asm(
".text\n.align 4\n" 147 " movl 4(%esp), %eax\n" 152 #define __isErrorCodeInterrupt(i) \ 153 ((i) == 8 || ((i) >= 10 && (i) <= 14) || (i) == 17) 162 static __attribute__((cdecl))
void __dispatchKernelInterrupt(uint32_t interrupt, uint32_t error,
struct taskContext *context)
170 asm volatile(
"mov %%cr2, %0" :
"=r" (cr2));
171 uint32_t args[] = {interrupt, error, status, cr2};
172 consoleSystemFailure(error_unhandledKernelInterrupt,
sizeof(args)/
sizeof(args[0]), args, context);
178 context->
eflags &= ~(1 << 9);
190 static void __initBasicGDT()
255 static void __initBasicTask()
270 kernelTask->
user = 0;
275 memset(task, 0,
sizeof(*task));
277 task->
iomap =
sizeof(*task);
290 usermodeTask->
user = 0;
295 memset(task, 0,
sizeof(*task));
297 task->
iomap =
sizeof(*task);
311 static void __generateIntJmpTables()
314 uint8_t *cur, *dispatcher;
332 *cur++ = 0x83; *cur++ = 0xEC; *cur++ = 0x6C;
336 *cur++ = 0x83; *cur++ = 0xEC; *cur++ = 0x68;
340 *(uint32_t *)cur = dispatcher - (cur + 4); cur += 4;
355 *cur++ = 0x89; *cur++ = 0x44; *cur++ = 0x24; *cur++ = 0x2C;
356 *cur++ = 0x89; *cur++ = 0x4C; *cur++ = 0x24; *cur++ = 0x30;
357 *cur++ = 0x89; *cur++ = 0x54; *cur++ = 0x24; *cur++ = 0x34;
358 *cur++ = 0x89; *cur++ = 0x5C; *cur++ = 0x24; *cur++ = 0x38;
359 *cur++ = 0x8D; *cur++ = 0x84; *cur++ = 0x24; *cur++ = 0x80;
360 *cur++ = 0x00; *cur++ = 0x00; *cur++ = 0x00;
361 *cur++ = 0x89; *cur++ = 0x44; *cur++ = 0x24; *cur++ = 0x3C;
362 *cur++ = 0x89; *cur++ = 0x6C; *cur++ = 0x24; *cur++ = 0x40;
363 *cur++ = 0x89; *cur++ = 0x74; *cur++ = 0x24; *cur++ = 0x44;
364 *cur++ = 0x89; *cur++ = 0x7C; *cur++ = 0x24; *cur++ = 0x48;
365 *cur++ = 0x8C; *cur++ = 0x44; *cur++ = 0x24; *cur++ = 0x4C;
366 *cur++ = 0x66; *cur++ = 0x8B; *cur++ = 0x44; *cur++ = 0x24;
368 *cur++ = 0x66; *cur++ = 0x89; *cur++ = 0x44; *cur++ = 0x24;
370 *cur++ = 0x8C; *cur++ = 0x54; *cur++ = 0x24; *cur++ = 0x54;
371 *cur++ = 0x8C; *cur++ = 0x5C; *cur++ = 0x24; *cur++ = 0x58;
372 *cur++ = 0x8C; *cur++ = 0x64; *cur++ = 0x24; *cur++ = 0x5C;
373 *cur++ = 0x8C; *cur++ = 0x6C; *cur++ = 0x24; *cur++ = 0x60;
374 *cur++ = 0x0F; *cur++ = 0x20; *cur++ = 0xD8;
375 *cur++ = 0x89; *cur++ = 0x44; *cur++ = 0x24; *cur++ = 0x20;
376 *cur++ = 0x8B; *cur++ = 0x44; *cur++ = 0x24; *cur++ = 0x70;
377 *cur++ = 0x89; *cur++ = 0x44; *cur++ = 0x24; *cur++ = 0x24;
378 *cur++ = 0x8B; *cur++ = 0x44; *cur++ = 0x24; *cur++ = 0x78;
379 *cur++ = 0x89; *cur++ = 0x44; *cur++ = 0x24; *cur++ = 0x28;
383 *cur++ = 0xC1; *cur++ = 0xE8; *cur++ = 0x03;
385 *cur++ = 0xFF; *cur++ = 0x74; *cur++ = 0x24; *cur++ = 0x6C;
388 *(uint32_t *)cur = (uint8_t *)&__dispatchKernelInterrupt - (cur + 4); cur += 4;
389 *cur++ = 0x8B; *cur++ = 0x44; *cur++ = 0x24; *cur++ = 0x2C;
390 *cur++ = 0x89; *cur++ = 0x44; *cur++ = 0x24; *cur++ = 0x78;
391 *cur++ = 0x8B; *cur++ = 0x44; *cur++ = 0x24; *cur++ = 0x58;
392 *cur++ = 0x66; *cur++ = 0x89; *cur++ = 0x44; *cur++ = 0x24;
394 *cur++ = 0x8B; *cur++ = 0x44; *cur++ = 0x24; *cur++ = 0x30;
395 *cur++ = 0x89; *cur++ = 0x84; *cur++ = 0x24; *cur++ = 0x80;
396 *cur++ = 0x00; *cur++ = 0x00; *cur++ = 0x00;
397 *cur++ = 0x8B; *cur++ = 0x7C; *cur++ = 0x24; *cur++ = 0x50;
398 *cur++ = 0x8B; *cur++ = 0x74; *cur++ = 0x24; *cur++ = 0x4C;
399 *cur++ = 0x8B; *cur++ = 0x6C; *cur++ = 0x24; *cur++ = 0x48;
400 *cur++ = 0x8B; *cur++ = 0x5C; *cur++ = 0x24; *cur++ = 0x40;
401 *cur++ = 0x8B; *cur++ = 0x54; *cur++ = 0x24; *cur++ = 0x3C;
402 *cur++ = 0x8B; *cur++ = 0x4C; *cur++ = 0x24; *cur++ = 0x38;
403 *cur++ = 0x8B; *cur++ = 0x44; *cur++ = 0x24; *cur++ = 0x34;
404 *cur++ = 0x83; *cur++ = 0xC4; *cur++ = 0x78;
416 *cur++ = 0xEA; *(uint32_t *)cur = 0; cur += 4;
424 *cur++ = 0x0F; *cur++ = 0x06;
467 gdtTable.
address = (uint32_t)gdtTableEntries;
477 __generateIntJmpTables();
481 struct IDTEntry *entry = &idtTableEntries[i];
494 idtTable.
limit = IDT_MAX_COUNT *
sizeof(
struct IDTEntry) - 1;
495 idtTable.
address = (uint32_t)idtTableEntries;
515 return &gdtTableEntries[i];
540 assert(gdtTableEntries && entry >= gdtTableEntries && entry < gdtTableEntries +
GDT_MAX_COUNT);
542 offset = (uint32_t)entry - (uint32_t)gdtTableEntries;
543 assert((offset & 7) == 0);
545 return offset | ring;
561 entry->
address1 = address & 0x0000FFFF;
562 entry->
address2 = (address & 0x00FF0000) >> 16;
563 entry->
address3 = (address & 0xFF000000) >> 24;
585 assert(length <= 0x100000000);
588 if (length > 0x100000)
601 entry->
limit1 = length & 0x0000FFFF;
602 entry->
limit2 = (length >> 16) & 0xF;
630 uint32_t interrupt, error = 0;
643 args[0] = TSS_user->
eip;
644 args[1] = TSS_user->
cs;
645 args[2] = TSS_user->
eflags;
646 args[3] = TSS_user->
esp;
647 args[4] = TSS_user->
ss;
665 assert((interrupt & ~255) == 0);
702 asm(
".text\n.align 4\n" 703 ".globl tssKernelIdle\n" 705 "__kernelIdleBegin:\n" #define USERMODE_KERNELSTACK_LIMIT
#define USERMODE_IDT_ADDRESS
#define INTJMP_ENTRY_MASK
void * pagingAllocatePhysMemFixedUnpageable(struct process *p, void *addr, uint32_t length, bool rw, bool user)
Allocates several pages of unpageable physical memory at a fixed virtual address in a process...
void * memset(void *ptr, int value, size_t num)
Fills a memory region with some specific byte value.
void * pagingAllocatePhysMemUnpageable(struct process *p, uint32_t length, bool rw, bool user)
Allocates several pages of unpageable physical memory in a process.
uint32_t __kernelIdleBegin
void gdtEntrySetAddress(struct GDTEntry *entry, uint32_t address)
Helper function to set the address inside a GDTEntry.
#define USERMODE_GDT_ADDRESS
struct GDTEntry * gdtGetFreeEntry()
Get a free entry in the GDT.
void gdtReleaseEntry(struct GDTEntry *entry)
Mark a GDTEntry as free.
struct thread * lastFPUthread
void debugCaptureCpuContext(struct taskContext *context)
#define USERMODE_INTJMP_ENABLE_FPU
struct IDTEntry::@7::@9 typeBits
#define USERMODE_KERNELSTACK_ADDRESS
struct GDTEntry * codeRing3
struct GDTEntry * dataRing0
#define INTJMP_ENTRY_SIZE
struct GDTEntry::@0::@1 accessBits
uint32_t gdtGetEntryOffset(struct GDTEntry *entry, uint32_t ring)
Determines the offset of a GDT entry.
uint32_t tssRunUsermodeThread(struct thread *t)
Run a thread.
#define __isErrorCodeInterrupt(i)
#define SYSTEM_FAILURE(lines,...)
struct GDTEntry * dataRing3
void consoleSystemFailure(const char **lines, uint32_t numArgs, uint32_t *args, struct taskContext *context)
Print a system failure message and halts the system.
void __attribute__((cdecl))
#define KERNEL_IDLE_BEGIN
#define INTERRUPT_CONTINUE_EXECUTION
#define INTJMP_ENTRY_BITS
void * intJmpTable_kernel
struct GDTEntry * usermodeTask
void gdtEntrySetLimit(struct GDTEntry *entry, uint64_t length)
Helper function to set the length inside a GDTEntry.
uint32_t dispatchInterrupt(uint32_t interrupt, uint32_t error, struct thread *t)
Handle an incoming interrupt.
struct GDTEntry * kernelTask
struct GDTEntry * codeRing0
void gdtInit()
Initializes the GDT, task registers, and sets up everything required for multiprocessing.
#define USERMODE_TASK_ADDRESS
#define USERMODE_INTJMP_ADDRESS