Page 2 of 2

Re: Setting up GDT breaks code

Posted: Fri Oct 24, 2014 11:39 am
by Combuster
check_cs(0x0008): conforming code seg descriptor dpl > cpl, dpl=3, cpl=0
Here's your GPF: apparently your GDT has DPL=3 for the second entry - or rather, the GDT is in the wrong location.

Furthermore, your stack is in reserved memory and your code contains a lot of other bits of garbage though that say you don't understand what you're were doing in the first place:
gdt_install:
movw $23, gdtr /* sizeof (gdt) */
movl $1, %edi
movw $0, gdtr(, %edi, 2)
movl $2, %edi
movw gdt, %ax
movw %ax, gdtr(, %edi, 2)
For instance, you could trivially have done that in two instructions, and zero if you think about it properly.

Re: Setting up GDT breaks code

Posted: Sat Oct 25, 2014 2:56 am
by jrhetf4xb
Combuster wrote:
check_cs(0x0008): conforming code seg descriptor dpl > cpl, dpl=3, cpl=0
Here's your GPF: apparently your GDT has DPL=3 for the second entry - or rather, the GDT is in the wrong location.
I really don't understand how it's in the wrong location then... Did I put it wrong in gdtr? I tried about 20 variations of table entries as well, now I get another type of error: fetch_raw_descriptor: GDT: index (f) 1 > limit (0). All of the solutions I found we're the sorts of "I found it, it was the GDT, fixed", without specifying what exactly in the GDT...
For instance, you could trivially have done that in two instructions, and zero if you think about it properly.
The only way I thought of is gdtr: .word 23 .long gdt, is this what you had in mind?

Re: Setting up GDT breaks code

Posted: Sat Oct 25, 2014 3:38 am
by Combuster
All of the solutions I found we're the sorts of "I found it, it was the GDT, fixed", without specifying what exactly in the GDT...
Did you read the comments leading up to the closing post? You'll see that many of them will mention segmentation - yet another thing which is broken in your case, and by the looks of it, never properly understood as well. What's the difference between virtual and physical memory? What's the difference between CS, CS.base and the far jump address?

Re: Setting up GDT breaks code

Posted: Mon Oct 27, 2014 2:50 pm
by jrhetf4xb
Alright, I tried to read up on these topics once again so correct me if I'm wrong in my understanding.
In real mode, linear addresses are computed by the segment:offset pair corresponding to the data you want to get. There are separate segment registers for code (%ss) and data (%ds), with the additional extra segments. The address is then the result of the value in the segment register multiplied by 16 (shifted left by 4), plus the offset.
In protected mode segmentation works by referencing a global (or local) descriptor table. This table has 64-bit entries, which contain information about a segment. A special 48-bit register, the GDT register, contains the size of this table, as well as the base address from where the structure begins. The segment selectors now contain an offset into the GDT register, so if the code segment is the second entry into the GDT, it would contain the value of 8, because the descriptor starts at the eighth byte.

I can't see why my segmentation would be broken as I checked that my GDT entries are correct and ensured that at least most of my code complies with the examples given in numerous places... But it actually is broken and I really can't understand why and it's driving me crazy.
From my latest code edit I get a new type of error: jump_protected: gate type 0 unsupported

Code: Select all

.section .data
	gdt: .quad 0
		 .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00
		 .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 
	gdtr: .word 23
		  .long gdt

.code16
.section .text
	.globl boot1
	
boot1:
	cli
	
	/* re-set the stack and segments */
	xorw %ax, %ax
	movw %ax, %es
	movw %ax, %ds
	
	movw $0x7C00, %ax
	movw %ax, %ss
	movw $0x7CDF, %sp
	
	sti
	
	/* enable A20 line */
	movw $0x2401, %ax
	int $0x15

	/* load the kernel */
	
	/* set up for protected mode */
	cli
	movl $2, %edi
	movw gdt, %eax 
	orw $0x0100, %eax 
	movl %eax, gdtr(, %edi, 2)
	
	/* enter protected mode */
	lgdt gdtr 
	movl %cr0, %eax
	orl $1, %eax
	movl %eax, %cr0
	ljmp $0x08, $protected_mode

.code32
protected_mode:
	/* update segments */
	movw $0x10, %ax
	movw %ax, %ds
	movw %ax, %es
	movw %ax, %gs
	movw %ax, %fs
	movw %ax, %ss
	movl $0x0001000, %esp
	
	
	//call kmain
	/* NOTREACHED */
  halt:
	hlt
	jmp halt
