Page 1 of 3

Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 10:59 am
by spiner900
( i'm not very good in english )

Hey, I try to write a simple Kernel in C but I have a problem when I would like to print a char.
I have this and it dont work.

Code: Select all


unsigned char* video = (unsigend char*)0xB8000;

int main(void){
  
  *video++ = 'H';
  *video++ = 0x2;
  *video++ = 'L';
  *video++ = 0x2;
  *video++ = 'L';
  *video++ = 0x2;
  *video++ = 'O';
  *video++ = 0x2;

  return 0;
}

If I put video in the main function, that's work !!

Re: Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 11:02 am
by kmtdk
well
are you in real mode, or in pmode ?
im no c programmer, but you have to change the order, the "0x02" has to come before the "H", and so on ..

KMT dk

Re: Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 11:09 am
by spiner900
I'm in Pmode but why I have to switch 0x2 with 'H' ???

Re: Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 1:25 pm
by neon
spiner900 wrote:I'm in Pmode but why I have to switch 0x2 with 'H' ???
Because you have it backwards.
The first byte is the attibute byte, the second is the ascii character. Not the other way around.

Re: Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 2:04 pm
by gzaloprgm
If I put video in the main function, that's work !!
Hmm, that sounds like a ld config file missing some sections. You could try using linker.ld from JamesMolloy.co.uk or bkerndev.

Cheers,
Gzaloprgm

Re: Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 2:13 pm
by Laksen
neon wrote:
spiner900 wrote:I'm in Pmode but why I have to switch 0x2 with 'H' ???
Because you have it backwards.
The first byte is the attibute byte, the second is the ascii character. Not the other way around.
That's not correct. First, in a little endian system, is the character, then comes the attribute :wink:

Re: Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 2:42 pm
by neon
If I put video in the main function, that's work !!
Hm.. I must have missed that. However it would be more helpful if you show your non working code and further describe "does not work". Also, tell us your tool chain.

Re: Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 2:54 pm
by spiner900
I try the both script but ..... nothing !!!

this is my bootSector

Code: Select all

[BITS 16]
%define SEG_DATA 	0x7C0
%define SEG_PILE 	0x7E0
%define PTR_PILE 	0x820
%define SEG_KERNEL  0x100
%define KERNEL_SIZE  1

;------------------------------------------------
;	Procedure Main 								-
;------------------------------------------------
main:

	;	Initialise le segments de données
	MOV AX, SEG_DATA
	MOV DS, AX
	MOV ES, AX

	; Inisialise le segement de pile et son pointeur
	MOV AX, SEG_PILE
	MOV SS, AX
	MOV SP, PTR_PILE
	
	;	Sauvegarde du périphérique de boot
	MOV [ bootDevice ],DL
	
	;	Affiche le message de boot à l'écran
	MOV  SI, szBootMsg
	CALL printMsg

	;	Chargement du kernel
	CALL loadKernel

	;	Activation du mode protégé
	CALL switchProtectedMode

	;	Réinisialise les segments de la pile

	;	pour qu'il fonctionne en mode protégé

	MOV AX, (gdt_data_desc - gdt_start)
	MOV SS, AX
	MOV ESP, ( SEG_PILE * 10h ) + PTR_PILE
	
	;	Passe la main au Kernel
	;	et réinisialise le segment de code ( descripteur de code )
	;	La multiplication par 10 est pour transformer la valeur
	;	de SEG_KERNEL en 0x0:offset.
	JMP DWORD (gdt_code_desc - gdt_start):(SEG_KERNEL * 0x10)

;------------------------------------------------------------

;	Procedure printMsg 										-
;															-
;	Permet d'afficher une chaîne de caractaire à l'écran	-
;	en utilisant la fonction 0xE de l'interrupteur 0x10		-
;															-
;	Entrée	:	SI -> L'adresse de la chaîne à afficher 	-
;------------------------------------------------------------

printMsg:

	PUSH AX
	MOV AH, 0xE

	.debut:
		LODSB
		CMP AL, 0
		JZ .fin
		INT 0x10
		JMP .debut
	.fin:
		POP AX
RET

;------------------------------------------------------------
;	 Procédure loadKernel									-
;															
;	Permet de charge le kernel en mémoire					-
;	à partir d'une disquette								-
;															-
;	Le kernel doit être sur le deuxième secteur 			-
;	de la disquette ( CHS -> 0/0/2 )						-
;	Utilise la fonction 0x0 et 0x3 de l'interrupt 0x13		-	
;															-
;------------------------------------------------------------

loadKernel:
	PUSHA
	PUSH ES

	; Réinitialisation du lecteur de disquette 
	MOV AH, 0	; Fonction qui sera appelé
	INT 0x13
	MOV BX, SEG_KERNEL
	MOV ES,	BX				; Segment de l'adresse du buffer
	XOR BX, BX				; Offset de l'adresse du buffer
	MOV AH, 0x2				; La fonction qui permet de lire la disquette
	MOV DL, [ bootDevice ]  ; Numéro du lecteur de disquette
	MOV DH, 0				; Numéro de la face de disquette (0 ou 1)
	MOV CH,	0				; Numéro de piste ( Cylindre ) ( 0 à 79 )
	MOV CL,	2				; Numéro de secteur ( 1 à 18 )
	MOV AL, KERNEL_SIZE		; Nombre de secteurs à lire
	INT 0x13

	POP ES
	POPA
RET

;------------------------------------------------------------
;	Procédure switchProtectedMode							-
;															-
;	Permet de passer en mode protégé						-
;	Désactive les interrupts								-
;															-
;------------------------------------------------------------

switchProtectedMode:
	PUSH EAX

	; Désactive les interrupts
	CLI

	; Charge la GDT
	CALL loadGDT
	
	; Passage en mode protégé
	; PE devient 1
	MOV EAX, CR0
	OR AX, 1
	MOV CR0, EAX
	
	; Permet de vider le cache interne du processeur

	JMP .clearCPUCahce
	.clearCPUCahce:

	;	Réinisialise les segments de données
	;	pour qu'il fonctionne en mode protégé
	MOV AX, (gdt_data_desc - gdt_start)
	MOV DS, AX
	MOV ES, AX
	MOV GS, AX
	MOV FS, AX
	POP EAX
RET

;------------------------------------------------------------
;	Procédure loadGDT										-
;															-
;	Permet de remplire la structure 'gdtPtr' et de la		-
;	charger la GDT dans le registre GDTR					-
;															-
;------------------------------------------------------------

loadGDT:
	PUSH AX
	PUSH CX
	
	; Calcule la taile de la GDT
	MOV AX, gdt_end
	MOV CX, gdt_start
	SUB AX, CX
	MOV WORD [gdtPtr], AX

	; Calcule l'adresse physique de la GDT
	XOR CX, CX
	MOV CX, DS
	SHL CX, 4
	ADD CX, gdt_start
	MOV DWORD[gdtPtr + 2], ECX

	; Charge la GDT dans le registre GDTR
	LGDT [ gdtPtr ]
	POP CX
	POP AX
RET

;------------------------------------------------
;			Section des variables				-
;------------------------------------------------
bootDevice 			DB 0
szBootMsg 			DB 13,10,"Chargement du systeme...",13,10,0
szA20Msg 			DB "Chargement de A20...",0
szGdtMsg 			DB "Chargement de la GDT...",0
szIdtMsg			DB "Chargement de la IDT...",0
szProtected32Msg	DB "Activation du mode protege 32 bits...",0

gdt_start:
	gdt_null_desc:
	DB 0, 0, 0, 0, 0, 0, 0, 0						;	NULL
	gdt_code_desc:
	DB 0xFF, 0xFF, 0, 0, 0, 10011011b, 11001111b, 0	;	code
	gdt_data_desc:
	DB 0xFF, 0xFF, 0, 0, 0, 10010011b, 11001111b, 0	;	DATA
gdt_end:

gdtPtr:
	DW 0	;	La taille
	DD 0	;	Son adresse

; S'assure que le fichier soit de 512 octects
times 510 - ( $ - $$ ) DB 0

; Nombre magic pour rendre le fichier amorcable
DW 0xAA55
this is the main.c

Code: Select all

unsigned char* p = (unsigned char*)0xB8000;

void kernel_main( void ){
	#if DEBUG_MODE == 1
		char* string = "Kernel is speaking !!";	
		char* c = (char*)0xB8000;
		
		while( *string ){
			*c++ = *string++;
			*c++ =	0x2;
		}
	#endif	
	
	*p++ = 'A';
	*p++ = 0x2;
	*p++ = 'A';
	*p++ = 0x2;
	*p++ = 'A';
	*p++ = 0x2;

	while(1);
}

Re: Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 3:05 pm
by neon
Assuming you are using GCC, please post your LD linker script.

Also, whats with all of the Uneeded text output? ;)

