Placing kernel in 4MB in RAM on real hardware.

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.
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Placing kernel in 4MB in RAM on real hardware.

Post by Waszka »

Hi all,
I'm new to the forum and this is my first post.
I've been trying to write my own simple kernel, and I'm following BrokenThorn Entertainment tutorial.
Right now I'm somewhere after FDC programming, and on Bochs (VirtualBox too) everything works fine.
I managed to implement Virtual Memory Manager, and mapped my kernel address (0xc0000000) to 4MB in RAM (0x400000).
Right now I have two page tables in memory: one for addresses [0x0 - 0x400000] identity mapped, and the other one for addresses [0xc0000000 - 0xc0400000] mapped to 0x400000 - 0x800000 (next 4MB).
The problem is, this does not work on real hardware. Immediately after I do sti() (enable interrupts) I get General Protection Fault.
The problem does not occur when I map addresses [0xc0000000 - 0xc0400000] to 0x100000 - 0x500000 which is, for me, quite strange.

I set up everything (after far jump) like that:

Code: Select all

mov ax, 0x10
	mov ds, ax
	mov es, ax
	mov fs,ax
	mov gs,ax
	mov ss, ax	
	mov esp, 0xC0300000
Paging is done like that:

Code: Select all

   //! 1st 4mb are idenitity mapped
   for( i=0, frame=0x0, virt=0x00000000; i<1024; i++, frame+=4096, virt+=4096) {

      //! create a new page
      unsigned int page=0;
      st_wpis_dodaj_atryb (&page, I86_PTE_PRESENT);
      st_wpis_ustaw_ramke (&page, frame);

      //! ...and add it to the page table
      table2->m_entries [INDEKS_TABLICY_STRON (virt) ] = page;
   }

   // mapping for my kernel
   for( i=0, frame=0x400000, virt=0xc0000000; i<1024; i++, frame+=4096, virt+=4096) {

      //! create a new page
      unsigned int page=0;
      st_wpis_dodaj_atryb (&page, I86_PTE_PRESENT);
      st_wpis_ustaw_ramke (&page, frame);

      //! ...and add it to the page table
      table->m_entries [INDEKS_TABLICY_STRON (virt) ] = page;
   }
If any more code is required I'd be happy to paste it here. :)
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Re: Placing kernel in 4MB in RAM on real hardware.

Post by Waszka »

One thing: should I reload GDT after I enter kernel land?
Because I saw that many people do so, but when I implemented it, it runs in Bochs - on real hardware it's intstant Triple Fault.
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

Re: Placing kernel in 4MB in RAM on real hardware.

Post by BASICFreak »

If you are following and using brokenthorn's bootsector, remember his stage two loads kernel at 0x100000 (1MB) with a virtual address of 0xC0000000 (3GB)

And he states 0x0 - 0x400000 is mapped to 0x0 - 0x400000 and 0xC0000000 mapped to 0x100000

EDIT:
And yes you SHOULD load GDT after far jump to Kernel.

this is my initialization code snippit:

Code: Select all

gdt_install ();
idt_install ();
isrs_install ();
irq_install ();
initVideo ();
readCMOS ();
install_keyboard();
timer_install ();
initPHYSMEM();
init_pageFault();
vmmngr_initialize ();
__asm__ __volatile__ ("sti");					//DON'T FROGET TO RE-ENABLE INTS OR NOTHING WILL WORK RIGHT!!!!
floppy_install ();
fsysFatInitialize ();
*yes I know I need to uniform my function names :shock:
BOS Source Thanks to GitHub
BOS Expanded Commentary
Both under active development!
Sortie wrote:
  • Don't play the role of an operating systems developer, be one.
  • Be truly afraid of undefined [behavior].
  • Your operating system should be itself, not fight what it is.
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Re: Placing kernel in 4MB in RAM on real hardware.

Post by Waszka »

BASICFreak wrote:If you are following and using brokenthorn's bootsector, remember his stage two loads kernel at 0x100000 (1MB) with a virtual address of 0xC0000000 (3GB)

And he states 0x0 - 0x400000 is mapped to 0x0 - 0x400000 and 0xC0000000 mapped to 0x100000
Yes, yes I do the following:

Code: Select all

