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.
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: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?
I haven't used GRUB, but what I gather from the Multiboot specification is that GRUB initializes a protected-mode environment, loads your code (be it a kernel or another bootloader) at an address that you specify (which however needs to be above the 1M mark), and executes it. You are required to load a new GDTR and IDTR, and provide a Multiboot header somewhere in the first 4096 bytes of the image to be loaded, if you don't use the ELF file format.
InsightSoft
Member
Member
Posts: 76
Joined: Mon Aug 18, 2008 6:17 am

Re: What's problem with this code?

Post by InsightSoft »

That's way I love this game!!!
I'm starting getting lost and... here I am, trying to figure it out!!! (:

Reviewing my code:

1) Boot
-load {Kernel.Stage.1} [asm 16 bits] to 7000:0000;
2) Kernel.Stage.1 (7000:0000) (16 bits)
-create and fill a simple GDT
gdt_tbl.dummy (0) - (you know...)
gdt_tbl.ks1code (0x9a, 0x0) - For first jmp to PM
gdt_tbl.ks1video (0x92, 0x0) - for simple print to...
gdt_tbl.ks2code (0x9a, 0xcf) - for the kernel final stage (asm+c 32 bit code) [9000:0000]
gdt_tbl.c32stack (0x92, 0xC0) - for stack 32 bit operations
gdt_tbl.c32code (0x9a, 0xcf) - not necessary/not used
gdt_tbl.c32data (0x92, 0xcf) - for DS, ES, etc

load code [asm+c] to 9000:0000
fill the addresses...
enable A20
jmp to PM (descriptor 8)

already in PM
jmp to 24:0 (9000:0000)

3) at asm+c (9000:0000 or descriptor 24:0)
-asm
point SS to the 0x20:ffff (only 65535 bytes)
point DS, ES, FS and GS to descriptor 48
call C main function
-c main function
call gdt_install();
- define gp and gdt
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);

works fine until next function...
gdt_flush(); (defined previous asm file) - crash here

...and as told (ru2aqare), I need to compensate the p.a. of _gp with the offset of starting point of the asm code...
But what's wrong on my sadly way to replace the grub (of course, on the very simple task, load and run the 'kernel')?...

