OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Apr 19, 2024 1:29 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 18 posts ]  Go to page Previous  1, 2
Author Message
 Post subject: Re: Higher Half kernel load, linker error
PostPosted: Sat Mar 20, 2021 12:40 am 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1604
finarfin wrote:
So in the 64 bit world the move to the higher half can be done after i set everything up in 32bits world?
Yes, almost. Again, you need a tiny bit of 64-bit code in your 32-bit trampoline, because you cannot jump beyond the 4GB barrier from Long Compatibility mode. So you have to switch to Long 64-bit mode first.
finarfin wrote:
That means that my gdt should have 4 entries? 2 for 32 bit data and code segments and 2 for 64 bit version?
It is an option if you already need a GDT with 32-bit segments around. Then you can just add the 64-bit segments. The main kernel will need to load the final version after enabling paging, anyway.
finarfin wrote:
I see that in your example, you enable paging after having loaded the GDT and not before, is that strictly necessary? or i can keep paging being enabled just before the gdt?
It does not really matter. You need to load the GDT before doing the far jump. Any time before that is fine. I added the enabling of paging to show that that is the mode switch. That point is when the CPU enters Long mode.
finarfin wrote:
When you do the jmp 8:next the instructions after the label, are already in the higher half?
No, this is all in the lower half. Which is why that sequence ends with "jmp higher_half".
finarfin wrote:
But then if i'm going to load the kernel at 0xffff800000000000 this means that the address can't stay 32bit register, so i suppose that the linker script should be different correct ? Because, from what i understood from @velko comment one of my problem is that i am using variables in asm like if they were still placed with the old addressing (not subtracting 0xC0000000), and in 32bit world i can't subtract a 64bit address (i suppose).
I strongly suggest you reconsider that load address. Using it will require you to use the "large" code model, which will generate more complicated code. Moreover, you will have to write your assembler for that code model as well, which I would not recommend on a beginner. For instance, you cannot just call external functions. If you just used -2GB (or 0xFFFF'FFFF'8000'0000) as load address, you could use the "kernel" code model, which is much closer to the "small" code model you might already be used to. And the tooling will be better tested, since "kernel" is the code model used by tons of other kernels, including Linux.

Besides that rant, sure you can get your assembler to do 64-bit subtraction in 32-bit mode, as long as the result fits.

finarfin wrote:
I think this can be a good example: https://github.com/charpointer/celesteo ... asm/boot.s?
Acceptable, although it maps the kernel differently from you.
finarfin wrote:
There is only one thing not totally clear to me, all the initalization is done at 32 bit, ok got it, but when initalizing the data strcuture i see the subtractions like: p4_table - 0xFFFFFFFF80000000 that afaik is a 64bit value. Is that possible??
The result of that calculation will be below 4G, and therefore fit. So no "relocation truncated to fit".
finarfin wrote:
Btw reading that example looks like that i can just need one code and one data segment of the gdt, is that correct?
Apparently. I used my own 32-bit segments, just in case, but maybe that was overly cautious.
finarfin wrote:
Is there a big difference?
Not overly so. In linker scripts, 4K and 0x1000 are different ways to write the same thing. The symbols he defines are set to physical addresses rather than virtual ones, whatever that gets him, and the KEEP() only kneecaps any chance of "--gc-sections" doing its job. Not that there is a big reason to use that switch on a kernel, where you control every last section that enters a kernel.
finarfin wrote:
(and i see that in some case labels like _sbss, section_data_end are added, and in other projects not. Is there a reason for them? (or maybe are just depending on some of the developer choices?)
The choice of name rarely matters. And even having those labels is only needed if your kernel does not get loaded by a competent boot loader that fails to zero out the BSS section. In that case you have to do it yourself, and that is very easy with those symbols.

Some people like to use "_end" as the symbol at the end of their kernel, and use it to initialize their allocators. Which I personally dislike, because you don't know how much space after _end is unused before you hit something worth preserving. Or just end of memory. Never mind MMIO, there's a chance of a memory hole somewhere in there. Beyond that, the world is your oyster. You only define the symbols you need. That said, these linearly mapped kernels can just use linker symbols as stand-ins for physical addresses. I cannot do that in my kernel, since it will be loaded at an unpredictable address. Or maybe not even just one address, maybe it is in pieces distributed over all the memory. Virtual memory makes it all seem contiguous in VM space, and the only need I have to care about their physical addresses is that I must not overwrite them when allocating physical memory.
finarfin wrote:
Ah one last thing; the purpose of the new stack allocated, why is needed? And what about the size is there any convention?
The stack must be reloaded after enabling paging because the interpretation of the stack pointer has changed, and you don't want to have the stack remain in the lower half. For stack size, the only advice is "enough". Most start with 8K and see how far they get. I'm using 12K and a 4K guard page (allocated at run time from the stage 1 kernel), so the whole package has a nice round 16K size (4 pages).

_________________
Carpe diem!


Top
 Profile  
 
 Post subject: Re: Higher Half kernel load, linker error
PostPosted: Sat Mar 20, 2021 8:27 am 
Offline
Member
Member

Joined: Tue Aug 11, 2020 12:14 pm
Posts: 151
nullplan wrote:
finarfin wrote:
I see that in your example, you enable paging after having loaded the GDT and not before, is that strictly necessary? or i can keep paging being enabled just before the gdt?
It does not really matter. You need to load the GDT before doing the far jump. Any time before that is fine. I added the enabling of paging to show that that is the mode switch. That point is when the CPU enters Long mode.

I would only clarify this to say that, as a beginner, you should load the GDT right before you switch to 64-bit mode. Technically, you can load it earlier but you run the risk of some event, like an exception, forcing the load of that new CS value and taking you somewhere you're not ready to be.

It's best to stick with the exact sequence of:

- load GDT
- enable 64-bit mode (by modifying EFER, or in my case enabling PE and PG at the same time)
- jump to new CS

nullplan wrote:
Again, you need a tiny bit of 64-bit code in your 32-bit trampoline, because you cannot jump beyond the 4GB barrier from Long Compatibility mode. So you have to switch to Long 64-bit mode first.

For the sake of beginners, I really wish they had put more thought into the terminology. They describe long mode (Intel calls it IA32e) as having two "submodes" as if you were free to pick one or the other, which you're not. An OS has to be in long (64-bit) mode, with 64-bit segments and 64-bit IDT entries. Concepts like hardware-based task switches aren't available in any way. Compatibility mode is merely the submode of that where userspace code can function in a 32-bit compatible environment.

I think this misleads some people just starting down the 64-bit path to think that with a few modifications, their 32-bit OS can run in compatibility submode.


Top
 Profile  
 
 Post subject: Re: Higher Half kernel load, linker error
PostPosted: Sat Mar 20, 2021 12:21 pm 
Offline
Member
Member
User avatar

Joined: Fri Feb 23, 2007 1:41 am
Posts: 106
Location: Italy & Ireland
Thanks everyone for the answers, i finally got it working.

Btw i think that the wiki article should be made little bit more clear about all the steps for move to higher half, and give little bit more explanation.

_________________
Elen síla lúmenn' omentielvo
- DreamOS64 - My latest attempt with osdev: https://github.com/dreamos82/Dreamos64
- Osdev Notes - My notes about osdeving! https://github.com/dreamos82/Osdev-Notes
- My old Os Project: https://github.com/dreamos82/DreamOs


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 18 posts ]  Go to page Previous  1, 2

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 171 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group