问题
I'm currently developing an OS kernel from scratch.
I want to use a function to write characters on the screen , using the 0xB8000 memory location.
the problem is the following :
I use :
void video_write(const unsigned char *string , char color ){
unsigned char *p = (unsigned char*) string ;
char *c = (char*) (VIDEO_MEMORY ); //VIDEO_MEMORY is 0XB8000
while(*p != '\0')
{
*c = p[0] ;
c++ ;
*c = color ;
c++ ;
p++ ;
}
}
void clear_screen(){
char *c = (char*) VIDEO_MEMORY ;
int i = 0 ;
for(i ; i < 4000 ; i++){
*c='\0' ;
c++ ;
}
}
to print to the screen .
The function is called by :
void main(){
clear_screen() ;
video_write("Message\0" , 0x0E);
}
The OS boots correctly , but upon entering 32 bits PM and printing the message , I get this :
There is one additional character , at the beginning of the string , that I did not put.
When I dump the memory at 0xB8000 , I get this :
00000000: c30e 4d0e 650e 730e 730e 610e 670e 650e ..M.e.s.s.a.g.e.
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
4D in Hex is "M" . It should be the first character in the string , but it isn't , for god knows what reason. Instead the first character is C3 , which is the garbage at the beginning of the string.
Nevertheless , printing these characters directly from the main() function works flawlessly , so my guess is that the pointer of the string got corrupted .
Do you guys have any idea of what's happening there ?
EDIT: Here's the Bootloader code :
ifndef BOOT_ASM
%define BOOT_ASM
[org 0x7C00]
KERNEL_OFFSET equ 0x1000
[bits 16]
mov [BOOT_DRIVE] , dl
mov BP , 0x9000
mov SP , BP
call load_kernel
call switch_pm
%include "print.asm"
%include "hexprint.asm"
%include "disk_io.asm"
%include "GDT.asm"
load_kernel :
mov SI , KERNEL_MSG
call print_string
mov BX , KERNEL_OFFSET
mov DH , 15
mov DL , [BOOT_DRIVE]
call disk_load
ret
switch_pm:
cli
lgdt [gdt_descriptor]
mov EAX , CR0
or EAX , 1
mov CR0 , EAX
jmp CODE_SEG:PM_init
[bits 32]
PM_init:
mov AX , DATA_SEG
mov DS , AX
mov SS , AX
mov ES , AX
mov FS , AX
mov GS , AX
mov EBP , 0x90000
mov ESP , EBP
call BEGIN_PM
jmp $
BEGIN_PM :
call KERNEL_OFFSET
ret
BOOT_DRIVE: db 0
RM_MSG db "SAHARA OS , Real mode" , 0x0
PM_MSG db "SAHARA OS , Protected mode" , 0x0
KERNEL_MSG db "SaharaOS : Oasis kernel " , 0x0A , 0x0D , 0x0
times 510 - ($-$$) db 0
dw 0xaa55
%endif
(DATA_SEG is the in the GDT , gdt_data - gdt_start)
At 0x1000 I execute this code , which is the kernel entry
[bits 32]
[extern main]
call main
jmp $
When dumping the memory after clear_screen() , I only get 0 , so this is working as intended.
I think it's really the string variable that contains this character , because when I do :
void video_write(const unsigned char *string , char color ){
unsigned char *p = (unsigned char*) string ;
p++ ;
char *c = (char*) (VIDEO_MEMORY ); //VIDEO_MEMORY is 0XB8000
while(*p != '\0')
{
*c = *p ;
c++ ;
*c = color ;
c++ ;
p++ ;
}
adding the "p++;" , the message prints without artifacts. So I don't think it's some garbage that was put specifically in 0xB8000. Offsetting the video memory so that the message prints in the middle of the screen for example , gives the same result : when I offset VIDEO_MEMORY by any value :
void video_write(const unsigned char *string , char color ){
unsigned char *p = (unsigned char*) string ;
char *c = (char*) (VIDEO_MEMORY + 1980 ); //VIDEO_MEMORY is 0XB8000
while(*p != '\0')
{
*c = p[0] ;
c++ ;
*c = color ;
c++ ;
p++ ;
}
I get this :
回答1:
EDIT : okay , so I just figured where the problem was , but not really why. The problem is from the compilation and the linking ... I compiled previously for 64 bits elf , I just changed to 32 bits compiling/linking everywhere and the text prints correctly without artifacts.
来源:https://stackoverflow.com/questions/58633806/weird-behavior-when-writing-to-0xb8000-corrupted-pointer