And of course, i'm sorry for boring you with this kind of problems...
It has been a real bit by bit approach... sorry (:
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 »

If you have a working GDT when the C code receives control, why do you need to replace it? Other that that, I can't imagine why it triple faults.
InsightSoft
Member
Member
Posts: 76
Joined: Mon Aug 18, 2008 6:17 am

Re: What's problem with this code?

Post by InsightSoft »

Well, I just want to execute the the C kernel code from the tutorial (without grub)... it's all I want...
but, anyway, it seems that I need to resolve the address of _gp...

the major problem is that I'm trying to accommodate that code to a new reality... while I'm starting to learn this first stage of OS dev... but, I will be there (:
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:Well, I just want to execute the the C kernel code from the tutorial (without grub)... it's all I want...
but, anyway, it seems that I need to resolve the address of _gp...

the major problem is that I'm trying to accommodate that code to a new reality... while I'm starting to learn this first stage of OS dev... but, I will be there (:
If you know at compile time where your code will be loaded, then calculating the address of _gp is easy.

Code: Select all

    call  _prnt
    mov   ebx, 09000h*16 ; < segment where the code is loaded * 16
    lgdt  [ebx + _gp]
    call  _prnt
If it is any help, I can try to post my first stage loader (I don't know if I can squeeze it into the 3*64K allowed for attachments). It performs similar steps, however it is a bit more complex (it supports long mode and v86 monitor).
InsightSoft
Member
Member
Posts: 76
Joined: Mon Aug 18, 2008 6:17 am

Re: What's problem with this code?

Post by InsightSoft »

for sure it will help... I'm eager for information... I eat everything... (i'm just kidding)...
You can, if you want, send to [email protected] or if you prefer, to [email protected]...

I know that the code will be loaded to 9000:0000 (pa 90000)... and it will be something like [90000 + offset of _gp]... (I hope it works...) ...
InsightSoft
Member
Member
Posts: 76
Joined: Mon Aug 18, 2008 6:17 am

Re: What's problem with this code?

Post by InsightSoft »

no way...
let start in hard way...

Code: Select all

[BITS 16]

;structures
	struc gdt_adr
		.limit 		resw 1
		.base		resd 1
	endstruc

	struc gdt_tbl
		.dummy		resb	8
		.ks1code	resb	8
		.ks1video	resb	8
		.ks2code	resb	8
		.c32stack	resb	8
		.c32code	resb	8
		.c32data	resb	8
	endstruc

	_ptr	equ	0x0	

	
;External functions



;the code
	global start
	start:
	
		xor eax, eax
	    mov ax, cs 
  		mov ds, ax

  		shl eax, 4
  		add eax, gdt_tbl_start + _ptr 
  		mov [gdt + gdt_adr.base + _ptr], eax 
	      	      
		;kernel stage 1 gdt.limit
		mov Eax, gdt_tbl_finish - gdt_tbl_start
	    mov [gdt + gdt_adr.limit + _ptr], ax    

		;code
		xor eax, eax
		mov ax, cs
		
		and eax, 0xFFFF
		shl eax, 4
        add ax, start + _ptr
        mov word [gdt_tbl_start + gdt_tbl.ks1code + _ptr + 2], ax
        shr eax,16
        mov byte [gdt_tbl_start + gdt_tbl.ks1code + _ptr + 4], al    		
			

		;stack for 32 bits code
		xor eax, eax
		mov ax, 0x8000
		
		and eax, 0xFFFF
		shl eax, 4
        add ax, 0
        mov word [gdt_tbl_start + gdt_tbl.c32stack + _ptr + 2], ax
        shr eax,16
        mov byte [gdt_tbl_start + gdt_tbl.c32stack + _ptr + 4], al   
         		

		;32Bit code
		xor eax, eax
		mov ax, 0x9000
		
		and eax, 0xFFFF
		shl eax, 4
        add ax, 0
        mov word [gdt_tbl_start + gdt_tbl.ks2code + _ptr + 2], ax
 
 mov word [gdt_tbl_start + gdt_tbl.c32data + _ptr + 2], ax
 
        shr eax,16
        mov byte [gdt_tbl_start + gdt_tbl.ks2code + _ptr + 4], al    		
 
 mov byte [gdt_tbl_start + gdt_tbl.c32data + _ptr + 4], al    		

		
		cli		
		call Enable_A20	
		
		sti

		;Load final kernel stage
		mov ax, 0x9000
		mov es, ax
		xor bx, bx					  
        mov ah, 0x02                     ; service 2 (read disk sector)
        mov al, 0x10                     ; number of sector to read [(512 x 2=1024) = 512=CPU; 512=Library]
		mov ch, 0x00                     ; track/cylinder number (0-1023)
		mov cl, 0x03                     ; sector number (1-17)
		mov dh, 0x00                     ; head number (0-15)
		mov dl, 0x00                     ; drive a:
		int 0x13                         ; action					
        jnc _set_gdt
		
		mov ax, 0
		int 0x16	
		
		db 0xEA
        dw 0x0000
        dw 0xffff										

	_set_gdt:
		;load gdt
		cli
		LGDT [gdt + _ptr]
				
		;goto PM - no interrup, there's no IDT
		mov eax, cr0
        or eax, 1
        mov cr0, eax 
        
		;jmp to PM code (clear buffer)
		db 0xEA
        dw pm_start + _ptr
        dw 8				;jump to 16Bits (PM)		; 00000000 00001000:x
                                                        ;              ||+-> 00=higest level
                                                        ;			   |+-->  0=gdt
                                                        ;              +--->  1=selector 1 
		pm_start:
			db 0xEA
	        dw 0
	        dw 24			;jump to 32Bits (PM)
	        
		;-------------Enable A20 Gate-----------------------------------------------
		Enable_A20:
	        call    a20wait
	        mov     al,0xAD
	        out     0x64,al
	        call    a20wait
	        mov     al,0xD0
	        out     0x64,al	
	        call    a20wait2
	        in      al,0x60
	        push    eax	
	        call    a20wait
	        mov     al,0xD1
	        out     0x64,al
	        call    a20wait
	        pop     eax
	        or      al,2
	        out     0x60,al
	        call    a20wait
	        mov     al,0xAE
	        out     0x64,al
	        call    a20wait
	        ret	
			a20wait:
		        in      al,0x64
		        test    al,2
		        jnz     a20wait
		        ret
			a20wait2:
		        in      al,0x64
		        test    al,1
		        jz      a20wait2
		        ret				
		;-------------Global Descriptor Table-----------------------------------------
		gdt:	
			istruc gdt_adr
				at gdt_adr.limit, 		dw 0x0000		;at run-time
				at gdt_adr.base, 		dd 0x00000000	;at run-time
			iend
		
		gdt_tbl_start:
			istruc gdt_tbl
				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 0xC0		
		                   				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 0x92			;
		                   				db 0xcf			;
		                   				db 0x0			;

			iend	
		gdt_tbl_finish:
		;-------------end of Global Descriptor Table-----------------------------------

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, 48
	    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], bl
	    	ret
	    	
	    global _gdt_flush
		extern _gp
		_gdt_flush:
    		lgdt [_gp]

			mov bl, 'x'
			call _prnt
			
    		mov ax, 0x10
		    mov ds, ax
		    mov es, ax
		    mov fs, ax
		    mov gs, ax
		    mov ss, ax
		    
		    jmp 0x08:flush2
			
			flush2:
		    	ret
			

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)
{
    gdt[num].base_low = (base & 0xFFFF);
    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()
{
	gdt_install();	
    for (;;);
    return 0; 
}


to compile 16 bit code

Code: Select all

OUTPUT_FORMAT("binary")

ENTRY(start)

phys = 0x0;

SECTIONS
{
  .text phys : AT(phys) {
    code = .;
    *(.text)
    *(.rodata)
    . = ALIGN(512);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(512);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(.bss)
    . = ALIGN(512);
  }
  end = .;
}
to compile a 32 bit code

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(KernelEntry)

phys = 0x00001000;

SECTIONS
{
  .text phys : AT(phys) {
    code = .;
    *(.text)
    *(.rodata)
    . = ALIGN(4096);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
  end = .;
}
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:no way...
let start in hard way...
And how do I compile this code? I am using Cygwin.

Code: Select all

$ nasm -f win32 a16.asm
a16.asm:36: error: COFF format does not support non-32-bit relocations
a16.asm:40: error: COFF format does not support non-32-bit relocations
...

$ nasm b32.asm
b32.asm:20: error: binary output format does not support external references
b32.asm:35: error: binary output format does not support external references
InsightSoft
Member
Member
Posts: 76
Joined: Mon Aug 18, 2008 6:17 am

Re: What's problem with this code?

Post by InsightSoft »

ECHO Building: BOOT
%tools%\masm611\bin\ml boot.asm /AT

ECHO Building: KRNLS1 (Kernel first stage)
%tools%\nasm\nasm -f aout -o KRNLS1.o KRNLS1.asm

ECHO Building: KRNLS2 (Kernel second stage)
%tools%\nasm\nasm -f aout -o KRNLS2.o krn32.asm

echo Building: KRNLS3 (Kernel 3rt and final stage)
gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o krn32.o krn32.c

echo linking together...
ld -T _scrpt16.ld -o _KRNLS1.bin KRNLS1.o
ld -T _scrpt32.ld -o _KRNL32.bin KRNLS2.o krn32.o



for the boot: masm611
asm 16 bits: nasm (with BITS 16)
asm 32 bits: nasm (with BITS 32)
c 32 bits (djgpp gcc)...
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:ECHO Building: BOOT
echo linking together...
ld -T _scrpt16.ld -o _KRNLS1.bin KRNLS1.o
ld -T _scrpt32.ld -o _KRNL32.bin KRNLS2.o krn32.o
ld fails for me at this step. All previous steps complete, but

Code: Select all

$ ld -T link16.ld -o krnls1.bin krnls1.o
krnls1.o: file not recognized: File format not recognized
The reason is, the Cygwin toolchain supports only COFF format. I don't really have the time to download the sources and tinker with them...
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: What's problem with this code?

Post by Solar »

ru2aqare wrote:The reason is, the Cygwin toolchain supports only COFF format. I don't really have the time to download the sources and tinker with them...
GCC Cross-Compiler... no need to tinker, just download && compile && there you are.
Every good solution is obvious once you've found it.
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:That's way I love this game!!!
I'm starting getting lost and... here I am, trying to figure it out!!! (:

Reviewing my code:

1) Boot
-load {Kernel.Stage.1} [asm 16 bits] to 7000:0000;
2) Kernel.Stage.1 (7000:0000) (16 bits)
-create and fill a simple GDT
gdt_tbl.dummy (0) - (you know...)
gdt_tbl.ks1code (0x9a, 0x0) - For first jmp to PM
gdt_tbl.ks1video (0x92, 0x0) - for simple print to...
gdt_tbl.ks2code (0x9a, 0xcf) - for the kernel final stage (asm+c 32 bit code) [9000:0000]
gdt_tbl.c32stack (0x92, 0xC0) - for stack 32 bit operations
gdt_tbl.c32code (0x9a, 0xcf) - not necessary/not used
gdt_tbl.c32data (0x92, 0xcf) - for DS, ES, etc

load code [asm+c] to 9000:0000
fill the addresses...
enable A20
jmp to PM (descriptor 8)

already in PM
jmp to 24:0 (9000:0000)
GRUB sets up your environment such that both the CS and the {SS=DS=ES=FS=GS} have a base of zero and a length of 0xffffffff. So, the kernel itself is linked to 0x100000, not 0x0 as yours will be.

Not only that, but C compilers assume that SS=DS, which is not the case in your environment. You're violating assumptions made by the compiler, and that will always lead to trouble.

Cheers,

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

Re: What's problem with this code?

Post by InsightSoft »

JamesM wrote: GRUB sets up your environment such that both the CS and the {SS=DS=ES=FS=GS} have a base of zero and a length of 0xffffffff. So, the kernel itself is linked to 0x100000, not 0x0 as yours will be.
Ohh, I see... it's more easy...
JamesM wrote: Not only that, but C compilers assume that SS=DS, which is not the case in your environment. You're violating assumptions made by the compiler, and that will always lead to trouble.
Ok... I didn't knew that... I always thought we could define a empty zone to serve as stack (that's one of my problems)....

