Loading a 64bit kernel
Loading a 64bit kernel
I'd really appreciate some hints where I could start if I want to load a 64bit C kernel using my own bootloader (like resources to read..) . I understand that loading 64bit kernels is different since you have to (?) use the fastcall calling convention. I initially wanted to use an x64 PE kernel compiled with the Visual C++ compiler, but as I understand it's quite hard to configure the compiler, I thought I'd better go with ELF (I still like the PE idea more, since doing more research into PE executables may come in handy as I've been studying a little malware analysis on Windows).
EDIT: Reading @bzt's post from here with a little more attention ,it seems that he addressed quite a few of my issues. As far as I was able to understand, it should be fine to call the entry point with a simple 'call' provided I define it as having no arguments in C? Actually, it wouldn't make sense to behave otherwise.
EDIT:
1. My real problem is connecting the bootloader (assembled using NASM) and the kernel's executable (compiled using the Visual C++ compiler).
2. Things I managed to do so far: reading from disk, jumping into the stage 2 bootloader, setting up long mode.. I also managed to build the x86_64-elf-gcc cross compiler, but I'd still like it better if I could go with PE executables instead (I read GCC can also output executables for MinGW, but I'd rather not go with that).
3. With regard to long mode, could someone point me to some resources where I could read about the GDT (entries) needed in long mode? I know about the Intel/AMD manuals, but I'd like more information about the entries (like the null one etc).
EDIT: Reading @bzt's post from here with a little more attention ,it seems that he addressed quite a few of my issues. As far as I was able to understand, it should be fine to call the entry point with a simple 'call' provided I define it as having no arguments in C? Actually, it wouldn't make sense to behave otherwise.
EDIT:
1. My real problem is connecting the bootloader (assembled using NASM) and the kernel's executable (compiled using the Visual C++ compiler).
2. Things I managed to do so far: reading from disk, jumping into the stage 2 bootloader, setting up long mode.. I also managed to build the x86_64-elf-gcc cross compiler, but I'd still like it better if I could go with PE executables instead (I read GCC can also output executables for MinGW, but I'd rather not go with that).
3. With regard to long mode, could someone point me to some resources where I could read about the GDT (entries) needed in long mode? I know about the Intel/AMD manuals, but I'd like more information about the entries (like the null one etc).
Re: Loading a 64bit kernel
Well, you do what you usually do: Load the kernel image from disk into memory, prepare an environment it can work with, then jump to its entry point. You read the entry point out of the executable! It's written in the header somewhere. The executable format itself is pretty immaterial to the kernel. Only the bootloader needs to know. You can propably objcopy an ELF file into a PE one without too much damage. And how you call the entry point is between the bootloader and the kernel. I have the bootloader prepare a stack with an argument structure on it. Other conventions are possible.
Regarding the GDT: If you already have the manuals, what more do you need? Especially in the boot loader, you only need a null segment, a code segment, and a data segment. The only difference to protected mode is that you set the L bit in both of them, which was reserved before. The null segment is just the name for the first GDT entry, which is unusable thanks to the architecture. You can write there whatever you want, the CPU will never read it. The manuals will also tell you what kind of segments are still valid in long mode. In addition to a code and data seg, you will need a TSS. Actually one TSS per CPU.
Regarding the GDT: If you already have the manuals, what more do you need? Especially in the boot loader, you only need a null segment, a code segment, and a data segment. The only difference to protected mode is that you set the L bit in both of them, which was reserved before. The null segment is just the name for the first GDT entry, which is unusable thanks to the architecture. You can write there whatever you want, the CPU will never read it. The manuals will also tell you what kind of segments are still valid in long mode. In addition to a code and data seg, you will need a TSS. Actually one TSS per CPU.
Carpe diem!
-
- Member
- Posts: 5586
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Loading a 64bit kernel
Pretty much. There are two calling conventions for x64 (AMD and Microsoft), but they're both very similar to fastcall for x86. GCC supports both.PhantomR wrote:I understand that loading 64bit kernels is different since you have to (?) use the fastcall calling convention.
I've never tried building x86_64-pe-gcc (or x86_64-coff-gcc), but it might be worth a shot. If it works, you'll have a copy of GCC that directly produces PE executables.PhantomR wrote:I initially wanted to use an x64 PE kernel compiled with the Visual C++ compiler, but as I understand it's quite hard to configure the compiler, I thought I'd better go with ELF (I still like the PE idea more, since doing more research into PE executables may come in handy as I've been studying a little malware analysis on Windows).
If it doesn't work, you can always use objcopy.
Correct. However, at some point you will want to pass arguments to functions from assembly (or call assembly functions from C), so you might as well learn how to do it.PhantomR wrote:As far as I was able to understand, it should be fine to call the entry point with a simple 'call' provided I define it as having no arguments in C? Actually, it wouldn't make sense to behave otherwise.
At minimum, you need a null descriptor, a 64-bit ring 0 code descriptor, and a ring 0 data descriptor. Here's an example of such code. This example skips some steps that are "required" according to the Intel/AMD manuals. If you decide to follow the officially-sanctioned method to enter long mode, you'll also need a 32-bit ring 0 code descriptor.PhantomR wrote:3. With regard to long mode, could someone point me to some resources where I could read about the GDT (entries) needed in long mode? I know about the Intel/AMD manuals, but I'd like more information about the entries (like the null one etc).
Re: Loading a 64bit kernel
the reason you have heard that is because people like to lie to you -- after all, VC++ was specifically designed for OSdev (it is what MS uses to build windows)PhantomR wrote: I initially wanted to use an x64 PE kernel compiled with the Visual C++ compiler, but as I understand it's quite hard to configure the compiler, I thought I'd better go with ELF (I still like the PE idea more, since doing more research into PE executables may come in handy as I've been studying a little malware analysis on Windows).
to configure VisualStudio to compile your kernel there is a number of things you have to do:
1) in build settings, under linker section, change your build target -- change it to "freestanding"
... and your done! thats it!
(yes, 1 is a number...) -- note though that this doesn't include properly supporting global object construction/destruction, for which the process is (iirc) almost exactly like it is with GCC
in fact, it is so easy to do that the person who wrote our wiki guide for VC++ had to think up some way to make it seem more complicated, so instead he listed every single option in build settings, and gave his own personal recommendation for each one (and for most of them he actually recommended the default settings!)
this will work if your PE loader is fully-functional, to make things a little easier for yourself you might also want to strip relocations and specify your base address (since you should have paging enabled before loading your kernel, you can hardcode the load address and simplify your loader significantly by avoiding the need for supporting runtime relocations)
now if you want to load with GRUB (no good reason for that in 2019...) there are 2 other changes you have to make, but its not hard
if you are writing your own bootloader, for the bootloader you have to:
1) in build settings, under linker section, change your build target -- change it to "UEFI application"
... and your done! hit "build" and you have yourself a working UEFI bootloader (assuming your own code follows the UEFI rules...)
-
- Member
- Posts: 5586
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Loading a 64bit kernel
Where are these build targets documented? Microsoft's Visual Studio documentation makes no mention of them.JAAman wrote:in build settings, under linker section, change your build target
Re: Loading a 64bit kernel
Does the license even allow this for other users? I could easily change my build scripts to use cl.exe as a compiler (for kernel, tools are normal programs), but I'm quite sure that this would violate the terms of usage. If not forbidden outright, it would be morally/ethically questionable. It is clear that the intent for the cl.exe is to produce executables that run on MS platforms.JAAman wrote:VC++ was specifically designed for OSdev
However, how about UEFI applications? That an interesting question. Maybe this is not clear at all.
Re: Loading a 64bit kernel
But Windows is the only OS (of any significance) built with VC++ and has been heavily customised for the needs of that one product. Although admittedly VC++ was developed from the earlier "Microsoft C Compiler" (later "Microsoft C/C++ Compiler") that was also (in various versions) used to build Xenix, OS/2 and parts of MS-DOS (although the MS-DOS "kernel" was always 100% ASM). Of course, since it hasn't been used to build anything non-Windows since the early 1990s, there's little reason for Microsoft to care if you run into issues doing so.JAAman wrote:VC++ was specifically designed for OSdev (it is what MS uses to build windows)
On the other hand, I can think of at least a dozen operating systems that are built with GCC and the GCC developers are interested in fixing issues that arise even in the most obscure of situations. They're not tied to the compilation needs of any one product.
I don't think either compiler can be accurately described as being "specifically designed for OSdev", only that they are both suitable for building kernels to different degrees.
Re: Loading a 64bit kernel
yes, this is completely allowed by the license agreement (they changed it recently, and I carefully examined it to be sure this is allowed because some people have falsely claimed that it wasn't allowed)Antti wrote:Does the license even allow this for other users? I could easily change my build scripts to use cl.exe as a compiler (for kernel, tools are normal programs), but I'm quite sure that this would violate the terms of usage. If not forbidden outright, it would be morally/ethically questionable. It is clear that the intent for the cl.exe is to produce executables that run on MS platforms.JAAman wrote:VC++ was specifically designed for OSdev
there are a few components of VS that are not allowed for use for anything not targeting windows (under the new license they have a separate license that covers them) -- but these are all windows-specific advanced debug tools and a few libraries (MFC and ATL, iirc, don't remember if this included the windows header files also? but I actually don't think it did but might include the new library that replaced them) and would be mostly pointless for anything not targeting windows anyway, older versions of the license were not as clear, and included everything in a single license which mentioned "portions" which were not allowed to use for anything not targeting windows
CL does not have a separate license, and falls under the main license... which comes specifically configured for android and ios development! (if you check the android and IOS options in the installer) and thus clearly not intended for windows only development (though android and IOS targeting use a different compiler (clang, iirc), the CL license is the same as the VS license)
let me be very clear here: while the current license is much more clear, it has never been a violation of the license to OSdev using VS/VC++/MASM
if you use CL, however, remember that it isn't incredibly buggy, and therefore you should not ever use /Wall /Werror... as this will not be capable of compiling anything non-trivial (or perhaps even trivial code)
just looked it up, and my memory was a little off... the setting I was referring to is called "subsystem" (in Linker->System, or on the commandline: "/SUBSYSTEM:<specify target subsystem>) and it is documented (though the current options don't provide the "freestanding" option I thought I remembered... that is what time does to memory) but it isn't necessary for OSdev at all... instead the option that you need (I correctly remembered that only 1 option was needed...) is to specify the entry point (in Linker->Advanced, or on the commandline "/ENTRY:<function name>") of course even this is only necessary if you don't want to use the default entrypoint function nameWhere are these build targets documented? Microsoft's Visual Studio documentation makes no mention of them.
while no option is strictly necessary, there are only 3 options that are relevant for OSdev (that aren't directly related to regular application development)
1) disable exceptions (C++ ->code generation->Enable C++ Exceptions -- on the commandline this is: nothing specified) -- the code shouldn't produce any exception code if you don't use exceptions in your code, therefore this should be irrelevant (it would only affect the CRT code, which shouldn't exist in your OS kernel or bootloader), in fact I'm not convinced this actually has any effect at all (I think, but I don't know, if exceptions exist in the code being compiled, it will default to something rather than failing with an error -- the option exists to allow you to choose between different types of exception handling, not to disable exception handling)
2) disable standard libraries (Linker->Input->Ignore All Default Libraries -- on the commandline this is /NODEFAULTLIB) again, this isn't necessary but will prevent the compiler from searching the standard libraries for code you call but fail to provide (I consider this the OSdev equivalent to using /Werror -- turns what could be incorrect code generation into a hard error)
3) entrypoint (Linker->Advanced->Entry Point -- on the commandline this is /ENTRY:<specify entry point function name>) this will allow you to specify the true entry point function name, overriding the default one provided by the CRT (necessary if you don't use the default function name)
- Schol-R-LEA
- Member
- Posts: 1925
- Joined: Fri Oct 27, 2006 9:42 am
- Location: Athens, GA, USA
Re: Loading a 64bit kernel
Where is is said that VC++ is used for Windows itself? I am not questioning the claim, so much as questioning how you found this out - Microsoft are very tight-lipped about their internal procedures, AFAICT. From what little I have ever heard about it, it has always been my understanding that they used a different, internal-use-only compiler for Windows proper, but I never looked into it (nor ever cared) so I do not know.
Keep in mind that I have no horse in this race; my OS dev isn't in C or C++, and the only concern I have about other people's tools is being able to give useful advice.
Not that it matters; using VC++ means you can't self-host, and I rather doubt anyone here would want to be in that position. As terrible as GCC and LLVM are, they are at least portable. I'll keep my own counsel on the wisdom of using C/C++ in the first place... (for further Illumination fnord seen my .sig, or consult your pineal gland).
Keep in mind that I have no horse in this race; my OS dev isn't in C or C++, and the only concern I have about other people's tools is being able to give useful advice.
They were stating it because it wasn't true in the past (the older license, for both VC++ and MASM, specifically prohibited cross-development in general, and OS dev in particular). TBH, I really doubt anyone else here has looked at the VC++ license in recent years.JAAman wrote:yes, this is completely allowed by the license agreement (they changed it recently, and I carefully examined it to be sure this is allowed because some people have falsely claimed that it wasn't allowed)Antti wrote:Does the license even allow this for other users? I could easily change my build scripts to use cl.exe as a compiler (for kernel, tools are normal programs), but I'm quite sure that this would violate the terms of usage. If not forbidden outright, it would be morally/ethically questionable. It is clear that the intent for the cl.exe is to produce executables that run on MS platforms.JAAman wrote:VC++ was specifically designed for OSdev
Not that it matters; using VC++ means you can't self-host, and I rather doubt anyone here would want to be in that position. As terrible as GCC and LLVM are, they are at least portable. I'll keep my own counsel on the wisdom of using C/C++ in the first place... (for further Illumination fnord seen my .sig, or consult your pineal gland).
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
Re: Loading a 64bit kernel
that is a myth, created by the combination of assuming it would be the case (because, you know, MS is evil...) and failing to read the license carefullySchol-R-LEA wrote: They were stating it because it wasn't true in the past (the older license, for both VC++ and MASM, specifically prohibited cross-development in general, and OS dev in particular).
the MASM32 license was often quoted here on this forum as "proof" that the license for MASM and VC++ forbid OSdev... problem is, MASM32 is a separate non-MS product that consists of a set of tools and libraries for use with MASM for Win32 ASM development
the older VS license was a lot more complicated than the current one (the current one is only 3-4 short paragraphs), and included all rules for all tools (currently, some tools utilize a separate license, which does still forbid non-windows development) -- there was a clause, in that license, which forbade "development not targeting windows" (don't recall the exact wording now) ... what many people missed (because they assumed or had been told, that MS wouldn't allow OSdev) was that this clause was in a section applying to libraries bundled with VS (and not to VS itself, nor to the MS compilers) -- this section applies to the MFC library, the ATL library, the STL, std-c, and CRT libraries
now when it comes to MASM there is one other factor: MASM was not bundled with VS, instead it was part of the DDK (driver development kit) which had its own license, which also restricts use of some of its components to windows development -- I don't believe this applied to MASM though, however I never read that license, so I don't know for sure (I don't consider MASM a good choice for OSdev, I prefer NASM myself)
edit:
I just realized, my previous post may have unintentionally implied that I hadn't read the previous license, and was only reading the new one in response to people's comments about it
this is not true, I have read the license for every version I have ever had (and do so habitually, as to ensure that I fully understand any restrictions on what I can and cannot do with it) -- this includes VC6 (starter), 2008 (express), 2010 (express), 2012 (express), 2013 (express), 2015 (express?), and 2017 (community)
I have completely read and understood all terms in all products, this is not something I only did with the recent version after the recent changes
NOTE: while the wording, length, and complexity of the document has changed, what it does and what it does not allow has not substantially changed -- however it is easier to understand now (and clearer that there are no cross-development restrictions on the main VS/VC++ products)
- Schol-R-LEA
- Member
- Posts: 1925
- Joined: Fri Oct 27, 2006 9:42 am
- Location: Athens, GA, USA
Re: Loading a 64bit kernel
I assumed it because MS aren't stupid. Would you want to support a the development of a competitor to your commercial product? More importantly, would you want to handle the technical support for all the possible use cases of a tool being (mis)used for cross-development, when it wasn't intended for it in the first place?JAAman wrote:that is a myth, created by the combination of assuming it would be the case (because, you know, MS is evil...)Schol-R-LEA wrote: They were stating it because it wasn't true in the past (the older license, for both VC++ and MASM, specifically prohibited cross-development in general, and OS dev in particular).
It isn't the same situation as the FOSS tools at all; those explicitly place support on the community, not paid support technicians. The two models have different advantages and disadvantages, but they really can't be compared in this instance - the two support models are simply too different from each other, not better or worse in any meaningful way.
And as I already said, I don't have any interest in this personally.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
Re: Loading a 64bit kernel
As you have said, if you don't pass arguments, then setting up a stack, clearing bss and jumping to the entry point is pretty much all you need. That's exactly why my boot loader uses memory mapped structures, as that's architecture, platform and ABI agnostic. See viewtopic.php?f=2&t=33362PhantomR wrote:EDIT: Reading @bzt's post from here with a little more attention ,it seems that he addressed quite a few of my issues. As far as I was able to understand, it should be fine to call the entry point with a simple 'call' provided I define it as having no arguments in C? Actually, it wouldn't make sense to behave otherwise.
EDIT:
1. My real problem is connecting the bootloader (assembled using NASM) and the kernel's executable (compiled using the Visual C++ compiler).
I don't have VC++, but regarding to PE executables you should take a look at my boot loader's source. It sets up long mode, and able to load both ELF64 and PE32+ executables. There's a BIOS (fully written in Assembly) and an UEFI version (written in C with GNU EFI lib). It can be useful to see how to parse the PE structures in the binary. Some nasty sign extension tricks are required if you have a higher-half kernel because PE format can't store 64 bit address in some cases.2. Things I managed to do so far: reading from disk, jumping into the stage 2 bootloader, setting up long mode.. I also managed to build the x86_64-elf-gcc cross compiler, but I'd still like it better if I could go with PE executables instead (I read GCC can also output executables for MinGW, but I'd rather not go with that).
I think manuals and the wiki are your best chance.3. With regard to long mode, could someone point me to some resources where I could read about the GDT (entries) needed in long mode? I know about the Intel/AMD manuals, but I'd like more information about the entries (like the null one etc).
Cheers,
bzt
Re: Loading a 64bit kernel
There is/was a (more-or-less successful) project to build a functional Windows OS based on "leaked" NT 4.0 code. If you know the right search terms (I won't detail them here due to the obviously dubious legal status of the project... Somewhat ironically, you can find the code on a certain Microsoft-owned source code hosting service.) you can find not only the complete source code to a functioning version of Windows (albeit not one that's exactly identical to any official release), but also the build environment used. The compiler is the standard VC++ 7.0 (2002) compiler. Obviously this is newer than most of the code, so wasn't what was used for actual NT 4.0 releases, but it's a good indicator that the standard compiler is capable.Schol-R-LEA wrote:Where is is said that VC++ is used for Windows itself? I am not questioning the claim, so much as questioning how you found this out - Microsoft are very tight-lipped about their internal procedures, AFAICT. From what little I have ever heard about it, it has always been my understanding that they used a different, internal-use-only compiler for Windows proper, but I never looked into it (nor ever cared) so I do not know.
Additionally, Microsoft did release the source code to (most of) the Windows Server 2003 kernel under an academic licence as the Windows Research Kernel (WRK). It's compiled with the standard VC++ 7.1 (2003) compiler.
With older versions, you may be correct (although it's pretty much certain that all versions were built with some variant of the VC++/MS C/C++ compiler family, the exact versions used may not have been commercially released; I believe that older Windows DDKs included some "special" compilers needed for building drivers, etc.), but these days it's almost certain that the Windows kernel is built with standard commercially available tools.
- Schol-R-LEA
- Member
- Posts: 1925
- Joined: Fri Oct 27, 2006 9:42 am
- Location: Athens, GA, USA
Re: Loading a 64bit kernel
Interesting. OK, then, thank you for the information, I didn't realize that.mallard wrote:With older versions, you may be correct (although it's pretty much certain that all versions were built with some variant of the VC++/MS C/C++ compiler family, the exact versions used may not have been commercially released; I believe that older Windows DDKs included some "special" compilers needed for building drivers, etc.), but these days it's almost certain that the Windows kernel is built with standard commercially available tools.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
Re: Loading a 64bit kernel
Thank you very much to all of you who responed! I'm sorry for the delay.. I'll get back to this topic when I'm closer to loading the C kernel.