/*
    exDOS - Experimental 32 Bit protected mode scripted operating system
    (C) 2005 Jason Hunt
    
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    Contact: nulluser@gmail.com

    File: process.c
*/


#include "types.h"
#include "process.h"
#include "stdio.h"
#include "video.h"
#include "system.h"
#include "interrupt.h"
#include "mem.h"


process_type *cur_process = NULL;

dword next_pid = 0;

dword save_eax;


bool process_lock = 0;


void process_show_all( void );

void process_show_state(process_type *p);

word last_offset = 0;


/* Setup the inital process in the process ring */
void process_init( void )
{
    // get memory for the process state
    cur_process = (process_type *) kmallocn(sizeof(process_type), "core");
        
    strncpy(cur_process->name, "core", PROCESS_NAME_SIZE); // set process name

    cur_process->pid = next_pid++;
                                    
    cur_process->next = cur_process; // setup inital ring
}
/* end of process_init */


/* Task swapping */
void process_update( void )
{
//puts("update\n");
    cur_process = cur_process->next;           // next task
}
/* End of task_update */



/* This will put a value onto the stack of a process */
void stack_push(process_type *p, dword val)
{
    p->esp -= 4; 
    p->stack[(p->esp - (dword)p->stack) / 4] = val;
}
/* End of stack_push */



/* Adds a task to the ring */
int process_create( void (*process)(void) , char *name)
{
    disable_nmi();     // We absolutly can not have a context switch during this

  //  process_lock = 1;

    // save old pointer to te next process
    process_type *old_next = cur_process->next; 
    process_type *orig_process = cur_process; 

    // get memory for the process table entry
    cur_process->next = (process_type *) kmallocn(sizeof(process_type), "process");

    cur_process = cur_process->next; // set cur_process to the new process area

    cur_process->next = old_next; // complete ring insertion

    // now cur_process is the new process that we are adding
    cur_process->stack = (dword *) kmallocn(STACK_SIZE * sizeof(dword), "stack");

    strncpy(cur_process->name, name, PROCESS_NAME_SIZE); // set process name

    cur_process->pid = next_pid++;

    // Init the stack pointer
    cur_process->esp = (dword)cur_process->stack + STACK_SIZE * sizeof(dword);

    // Setup return frame for the process

    stack_push(cur_process, 0x200);             // eflags, interrupts enabled
    stack_push(cur_process, 0x08);              // Code segment
    stack_push(cur_process, (dword)process);    // eip for new process
                                                // Setup inital registers
    stack_push(cur_process, 0x00);              // eax
    stack_push(cur_process, 0x00);              // ecx
    stack_push(cur_process, 0x00);              // edx
    stack_push(cur_process, 0x00);              // ebx
    stack_push(cur_process, 0x00);              // esp   (not used)
    stack_push(cur_process, 0x00);              // ebp
    stack_push(cur_process, 0x00);              // esi
    stack_push(cur_process, 0x00);              // edi

    // To make sure this process is next in line to get loaded from, and not
    // saved to, we set the current process back to the was it was before we
    // added the new process

    cur_process = orig_process; 

    enable_nmi();

  //  process_lock = 0;

    process_show_all();

    return(0);
}



void process_show_all( void )
{
    if (cur_process == NULL) return;

    process_lock = 1;

    process_type *start = cur_process;
    process_type *cur_show = cur_process;

    printd("Cur: ", cur_process->pid);

    puts("Name              Pid       Addr      Next      Stack     esp\n");

    do
    {
        word pad = 16 - strlen(cur_show->name);

        puts(cur_show->name);
        while (pad--) putchar(' ');             // Pad the name

        puts("  ");
        vga_put_hex_32(cur_show->pid);

        puts("  ");
        vga_put_hex_32((dword)cur_show);

        puts("  ");
        vga_put_hex_32((dword)cur_show->next);

        puts("  ");
        vga_put_hex_32((dword)cur_show->stack);

        puts("  ");
        vga_put_hex_32((dword)cur_show->esp);

        putchar('\n');

        cur_show = cur_show->next;
    }
    while (cur_show != start);

    process_lock = 0;


}



void process1( void )
{
    byte * vga = vga_get_buffer_addr();
    word offset = last_offset;
    last_offset+=2;

    byte v = 0;

    while(1) { vga[offset] = v++;  }
}




void process_test ( void )
{
    process_create(process1, "test process"); 

}










