What's problem with this code?

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.
InsightSoft
Member
Member
Posts: 76
Joined: Mon Aug 18, 2008 6:17 am

Re: What's problem with this code?

Post by InsightSoft »

Does anybody knows how to implements this code in gcc???

Code: Select all

		mov eax, 0x0010
		mov es, ax		
		mov si, -2
		w:
			add si, 2
			mov ax, si
			mov byte [es:si], al
			cmp si, 0xff
		jne w
I need to trace the problem I'm experiencing calling C 32bit code

Double post removed - Combuster
ru2aqare
Member
Member
Posts: 342
Joined: Fri Jul 11, 2008 5:15 am
Location: Hungary

Re: What's problem with this code?

Post by ru2aqare »

InsightSoft wrote:Does anybody knows how to implements this code in gcc???

Code: Select all

		mov eax, 0x0010
		mov es, ax		
		mov si, -2
		w:
			add si, 2
			mov ax, si
			mov byte [es:si], al
			cmp si, 0xff
		jne w
I need to trace the problem I'm experiencing calling C 32bit code
That would be

Code: Select all

uint8* p = (uint8*)0x100;
for (int i = 0; ; i+=2)
{
   p[i] = i & 0xFF;
}
in C. Note that there is no condition to terminate the loop. It is endless, as incrementing the register si by two (thus keeping it even) will never equal to an odd number.

By the way, what would be the purpose of the assembly loop?
InsightSoft
Member
Member
Posts: 76
Joined: Mon Aug 18, 2008 6:17 am

Re: What's problem with this code?

Post by InsightSoft »

Ok, thanks...
it will works any way...
InsightSoft
Member
Member
Posts: 76
Joined: Mon Aug 18, 2008 6:17 am

Re: What's problem with this code?

Post by InsightSoft »

pardon,

Code: Select all

		mov eax, 0x0010
		mov es, ax		
		mov si, -2
		w:
			add si, 2
			mov ax, si
			mov byte [es:si], al
			cmp si, 0xff
		jne w
the two instructions allows us to select the selector that represent the video memory (...the selector, gdt and pl, as you know...)

following your code (in c) result this opcodes...

Code: Select all

typedef unsigned char uint8;
int i;
uint8* p = (uint8*)0x100;
for(i = 0; i<= 100 ; i+=2)
{
     p[i] = i & 0xFF;
}

00000312  B80000            mov ax,0x0
00000315  0000              add [bx+si],al
00000317  88800001          mov [bx+si+0x100],al
0000031B  0000              add [bx+si],al
0000031D  83C002            add ax,byte  0x2
00000320  83F866            cmp ax,byte  0x66
00000323  75F2              jnz 0x317
As we can see, there is no reference to the selector... it will crash, right?
ru2aqare
Member
Member
Posts: 342
Joined: Fri Jul 11, 2008 5:15 am
Location: Hungary

Re: What's problem with this code?

Post by ru2aqare »

InsightSoft wrote:pardon,

the two instructions allows us to select the selector that represent the video memory (...the selector, gdt and pl, as you know...)
Oh, I see.
InsightSoft wrote: following your code (in c) result this opcodes...

As we can see, there is no reference to the selector... it will crash, right?
Yes and no. First, you compiled the wrong C code. My assembly to C transcript was an endless loop, but the loop you quoted terminates after 50 iterations. Second, most C compilers target application development (user mode), and assume that all segment registers are set up (by the kernel or by the programmer). Old real-mode C compilers may be an exception to this, however.
So, if you set the segment registers before invoking any C code, it should run just fine.
InsightSoft
Member
Member
Posts: 76
Joined: Mon Aug 18, 2008 6:17 am

Re: What's problem with this code?

Post by InsightSoft »

Now I have other problem...

...I have a GDT with the following descriptors:

1). Empty;
2). 16Bits code that will call the next stage of Kernel
3). Video memory
4). stack for 32 bit operations
5). code for 32 bit (asm linked to c)
6). data for 32 bit

I load the (asm linked to C) before i switch to PM and calculate the address witch I put in the correspondent GDT descriptor...
...switch PM
...jmp to 32 Bit code (asm linked to c)... then

Code: Select all

