Request for Assistance: Kernel Debugging and Triple Faults

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
ChristianArno1d
Posts: 3
Joined: Sat Aug 11, 2012 6:47 pm

Request for Assistance: Kernel Debugging and Triple Faults

Post by ChristianArno1d »

I'm a novice when it comes to OS Development and I really hate to be that one guy, but I really can't find any solution to the problem I am facing. I hope someone from the community, whom is smarter and more experienced than me, will take the time (and undergo the possible frustration my lack of knowledge may put them through) to help a young aspirational novice programmer.

Here is my dilemma:

I have been following a tutorial, Mixing Assembly and C, in order to kick-start my adventure into the unknown world of OS development. Now I know what you're thinking, why not ask for help from the guy that created the tutorial? Well, that tutorial was created way back in 2003, and there is little possibility he will respond to my email.

I learned a wealth of information from his tutorial, and he explained nearly every line of code that was written in such a manner that was easily understandable for a novice like myself. However, after finishing the final section of the tutorial and following every instruction with great diligence, my efforts left me unsuccessful. I began to have an acquired hatred for the Tripple Fault, the dreaded error that posed itself with every execution of the program.

So far, all I can determine from the bochs debugger is that the error occurs shortly after the instruction from "boot.asm" tells the computer to jump to memory address 0x1000

Here is the code for "boot.asm"

Code: Select all

[BITS 16]      			; We need 16-bit intructions for Real mode

[ORG 0x7C00]    		; The BIOS loads the boot sector into memory location 0x7C00

reset_drive:
        mov ah, 0               ; RESET-command
        int 13h                 ; Call interrupt 13h
        or ah, ah               ; Check for error code
        jnz reset_drive         ; Try again if ah != 0

        mov ax, 0
        mov es, ax
        mov bx, 0x1000          ; Destination address = 0000:1000

        mov ah, 02h             ; READ SECTOR-command
        mov al, 02h             ; Number of sectors to read = 1
        mov ch, 0               ; Cylinder = 0
        mov cl, 02h             ; Sector = 2
        mov dh, 0               ; Head = 0
        int 13h                 ; Call interrupt 13h
        or ah, ah               ; Check for error code
        jnz reset_drive         ; Try again if ah != 0

        cli                     ; Disable interrupts, we want to be alone

        xor ax, ax
        mov ds, ax              ; Set DS-register to 0 - used by lgdt

        lgdt [gdt_desc]         ; Load the GDT descriptor

        mov eax, cr0            ; Copy the contents of CR0 into EAX
        or eax, 1               ; Set bit 0
        mov cr0, eax            ; Copy the contents of EAX into CR0

        jmp 08h:clear_pipe      ; Jump to code segment, offset clear_pipe


[BITS 32]                       ; We now need 32-bit instructions
clear_pipe:
        mov ax, 10h             ; Save data segment identifyer
        mov ds, ax              ; Move a valid data segment into the data segment register
        mov ss, ax              ; Move a valid data segment into the stack segment register
        mov esp, 090000h        ; Move the stack pointer to 090000h

        jmp 08h:01000h          ; Jump to section 08h (code), offset 01000h

gdt:				; Address for the GDT

gdt_null:			; Null Segment
	dd 0
	dd 0

gdt_code: 			; Code Segment, read/execute, nonconforming
	dw 0FFFFh
	dw 0
	db 0
	db 10011010b
	db 11001111b
	db 0

gdt_data: 			; Data Segment, read/write, expand down
	dw 0FFFFh
	dw 0
	db 0
	db 10010010b
	db 11001111b
	db 0

gdt_end:			; Used to calculate the size of the GDT


gdt_desc:			; The GDT descriptor
	dw gdt_end - gdt - 1	; Limit (Size)
	dd gdt			; Address of the GDT

times 510-($-$$) db 0		; Zero out the rest of the sector
	dw 0AA55h		; Bootsector Signature
What should be at 0x1000 is the beginning of kernel.bin which is a linked compilation of three(3) programs: "main.c", "video.c", and "ports.c".

