3 schedule = page 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
mariuszp
Member
Member
Posts: 587
Joined: Sat Oct 16, 2010 3:38 pm

3 schedule = page fault

Post by mariuszp »

Yeah, again, it's a problem with my multitasking code for Asmadian.

I fork()'ed the kernel process. Then I got a page fault (address 0xF000E752). I decided to check what's up...

Well, I just got my schedule() function to print "schedule!" whenever it is called, and here's what I got:

Code: Select all

fork() returned 0x1 and getpid() returned 0x0
=============================
schedule!
schedule!
schedule!
PAGE FAULT! HOORAY!
Address: 0xf000e752
There are two processes, but the first one (0x0) runs at start, so the first schedule causes it to go to 0x1, then to 0x0 and then to 0x1 again. What caused this error??

Here's all my multitasking code:

Code: Select all

/*

proc.h -- process structures and scheduler.

*/

#ifndef _PROC
#define _PROC

#include "common.h"
#include "kernel.h"
#include "paging.h"
#include "memory.h"
#include "heap.h"

// process states
#define P_ALIVE          0x01
#define P_SLEEP          0x02
#define P_DEAD           0x03

// OR this with the task state to get a daemon/root task
#define P_ROOT           0x80
#define P_DAEMON         P_ROOT

struct process;

struct process
{
	char name[50]; // e.g. KERNEL TASK, or Asmadianet
	int pid;
	u32int eax, ebx, ecx, edx, eip, esp, ebp, esi, edi;
	struct page_directory * pdir;
	u8int state;
	struct process * next;
};

struct process * kernel_proc = NULL;  // also the FIRST process.
struct process * current_proc;        // currently running process
int pid_top = 0;                      // highest pid so far.
u32int ebp;

extern u32int read_eip();

void init_sched();
void schedule();
int fork();
int getpid();
struct process * getproc(int);
struct process * find_free_proc();

void init_sched()
{
	asm volatile ("cli"); // important stuff happening; disabled interrupt!
	print("sched start\n");
	kernel_proc = (struct process *) malloc(sizeof(struct process));
	if (kernel_proc == NULL)
	{
		failure("could not initialise multitasking; out of memory in critical state\n");
	};
	strcpy(kernel_proc->name, "KERNEL TASK");
	kernel_proc->pid = pid_top++;
	kernel_proc->eax = kernel_proc->ebx = kernel_proc->ecx = kernel_proc->edx = kernel_proc->esi = kernel_proc->edi = 0;
	kernel_proc->ebp = kernel_proc->esp = 0;
	kernel_proc->eip = read_eip();
	if (kernel_proc->eip == 0x12345)
	{
		print ("init_sched() success\n");
		return;
	};
	kernel_proc->pdir = kernel_directory;
	kernel_proc->state = P_SLEEP;
	kernel_proc->next = NULL;
	current_proc = kernel_proc;
	asm volatile ("mov $0x12345, %%eax;" : :);
	asm volatile ("sti"); // done with the important stuff.. you can start interrupting!
	print("end sched\n");
};

struct process * find_free_proc()
{
	struct process * proc = kernel_proc;
	while (proc->state != P_DEAD)
	{
		if (proc->next != NULL)
		{
			proc = proc->next;
		} else {
			proc->next = (struct process *) malloc(sizeof(struct process));
			proc = proc->next;
			proc->pid = pid_top++;
			return proc;
		};
	};
	// found a dead process; reuse
	return proc;
};

int fork()
{
	asm volatile ("cli"); // we shall not be interrupted
	struct process * parent_proc = current_proc; // needed so we don't confuse namespaces.
	struct page_directory * pdir = clone_directory(current_directory);
	struct process * proc = find_free_proc();
	int pid = proc->pid; // save
	memcpy(proc, current_proc, sizeof(struct process)); // copy process
	if (parent_proc == current_proc)
	{
		proc->pid = pid;
		proc->next = NULL;
		asm ("sti");
		return pid;
	} else {
		return 0;
	};
};