00017202782i[BIOS ] Booting from 0000:7c00
00018358895e[CPU0 ] write_virtual_checks(): no write access to seg
00018358895i[CPU0 ] CPU is in protected mode (active)
00018358895i[CPU0 ] CS.d_b = 32 bit
00018358895i[CPU0 ] SS.d_b = 16 bit
00018358895i[CPU0 ] EFER   = 0x00000000
00018358895i[CPU0 ] | RAX=0000000000000018  RBX=0000000000000000
00018358895i[CPU0 ] | RCX=0000000000000003  RDX=0000000000000000
00018358895i[CPU0 ] | RSP=000000000000ffe3  RBP=0000000000000000
00018358895i[CPU0 ] | RSI=00000000ffff009c  RDI=000000000008ffac
00018358895i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00018358895i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00018358895i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00018358895i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00018358895i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af pf cf
00018358895i[CPU0 ] | SEG selector     base    limit G D
00018358895i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00018358895i[CPU0 ] |  CS:0018( 0003| 0|  0) 00090000 000fffff 1 1
00018358895i[CPU0 ] |  DS:0018( 0003| 0|  0) 00090000 000fffff 1 1
00018358895i[CPU0 ] |  SS:0020( 0004| 0|  0) 00080000 000cffff 0 0
00018358895i[CPU0 ] |  ES:0018( 0003| 0|  0) 00090000 000fffff 1 1
00018358895i[CPU0 ] |  FS:0018( 0003| 0|  0) 00090000 000fffff 1 1
00018358895i[CPU0 ] |  GS:0018( 0003| 0|  0) 00090000 000fffff 1 1
00018358895i[CPU0 ] |  MSR_FS_BASE:0000000000090000
00018358895i[CPU0 ] |  MSR_GS_BASE:0000000000090000
00018358895i[CPU0 ] | RIP=00000000000004ec (00000000000004ec)
00018358895i[CPU0 ] | CR0=0x60000011 CR1=0x0 CR2=0x0000000000000000
00018358895i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00018358895i[CPU0 ] >> mov dword ptr ds:0x1000, 0x000b8000 : C7050010000000800B0
0
00018358895e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown
 status is 00h, resetting
