Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Reset when i enable paging

11 views
Skip to first unread message

Anthony M.

unread,
Apr 10, 2006, 6:27:39 PM4/10/06
to
I started an OS before. but i decided to start over again, as last time
i copied a lot of the paging code, so i didn't have a full
understanding, and this time i want to make it multiboot compliant.
anyways, right now, i am just Identity mapping the first 4 megs. here
is my code so far.

boot.asm:
Code:

extern meminit
[BITS 32]
global setup ;GRUB loads kernel and enters here
setup:
cmp eax,0x2BADB002
jne notmb

mov eax, 0xFFFF
mov esp, eax ;set temp stack pointer
mov ebp, eax ;set temp base pointer

push ebx ;push pointer to multiboot info
call meminit
pop ebx

notmb:
hlt
jmp notmb

;multiboot header info below
.
.
.


and here is meminit()
Code:

static uint32_t pages;

void meminit(multiboot_info_t *mb_info)
{
uint32_t *pdir, *ptab;
int i;

pages = ((mb_info->mem_lower + mb_info->mem_upper)*1024) /
PAGESIZE;

//Use the last page in memory for the page directory
pdir = (uint32_t *)(--pages * PAGESIZE);
//map the Page Directory to the last PDE
//this will now be mapped to virtual 0xffc00000
pdir[1023] = (uint32_t)pdir | PG_PRESENT | PG_WRITABLE;

//Identity Map the first 4Megs of memory
ptab = (uint32_t *)((--pages * PAGESIZE) | PG_PRESENT |
PG_WRITABLE);
for(i=0; i<1024; i++)
{
ptab[i]=(i*PAGESIZE)| PG_PRESENT | PG_WRITABLE;
}
pdir[0] = (uint32_t)ptab;

//set page directory base address
set_cr3(pdi

//enable paging
set_cr0(get_cr0 | CR0_PG);
}


using bochs, it reboots using that code.
but if i comment out the line that enables paging, it will hit the
notmb loop fine and endlessly loop like its supposed to. I dont see any
blatantly obvious problems. Could someone please help me with this?

Alexei A. Frounze

unread,
Apr 10, 2006, 10:10:06 PM4/10/06
to

I don't think the above line is generally safe. There's probably a reason
why GRUB returns separate memory counts, there're memory holes.

> //map the Page Directory to the last PDE
> //this will now be mapped to virtual 0xffc00000
> pdir[1023] = (uint32_t)pdir | PG_PRESENT | PG_WRITABLE;
>
> //Identity Map the first 4Megs of memory
> ptab = (uint32_t *)((--pages * PAGESIZE) | PG_PRESENT |
> PG_WRITABLE);
> for(i=0; i<1024; i++)
> {
> ptab[i]=(i*PAGESIZE)| PG_PRESENT | PG_WRITABLE;
> }
> pdir[0] = (uint32_t)ptab;

Here (in the above line) I think something important is missing.

> //set page directory base address
> set_cr3(pdi

Is this code the actual code you're trying to execute? The above line won't
even compile.

> //enable paging
> set_cr0(get_cr0 | CR0_PG);

get_cr0 doesn't look like a function either, so is this the actual code???

> }
>
>
> using bochs, it reboots using that code.
> but if i comment out the line that enables paging, it will hit the
> notmb loop fine and endlessly loop like its supposed to. I dont see
> any blatantly obvious problems. Could someone please help me with
> this?

What are these: PAGESIZE, PG_PRESENT, PG_WRITABLE, CR0_PG?
What are these: set_cr3(), set_cr0(), get_cr0?
Does GRUB do any page setup for you?
Where does GRUB load your code in memory?

Alex

Paul Barker

unread,
Apr 11, 2006, 6:31:40 AM4/11/06
to
I've answered this over at the Mega-Tokyo forums, but since theyre down
this morning I'll answer here incase you didnt see my reply over there.

Everything Alex says is right, but I don't think thats the problem.

Think about these 2 lines:

ptab = (uint32_t *)((--pages * PAGESIZE) | PG_PRESENT | PG_WRITABLE);

And later, in the loop:

ptab[i]=(i*PAGESIZE)| PG_PRESENT | PG_WRITABLE;

Now it should be clear whats causing the problem.

Y...@t.hon9

unread,
Apr 11, 2006, 11:23:43 AM4/11/06
to
Anthony M. wrote:
> I started an OS before. but i decided to start over again, as last time
> i copied a lot of the paging code, so i didn't have a full
> understanding, and this time i want to make it multiboot compliant.
> anyways, right now, i am just Identity mapping the first 4 megs. here
> is my code so far.
>
> boot.asm:
> Code:
>
> extern meminit
> [BITS 32]
> global setup ;GRUB loads kernel and enters here
> setup:
> cmp eax,0x2BADB002
> jne notmb
>
> mov eax, 0xFFFF
> mov esp, eax ;set temp stack pointer
Any reason to setup stack pointer with an odd value? That means stack is
not even aligned. Does Read/Write on stack is different to normal
Read/Write?

Hong

Alexei A. Frounze

unread,
Apr 11, 2006, 11:46:55 AM4/11/06
to

OK, I missed half of this. Once the two lines you mention are fixed, the
following line also needs fixing:

pdir[0] = (uint32_t)ptab;

Alex

Anthony M.

unread,
Apr 11, 2006, 4:36:20 PM4/11/06
to
From: "Anthony M." <omin0...@gmail.com>
Newsgroups: alt.os.development
Subject: Re: Reset when i enable paging
Date: Tue, 11 Apr 2006 11:56:12 -0700

that is the actual code,
the line: set_cr3(pdi accidentally got deleted a bit when copying.
the code
all those other functions you asked about are assembly stubs, elsewhere
in my code, but they should be self explanitory as to what they do if
you know about paging.

anyway, i made some of those changes, so the code looks like this now
for meminit()

static uint32_t pages;

void meminit(multiboot_info_t *mb_info)
{
uint32_t *pdir, *ptab;
int i;

pages = ((mb_info->mem_lower + mb_info->mem_upper)*1024) /
PAGESIZE;

//Use the last page in memory for the page directory
pdir = (uint32_t *)(--pages * PAGESIZE);
//map the Page Directory to the last PDE
//this will now be mapped to virtual 0xffc00000
pdir[1023] = (uint32_t)pdir | PG_PRESENT | PG_WRITABLE;

//Identity Map the first 4Megs of memory

ptab = (uint32_t *)(--pages * PAGESIZE);
for(i=0; i<1024; i++)
{


ptab[i]=(i*PAGESIZE)| PG_PRESENT | PG_WRITABLE;
}

pdir[0] = (uint32_t)ptab | PG_PRESENT | PG_WRITABLE;

//set page directory base address

set_cr3(pdir);

//enable paging
set_cr0(get_cr0 | CR0_PG);

}

I understand why i needed to change the line that said


ptab = (uint32_t *)((--pages * PAGESIZE) | PG_PRESENT | PG_WRITABLE);

bcause then the array would have been off by 0x3 when accessing it in
the loop.
but i dont understand the problem with the line in the loop that is
setting permissions to the PTE's themselves? anyway, that new code
still resets the computer. I'm assuming it is a triple fault or
something. i really dont understand what is wrong.

Alexei A. Frounze

unread,
Apr 11, 2006, 8:36:55 PM4/11/06
to

It was using that wrong "off by something" pointer.

> anyway, that new code
> still resets the computer. I'm assuming it is a triple fault or
> something. i really dont understand what is wrong.

Do you really know where your code is located? At what physical address? If
your code is located above 4 MB, the above won't work.
How does GRUB set the segment registers for your code? Are the base
addresses of the segment descriptors 0 for your code/data? If they aren't
the above can't work.

When you're done filling the tables, can you dump the following to the
screen to make sure everything makes sense:
pdir, pdir[0], pdir[1023]
ptab, ptab[0], ptab[1], ptab[1023]
What do you get?

Alex

Anthony M.

unread,
Apr 12, 2006, 1:14:31 AM4/12/06
to
Grub is loading the kernel at 1mb (0x100000).
i am actually not sure what the segment registers are set to.
i have seen code before that does something like

mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax

i dont know why they are using the value 0x10 though.

should i maybe load a temp gdt before i enable paging and see if that
works?

Alexei A. Frounze

unread,
Apr 12, 2006, 1:57:03 AM4/12/06
to

You should have probably read the GRUB docs in the first place ;)
In case you've lost the link, it's all here:
http://www.gnu.org/software/grub/manual/multiboot/multiboot.html
Alright, GRUB seems to be not doing anything funky according to the above
doc, so, my next question is how do you build what you feed to GRUB?
I'm particularly interested in how you link your thing and what addresses
you use. Don't tell me you don't know the addresses. :)

