midnadimple :/

My ideal computing environment

Computers are insanely useful and they are a core element of our modern society. Unfortunately, they run on a limited selection of million-line operating systems, which take forever to perform basic operations like opening a browser window, are easily exploitable in their innate design and abstract away a lot of what makes programming interesting and useful. The worst part is we end up just sucking it up and dealing with these bloated and incomprehensible computing environments.

Many attempts have been made to clean up these environments, like new programming languages or operating system patches, but most failed to make a significant impact on our current computer mess, and those that did still didn't solve the underlying design issues in these systems. In addition, most of these solutions just add additional abstraction to an already bloated system.

Personally, I now hold the opinion that we must abandon ship and start from scratch in order to ensure we have a saner future of computing. So, how would these new systems function? I have a few design ideas I'd like to share.

The whole package

I think a major reason for all the complexity in modern operating systems is that they attempt to account for all computer configurations. This results in large amounts of code designed to fix the bugs on different machines.

Instead, I think that operating systems should be directly tied to specific sets of hardware. By writing an OS designed for your hardware, you ensure that once you fix a bug in a program, other users of the program will never encounter that bug again. It would be necessary to use ISAs that anyone can build an SoC for, like RISC-V, in order to support healthy competition between brands.

This approach, on its own, will only lead to more unnecessary code, since people will have to reimplement their programs on every machine. This is why it is vital to this design that we also provide a universal virtual machine for applications to run on.

A virtual machine, when simply designed, can provide a platform on which developers can make programs that can be shared with people of any system configuration. This provides freedom of operating systems and keeps them small, while also allowing each operating system to implement this virtual machine in a way that makes sense for the machine. In addition, personal programs that are only used on the individual OS don't have to worry about accommodating other users and can directly use the power of their respective systems.

The VM I'd use would be similar in design to uxn but more powerful and in 32 bits.

No drivers

Following on from that previous principle, since the OS now focuses on 1 device configuration, there is no need for drivers in the system.

Drivers are the primary reason why we have this 30 million line problem. They force the operating system to martial all connections to hardware in a uniform interface that a lot of devices don't support. The major trouble is that under our current operating system doctrine, there's no way of avoiding the imminent code explosion most hobbyist developers face.

There's 2 solutions to this issue. We can either:

  1. Standardise all hardware interfaces, or
  2. Keep drivers in applications, so only the required drivers are included

In terms of standardising hardware interfaces, since we have one skew of hardware in our design, this is a non-issue, because all users of the system have the exact same configuration. Standardising these interfaces on an individual component level is a lot harder, since companies often get an ego and think their way of implementing Wi-Fi or graphics cards is superior to others. Regardless of whether they are right, this has just made supporting multiple hardware configurations a nightmare. Maybe, one day, we'll get a POSIX-like standard for hardware and eliminate the need for my "whole package" solution, but that's a long way away.

For reference, here's how using the graphics card could look like under this system:

char* video_memory = 0x80000; // Start of video buffer, for example
*video_memory++ = 0xffffff; // Sets the first pixel in memory to white

...and with an API this could look even simpler:

//           x, y, color
gfxPixelDraw(0, 0, 0xffffff);
//          x, y, w, h, color
gfxRectDraw(0, 0, 100, 100, 0xff0000);

This could then be expanded to implement double-buffering, V-Sync, etc.

Keeping drivers in applications, upon first hearing the idea, sounds very stupid. "Why would you take this million line problem and put it in every application?" However, consider the system the OS developer has given to the user. Most of the essential components will have standardised hardware interfaces, like your graphics, Wi-Fi and most common USB accessories. It's only the weird, non-standard peripherals that will need drivers and typically only a few programs are going to use that peculiar device. So, this still works perfectly fine.

One final point I want to make is that under this design I've outlined, you may notice that only one program can access a device at a time. This may sound weird and like a regression in history, but 90% of user applications don't actually access hardware, they just call to other programs which do. So we can run with that in this system. For example, if a program wants to create a window, it will render a RGBA frame and then send that frame to the window manager, which has a lock on the graphics device and accepts incoming requests for new windows to create, allowing multiple windows. This gives developers the flexibility to bypass this window manager, if they want absolute maximum performance for something like a game, and even replace the default multiplexer with their own.

I'll take about how you'll actually talk to other programs in the next session.

Completely sandboxed programs

A big issue on modern computers is how trusting they are. They all inherit the UNIX idea of giving all programs access to the entire filesystem. This is a massive vulnerability innate in the design of operating systems and has definitely lead to more than one grandma's personal photos being stolen.

There are systems designed to alleviate UNIX-likes of this problem but these are, once again, abstractions over inherently broken systems. We need to tackle this issue at the core design level.

What I propose is an Android-like permission system built-in to the operating system. Each program that is opened can not access the file system, the graphics card, USB devices or much else. The developer must first make a call that asks for permissions to see these resources. An API like this could work:

Permissions* perms = permissionsRequest(PERMS_FILE | PERMS_SOUND);
if (perms) {
    // Could optionally limit scope of files that can be accessed
    perms->files->write("test.txt", &testBuffer);
    perms->sound->playSound("test.wav");
}

As I mentioned in the previous section, most programs interface with other programs to function. A way we can achieve this is by adding another permission that provides a memory buffer that both programs can read and write from. This buffer would also specify the specific programs that have been allowed to communicate with each other This allows the user to prevent certain programs from communicate with each other in case they require extra security:

Here's an naive example API:

// Window Manager

Permissions *perms = permissionsRequest(PERMS_DMA);
// Set a unique class name
perms->dma->setClassName("WindowManager");
// We can then accept external connections and do something with memory in a callback (i.e. create a new window)
perms->dma->acceptConnections(drawWindowCallback);
// Another program

Permissions *perms = permissionsRequest(PERMS_DMA);
// Programs can be accessed using the unique class name
// Both programs must have the DMA permission
int allowed = perms->dma->connectToProgram("WindowManager"); 
if (allowed) {
    // e.g. writing
    memcpy(exampleFrame, perms->dma->buffer);
}

This system would need to involve some sort of coroutine system, which waits for changes to the buffer to know when it can access it. I won't go into that here.

It's Forth all the way down

This last point is far more personal than any of the other general principles.

Forth is a stack-based interpreted compiled language. If none of that makes any sense, just click the link and see what I'm talking about. A nice example of a modern Forth OS is Dusk OS. I personally have no love for bare-metal Forth systems (I find some of the design rather bizarre), but the idea of Forth as a shell could be really interesting.

Forth words could be used as an alternative to a PATH on the system. If you want to make a program easier to run, you define a word like this, for example:

: WM ( -- ) PROGEXEC /bin/window-manager ;

Then, calling the window manager is as simple as typing WM, eliminating the need for a PATH.

In addition, Forths work great as a scripting language for small personal user programs. They are an adequate replacement for Bash scripting, being an actual programming language and all. The performance will probably be great than Bash as well. I could envision small user space multiplexers for things like Bluetooth being written in Forth, which lets the system operator to modify said programs to their liking in an easier fashion than recompiling C source code.

Conclusions

There's obviously a lot I have not considered (mostly because I haven't actually made this system yet), but I think that a system like this would be more enjoyable for developers to program on, more performant for users to work on, and more interesting in terms of competition.

I'd like to give a quick shout out to Sam H. Smith, whose Serenum system best represents what I've outlined in this article, right now.

tl;dr: my ideal computer would be a full hardware and software solution. It would use direct memory accessing to interact with other programs and hardware, eliminating a need for drivers. Applications would be completely sandboxed from each other, in order to improve security. It would be nice to use a Forth-like shell for a better PATH system and shell scripting