Fun with Nano Server

(This is a guest post by Antoni Sawicki aka Tenox)

While everybody is busy buzzing about Windows 11, I wanted to commemorate the finest operating system ever made by Microsoft – Nano Server.

The OS was somewhat esoteric and had a rather steep entry point, requiring you to build it on a Windows Server 2016 host using PowerShell magic spells. You couldn’t just download and run it. Even once you built and ran it, there wasn’t much you could “normally” do with it. Which made it much less popular than it deserved to be. My goal is to demystify this a bit, lower the entry bar and made it super easy for people to hack it.

Background and Intro (you can skip it)

This article started around my efforts to run (or port if needed) aclock to this platform. At the time of writing this article, the technology is already dead for several years, however all the artifacts and documentation are still available on Microsoft’s website. Probably not for long. So a good moment in time before everything gets deleted from existence.

Nano Server was an interesting attempt at creating a datacenter grade OS that’s not managed via local GUI, keyboard and mouse, but rather full automation, code and remote tooling. It went one step further than Server Core or Windows PE by completely removing GUI components and local shell. Hence it’s not actually called “Windows” or “Windows Nano” but rather simply “Nano Server”. Rumor has it, it started as MinWin. The OS has a rudimentary text mode console loosely resembling this of VMware ESXi. However Nano was much more than a bare metal hypervisor. It was a fully fledged operating system.

Ever since I first saw a demo on Microsoft Ignite (previously known as TechEd) I wanted to run aclock on the text console. Much like the WinNT BSOD edition. Unfortunately never really got to it until now.

How to quickly deploy Nano Server and run command line apps on the console

The hard way: you need to download Windows 2016 Server (eval) and run a PowerShell command to produce a bootable VHD file. While installing, you may want the Desktop Experience. However Nano creation is basically just a PowerShell command so you don’t actually need it.

Microsoft provides (soon to be deleted) Nano Server Quick Start. However the steps are trivial so you can totally skip that and stick just to this:

  • Launch PowerShell terminal window on WS2016 host.
  • Run: Import-Module D:\NanoServer\NanoServerImageGenerator -Verbose
    (D:\ drive being where Windows Server CDROM is mounted)
  • Run: New-NanoServerImage -DeploymentType Guest -Edition Standard -MediaPath d:\ -BasePath c:\nano -TargetPath c:\nano.vhdx -ComputerName nano -Development
    (c:\nano folder and c:\nano.vhdx image will be created for you)

Done! This will build a .vhdx image that can be run under Hyper-V as Gen-2 VM. For Gen-1 or to run it on say Virtual Box change .vhdx to .vhd in -TargetPath while running the PowerShell command.

The easy way: you can just download a pre-built VM image from here.

Once you boot it up you will be greeted with a PowerShell prompt. Just like that! You can simply type cmd to launch the good old cmd.exe shell. MS-DOS anyone?

Keep in mind, this is a developer mode, normally you would be greeted with login/password prompt and a boring menu that allows to change some networking settings and not much beyond that. In production mode you need to resort to hacks (or this) to get stuff running, fortunately nothing like that needed here.

So what can you run on it?

Firstly In order to get some external utilities going, you can mount a SMB share using net use in cmd or New-SMBMapping in PS world. Or being a server and all, better yet share out a folder via net share or use C$. Alternatively you can just shut it down, mount the vhd image on your host and copy stuff in to the image then detach the VHD. Finally, if you live in completely Windows-free world, you can install Posh-SSH module and use SCP from PowerShell.

Aclock worked on the first run, no issues, using standard win64 exe:

Wow! So looks like Nano console does have basic terminal controls. That opens quite a lot of possibilities. But can you run more complex apps? Text editors? Web browsers? GAMES?

Well, yes…, but likely not, but it really depends – on dependencies (read: DLLs).

From all the editors I tried XVI is probably the best:

Everything else has a variety of issues:

  • The console is not a real text mode as was promised in MinWin or even was in NT BSOD. Rather it’s a weird graphical mode that merely emulates text.
  • The font is lacking line drawing characters. Some editors like YEdit allow to use ASCII drawing characters fortunately.
  • There is no reverse video. This manifests mostly in menus, etc. however it also applies to the cursor.
  • There is no cursor, or rather the cursor is an underscore and not transparent cell. Moving arrow left in the CLI doesn’t actually move the cursor it erases characters. There is no line editing.
  • Also related to reverse video, it appears Nano console is simply lacking a lot of colors.
  • Missing DLLs. Nano Server not being a Windows OS is missing a lot of Windows DLLs and it has its own nano DLL hell. This has actually been acknowledged in MinWin. As such a lot of apps will not launch due to dependencies.

For example YEdit works remarkably well except for the menus, which use reverse video:

Perhaps Malcolm could make a Nano edition of YEdit? 🙂