Code for "main.c"

Code: Select all

const char *StartUpMessage;

int *__main;

int main(void)
{
	clearScreen();
	print(StartUpMessage);
	for(;;);
}

const char *StartUpMessage = "Welcome to MyOS.";


Code for "video.c"

Code: Select all

void clearScreen()
{
	unsigned char *vidmem = (unsigned char *)0xB8000;
	const long size = 80*25;
	long loop;

	// Clear visible video memory
	for (loop = 0; loop < size; loop++)
	{
		*vidmem++ = 0;
		*vidmem++ = 0xF;
	}
	
	// Set cursor position to 0,0
	out(0x3D4, 14);
	out(0x3D5, 0);
	out(0x3D4, 15);
	out(0x3D5, 0);
}

void print(const char *_message)
{
	unsigned char *vidmem = (unsigned char *)0xB8000;
	unsigned short offset;
	unsigned long i;

	// Read cursor position
	out(0x3D4, 14);
	offset = in(0x3D5) << 8;
	out(0x3D4, 15);
	offset |= in(0x3D5);

	// One offset for the ASCII and one the color :)
	vidmem += offset*2;

	// Continue writing message until null
	i = 0;
	while (_message[i] != 0)
	{
		*vidmem = _message[i++];
		vidmem += 2;
	}

	// Set new cursor position
	offset += i;
	out(0x3D5, (unsigned char)(offset));
	out(0x3D4, 14);
	out(0x3D5, (unsigned char)(offset >> 8));
}
Code for "ports.c"

Code: Select all

unsigned char in(unsigned short _port)
{
	// "=a" (result) means: put AL register in variable result when finished
  	// "d" (_port) means: load EDX with _port
	
	unsigned char result;
	__asm__ ("in %%dx, %%al" : "=a" (result) : "d" (_port));
	return result;
}

void out(unsigned short _port, unsigned char _data)
{
	// "a" (_data) means: load EAX with _data
  	// "d" (_port) means: load EDX with _port

	__asm__ ("out %%al, %%dx" : :"a" (_data), "d" (_port));
}
Here are the instruction I type into the command prompt to create one file "boot.img"

Code: Select all

nasm C:\MyOS\boot.asm -f bin o- C:\MyOS\boot.bin

gcc -ffreestanding -c main.c -o main.o
gcc -c video.c -o video.o
gcc -c ports.c -o ports.o
ld -e _main -Ttext 0x1000 -o kernel.o main.o video.o ports.o
ld -i -e _main -Ttext 0x1000 -o kernel.o main.o video.o ports.o
objcopy -R .note -R .comment -S -O binary kernel.o kernel.bin

makeboot boot.img boot.bin kernel.bin
According to the tutorial, the ld command is run twice because the first time will tell me if there are any errors during the linking, and the second is to make the link incremental and reduce the size of the file, however, it will not report any errors encountered while linking.

That last command "makeboot" is a program created by the guy who wrote the tutorial.
Here is the source for "makeboot.c"

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argnr, char *args[])
{
  FILE *output, *input;
  int i, bytes_read, sectors_read, bytes_from_file;
  char buffer[512];

  if (argnr < 4) {
    printf("Invalid number of parameters.\n\n");
    printf("USAGE: %s [output] [input 1] [input 2] ... [input n]\n", args[0]);
    printf("Example: %s a.img bootsect.bin kernel.bin");
    exit(0);
  }

  output = fopen(args[1], "r");

  if (output != NULL) {
    buffer[0] = 0;
    while (buffer[0] != 'y' && buffer[0] != 'Y') {
      printf("%s already exists. Overwrite(y/n)? ", args[1]);
      scanf("%s", buffer);
      if (buffer[0] == 'n' || buffer[0] == 'N')
        exit(0);
    }
  }

  fclose(output);
  output = fopen(args[1], "wb");

  for (i = 2; i < argnr; i++) {
    input = fopen(args[i], "rb");

    if (input == NULL) {
      printf("Missing input file %s. Aborting operation...", args[i]);
      fclose(output);
      exit(1);
    }

    bytes_read = 512;
    bytes_from_file = 0;
    sectors_read = 0;

    while(bytes_read == 512 && !feof(input)) {
      bytes_read = fread(buffer, 1, 512, input);

      if (bytes_read == 0)
        break;

      if (bytes_read != 512)
        memset(buffer+bytes_read, 0, 512-bytes_read);

      sectors_read++;
      fwrite(buffer, 1, 512, output);
      bytes_from_file += bytes_read;
    }

    printf("%d sectors, %d bytes read from file %s...\n", sectors_read, bytes_from_file, args[i]);

    fclose(input);
  }

  fclose(output);
  return 0;
}
Then I run "boot.img" in bochs and it triple faults.