Alex

Anthony M.

unread,
Apr 12, 2006, 4:59:08 AM4/12/06
to
Below the code i posted in my first post of boot.asm is this, which is
what grub needs
to know that it is a multiboot kernel.

; Multiboot header
magic equ 0x1BADB002
flags equ 0x00000003

align 4

dd magic ; magic
dd flags ; flags
dd -(magic+flags) ; checksum
dd 0 ; header_addr (if flags bit 16 set)
dd 0 ; load_addr (if flags bit 16 set)
dd 0 ; load_end_addr (if flags bit 16 set)
dd 0 ; bss_end_addr (if flags bit 16 set)
dd 0 ; entry_addr (if flags bit 16 set)
dd 0 ; mode_type (if flags bit 2 set)
dd 0 ; width (if flags bit 2 set)
dd 0 ; height (if flags bit 2 set)
dd 0 ; depth (if flags bit 2 set)

Grub loads everything at 0x100000 (1mb). everything is compiled to
objects files, and
then everything is linked using this ld script:

OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)

phys = 0x100000;

ENTRY(setup)
SECTIONS
{
. = phys;
.text phys : AT(phys)
{
code = .; _code = .;
*(.text)
. = ALIGN(4096);
}

.data : AT(phys + ( data - code ) )
{
data = .; _data = .;
*(.data)
. = ALIGN(4096);
}

.bss : AT(phys + ( bss - code ))
{
bss = .; _bss = .;
*(.bss)
. = ALIGN(4096);
}

.rodata : AT(phys + (rodata - code ))
{
rodata = .; _rodata = .;
*(.rodata)
. = ALIGN(4096);
}
. = ALIGN(4096);
end = .; _end = .;
}