Thus, setting the descriptors from 0 to 0xffffffff, covering all the 16bit bios code/data will be at level 0, and starting somewhere in between (for exemple 0x0010000) the kernel will take place... is definitely more simple...

I know that the starting point of my kernel I can define it at LD.exe script file... right? (and it will be only for internal propose, to calculate correctly the displacement of offsets... right?)

Any way, you open my eyes... thanks all of you... you are the greatest
InsightSoft
Member
Member
Posts: 76
Joined: Mon Aug 18, 2008 6:17 am

Re: What's problem with this code?

Post by InsightSoft »

Other question:
Why, in Bran's Kernel Development Tutorial, he sets a new gdt with exactly the same base and limit?

void gdt_install()
{
/* Setup the GDT pointer and limit */
gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
gp.base = &gdt;
/* Our NULL descriptor */
gdt_set_gate(0, 0, 0, 0, 0);
/* The second entry is our Code Segment. The base address
* is 0, the limit is 4GBytes, it uses 4KByte granularity,
* uses 32-bit opcodes, and is a Code Segment descriptor.
* Please check the table above in the tutorial in order
* to see exactly what each value means */
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
/* The third entry is our Data Segment. It's EXACTLY the
* same as our code segment, but the descriptor type in
* this entry's access byte says it's a Data Segment */
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
/* Flush out the old GDT and install the new changes! */
gdt_flush();
}
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 »

I can only think that the tutorial is loaded by GRUB, and GRUB leaves the state of the GDT and IDT undefined. Otherwise I have no clue.
Post Reply