Re: Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 3:32 pm
by spiner900
this is my linker script

Code: Select all

/*
*	Fichier	:	linker.ls
*	Auteur	:	Luc Spinelli
*	Data	:	22 Février 2009
*	Modifier:	--------
*	Version	:	1.0
*/
/*STARTUP(../../objs/debug/kernel/kernel.o)*/
OUTPUT_FORMAT(binary)
ENTRY(kernel_main)
SECTIONS{
	. = 0x1000;
	.text : {
		*(.text)
	}
	.data : {
		*(.data)
		*(.rodata)
	}
	.bss : {
		*(.bss)
	}
}



Re: Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 3:49 pm
by gzaloprgm
Is your kernel size < 512 Bytes ?

Code: Select all

   MOV EAX, CR0
   OR AX, 1
   MOV CR0, EAX
   
   ; Permet de vider le cache interne du processeur

   JMP .clearCPUCahce
   .clearCPUCahce:

   ;   Réinisialise les segments de données
   ;   pour qu'il fonctionne en mode protégé
   MOV AX, (gdt_data_desc - gdt_start)
   MOV DS, AX
   MOV ES, AX
   MOV GS, AX
   MOV FS, AX
Is that middle jump needed?
Cheers,
Gzaloprgm

Re: Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 4:45 pm
by spiner900
Yes my kernel size is 512

