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
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
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
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