Page 2 of 4
Re: What's problem with this code?
Posted: Thu Sep 18, 2008 10:21 am
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
Re: What's problem with this code?
Posted: Thu Sep 18, 2008 10:48 am
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?
Re: What's problem with this code?
Posted: Thu Sep 18, 2008 11:07 am
by InsightSoft
Ok, thanks...
it will works any way...
Re: What's problem with this code?
Posted: Thu Sep 18, 2008 12:45 pm
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?
Re: What's problem with this code?
Posted: Thu Sep 18, 2008 1:59 pm
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.
Re: What's problem with this code?
Posted: Fri Sep 19, 2008 10:50 am
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...
Re: What's problem with this code?
Posted: Fri Sep 19, 2008 12:12 pm
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.
Re: What's problem with this code?
Posted: Sat Sep 20, 2008 6:28 am
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...
Re: What's problem with this code?
Posted: Sat Sep 20, 2008 7:34 am
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.
Re: What's problem with this code?
Posted: Sat Sep 20, 2008 11:04 am
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
Re: What's problem with this code?
Posted: Sat Sep 20, 2008 11:35 am
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
Re: What's problem with this code?
Posted: Sun Sep 21, 2008 5:19 am
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)
Re: What's problem with this code?
Posted: Sun Sep 21, 2008 5:34 am
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.
Re: What's problem with this code?
Posted: Sun Sep 21, 2008 6:04 am
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
Re: What's problem with this code?
Posted: Mon Sep 22, 2008 5:05 am
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?