So what about games?

Well I had a lot of hopes for ascii-patrol since it’s pure console and 64bit exe. Unfortunately didn’t work out because it was missing a bunch of multimedia/sound related DLLs from Windows. I think these can be either added, substituted or the game built without sound, but I did not had time for this. Maybe some readers do.

There was one game that actually worked! Its a pure PowerShell adaptation of snake:

I’m hoping readers can find more text mode/ascii apps and games that will work on the console. Please comment and send links!

In another dimension, having a semi working text editor, smb/scp, maybe with help of mingw64 or sdk tools one could have a self hosted developer workstation with this.

For now please just download the pre-build image, or make one yourself and run it in your favorite hypervisor. It’s fun!

With this, goodbye Nano Server! You will be always remembered. I know folks at Redmond tried really hard to make it such beautiful gem.

ASCII Patrol

Minor note from Neozeed, I took the ascii patrol source, amputated all the neat multimedia stuff, borrowed the Unix clock code and gettimeofday, and had to use Visual Studio 2010 x64 to build this. There is no Win32, only Win64, and 2019 is just too new. I guess you could deploy the runtimes?

Also create local users to share stuff with powershell like this:

New-LocalUser "neozeed" -Password (ConvertTo-SecureString -AsPlainText "TooCoolForSchool" -Force) -FullName "Neo-Zeed" -Description "Super cool guy"

Something like this to create a local user and share out the disk to copy stuff. I’ll add more stuff later.

Compiling Mach under Windows

This is a bit cheating, but I broke down and did some dump/exports of a building system to get the file layout. Since the MiG phase was totally done native, I didn’t bother with that, or trying to ‘fix’ the nested Makefiles, rather I just dumped the output and worked with that. I guess I could make my own Makefile but for now it’s a stupid script. I used the a.out build tools for Linux as the objects are all the same anyways.

So yeah, download and extract Ancient Linux on Windows, grab and extract mach25-X113-noblock.zip, and then run:

cd mach25-X113\obj\STD+WS-afs-nfs
build-gcc258.cmd

Since there is no Makefile it won’t run in parallel. About 20 seconds or so later you’ll get a linked ‘a.out’ but it won’t run. The script xport.cmd is rigged for me and Qemu 0.10.5 to create a tar file to extract inside of mach and perform the native link.

Obviously this means you can us modern UI’s tools and everything else as you are now on the outside! If you can force your build to use my ancient tools you can even do the build. Nice!

Doing a rebuild of the kernel in Qemu the 2.5.8 -O2 build shaved a whole second off the build, so yes it actually did something.

Things to do would be cross linking, fixing the drivers that don’t build, and probably improving stuff like bigger disks, filesystems and memory… or networking!.. .but that’s all too complicated for me!

WSLg aka the killer feature of Windows 11

One of the great things about Windows 11 was the inclusion of the Windows Subsystem for Linux or WSL. It wasn’t available at launch but it started with v1 a simple ELF loader and an implementation of the Linux kernel on the NTOS kernel. Being a re-implementation of Linux it was great for what did work, however many things did not. Compared to other Unix subsystems for NT over the years however WSLv1 was the best no question.

Not being enough however, Microsoft took a page out of the old WinOS/2 days and stubbed a Linux kernel to run under Hyper-V, allowing it to run far more applications, and for me giving the ability to use applications that alter memory space, and allowing i386/x32 applications to run. You could happily export your X-11 display to a Windows based X server, and get applications that way. But this isn’t 1993 so it was very limiting.

Enter WSLg