void schedule()
{
	print("schedule!\n");
	if (kernel_proc == NULL) return;
	u32int esp, ebp, eip;
	asm volatile("mov %%esp, %0" : "=r"(esp));
	asm volatile("mov %%ebp, %0" : "=r"(ebp));
	eip = read_eip();
	if (eip == 0x12345)
	{
		return;
	};
	current_proc->eip = eip;
	current_proc->esp = esp;
	current_proc->ebp = ebp;
	current_proc = current_proc->next;
	if (current_proc->state != P_ALIVE)
	{
		schedule();
		return;
	};
	if (!current_proc) current_proc = kernel_proc;
	esp = current_proc->esp;
	ebp = current_proc->ebp;
	asm volatile("            \ 
	     cli;                 \ 
	     mov %0, %%ecx;       \ 
	     mov %1, %%esp;       \ 
	     mov %2, %%ebp;       \ 
	     mov %3, %%cr3;       \ 
	     mov $0x12345, %%eax; \ 
	     sti;                 \ 
	     jmp *%%ecx           "
		        : : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr));
};

int getpid()
{
	return current_proc->pid;
};

#endif /* _PROC */
Any help? Thanks.
User avatar
piranha
Member
Member
Posts: 1391
Joined: Thu Dec 21, 2006 7:42 pm
Location: Unknown. Momentum is pretty certain, however.
Contact:

Re: 3 schedule = page fault

Post by piranha »

Well, first of all...why this:

Code: Select all

 current_proc = current_proc->next;
   if (current_proc->state != P_ALIVE)
   {
      schedule();
      return;
   };
   if (!current_proc) current_proc = kernel_proc;
It would be better to loop through the linked list until you find a runable task, and then switch to that. Right now, if a task is not runable, you'll store bogus values into eip, etc. I believe that your way is also causing a dereference of a null pointer. So...yeah.

Code: Select all

current_proc = current_proc->next;
while(IS_NOT_RUNNABLE(current_proc)) {
    current_proc = current_proc->next;
    if(!current_proc) current_proc = kernel_proc;
}
Saves CPU too.

Edit: Just noticed...why are you putting functions inside a header file?!

-JL
SeaOS: Adding VT-x, networking, and ARM support
dbittman on IRC, @danielbittman on twitter
https://dbittman.github.io
mariuszp
Member
Member
Posts: 587
Joined: Sat Oct 16, 2010 3:38 pm

Re: 3 schedule = page fault

Post by mariuszp »

Because of the way my kernel is written. I have just one source file, kernel.c, but it only stores kmain(). Is there a problem with that?
mariuszp
Member
Member
Posts: 587
Joined: Sat Oct 16, 2010 3:38 pm

Re: 3 schedule = page fault

Post by mariuszp »

berkus wrote:
mariuszp wrote:Because of the way my kernel is written. I have just one source file, kernel.c, but it only stores kmain(). Is there a problem with that?
Not at all. I heard the best way is to put everything into one single kernel.c file, though.
I'm serious... right now i don't get if you are sarcastic or not..
mariuszp
Member
Member
Posts: 587
Joined: Sat Oct 16, 2010 3:38 pm

Re: 3 schedule = page fault

Post by mariuszp »

Hey, I changed my code now. Now there is some other problem. First the system just crashed when it scheduled the second time. I managed to fix the problem (turned out both processes were sleeping, so the schedule() function fell into an infinite loop). Then a got a page fault, and I tried to do some debugging. I also went through code manually. Something forced me to check the stack location in page fault. Here's what I got:

Code: Select all

Asmadian kernel booting...
initrd OEM name: initrd
sched start
schedule!
current process: KERNEL TASK pid 0x0
EIP: 0x1062C9
end sched
I am parent
fork() returned 0x1 and getpid() returned 0x0
=================
schedule!
current process: FORKED TASK pid 0x1
EIP: 0x106240
PAGE FAULT! HOORAY
Address: 0x1FCE6121
Stack is at 0x10+0x104188
The stack thingy shows segment+offset to stack. You can browse my proc.h source code here:
http://projekt-darma.cba.pl/proc.h.txt
All help appreciated.
Post Reply