Я сейчас занимаюсь разработкой ядра ОС с нуля. Я хочу использовать функцию для записи символов на экране, используя ячейку памяти 0xB8000.
Проблема заключается в следующем:
Я использую:
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++ ;
}
}
для печати на экране.
Функция вызывается:
void main(){
clear_screen() ;
video_write("Message\0" , 0x0E);
}
Операционная система загружается правильно, но после ввода 32-битного PM и печати сообщения я получаю следующее:
В начале строки есть еще один символ, который я не поставил.
Когда я выкидываю память в 0xB8000, я получаю это:
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 в шестнадцатеричном - это "M". Это должен быть первый символ в строке, но это не так, потому что бог знает, по какой причине. Вместо этого первым символом является C3, который является мусором в начале строки.
Тем не менее, печать этих символов непосредственно из функции main () работает безупречно, поэтому я предполагаю, что указатель на строку получилиспорчен.
Ребята, вы хоть представляете, что там происходит?
РЕДАКТИРОВАТЬ: Вот код загрузчика:
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 - это GDT, gdt_data- gdt_start)
В 0x1000 я выполняю этот код, который является записью ядра
[bits 32]
[extern main]
call main
jmp $
При сбросе памяти после clear_screen () я получаю только 0, так что это работает, как и предполагалось.
Я думаю, что это действительно строковая переменная, которая содержит этот символ, потому что, когда я делаю:
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++ ;
}
с добавлением "p ++;"сообщение печатается без артефактов. Так что я не думаю, что это какой-то мусор, который был помещен специально в 0xB8000. Смещение видеопамяти, чтобы сообщение печаталось, например, в середине экрана, дает тот же результат: когда я смещаю VIDEO_MEMORY на любое значение:
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++ ;
}
, я получаю это: