i have a little problem with my "os": i have written a 16 bit bootloader what loads a 16 bit code! this bootloader is working! i have tested it with a asm kernel! now bcc have generated me the following 16 bit asm code: (c code: int main(){ char *text = "Hi I am the Railex Kernel"; char *vidMem = (char*) 0xA800;
export _main
_main:
! 10 char *text = "Hi I am the Railex Kernel";
push bp
mov bp,sp
push di
push si
dec sp
dec sp
mov bx,#.1
mov -6[bp],bx
! 11 char *vidMem = (char*) 0xA800;
dec sp
dec sp
mov ax,#$A800
mov -8[bp],ax
! 12
! 13 while(*text){
jmp .3
.4:
! 14 *vidMem = *text;
mov bx,-6[bp]
mov si,-8[bp]
mov al,[bx]
mov [si],al
! 15 *vidMem++;
mov bx,-8[bp]
inc bx
mov -8[bp],bx
! 16 *vidMem = 7;
mov bx,-8[bp]
mov al,*7
mov [bx],al
! 17 *vidMem++;
mov bx,-8[bp]
inc bx
mov -8[bp],bx
! 18 *text++;
mov bx,-6[bp]
inc bx
mov -6[bp],bx
! 19 }
! 20
! 21 return 0;
.3:
mov bx,-6[bp]
mov al,[bx]
test al,al
jne .4
.5:
.2:
xor ax,ax
add sp,*4
pop si
pop di
pop bp
ret
! 22 }
! 23
.data
.1:
.6:
.ascii "Hi I am the Railex Kernel"
.byte 0
.bss
! 0 errors detected
now i have assembled and linked it with the following lines:
bcc -S kernel.c -o kernel.asm <-- the c file
as86 kernel.asm -o kernel.o
ld86 kernel.o -o kernel
when i boot my pc with this kernel it does not work i see the output of my bootloader that he loads the kernel but then my pc is frezed only the cursor blinks
waht is the reason of my problem?
thanx
hazelnoot!
| | The administrator has disabled public write access.
OSDEV Community
Advertisement
gaf
User Platinum Osdever
Posts: 153
Karma: 10
Re: 16 bit x86 c kernel - 2006/03/10 05:39Hello hazelnoot, first of all the address of the video-memory is 0xB8000 and not 0xA0000. These are physical addresses and, as you can see, they're longer than 4 digits and thus too big to fit into a single 16bit register. This is why segmentation has to be used to access the video-memory in real-mode: DS gets loaded with 0xB800 (physical address/16) and AX with the character's offset in the video-buffer. Your compiler however can't know this why is why it just loads the address to AX:
Code:
mov ax,#$A800
mov -8[bp],ax ; AX is stored on the stack as a local variable
To tell the compiler to use segmentation, you have to declare vidmem as a far pointer (refere to your compiler's documation to find out how exactly this is done) and then initialize it with the physical address of the video-memory, which is 0xB8000.
There's by the way another thing about your C code that you should fix:
Due to the operator's priorities *var_name++ is the same as *(var_name++), which increases the value of the pointer by one, so that it points to the next element, and then dereferences the pointer. The latter step is somewhat redundant as nothing more is done with the dereferenced pointer, so that you could aswell simply write var_name++ - or even better ++var_name, which increases the pointer's value right away, rather then after the line has been executed, so that no temporary variable is needed. To increase the value of the element your pointer points to you by the way have to write (*var_name)++.
Maybe this also sorts out some of the rather awkward assembly code your compiler produces..
regards,
gaf
| | The administrator has disabled public write access.
hazelnoot
User Junior Osdever
Posts: 5
Karma: 0
Re: 16 bit x86 c kernel - 2006/03/11 09:42hi thanx for your answer! but i have one problem i think the bcc(http://dir.filewatcher.com/d/NetBSD/1.5/m68k/bcc-95.3.12.tgz.92909.html) didn't understand "far"! do you know a good 16 bit c compiler for linux or does somebody know how i can use "far" with this compiler? thx!
| | The administrator has disabled public write access.
gaf
User Platinum Osdever
Posts: 153
Karma: 10
Re: 16 bit x86 c kernel - 2006/03/12 08:51According to a tutorial on vga programming (tutorial, code) that I found on the internet, bcc really doesn't seem to support the far keyword. The trick seems to be to tell the compiler to use the large memory model in which all pointers are by default far, so that the whole lower MB can be accessed directly:
Code:
char* vidmem = (char*) 0xB8000000L; /* seg=0xB800 offset=0x0000 */
bcc -ml -S kernel.c -o kernel.asm /* ml = large memory model */
regards,
gaf
| | The administrator has disabled public write access.
DRF
User Platinum Osdever
Posts: 123
Karma: 1
Re: 16 bit x86 c kernel - 2006/03/16 16:19Bit off topic but if your in 16bit real mode you can use the BIOS to print characters to the screen. I just find the BIOS easier to work with if I'm in real mode, but you will have to access the graphics memory in a similar way as your doing now in protected mode.
But in real mode here is a quick paste of a small example bootloader I wrote some time back. The code should be the same or similar in the kernel.
; Main program main: ; Label for the start of the main program
mov ax,0x0000 ; Setup the Data Segment register ; Location of data is DS:Offset mov ds,ax ; This can not be loaded directly it has to be in two steps. ; 'mov ds, 0x0000' will NOT work due to limitations on the CPU
mov si, HelloWorld ; Load the string into position for the procedure. call PutStr ; Call/start the procedure
jmp $ ; Never ending loop
; Procedures PutStr: ; Procedure label/start ; Set up the registers for the interrupt call mov ah,0x0E ; The function to display a chacter (teletype) mov bh,0x00 ; Page number mov bl,0x07 ; Normal text attribute
.nextchar ; Internal label (needed to loop round for the next character) lodsb ; I think of this as LOaD String Block ; (Not the real meaning of the command! is LOaD Single Byte) ; Loads [SI] into AL and increases SI by one ; Check for end of string '0' or al,al ; Sets the zero flag if al = 0 ; (OR outputs 0's where there is a zero bit in the register) jz .return ; If the zero flag has been set go to the end of the procedure. ; Zero flag gets set when an instruction returns 0 as the answer. int 0x10 ; Run the BIOS video interrupt jmp .nextchar ; Loop back round tothe top .return ; Label at the end to jump to when complete ret ; Return to main program
; Data
HelloWorld db 'Hello World',13,10,0
; End Matter times 510-($-$$ db 0 ; Fill the rest with zeros dw 0xAA55 ; Boot loader signature
This is a complete example bootloader so you will have to change some things obviously, but the print string function should work in a kernel if you want to learn from this example and write a similar function as an alternative.
Further info on int 10 function E:
INT 10,E - Write Text in Teletype Mode
AH = 0E AL = ASCII character to write BH = page number (text modes) BL = foreground pixel color (graphics modes)
returns nothing
- cursor advances after write - characters BEL (7), BS (8), LF (A), and CR (D) are treated as control codes - for some older BIOS (10/19/81), the BH register must point to the currently displayed page - on CGA adapters this function can disable the video signal while performing the output which causes flitter.
From HelpPC. (download link is on the bonafide website osdever.net it's a DOS .com file but the documents are all plain txt and the .com file is just the vewer)
Hope this helps, but this is just to make you aware of the alternatives if you didn't already know (or other people reading this thread don't know) and if your happy doing it your way then continue doing it that way.
Daniel
| | The administrator has disabled public write access.