Simple GUI based Operating System - Based upon my own Microcokernel, heavily inspired by the original 1980s AmigaOS (though somewhat simpler).
CuriOS is closely modelled upon the original AmigaOS architecture, but with several very distinct differences. The biggest differences are as follows:
The Zip files here are the bootable raw hard disk image (and a VDI for VirtualBox), these builds tend to be reasonabily up to date...
The command shell currently supports a few commands, type help for a full list.
Three example programs are included on the boot disk, called prog.elf, draw.elf, and clock.elf -Warning- The Kernel API is currently in flux, so you will likely need to recompile programs between kernel updates at this time. Once the Executive API stabilises programs shouldn't need to be recompiled between kernel updates.
The graphical user interface can be "themed", in the style of one of three built in themes, which can be selected at compile time to suit the user's preference. To set the theme, change the guiTheme variable in the intuition.c file to either THEME_OLD, THEME_NEW, or THEME_MAC.
Normal Theme:
Classic Mac Theme:
AmigaOS3.0 Theme:
Things to note:
Some components (libraries, devices), notably the older ones, are currently in a "primeval" state, that is to say they do not follow the normal initialisation process. Since they are compiled together a single blob, they have access to name-spaces out of normal scope.
There is rudimentray file system support for FAT32 drives. There is a working ata device driver (read only), so you can read raw data blocks from a hard drive. There is a FAT32 filesystem handler (a "handler" is a special device/library which knows how to translate the block data returned from a device into stream data for DOS, all file systems are implmented this way, a device can be its own handler usually when the device doesn't support file systems) which sits on top of the ata device. When the filesystem is more mature, all future components will be loaded from disk and will be initialised and accessed via the proper formal executive interface. The code currently in cli.c is just temporary while I'm building the file system and DOS code. This will eventually become the boot task whick will take over most of the role that kernel.c currently performs. I will then write a proper command shell, which will then be spawned by the boot task. The CLI can load ELF executable files and execute them.
The is no proper build process, this is the 8th step (code rewrite) and I will formalise the build process with a hierarchical file structure and Make files once step 8 reaches maturity. At the moment the whole thing is built using simple shell scripts.
The Executive (the public interface of the kernel), is just a composite of various sub components (i.e. memory.h, list.h, task.h, ports.h, etc...) which is constructed during their initialisation, this is due to API being in flux at the moment. I plan to formalise this at some point.
The most basic operating system unit is the node. Everything in the operating system is a node, nodes record their type, their size, and also can have a name string. Nodes may be added to list instance (which is itself a node), but can only be a member of one list at any given time.
There are three fundamental components (everything is built from one of these):
Message passing is the primary IPC used in the operating system. Messages have a specific structure and must be allocated using the executive CreateMessage() function, but they do allow for user defined data. For a receiving task to access a message it must call the executive function GetMessage(), this transfers ownership of the message to the receiving task, at which point the sending task can no longer access it. All messages need to be replied to once the receiving task has finished with the message (i.e. made a copy of the data it needs). If the message has no reply port set, the message will be deleted by the kernel. If the message has a reply port set, ownership of the message is returned to the sending task.
The kernel design is a fairly pure microkernel; Library calls generally happen in the context of the calling task, messages should be handled in the context of the receiving task (devices have mechanisms to get around this).
No memory protection, any task can access any memory address. Don't rely on it always being like this, only access memory obtained via the executive interface (always manipulate data structures via the documented interface), and don't try to access messages if they are not in the possession of that task. It might work now, it won't work in the future.
There is no documentation... yet :-)
I plan to add an Application framework built on Objective-C using Jonathan Schleifer's Obj-FW runtime. This should hide the complexity of developing GUI applications, but CLI applications will probably still need to deal with the lower level system components.
#CuriOS2 As of September 2022, I started refactoring the code to clean up the inconsistencies in the code base. Have restructured the system library objects, THis has moved them away from the traditional Amiga Exec structure, and making them closer in design to C++ objects, this has also alowed me to run the "User Space" on top of a Unix kernel (using a thin shim) and has made development/debugging much easier.
When opening a library or device, all tasks receive an instance of that library with consists of a data structure which looks like this:
struct library_t{ node_t node; libCommon_t* common; task_t* thisTask; void* priv; void* lib; void* data; //below this point is where the library instance data can be found. int someData; }
As a user you would generally only access the lib pointer which is in effect the vtable for the object.