kernel problem (C Pointer)

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

kernel problem (C Pointer)

Post by guest »

hi can anybody say me what is the probleme whith this code??
when I load this with my own bootlaoder the kernel only prints ' ' on the screen (test[0]...test[3] == 0 !!!). when I load this with the bootf02 by John S. Fine all works fine. what can be the problem???

Code: Select all

int main()
{
  char* videomem = (char*)0xB8000;
  char test[] = "LALA";
  
  // doesn't work: prints only '    ' on the screen
  videomem[0] = test[0];
  videomem[1] =  7 ;
  videomem[2] = test[1];
  videomem[3] =  7 ;
  videomem[4] = test[2];
  videomem[5] =  7 ;
  videomem[6] = test[3];
  videomem[7] =  7 ;

  /* works fine with both bootf02 and my own
  videomem[0] = 'L';
  videomem[1] =  7 ;
  videomem[2] = 'A';
  videomem[3] =  7 ;*/

  return 0;
}
frank

Re:kernel problem (C Pointer)

Post by frank »

Code: Select all

  char* videomem = (char*)0xB8000;
  char test[] = "LALA";
I think these need to be unsigned char, not (signed) char.
The difference is that with signed 0x07 is at 128+7 not at 0x07

Code: Select all

  // doesn't work: prints only '    ' on the screen
  videomem[0] = test[0];
  videomem[1] =  7 ;
  videomem[2] = test[1];
  videomem[3] =  7 ;
  videomem[4] = test[2];
  videomem[5] =  7 ;
  videomem[6] = test[3];
  videomem[7] =  7 ;
Why not put this in a loop, or if you're going to test it anyway only print 1 character.
guest

Re:kernel problem (C Pointer)

Post by guest »

I changed it but it doesn't work. the problem is that every item of the array test is 0. thats only an example later i will put all in a loop (and use a function etc.)
frank

Re:kernel problem (C Pointer)

Post by frank »

Something must be wrong / forgotten in your bootup.
This code (basically the same as yours) works:

Code: Select all

   unsigned char* vm = (unsigned char*)0xB8000;
   unsigned char ar[50] = "TEST";
   vm[0] = ar[0];
   vm[1] = 0x07;
Post your bootloader code

I think it's your stack or the segments you haven't re-set after switching to protected mode.
guest

Re:kernel problem (C Pointer)

Post by guest »

thats the function which enters pmode:

Code: Select all

enter_pmode:
   cli

   lgdt [gdt_desc]

   mov eax, cr0      ; enable pmode
   or eax, 1
   mov cr0, eax

   mov eax, DATA_SEL
   mov ds,   eax
   mov es, eax
   mov ss, eax

   mov esp, 0xFFFF

   jmp CODE_SEL:0x1000
frank

Re:kernel problem (C Pointer)

Post by frank »

enter_pmode:
cli

lgdt [gdt_desc]

mov eax, cr0 ; enable pmode
or eax, 1
mov cr0, eax

mov eax, DATA_SEL
mov ds, eax
mov es, eax
mov ss, eax
mov ds,eax
mov gs,eax
mov fs,eax

mov ax, point to your stack
mov ss,ax

mov esp, 0xFFFF

jmp CODE_SEL:0x1000



You forgot to set a few segments including the stack segment.
guest

Re:kernel problem (C Pointer)

Post by guest »

I set the stack to DATA_SEL address, or??

mov eax, DATA_SEL
mov ds, eax
mov es, eax
mov ss, eax

mov esp, 0xFFFF

jmp CODE_SEL:0x1000
frank

Re:kernel problem (C Pointer)

Post by frank »

You should point it to your stack segment.
I don't know where your stack segment starts nor how big it is.
guest

Re:kernel problem (C Pointer)

Post by guest »

OK I added this to my code:

Code: Select all

mov ds,eax
mov gs,eax
mov fs,eax 
    
mov ax, STACK_SEL
mov ss,ax
and this to my GDT:

Code: Select all

; stack descriptor
STACK_SEL equ $-gdt

   dw 0xFFFF      ; limit 15:0
   dw 0x00         ; base  15:0
   db 0x00         ; base  23:16
   db 0x92         ; access byte: present, ring0, code/data segment, non-executable, non-conforming, writeable, not-accessed
   db 0xC0         ; flags: Granularity, 32-bit
   db 0x00         ; base 31:24
