Home arrow Forums
OSDEV Forums  


<< Start < Previous 1 2 3 4 5 Next > End >>
wojtekw86
User

Junior Osdever
Posts: 24
graphgraph
Karma: 0  
Re:My C kernel does not load - 2006/07/13 03:14 IT'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
graphgraph
Karma: 0  
Re:My C kernel does not load - 2006/07/13 04:44 wojtekw86 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
graph
Karma: 10  
Re:My C kernel does not load - 2006/07/13 09:21 ohhh.. 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):
Code:

             o----o-------o---------------o--------o bit number: | 15 14 13 12            7    0 |             o----o-------o---------------o--------o value/name: |  |  DPL  0  D  1  1  0 .. |             o----o-------o---------------o--------o


  • P stands for present and has to be set to enable the entry
  • DPL is the ring, if you set it to zero only the kernel may call the interrupt
  • D must be set to make the entry a 32bit descriptor

If you now hack all the bits in your calculator and convert the result to a hexadecimal value, you should end up with 0x8E00.

regards,
gaf
  | | The administrator has disabled public write access.
wojtekw86
User

Junior Osdever
Posts: 24
graphgraph
Karma: 0  
Re:My C kernel does not load - 2006/07/13 10:44 great... thx...

now I have found a function which sets the cursor position on text VGA screen...

