Sunday 11 March 2012

Rebooting Operating System

Eva Os Reboot


                                 How To ReBooT??

Keyboard - reboot via the keyboard controller. The original IBM PC had the CPU reset line tied to the keyboard controller. Writing the appropriate magic value pulses the line and the machine resets. This is all very straightforward, except for the fact that modern machines don't have keyboard controllers (they're actually part of the embedded controller) and even more modern machines don't even pretend to have a keyboard controller. Now, embedded controllers run software. But i am using this method in my Eva Operating System because its the easiest way i came across and right now i dont have any other choice, but in future  i'll try my best to do it with PCI or ACPI.

 // eva.c 
 //      @author<Vishal Mishra><email:vishalmishra.ietjhansi@gmail.com>
//           @change fri-Mar-11,19:01 
void reboot(void)
{
        char temp;

       asm volatile("cli");
        
        /* flush the keyboard controller */
        do 
        {
                temp = inb(0x64);
                if (temp & 1)
                        inb(0x60);
        }while(temp & 2);

        /* send the CPU reset line */
        outb(0x64, 0xFE);

        asm volatile("hlt");
}


Triple Fault -A triple fault is a special kind of exception generated by the CPU when an exception occurs while the CPU is trying to invoke the double fault exception handler, which itself handles exceptions occurring while trying to invoke a regular exception handler.
x86 processors beginning with the 80286 will cause a shutdown cycle to occur when a triple fault is encountered. This typically causes the motherboard hardware to initiate a CPU reset which in turn causes the whole computer to reboot. attempt to generate a triple fault. This is done by loading an empty interrupt descriptor table and then calling int(3). The interrupt fails (there's no IDT), the fault handler fails (there's no IDT) and the CPU enters a condition which should, in theory, then trigger a reset. Except there doesn't seem to be a requirement that this happen and it just doesn't work on a bunch of machines.


PCI - Traditional PCI config space access is achieved by writing a 32 bit value to io port 0xcf8 to identify the bus, device, function and config register. Port 0xcfc then contains the register in question. But if you write the appropriate pair of magic values to 0xcf9, the machine will reboot. Spectacular! And not standardised in any way (certainly not part of the PCI spec), so different chipsets may have different requirements. 


EFI -The Unified Extensible Firmware Interface (UEFI) is a specification that defines a software interface between an operating system and platform firmware.
The original EFI (Extensible Firmware Interface) specification was developed by Intel. In 2005, development of the EFI specification ceased in favor of UEFI, which had evolved from EFI 1.10.
EFI runtime services provide an entry point to reboot the machine. It usually even works! As long as EFI runtime services are working at all, which may be a stretch.


ACPI -the Advanced Configuration and Power Interface (ACPI) specification provides an open standard for device configuration and power management by the operating system.
 Recent versions of the ACPI  let you provide an address (typically memory or system IO space) and a value to write there. The idea is that writing the value to the address resets the system. It turns out that doing so often fails. It's also impossible to represent the PCI reboot method via ACPI, because the PCI reboot method requires a pair of values and ACPI only gives you one.

Wednesday 7 March 2012

Debug Your Operating System(Eva Os)


tty2 screenshot



//tty1
qemu -s -S -kernel /home/vishal/evaos/working/22/kernel -gdb tcp::50022 -vnc :0






//tty2
gdb
(gdb) target remote 127.0.0.1:50022
Remote debugging using 127.0.0.1:50022
0x0000fff0 in ?? ()
(gdb) file /home/vishal/evaos/working/22/kernel
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Reading symbols from /home/vishal/evaos/working/22/kernel...(no debugging symbols found)...done.
(gdb) break eva
Note: breakpoint 1 also set at pc 0x100032.
Breakpoint 2 at 0x100032




//tty3
vncviewer 127.0.0.1

So that's how you can debug your own operating system .I known it gets really frustrating if some error occur and you dont known its location or how to remove it .I hope this will help you out to get out of such situations.



//please feel free to comment //

Thursday 1 March 2012

How to make a Operating System ..The SCreeN(TEXT_MODE+VGA)

Well hello guys ones again!!.Well last time we learned how to make a hello-bootloader, but i'll be using from now on grub as my bootloader so that we can focus more on our kernel.Its also very safe to use grub because we dont have to worry about machine architecture before loading our kernel. 
So let start make our very first module of kernel ...


 The SCREEN Module:


Memory Layout