What's the difference between CS, CS.base and the far jump address?
CS has two meanings depending on real/protected mode (like I wrote above, if it's even correct). CS.base specifies the starting address of the segment in protected mode (are you refering to .base in the CS entry in GDT?). The far jump modifies the code segment when jumping to an address. So when I perform a far jump to protected mode, basically CS gets the value of 8 in order to offset the correct entry in the GDT.

Re: Setting up GDT breaks code

Posted: Mon Oct 27, 2014 3:21 pm
by Combuster
Problems don't simply disappear if you only stare at the screen though. Apart from screensavers, that is.
jrhetf4xb wrote:
What's the difference between CS, CS.base and the far jump address?
CS has two meanings depending on real/protected mode (...)
Take a good look at the logdump you posted earlier, then answer that question again. Where do those values come from, and why are they correct or wrong? Even though you have made some changes, I'm pretty sure you will see roughly the same numbers in your current dump because you have missed the problem so far.

Re: Setting up GDT breaks code

Posted: Mon Oct 27, 2014 3:44 pm
by jrhetf4xb
00018222607i[CPU0 ] 0x000000000000004f>> jmp far 0008:0554 : EA54050800
As far as I understand, from last page's dump I'm jumping to 0x0554 where the label should be located (0x0050:0x0054 CS:IP pair) and after the jump to protected mode CS gets the value of 0x0008 so it can offset the table. Or am I completely misunderstanding the jump?
Does it assign CS to 0x0008 while in real mode and use real mode addressing (0x0080 + 0x0554 = ... wrong jump)? Or is it after real mode (in protected) but not requiring the 0x0050 offsetting, thus wrongly landing at 0x0554 instead of 0x0054 (again a wrong jump)? Do I have to manipulate the addresses in any way?

Re: Setting up GDT breaks code

Posted: Mon Oct 27, 2014 5:09 pm
by Cjreek
I'm having a hard time reading AT&T assembler syntax but I'm wondering what those lines are supposed to do:

Code: Select all

 
   movl $2, %edi  
   movw gdt, %eax 
   orw $0x0100, %eax 
   movl %eax, gdtr(, %edi, 2)
I'm pretty sure this messes up your GDTR.

you load the address of your GDT in eax, setting Bit 8 of this to 1 and than you write this value into the base-field of your GDTR (using a very confusing way to calculate this address, why not just gdtr+4?)

Why do you change this bit? Best case this does nothing if your .data section starts beyond 0x7D00. Otherwise the base of your GDTR is just wrong and the processor will read crap instead of your GDT.

I think if you just delete those lines everything might work fine.

Re: Setting up GDT breaks code

Posted: Mon Oct 27, 2014 5:40 pm
by jrhetf4xb
Sorry, ignore that part as I was trying some stupid stuff to put the address in the gdtr, it should be like this:

Code: Select all

.section .data
	gdt: .quad 0
		 .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00
		 .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 
	gdtr: .word 23
		  .long gdt

.code16
.section .text
	.globl boot1
	
boot1:
	cli
	
	/* re-set the stack and segments */
	xorw %ax, %ax
	movw %ax, %es
	movw %ax, %ds
	
	movw $0x7C00, %ax
	movw %ax, %ss
	movw $0x7CDF, %sp
	
	sti
	
	/* enable A20 line */
	movw $0x2401, %ax
	int $0x15

	/* load the kernel */
	
	/* set up for protected mode */
	cli
	
	/* enter protected mode */
	lgdt gdtr 
	movl %cr0, %eax
	orb 1, %al
	movl %eax, %cr0
	ljmp $0x08, $protected_mode

.code32
protected_mode:
	/* update segments */
	movw $0x10, %ax
	movw %ax, %ds
	movw %ax, %es
	movw %ax, %gs
	movw %ax, %fs
	movw %ax, %ss
	movl $0x0001000, %esp
	
	
	//call kmain
	/* NOTREACHED */
  halt:
	hlt
	jmp halt


Re: Setting up GDT breaks code

Posted: Mon Oct 27, 2014 11:25 pm
by Combuster
jrhetf4xb wrote:
00018222607i[CPU0 ] 0x000000000000004f>> jmp far 0008:0554 : EA54050800
As far as I understand, from last page's dump I'm jumping to 0x0554 where the label should be located (0x0050:0x0054 CS:IP pair) and after the jump to protected mode CS gets the value of 0x0008 so it can offset the table. Or am I completely misunderstanding the jump?
Does it assign CS to 0x0008 while in real mode and use real mode addressing (0x0080 + 0x0554 = ... wrong jump)? Or is it after real mode (in protected) but not requiring the 0x0050 offsetting, thus wrongly landing at 0x0554 instead of 0x0054 (again a wrong jump)? Do I have to manipulate the addresses in any way?
There's actually no such thing as a "jump" to protected mode. If bit 0 of CR0 is set, the segment.base is loaded from the GDT. If it's clear, then segment.base = segment.selector * 16. The jump fails because you already are in protected mode, and there's garbage at the supposed GDT.

All GDT entries in your code have a base of zero, so a jump to 8:554 should set CS.base = GDT[1].base = 0 and IP to 0x554, and thus continue executing at 0x554 physical. Your dump doesn't show GDTR, but the base you have set for it is probably 0x000005xx or 0x000006xx because you will most likely have told your linker to start everything from 0x0500

However, the actual code is somewhere else:

Code: Select all

00018222607i[CPU0 ] |  CS:0500( 0004| 0|  0) 00005000 0000ffff 0 0
00018222607i[CPU0 ] | RIP=000000000000004f
Which physical address is that? What goes wrong here?

Re: Setting up GDT breaks code

Posted: Tue Oct 28, 2014 7:04 am
by jrhetf4xb
Alright! I tweaked where code should be in my linker script (from 0x0500 to 0x1000) and it works now!! Did I run over BIOS memory and that caused these errors? I really don't understand how it got fixed...
What I did is just tweak the addresses -- I put my kernel from 0x1000 onwards and now everything works like a charm, the segments seem to contain the correct value and code past protected_mode label gets executed.