Page 1 of 2

reboot in protected mode

Posted: Sun Apr 06, 2008 9:45 am
by Tbeginner
Hello,

I'm from Germany and I'm just a beginner in OS Development.
So I searched the Internet and found a (German) tutorial.
So I have a kernel.asm and a kernel.c from the tutorial. I use GRUB as Bootloader.

Here the files:

kernel.asm

Code: Select all


global loader ; loader für Linker sichtbar machen
extern main   ; main-Funktion des C-Kernels
 
FLAGS    equ 0
MAGIC    equ 0x1BADB002       ; Magicnumber - Erkennungsmerkmal für Grub
CHECKSUM equ -(MAGIC + FLAGS) ; Checksum
 
section .text
align 4
align 4
MultiBootHeader:
  dd MAGIC       ; Magic number
  dd FLAGS       ; Flags
  dd CHECKSUM    ; Checksum
 
loader:
  mov esp,0x200000 ; Stack an die 2MB-Grenze platzieren
  push eax         ; Multiboot Magicnumber auf den Stack legen
  push ebx         ; Adresse der Multiboot-Structure auf den Stack legen
  call main        ; main-Funktion des C-Kernels aufrufen
  
  cli ; falls der Kernel bis hier her kommt, CPU anhalten      
  hlt 

kernel.c

Code: Select all

int main()
{
  // Pointer zum Videospeicher
  char *video = (char*)0xB8000;
  // String zum Ausgeben
  char *hello = "Hello World"; 
 
  // Zuerst den Speicher leeren
  for(video+=4000; video !=(char*)0xB8000 ;video--)
     *video=0;
 
  // String ausgeben
  while (*hello)
 {
    *video = *hello;
    video++;
    *video = 0x07;
    video++;
    hello++;
  } 
   
  // jetzt wo wir schon im Kernel drin sind, wollen wir auch nicht mehr raus ;)
  //while (1); da mit GRUB geladen->nicht nötig	
  return 0;
}

ah, and the linker file

Code: Select all

ENTRY (loader)

SECTIONS{
    . = 0x00100000;

    .text :{
        *(.text)
    }

    .rodata ALIGN (0x1000) : {
        *(.rodata)
    }

    .data ALIGN (0x1000) : {
        *(.data)
    }

    .bss : {
        _sbss = .;
        *(COMMON)
        *(.bss)
        _ebss = .;
    }
}

Now, my problem is quite simple: The OS boots with GRUB and shows the message "Hello World" on the screen. But now the computer do nothing. I want to add a reboot command into the kernel.c (like "Press any key to reboot...") for rebooting the computer after succeeded booting.

But I'm searched and searched and found a lot of code for rebooting, but mostly in assembler (not good for kernel.c :)) and nothing work.

Please help me to find a reboot function for my code because I want to understand these stuff and so I want to add something to see what happens. But only error aren't so great. So please help me and sorry for my (possibly) bad english.

Thanks a lot

The beginner

Posted: Sun Apr 06, 2008 10:03 am
by ucosty
Without writing a driver to control the computer's power management interface your easiest option is to forcibly triple fault the CPU. Loading an IDT with a limit of 0 and call an interrupt should do the trick.

Posted: Sun Apr 06, 2008 10:10 am
by milyges
Use keyboard controller:

Code: Select all

void reboot(void)
{
 unsigned temp;

 do
 {
  temp = inportb(0x64);
  if((temp & 0x01) != 0)
  {
   (void)inportb(0x60);
   continue;
  }
  } while((temp & 0x02) != 0);

  outportb(0x64, 0xFE);
  while(1);
}

Posted: Sun Apr 06, 2008 10:27 am
by einsteinjunior
Add a keyboard device driver for keyboard mangement,
a video driver for display management and an ACPI driver for power management to reboot or other rebooting methods i heard about out there...

Posted: Sun Apr 06, 2008 11:00 am
by Tbeginner
oh great, thanks for this fast answers! (is this correct english ??)

Thanks for the code example and @ucosty:
your easiest option is to forcibly triple fault the CPU
What is the triple fault and how should I integratae it in my kernel.c?

The Beginner

Posted: Sun Apr 06, 2008 11:11 am
by Tbeginner
oh, sorry it should be "integrate" in the previous post.

@milyges:
I tried to integrate your code into my kernel.c:

Code: Select all

void reboot(void)
{
 unsigned temp;

 do
 {
  temp = inportb(0x64);
  if((temp & 0x01) != 0)
  {
   (void)inportb(0x60);
   continue;
  }
  } while((temp & 0x02) != 0);

  outportb(0x64, 0xFE);
  while(1);
}


