Re:My C kernel does not load - 2006/07/13 03:14IT's WORKING! -> it was my mistake b'cause I gave bochs static path to the image file and these new images I place in different location, so it still shows me up my old images ... stupid mistake... hehe. Tkanks for help a lot...
... but why my inb() and outb() function does not work... b'cause even if I change everything in my code as you have (but without this functions to yours) it does not work still... so the problem are these functions... whats wrong with them? ... and how your functions work... whats the difference...?
ohhh.. and why that type is 0x8E00...? How could I cout it?
Post edited by: wojtekw86, at: 2006/07/13 05:16
| | The administrator has disabled public write access.
OSDEV Community
Advertisement
wojtekw86
User Junior Osdever
Posts: 24
Karma: 0
Re:My C kernel does not load - 2006/07/13 04:44wojtekw86 wrote: ... but why my inb() and outb() function does not work... b'cause even if I change everything in my code as you have (but without this functions to yours) it does not work still... so the problem are these functions... whats wrong with them? ... and how your functions work... whats the difference...?
Works now with my functions inb/outb -> I needed to include <sys/io.h> instead of <asm/io.h> -> there was different definitions of these functions I suppose or something similar... .
| | The administrator has disabled public write access.
gaf
User Platinum Osdever
Posts: 153
Karma: 10
Re:My C kernel does not load - 2006/07/13 09:21ohhh.. and why that type is 0x8E00...? How could I cout it? Chapter 5.11 of the 3rd Intel Manual shows the IDT descriptor layout as it is represented by the gate_desc structure. The type field of the structure maps to the lower 16bits of the second dword of the descriptor ("Interrupt Descriptor" - upper dword - bits 0-15):
but I could not find any function that read the position from screen... Is it possible... I mean in this way: inb(0x3D4)...? B'cause it does not work... so I decided to write an asm function which push current position and when I will need it I will pop it... but I have problems with understanding assembler AT&T inside C code... ... I read some article but it does not work... I want to do something like this:
Code:
pop eax
mov eax, position
push eax
but I do not know how to place C variable in this code so it could be readable and writable...
or mayby better choice is to write this code in asm part and then link to C code... what is more professional way? oohh... here I also does not know how to comunicate with function operands... I tried to look at your funtions WritePort and ReadPort, but I still do not understand... where there are these function arguments in asm code? Thx for help...
| | The administrator has disabled public write access.
gaf
User Platinum Osdever
Posts: 153
Karma: 10
Re:My C kernel does not load - 2006/07/14 06:03But I could not find any function that read the position from screen Why do you need to get the cursor position ? It's only moved by your kernel, so that you can simply use a global variabale to remember the position:
Code:
(cursor.c)
uint cursor_position;
void SetCursor(uchar x, uchar y)
{
ushort temp = y*80 + x;
outb(14, 0x3D4);
outb(temp>>8, 0x3D4+1);
outb(15, 0x3D4);
outb(temp, 0x3D4+1);
cursor_position = temp; // Remember the position
}
uint GetCursor() { return cursor_position; }
void CursorNextLine()
{
// Get the cursor position and jump to the next line
SetCursor((GetCursor() + 79) &(0xffff - 80));
}
(console.c)
void PrintString(char*);
void PrintLine(char* string)
{
CursorNextLine();
PrintString(string);
CursorNextLine();
}
So I decided to write an asm function which push current position and when I will need it I will pop it That can't work as the stack is used all the time to store temporary data (mainly function return-addresses & temporary variables). Leaving anything on the stack when returning from a procedure would lead to a systemcrash:
Code:
int printf(char* string, ...)
{
int number_arguments = GetNumberArguments(string);
int counter = 0;
while(counter < number_arguments)
{
// "Test number %d returns: %#x" , int(2), int(-1)
// Token0: "Test number " Arg0: int(2)
// Token1: " returns: " Arg1: int(-1)
PrintStringToken(string, counter);
PrintArgument(string, counter);
}
}
The code above might produce such a stack-frame:
Code:
3rd argument
2nd argument
1st argument
0th argument
return address of the caller
// int printf(char* string, ...) - We're in line 2
temporary variable: "number_arguments"
temporary variable: "counter"
// Top of the stack (it grows downwards)
Any procedure returns to its caller using the "ret" instruction, which basically just pops the topmost element from the stack and jumps to it (pop ebx, jmp ebx). If the stack is at that point not exactly the same as when the procedure was called, the ret instruction gets the wrong value from the stack and jumps to a faulty memory address.
Your C compiler takes care of the stack and ensures that it's always cleaned up when a procedure returns. In assembler you however have do this yourself: For each push there must a pop and each "sub esp, x" must have a corresponding "add esp, x".
To create non-temporary memory objects at run-time, the heap should be used. This however requires you to write some basic memory-manager..
But I have problems with understanding assembler AT&T inside C code. I do not know how to place C variable in this code so it could be readable and writable Guess I'm not a real expert either, although I do know the basics. In my opinion this tutorial is quite helpful for a beginner.
Code:
int global_variable;
void function()
{
int local_variable;
asm("movl $0, global_variable");
asm("movl $0, %%eax" : : "a"(local_variable));
}
Or mayby better choice is to write this code in asm part and then link to C code... what is more professional way? In most cases it really doesn't matter, so that it's basically a question of personal preference. Inline assembler has the advantage that the compiler knows what's going on, so that it can optimize the code much better. For often used functions (like outport) I'd thus prefere inline assembly - in all other cases it however shouldn't make much of a difference. The other advantage of at&t is, that it's the standard gcc assembler syntax, which makes it more portable (the tool-chain, not the code itself).
Here I also does not know how to comunicate with function operands... where there are these function arguments in asm code? When the assembler function is called the stack looks roughly like that:
Code:
3rd argument
2nd argument
1st argument
0th argument
return address of the caller
As esp can't be used for indexing, one normally chooses ebp to access the parameters. Of course the ebp value has to be saved first:
On top of the stack there's the pushed ebp value and the return-address for the procedure. One thus has to jump over theses two elements when accessing the parameters (ebp+8, ebp+12, etc). At the end of the code ebp must get restored.
regards,
gaf
| | The administrator has disabled public write access.
wojtekw86
User Junior Osdever
Posts: 24
Karma: 0
Re:My C kernel does not load - 2006/07/14 12:45great... works now...
now I wanted to separate some parts of code and move them into headers... so it would be more clear...
so I make klawiatura.h (keyboard), ekran_vga80x25.h (screen), i.h (interrupts table and irq functions etc.)
but I could not separate some parts of code like: "keyb_isr" from starter.asm to klawiatura.h and all irq and idt functions from starter.asm & jadro.c to i.h ... how could I separate it and what is the smartest and most professional way...
#include "zal/ekran_vga80x25.h"
#include "zal/klawiatura.h"
#include "zal/i.h"
void k_main()
{
init_irq(0x20,0x28);
create_idt();
ustpoz(24,0);
print("Prostak OS (wersja z 13.07.2006)", 14);
ustpoz(27,1);
print("autor: Wojciech Wroblewski", 14);
ustpoz(0,3);
print("System status: READY",10);
ustpoz(0,6);
print("Lik#:",7);
}
starter.asm
Code:
[BITS 32]
[EXTERN k_main]
[EXTERN keyb]
[GLOBAL load_idt]
[GLOBAL keyb_isr]
section .text
call k_main
lidt [idtr]
sti
petla:
hlt
jmp petla
keyb_isr:
pusha
push gs
push fs
push es
push ds
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
call keyb
pop ds
pop es
pop fs
pop gs
popa
iret
section .data
idtr:
size: dw 2047
addr: dd 0x2500
offset dd 0
thx for any help... If that code is too big to keep it on this forum please edit this post and cut it off so it will be good...
| | The administrator has disabled public write access.
gaf
User Platinum Osdever
Posts: 153
Karma: 10
Re:My C kernel does not load - 2006/07/14 14:45Now I wanted to separate some parts of code and move them into headers... so it would be more clear Making the code more modular is always a good idea in my opinion. By splitting the source and moving it into several header-files you however merely made the code much easier to read for a programmer - for the compiler it's however still just one huge file. That is because include <x> is a precompiler directive and basically just means "insert all code from x here before compiling". For a smaller project this is no problem as the source isn't that much anyway. Operating systems however tend to eventually grow quite large, so that the time the compiler needs to run through all of the source can get very long (just think of how long it sometimes takes to compile a moderatly large linux program). As you however often only change a very small portion of the code, it would actually be enough to only recompile that module. Especially when you're trying to debug some part, this can save an enomous amount of time... and nerves.
To get such a design you would have to seperate between interface and implementation. The headers then only contain those definitions, that must be visible to the outside, while all the actual code gets moved into additional C files (klawiatura.c + klawiatura.h). All the C files get compiled independant from each other, so that the compiler really only has to update what has been changed in the meantime. The resulting object-files are then combined using the linker. Note that the whole process of compilation and linking can get done automatically by a make-script.
i.h (interrupts table and irq functions etc.) In my opinion you should really consider renaming that file into something more obvious, like "interrupt.h" or at least "int.h" - otherwise it's a bit hard to guess what it contains.
But I could not separate some parts of code like: "keyb_isr" from starter.asm to klawiatura.h Well.. you of course won't get the assembler code into a C header file. The only alternative is write some C procedures that create the stub code at run-time. This however means a lot of work and you'd probably nevertheless need at least one stub as an "example" to copy from.
And all irq and idt functions from starter.asm & jadro.c to i.h I guess you mean init_irq(0x20,0x28) & create_idt() that have to be called from the main function ? You'll never entirely get rid of it, but you can reduce such dependencies by defining some InitialzeX procedures. The kernel then only has to make one call to start the module. This doesn't only make k_main neater, but also helps to create more modular code as the main function doesn't have to bother about how the other modules work internally: It just calls InitialzeX..
Code:
(main.c)
#include <ecran_vga80x25.h>
#include <interrupts.h>
#include <klawiatura.h>
void k_main()
{
InitializeScreen();
InitializeInterrupts();
InitializeKeyboard();
print("Initialization completed", 0);
}
(ecran_vga80x25.h)
extern void InitializeScreen();
extern void print(unsigned char *str, unsigned char color);
(ecran_vga80x25.c)
#include <ecran_vga80x25.h>
// Insert your ecran_vga80x25.h here
void InitializeScreen()
{
ustpoz(0, 0); // Move the cursor to the upper-left corner
}
(interrupt.h)
extern void InitializeInterrupts();
extern void setup_int(int, unsigned long, unsigned short);
(interrupt.c)
// Insert your interrupt.h here
void InitializeInterrupt()
{
init_irq(0x20, 0x28)
}
(klawiatura.h)
extern void InitializeKeyboard();
(klawiatura.c)
#include <klawiatura.h>
#include <interrupt.h>
// Insert rest of your klawiatura.h here
void InitializeKeyboard()
{
// Setting up the keyboard interrupt
setup_int(0x21,(unsigned long)&keyb_isr,0x8E00);
}
The headers still look quite empty at the moment, but I'm sure that you'll have them filled in no time
For an example of a makefile you might have a look at the one I use to compile "my" operating system (link). A more detailed explanation of how makefiles work can be found here.
regards,
gaf
| | The administrator has disabled public write access.
wojtekw86
User Junior Osdever
Posts: 24
Karma: 0
Re:My C kernel does not load - 2006/07/14 15:12So it is bad Idea to move
Code:
keyb_isr:
pusha
push gs
push fs
push es
push ds
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
call keyb
pop ds
pop es
pop fs
pop gs
popa
iret
into C code (some header file)...?
I thought It would be better when it comes to write another irq (similar) function... then I could do it in some header instead of starter.asm... Is it professional and good idea or not...?
| | The administrator has disabled public write access.
gaf
User Platinum Osdever
Posts: 153
Karma: 10
Re:My C kernel does not load - 2006/07/14 16:09So it is bad Idea to move into C code (some header file)...? You actually can't translate this code into C as it requires some special prelude sequence. All the stub really does is to call a C procedure ("call keyb"), the rest of the assembler code is needed to make sure that the current processor state (segments, registers) gets restored when the procedure returns. Pushing the state onto the stack can however only be done in assembler. GCC doesn't know about interrupts and thus also can't create such a special stub for your C function by itself. Inline assembler also won't work here as the procedure itself still remains in C, which means that the compiler adds the standard prelude to it, which however isn't sufficient for interrupts. As the code has to be written in (non-inline) assembler there's of course no point in trying to move it to a header-file, as GCC only understands C code.
I thought It would be better when it comes to write another irq (similar) function... then I could do it in some header instead of starter.asm... Is it professional and good idea or not...? Even if it was possible to move the stub to a header-file, you still couldn't use it for any other interrupts, as it always calls the same C procedure (namely "keyb"). You'll thus, in any case, need one stub for each interrupt. How you create them is up to you: The simplest method definitly is to just add another stub to the assembler file. This is just copy&past and shouldn't take you more than 10 seconds. The alternative is that you create a much more sophicsticated system that can create new instances from a generic example stub. To do so, the C code first has to make a copy of the assembler stub, and then patch some of this copy's instructions (at least the destination of the call instruction). As I already mentioned this is the much more complicated approach, and in my opinion it's really not (yet) needed for your system. Just keep in mind that you won't need more than some 5 interrupts (mouse, keyboard, floppy, timer, systemcall) anytime soon, and that the PIC itself merely support 15 IRQs. Writing assembler stubs for such a small number of interrupts shouldn't really lead to any problems.
cheers, gaf
| | The administrator has disabled public write access.
wojtekw86
User Junior Osdever
Posts: 24
Karma: 0
Re:My C kernel does not load - 2006/07/15 04:16I separate this code as you said... but I have a little problem linking it (compiling is going without errors)...
I get such messages:
Code:
../tmp/entry.o(.text+0x24): In function `keyb_isr':
: undefined reference to `keyb'
../tmp/kernel.o(.text+0xa): In function `main':
: undefined reference to `init_screen'
../tmp/kernel.o(.text+0xf): In function `main':
: undefined reference to `init_int'
../tmp/kernel.o(.text+0x14): In function `main':
: undefined reference to `init_keyboard'
../tmp/kernel.o(.text+0x20): In function `main':
: undefined reference to `setpos'
../tmp/kernel.o(.text+0x2e): In function `main':
: undefined reference to `print'
...
Here is some part of code...
kernel.c
Code:
#include "screen_vga80x25.h"
#include "int.h"
#include "keyboard.h"
int main()
{
init_screen();
init_int();
init_keyboard();
setpos(24,0);
print("Prostak OS (wersja z 13.07.2006)", 14);
return 0;
}
screen_vgs80x25.h
Code:
#include <sys/io.h>
void init_screen();
void setpos(unsigned short,unsigned short);
unsigned short getpos();
void print(unsigned char *, unsigned char);
unsigned short curpos;