OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Jul 19, 2019 7:36 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: How should I begin the development of my OS?
PostPosted: Mon May 27, 2019 4:02 pm 
Offline

Joined: Mon May 27, 2019 3:24 pm
Posts: 2
I have thought out the bare bones design of the OS, namely that it should be in a sense object oriented („everything is an object”), similar in a sense to Windows NT (not identical, there are some details that will differ significantly). The following are my more specific questions:

* How to make my system bootable? I want to boot it under Qemu and Virtualbox, and have a bit of support for the emulated hardware in these products. Other virtualization products are a bonus, real hardware is beyond my dreams.
* How should I manage the physical memory? I want an advanced memory manager, capable of doing hard faults. For the hard fault implementation I may be able to fiddle, but for the actual allocation of physical memory what should I do, considering I want to be able to allocate DMA buffers too... Would a buddy allocation scheme be good or even decent?
* System call interface. What would be a simple but flexible means to implement system calls? +1 if I won't conflict with future plans of adding support for a Linux system call interface which would be separate from that of my OS. Maybe something like int 0x80, but with another number?
* x64 only. That may simplify memory management as I have quite a bit of extra space to tag segments. Right?
* All loading of executables will be done by manually mapping pages into memory of a child process from within the parent one. But how should the first process even be created? Can I include a userspace process image in the kernel itself and essentially hardcode an initial process object? How else can I do this?
* (later on) I think library loading may be a tricky topic later on. Executable file formats, similarly. But maybe by the time I fix the problems from above I may have an answer for this too?
* Objects (within the object manager) all have ACLs. Are there any optimizations that allow me to not walk the entire ACL list? Or should I just consider that ACL lists will never be significantly large for any object?
* Networking stack. Where can I find resources on how to actually implement the Ethernet, IP, IPv6, TCP, UDP protocols? (besides the University courses I took; they may be insufficient in detail). I'm not sure how Internet connections of any kind should be even provided to the user space, within the Object Manager or just to have something separate? I already think virtual memory segments which are not shared memory won't show up in the Object Manager but would the networking side be the second thing that is accessed via a separate API?
* Containers. For this OS it will be easy to set up containers: create a new root object, then create or deep-copy the structurally required objects into that and finally assign that new root object to the process that is being created. How should networking play into this? I may need to have the NICs themselves represented as objects even if they cannot be directly used via the Object Manager otherwise. Thoughts?
* What would be useful statistics that can be provided to user applications such as a future version of Task Manager or the like?
* How do I make it very easy to myself with audio? (least effort, quality shouldn't be PC speaker like but otherwise nothing special).
* Filesystem support. FAT is a bit restrictive I believe; would implementing some variant of ext, like ext2, be reasonable?
* Back to memory allocation. Above I have asked about physical memory and whether a buddy allocator is nice. Now about virtual memory, what would be the in-kernel virtual memory layout that makes my life easy? Also, I am aware about slab allocation techniques but are they sufficient for my goals?
* For USB, ACPI etc. is there any code that is nearly ready to use? I may connect a USB mouse or a USB flash storage device.
* Module loading. Modules can provide an object and, depending on the type of object provided, it would provide certain services related to that. For example a NIC, or a filesystem, or who knows what. Modules ought to mostly work even if the kernel itself is recompiled and updated with new functionality, with little necessity to rewrite them (only do incompatible changes to the module-exposed kernel API if absolutely required). I think whoever answers the executable loading question above can cover this too. Right? I guess I will have to think of a module API really besides that.
* Graphics pipeline. All graphics will be software rendered but this doesn't mean all user programs can directly access VGA memory. How should I provide graphics support to apps?
* Security. I will have 32-bit UIDs and GIDs, but ID 0 will not be considered any special. So would administrative rights be granted either via ACLs or via additional capabilities? I suspect a few things can only be done with an actual capability implementation (the possibility to override ACLs in particular, or to load kernel modules)
* For my own OS executables I will only feature 64-bit code support (and maybe, JUST MAYBE, something similar to x86_32; probably not as it can be considered an abomination by some). But if I eventually add support for Linux system calls, how would I work with 32-bit executables? [long-distance question]

I think that's it for now. I would like to be able to make it boot and load a text mode interface program within a few months. Graphical mode, not much more (but writing the actual screen compositor, even if in userspace, may be a pain). Being able to run ping on 8.8.8.8 on one of the platforms, within like 2 years. To make a decently complete userspace environment with a not-bad shell, who knows how long.


Top
 Profile  
 
 Post subject: Re: How should I begin the development of my OS?
PostPosted: Mon May 27, 2019 4:17 pm 
Offline
Member
Member
User avatar

Joined: Fri Oct 27, 2006 9:42 am
Posts: 1461
Location: Athens, GA, USA
I try to get this out to all new members, to get everyone started on the same footing. Usually I send it by PM, but in this case, I think it would be a good opportunity to post it to the public forum again. I hope this helps.
----------------------------------

The first thing I want to say is this: if you aren't already using version control for all software projects you are working on, drop everything and start to do that now. Set up a VCS such as Git, Subversion, Mercurial, Bazaar, or what have you - which you use is less important than the fact that you need to use it. Similarly, setting up your repos on an offsite host such as Gitlab, Github, Sourceforge, CloudForge, or BitBucket should be the very first thing you do whenever you start a new project, no matter how large or small it is.

If nothing else, it makes it easy to share your code with us on the forum, as you can just post a link, rather than pasting oodles and oodles of code into a post.

Once you have that out of the way (if you didn't already), you can start to consider the OS specific issues.

If you haven't already, I would strongly advise you to read the introductory material in the wiki:


After this, go through the material on the practical aspects of
running an OS-dev project:

I strongly suggest that you read through these pages in detail, along with the appropriate ones to follow, before doing any actual development. These pages should ensure that you have at least the basic groundwork for learning about OS dev covered.

This brings you to your first big decision: which platform, or platforms, to target. Commonly options include:
  • x86 - the CPU architecture of the stock PC desktops and laptops, and the system which remains the 'default' for OS dev on this group. However, it is notoriously quirky, especially regarding Memory Segmentation, and the sharp divisions between 16-bit Real Mode, 16-bit and 32-bit Protected Modes, and 64-bit Long Mode.
  • ARM - a RISC architecture widely used on mobile devices and for 'Internet of Things' and 'Maker' equipment, including the popular Raspberry Pi and Beagleboard single board computers. While it is generally seen as easier to work with that x86, most notably in the much less severe differences in between the 32-bit and 64-bit modes and the lack of memory segmentation, the wiki and other resources don't cover it nearly as well (though this is changing over time as it becomes more commonly targeted).
  • MIPS, another RISC design which is slightly older than ARM. It is one of the first RISC design to come out, being part of the reason the idea caught on, and is even simpler than ARM in terms of programming, though a bit tedious when it comes to assembly programming. While it was widely used in workstations and game consoles in the 1990s, it has declined significantly due to mismanagement by the owners of the design, and is mostly seen in devices such as routers. There are a handful of System on Chip single-board computers that use it, such as the Creator Board and the Onion Omega2, and manufacturers in both China and Russia have licensed the ISA with the idea of breaking their dependence on Intel. Finding good information on the instruction set is easy, as it is widely used in courses on assembly language and computer architecture and there are several emulators that run MIPS code, but finding usable information on the actual hardware systems using it is often difficult at best.
  • RISC-V is an up and coming open source hardware ISA, but so far is Not Ready For Prime Time. This may change in the next few years, though.

You then need to decide which Language to use for the kernel. For most OS-Developers this means knowing and using C; while other languages can be used, it is important to know how to read C code, even if you don't use C, as most OS examples are written in it. You will also need to know at least some assembly language for the target platform, as there are always parts of the kernel and the device drivers which cannot be done in high-level languages.

You further need to choose the compiler, assembler, linker, build tool, and support utilities to use - what is called the 'toolchain' for your OS. For most platforms, there aren't many to choose from, and the obvious choice would be GCC and the Binutils toolchain due to their ubiquity. However, on the Intel x86 platform, it isn't as simple, as there are several other toolchains which are in widespread use for it, the most notable being the Microsoft one - a very familiar one to Windows programmers, but one which presents problems in OSDev. The biggest issue with Visual Studio, and with proprietary toolchains in general, is that using it rules out the possibility of your OS being "self-hosting" - that is to say, being able to develop your OS in the OS itself, something most OSdevs do want to eventually be able to do. The fact that Porting GCC to your OS is feasible, whereas porting proprietary x86 toolchains isn't, is a big factor in the use Binutils and GCC, as it their deep connection to Linux and other Unix derivatives.

Regardless of the high-level language you use for OS dev (if any), you will still need to use assembly language, which means choosing an assembler. If you are using Binutils and GCC, the obvious choice would be GAS, but for x86 especially, there are other assemblers which many OSdevs prefer, such as Netwide Assembler (NASM) and Flat Assembler (FASM).

The important thing here is that assembly language syntax varies more among the x86 assemblers than it does for most other platforms, with the biggest difference being that between the Intel syntax used in the majority of x86 assemblers, and the AT&T syntax used in GAS. You can see an overview of the differences on the somewhat misnamed wiki page Opcode syntax. While it is possible to coax GAS to use the Intel syntax using the .intel_syntax noprefix directive, the opposite is generally not true for Intel-based assemblers such as NASM, and even with that directive, GAS is still quite different from other x86 assemblers in other regards.

It is still important to understand that the various Intel syntax assemblers - NASM, FASM, and YASM among others - have differences in how they handle indexing, in the directives they use, and in their support for features such as macros and defining data structures. While most of these follow the general syntax of Microsoft Assembler (MASM), they all diverge from it in various ways.

Once you know which platform you are targeting, and the toolchain you want to use, you need to understand them. You should read up on the core technologies for the platform. Assuming that you are targeting the PC architecture, this would include:

This leads to the next big decision: which Bootloader to use. There are a number of different standard bootloaders for x86, with the most prominent being GRUB. We strong recommend against Rolling Your Own Bootloader, but it is an option as well.

You need to consider what kind of File System to use. Common ones used when starting out in OS dev include:

We generally don't recommend designing your own, but as with boot loaders, it is a possibility as well.

While this is a lot of reading, it simply reflects the due diligence that any OS-devver needs to go through in order to get anywhere. OS development, even as a simple project, is not amenable to the Stack Overflow cut-and-paste model of software development; you really need to understand a fair amount of the concepts and principles before writing any code, and the examples given in tutorials and forum posts generally are exactly that. Copying an existing code snippet without at least a basic idea of what it is doing simply won't do. While learning itself is an iterative process - you learn one thing, try it out, see what worked and what didn't, read some more, etc. - in this case a basic foundation is needed at the start. Without a solid understanding of at least some of the core ideas before starting, you simply can't get very far in OS dev.

Hopefully, this won't scare you off; it isn't nearly as bad as it sounds. It just takes a lot of patience and a bit of effort, a little at a time.

_________________
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
μή εἶναι βασιλικήν ἀτραπόν ἐπί γεωμετρίαν
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.


Top
 Profile  
 
 Post subject: Re: How should I begin the development of my OS?
PostPosted: Tue May 28, 2019 8:43 am 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 217
I will not quote all of this, I will simply answer in the order you have provided.

  • You make it bootable by writing a bootloader? I don't know what you're really asking. I'd suggest writing a UEFI bootloader, as that is going to be the standard for the forseeable future. QEMU can deal with that if you use OVMF. VirtualBox? I don't know.
  • Start out with a bitmap allocator. This has the advantage of being able to set and query the availability of specific memory ranges. Otherwise I hear good things about the buddy allocator, but I have yet to wrap my head around that one. Anyway, allocating DMA buffers should be easy once you separate the allocator into zones. The zones I have set up are 1MB, 4GB, and beyond. Because some things require physical memory within the low MB, and some hardware cannot deal with addresses >4GB. I always try to return an address from the highest possible zone. This way, the valuable 1MB-pages don't get used up by things that could deal with >4GB addresses.
  • On x86, you have SYSCALL, SYSENTER, softint, and call gate. If you want to do anything remotely like POSIX, stay away from call gates. for SYSCALL, there is only one entry point, but you could do something like "set_personality()" and choose a different syscall table depending on process flags. SYSENTER is only supported on Intel, so I'd stay away from it. And for softint, you could just use a different gate number than Linux.
  • The first part: Yes. The second: I have no idea what you mean. Anyway, in x86_64, virtual address space is guaranteed to be at least 4 times larger than physical address space, so you can dedicate a quarter of virtual address space to mapping in the entire physical address space. Makes MMIO and paging a lot easier.
  • This will put the executable parser into every process, instead of just into the kernel. It will also eliminate any possibility of escalating priviledge. Linux has setuid programs and VFS capabilities. You could never use these, since with them a process could map higher-priviledge executable pages and then just put their own code into them. So, bad idea. I suggest just parsing the executable format. Try it! It's not that hard.
  • ELF is not that hard. PE likewise. These are the two most often used formats. For ELF, loading shared libraries is done in userspace, so the kernel doesn't have to concern itself with it, as long as the kernel responds to the presence of a PT_INTERP segment.
  • The very idea of ACLs is that they be walked until a match is found.
  • Read the relevant RFCs and do what they say. Cross-test with existing implementations, but don't take those as sacrosanct.
  • Containers are a fad.
  • Everything that tells the user which process is hogging ressources is good. VSize, CPU time, RSS, open files. Maybe amount of data transferred for network interfaces and disks, so the user can make an informed decision e.g. on upgrading network or going SSD.
  • Most audio devices set up a DMA buffer. Once playback starts, the card plays the same buffer over and over again, and the main CPU keeps feeding the buffer with new data. Doesn't get much easier, but sounds horrible when it crashes. Recording is then the same thing in the other direction.
  • Considering ext4 is a variant of ext2, yes it is very reasonable. As UNIX filesystems go, it doesn't get much simpler than ext2.
  • Low half for userspace, low half of high half for physical memory mirror, highest 2GB for kernel code, rest as needed.
  • For ACPI there is ACPICA. For USB there is nothing, because while the device is always the same, the handling of the devices is quite OS-specific.
  • Don't. Modules are rarely worth the effort.
  • For starters, expose a frame buffer (a device or similar users can map into their address space and then write to). Everything else will take care of itself once X.org runs.
  • Decide now: Do you want capabilities or not? If not, then why not just branch on uid == 0?
  • Meh. The abomination is x86_64. x32 merely does the best with the bad hand it was dealt. If you want to support Linux system calls and Linux 32-bit executables, you are going to have to inject a VDSO into processes. Other than that, it shouldn't be much different from implementing Linux 64-bit compatibility.


Top
 Profile  
 
 Post subject: Re: How should I begin the development of my OS?
PostPosted: Wed May 29, 2019 6:56 am 
Offline

Joined: Mon May 27, 2019 3:24 pm
Posts: 2
Guess I'll take it from your answer for now.

* Bootloader? Well, is UEFI easier or harder than making it boot from Grub? Also, depending on what I end up doing I may or may not need an initial RAM image; would it be best to just combine it with the kernel binary itself in that case?
* Guess I'll start with bitmap, and once I get something working I may change to buddy (this one works great for power-of-two allocations and is half-decent for others, and if all my allocations end up being power-of-two I think it guarantees zero memory fragmentation [rejected allocations when there is the free memory]). Thanks for that.
* Linux apparently uses 0x80 [and so does BSD, but I doubt I'll do anything like that unless it's very easy], thus I could just use 0x81 fine? I may also add alternate mechanisms besides that. My OS design will come from having a shared library injected into every process though, and that one handling system calls. Should I give up on this idea or will it work?
* Internally, I will manage virtual memory as segments which may be one or more pages long. I would like to ask if there is anything in the paging structures of x86_64 that would allow me to EASILY figure out which segment a physical page belongs to, when it is in memory. [Is it even necessary if I won't do COW?]
* As I said two points ago, I would like to inject some sort of shared library. That executable parser could be part of that shared library. For escalating privilege I would think of a token based escalation (processes could pass their credentials to each other by passing some sort of object/handle between them). Yes, that's pretty different from setuid and if I wanted to emulate that it would be an interesting feat.
* Where would the very first executable be located? Should the kernel actually mount the disk in order to find it? Or would it be better if I had some other mechanism?
* Guess I'll go with ELF. Thanks. ACL linearly walked, fair enough, thanks for that too.
* Fair enough. After all I will need to implement the first few NIC drivers themselves. Guess I'll figure with Ethernet, IP, IPv6, TCP (and TCPv6) and UDP (and UDPv6). Maybe for the userspace I'll just go with something very similar to the BSD socket API after all.
* Containers may be a fad, but the design itself will make them come for nearly-free. I'll keep them.
* I'll struggle a little bit with how I should represent shared memory segments in those statistics (should I just consider the RSS for those segments to be split up among the processes that have the segment in their address spaces?). Thanks otherwise.
* "sounds horrible when it crashes" I know what you're saying xD Also, this summer I'll have an internship which is audio-related so I think I will learn quite a bit about it anyway. But thanks.
* ext2 it is then. (nothing good outside the Unix world besides FAT variants, which have those 2GB/4GB file size limitations and are thus no good?)
* Fair enough.
* ACPICA? Thanks then (would detection of the hardware on the motherboard, and power management, be free? Maybe even PCI on certain physical devices which have firmwares that directly put PCI devices in the DSDT....). Yeah, good point about USB handling being OS-specific, guess I'll have to figure it out myself.
* Modules will be in eventually, but thanks for making me lower the priority for them.
* Directly giving the frame buffer to apps? Fair. Although many versions before Linux support may actually not even use X or something, but a different window manager. How good even *is* X with software rendering?
* I probably will have some capabilities. So for elevation really I would then implement a means to pass capabilities between processes, probably as objects. Object passing between processes within the kernel will be more of a norm.
* Guess 32-bit support... Oh, now I looked up what VDSO was, guess I would by design inject a VDSO even way before supporting Linux and 32-bit support. In fact I may even not standardize the actual system call interface but only the VDSO itself.
* Anyway, returning to the previous bullet point, 32-bit support will probably not happen anytime soon (maybe I'll even put it at an even lower priority than modules).

Thanks for the input.


Top
 Profile  
 
 Post subject: Re: How should I begin the development of my OS?
PostPosted: Wed May 29, 2019 10:10 am 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 217
I just noticed that I can click on "post reply", and then select part of your answer an click "quote", and then it'll add a quote just for the part I selected. Like this:

paulstelian97 wrote:
* Bootloader? Well, is UEFI easier or harder than making it boot from Grub? Also, depending on what I end up doing I may or may not need an initial RAM image; would it be best to just combine it with the kernel binary itself in that case?

Well, it isn't a whole lot simpler. The bootloader will dump you in a state that it defines, which is almost certainly not the operating state you want to be in, so you have to transition out of that state into the one you want to be in. In x64, GRUB's (well, Multiboot's) initial state is almost the same as UEFI's. GRUB does save you from loading the actual file yourself, but then in UEFI that isn't all that difficult.

paulstelian97 wrote:
* Linux apparently uses 0x80 [and so does BSD, but I doubt I'll do anything like that unless it's very easy], thus I could just use 0x81 fine? I may also add alternate mechanisms besides that. My OS design will come from having a shared library injected into every process though, and that one handling system calls. Should I give up on this idea or will it work?

Linux uses SYSCALL on AMD64. Int 80h is legacy/compatibility with 32-bit SW. Also, syscalls are for priviledged work (as in, accessing the hardware), so you need some kind of way to escalate priviledge. The ways listed before are the only ones to do that.

paulstelian97 wrote:
* Internally, I will manage virtual memory as segments which may be one or more pages long. I would like to ask if there is anything in the paging structures of x86_64 that would allow me to EASILY figure out which segment a physical page belongs to, when it is in memory. [Is it even necessary if I won't do COW?]

Well, no, that mapping is the wrong way around. Worst comes to it, you will have to search through all page tables for the address. On the plus side, you are handling an exception here, so speed is not imperative.

paulstelian97 wrote:
* As I said two points ago, I would like to inject some sort of shared library. That executable parser could be part of that shared library. For escalating privilege I would think of a token based escalation (processes could pass their credentials to each other by passing some sort of object/handle between them). Yes, that's pretty different from setuid and if I wanted to emulate that it would be an interesting feat.

That sounds interesting. But complicated. But you do you.

paulstelian97 wrote:
* Where would the very first executable be located? Should the kernel actually mount the disk in order to find it? Or would it be better if I had some other mechanism?

I'm a monolithic kind of guy, so for me the VFS runs in the kernel. As such, of course the kernel has to mount the root FS first, then load the initial program like it would any other.
The micro-kernel guys have this problem, but they generally solve it with a very limited in-kernel VFS that is immediately replaced with a userspace VFS server from an initrd.

paulstelian97 wrote:
* Guess I'll go with ELF. Thanks.

Do bear in mind that I am biased towards the UNIX side of things, and I recommend ELF mainly because I know it better.

paulstelian97 wrote:
Maybe for the userspace I'll just go with something very similar to the BSD socket API after all.

Well, that API is the standard that most people know. It is horrible, but standard nonetheless.

paulstelian97 wrote:
* ext2 it is then. (nothing good outside the Unix world besides FAT variants, which have those 2GB/4GB file size limitations and are thus no good?)
Every FS has limitations. FAT is bad mainly because it has so many of them. Maybe NTFS could be good, if anything official was known about it.

paulstelian97 wrote:
* ACPICA? Thanks then (would detection of the hardware on the motherboard, and power management, be free?

Nothing ever comes for free. But ACPICA makes it more bearable. You still need to write the OS layer for it, and you still need to use it correctly.

paulstelian97 wrote:
Maybe even PCI on certain physical devices which have firmwares that directly put PCI devices in the DSDT

If that's a thing, this is the first I've heard of it.

paulstelian97 wrote:
* Directly giving the frame buffer to apps? Fair. Although many versions before Linux support may actually not even use X or something, but a different window manager. How good even *is* X with software rendering?

Access can be controlled with administrative means (owner/group and access rights), so no need to do anything in kernel. X is reasonably good, given that software rendering is the only thing the VESA driver can do. And X is a graphics server. A window manager is a thing that runs on X. And the nice thing is, once you have X going and xlib compiled, you already have access to a huge list of programs for your OS.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot], pat, Sik, wgrant and 3 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