If anyone could please help me, it would be much appreciated. If you need anymore details, I would be glad to provide them. Also, I am running Windows 7 64 bit.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Request for Assistance: Kernel Debugging and Triple Faul

Post by gerryg400 »

What should be at 0x1000 is the beginning of kernel.bin which is a linked compilation of three(3) programs: "main.c", "video.c", and "ports.c".
You should disassemble kernel.bin and see what is at the beginning of it. You may be surprised to find that the binary stuff at 0x1000 is not actually the code from main.c but something else. You really need to write some startup code in asm that goes before main, initialises a C environment and calls main for you.

Code: Select all

int *__main;
What's that ?

[edit] I had a quick look at the tutorial. The author does lot's of guessing and even poses questions inline. I'm not sure I'd rely too much on it. There really is no room (or need) for guesswork in this area.
If a trainstation is where trains stop, what is a workstation ?
User avatar
eryjus
Member
Member
Posts: 286
Joined: Fri Oct 21, 2011 9:47 pm
Libera.chat IRC: eryjus
Location: Tustin, CA USA

Re: Request for Assistance: Kernel Debugging and Triple Faul

Post by eryjus »

Your bootstrap also makes BIOS calls before setting up a stack.
Last edited by eryjus on Sun Aug 19, 2012 7:15 pm, edited 1 time in total.
Adam

The name is fitting: Century Hobby OS -- At this rate, it's gonna take me that long!
Read about my mistakes and missteps with this iteration: Journal

"Sometimes things just don't make sense until you figure them out." -- Phil Stahlheber
ChristianArno1d
Posts: 3
Joined: Sat Aug 11, 2012 6:47 pm

Re: Request for Assistance: Kernel Debugging and Triple Faul

Post by ChristianArno1d »

gerryg400 wrote:
What should be at 0x1000 is the beginning of kernel.bin which is a linked compilation of three(3) programs: "main.c", "video.c", and "ports.c".
You should disassemble kernel.bin and see what is at the beginning of it. You may be surprised to find that the binary stuff at 0x1000 is not actually the code from main.c but something else. You really need to write some startup code in asm that goes before main, initialises a C environment and calls main for you.
If only I knew how to do that.. I've been using simple tutorials to learn asm and I've read the first part of a book on it, but I am no where near creating code from thing air yet. I'll definitely look around the internet for help on that, unless you'd be willing to baby me, but I completely understand if you don't. (Maybe I should have never come to this forum)
gerryg400 wrote:

Code: Select all

int *__main;
What's that ?
I really have no clue. When I tried linking all the three files into kernel.o I kept getting an error saying "main.o:main.c:(.text+0xa): undefined reference to `__main" and adding that bit of code seemed to fix the error. However, it was just a guess.
gerryg400 wrote: I had a quick look at the tutorial. The author does lot's of guessing and even poses questions inline. I'm not sure I'd rely too much on it. There really is no room (or need) for guesswork in this area.
With you saying how faulty the tutorial looks, would you recommend that I follow your suggestion from the top of this post and try to fix what I have, or search for a new tutorial and start over?
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Request for Assistance: Kernel Debugging and Triple Faul

Post by bluemoon »