So we are here interested in 0xB8000-0xBFFFF which constitutes our video memory.Well its just a basic video area which have few  colors only. For VGA(vesa) we have to use A0000 but right now i dont want to discuss these things.
The area of memory known as the framebuffer is accessible just like normal RAM, at address 0xB8000 it controls a screen of characters (not pixels) 80 wide by 25 high.


Printing Character
Okay, so how do we print a character at any x/y location on screen?
A special property about memory is how it is linear. If we reach the end of a line being displayed, the next byte is on the line right below it. Because of linear addressing, we have to be able to convert an x/y location to a linear address to render it to screen. And, a special forumula to do that is: x + y * screen width.






Cursor Position


The framebuffer is just an array of 16-bit words about which we talked above, each 16-bit value representing the display of one character. The offset from the start of the framebuffer of the word that specifies a character at position xy is:

(y * 80 + x) * 2


If you are thinking why its multiplied by two then here is its answer
 because each element is 2 bytes (16 bits) long. If you're indexing an array of 16-bit values, for example, your index would just be x+(y*80)

4 bits for a colour code gives us 15 possible colours we can display:

  • 0 - Black
  • 1 - Blue
  • 2 - Green
  • 3 - Cyan
  • 4 - Red
  • 5 - Magenta
  • 6 - Brown
  • 7 - Light Gray
  • 8 - Dark Gray
  • 9 - Light Blue
  • 10 - Light Green
  • 11 - Light Cyan
  • 12 - Light Red
  • 13 - Light Magenta
  • 14 - Light Brown
  • 15 - White

The VGA controller also has some ports on the main I/O bus, which you can use to send it specific instructions. (Among others) it has a control register at 0x3D4 and a data register at 0x3D5. We will use these to instruct the controller to update it's cursor position.




Now Lets Move to the Implementation Part....


So first define some common things which we will need all the time like 
1:int,char, short long;
2:functions for reading from i/o bus;
3:string manipulation function like string copy,concatenate,compare etc..
4:memory comparison and copy function etc.







// common.h -- Defines typedefs and some global functions.
//           @author<Vishal Mishra><email:vishalmishra.ietjhansi@gmail.com>
//           @change fri-Mar-2,12:01


#ifndef COMMON_H
#define COMMON_H


// Some nice typedefs, to standardise sizes across platforms.
// These typedefs are written for 32-bit X86.
typedef unsigned int   u32int;
typedef          int   s32int;
typedef unsigned short u16int;
typedef          short s16int;
typedef unsigned char  u8int;
typedef          char  s8int;


void outb(u16int port, u8int value);
void outw(u16int port, u16int value);
u8int inb(u16int port);
u16int inw(u16int port);
u32int zkmalloc(u32int sz);
u32int kmalloc_int(u32int sz, int align, u32int *phys);


#endif // COMMON_H















//common.c -- Defines some global functions.
//            @author<Vishal Mishra><email:vishalmishra.ietjhansi@gmail.com>
//            @change fri-Mar-2,12:01


#include "common.h"


// Write a byte out to the specified port.
void outb(u16int port, u8int value)
{
    asm volatile ("outb %1, %0" : : "dN" (port), "a" (value));
}


//write a word to specific port
void outw(u16int port, u16int value)
{
    asm volatile ("outw %1, %0" : : "dN" (port), "a" (value));

}




//Read a byte from a Port
u8int inb(u16int port)
{
    u8int ret;
    asm volatile("inb %1, %0" : "=a" (ret) : "dN" (port));
    return ret;
}

//Read a word from a Port
u16int inw(u16int port)
{
    u16int ret;
    asm volatile ("inw %1, %0" : "=a" (ret) : "dN" (port));
    return ret;
}















// text_mode.h -- Defines the interface for text_mode.h
//           @author<Vishal Mishra><email:vishalmishra.ietjhansi@gmail.com>
//           @change fri-Mar-2,12:01


#ifndef TEXT_MODE_H
#define TEXT_MODE_H


#include "common.h"


//Write a single charactere out to the screen of specific background and forecolour value
void eva_put(char c,u8int backColour,u8int foreColour);


// Write a single character out to the screen.
void eva_puts(char c);


// Clear the screen to 'bg' color code.
void eva_clear(int bg);


// Output a null-terminated ASCII string .
void eva_write(char *c);




#endif // TEXT_MODE_H