%define IMAGE_PMODE_BASE 0xC0000000
;************************
	; Set Registers
	;************************

	mov	ax, DATA_DESC		; set data segments to data selector (0x10)
	mov	ds, ax
	mov	ss, ax
	mov	es, ax
	mov	esp, 90000h

	call	EnablePaging

	;**********************************
	; Kernel loaded under 4MB 
	;**********************************
        [....] ; some code here
        jmp	CODE_DESC:IMAGE_PMODE_BASE
I noticed that my kernel boots from time to time on real hardware - it's just like I don't clear memory somewhere?
Also, when trying to load GDT just like in Broken Thorn Enterteinment tutorial:

Code: Select all

#include "gdt_bib.h"

//! processor gdtr register points to base of gdt. This helps
//! us set up the pointer
struct gdtr {

	//! size of gdt
	unsigned short		m_limit;

	//! base address of gdt
	unsigned int		m_base;
}__attribute__((packed));


//! global descriptor table is an array of descriptors
static gdt_descriptor	_gdt [MAX_DESCRIPTORS];

//! gdtr data
static struct gdtr		_gdtr;

//! install gdtr
static void gdt_install ();

//============================================================================
//    IMPLEMENTATION PRIVATE FUNCTIONS
//============================================================================

//! install gdtr
static void gdt_install () {
	asm(".intel_syntax noprefix\n\t"
		"invd		\n"
		"lgdt [_gdtr]\n"
		".att_syntax prefix");
}



//! Setup a descriptor in the Global Descriptor Table
void gdt_set_descriptor(unsigned int i, unsigned long base, unsigned long limit, unsigned char access, unsigned char grand)
{
	if (i > MAX_DESCRIPTORS)
		return;

	//! null out the descriptor
	memset ((void*)&_gdt[i], 0, sizeof (gdt_descriptor));

	//! set limit and base addresses
	_gdt[i].baseLo	= (unsigned short)(base & 0xffff);
	_gdt[i].baseMid	= (unsigned char)((base >> 16) & 0xff);
	_gdt[i].baseHi	= (unsigned char)((base >> 24) & 0xff);
	_gdt[i].limit	= (unsigned short)(limit & 0xffff);

	//! set flags and grandularity bytes
	_gdt[i].flags = access;
	_gdt[i].grand = (unsigned char)((limit >> 16) & 0x0f);
	_gdt[i].grand |= grand & 0xf0;
}


//! returns descriptor in gdt
gdt_descriptor* i86_gdt_get_descriptor (int i) {

	if (i > MAX_DESCRIPTORS)
		return 0;

	return &_gdt[i];
}


//! initialize gdt
int i86_gdt_initialize () {

	//! set up gdtr
	_gdtr.m_limit = (sizeof (gdt_descriptor) * MAX_DESCRIPTORS)-1;
	_gdtr.m_base = (unsigned int)&_gdt[0];

	//! set null descriptor
	gdt_set_descriptor(0, 0, 0, 0, 0);

	//! set default code descriptor
	gdt_set_descriptor (1,0,0xffffffff,
		I86_GDT_DESC_READWRITE|I86_GDT_DESC_EXEC_CODE|I86_GDT_DESC_CODEDATA|I86_GDT_DESC_MEMORY,
		I86_GDT_GRAND_4K | I86_GDT_GRAND_32BIT | I86_GDT_GRAND_LIMITHI_MASK);

	//! set default data descriptor
	gdt_set_descriptor (2,0,0xffffffff,
		I86_GDT_DESC_READWRITE|I86_GDT_DESC_CODEDATA|I86_GDT_DESC_MEMORY,
		I86_GDT_GRAND_4K | I86_GDT_GRAND_32BIT | I86_GDT_GRAND_LIMITHI_MASK);

	//! install gdtr
	gdt_install ();

	return 0;
}

Code: Select all

#define gdt_descriptor struct gdt_descriptor
//! maximum amount of descriptors allowed
#define MAX_DESCRIPTORS					3

/***	 gdt descriptor access bit flags.	***/

//! set access bit
#define I86_GDT_DESC_ACCESS			0x0001			//00000001

//! descriptor is readable and writable. default: read only
#define I86_GDT_DESC_READWRITE			0x0002			//00000010

//! set expansion direction bit
#define I86_GDT_DESC_EXPANSION			0x0004			//00000100

//! executable code segment. Default: data segment
#define I86_GDT_DESC_EXEC_CODE			0x0008			//00001000

//! set code or data descriptor. defult: system defined descriptor
#define I86_GDT_DESC_CODEDATA			0x0010			//00010000

