Cosmos (operating system)


C# Open Source Managed Operating System is a toolkit for building GUI and command-line based operating systems, written mostly in the programming language C# and small amounts of a high-level assembly language named X#. Cosmos is a backronym, in that the acronym was chosen before the meaning. It is open-source software released under a BSD license.
, Cosmos encompasses an ahead-of-time compiler named IL2CPU to translate Common Intermediate Language into native instructions. Cosmos compiles user-made programs and associated libraries using IL2CPU to create a bootable native executable that can run independently. The resulting output can be booted from a USB flash drive, CD-ROM, over a network via Preboot Execution Environment, or inside a virtual machine. Recent releases also allow deploying to certain x86 embedded devices over Universal Serial Bus. While C# is the primary language used by developers, many CLI languages can be used, provided they compile to pure CIL without the use of Platform Invocation Services. Cosmos is mainly intended for use with.NET.
Cosmos does not aim to become a full operating system, but rather a toolkit to allow other developers to simply and easily build their own operating systems using.NET. It also functions as an abstraction layer, hiding much of the inner workings of the hardware from the eventual developer.
Older versions of Cosmos were released in Milestones, with the last being Milestone 5. More recently, the project switched to simply naming new releases after the latest commit number.
Releases of Cosmos are divided into two types: the Userkit, and the Devkit. The Userkit is a pre-packaged release that is updated irregularly, as new and improved features are added. Userkits are generally considered stable, but do not include recent changes and may lack features. The Devkits, which refers to the source code of Cosmos, are usually stable but may have some bugs. They can be acquired on GitHub and must be built manually. Git is used for source control management.
Most work on Cosmos is currently aimed at improving debugger functionality and Microsoft Visual Studio integration. Kernel work is focused on implementing file systems, memory management, and developing a reliable network interface. Limine serves as the project's bootloader; in older versions of the toolkit, GRUB was used instead.

Origin

The idea for Cosmos was created by Chad Hower and was initially co-developed by Hower and Matthijs ter Woord. Over time, Cosmos has been maintained and improved by many other individuals.

Developing with Cosmos

Cosmos has many facilities to improve the experience of developing operating systems, and is designed to make the process as fast and painless as possible. Knowledge of assembly language is not required to use Cosmos.

Visual Studio integration

A key feature of Cosmos, which separates it from other operating systems of its type, is its tight integration with Microsoft Visual Studio. Code can be written, compiled, debugged, and run entirely through Visual Studio, with only a few keypresses. Cosmos no longer supports Visual Studio 2015, Visual Studio 2017, or Visual Studio 2019, only supporting Visual Studio 2022.

Debugging

Cosmos can be seamlessly debugged through Visual Studio when running over PXE or in a virtual machine. Many standard debugging features are present, such as breakpoints, tracing, and logging. Also, debugging can be done via serial cables, if running on physical hardware. When running in VMWare, Cosmos supports stepping and breakpoints, even while an operating system is running.

Running

Cosmos uses virtualisation to help speed development by allowing developers to test their operating systems without having to restart their computers as often. By default, VMware Player is used, due to its ease of use in terms of integration with the project. Other virtualisation environments are supported as well, such as Bochs and Hyper-V. An ISO disk image may also be generated that can be burned to a USB flash drive, CD-ROM, or similar media.
PXE booting is also supported, allowing for remote machines to run Cosmos over a network connection.

IDE support

Cosmos does not strictly require Visual Studio. Projects can be created by running the command below, given you have the template installed:
dotnet new cosmosCSKernel -n MyCOSMOSProject
Code can be written in other editors and IDEs, such as JetBrains Rider, Visual Studio Code, Neovim and GNU Nano. One downside of this is that debugging may be difficult without the Visual Studio debugger. COSMOS will also not automatically launch your virtualisation software on build. If you would like to use QEMU, for instance, you can run this command after build:
qemu-system-x86_64 -cdrom./bin/Debug/net6.0/MyCOSMOSProject.iso

Compile process

IL2CPU

To compile.NET CIL into assembly language, Cosmos developers created an ahead-of-time compiler named IL2CPU, designed to parse CIL and output x86 opcodes. is an AOT compiler that is written using a Common Intermediate Language compliant language. It translates Common Intermediate Language to machine code.

X#