// text_mode.c -- Defines functions for writing to the text mode.
//           @author<Vishal Mishra><email:vishalmishra.ietjhansi@gmail.com>
//           @change fri-Mar-2,12:01


#include "text_mode.h"


// The VGA framebuffer starts at 0xB8000.
u16int *video_memory = (u16int *)0xB8000;
// Stores the cursor position.
u8int cursor_x ;
u8int cursor_y ;


// Updates the hardware cursor.
static void move_cursor()
{
    // The screen is 80 characters wide...
    u16int cursorLocation = cursor_y * 80 + cursor_x;
    outb(0x3D4, 14);                  // Tell the VGA board we are setting the high cursor byte.
    outb(0x3D5, cursorLocation >> 8); // Send the high cursor byte.
    outb(0x3D4, 15);                  // Tell the VGA board we are setting the low cursor byte.
    outb(0x3D5, cursorLocation);      // Send the low cursor byte.
}


// Scrolls the text on the screen up by one line.
static void scroll()
{


    // Get a space character with the default colour attributes.
    u8int attributeByte = (0 /*black*/ << 4) | (15 /*white*/ & 0x0F);
    u16int blank = 0x20 /* space */ | (attributeByte << 8);


    // Row 25 is the end, this means we need to scroll up
    if(cursor_y >= 25)
    {
        // Move the current text chunk that makes up the screen
        // back in the buffer by a line
        int i;
        for (i = 0*80; i < 24*80; i++)
        {
            video_memory[i] = video_memory[i+80];
        }


        // The last line should now be blank. Do this by writing
        // 80 spaces to it.
        for (i = 24*80; i < 25*80; i++)
        {
            video_memory[i] = blank;
        }
        // The cursor should now be on the last line.
        cursor_y = 24;
    }
}


// Writes a single character out to the screen.
void eva_put(char c,u8int backColour,u8int foreColour)
{




    // The background colour is black (0), the foreground is white (15).
    


    // The attribute byte is made up of two nibbles - the lower being the 
    // foreground colour, and the upper the background colour.
    u8int  attributeByte = (backColour << 4) | (foreColour & 0x0F);
    // The attribute byte is the top 8 bits of the word we have to send to the
    // VGA board.
    u16int attribute = attributeByte << 8;
    u16int *location;


    // Handle a backspace, by moving the cursor back one space
    if (c == 0x08 && cursor_x)
    {
        cursor_x--;
    }


    // Handle a tab by increasing the cursor's X, but only to a point
    // where it is divisible by 8.
    else if (c == 0x09)
    {
        cursor_x = (cursor_x+8) & ~(8-1);
    }


    // Handle carriage return
    else if (c == '\r')
    {
        cursor_x = 0;
    }


    // Handle newline by moving cursor back to left and increasing the row
    else if (c == '\n')
    {
        cursor_x = 0;
        cursor_y++;
    }
    // Handle any other printable character.
    else if(c >= ' ')
    {
        location = video_memory + (cursor_y*80 + cursor_x);
        *location = c | attribute;
        cursor_x++;
    }


    // Check if we need to insert a new line because we have reached the end
    // of the screen.
    if (cursor_x >= 80)
    {
        cursor_x = 0;
        cursor_y ++;
    }


    // Scroll the screen if needed.
    scroll();
    // Move the hardware cursor.
    move_cursor();


}




void eva_puts(char c)
{


eva_put(c,0,15);




}




// Clears the screen, by copying lots of spaces to the framebuffer.
void eva_clear(int bg)
{

    // Make an attribute byte for the default colours
    u8int attributeByte = (bg /*black*/ << 4) | (15 /*white*/ & 0x0F);
    u16int blank = 0x20 /* space */ | (attributeByte << 8);


    int i;
    for (i = 0; i < 80*25; i++)
    {
        video_memory[i] = blank;
    }


    // Move the hardware cursor back to the start.
    cursor_x = 0;
    cursor_y = 0;
    move_cursor();
}


// Outputs a null-terminated ASCII string to the monitor.
void eva_write(char *c)
{
    int i = 0;
    while (c[i])
    {
        eva_puts(c[i++]);
    }
}