//! set dpl bits
#define I86_GDT_DESC_DPL			0x0060			//01100000

//! set "in memory" bit
#define I86_GDT_DESC_MEMORY			0x0080			//10000000

/**	gdt descriptor grandularity bit flags	***/

//! masks out limitHi (High 4 bits of limit)
#define I86_GDT_GRAND_LIMITHI_MASK		0x0f			//00001111

//! set os defined bit
#define I86_GDT_GRAND_OS			0x10			//00010000

//! set if 32bit. default: 16 bit
#define I86_GDT_GRAND_32BIT			0x40			//01000000

//! 4k grandularity. default: none
#define I86_GDT_GRAND_4K			0x80			//10000000


//! gdt descriptor. A gdt descriptor defines the properties of a specific
//! memory block and permissions.

gdt_descriptor {

	//! bits 0-15 of segment limit
	unsigned short		limit;

	//! bits 0-23 of base address
	unsigned short		baseLo;
	unsigned char			baseMid;

	//! descriptor access flags
	unsigned char			flags;

	unsigned char			grand;

	//! bits 24-32 of base address
	unsigned char			baseHi;
}__attribute__((packed));


//! Setup a descriptor in the Global Descriptor Table
void gdt_set_descriptor(unsigned int, unsigned long , unsigned long , unsigned char , unsigned char);

//! returns descritor
gdt_descriptor* i86_gdt_get_descriptor (int i);

//! initializes gdt
int i86_gdt_initialize ();
I get instatnt Triple Fault on my computer (real hardware). It does not occur in bochs or VirtualBox.

Also, the GPF occurs always when I do sti(). It does not matter if it's after enabling Paging in kernel, or MemoryManager, or anything.
I just have to prepare IDT (otherwise Triple Fault), and then I get GPF.

I'll try to look into it deeper this evening, but any guesses would be appreciated. :)
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: Placing kernel in 4MB in RAM on real hardware.

Post by jnc100 »

Waszka wrote:Also, the GPF occurs always when I do sti(). It does not matter if it's after enabling Paging in kernel, or MemoryManager, or anything.
I just have to prepare IDT (otherwise Triple Fault), and then I get GPF.
1) What is the error code of the GP fault?
2) What is the return EIP when it is triggered?

My guess is a stale interrupt (probably keyboard or timer) being signaled when you do sti that you haven't installed a handler for.

How have you set up your IDT and PIC?

Regards,
John.
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

Re: Placing kernel in 4MB in RAM on real hardware.

Post by BASICFreak »