Code: Select all

times 510 - ( $ - $$ ) DB 0
For the jump, I founnd on the web that when you Sit the 0 byte for the CR0 you have to make un jump to clear the CPU cache

Re: Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 4:51 pm
by gzaloprgm
spiner900 wrote:Yes my kernel size is 512

Code: Select all

times 510 - ( $ - $$ ) DB 0
For the jump, I founnd on the web that when you Sit the 0 byte for the CR0 you have to make un jump to clear the CPU cache
Yes, but you do that in

Code: Select all

JMP DWORD (gdt_code_desc - gdt_start):(SEG_KERNEL * 0x10)
NO; I mean the KERNEL size, not the bootloader size. If in you bootloader you load only 1 sector and your kernel is bigger, probably some things will fail (Global variables/Strings/Etc)

Re: Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 5:02 pm
by spiner900
Oh sorry ... my kernl is 8Ko

Re: Write to 0xB8000 does't work

Posted: Mon Mar 09, 2009 5:25 pm
by gzaloprgm
Hmm, so you kernel does not get loaded completely -> %define KERNEL_SIZE 1 . You only load the first 512 bytes of it.

To avoid that, you may increment that number to lets say 16 Sectors (8KiB) while REMEMBERING SOME (If not all) BIOS load up to 18 Sectors a time AFAIK (correct me if wrong)

Other alternative you may have is to load your kernel one sector per time (with a loop or je/jne&inc/dec) or use some premade bootloader, such as neon's (http://brokenthorn.com - Loads up to 64KiB Kernel), GRUB. However, if you use GRUB, remember it may require your OS to be GPL'd or similar.

Cheers,
Gzaloprgm