Page 2 of 3
Re:Tim Robinson's Memory Management-1
Posted: Sat Dec 13, 2003 1:49 pm
by Candy
Neo wrote:
i guess my real question is what really happens when i use LGDT [desc], does the CPU straight away start using this new GDT or does it continue using the old CS etc values until i explicitly issue a jmp instructionv
It uses the old information, since you reload the GDTR, not the selectors (it does not do a lot automatically, if it did it would slow it down. When in difference, assume it doesn't). You have to explicitly reload a segment register to even USE the new GDT.
That was the entire reason Intel explained the hidden part of the segment registers.
Re:Tim Robinson's Memory Management-1
Posted: Sat Dec 13, 2003 1:53 pm
by Neo
then can anyone tell me why the code after i reload the GDT stops running as soon as i reload the GDT
Re:Tim Robinson's Memory Management-1
Posted: Sat Dec 13, 2003 2:05 pm
by Candy
Neo wrote:
then can anyone tell me why the code after i reload the GDT stops running as soon as i reload the GDT
That could have a few causes.
As for the first most obvious one, you need to load a pseudo descriptor at the location you specify.
That does imply that you must specify a location (registers do not work unless used indirectly) and that the location must be both accessible and contain valid information.
It might be that something else is wrong, but the most obvious thing that occurs to me is that you might have some problem a slight bit later, when you reload a register (accidentally or on purpose) which doesn't work, or something else. For the exact idea, why are you so sure that the cpu crashes on your lgdt?
You can also try to use the bochs debugger (which I'm advertising a lot lately) to see what ends up in the gdtr after your instruction, and to see whether the instruction formatting is correct etc.
Is your GDT valid btw?
HTH, Candy
-- EDIT --
Ok, your GDT seems to be valid. Is the GDT actually at F00, do you copy it there?
How do you load the GDT?
Re:Tim Robinson's Memory Management-1
Posted: Sat Dec 13, 2003 2:15 pm
by Neo
Code: Select all
;??????COPY GDT TO Address 0x0:0xF00
;-------------------------------------------------------------------------------
???xor???eax,eax?????????;
???cli????????????;
???mov???ds,ax?????????;
???mov???es,ax?????????;
???mov???di,[GDT_BASE]??????;
???mov???si,gdt?????????;
???mov???cx,[GDT_SIZE]??????;
???cld????????????;
???rep???movsb
???sti????????????; re-enable interrupts
lgdt???[gdt_descriptor]???;Load GDT???????????????;
mov???eax,cr0?????????; i'm not sure if the error is from here
or???eax, 1?????????;Set PE bit
mov???cr0,eax?????????
jmp???CODE_SEL:start32???;(or here)Jumps to PMODE coding
????????????;it must be here after using the GDT shown previously ???
????????????; i think the address of 'start32' is being computed
????????????; wrongly. could that be the reason?
????????????; if so how do i cahnge this?(the base is now 0x40100000)
hlt???
[BITS 32]
start32:
???cli???
???mov???ax, DATA_SEL??????;
???mov???ds, ax
???mov???es, ax
???mov???gs, ax?????????; Initialize all the necessary segments
???mov???fs, ax
???mov???ax, STACK_SEL???
???mov???ss, ax
???mov???esp,0x9bffc??????;
???sti
???mov???ebx,mem_map??????; pointer to mem map in the EBX register
???push???dword???mem_map??????; and the stack
???jmp???CODE_SEL:0x100000???; How do i change this too??
the BOCHS debugger also crashes with my code funny huh?
Re:Tim Robinson's Memory Management-1
Posted: Sat Dec 13, 2003 3:36 pm
by Candy
two direct points:
Do not reenable the interrupts.
your variable GDT_SIZE indicates the limit, not the size. The size is one larger.
as a side note, you do not need a stack segment-type just to have a stack. Stack == data == stack. Use a normal data segment for your stack, don't mess around with expand-down segments.
If start32 is being computed wrong, you can add the ORG of this section of code to it manually, or you can locate it at a static point somewhere and then jump there.
A way to check it (if using a relocatable format you know) is to manually check the relocation, and the addend that the assembler puts there.
Re:Tim Robinson's Memory Management-1
Posted: Sat Dec 13, 2003 10:25 pm
by Neo
Code: Select all
00000631190i[CPU ] | EAX=60000018 EBX=000083e7 ECX=00000000 EDX=534d03f2
00000631190i[CPU ] | ESP=0009bffc EBP=01f90002 ESI=000082ae EDI=00000f2f
00000631190i[CPU ] | IOPL=0 NV UP EI PL NZ NA PE NC
00000631190i[CPU ] | SEG selector base limit G D
00000631190i[CPU ] | SEG sltr(index|ti|rpl) base limit G D
00000631190i[CPU ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00000631190i[CPU ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1
00000631190i[CPU ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00000631190i[CPU ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00000631190i[CPU ] | SS:0018( 0003| 0| 0) 00000000 0009bfff 0 1
00000631190i[CPU ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1
00000631190i[CPU ] | EIP=0010001e (0010001e)
00000631190i[CPU ] | CR0=0x60000011 CR1=0x00000000 CR2=0x00000000
00000631190i[CPU ] | CR3=0x00000000 CR4=0x00000000
00000631190i[CPU ] >> ea
00000631190i[CPU ] >> 25
00000631190i[CPU ] >> 00
00000631190i[CPU ] >> 00
00000631190i[CPU ] >> c0
00000631190i[CPU ] >> 08
00000631190i[CPU ] >> 00
00000631190i[CPU ] >> : jmp 0008:c0000025
00000631190i[CTRL ] quit_sim called with exit code 1
This is the BOCHS output i get when i excecute the code shown below. I see that the segment registers are not loaded with the GDT selectors. Why is this? is there something else i should do.
Code: Select all
start:
mov ax,KDATA_SEL
mov ds,ax
mov es,ax
mov gs,ax
mov fs,ax
mov ax,KSTACK_SEL
mov ss,ax
mov esp, 0x9bffc
lgdt [gdt_desc]
jmp KCODE_SEL:rstrt
rstrt:
; rest of code here
i keep triple faulting as soon as i 'jmp'. btw is there something wrong with the GDT such as its limits etc. or does anyone who has loaded their kernel at 0xc0000000 have a GDT that i could see.
Re:Tim Robinson's Memory Management-1
Posted: Sun Dec 14, 2003 2:05 am
by Neo
In Tim's tutorial he talks about setting the segment base as 0x40100000. I just wanted to know if anyone has any code (asm preferably) showing exactly that. mine loads wrong values in the GDT and triple faults on the next jump or sometimes when i reload the registers. this is really drivin me crazy.
I jump to the kernel which is a binary format one linked at 0xc0000000 and loaded at 0x100000 by the boot loader. after this i tried loading the GDT with the new GDT values but everything goes haywire. The segment registers themselves show only the previous GDT values in BOCHS.
So i just wanted to know is there some particular way to reload the GDT?
also the segment base is 0x40100000 so if i want to get to an address after reloading the GDT then i would have to use
isn't that so? I'm really getting crazy with this stuff.
Re:Tim Robinson's Memory Management-1
Posted: Sun Dec 14, 2003 11:18 am
by Neo
I got it working at last, i used a temporary selector(base 0) in the bootloader to do all the bootloader stuff and only finally execute a jump with the real segment(base 0x40100000) (btw is this how it is done everywhere?) however now in the kernel i get some errors. The first 2 functions are execute fine(just disabling IRQ's and remapping the PIC) the next one which loads the IDT with interrupts hangs.Why is this? the only reason i can think of is that these other functions all have memory references which the first 2 do not. So if this is the problem then how can i overcome this? do i have to enable paging right away in the kernel or is it something else?
Re:Tim Robinson's Memory Management-1
Posted: Sun Dec 14, 2003 11:30 am
by Candy
Neo wrote:
I got it working at last, i used a temporary selector(base 0) in the bootloader to do all the bootloader stuff and only finally execute a jump with the real segment(base 0x40100000) (btw is this how it is done everywhere?) however now in the kernel i get some errors. The first 2 functions are execute fine(just disabling IRQ's and remapping the PIC) the next one which loads the IDT with interrupts hangs.Why is this? the only reason i can think of is that these other functions all have memory references which the first 2 do not. So if this is the problem then how can i overcome this? do i have to enable paging right away in the kernel or is it something else?
You set the data segment registers etc to 0, and then when you use them they don't work. You are surprised.
Don't be. The null selector (value: 0) is not valid even if you have a perfectly working GDT. It is even not loaded from the GDT, so you can load a null selector even without a GDT. If you cannot load your selectors with proper values your GDTR or your GDT is not correct. Try bochs with debugging breakpoint around there, and examine the memory your gdt points to. You are doing something thoroughly wrong, but I don't see what.
Re:Tim Robinson's Memory Management-1
Posted: Sun Dec 14, 2003 12:24 pm
by Neo
thats not what i meant i used selectors with base address 0 not selector 0.
btw do i have to enable paging as soon as i enter the kernel.
Re:Tim Robinson's Memory Management-1
Posted: Sun Dec 14, 2003 1:30 pm
by Candy
Neo wrote:
thats not what i meant i used selectors with base address 0 not selector 0.
btw do i have to enable paging as soon as i enter the kernel.
must be my lysdexia kicking in again...
As your kernel is completely your own design, you determine for yourself whether you're going to demand paging to be running at the start of the kernel.
You can handle the mapping problem with paging only, would advise that. The Tim Robinson way assumes that the address space will always wrap around. While that might be a valid assumption, it's the exact same as lots of people did in 16-bit with the 1M limit, causing the A20 mask. Please, learn.
HTH
Re:Tim Robinson's Memory Management-1
Posted: Sun Dec 14, 2003 1:45 pm
by Tim
Well, I assumed that all CPUs with a GDT have a 32-bit address space.
Re:Tim Robinson's Memory Management-1
Posted: Mon Dec 15, 2003 11:18 am
by Neo
Man this is turning out to be a lot more complicated than i thought it would. Anyway i would like to collect all this info/bugs etc.. in one place so that it would be easier for anyone to learn from my mistakes.
Ok saying that let me try to put what i understand into perspective (Please correct me wherever i'm wrong). Lets say that a bootloader(GRUB??) has loaded my kernel to some address (1MB for e.g) and paging is not yet enabled,also GRUB only loads the kernel with FLAT GDT descriptors. My kernel has been linked to run at 3GB(0xC000_0000).
The kernel asm stub file first disables the IRQ's and remap's the PIC's(these are memory independent so they can be executed here)
Next identity map the first linear 4MB to first physical 4MB.
Now map first 4MB of 0xC000_0000(3GB) to first 4MB of 0x100000(1MB)
Enable paging(how?? what values in CR3 etc..?)
Load the GDT with new segments whose base address is 0x4010_0000 (so that 0x4010_0000+0xC000_0000) gives 0x100000(1MB)
Next i don't know what comes so Guru's out there could you fill it up?
Re:Tim Robinson's Memory Management-1
Posted: Mon Dec 15, 2003 12:01 pm
by Tim
Neo wrote:
Man this is turning out to be a lot more complicated than i thought it would. Anyway i would like to collect all this info/bugs etc.. in one place so that it would be easier for anyone to learn from my mistakes.
Ok saying that let me try to put what i understand into perspective (Please correct me wherever i'm wrong). Lets say that a bootloader(GRUB??) has loaded my kernel to some address (1MB for e.g) and paging is not yet enabled,also GRUB only loads the kernel with FLAT GDT descriptors. My kernel has been linked to run at 3GB(0xC000_0000).
If you link your kernel to C000_0000 but load it at 0010_0000, you'll either need to:
- Use the GDT trick to make 0010_0000 appear at C000_0000 without paging
- Enable paging really early
You will need to make your code position-independent until it does one of these two things. Position-independent code isn't impossible to write (only global variable accesses need to be position-independent, not CALL or JMP) but it's a pain to do. Currently I prefer to get some paging enabled really early on -- in the assembler startup routine -- and not worry about it.
The kernel asm stub file first disables the IRQ's and remap's the PIC's(these are memory independent so they can be executed here)
This could be done before or after paging is enabled.
Next identity map the first linear 4MB to first physical 4MB.
Now map first 4MB of 0xC000_0000(3GB) to first 4MB of 0x100000(1MB)
Enable paging(how?? what values in CR3 etc..?)
The normal ones. Allocate two page tables: one to map 0000_0000 to 0040_0000, and one to map C000_0000 to C040_0000. Allocate a page directory. Enter the PTs into the PD. Load the address of the PD into CR3. Enable CR0.PG. All of this is completely standard.
Load the GDT with new segments whose base address is 0x4010_0000 (so that 0x4010_0000+0xC000_0000) gives 0x100000(1MB)
No. This is the GDT trick, which if you use it is only necessary before paging is enabled. And if you're happy with making your pre-paging code position-independent, it's not necessary at all.
Next i don't know what comes so Guru's out there could you fill it up?
Whatever you want
. From now on, you can implement your kernel design freely.
Re:Tim Robinson's Memory Management-1
Posted: Tue Dec 16, 2003 5:12 am
by Pype.Clicker
Tim Robinson wrote:
Neo wrote:what about the space complexity?
the stack approach needs 1MB space for 128Mb RAM isn't that so(or am i wrong)?
Well, a stack with 32 bits per page would need 1KB for every 1MB of RAM (or less than 0.1%), so there's not much space overhead. A bitmap would need 1/32 of that amount, but you pay for that with decreased allocation speed.
I really must have a "twisted" mind but ... What about having a 'bitmap' (for the size) of the whole memory combined with a fixed-size stack with the last N freed physical page (as a sort of cache for the bitmap) ?