The big change is the ability to use RDP to hook both Wayland and Pulse Audio bringing Linux ‘desktop’ X11 applications to the Windows desktop. Also added in is virtual GPU capabilities allowing accelerated 3D, along with CUDA applications to run (although with a performance penalty.

The downshot for me, is that my existing Debian 10 install was not picking this up, and was somehow picking up a VMware

VMware llvmpipe

I have no idea how or why it was picking this up. While I did have the VMware Player installed, the newer versions backend through Hyper-V.

I did find this article, which gave me a path to get where I wanted, although the transition of an existing v2 instance didn’t work for me. Maybe Debian 10 is too weird. I don’t know.

Not sure where how to proceed I backed up my home directory and un-installed VMware Player and purged my existing Debian 10. I installed that Ubuntu Community Preview which promises to include all the new and exciting features.

$ glxinfo -B
name of display: :0
display: :0  screen: 0
direct rendering: Yes
Extended renderer info (GLX_MESA_query_renderer):
    Vendor: Microsoft Corporation (0xffffffff)
    Device: D3D12 (NVIDIA GeForce RTX 2070) (0xffffffff)
    Version: 21.0.3
    Accelerated: yes
    Video memory: 40710MB
    Unified memory: no
    Preferred profile: core (0x1)
    Max core profile version: 3.3
    Max compat profile version: 3.1
    Max GLES1 profile version: 1.1
    Max GLES[23] profile version: 3.0
OpenGL vendor string: Microsoft Corporation
OpenGL renderer string: D3D12 (NVIDIA GeForce RTX 2070)
OpenGL core profile version string: 3.3 (Core Profile) Mesa 21.0.3
OpenGL core profile shading language version string: 3.30
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile

OpenGL version string: 3.1 Mesa 21.0.3
OpenGL shading language version string: 1.40
OpenGL context flags: (none)

OpenGL ES profile version string: OpenGL ES 3.0 Mesa 21.0.3
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.00

Now this is looking MUCH better.

224FPS! FurMark

Now compare this to a native version of FuMark:

500 FPS

So it’s a 50% haircut. Ouch.

Gaming however using steam (yes steam runs!) reveals some other deeper issues. The mouse tracking is WAY off. So for FPS stuff you’ll spend a lot of time staring at the ceiling or the floors. The next issue is there is no mouselock, so things that rely on being able to move the mouse far beyond a screen length is impossible to play. To be fair it’s a preview, and so far I have to admit Windows 11 feels more like a technical preview. Also I don’t know what the deal is or anything about profiling it but KOTOR2 is insanely slow. Although at least with 3d acceleration running it’s not 1 frame every 5 seconds.

Good news! Windows 11 leaked a day early!

This PC meets the minimum system requirements!

You too can download it from here:

https://www.microsoft.com/en-ca/software-download/windows11

I for one, blame Canada.

—-edit

So I installed steam, because why not? But this is steam for Linux. It’s picking up VMware 3D accel.. .I don’t think that’s right. KOTOR2 loads but it’s 100% cpu and 1 frame every 5 seconds.

On the otherhand I’d installed Micropolis ages ago, and it added itself to the 11 launcher:

Even better, IT JUST WORKS!

Space Cadet 3D Pinball reverse engineered!

With all the controversy over 64bit pinball, and where and how things appeared, then disappeared to the discovery that the x64 version was a thing, but it was left off the install manifest but shipped on CD, along with my simple script to just extract it, the problem was that ARM32/64 users were left in the cold.

Don’t get me wrong, the original 32bit exe runs fine under emulation, but who wants emulation when you can have NATIVE CODE?! You’d have to try to find the source code (lol good luck!) or reverse engineer the program. And that’s what happened, enter:

k4zmu2a/SpaceCadetPinball: Decompilation of 3D Pinball for Windows – Space Cadet (github.com)

64bit ARM Pinball!

I’m using Visual Studio 2019 to build this, and it was great it *just worked*. Hurray!

There is also a rebuild going on for SDL to bring Space Cadet Pin Ball to Linux and beyond. The only downside is that it uses a number of ‘new C++ features’ locking out older platforms. I’d done some work to dumb it down although there is a bit of this new fangled C++ I’m unsure of what is going on. So that means, unfortunately Itanium users are left in the dark, as Visual Studio 2010 is too old.

32016 stand alone planetfall!

InfoTaskForce’87 running on a simple NS32016 emulator

What is it?

It sure may not look like much but it was an adventure getting here.

First, what is it? Well it’s the very simple NS32016 from here, with a few minor changes. I expanded the RAM from 256kb to a whopping 8MB. Then I added simple character I/O allowing me to print messages to the screen. Next looking at the toolchain page, I used my old Linux to Windows GCC 4 cross compiler to build the appropriate Canadian cross compiler to the NS3216.

Building the tools

A while back, I had built a cross compiler from Linux to Windows using GCC 4.1 as the basis as it was the last version that didn’t have massive external dependencies. NS32016 support was dropped some time in the late 3.x or early 4.x GCC so it means we need to go old anyways. I arbitrary picked GCC 2.8.1 for this build, while using the recommended Binutils 2.27

I cheated and just downloaded my existing linux-minw32.7z cross compiler as I didn’t feel like rebuilding everything again, although it is all in the Building a MIPS Compiler for Windows on a Linux VM! article. I also used an old Linux to Linux i586 32bit compiler (back from the OSKit build!) although you can use your hosts as well.

configuring Binutils is pretty simple like this:

./configure --prefix=/cross --target=ns32k-pc532-netbsd --host=i686-mingw32 --build=i586-linux

You can try omitting the –build portion, Debian GNU Linux 10 seemed okay with Gcc 8 as the default system compiler.

configuring GCC 2.8.1 was pretty similar:

./configure --target=ns32k-pc532-netbsd --prefix=/cross --disable-libssp --build=i586-linux --host=i686-mingw32

GCC 2.8.1 doesn’t quite know what we are doing so there is some flags we need to run off in auto-config.h namely

  • #define HAVE_BCMP 1
  • #define HAVE_BCOPY 1
  • #define HAVE_BZERO 1
  • #define HAVE_INDEX 1
  • #define HAVE_KILL 1
  • #define HAVE_RINDEX 1
  • #define HAVE_SYS_RESOURCE_H 1
  • #define HAVE_SYS_TIMES_H 1

You can just comment them out, or remove those lines all together.

When it came to building GCC, I did run into issues with GCC 7/8 trying to build GCC 2.8.1. I found it much easier to either have that Linux 4.1 compiler, or if you have access to Wine or WSL you can just run the Win32 binaries for the gen phases.

./configure --prefix=/cross --target=ns32k-pc532-netbsd --host=i686-mingw32
make CC=i686-mingw32-gcc xgcc cccp cc1 cc1obj

If you can run your own Win32 exe’s on Linux it’ll run just fine using the Linux to Windows GCC 4 cross. Otherwise you will need to either patch GCC or make your own GCC 4 hosted Linux to Linux cross compiler like this:

make CC=i686-mingw32-gcc HOST_CC=i586-linux-gcc xgcc cccp cc1 cc1obj

Hopefully that worked enough, and now you have your cross compiler. Now it’s time to build libgcc1.a

cp cccp cpp.exe
cp cc1 cc1.exe
cp xgcc xgcc.exe
cp ../binutils-2.27/gas/.libs/as-new.exe as.exe
cp ../binutils-2.27/binutils/.libs/ar.exe ar
cp ../binutils-2.27/binutils/.libs/ranlib.exe ranlib
make libgcc1.a TARGET_TOOLPREFIX="./" OLDCC=./xgcc.exe

Again you really want to be able to run the resulting programs on Linux but I guess you could script it out. Naturally if you wanted to just use Linux, it’d be easier to make that cross compiler directly, although I’m not sure how much of GCC 2.8.1 I want to fight, or just get GCC 4 running on Linux and use that to port.

crt0, somewhere for C to start

As mentioned a crt0.s is missing but there was enough inspiration to come up with this:

#NO_APP
gcc_compiled.:
.text
        .align 1
.globl _start
_start:
        enter [],0
#APP
#       setting the stack 256k under 8MB
        lprd sp,0x7c0000
        jsr _main
#NO_APP
L1:
        exit []
#       setting the stack 256k under 8MB
        lprd sp,0x7c0000
        bpt
        .align 1

#does nothing
.globl ___main
___main:
        ret 0

.globl _exit
_exit:
        bpt
        ret 0

I used a bit of the C example, and added some hooks that GCC was expecting namely a __main call that is made from main before it does anything (a place to init memory perhaps?), a place to catch an explicit exit call, along with setting the stack of course.

Patching InfoTaskForce without malloc / disk access

It’s not going to win any awards, but it was really great to get it to run a simple program written in GCC. Looking for something more fun, I took the old InfoTaskForce interpreter from ’87, and dug up my modification to run on cisco routers, and cooked up this version, that adds enough of printf from Linux, a bogus malloc that just allocates from a fixed memory array (otherwise you have to actually know about your platform), and a fun trick with later binutils where you can import a binary file directly as an object!

Neat!

Since I don’t have any file I/O being able to have the game data in RAM is crucial. I tried to tweak it so you could build the same working thing on Windows (maybe others?).

So for anyone who wants to look at the standalone adventure Win32 hosted tools are here, although the emulator should be somewhat portable.

lsblk for Windows released

(This is a guest post by Antoni Sawicki aka Tenox)

Pleased to announce that lsblk utility for Windows is finally released. This is not entirely new, the original code was on github for a few years now, but it was lacking major features of printing drive letters, mount points and filesystem types.

Why would anyone even want lsblk for Windows? There are many other “native” ways of displaying disks and volumes. For example in PowerShell: Get-Disk or Get-PhysicalDisk or in cmd: wmic diskdrive list brief. Not to mention diskpart or disk management UI. There are a few answers to this.

Firstly the output format of lsblk on Linux is rather intuitive and useful, which can’t be said about previously mentioned utilities. People with Linux background find it more like at home.

PowerShell and wmic lack ability to combine disk and volume information, unless you want to write a larger script. This is now part of lsblk.

Lastly lsblk uses low level function to list objects directly from the kernel (think WinObj), rather than going through various high level services, management interfaces and relying on VDS (Virtual Disk Service). As such it’s super fast and you can use it even with VDS stopped or inoperable. Finally it’s yet another of these native Linux tools now also available on Windows.

Finally, some of the column names may sound cryptic, so here is an explanation:

ST – Status 1=healthy 0=unhealthy
TR – Trim / Unmap / Discard Capability
RM – Removable Media
MD – Media changed (for removable media)
RO – Read only