/* ------------------------------------------------------------------------

 Debugging command format is:
	-command type (ascii char)
	 (g="go", d="delete breakposhort", b="set breakposhort", n="ask data value")
	-process number (ascii char)
	-hex number (break or data address 16- bit offset of the process segment)
	 You have got this offset from linkmap.
	 There is a tool to find this constant when symbolic name is known.

         Example commands:

              b300fc / Stop (break) the process number 3 at address 0x00fc (from link map)
              n3009c / Diplay, the process 3, the contents of the address 0x009c
              b09700 / Break, the kernel (nr 0), the address 0x09700
              g      / go
              d      / delete breaks


OBS----------------->!
If you set a break point in the kernel area, you must understand:
-You can set a break point even in the timer interrupt routine of the kernel
-You leave the debugger only with the command go (g).
-You CAN NOT set a break point to a KERNEL area where you can enter BEFORE
 you leave the debugger (as reading KBD or sending message- 
 because KBD sends a character as a message).
-Simply this means: you can not debug the debugger.
-An other possiblility would be to leave the debugger (go) immediately
 after setting a break (goto "RetFromDebug")- then it would be possible to set a break
 everywhere in the kernel code. You get a general protection fault if
 you violate this rule.
--------------------------------------------------------------------------*/

// This version of the debugger works only if there are no other
// processes waiting on the debuggers mail box KBD/SERIAL_BOX--- 
#include "../includes/inline.h"
#include "../includes/debugger.h"
#include "../includes/kernel.h"
#include "../includes/hw_x86.h"
#include "../includes/lib.h"


extern  long  SOT[];
extern struct MailBoxType MailBox[] ;

void DebugTask( void ) {
char command[20]; // User command from KBD or serial line
   short i,ind,index;
   char c;
   short found;
    
 while(1) {
  outportb(0x21, 0xfd);//Stop the clock - system time is not running  
  outportb(0x20,0x20); //Only KBD interrupt allowed
  index = 0;
  found = FALSE;
  enable();
  string_out(0,5," Entering builtin debugger/ press \"d\" for delete all breaks\"g\" for go!" ); 
    while( !found ) { 
        char_out2('>',160*3+6);
        do { disable();
             c = GetBuff(&MailBox[ (DEVICE==KBD_DEBUG) ? KBD_BOX : SERIAL_BOX]);
	     enable();
           } while( c == -1);// "Nothing doing" loop- waiting user command
        disable();
        if(index==0)for(i=0;i<12;i=i+2)// Clear command buffer
             char_out2(' ',160*3+10+i);
	char_out2('>',160*3+8);
	ind = 2*index;
	if( c) { command[index++] = c;
                 char_out2(c,160*3+10+ind);
               }
	if( index >= 6 || ((index==1) && (c == 'g' || c == 'd' ))) // Command ready
		switch(command[0]) {
		case 'b':{SetBreak(command)  ;index=0;break;} // Seting next breakposhort
		case 'd':{SetBreak("b0000b") ;index=0;break;} // Delete breakposhort
		case 'n':{DispMemory(command);index=0;break;} // Display memory location
		case 'g':{found = TRUE               ;break;} // Go
		default : index = 0;
		}
    } //End debug command loop

 outportb( 0x21, 0xfc);
 outportb(0x20,0x20);
 enable();
 RetFromDebug(); // Return to the system
 } 
}

void SetBreak( char  *c ) {
  long  n, i, hex, task;
  long  reg_eax;
  
  hex  =0;
  n    =0;
  task = (c[1]-'0');
  for(i=0;i<4;i++) 
       hex = (hex<<4) | ((c[2+i] >= 'a')?(short)(c[2+i]-'a'+10):(short)(c[2+i]-'0'));
  reg_eax = (task==0) ? (hex) : (SOT[task-1] + hex);
  
  asm("movl %0,%%eax;
       movl %%eax,%%dr0;
       movl $0x0303,%%eax;
       movl %%eax,%%dr7;
       movl $0,%%eax;
       movl %%eax,%%dr6"
      :
      : "m" (reg_eax)
      : "eax");
}
 
void DispMemory(char *c) {
  long n, i, hex, task;
  long  reg_eax;
  hex  =0;
  
  task = (c[1]-'0');
  for(i=0;i<4;i++) 
       hex = (hex<<4) | ((c[2+i] >= 'a')?(short)(c[2+i]-'a'+10):(short)(c[2+i]-'0'));
 
  reg_eax = (task==0) ? (hex ) : (SOT[task-1] + hex);
  asm("movl %1,%%esi;
       movw (%%esi),%%ax;
       movw %%ax,%0;"
      : "=m"(n)
      : "m"(reg_eax)
      : "eax","esi");

  if(DEVICE == KBD_DEBUG)
    hex_out_core((4*160)+18,n);
  else 
    for(i=0;i<4;i++)
      PutSerial(c[i+2]);
}

void DebugSetup() {      
  long reg_eax;
  reg_eax = (long)Receive;// This is first breakpoint

   asm ("
        movl %0,%%eax;
        movl %%eax,%%dr0;
        movl $0x0303,%%eax;
        movl %%eax,%%dr7;
        movl $0,%%eax;
        movl %%eax,%%dr6;"
       :
       : "m"(reg_eax)
       : "eax");
}