void eva_write_hex(u32int n)
{


s32int tmp;


    eva_write("0x");


    char noZeroes = 1;


    int i;
    for (i = 28; i > 0; i -= 4)
    {
        tmp = (n >> i) & 0xF;
        if (tmp == 0 && noZeroes != 0)
        {
            continue;
        }
    
        if (tmp >= 0xA)
        {
            noZeroes = 0;
            eva_puts (tmp-0xA+'a' );
        }
        else
        {
            noZeroes = 0;
            eva_puts( tmp+'0' );
        }
    }
  
    tmp = n & 0xF;
    if (tmp >= 0xA)
    {
        eva_puts (tmp-0xA+'a');
    }
    else
    {
        eva_puts (tmp+'0');
    }




    
}


void eva_write_dec(u32int n)
{
    if (n == 0)
    {
        eva_puts('0');
        return;
    }


    s32int acc = n;
    char c[32];
    int i = 0;
    while (acc > 0)
    {
        c[i] = '0' + acc%10;
        acc /= 10;
        i++;
    }
    c[i] = 0;


    char c2[32];
    c2[i--] = 0;
    int j = 0;
    while(i >= 0)
    {
        c2[i--] = c[j++];
    }
    eva_write(c2);
}













Moving the cursor(In  move_cursor() Function)

To move the hardware cursor, we must firstly work out the linear offset of the x,y cursor coordinate. We do this by using the equation above. Next, we have to send this offset to the VGA controller. For some reason, it accepts the 16-bit location as two bytes. We send the controller's command port (0x3D4) the command 14 to tell it we are sending the high byte, then send that byte to port 0x3D5. We then repeat with the low byte, but send the command 15 instead.






 VGA mode(pixel):





#ifndef VGA_H
#define VGA_H


void VgaTest(void);
void VgaUpdateMouse(int x, int y);
void VgaDrawString(int x, int y, int reps, char font[8], char color);
void VgaDrawFont(int x, int y, char font[8], int c1);
void VgaDrawWindow(int x, int y, int size);
void VgaDrawRectangle(int x, int y, int w, int h, u8int color);
void vga_draw_vert(int x, int y, int length, u8int color);
void vga_draw_hort(int x, int y, int length, u8int color);
void VgaFillRectangle(int x, int y, int w, int h, u8int color);
void VgaGetFont(char *buffer);
void mode3(void);
void mode13(void);
void VgaClearScreen(void);
void VgaClear(u8int color);
u8int VgaReadPixel(int x, int y);
void VgaDrawPixel(unsigned x, unsigned y, unsigned c);
void VgaSetColor(u8int color, u8int red, u8int green, u8int blue);
#endif











// vga.c
//           @author<Vishal Mishra><email:vishalmishra.ietjhansi@gmail.com>
//           @change fri-Mar-2,12:01
#include "common.h"


#include "vga.h"


int mx, my; // mouse data
char bg;




void VgaSetColor(u8int color, u8int red, u8int green, u8int blue)
{
outb(0x3C8, color);
outb(0x3C9, red);
outb(0x3C9, green);
outb(0x3C9, blue);
}


void VgaDrawPixel(unsigned x, unsigned y, unsigned c)
{
u8int *vga = (u8int*)0xA0000;
int offset = y * 320 + x;
vga[offset] = c;
}


u8int VgaReadPixel(int x, int y)
{
u8int *vga = (u8int*) 0xA0000;
int offset = y * 320 + x;
return vga[offset];
}


void VgaClear(u8int color)
{
int w, h;
for (w = 0; w < 320; w++)
{
for (h = 0; h < 200; h++)
VgaDrawPixel(w, h, color);
}
}


void VgaClearScreen(void)
{
VgaClear(0);
}


void mode13(void)
{
const u8int w[7] = { 0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x28 }; // width = 320
const u8int h[8] = { 0xBF, 0x1F, 0x41, 0x9C, 0x8E, 0x8F, 0x96, 0xB9 }; // height = 200
const u8int w_regs[7] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x13 };
const u8int h_regs[8] = { 0x6, 0x7, 0x9, 0x10, 0x11, 0x12, 0x15, 0x16 };
int i;



outb(0x3C2, 0x63); // mode switch
outw(0x3D4, 0x0E11); // enable registers


for (i = 0; i < 7; i++)
outw(0x3D4, (short)((w[i]<<8)+w_regs[i]));
for (i = 0; i < 8; i++)
outw(0x3D4, (short)((h[i]<<8)+h_regs[i]));
outw(0x3D4, 0x0008);
outw(0x3D4, 0x4014);
    outw(0x3D4, 0xA317);
    outw(0x3C4, 0x0E04);