Anthony M.

unread,
Apr 15, 2006, 8:22:11 PM4/15/06
to
no ideas on this yet?

Alexei A. Frounze

unread,
Apr 16, 2006, 2:28:36 PM4/16/06
to

My ld doesn't like the above script. It barks at:
.text phys : AT(phys)


I used to use something like this for C (gcc=DJGPP):
OUTPUT_FORMAT("coff-go32")

ENTRY(__start)

FORCE_COMMON_ALLOCATION

SECTIONS
{
.text 0xC0000000: /* .text starts at 0xC0000000
virtual */
{
*(.text)
FILL(0x0) /* gap filler value */
. = ALIGN(0x1000); /* round up the size to 4KB page
size */
etext = .; _etext = .;
}
.data :
{
*(.data)
FILL(0x0)
. = ALIGN(0x1000);
edata = .; _edata = .;
}
.bss :
{
*(.bss)
FILL(0x0)
*(COMMON) /* place COMMONs to .bss */
FILL(0x0)
. = ALIGN(0x1000);


end = .; _end = .;
}
}

I think you may not need to specify both virtual and physical addresses. I
specify only the virtual one because the load address is the same by
default. They need to be different if the image is stored at different
location than used (e.g. ROM, from which it later gets copied to RAM).

Alex

Anthony M.

unread,
Apr 18, 2006, 5:33:38 PM4/18/06
to
This did not seem to solve the problem. This is really bugging me. i
mean, the code cant really get more basic than it already it. :(
any other suggestions?

Alexei A. Frounze

unread,
Apr 18, 2006, 11:38:33 PM4/18/06
to

Nope, even though I believe it must be something very simple. Did you try
searching for examples of GRUB use?
You could also try to boot a flat image, something very simple made with
e.g. nasm (it can produce an image). And maybe you could spend sometime
trying to repeat after GRUB -- emulate the load and execution (either in
real (tweaking the GRUB's code) or by hand with a fileviewer+disassembler
and calculator).

There's nothing impossbile, especially with the code of this size. I
sometimes dump the stack and other important things to memory or screen (if
possible) if things go wrong and study that along with the disassembly.
Takes time but lets find the problems.

Alex

Y...@t.hon9

unread,
Apr 20, 2006, 2:16:34 PM4/20/06
to
Anthony M. wrote:
> From: "Anthony M." <omin0...@gmail.com>
> Newsgroups: alt.os.development
> Subject: Re: Reset when i enable paging
> Date: Tue, 11 Apr 2006 11:56:12 -0700
>
> that is the actual code,
> the line: set_cr3(pdi accidentally got deleted a bit when copying.
> the code
> all those other functions you asked about are assembly stubs, elsewhere
> in my code, but they should be self explanitory as to what they do if
> you know about paging.
>
> anyway, i made some of those changes, so the code looks like this now
> for meminit()
>
> static uint32_t pages;
>
> void meminit(multiboot_info_t *mb_info)
> {
> uint32_t *pdir, *ptab;
> int i;
>
> pages = ((mb_info->mem_lower + mb_info->mem_upper)*1024) /
> PAGESIZE;
>
> //Use the last page in memory for the page directory
> pdir = (uint32_t *)(--pages * PAGESIZE);
Here, you are not use the last page in memory for the page directory.
mem_lower starts at address 0, mem_upper starts at address 1MB. The
address of last page should be
(((mb_info->mem_upper*1024 + 1MB)/PAGESIZE) - 1) * PAGESIZE

And if mem_upper is smaller than 3MB, that means your pd and pt are
placed below 4MB, when you identity map the first 4MB, apart from
virtual address 0xffc00000, there is another address can access the pd,
and you may destroy it accidentally.
I don't know if this is the cause of your problem.

Hong

0 new messages