Re:My C kernel does not load - 2006/07/05 10:141) Is GDT some sort of map of memory where I decide where to place VGA Soundcard and other sections, or not? If yes then cool... I just want to know what is it in global meaning... The gdt is part of the segmentation system, which is one of the x86's ways of supporting virtual-addressing. The basic idea behind it is to add a layer of abstraction between raw physical memory and the applications' view of it. As each memory reference goes through that layer, applications can be limited to a certain range of memory, so that they can't interfere with other tasks' data: As soon as some task tries to access memory that is not inside its gdt/ldt, an exception is caused, allowing the operating-system to intervene (eg: by killing the task). Descriptors consist of a base, a limit and a couple of flags defining their behaviour. To activate a descriptor, the OS has to load its offset from the gdt table's start into one of the segment-registers (cs, ds, es, fs, gs, ss) using a regular mov instruction. Jumps and calls are relative to cs, data references may use ds, es, fs or gs and all stack-operations (push, pop, etc) are based on the ss register. Most of today's operating system (aswell as your own code) don't rely on segmentation. They set-up their gdt in a way, so that all descriptor have a base of zero and a limit of 4 Gb ("flat-mode"). This means that the layer of abstraction provided by segmentation gets effectivly disabled, as physical memory is exactly the same as virtual memory again. Nevertheless segmentation is never totally disabled, but always runs under the hood. As it is required later to, for example, enable user-mode task, you also won't get away without learning how segmentation really works.
2) I should set GDT before entering PMODE or I can do it after...? If yes do I must define it before and after or can only after? B'cause I wanted to write this part of code in C... Where should that part of code be placed (where is the best place for it?) The gdt has to be set up (lgdt instruction) before protected-mode gets enabled, but you can change it at anytime. So there's nothing that holds you from creating a new gdt in your C code, although I personally think that it's seldomly necessary to really change something at run-time. Of course this also depends on your overall system design..
3) I read some stuff now and I do not understand one thing... There is stated that "lets say GDT will be under address 0x2000 and IDT under 0x2500 ... and then ... this will give us 2KiB for each of it"... 2KiB? "500" in Hex is 2KiB? How to count it? It is a little bit weird for me... could you explain? Can you give a link to the tutorial ? The way you describe it, it's actually wrong: 0x500 is 1280 (it's 0x800 for 2 kb)
You should actually be able to find some explanations about hexadecimal number on google (like this site for exampe). Most (software) calculators also provide some "scientific" mode that allows you to convert from one base to the other. It's however much more convenient if you can do it by head..
4) What is happening when I am reloading GDT - setting up in diffrent place and reloading? Whats going with old GDT? Nothing happends. The new gdt will be used from that moment on, and the old just remains where it is until you eventually overwrite it.
And does Kernel should have separate GDT for itself and other GDT for other things? You only need to create one gdt for the whole system. If you really have to use special descriptors for some tasks, there's still the LDT. Note that I've however never used it myself, so that I can't give much more details..
5) How do I know how many memory do I have... There's a detailed article about that in the mega-tokyo faq (link). To make it short: It's not trivial as there might be holes in memory that are used by devices. You thus have to parse through a memory map that describes which areas can be used, and which are reserved. For the moment you can just assume that there's enough memory, especially as your kernel should be small enough..
how many and how big GDT's and IDT's can I make? You can create new GDTs and IDTs until you eventually run out of memory. The maximum size of the tables is determined by the limit field in the gdtr/idtr pointer: As it's 16 bit wide, you can create 2^16/sizeof(gdtslot) = 8192 entries per table.
regards, gaf
| | The administrator has disabled public write access.
OSDEV Community
Advertisement
gaf
User Platinum Osdever
Posts: 153
Karma: 10
Re:My C kernel does not load - 2006/07/05 10:27I tried to understand... read many articles about GDT and so on, but do not understand why in this code is "int i"? In my opinion the procedure's name (void setup_gdt(...)) is just a bit misleading. What the code really does is to initialize one of the slots of the gdt. It does not create a new gdt. Parameter i is the number of the entry that should get initialized: With your loader i=0 referes to the null-descriptor, i=1 to the code and i=2 to the data-descriptor.
Code:
desc = new sysdesc[MAX_GDT_ENTRIES];
setup_gdt(0, 0, 0x00000, 0); // Null-Descriptor
setup_gdt(1, 0, 0xfffff, ?); // Code-Descriptor
setup_gdt(2, 0, 0xfffff, ?); // Data-Descriptor
// TODO: Enable the just created gdt by reloading gdtr
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/05 13:23Another small question... (sorry for bothering you so often)... You saw my code in the 1st post of that topic... Is it professional to place GDT code and functions in bootloader? If no then tell me where to place them... And mayby you know where can I find some answers how to make files from that... I mean not to convert all (bootloader and kernel) into one image but leave it in some way in separate files and boot in that way... (is it more proffesional than making image?)
PS. much work on this forum?
| | The administrator has disabled public write access.
gaf
User Platinum Osdever
Posts: 153
Karma: 10
Re:My C kernel does not load - 2006/07/06 12:33Is it professional to place GDT code and functions in bootloader? If no then tell me where to place them As a basic gdt is required to enter protected mode, there's really no alternative to including at least the table in the bootloader. Any further functions to add/change/remove descriptors should however not be part of the bootsector as its size is restricted to 512 bytes: too little to include anything that's not really vital. You should thus place such functions in the actual kernel, which is in your case the C part of the code.
And mayby you know where can I find some answers how to make files from that... I mean not to convert all (bootloader and kernel) into one image but leave it in some way in separate files and boot in that way That would of course by a much nicer design, but it does require some work: Your current code relies on the kernel following right after the boot-sector on the floppy (it assumes that it's stored in sector 2). If you want to make the kernel a file, this as however no longer true as the filesystem may decide to store the kernel anywhere on the disk. To load it, your loader would have to search the filesystem table in order to get the sector numbers. Unfortunately this is far from trivial and requires too much code to fit into the 512 bytes of the boot-sector. This is why a second-stage loader is normally inevitable, making the whole code even more complicated.
You could avoid this altogether by using a 3rd party bootloader. The most widely used is called GRUB. You just tell it your kernel's path and where it shall be loaded to, and GRUB will take care of all the nasty details. You can find both, a detailed installation guide and a small example kernel in the mega-tokyo wiki.
Probably I should add that the above is just my opinion, and that there are others who consider the writing of an own boot-loader as a good learning experience.
PS. much work on this forum? Hmm, not quite sure what you mean..
regards, gaf
Post edited by: gaf, at: 2006/07/06 13:35
| | The administrator has disabled public write access.
wojtekw86
User Junior Osdever
Posts: 24
Karma: 0
Re:My C kernel does not load - 2006/07/08 08:41Ok... now I have problem with IDT...
I have a function... void setup_int(int i, unsigned long p_hand, unsigned 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); }
and this... [GLOBAL keyb_isr] keyb_isr: pusha push gs push fs push es push ds
[EXTERN keyb] call keyb ;jakas funkcja w C
pop ds pop es pop fs pop gs popa iret
Should I write 'setup_init(0x28,keyb_isr,14);' in main funtion? is p_handle = keyb_isr? And if yes than how should it be done b'cause first part of code is in *.c file and second in starter *.asm file... bud while compiling *.c file compiler does not see keyb_isr...
| | The administrator has disabled public write access.
gaf
User Platinum Osdever
Posts: 153
Karma: 10
Re:My C kernel does not load - 2006/07/08 09:46Should I write 'setup_init(0x28,keyb_isr,14);' in main funtion? is p_handle = keyb_isr? And if yes than how should it be done b'cause first part of code is in *.c file and second in starter *.asm file The [GLOBAL keyb_isr] directive should make the assembler stub-code visible outside of the current module. If you declare the assembler procedure as extern in your C code, the linker won't have any problems finding it:
Code:
extern "C" void keyb_isr(); // Include assembler stub
extern "C" void keyb(); // Make C procedure extern
void create_idt() { setup_int(0x20, (ulong)&keyb_isr, type); }
I hope you've already remapped the PIC, otherwise the code yon't work for hardare interrupts..
regards,
gaf
Post edited by: gaf, at: 2006/07/08 13:42
| | The administrator has disabled public write access.
wojtekw86
User Junior Osdever
Posts: 24
Karma: 0
Re:My C kernel does not load - 2006/07/08 13:06great... so I need to add these lines with "extern" word to the main function or outside of it... and what should I type as "type" what is this, and how to findout what to set up? I wanted to be able to read from keyboard...
what is under parameters pic1 and pic2 in this function... what should I type there if for example I want to use keyboard...?
Post edited by: wojtekw86, at: 2006/07/08 15:55
| | The administrator has disabled public write access.
gaf
Visitor
Re:My C kernel does not load - 2006/07/08 16:00so I need to add these lines with "extern" word to the main function or outside of it... As the two lines are basically normal function declarations, you would of course place them somewhere outside of main().
The extern keyword tells the compiler that a function or a variable is declared in some other source-file. It is followed by a function prototype, so that the compiler knows which parameters the function takes and if there's a return value. The "C" in between defines that the function should be linked according to the traditional C linking method (as opposed to the C++ way). On a closer look I actually think that you won't need it as all your code is C anyway. This also makes the second extern definition redundant.
Note that you *might* have to replace keyb by _keyb in your assembler code (both times: extern + call). Whether this is necessary depends on your kernel's executable format..
what should I type as "type" what is this, and how to findout what to set up? Type is the 3rd parameter of setup_int() . Without knowing how gate_desc is defined I can merely guess what it's value should be. To me 0x4700 seems the most reasonably, if I assume that type includes all fields of the descriptor, except for selector and offset. If you aren't sure about such things, the best solution normally is to look it up in the Intel Manuals. The structure of the IDT entries is for example described in chapter 5.11 of volume 3a. You should be able to find out what type really does by comparing the definition of your gate_desc structure with the idt descriptor's layout..
I wanted to be able to read from keyboard... The (ps/2) keyboard uses IRQ1 to signal that a key was pressed. The interrupt number this translates to depends on how you remapped the PIC, most tutorials map it to 0x21. The C interrupt-handler can get the key's scancode from port 0x60 and print it to the screen. To get the actual character the scancode would have to get translated first (ps/2 info, scancodes). One often made mistake is to not signal an EOI to the PIC, which causes the IRQ to "lock up". This means that you only receive one key press.
Initialize the PIC
Install a handler for IRQ1
Get the scancode from port 0x60
Print it to the screen
Send an EOI to the PIC
What is under parameters pic1 and pic2 in this function The PIC actually consists of two independant chips. The first is in charge of the lower 8 ISA IRQs, the second controlls the upper 8 IRQs. Both PIC devices are conected via a cascated IRQ, so that they can function as a unit. The two parameters define the mapping from IRQ to interrupt number for each of the chips. IRQs are always mapped per PIC chip and the first interrupt number must be a multiple of eight. Here's an example with the most frequently used mapping (0x20, 0x28):