Task Switching (General protection fault)

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
gardinirafael
Posts: 21
Joined: Mon Feb 03, 2014 12:52 pm

Task Switching (General protection fault)

Post by gardinirafael »

Good day

I have a little problem with task switching (I hope).

My system works without paging on ring 0 only and using 32 bits architecture.

The objective is create a task management for kernel in this first time. The paging and user-mode will be in the future.

My problem appear when the task will change for the new context on schedule function.

After the schedule function execute all tasks and assign the new context, BOCHS show me a (general protection fault) message. task's and schedule function doesn't execute anymore.

Bellow you can find the main functions about this problem.

I no have ideia how to solve this problem, someone can help-me to fix?

Thank in advance.

k_main.c

Code: Select all

/////////////////////////////////////////////////
// Author: 	Rafael Angelo Gardini
// File: 	k_main.c
// Description:	Kernel main
// Last update:	21/06/2012
/////////////////////////////////////////////////

#include "../headers/io/stdio.h"
#include "../headers/io/video.h"
#include "../headers/memory/mm.h"
#include "../headers/process/process.h"
#include "../headers/system/fpu.h"
#include "../headers/system/gdt.h"
#include "../headers/system/idt.h"
#include "../headers/system/irq.h"
#include "../headers/system/isr.h"
#include "../headers/system/kernel.h"
#include "../headers/system/timer.h"

#ifndef K_MAIN

void task0(void)
{
	k_printf("task0\n");

	for(;;);

}

void task1(void)
{
	k_printf("task1\n");

	for(;;);
}

void task2(void)
{
	k_printf("task2\n");

	for(;;);
}

void task3(void)
{
	k_printf("task3\n");

	for(;;);
}

void k_main() 
{
	k_cli_irq();

	k_install_memory();

	k_install_video();

	k_install_gdt();	
	
	k_install_idt();

	k_install_irq();

	k_install_isr();

	k_install_fpu();

	k_install_timer();

	k_install_process();

	k_info_kernel();

	k_sti_irq();

	//---------------------------------------------
	k_create_process(task0);
	k_create_process(task1);
	k_create_process(task2);
	k_create_process(task3);
	//---------------------------------------------

	k_enable_schedule_process();

	k_loop_kernel();
}

#endif
process.c

Code: Select all

/////////////////////////////////////////////////
// Author: 	Rafael Angelo Gardini
// File: 	process.h
// Description:	Process functions
// Last update:	30/09/2013
/////////////////////////////////////////////////

#include "../../headers/io/stdio.h"
#include "../../headers/memory/mm.h"
#include "../../headers/process/process.h"
#include "../../headers/system/irq.h"

#ifndef PROCESS
#define PROCESS

void k_install_process()
{
	process.storepid = 0;
	process.enable = 0;

	process.running = MEMORY_NULL;
	process.task = MEMORY_NULL;

	k_printf("Install process management sucess...\n");
}

int k_create_stack(void (*task)(void))
{
	int stackptr = (int)k_malloc(STACK_SIZE) + STACK_SIZE ;

	unsigned int * stack = (unsigned int*)stackptr;

	*--stack = 0x202;

	*--stack = 0x08;

	*--stack = (unsigned int) task;

	*--stack = 0;
	*--stack = 0;
	*--stack = 0;
	*--stack = 0;
	*--stack = 0;
	*--stack = 0;
	*--stack = 0;
	*--stack = 0;

	*--stack = 0x10;
	*--stack = 0x10;
	*--stack = 0x10;
	*--stack = 0x10;

	return (unsigned int) stack;
}

void k_create_process(void (*task)(void))
{
	k_cli_irq();

	TASK * newtask = (TASK *) k_malloc(sizeof(TASK));

	newtask->stack = k_create_stack(task);

	newtask->status = STOPPED;
	newtask->task = task;
	newtask->pid = process.storepid;

	k_printf("CREATE PID [%d] STACK: [%d] TASK: [%d]\n", newtask->pid, newtask->stack, newtask->task);

	if (process.task == MEMORY_NULL)
	{
		process.task = newtask;
		process.task->next = MEMORY_NULL;
	}
	else
	{
		newtask->next = process.task;
		process.task = newtask;
	}

	process.storepid++;

	k_sti_irq();
}

void k_enable_schedule_process()
{
	process.enable = 1;
}

int k_schedule_process(int context)
{
	if (process.task == MEMORY_NULL)
	{
		return context;
	}

	if (process.running == MEMORY_NULL)
	{
		process.running = process.task;
	}
	else
	{
		process.running->stack = context;

		if (process.running->next != MEMORY_NULL)
		{
			process.running = process.running->next;
		}
		else
		{
			process.running = process.task;
		}
	}

	k_printf("PID %d CONTEXT: %d STACK %d\n", process.running->pid, context, process.running->stack);

	return process.running->stack;
}

