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
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: 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));
}
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
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;
}
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.