outw(0x3C4, 0x0101);
    outw(0x3C4, 0x0F02); // enable writing to all planes


    outw(0x3CE, 0x4005); // 256color mode
outw(0x3CE, 0x0506); // graph mode & A000-AFFF

inb(0x3da);
outb(0x3C0, 0x30); 
outb(0x3C0, 0x41);
outb(0x3C0, 0x33);
outb(0x3C0, 0x00);


// EGA Colors
for (i = 0; i < 16; i++)
{
outb(0x3C0, (u8int)i);
outb(0x3C0, (u8int)i);
}
outb(0x3C0, 0x20); // enable video
}








void VgaGetFont(char *buffer)
{
int i;
char *vga = (char *) 0xA0000;
outb(0x3CE, 0x0204);
for (i = 0; i < 0x2000; i++)
buffer[i] = vga[i];
}




void VgaFillRectangle(int x, int y, int w, int h, u8int color)
{
int a, b;
for (a = y; a < (y + h); a++)
{
for (b = x; b < (x + w); b++)
VgaDrawPixel(b, a, color);
}
}




//void VgaDrawRectangle(Rectangle_t *rect, int color)
//{


void vga_draw_hort(int x, int y, int length, u8int color)
{
int a;
for (a = x; a < (x + length); a++)
VgaDrawPixel(a, y, color);
}


void vga_draw_vert(int x, int y, int length, u8int color)
{
int a;
for (a = y; a < (y + length); a++)
VgaDrawPixel(x, a, color);
}


void VgaDrawRectangle(int x, int y, int w, int h, u8int color)
{
vga_draw_hort(x, y, w, color); // Draw top border
vga_draw_hort(x, y+h, w, color); // Draw bottom border


vga_draw_vert(x, y, h, color); // Draw left border
vga_draw_vert(x+w, y, h, color); // Draw right border
}


void VgaDrawWindow(int x, int y, int size)
{
VgaFillRectangle(x, y, size, size, 2); // Green
VgaDrawRectangle(x, y, size, size, 0); // Black
}


void VgaDrawFont(int x, int y, char font[8], int c1)
{
int i, l;
int j = x;
int h = y;
int c;
for (l = 0; l < 8; l++)
{
for (i = 0; i < 8; i++)
{
if ((font[l] & (1<<i)))
c = c1; // New color
else
c = VgaReadPixel(j, h); // Don't overwrite background
VgaDrawPixel(j++, h, c);
}
h++;
j = x;
}
}


void VgaDrawString(int x, int y, int reps, char font[8], char color)
{
int i;
int a = x;
for (i = 0; i < reps; i++)
{
VgaDrawFont(a, y, font, color);
a += 8;
}
}


void VgaUpdateMouse(int x, int y)
{
VgaDrawPixel(mx, my, bg);
VgaDrawPixel(x, y, 0);
mx = x;
my = y;
}


void VgaTest(void)
{
mode13();


char a[10]="hi wassup";

bg = 0;
VgaClear(bg);

VgaDrawWindow(96, 36, 128);






char font_a[8] = {0x18, 0x3C, 0x66, 0x7E,
0x66, 0x66, 0x66, 0x00};
char font_b[8] = {0x7E, 0x66, 0x66, 0x7E,
0x66, 0x66, 0x7E, 0x00 };

 


}




void init_vga(void)
{
VgaTest();


}











Now our main file that will call all function



// eva.c -- Defines the C-code kernel entry point, calls initialisation routines.
//           @author<Vishal Mishra><email:vishalmishra.ietjhansi@gmail.com>
//           @change fri-Mar-2,12:01 


#include "text_mode.h"
#include "vga.h"


int eva(struct multiboot *mboot_ptr)
{
    // Initialise the screen (by clearing it)
    eva_clear(0);
    // Write out a sample string
   
   
     eva_write(" Eva Operating System ....Loading   ");
    eva_put('V',0,4);
 eva_puts('-');
    eva_puts('1');
    //VgaTest();
   //uncomment above statement to switch to vga mode 
   
    
    return 0;
}








Output after compiling and linking ....


Eva Operating System




After uncommenting the VgaTest function output looks like...


  






To compile it use following commands in linux(ubuntu)

1: sudo make -f Makefile
2: qemu -kernel kernel



Reference:
http://www.jamesmolloy.co.uk
http://viralpatel.net/taj/operating-system-tutorial.php
http://www.brokenthorn.com/Resources/