Code:

 void pozycja(int x,int y) {     int temp;     temp=(y*80+x);     outb(14,0x3D4);     outb(temp>>8,0x3D4+1);     outb(15,0x3D4);     outb(temp,0x3D4+1); }



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 eaxposition 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
graph
Karma: 10  
Re:My C kernel does not load - 2006/07/14 06:03 But 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 xuchar y) {     ushort temp y*80 x;     outb(140x3D4);     outb(temp>>80x3D4+1);     outb(150x3D4);     outb(temp0x3D4+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(charstring) {     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(charstring, ...) {    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(stringcounter);        PrintArgument(stringcounter);    } }


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:
Code:

 C_code_called_procedure: push ebp mov  ebpesp mov eax, [ebp8// 0th argument mov ebx, [ebp+12// 1st argument mov ecx, [ebp+16// 2nd argument pop ebp ret


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
graphgraph
Karma: 0  
Re:My C kernel does not load - 2006/07/14 12:45 great... 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...

These are files which I could make for now:

klawiatura.h
Code:

 #include <sys/io.h> #define KBD_SPECIAL 200 #define ENTER 10 #define F1 201 #define F2 202 #define F3 203 #define F4 204 #define F5 205 #define F6 206 #define F7 207 #define F8 208 #define F9 209 #define F10 210 #define F11 211 #define F12 212 #define PAUSE 213 extern void keyb_isr(); char scancode_ascii[0x100] = {    KBD_SPECIALKBD_SPECIAL,    '1','2','3','4','5','6','7','8','9','0','-','=',    KBD_SPECIALKBD_SPECIAL,    'q','w','e','r','t','y','u','i','o','p','[',']','n',KBD_SPECIAL,    'a','s','d','f','g','h','j','k','l',';',''',KBD_SPECIAL,'\',    '<','z','x','c','v','b','n','m',',','.','/',KBD_SPECIAL,KBD_SPECIAL,KBD_SPECIAL,    ' ',KBD_SPECIAL,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12,PAUSE,KBD_SPECIAL,KBD_SPECIAL, }; void keyb() {     char key = scancode_ascii[inb(0x60)];     print((char *)&key,3);     outb(0x20,0x20); }



ekran_vga80x25.h
Code:

 #include <sys/io.h> unsigned short pozkur=0; void ustpoz(int x,int y) {     unsigned short temp=(y*80+x);     outb(14,0x3D4);     outb(temp>>8,0x3D4+1);     outb(15,0x3D4);     outb(temp,0x3D4+1);     temp=temp*2;     pozkur=temp; } unsigned short odcpoz() {     return pozkur; } void print(unsigned char *strunsigned char color) {     unsigned char *vga = (unsigned char *)0xb8000;     unsigned int aktpoz=odcpoz();     vga+=aktpoz;     aktpoz=aktpoz/2;     while(*str != 0)     {         *vga = *str;         *(vga 1) = color;         str++;         vga += 2;         aktpoz++;     }     unsigned short X;     unsigned short Y;     Y=aktpoz/80;     X=aktpoz-(Y*80);     ustpoz(X,Y); }



i.h
Code:

 #define KERNEL_IDT            0x2500 #define PIC1 0x20 #define PIC2 0xA0 #define ICW1 0x11 #define ICW4 0x01 typedef struct {   unsigned short offset_0;   unsigned short selector;   unsigned short type;   unsigned short offset_16; } gate_desc; void setup_int(int iunsigned long p_handunsigned short type) {    gate_desc *idt = (gate_desc*)KERNEL_IDT;    idt[i].offset_0  p_hand;    idt[i].selector  0x08;    idt[i].type      type;    idt[i].offset_16 = (p_hand >> 16); } void init_irq(int pic1int pic2) {     outb(ICW1,PIC1);     outb(ICW1,PIC2);     outb(pic1,PIC1 1);     outb(pic2,PIC2 1);     outb(4,PIC1 1);     outb(2,PIC2 1);     outb(ICW4,PIC1 1);     outb(ICW4,PIC2 1);     outb(0xfd,PIC1 1);     outb(0xff,PIC2 1); } void create_idt() {     setup_int(0x21,(unsigned long)&keyb_isr,0x8E00); }



jadro.c
Code:

 #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 ax0x10     mov dsax     mov esax     mov fsax     mov gsax     call keyb     pop ds     pop es     pop fs     pop gs     popa     iret section .data idtr:     sizedw 2047     addrdd 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
graph
Karma: 10  
Re:My C kernel does not load - 2006/07/14 14:45 Now 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 *strunsigned char color); (ecran_vga80x25.c) #include <ecran_vga80x25.h> // Insert your ecran_vga80x25.h here void InitializeScreen() {     ustpoz(00); // Move the cursor to the upper-left corner } (interrupt.h) extern void InitializeInterrupts(); extern void setup_int(intunsigned longunsigned short); (interrupt.c) // Insert your interrupt.h here void InitializeInterrupt() {    init_irq(0x200x28) } (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
graphgraph
Karma: 0  
Re:My C kernel does not load - 2006/07/14 15:12 So it is bad Idea to move
Code:

 keyb_isr:     pusha     push gs     push fs     push es     push ds     mov ax0x10     mov dsax     mov esax     mov fsax     mov gsax     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
graph
Karma: 10  
Re:My C kernel does not load - 2006/07/14 16:09 So 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
graphgraph
Karma: 0  
Re:My C kernel does not load - 2006/07/15 04:16 I 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;



screen_vga80x25.c
Code:

 #include "screen_vga80x25.h" void init_screen() {     setpos(0,0); } void setpos(unsigned short x,unsigned short y) {     ... } unsigned short getpos() {     ... } void print(unsigned char *strunsigned char color) {     ... }



make file:
Code:

 nasm -f bin ../bootloader.asm -../tmp/bootloader.bin nasm -f elf ../entry.asm -../tmp/entry.o gcc -../kernel.-O2 -../tmp/kernel.o ld -Map ../tmp/kernel.map ../tmp/entry.../tmp/kernel.-../link.ld -../tmp/kernel.bin ./merge ../tmp/bootloader.bin ../tmp/kernel.bin ../bin/image.img rm ../tmp



Post edited by: wojtekw86, at: 2006/07/15 05:18
  | | The administrator has disabled public write access.
<< Start < Previous 1 2 3 4 5 Next > End >>

A WebArticles site. Sponsored by Evoleto. Motorola V525 / Business Directory / Delaware Incorporation / Home Made Bazaar