00018358895i[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called
...it seems to me that I have DS with wrong descriptor (right?)... as told before, it is a programmer responsibility...

now start my problem... I load the binary (asm linked to C) information as continuous block of bytes (512 bytes) to the expected location 9000:0000...
How can I distinguish the .text, .data and .bss sections? I try to make a simple debug and is not easy... maybe I'm trying with hard way... that's why I came again asking for help...
ru2aqare
Member
Member
Posts: 342
Joined: Fri Jul 11, 2008 5:15 am
Location: Hungary

Re: What's problem with this code?

Post by ru2aqare »

InsightSoft wrote: How can I distinguish the .text, .data and .bss sections? I try to make a simple debug and is not easy... maybe I'm trying with hard way... that's why I came again asking for help...
There is no way to distinguish code sections from data sections in a binary file without any headers. There are no sections in a binary file to begin with. It's just a big blob of bits.

The Writable bit in your descriptor is probably wrong, that is causing the exception.
InsightSoft
Member
Member
Posts: 76
Joined: Mon Aug 18, 2008 6:17 am

Re: What's problem with this code?

Post by InsightSoft »

My descriptors...

asm [16bits]

Code: Select all

				at gdt_tbl.dummy, 		db 0			;Empty
				
				at gdt_tbl.ks1code, 	dw 0xFFFF		;[08] size 1 e 2
										dw 0x0			;base 1 e 2
		                   				db 0x0			;base 3
		                   				db 0x9a			;flag1 	>	1 00 1 1010 		> [p=1 (in mem); dpl=10 (level); s=0 (system); segtype=1010]  _1 10 0 1010
		                   				db 0x0			;flag2	>	0 0 0 1 1010	> [g=0 (len in byts); d/b=0 (); 0; avl=1; seg size nib=1010 ();  ] 00011010
		                   				db 0x0			;base4
		                   				                ; 00 00 00 00 (32 bits) (0000:0000) 
		                   								; 04|03|01|02			(7000:0000)
		                   				
				at gdt_tbl.ks1video, 	dw 0x0FA0		;[16]	at run-time:fixed/size 0fA0=4.000 bytes
		                   				dw 0x8000		;base1 e 2
		                   				db 0x0B			;base3
		                   				db 0x92			;flag1	> 1 00 1 0010 	> [p=1 (in mem); dpl=00 (level); s=1 (not system); segtype=0010]
		                   				db 0x0			;flag2	> 0 0 0 0 0000 	> [g=0 (len in bytes); d/b=0 (data); 0; avl=0 (?); sg size nib=0000]
		                   				db 0x0			;at run-time:fixed
		                   								;000B8000 32 bits (b800:0000 bits)
		                   								;04030102
		                   				
				at gdt_tbl.ks2code, 	dw 0xffff		;[24] - 32 Bits ---- asm c bootstrap
		                   				dw 0x0			;
		                   				db 0x0			;
		                   				db 0x9a			;
		                   				db 0xcf			;
		                   				db 0x0			;

				at gdt_tbl.c32stack, 	dw 0xFFFF		;[32] - Stack
										dw 0x0		
		                   				db 0x0		
		                   				db 0x92		
		                   				db 0xC		
		                   				db 0x0	

				at gdt_tbl.c32code, 	dw 0xffff		;[40] - 32 Bits ---- C EntryPoint
		                   				dw 0x0			;
		                   				db 0x0			;
		                   				db 0x9a			;
		                   				db 0xcf			;
		                   				db 0x0			;

				at gdt_tbl.c32data, 	dw 0xffff		;[48] - 32 Bits ---- C Data
		                   				dw 0x0			;
		                   				db 0x0			;
		                   				db 0x9a			;
		                   				db 0xcf			;
		                   				db 0x0			;


asm [32 bits] linked to c [32bits]

Code: Select all

[BITS 32]
global KernelEntry
KernelEntry:
		;setting up the 32 bit stack
		mov eax, 0x0020
		mov ss, ax
		mov esp, 0x0000ffff

		;setting up segments
		;mov ax, 40
	        ;mov ds, ax
	        ;mov es, ax
	        ;mov fs, ax
	        ;mov gs, ax
		
		;call C Kernel
	    extern _kernel
	    call _kernel

		;loop endless
	    jmp $
	    
	    global _prnt
	    _prnt:
	    	mov ax, 16
	    	mov es, ax
	    	mov byte [es:0x0], 'I'
	    	ret
	    	
	    global _gdt_flush
		extern _gp
		_gdt_flush:
    		lgdt [_gp]
    		mov ax, 0x10
		    mov ds, ax
		    mov es, ax
		    mov fs, ax
		    mov gs, ax
		    mov ss, ax
		    jmp 0x08:flush2
			flush2:
		    	ret
c [32bits]

Code: Select all

typedef int size_t;
extern size_t strlen(const char *str);

struct gdt_entry
{
    unsigned short limit_low;
    unsigned short base_low;
    unsigned char base_middle;
    unsigned char access;
    unsigned char granularity;
    unsigned char base_high;
} __attribute__((packed));

struct gdt_ptr
{
    unsigned short limit;
    unsigned int base;
} __attribute__((packed));
struct gdt_entry gdt[3];
struct gdt_ptr gp;

extern void gdt_flush();

void gdt_set_gate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran)
{
	prnt();           //it works fine
    gdt[num].base_low = (base & 0xFFFF);      //crash here!!!
	prnt();           //it will not run
    gdt[num].base_middle = (base >> 16) & 0xFF;
    gdt[num].base_high = (base >> 24) & 0xFF;
    gdt[num].limit_low = (limit & 0xFFFF);
    gdt[num].granularity = ((limit >> 16) & 0x0F);
    gdt[num].granularity |= (gran & 0xF0);
    gdt[num].access = access;
}

void gdt_install()
{
    gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
    gp.base = &gdt;
    gdt_set_gate(0, 0, 0, 0, 0);
    gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
    gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
    gdt_flush();
}

extern void prnt();

int kernel()
{
	prnt();           //it works fine
	gdt_install();	
    for (;;);
    return 0; 
}

It seems to me that when I work with a variable it crash...
at that point all piece of code is running at descriptor 24 (code and 32 bit)... and doesn't allow any write operation...
ru2aqare
Member
Member
Posts: 342
Joined: Fri Jul 11, 2008 5:15 am
Location: Hungary

Re: What's problem with this code?

Post by ru2aqare »

InsightSoft wrote: It seems to me that when I work with a variable it crash...
at that point all piece of code is running at descriptor 24 (code and 32 bit)... and doesn't allow any write operation...
I should have noticed it when I posted my earlier reply...

Code: Select all