but it doesn't work.
frank

Re:kernel problem (C Pointer)

Post by frank »

Post the whole source code or compare your code to john's. (since that one works, you must have forgotten something)
guest

Re:kernel problem (C Pointer)

Post by guest »

my boot.asm:

Code: Select all

[BITS 16]
[ORG 0x7C00]
ALIGN 4

jmp start         ; jump to the code // if any other things a decleared after this

%include 'gdt.inc'

msg_ok      db "OK",10,13,0
msg_failed   db "Failed!!!",10,13,"Halt CPU",0

msg_enable_a20   db "Enable the A20 Gate...",0
msg_load_kernel   db "Load the Kernel...",0

msg_check_cpu   db "Check if CPU is >= 368...",0
msg_need_368   db "Failed",10,13,"Sorry your CPU must be a 368 or better",0

bootdrive db 0

kernel_addr dw 0x100
read_sectors db 0x04

putstr:
   lodsb         ; load the next character
   or al,al      ; if al = 0 (= character)
   jz short putstrd   ; return
   mov ah, 0x0E      ; function 0x0E (display character)
   mov bh, 0x00      ; current page
   mov bl,   0x07      ; color
   int 0x10      ; call display interrupt
   jmp putstr
putstrd:
   ret

check_cpu:
   ; i left this out because the message was too long
.386

enable_a20:
   cli         ; disable interrupts
   call wait_key_buf   ; wait for kbd buffer to clear

   mov al,0xd1      ; tell it we want to write to output port
   out 0x64,al
   
   call wait_key_buf   ; wait again for kbd to clear

   mov al,0xdf      ; set desired settings (A20 gate)
   out 0x60,al      ; send value to data reg

   call wait_key_buf   ; wait for kbd to clear

   mov cx,0x10      ; loop count
   
   kbdwait:
      xor ax,ax   ; do anything
      out 0xe0,ax   ; some mor nonsense
   loop kbdwait            ; loop to waste time


   ;-------------- check if a20 was enabled --------------
   
   mov al,0xd0
   out 0x64,al      ; tell kbdc we want to read output port
   call wait_key_buf_data   ; wait for data to get in it
   in al,0x60      ; get it
   test al,2      ; test if A20 is on
   jnz a20_on      ; if it is clear, then it is off

   jmp error

   a20_on:
   ret


wait_key_buf:
   xor al,al      ; al = 0
   in  al, 0x64      ; get kbd status
   test al, 2      ; is bit 1 clear?
   jnz wait_key_buf   ; if not wait some more
   
   ret

wait_key_buf_data:
   xor cx,cx      ; cx = 0
   in al, 0x64      ; get kbd status
   test al, 1      ; is bit 0 clear?
   jz wait_key_buf_data   ; if not wait some more
   ret

load_kernel:
   clc         ; clear the carry flag
   mov ecx, 5      ; try to reset the driver 5 times

   reset_drive:
   xor ax, ax      ; ax = 0
   mov dl, [bootdrive]   ; dl = bootdrive
   int 0x13      ; reset drive
   jnc reset_ok      ; if carry flag = 0
   loop reset_drive   ; else try it again if ecx != 0
   
   jmp error      ; if ecx = 0 and the reset always failed, halt

reset_ok:
   mov ecx, 5      ; try to read the kernel 5 times

    read_kernel:
   mov ax, [kernel_addr]
   mov es, ax      ; address of the buffer
   mov ah, 0x02      ; function number 2 (read from disk)
   mov al, [read_sectors]   ; number of sectors to read
   mov dl, [bootdrive]   ; set drive
   mov dh, 0x00      ; read/write head number
   mov ch, 0x00      ; number of the track or cylinder (0 = first)
   mov cl, 0x02      ; number of the sector where to start (1 = first)
   xor bx, bx      ; offset of the buffer
   int 0x13

   jnc load_ok      ; if all is ok return

   loop read_kernel   ; try once again if there is an error

   jmp error      ; if ecx = 0 and the read operation always failed, halt

load_ok:   
   ret

