@ -22,7 +22,7 @@ the source code. In this post I describe how I did this with `DeRez`.
To build the temperature converter I started with the [Dialog sample] from
[Retro68], which looks like this:
{{ figure(image="posts/2023/derez/Dialog.png", link="posts/2023/derez/Dialog.png", pixelated=true, alt="Screenshot of the Dialog sample from Retro68. It has a static text item, edit text item, check box, two radio buttons, and a Quit button.", caption="Dialog Sample") }}
that file for resource descriptions. Running the command I was now rewarded
with textual resources:
{{ figure(image="posts/2023/derez/MPW.png", link="posts/2023/derez/MPW.png", pixelated=true, alt="Screenshot of an MPW worksheet on Mac OS 8 showing the output of running DeRez on an application.", caption="DeRez output in MPW") }}
{{ figure(image="posts/2023/derez/MPW.png", link="posts/2023/derez/MPW.png", pixelated=true, alt="TODO", caption="DeRez output in MPW") }}
To get the text out of the VM I copied and pasted it into a new document in
[BBEdit] (version 5.0) and saved it with Unix line endings to the Unix folder
title = "Fixing OpenBSD panic dc_atapi_start: not ready in KVM"
date = 2023-09-17T12:13:24+10:00
[extra]
updated = 2023-09-22T11:56:57+10:00
+++
I tried creating an OpenBSD 7.3 virtual machine on my new computer (Arch Linux
host) and the installer kept crashing with the error:
{{ figure(image="posts/2023/openbsd-db-atapi-start-not-ready/openbsd_panic_dc_atapi_start_not_ready.png", link="posts/2023/openbsd-db-atapi-start-not-ready/openbsd_panic_dc_atapi_start_not_ready.png", alt="Screenshot of the installer crash.", caption="Screenshot of the installer crash.") }}
I did a bunch of searching online and tried a several different suggestions but that one that
worked for me was from [this Reddid thread][reddit]:
> **tinneriw31**
>
> Switch the virtual cd drive from ide to sata. Worked for me. Exact same issue.
I use [virt-manager] to manage VMs. These are the steps to do that when creating the VM:
1. Create the VM and at the last step choose "Customize configuration before install"
2. Click on the "IDE CDROM 1" tab and change "Disk bus" to SATA
3. Then click Apply, and then Begin installation in the top left.
After that the VM installed successfully.
{{ figure(image="posts/2023/openbsd-db-atapi-start-not-ready/virt-manager-customize-configuration.png", link="posts/2023/openbsd-db-atapi-start-not-ready/virt-manager-customize-configuration.png", alt="Screenshot of step 5 in the new virtual machine wizard in virt-manager showing the 'Customize configuration before install' option checked.", caption="Customize configuration before install.", width=504) }}
{{ figure(image="posts/2023/openbsd-db-atapi-start-not-ready/virt-manager-sata-cd-rom.png", link="posts/2023/openbsd-db-atapi-start-not-ready/virt-manager-sata-cd-rom.png", alt="Screenshot of the virt-manager CD ROM tab showing 'Disk bus: SATA' selected.", caption="Disk bus: SATA", width=1028) }}
Instead of using my funemployment to build useful things I have continued to
build things for old versions of Mac OS. Through some luck and a little
persistence I have actually managed to get Rust code running on classic Mac OS
(I've tried Mac OS 7.5 and 8.1). In this post I'll cover how I got here and
show a little network connected demo application I built—just in time for
the end of [#MARCHintosh].
<!-- more -->
Before I get into the details this is where we're headed:
{{ video(video="posts/2023/rust-classic-mac-os-app/ferris-weather-2023-03-31_12.37.49_edit.mp4", height=480, poster="png", preload="auto", alt="Video showing the Ferris Weather application in operation. Initially there is a window with a Ferris icon, the text, 'An application that exercises my Open Transport Rust bindings and HTTP client', and a button 'Get Weather'. Clicking the button results in an alert that says: 'The temperature in Brisbane is 26.9°C'.", caption="Ferris Weather, a weather app built with Rust (and some C)") }}
### DeRez Redux
In [the last post](@/posts/2023/derez/index.md) I got Nim code running on Mac
OS and toyed with DeRez. [The author of `mpu-emu` replied on Mastodon][Ninji]
letting me know that DeRez _should_ run via `mpw-emu` on Linux as the
I rebuilt the temperature converter that I'd built in Nim in Rust ([source code][rust-temp]) and ran into
more linker/`binutils` issues. After a _lot_ of trial-and-error and some more
luck I was able to solve that by using the updated `binutils` on the
`gcc12-update branch` branch of Retro68. I now had a working temperature
converter:
{{ video(video="posts/2023/rust-classic-mac-os-app/classic-mac-rust-2023-03-28_20.00.31.mp4", height=480, poster="png", preload="auto", alt="Video of the temperature converter converting values to and from Celsius, running on Mac OS 8.1 (in emulator).", caption="The temperature converter application ported to Rust") }}
It worked on Mac OS 7.5 too:
{{ figure(image="posts/2023/rust-classic-mac-os-app/rust-on-mac-os-7.png", link="posts/2023/rust-classic-mac-os-app/rust-on-mac-os-7.png", pixelated=true, border=1, alt="Screenshot of the temperature converter application running on Mac OS 7.5 (in emulator).", caption="Temperature converter application running on Mac OS 7.5") }}
The Rust version is a bit more efficient than the [Nim version][nim-version] as
it avoids some copying and heap allocation. That latter of which because I'm
coding in a `no_std` environment without a heap.
The Rust standard library is divided into three main parts (crates):
1. `core` for things that do not require heap allocation, I/O, etc.
2. `alloc` for things that use heap allocation but not I/O etc.
3. `std`, the rest: files, networking, threads, etc. `std` re-exports the
other two.
By defining a custom allocator that called `malloc` and `free` provided by the
Retro68 environment I was able to use the `alloc` crate in addition to `core`.
This gained me access `String`, `Vec`, and friends.
#### Networking
I now wanted to build something a little more involved than a single dialog. I
set about building bindings to Open Transport, Apple's network stack introduced
with PCI Power Macs (like my 9500).
Due to its heritage most of the Mac OS toolbox functions use the Pascal calling
convention, [which LLVM does not support][llvm-pascal]. To bridge the C (and
Rust) world to this Pascal world I had to create [trampoline functions] in C
for each toolbox function that I wanted to call from Rust (if there's a better
way to do this I'd love to know how). This works because `gcc` in Retro68
understands both C and Pascal calling conventions. I appended an underscore to
I used the "Downloading a URL With HTTP" example from the [Networking With Open Transport]
book as a guide for the functions I needed. Once the bindings were created I
implemented the `TcpClientStack` trait from the [embedded-nal] \(embedded network abstraction layer)
crate against Open Transport. Next I used this with the [http_io] crate to be able
to make HTTP requests.
As an initial test I wrote an app to fetch a friend's website (since it's
available over plain HTTP) and show an alert with the number of bytes read.
Amazingly this worked on the first try: the Open Transport bindings, the
`TcpClientStack` implementation, the HTTP client, and my test code all worked!
Finally I used my newfound networking abilities to build [Ferris
Weather][ferris-weather], the application shown at the start of the post. This
uses the HTTP client to fetch a JSON file containing weather observations,
parses it with [serde] and then shows an alert with the most recent
observation. I also drew a little 1-bit [Ferris the Rustacean][Ferris] in
[ResEdit] for it.
The idea for this was prompted by the [Australian Bureau of Meteorology][bom]
still being accessible over HTTP. Unfortunately it wasn't working and after a
lot of debugging I eventually discovered that I triggering their anti-scraping
blocker for some reason. To work around this I copied a snapshot of the JSON to
my own server. So, unfortunately the data shown by the application does not
update but you still get the idea.
{{ figure(image="posts/2023/rust-classic-mac-os-app/Ferris%20Weather.png", link="posts/2023/rust-classic-mac-os-app/Ferris%20Weather.png", pixelated=true, border=1, alt="Screenshot of the Ferris Weather application showing an alert with the temperature in Brisbane.", caption="Ferris Weather") }}
So there you have it, that's how I built an application in Rust (and some C)
for classic Mac OS. The [source code to Ferris Weather][ferris-weather] is on
GitHub.
### Next
My intention is to take a bit of a break from classic Mac OS for a bit and work
on some other projects—ones that might be useful to people in this century—but
there are some things I want to look at when I come back to it:
First is TLS support for the HTTP client. I think this should be relatively
straightforward with the [embedded-tls] crate.
Next I'd like to improve how Open Transport is used. I think with either
the synchronous, non-blocking mode I'm using now or the asynchronous mode it
should be possible to tie it into the async Rust ecosystem, which would allow
it to play nicer with the event loop and cooperative multi-tasking.
Finally, so far I've been working without the full Rust standard library, only
`core` and `alloc`. It seems like it should be possible to implement a lot of
the remaining standard library (io, networking), on top of the Mac OS toolbox,
but that's a lot of work and will have to wait for another time.
### Hire Me
As mentioned at the start of this post I'm currently taking a break from
employment but I will be looking for a new role next month, so if you're looking