ChristianArno1d wrote:I really have no clue.
Indeed knowing what you have no clue is a good sign. Self-learning skill is definitely core skill for OS development.
Search for the related topic (ie. what's required for C environment and how assembly code interact with C), read the manual, twice.
Some hint for keywords: C99/C11 specification, calling convention, ABI.
Further reading: C bare-bone on osdev wiki.
ChristianArno1d
Posts: 3
Joined: Sat Aug 11, 2012 6:47 pm

Re: Request for Assistance: Kernel Debugging and Triple Faul

Post by ChristianArno1d »

bluemoon wrote:Search for the related topic (ie. what's required for C environment and how assembly code interact with C), read the manual, twice.
Well I have read the first 20 pages or so of PCASM-Book(Download link) from http://www.drpaulcarter.com/pcasm. I'll go back to it and try to finish reading the rest of the 180 pages, I just got impatient and was so eager to just jump right into the programming. I'm a big hands-on learner, and I had taught myself other languages all on my own based on source code and examples, and I was pretty good at it too (I even won some academic programming competitions for my high school), but I suppose OS development is not something that one can just jump in to.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Request for Assistance: Kernel Debugging and Triple Faul

Post by gerryg400 »

To disassemble use objdump. This is an essential tool for low level development and you will be able to see exactly what the tools have done with your code. You can use objdump to see what the various options do to your code and to make sure it looks like it should.
If a trainstation is where trains stop, what is a workstation ?
Tosi
Member
Member
Posts: 255
Joined: Tue Jun 15, 2010 9:27 am
Location: Flyover State, United States
Contact:

Re: Request for Assistance: Kernel Debugging and Triple Faul

Post by Tosi »

If you're just learning assembly then write user-mode applications.
It's a lot easier to debug. Wait until you're better at assembly to write the kernel (if you're going to use it assembly a lot).
sounds
Member
Member
Posts: 112
Joined: Sat Feb 04, 2012 5:03 pm

Re: Request for Assistance: Kernel Debugging and Triple Faul

Post by sounds »

gerryg400 wrote:To disassemble use objdump. This is an essential tool for low level development and you will be able to see exactly what the tools have done with your code. You can use objdump to see what the various options do to your code and to make sure it looks like it should.
After you have a disassembled program and you know which instructions should be there, you might want to use the bochs debugger (or any debugger, since bochs allows you to hook up an external debugger).

Using a debugger like this gives you both the disassembly and the instruction trace.

Step by step:

Code: Select all

$ bochs
00000000000i[     ] ... lots of info about bochs starting up ...
00000000000i[     ] ... lots of info about bochs starting up ...
Next at t=0
(0) [0xfffffff0] f000:fff0 (no symbol): jmp far f000:e05b         ; ea5be000f0
<bochs:1>
Set a breakpoint by typing: b 0x7c00
Then run through the BIOS startup until the breakpoint is reached by typing: c

Code: Select all

<bochs:1> b 0x7c00
<bochs:2> c
(0) Breakpoint 1, 0x00007c00 in ?? ()
Next at t=906300525
(0) [0x00007c00] 0000:7c00 (no symbol): disassembly                    ; hex
<bochs:3> 
If the disassembly is not the first instruction in boot.asm, you have a different problem. I'm betting this part will go smoothly.

From here, you can step one instruction at a time through boot.asm to where it jumps to 0x1000. And you will be able to see what instruction it reaches at 0x1000.

As a shortcut, you can set the breakpoint for 0x1000 using "pb 0x1000" (pb sets a breakpoint that ignores the GDT and just breaks at a physical address of 0x1000). Bochs also has a help command you may find useful.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Request for Assistance: Kernel Debugging and Triple Faul

Post by Combuster »

ChristianArno1d wrote:I have been following a tutorial, Mixing Assembly and C, in order to kick-start my adventure into the unknown world of OS development.
And so...
THE TUTOIAL FROM HELL STRIKES AGAIN


Its known to be broken, and contains a lot of fundamental design errors and teaches really bad coding habits. I suggest you start again with the Tutorials on our wiki - the bare bones are a good start.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Post Reply