enter_pmode:
   cli

   lgdt [gdt_desc]

   mov eax, cr0      ; enable pmode
   or eax, 1
   mov cr0, eax

   mov eax, DATA_SEL
   mov ds,   eax
   mov es, eax
   mov ss, eax
   mov ds,eax
   mov gs,eax
   mov fs,eax

   mov ax, STACK_SEL
   mov ss,ax
    

   mov esp, 0xFFFF

   jmp CODE_SEL:0x1000

   cli
   hlt
   jmp $-2
   

error:
   mov si, msg_failed
   call putstr
   cli
   hlt
   jmp $-2


start:
   cli
   mov [bootdrive], dl   ; save the bootdrive

   mov ax, 0x9000
   mov ss, ax      ; setup the stack at 0x9000
   mov esp, 0x8000      ; set the stack size
   sti

   mov ax,0x0000      ; ax = 0
   mov es,ax               ; correct the segment register
   mov ds,ax

   call check_cpu

.386
   mov si, msg_enable_a20
   call putstr

   call enable_a20
   
   mov si, msg_ok
   call putstr

   mov si, msg_load_kernel
   call putstr

   call load_kernel   ; load the kernel

   mov si, msg_ok
   call putstr

   call enter_pmode

   cli
   hlt
   jmp $-2


times 510-($-$$) db 0

db 0x55
db 0xAA
guest

Re:kernel problem (C Pointer)

Post by guest »

Thank you for looking at the code!

my gdt.inc:

Code: Select all

gdt:
; null descriptor
   dw 0         ; limit 15:0
   dw 0         ; base 15:0
   db 0         ; base 23:16
   db 0         ; type
   db 0         ; limit 19:16, flags
   db 0         ; base 31:24
; stack descriptor
STACK_SEL equ $-gdt

   dw 0xFFFF      ; limit 15:0
   dw 0x00         ; base  15:0
   db 0x00         ; base  23:16
   db 0x92         ; access byte: present, ring0, code/data segment, non-executable, non-conforming, writeable, not-accessed
   db 0xC0         ; flags: Granularity, 32-bit
   db 0x00         ; base 31:24
; data descriptor
DATA_SEL equ $-gdt

   dw 0xFFFF      ; limit 15:0
   dw 0x00         ; base  15:0
   db 0x00         ; base  23:16
   db 0x92         ; access byte: present, ring0, code/data segment, non-executable, non-conforming, writeable, not-accessed
   db 0xC0         ; flags: Granularity, 32-bit
   db 0x00         ; base 31:24

; code descriptor
CODE_SEL equ $-gdt

   dw 0xFFFF      ; limit 15:0
   dw 0x00         ; base  15:0
   db 0x00         ; base  23:16
   db 0x9A         ; access byte: present, ring0, code/data segment, executable, non-conforming, readable, not-accessed
   db 0xC0         ; flags: Granularity, 32-bit
   db 0x00         ; base 31:24

gdt_end:

gdt_desc:
   dw gdt_end - gdt - 1   ; GDT limit
   dd gdt         ; linear address of GDT
frank

Re:kernel problem (C Pointer)

Post by frank »

kernel_addr dw 0x100
You've loaded your kernel at 0x1000, not 0x100
Change into kernel_addr dw 0x1000

I think the empty character(s) came from
mov si, msg_ok
call putstr

I suppose it has not went into main() 'cause it jumped to 0x100.
I don't know why it hasn't crashed though.. probably cause at 0x100 the first data is empty.
guest

Re:kernel problem (C Pointer)

Post by guest »

no that's not the problem because in real mode the address is 0x100 in protected mode 0x1000. if i jmp to CODE_SEL:0x100 the cpu crashes
frank

Re:kernel problem (C Pointer)

Post by frank »

no that's not the problem because in real mode the address is 0x100 in protected mode 0x1000.
segmented (real mode address) is basically the same as linear addresseses in protected mode when paging is not enabled.
So 0x1000 is 0x1000
0x100 is 0x100
Change it into dw 0x1000

Code: Select all

 if i jmp to CODE_SEL:0x100 the cpu crashes
Correct, 'cause your kernel should be loaded at 0x1000, you'll have to jump to 0x1000
Have a look at http://my.execpc.com/~geezer/osd/ram/
The free memory starts at 0x500
Post Reply