Did you remember to remap your interrupts?
Bran's Kernel Development Tutorial wrote:/* Normally, IRQs 0 to 7 are mapped to entries 8 to 15. This
* is a problem in protected mode, because IDT entry 8 is a
* Double Fault! Without remapping, every time IRQ0 fires,
* you get a Double Fault Exception, which is NOT actually
* what's happening. We send commands to the Programmable
* Interrupt Controller (PICs - also called the 8259's) in
* order to make IRQ0 to 15 be remapped to IDT entries 32 to
* 47 */
remap eg.

Code: Select all

outb(0x20, 0x11);
outb(0xA0, 0x11);
outb(0x21, 0x20);
outb(0xA1, 0x28);
outb(0x21, 0x04);
outb(0xA1, 0x02);
outb(0x21, 0x01);
outb(0xA1, 0x01);
outb(0x21, 0x0);
outb(0xA1, 0x0);
@jnc100 - beat me to it =D>
BOS Source Thanks to GitHub
BOS Expanded Commentary
Both under active development!
Sortie wrote:
  • Don't play the role of an operating systems developer, be one.
  • Be truly afraid of undefined [behavior].
  • Your operating system should be itself, not fight what it is.
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Re: Placing kernel in 4MB in RAM on real hardware.

Post by Waszka »

Thanks for the reply. I checked everything and it was ok.
The problem is somwhere else, and I'm ashamed I didn't see that... :oops:

The GPF was caused by Page Fault! Further investigating showed that:
Int number: 14 [ Page Fault ]
ESP: 0xC002FD78
Error Code: 0
Physical address that caused an error was: 0x03826FE4?!
Really, I don't know how's that possible :P
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: Placing kernel in 4MB in RAM on real hardware.

Post by jnc100 »

If there is garbage in the IDT entry for a particular interrupt, then when that interrupt is signaled a page fault will occur.

Once again: have you remapped the PIC?
Have you installed dummy handlers for all possible IRQs and exceptions? This will greatly aid your debugging.

Regards,
John.
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Re: Placing kernel in 4MB in RAM on real hardware.

Post by Waszka »

jnc100 wrote:If there is garbage in the IDT entry for a particular interrupt, then when that interrupt is signaled a page fault will occur.

Once again: have you remapped the PIC?
Have you installed dummy handlers for all possible IRQs and exceptions? This will greatly aid your debugging.

Regards,
John.

Yes, yes, I did it:

Code: Select all

 /* Normally, IRQs 0 to 7 are mapped to entries 8 to 15. This
*  is a problem in protected mode, because IDT entry 8 is a
*  Double Fault! Without remapping, every time IRQ0 fires,
*  you get a Double Fault Exception, which is NOT actually
*  what's happening. We send commands to the Programmable
*  Interrupt Controller (PICs - also called the 8259's) in
*  order to make IRQ0 to 15 be remapped to IDT entries 32 to
*  47 */
void irq_remap()
{
    outportb(0x20, 0x11);
    outportb(0xA0, 0x11);	// ICW 1
    outportb(0x21, 0x20);
    outportb(0xA1, 0x28);	// ICW 2
    outportb(0x21, 0x04);
    outportb(0xA1, 0x02);	// ICW 3
    outportb(0x21, 0x01);
    outportb(0xA1, 0x01);	// ICW 4
    outportb(0x21, 0x0);
    outportb(0xA1, 0x0);
}

Code: Select all

void instaluj_irq()
{
    irq_remap();

    install_interrupt(32, (unsigned)irq0, SEL_KODU, FLAGI);
    install_interrupt(33, (unsigned)irq1, SEL_KODU, FLAGI);
    install_interrupt(34, (unsigned)irq2, SEL_KODU, FLAGI);
    install_interrupt(35, (unsigned)irq3, SEL_KODU, FLAGI);
    install_interrupt(36, (unsigned)irq4, SEL_KODU, FLAGI);
    install_interrupt(37, (unsigned)irq5, SEL_KODU, FLAGI);
    install_interrupt(38, (unsigned)irq6, SEL_KODU, FLAGI);
    install_interrupt(39, (unsigned)irq7, SEL_KODU, FLAGI);

    install_interrupt(40, (unsigned)irq8, SEL_KODU, FLAGI);
    install_interrupt(41, (unsigned)irq9, SEL_KODU, FLAGI);
    install_interrupt(42, (unsigned)irq10, SEL_KODU, FLAGI);
    install_interrupt(43, (unsigned)irq11, SEL_KODU, FLAGI);
    install_interrupt(44, (unsigned)irq12, SEL_KODU, FLAGI);
    install_interrupt(45, (unsigned)irq13, SEL_KODU, FLAGI);
    install_interrupt(46, (unsigned)irq14, SEL_KODU, FLAGI);
    install_interrupt(47, (unsigned)irq15, SEL_KODU, FLAGI);
}

Code: Select all

void  install_interrupt(unsigned char i, unsigned long baza, unsigned short sel, unsigned char flagi) {
	_idt[i].baseLo = (unsigned short)(baza & 0xffff);
	_idt[i].baseHi = (unsigned short)((baza >> 16) & 0xffff);
	_idt[i].reserved = 0;
	_idt[i].flags = (unsigned char)(flagi);
	_idt[i].sel = sel;
}
Here are my IRQ routines:

Code: Select all

void *irq_handlers[16] =
{
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0
};
EDIT:: The problem is probably caused by spurious IRQ 7 (maybe 15 too).
Handling them in a special way solved problem of Page Fault - but now I have problems with my IRQ0 routine - somehow tic_counter gets corrupted, and sometimes causes Triple Fault.
What's more, I can't get IRQ from Floppy Disk. :/
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

Re: Placing kernel in 4MB in RAM on real hardware.

Post by BASICFreak »

Well, I was going to ask about IRSs but I removed them on my kernel and it worked

can I see your startup asm script and your main() function.

So far I'm at a loss as all the code you have provided looks like it will work.
BOS Source Thanks to GitHub
BOS Expanded Commentary
Both under active development!
Sortie wrote:
  • Don't play the role of an operating systems developer, be one.
  • Be truly afraid of undefined [behavior].
  • Your operating system should be itself, not fight what it is.
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Re: Placing kernel in 4MB in RAM on real hardware.

Post by Waszka »

BASICFreak wrote:Well, I was going to ask about IRSs but I removed them on my kernel and it worked

can I see your startup asm script and your main() function.

So far I'm at a loss as all the code you have provided looks like it will work.
Yes! I'm very glad to hear that somebody is eager to help me, since this problems is driving me crazy :P

Here is the start.asm:

Code: Select all

[BITS 32]
global _start
jmp    _start

;*******************************************************
;	Biblioteki
;*******************************************************
 %include "Biblioteki/was_asm.asm"	   ; hal (isr + irq, etc...)
;*******************************************************
;	Program
;*******************************************************

_start:
	cli	

	EXTERN 	rozm_jadra
	mov dword [rozm_jadra], edx 	; the size of our kernel

	mov ax, 10h
	mov ds, ax
	mov es, ax
	mov fs,ax
	mov gs,ax
	mov ss, ax

	pop eax				       ; this is a must because eax has memory structure within it
	
	mov esp, 0xC0300000		;stack
	mov ebp, esp

	push eax	
	mov ax, 10h
	
 	EXTERN start_jadra 		;kernel start
 	call start_jadra
	jmp $
Then comes my main:

Code: Select all

#include "../Biblioteki/trzon_bib.h"
#include "../Biblioteki/napisy_bib.h"
#include "../Biblioteki/wewy_bib.h"
#include "../Biblioteki/was_bib.h"
#include "../Biblioteki/klaw_bib.h"
#include "../Biblioteki/pammen_bib.h"
#include "../Biblioteki/pammen_wirt_bib.h"
#include "../Biblioteki/dyskietka_bib.h"

unsigned short* ekran = (unsigned short*)0xB8000;   // screen address
extern int glob_kolor;			                             // global font colour
extern char* strMemoryTypes[];

/* Start naszego jądra! */
void start_jadra(struct multiboot_info* meminfo)
{
/* Ustawiamy zmienne globalne */
  glob_kolor=ustaw_kolory(7, 0);
  bootinfo = meminfo;				
  region = (struct region_pamieci*)0x1000;	// memory regions
						

/* KONIEC SEKCJI DANYCH */

/* Inicjalizacja */
  inicjalizuj_idt();				       // IDT init
  inicjuj_video(ekran, glob_kolor);	       // screen init 
  inicjuj_menedzera_pamieci(region);     // Memory Manager init
  pammen_wirt_inicjalizuj ();		       // virtual memory init
  pammen_realokuj_regiony(&region);   // realoc the memory structure, because DMA sends bytes to 0x1000

/* SEKCJA KODU */

/* Przywracamy przerwania */
  sti();                                 

/* Instalacja urządzeń */
  instaluj_dyskietke();				// FDD init

/* Oczekujemy na komendy */
   wypiszk((unsigned char*)"\n> ", ekran, -1);  // command prompt
   test_klawiatury();                                         // inisde it we have infinite loop waiting for commands

/* PAMIETAJ O NIESKONCZONEJ PETLI! */
    for (;;);                                                       // precautions :D    
}
Here is my linker script:

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(_start)
phys = 0xC0000000;
SECTIONS
{
  .text phys : AT(phys) {
    code = .;
    *(.text)
    *(.rodata)
    . = ALIGN(4096);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
  end = .;
}
Here what I added to my IRQ 7 and IRQ 15 problems:

Code: Select all

void irq_handler(struct regs *r)
{
    /* This is a blank function pointer */
    void (*handler)(struct regs *r);

    /* Find out if we have a custom handler to run for this
    *  IRQ, and then finally, run it */
    handler = irq_obsluga[r->int_no - 32];
    if (r->int_no != 39 && r->int_no != 47 && handler)
    {
        handler(r);
    }

    /* Error IRQ 7 lub IRQ 15 */
    if(r->int_no == 39 || r->int_no == 47) {
 	 outportb(0x20, 0x0B); 
	 unsigned char irr = inportb(0x20);
	 if(!(irr & 0x80)) return;                       // the interrupt was not real one (no need to send EOI)
    }
    /* If the IDT entry that was invoked was greater than 40
    *  (meaning IRQ8 - 15), then we need to send an EOI to
    *  the slave controller */
    if (r->int_no >= 40)
    {
        outportb(0xA0, 0x20);
    }

    /* In either case, we need to send an EOI to the master
    *  interrupt controller too */
    outportb(0x20, 0x20);
}
Right now, after implementing these changes I get Page Fault after entering: test_klawiatury(); in main() function,
which is some kind of improvement, but still I'm not satisfied with it. I noticed that I also get corrupted variable that is incremented every clock tick (inside IRQ0)
even if it's zero'ed before installing IRQ (it is also zero in definition).
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

Re: Placing kernel in 4MB in RAM on real hardware.

Post by BASICFreak »

http://www.brokenthorn.com/Resources/OSDev8.html
Section = PMode Memory Addressing

Correct me if I'm wrong but it looks like you didn't select what descriptor to use after GDT setup

Code: Select all

_gdt_flush:
 lgdt [_gp]        						; Load the GDT with our '_gp' which is a special pointer
 mov ax, 0x10      						; 0x10 is the offset in the GDT to our data segment
 mov ds, ax
 mov es, ax
 mov fs, ax
 mov gs, ax
 mov ss, ax
 jmp 0x08:flush2   						; 0x08 is the offset to our code segment: Far jump!


flush2:
 ret
in your case it is an addition to "static void gdt_install ()", I suggest have this in your main ASM file and call it where you called gdt_install()
BOS Source Thanks to GitHub
BOS Expanded Commentary
Both under active development!
Sortie wrote:
  • Don't play the role of an operating systems developer, be one.
  • Be truly afraid of undefined [behavior].
  • Your operating system should be itself, not fight what it is.
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Re: Placing kernel in 4MB in RAM on real hardware.

Post by Waszka »

BASICFreak wrote:http://www.brokenthorn.com/Resources/OSDev8.html
Section = PMode Memory Addressing

Correct me if I'm wrong but it looks like you didn't select what descriptor to use after GDT setup

Code: Select all

_gdt_flush:
 lgdt [_gp]        						; Load the GDT with our '_gp' which is a special pointer
 mov ax, 0x10      						; 0x10 is the offset in the GDT to our data segment
 mov ds, ax
 mov es, ax
 mov fs, ax
 mov gs, ax
 mov ss, ax
 jmp 0x08:flush2   						; 0x08 is the offset to our code segment: Far jump!


flush2:
 ret
in your case it is an addition to "static void gdt_install ()", I suggest have this in your main ASM file and call it where you called gdt_install()
Ok, I'll do that, but I have my GDT loaded during Stage2 (it is loaded somewhere after 0x500 - 0x600). It always worked, and on bochs and VirtualBox it is working too.
But I'll implement it, and tell You what happens ;)

Ok I made this change:

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; start.asm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; To stanowi tylko "wstęp" do naszego kernela
; ustawiamy najważniejsze rzeczy i do dzieła!


[BITS 32]
global _start
jmp    _start

;*******************************************************
;	Biblioteki
;*******************************************************
 %include "Biblioteki/was_asm.asm"	; obsługa WAS (HAL)
 %include "Biblioteki/gdt.asm"
;*******************************************************
;	Program
;*******************************************************

_start:
	cli
	call SetGDT
       [.... rest of the code..... ]
       lea ebx, [jadro]
	call ebx

jadro:
	jmp 0x8:fix_cs
fix_cs:

    [... rest of code....]
and in gdt.asm:

Code: Select all

[BITS 32]

SetGDT:

cli
pusha
lgdt [toc]
popa
ret

;*******************************************
; Global Descriptor Table (GDT)
;*******************************************
 
gdt_data: 
	dd 0 				; null descriptor
	dd 0 
 
; gdt code:				; code descriptor
	dw 0FFFFh 			; limit low
	dw 0 				; base low
	db 0 				; base middle
	db 10011010b 			; access
	db 11001111b 			; granularity
	db 0 				; base high
 
; gdt data:				; data descriptor
	dw 0FFFFh 			; limit low (Same as code)
	dw 0 				; base low
	db 0 				; base middle
	db 10010010b 			; access
	db 11001111b 			; granularity
	db 0				; base high
 
end_of_gdt:
toc: 
	dw end_of_gdt - gdt_data - 1 	; limit (Size of GDT)
	dd gdt_data 			; base of GDT
In bochs I get:
<bochs:2> info gdt
Global Descriptor Table (base=0x00000000c00001cd, limit=23):
GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x01]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
GDT[0x02]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
So this is not GDT problem, because on real hardware the problem persists...
This looks to me like calling function but on wrong address...
When mapping kernel to physical address 1MB there are no such problems... :|

Still Page Fault at: 0x7F147A0F
Last edited by Waszka on Wed Apr 23, 2014 3:27 pm, edited 2 times in total.
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

Re: Placing kernel in 4MB in RAM on real hardware.

Post by BASICFreak »

When mapping kernel to physical address 1MB there are no such problems... :|
Just for the sake of getting this out the way are you copying your kernel to 0x400000 in stage two?
BOS Source Thanks to GitHub
BOS Expanded Commentary
Both under active development!
Sortie wrote:
  • Don't play the role of an operating systems developer, be one.
  • Be truly afraid of undefined [behavior].
  • Your operating system should be itself, not fight what it is.
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Re: Placing kernel in 4MB in RAM on real hardware.

Post by Waszka »

BASICFreak wrote:
When mapping kernel to physical address 1MB there are no such problems... :|
Just for the sake of getting this out the way are you copying your kernel to 0x400000 in stage two?
I'm setting up temp. paging directory:

Code: Select all

; page directory table
%define		PAGE_DIR			0x9C000

; 0th page table. Address must be 4KB aligned
%define		PAGE_TABLE_0			0x9D000

; 768th page table. Address must be 4KB aligned
%define		PAGE_TABLE_768			0x9E000

; each page table has 1024 entries
%define		PAGE_TABLE_ENTRIES		1024

; attributes (page is present ; page is writable ; supervisor mode)
%define		PRIV				3

;****************************************
;	Enable Paging
;****************************************

EnablePaging:
	pusha								; save stack frame

	;------------------------------------------
	;	set up the entries in the directory table
	;------------------------------------------

	mov		eax, PAGE_TABLE_0 | PRIV			; 1st table is directory entry 0
	mov		dword [PAGE_DIR], eax

	mov		eax, PAGE_TABLE_768 | PRIV			; 768th entry in directory table
	mov		dword [PAGE_DIR+(768*4)], eax

	;------------------------------------------
	;	install directory table
	;------------------------------------------

	mov		eax, PAGE_DIR
	mov		cr3, eax

	;------------------------------------------
	;	idenitity map 1st page table (4MB)
	;------------------------------------------

	mov		eax, PAGE_TABLE_0				; first page table
	mov		ebx, 0x0 | PRIV					; starting physical address of page
	mov		ecx, PAGE_TABLE_ENTRIES				; for every page in table...
.loop:
	mov		dword [eax], ebx				; write the entry
	add		eax, 4						; go to next page entry in table (Each entry is 4 bytes)
	add		ebx, 4096					; go to next page address (Each page is 4Kb)
	loop	.loop							; go to next entry

	;------------------------------------------
	;	map the 768th table to physical addr 4MB
	;	the 768th table starts the 3gb virtual address
	;------------------------------------------
 
	mov		eax, PAGE_TABLE_768				; first page table
	mov		ebx, 0x400000 | PRIV				; starting physical address of page
	mov		ecx, PAGE_TABLE_ENTRIES				; for every page in table...
.loop2:
	mov		dword [eax], ebx				; write the entry
	add		eax, 4						; go to next page entry in table (Each entry is 4 bytes)
	add		ebx, 4096					; go to next page address (Each page is 4Kb)
	loop	.loop2							; go to next entry

	;------------------------------------------
	;	enable paging
	;------------------------------------------

	mov		eax, cr0
	or		eax, 0x80000000
	mov		cr0, eax

	popa
	ret
and then I jump to:

Code: Select all

 jmp 0x8 : 0xC0000000 
Copying:

Code: Select all

CopyImage:
  	 mov	eax, dword [ImageSize]
  	 movzx	ebx, word [bpbBytesPerSector]
  	 mul	ebx
  	 mov	ebx, 4
  	 div	ebx
   	 cld
   	 mov    esi, IMAGE_RMODE_BASE   ; which is 0x3000
   	 mov	edi, IMAGE_PMODE_BASE      ; virtual one
   	 mov	ecx, eax
   	 rep	movsd  
So it's like I jump to virtual address which should be translated to 4MB in memory.
Last edited by Waszka on Thu Apr 24, 2014 12:50 am, edited 1 time in total.
Post Reply