Right now I am in the progress of making a small microkernel. I am going to have it so that programs can run in a normal mode or in a server mode. For the server mode the programs will be able to use the I/O port commands (in and out) to access hardware. I went and tested this by loading a program I compiled that had an in and out instruction in it and I load it and the program runs fine without the eflags having the io flags set in them (bit 12 and bit 13 if I remember correctly) Here is my code for the parts that are relevant:
Code: Select all
task_t * new_task(char * name, void (*start)(), bool io_privilege){
asm volatile ("cli");
task_t *ntask = (task_t*)kmalloc(sizeof(task_t),0,0);
memset(ntask, 0, sizeof(task_t));
strcpy(ntask->name, name);
ntask->dir = copy_page_directory(current_directory);
ntask->pid = npid++;
ntask->start = (uint32_t)start;
ntask->sleep = 0;
ntask->in_buff = cb_new(64);
ntask->files[0].used = 1;
ntask->files[0].node = &stdin_node;
ntask->files[1].used = 1;
ntask->files[1].node = &stdout_node;
ntask->magic = 0xDEADC0DE;
uint32_t * new_stack = (uint32_t*)(kmalloc(0x1000, 1, 0) + 0x1000);
if(io_privilege)kprintf("Privilege\n");
else kprintf("No privilege.\n");
if(io_privilege) *--new_stack = (0x00003202); // eflags
else *--new_stack = 0x00000202; // eflags
*--new_stack = 0x08; // Kerenel code
*--new_stack = (uint32_t)&run;
*--new_stack = 0x00; // edi
*--new_stack = 0x00; // esi
*--new_stack = 0x00; // ebp
*--new_stack = 0x00; // empty
*--new_stack = 0x00; // ebx
*--new_stack = 0x00; // edx
*--new_stack = 0x00; // ecx
*--new_stack = 0x00; // eax
// data segments
*--new_stack = 0x10; // ds
*--new_stack = 0x10; // es
*--new_stack = 0x10; // fs
*--new_stack = 0x10; // gs
ntask->esp0 = (uint32_t)new_stack;
ntask->esp3 = (uint32_t)ustack;
asm volatile ("sti");
return ntask;
}
[global enter_user_mode]
enter_user_mode:
cli
mov ax, 0x23
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, stack
push 0x23
push eax
pushf
pop eax
or eax, 0x200
push eax
push 0x1B
mov eax, [esp + 20]
push eax
iret
[global gdt32_install]
gdt32_install:
GDT_ENTRY GDT32.Null, 0, 0, 0, 0
GDT_ENTRY GDT32.Kernel_Code, 0, 0xFFFFFFFF, 0x9A, 0xCF
GDT_ENTRY GDT32.Kernel_Data, 0, 0xFFFFFFFF, 0x92, 0xCF
GDT_ENTRY GDT32.User_Code, 0, 0xFFFFFFFF, 0xFA, 0xCF
GDT_ENTRY GDT32.User_Data, 0, 0xFFFFFFFF, 0xF2, 0xCF
GDT_ENTRY GDT32.TSS, TSS32, TSS32+26*4, 0xE9, 0
mov word [GDT32.Pointer], 6*8
mov dword [GDT32.Pointer+2], GDT32
lgdt [GDT32.Pointer] ; Load 32-bit GDT
mov ax, GDT32.Kernel_Data
mov ds, ax ; Load all data segment selectors
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08: GDT32Loaded ; Set the code segment and do a far jump!
GDT32Loaded:
call tss32_init
ret
Any input would be greatly appreciated because this one has got me stumped I just create a new task and make it so it isn't a server and doesn't have those bits set and the loaded programs that use the in and out don't cause the General Protection Fault like I thought they would.
Thanks,
Alex