int main()
{
  // Pointer zum Videospeicher
  char *video = (char*)0xB8000;
  // String zum Ausgeben
  char *hello = "Hello World"; 
 
  // Zuerst den Speicher leeren
  for(video+=4000; video !=(char*)0xB8000 ;video--)
     *video=0;
 
  // String ausgeben
  while (*hello)
 {
    *video = *hello;
    video++;
    *video = 0x07;
    video++;
    hello++;
  } 
   
  // jetzt wo wir schon im Kernel drin sind, wollen wir auch nicht mehr raus ;)
  //while (1); da mit GRUB geladen->nicht nötig	
  reboot();
  return 0;
}
But nothing happened. What is my mistake and btw how I can integrate a function to wait for an pressed key?

The Beginner

Posted: Sun Apr 06, 2008 11:15 am
by einsteinjunior
What is the triple fault and how should I integratae it in my kernel.c?
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.
Some operating systems such as linux use it as a last resource for rebooting.
An example of triple fault generation will be to set the IDT register to o and issuing an interrupt.
But you should try to reboot the pc using the acpi.
Also ,i note that your main problem understanding whats happening is that you do not master the hardware.
Download the intel manuals.You should download volume 1 and volumens 3a and 3b.
That will get you going.

Posted: Sun Apr 06, 2008 11:21 am
by salil_bhagurkar
You probably do not have inportb and outportb functions written in your OS. You should use assembly and code these functions. To write a key wait function you need a keyboard driver. Read on the 8042 keyboard controller and low level keyboard programming.

Posted: Sun Apr 06, 2008 11:30 am
by Tbeginner
mmh, it seems that I should learn more Assembler and that I probably write my own Bootloader (instead of GRUB) and that I write the Kernel also in Assembler. So thanks for the great answers but I must still learn a lot. Maybe you have good manuals ore something else for me? (maybe in German :))

Thanks

The Beginner

Posted: Sun Apr 06, 2008 11:55 am
by bluecode
Tbeginner wrote:Maybe you have good manuals ore something else for me? (maybe in German :)
A german forum with wiki: here. But official documentations/specifications/manuals are always in english.

Posted: Sun Apr 06, 2008 1:37 pm
by codemastersnake
Tbeginner wrote:oh, sorry it should be "integrate" in the previous post.

@milyges:
I tried to integrate your code into my kernel.c:

Code: Select all

void reboot(void)
{
 unsigned temp;

 do
 {
  temp = inportb(0x64);
  if((temp & 0x01) != 0)
  {
   (void)inportb(0x60);
   continue;
  }
  } while((temp & 0x02) != 0);

  outportb(0x64, 0xFE);
  while(1);
}


int main()
{
  // Pointer zum Videospeicher
  char *video = (char*)0xB8000;
  // String zum Ausgeben
  char *hello = "Hello World"; 
 
  // Zuerst den Speicher leeren
  for(video+=4000; video !=(char*)0xB8000 ;video--)
     *video=0;
 
  // String ausgeben
  while (*hello)
 {
    *video = *hello;
    video++;
    *video = 0x07;
    video++;
    hello++;
  } 
   
  // jetzt wo wir schon im Kernel drin sind, wollen wir auch nicht mehr raus ;)
  //while (1); da mit GRUB geladen->nicht nötig	
  reboot();
  return 0;
}
But nothing happened. What is my mistake and btw how I can integrate a function to wait for an pressed key?

The Beginner
You need to write I/O functions (inportb() and outportb())to your code yourself. By the what is the command you are using for compiling your kernel. It seems that you are not using the right flags with you compiler.

Posted: Sun Apr 06, 2008 2:25 pm
by JamesM
Note that keyboard controller reset is slightly broken in one emulator - I forget which one.

Posted: Mon Apr 07, 2008 1:16 am
by Laksen
You can triplefault the computer like this:

Code: Select all

asm
   push dword 0
   push dword 0
   lidt [esp]
   int 3
end;

Posted: Mon Apr 07, 2008 2:39 pm
by Masterkiller
Here is small function with inline assembly, every call to it will cause CPU to reset, when you are in protected mode.

Code: Select all

void reset()
{
  __asm {
    IN al, 0x92
    OR al, 1
    OUT 0x92, al
  }
}
If you want just to reboot without reseting, it is possible if you are not gone to paging, just simple pmode, you could store the old values for segment register, switch to real mode and call INT 19h. I'm have never worked with GRUB and I don't know the way it is going to pmode, but you could try.

Posted: Tue Apr 08, 2008 3:18 am
by Combuster
Masterkiller wrote:Here is small function with inline assembly, every call to it will cause CPU to reset, when you are in protected mode.
Yuck - writes to the fast A20 port. Have you made sure this also works on computers that do *not* support fast A20?