Write to 0xB8000 does't work

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.
spiner900
Member
Member
Posts: 26
Joined: Mon Mar 09, 2009 10:47 am

Write to 0xB8000 does't work

Post 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 !!
User avatar
kmtdk
Member
Member
Posts: 263
Joined: Sat May 17, 2008 4:05 am
Location: Cyperspace, Denmark
Contact:

Re: Write to 0xB8000 does't work

Post 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
well, what to say, to much to do in too little space.
when it goes up hill, increase work, when it goes straight, test yourself but when going down, slow down.
spiner900
Member
Member
Posts: 26
Joined: Mon Mar 09, 2009 10:47 am

Re: Write to 0xB8000 does't work

Post by spiner900 »

I'm in Pmode but why I have to switch 0x2 with 'H' ???
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Write to 0xB8000 does't work

Post 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.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
gzaloprgm
Member
Member
Posts: 141
Joined: Sun Sep 23, 2007 4:53 pm
Location: Buenos Aires, Argentina
Contact:

Re: Write to 0xB8000 does't work

Post 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
Visit https://gzalo.com : my web site with electronic circuits, articles, schematics, pcb, calculators, and other things related to electronics.
Laksen
Member
Member
Posts: 140
Joined: Fri Nov 09, 2007 3:30 am
Location: Aalborg, Denmark

Re: Write to 0xB8000 does't work

Post 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:
http://j-software.dk | JPasKernel - My Object Pascal kernel
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Write to 0xB8000 does't work

Post 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.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
spiner900
Member
Member
Posts: 26
Joined: Mon Mar 09, 2009 10:47 am

Re: Write to 0xB8000 does't work

Post 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);
}
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Write to 0xB8000 does't work

Post by neon »

Assuming you are using GCC, please post your LD linker script.

Also, whats with all of the Uneeded text output? ;)
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
spiner900
Member
Member
Posts: 26
Joined: Mon Mar 09, 2009 10:47 am

Re: Write to 0xB8000 does't work

Post 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)
	}
}


User avatar
gzaloprgm
Member
Member
Posts: 141
Joined: Sun Sep 23, 2007 4:53 pm
Location: Buenos Aires, Argentina
Contact:

Re: Write to 0xB8000 does't work

Post 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
Visit https://gzalo.com : my web site with electronic circuits, articles, schematics, pcb, calculators, and other things related to electronics.
spiner900
Member
Member
Posts: 26
Joined: Mon Mar 09, 2009 10:47 am

Re: Write to 0xB8000 does't work

Post 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
User avatar
gzaloprgm
Member
Member
Posts: 141
Joined: Sun Sep 23, 2007 4:53 pm
Location: Buenos Aires, Argentina
Contact:

Re: Write to 0xB8000 does't work

Post 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)
Visit https://gzalo.com : my web site with electronic circuits, articles, schematics, pcb, calculators, and other things related to electronics.
spiner900
Member
Member
Posts: 26
Joined: Mon Mar 09, 2009 10:47 am

Re: Write to 0xB8000 does't work

Post by spiner900 »

Oh sorry ... my kernl is 8Ko
User avatar
gzaloprgm
Member
Member
Posts: 141
Joined: Sun Sep 23, 2007 4:53 pm
Location: Buenos Aires, Argentina
Contact:

Re: Write to 0xB8000 does't work

Post 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
Visit https://gzalo.com : my web site with electronic circuits, articles, schematics, pcb, calculators, and other things related to electronics.
Post Reply