Well, I guess this qualifies as an introduction
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Re: Well, I guess this qualifies as an introduction
Mostly because it doesn't delve into the full details of the multiboot specification. When asked (which Bare Bones does by default), GRUB will give you the memory map as part of the information you get
Re: Well, I guess this qualifies as an introduction
When it says that the Multiboot address is present in EBX upon boot - that means that the address needs to be pulled immediately, before the main function has the chance to change it, right?Octocontrabass wrote:I think this is a good starting point. (Beware: although it does say that the machine state should be unchanged from what the BIOS left it in, you can't guarantee that the machine you're running on has a BIOS at all! It's better to assume that the BIOS is not available once GRUB is finished.)
And don't worry about feeling like an idiot - I've had plenty of those moments myself!
-
- Member
- Posts: 5513
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Well, I guess this qualifies as an introduction
You should have a small assembly function, usually named "_start" or similar, that GRUB will jump to after loading your kernel. In there, you'll set up a stack, prepare the arguments, and call kmain. One of those arguments will probably need to be the value GRUB put in EBX.
You shouldn't name it "main"; compilers will get very mad at you.
You shouldn't name it "main"; compilers will get very mad at you.
Re: Well, I guess this qualifies as an introduction
I'll probably just create an inline-assembly function and run it as the very first thing in kernel_main(). Eventually, I'll figure out a way to work it into bootstrap, but I might put that until a day when I have a bit better grasp of assembly.Octocontrabass wrote:You should have a small assembly function, usually named "_start" or similar, that GRUB will jump to after loading your kernel. In there, you'll set up a stack, prepare the arguments, and call kmain. One of those arguments will probably need to be the value GRUB put in EBX.
You shouldn't name it "main"; compilers will get very mad at you.
-
- Member
- Posts: 5513
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Well, I guess this qualifies as an introduction
That won't work. The compiler can and probably will insert additional code before it. It has to be plain assembly.
You should probably try to avoid inline assembly, as well, since it's not portable and tends to hide bugs.
You should probably try to avoid inline assembly, as well, since it's not portable and tends to hide bugs.
Re: Well, I guess this qualifies as an introduction
Yeah, I knew myself that it would almost come out botched anyway. Just got a bad feeling when looking at the code.Octocontrabass wrote:That won't work. The compiler can and probably will insert additional code before it. It has to be plain assembly.
You should probably try to avoid inline assembly, as well, since it's not portable and tends to hide bugs.
The information on extracting the multiboot info from GRUB says that in the BB tuts, the bootstrap code there automatically pushes EBX to the stack for the MB struct. Well, I've been over that bootstrap code at least 10 times, and I can't find any line that has any semblance to what I know a call stack push should look like.
One of my "fatal flaws" as a work ethic is that I get to the point where I can't move on if things don't logically flow to me, and this GRUB multiboot isn't transparent to the point of me feeling uneasy writing code for it, even making the null assumption that I understood it more. Now, why is it that jumping down to real mode is a bad idea?
-
- Member
- Posts: 5513
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Well, I guess this qualifies as an introduction
I'm not sure where you read that (I'm on my phone at the moment so I can't check), but I'm very certain that the function "void kernel_main()" doesn't take any parameters.
Of course, if your kernel_main takes parameters, then you should pass them according to the calling conventions.
Of course, if your kernel_main takes parameters, then you should pass them according to the calling conventions.
Re: Well, I guess this qualifies as an introduction
On the Detecting Memory page, in the GRUB section:Octocontrabass wrote:I'm not sure where you read that (I'm on my phone at the moment so I can't check), but I'm very certain that the function "void kernel_main()" doesn't take any parameters.
Of course, if your kernel_main takes parameters, then you should pass them according to the calling conventions.
I'm not afraid to admit I'm 100% lost at what's going on at this point. The other things up to this point, the INT 0x15 method I can understand, but merging C and ASM is past my knowledge. I won't burden you further - I'll call it quits on this until I have the requisite knowledge sometime. This has stressed me out badly, and it hasn't been something I've been able to solve like other programming problems. Inlining I can understand because of how the operands work to return values, but mushing C and ASM together and passing arguments like that doesn't make sense to me, and again I'm not going to beat around that bush.To utilize the information that GRUB passes to you, first include the file multiboot.h in your kernel's main file. Then, make sure that when you load your _main function from your assembly loader, you push EBX onto the stack. The Bare bones tutorials have already done this for you.
The key for memory detection lies in the multiboot_info struct. To get access to it, you've already pushed it onto the stack...define your start function as such:
[/b]Code: Select all
_main (multiboot_info_t* mbd, unsigned int magic) {...}
-
- Member
- Posts: 5513
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Well, I guess this qualifies as an introduction
Time for more learning? It's not really that complicated, but you might get a better idea of what's going on if you write a small program and tell GCC to dump the generated assembly. (That would be "gcc -O0 -S", and possibly with "-masm=intel" if you don't like AT&T syntax. The "-O0" is to tell GCC to not optimize, so you can see how values are passed to functions.)blasthash wrote:I'm not afraid to admit I'm 100% lost at what's going on at this point. The other things up to this point, the INT 0x15 method I can understand, but merging C and ASM is past my knowledge.
Don't stress yourself out over it. Isn't this supposed to be for fun?blasthash wrote:This has stressed me out badly, and it hasn't been something I've been able to solve like other programming problems.
Re: Well, I guess this qualifies as an introduction
That's not a fatal flaw! The Romans used to say something like "you can't give what you don't own". If you don't understand (own) it then you cannot build upon it or use it usefully (give). Now I'm older I realise that:blasthash wrote:One of my "fatal flaws" as a work ethic is that I get to the point where I can't move on if things don't logically flow to me,
1) things take as long as they take, and
2) you have to build upon solid foundations.
Just make progress every day and before too long you'll be in a good position with proper hard won experience. You've got the rest of your life to master these things. Whatever you do, just don't give up!
I never bother learning calling conventions. I just look at the disassembly of functions similar to the assembly routine I want to write so it can be called by C code. I do just like you describe.Octocontrabass wrote:That would be "gcc -O0 -S"
Every universe of discourse has its logical structure --- S. K. Langer.
Re: Well, I guess this qualifies as an introduction
Well, I took a day off from it. Didn't look at my kernel, tried not to do any reading on it, worked minimally on my other software projects, let my head clear a little bit. It's amazing what just taking a breather from a subject can do. This morning, as I was driving back into class, it popped in my head - let me know if I got this right:Octocontrabass wrote:Time for more learning? It's not really that complicated, but you might get a better idea of what's going on if you write a small program and tell GCC to dump the generated assembly. (That would be "gcc -O0 -S", and possibly with "-masm=intel" if you don't like AT&T syntax. The "-O0" is to tell GCC to not optimize, so you can see how values are passed to functions.)blasthash wrote:I'm not afraid to admit I'm 100% lost at what's going on at this point. The other things up to this point, the INT 0x15 method I can understand, but merging C and ASM is past my knowledge.
Don't stress yourself out over it. Isn't this supposed to be for fun?blasthash wrote:This has stressed me out badly, and it hasn't been something I've been able to solve like other programming problems.
Since the address of the boot table is stored into EBX after GRUB finishes, I'd configure an STDCALL/FASTCALL operation to forward it to kernel_main as an argument (as a pointer?). From then, all the reading of the table can be performed in C within the confines of kernel_main.
Code: Select all
int kernel_main (uint32_t *_bootloc)
{
// Retrieval of the table via pointer can be done here, in C
}
I've actually written entire algorithms in ASM before (including things like AES-256 and other crypto algos), although usually they're in MIPS, which is more "spacious" (32 general purpose registers). I can look at assembly and have a rough idea of what goes on, but I can't "visualize" it and actively think in ASM the way I can in C languages (C/C++/Obj-C).
Let me know if that works. I'm anxious to get to writing it.
Very true. I'd much rather work to understand it because then I can work it to my own purposes, as opposed to just having the code handed to me. Again, it's amazing what giving the mind a little rest and relaxation can do.bwat wrote:That's not a fatal flaw! The Romans used to say something like "you can't give what you don't own". If you don't understand (own) it then you cannot build upon it or use it usefully (give). Now I'm older I realise that:blasthash wrote:One of my "fatal flaws" as a work ethic is that I get to the point where I can't move on if things don't logically flow to me,
1) things take as long as they take, and
2) you have to build upon solid foundations.
Just make progress every day and before too long you'll be in a good position with proper hard won experience. You've got the rest of your life to master these things. Whatever you do, just don't give up!
I never bother learning calling conventions. I just look at the disassembly of functions similar to the assembly routine I want to write so it can be called by C code. I do just like you describe.Octocontrabass wrote:That would be "gcc -O0 -S"
-
- Member
- Posts: 5513
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Well, I guess this qualifies as an introduction
That sounds right, although I'd probably try CDECL first since that's (roughly) what GCC uses by default.blasthash wrote:Since the address of the boot table is stored into EBX after GRUB finishes, I'd configure an STDCALL/FASTCALL operation to forward it to kernel_main as an argument (as a pointer?). From then, all the reading of the table can be performed in C within the confines of kernel_main.
Technically you should pass a pointer to a struct instead of a pointer to uint32_t, but I wouldn't worry about it unless GCC starts to complain.
Re: Well, I guess this qualifies as an introduction
cdecl? stdcall? fastcall? What the ****? That's Windows calling conventions. If you are using a i686-elf cross-compiler as documented in Bare Bones, you are using the System V ABI.
All you need to do is preserve the value originally in the ebx register somehow (and eax, since that's a magic value) and pass it as a parameter to the kernel main function in accordance with the ABI in use.
All you need to do is preserve the value originally in the ebx register somehow (and eax, since that's a magic value) and pass it as a parameter to the kernel main function in accordance with the ABI in use.
- Bender
- Member
- Posts: 449
- Joined: Wed Aug 21, 2013 3:53 am
- Libera.chat IRC: bender|
- Location: Asia, Singapore
Re: Well, I guess this qualifies as an introduction
Code: Select all
int kernel_main (uint32_t *_bootloc)
{
// Retrieval of the table via pointer can be done here, in C
}
This should be of interest too: http://www.gnu.org/software/grub/manual ... rnel_002ec
"In a time of universal deceit - telling the truth is a revolutionary act." -- George Orwell
(R3X Runtime VM)(CHIP8 Interpreter OS)
(R3X Runtime VM)(CHIP8 Interpreter OS)
Re: Well, I guess this qualifies as an introduction
First things first, I'll go down the list. My apologies everyone, the Fedora partition decided to brick my MacBook Pro; now I have to get everything off and wipe it back to default.
The reason I originally used uint32_t was because of the fact that EBX is a 32-bit capable register. If I went the struct pointer route, how would I interpret
As per the Calling Conventions page (under GCC/x86) - is the process of passing in the parameter as simple as: ?
1. At this point, I want to get the hang of reading into and withdrawing from memory manually, because I know there's certainly more of it. Using a pre-made struct means I don't have to do the manual handling of the address and retrieval, which albeit hard, is what I want to do. I'd rather learn the hard way on this, although I'm not heart-set against it.
2. My main concern is with my laptop down and my lack of a development machine currently (I'm using my account on my dad's machine right now), I don't want to have to install GNU dependencies and libraries (on a Windows 7 machine at that) on a computer I don't exert day-to-day control over. Doing the process manually, I can write the code even on paper without needing dependent libraries in my system.
As I've tried to show so far, I'm welcoming of any reason to reconsider.
How would I orient the pointer to a struct? Just have something like struct boot_table *header in the arguments? (I'm a bit heavy-handed still with pointers; even though I've been working for the longest time in Objective-C which is ideally a superset of C, pointers have become somewhat vestigial)Octocontrabass wrote:That sounds right, although I'd probably try CDECL first since that's (roughly) what GCC uses by default.blasthash wrote:Since the address of the boot table is stored into EBX after GRUB finishes, I'd configure an STDCALL/FASTCALL operation to forward it to kernel_main as an argument (as a pointer?). From then, all the reading of the table can be performed in C within the confines of kernel_main.
Technically you should pass a pointer to a struct instead of a pointer to uint32_t, but I wouldn't worry about it unless GCC starts to complain.
The reason I originally used uint32_t was because of the fact that EBX is a 32-bit capable register. If I went the struct pointer route, how would I interpret
First of all, judging from the first part of your reply, calm down. If you read with a bit more context, the specifying of specific conventions was more out of getting a grip on the specific practice, not a plan to use one of those conventions per se.sortie wrote:cdecl? stdcall? fastcall? What the ****? That's Windows calling conventions. If you are using a i686-elf cross-compiler as documented in Bare Bones, you are using the System V ABI.
All you need to do is preserve the value originally in the ebx register somehow (and eax, since that's a magic value) and pass it as a parameter to the kernel main function in accordance with the ABI in use.
As per the Calling Conventions page (under GCC/x86) - is the process of passing in the parameter as simple as:
Code: Select all
push ebx
call kernel_main
This is due to a number of reasons, none of which will most likely hold up under any scrutiny.Bender wrote:Why not use structures? The multiboot information is given to the kernel inside a structure. Check this out: (Specifically the multiboot_info) http://www.gnu.org/software/grub/manual ... 002eh.htmlCode: Select all
int kernel_main (uint32_t *_bootloc) { // Retrieval of the table via pointer can be done here, in C }
This should be of interest too: http://www.gnu.org/software/grub/manual ... rnel_002ec
1. At this point, I want to get the hang of reading into and withdrawing from memory manually, because I know there's certainly more of it. Using a pre-made struct means I don't have to do the manual handling of the address and retrieval, which albeit hard, is what I want to do. I'd rather learn the hard way on this, although I'm not heart-set against it.
2. My main concern is with my laptop down and my lack of a development machine currently (I'm using my account on my dad's machine right now), I don't want to have to install GNU dependencies and libraries (on a Windows 7 machine at that) on a computer I don't exert day-to-day control over. Doing the process manually, I can write the code even on paper without needing dependent libraries in my system.
As I've tried to show so far, I'm welcoming of any reason to reconsider.