X# is a low-level programming language designed for the x86 processor architecture as part of Cosmos operating system. It aims to simplify operating system development by incorporating C-like language syntax to assembly language. Initially, X# was used for debugging services in Cosmos. The X# compiler is an open source command-line interface program that parses code lines into tokens, compares them with patterns, and translates matched patterns to intel syntax x86 assembly, typically for the YASM assembler. Early versions of X# operated mostly 1:1 with assembly code, but this is no longer the case.

Syntax

The syntax of X# is straightforward but stricter compared to C.

Comments

X# supports only single-line comments in the C++ style, starting with - //.

Constants

X# allows the definition of named constants declared outside functions. Numeric constants are defined similarly to C++; for example: const i = 0. Referencing them elsewhere requires a # before the name; for example: - "#i".
  • String constant use single quotes. To include a single quote in a string constant, use a backslash. X# strings are null terminated.
  • Hexadecimal constants are prefixed with a dollar sign, followed by the constant..
  • Decimal constants are not prefixed but cannot start with 0.
  • Binary and octal constants aren't supported yet.

    Labels

Labels in X# function similarly to labels in other assembly languages. The goto mnemonic is used to jump to a label instead of the conventional jump or jmp mnemonic.

CodeLabel1:
goto CodeLabel2:

Namespaces

X# program files must start with a namespace directive. X# lacks a namespace hierarchy, so the current namespace changes with each directive until the file ends. Variables or constants in different namespaces can have the same name, as the namespace is prefixed to the member's name in the assembly output. Namespaces cannot reference each other except through low-level operations.

namespace FIRST
// Everything variable or constant name will be prefixed with FIRST and an underscore. Hence the true full name of the below variable
// is FIRST_aVar.
var aVar
namespace SECOND
// It's not a problem to name another variable aVar. Its true name is SECOND_aVar.
var aVar
namespace FIRST
// This code is now back to the FIRST namespace until the file ends.

Functions

All X# executive code should be placed in functions defined by the 'function' keyword. Unlike C, X# does not support any formal parameter declaration in the header of the functions, so the conventional parentheses after the function name are omitted. Because line-fixed patterns are specified in syntax implemented in code parser, the opening curly bracket can't be placed on the next line, unlike in many other C-style languages.

function xSharpFunction

Because X# is a low-level language, there are no stack frames inserted, so by default, the return EIP address should be on the top of the stack. X# function calls do contain arguments enclosed in parentheses, unlike in function headers. Arguments passed to functions can be registers, addresses, or constants. These arguments are pushed onto the stack in reverse order. Note that the stack on x86 platforms cannot push or pop one-byte registers.

function xSharpFunction
function anotherFunction

The return keyword returns execution to the return EIP address saved in the stack.

Arithmetic and bitwise operations

X# can work with three low-level data structures: the registers, the stack and the memory, on different ports. The registers are the base of all normal operations for X#. A register can be copied to another by writing DST = SRC as opposed to mov or load/store instructions. Registers can be incremented or decremented just as easily. Arithmetic operations are written as dest op src where src is a constant, variable, or register, and dest is both an operand and the location where the result is stored.
Examples of assignment and arithmetic operations are shown below.

ESI = 12345 // assign 12345 to ESI
EDX = #constantForEDX // assign #ConstantForEDX to EDX
EAX = EBX // move EBX to EAX => mov eax, ebx
EAX-- // decrement EAX => dec eax
EAX++ // increment EAX => inc eax
EAX + 2 // add 2 to eax => add eax, 2
EAX - $80 // subtract 0x80 from eax => sub eax, 0x80
BX * CX // multiply BX by CX => mul cx -- division, multiplication and modulo should preserve registers
CX / BX // divide CX by BX => div bx
CX mod BX // remainder of CX/BX to BX => div bx

Register shifting and rolling is similar to C.

DX << 10 // shift left by 10 bits
CX >> 8 // shift right by 8 bits
EAX <~ 6 // rotate left by 6 bits
EAX ~> 4 // rotate right by 4 bits

Other bitwise operations are similar to arithmetic operations.

DL & $08 // perform bitwise AND on DL with 0x08 and store the result in DL
CX | 1 // set the lowest bit of CX to 1
EAX = ~ECX // perform bitwise NOT on ECX and store the result in EAX
EAX ^ EAX // erase EAX by XORing it with itself