void k_kill_process(int pid)
{
	TASK * index = MEMORY_NULL;

	for (index = process.task; index != MEMORY_NULL; index = index->next)
	{
		if (pid == index->pid)
		{
			index->status = KILLED;
		}
	}
}

#endif
process.asm

Code: Select all

[BITS 32]
extern k_schedule_process

global k_switch_process

k_switch_process:
                pusha
                push ds
                push es
                push fs
                push gs

                mov eax, 0x10
                mov ds, eax
                mov es, eax
                mov fs, eax
                mov gs, eax

                mov eax, esp

                push eax
                call k_schedule_process
                mov esp, eax

                mov al, 0x20
                out 0x20, al

                pop gs
                pop fs
                pop es
                pop ds
                popa

                iret

bochs.img
Image
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Task Switching (General protection fault)

Post by Combuster »

My crystal ball claims it's a corrupt stack.

But there's a lot more you can do to narrow the cause - you can print the registers at the time of the crash, as well as the error location and error code. That saves you a lot of guesswork.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
gardinirafael
Posts: 21
Joined: Mon Feb 03, 2014 12:52 pm

Re: Task Switching (General protection fault)

Post by gardinirafael »

Combuster wrote:My crystal ball claims it's a corrupt stack.

But there's a lot more you can do to narrow the cause - you can print the registers at the time of the crash, as well as the error location and error code. That saves you a lot of guesswork.
I printed the registers, but i don't have idea whats the problem.

does memory manager have something rule to create stack? or some place to begin?

because I am using the end of kernel to begin the address (from TLINK file) and I dont use anything rule.

Thank you

Image
User avatar
eryjus
Member
Member
Posts: 286
Joined: Fri Oct 21, 2011 9:47 pm
Libera.chat IRC: eryjus
Location: Tustin, CA USA

Re: Task Switching (General protection fault)

Post by eryjus »

One way to go is to look at your linker map:

For example:

Code: Select all

LD = i586-elf-ld -L bin -T $(LNKS) -Map kernel.map
The file kernel.map will have the starting address of each function. You can look at your EIP (0x100289) and fund the file/function you are in. You will have an offset from your starting function to your IP, which you can find by disassembling your file (i586-elf-objdump or similar). Once you have the exact asm instruction creating the issue, your error code and the Intel software development guides will be really helpful.

Also, change your register output to hex and get used to working with hex.

Good luck!
Adam

The name is fitting: Century Hobby OS -- At this rate, it's gonna take me that long!
Read about my mistakes and missteps with this iteration: Journal

"Sometimes things just don't make sense until you figure them out." -- Phil Stahlheber
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Task Switching (General protection fault)

Post by iansjack »

The value in SS is nonsense. Either you haven't set it correctly or something has changed it. Without a sane stack you are going to have problems.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Task Switching (General protection fault)

Post by Combuster »

Since the GPF comes from kernel land, there'll be no SS/ESP pushed by the exception, and you're looking at other variables on the stack as a result.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
gardinirafael
Posts: 21
Joined: Mon Feb 03, 2014 12:52 pm

Re: Task Switching (General protection fault)

Post by gardinirafael »

Hi guys,
I fix this issue finally.
when kernel.map was generated I could see my mistake.

Between irq and schedule function, I had a sub-function to call my schedule function, so the return address is ever to sub-function and not to new context from my task.

Exemple (with error):

irq_handle() -------call------> sub-function() -------call------> schedule()

I removed the sub-function, the problem was solved.

Exemple (working perfect):

irq_handle() -------call------> schedule()


Guys thank you for all. :lol:
Sorry by my bad english.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Task Switching (General protection fault)

Post by Combuster »

gardinirafael wrote:Between irq and schedule function, I had a sub-function to call my schedule function, so the return address is ever to sub-function and not to new context from my task.
This would be perfectly correct behaviour on my watch. If you saved the state correctly, that subfunction would be just as able to return to its caller after being rescheduled and you wouldn't depend on an exact stack layout.

By the sound of it you've successfully hidden a bug so that it can breed and swarm you later.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
gardinirafael
Posts: 21
Joined: Mon Feb 03, 2014 12:52 pm

Re: Task Switching (General protection fault)

Post by gardinirafael »

Combuster wrote:
gardinirafael wrote:Between irq and schedule function, I had a sub-function to call my schedule function, so the return address is ever to sub-function and not to new context from my task.
This would be perfectly correct behaviour on my watch. If you saved the state correctly, that subfunction would be just as able to return to its caller after being rescheduled and you wouldn't depend on an exact stack layout.

By the sound of it you've successfully hidden a bug so that it can breed and swarm you later.
You are correct and my fault was exactly doesn't save and restore the context correctly.

I had two steps to save the context, first on before to call sub-function by IRQ, second on before to call a task by sub-function and restore all in the end. I didnt do that.

I only saved and restored context from sub-function and task, so the new context stored on my task was trash.

;)
Post Reply