00018358895i[CPU0 ] |  CS:0018( 0003| 0|  0) 00090000 000fffff 1 1
00018358895i[CPU0 ] |  DS:0018( 0003| 0|  0) 00090000 000fffff 1 1
00018358895i[CPU0 ] |  SS:0020( 0004| 0|  0) 00080000 000cffff 0 0
00018358895i[CPU0 ] |  ES:0018( 0003| 0|  0) 00090000 000fffff 1 1
00018358895i[CPU0 ] |  FS:0018( 0003| 0|  0) 00090000 000fffff 1 1
00018358895i[CPU0 ] |  GS:0018( 0003| 0|  0) 00090000 000fffff 1 1
Look close. You loaded the data segment register (ds) and the others (except the stack segment register) with a selector that refers to a code segment (0x18). Code segments are never writable. The descriptors are probably fine (I didn't check them thorougly), but you should load ds: es: with selector 0x30 - a flat data segment.

Edit: also your data descriptors are flawed. The first flag byte (that is now 0x9A) should contain 0x92, because you want a data segment, not a code segment.
InsightSoft
Member
Member
Posts: 76
Joined: Mon Aug 18, 2008 6:17 am

Re: What's problem with this code?

Post by InsightSoft »

Solved! giving the same physical address code(9a)=data(92) (32 bits)...

now crash on

Code: Select all

		_gdt_flush:
			call _prnt      ;work fine
    		lgdt [_gp]     ;crash here
			call _prnt      ;will not run
			
    		mov ax, 0x10
		    mov ds, ax
		    mov es, ax
		    mov fs, ax
		    mov gs, ax
		    mov ss, ax
		    jmp 0x08:flush2
			flush2:
		    	ret
ru2aqare
Member
Member
Posts: 342
Joined: Fri Jul 11, 2008 5:15 am
Location: Hungary

Re: What's problem with this code?

Post by ru2aqare »

InsightSoft wrote:

Code: Select all

    call  _prnt      ;work fine
    lgdt  [_gp]      ;crash here
    call  _prnt      ;will not run
This one should be easy. If you check the operand of the lgdt instruction in the assembler's listing, you will find that it uses an offset measured from the start of the assembly file. Which is fine as long as the data segment points to the start of the assembly file. However, when you load ds: with selector 0x30, which specifies a descriptor with base address zero and limit four gigabytes (also called a flat segment), the data segment no longer points to the start of the assembly code. You need to compensate for the difference by doing something like this:

Code: Select all

    call  _prnt
    mov   ebx, runtime_address_where_the_assembly_code_is_loaded
    lgdt  [ebx + _gp]
    call  _prnt
And you calculate the aforementioned offset difference before you enter protected mode:

Code: Select all

    xor   eax, eax
    mov   ax, ds
    shl   eax, 4
    mov   [where_is_my_assembly_code_loaded], eax
...
...
    call  _print
    mov   ebx, [where_is_my_assembly_code_loaded]
    lgdt  [ebx + _gp]
    call  _print
InsightSoft
Member
Member
Posts: 76
Joined: Mon Aug 18, 2008 6:17 am

Re: What's problem with this code?

Post by InsightSoft »

Ok... I will try changing the code...
(even if the original idea were to preserve the code as is) (I took from Bran's Kernel Development Tutorial)
ru2aqare
Member
Member
Posts: 342
Joined: Fri Jul 11, 2008 5:15 am
Location: Hungary

Re: What's problem with this code?

Post by ru2aqare »

InsightSoft wrote:Ok... I will try changing the code...
(even if the original idea were to preserve the code as is) (I took from Bran's Kernel Development Tutorial)
Why would you want to preserve code that doesn't work? Though I haven't read Bran's tutorial, so I don't know if the code doesn't work generally, or doesn't work for you specifically.
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Re: What's problem with this code?

Post by JamesM »

InsightSoft wrote:Ok... I will try changing the code...
(even if the original idea were to preserve the code as is) (I took from Bran's Kernel Development Tutorial)
Bran's tutorial uses a flat segment model, totally different to yours. It therefore makes sense that pasting his code into your environment violates assumptions.


In Bran's tutorial (and mine, and many others) only two GDT entries are used - code and data. Both start at 0 and end at 0xFFFFFFFF, the only difference being the flags - one's a code segment, the other a data. Basically just enough to make the segmentation hardware work, almost transparently.

James
InsightSoft
Member
Member
Posts: 76
Joined: Mon Aug 18, 2008 6:17 am

Re: What's problem with this code?

Post by InsightSoft »

This descriptor definition are made at C 32 code, right?
What I'm trying to do (maybe in a wrong way) is create the correct environment to execute the C code...

the tutorial: it seems to me that grubs bring the machine to the PM with simplest (or necessary) 32 bit descriptor to fit next 'to be loaded' 32 bit code (at 0x0010000)... (and the asm+c are compiled to start at that address [definition at link.ld script file])

This code, after jumped will set a new descriptors... (the real kernel specification)

I'm completely wrong?
Post Reply