os8088 v1.0.20260803.1
Paint arrives -- a bitmap editor with eight tools, an undo that doubles as redo, and BMP and GIF files it reads and writes off the floppy -- and the kernel grows the thing Paint needed in order to exist. Under the old rules a program that wanted a quarter megabyte to draw on took it by picking an address and hoping nothing else wanted it; now it asks, and the arena that hands out program segments hands out plain memory from the same single first-fit walk. A window can also resize itself for the first time, which is what lets a canvas refuse a shrink that would crop the picture. Along the way the floppy driver learned that the DMA controller cannot cross a 64KB boundary -- a rule it had been getting away with ignoring only because every buffer before this one happened to be aligned.
What changed
Paint (#43). A bitmap editor contributed as a fork of os8088 by github.com/Elendilon: eight tools over a 4bpp offscreen canvas, one level of undo that doubles as redo, an internal clipboard, and BMP and GIF load and save through the Standard File dialog. At 14,112 bytes it is by some distance the largest package that ships -- the six before it ran from 323 bytes to 2,774. Its canvas, undo image, clipboard and scratch space are one allocation, sized from the largest free run the kernel reports, and it deliberately leaves 64KB behind when doing so still funds the top size tier: a canvas plus an equal-sized undo image otherwise eats a 233KB arena whole and nothing else can load while Paint is open. Two copies of Paint get two canvases, the second tiered down to fit.
A package can ask the kernel for memory (SPEC.md 2.6). Three new calls -- OSAPI_MEM_ALLOC, OSAPI_MEM_FREE and OSAPI_MEM_AVAIL -- hand a package a plain segment out of the same conventional-memory arena that loaded programs come from. A package's own region caps at one segment and holds its image and its static data, so an application whose working set is hundreds of kilobytes had nowhere to put it. What matters about the implementation is that there is still only one allocator: the loader's region search is now a jump into the grant allocator's first-fit walk, which rejects a candidate overlapping any package region or any grant. Two allocators over one arena that searched separately would eventually hand out the same paragraph. Grants are stamped with the instance that asked and force-freed at all three teardown paths, which is what makes the call safe for a package that owns no task and is therefore never told its window is closing.
The segment a package was already executing in. The loader reserves a package's region early but does not publish the instance record until after the entry procedure returns -- and the record is the only evidence the allocator has that a region is taken. So for the whole of that call, the loading package's own memory read as free. Paint was the first package to allocate from its entry, and it was handed the segment it was running in: it filled its new canvas with white and the machine wedged mid-repaint on the first 0xFF opcode, with the drawing lock still held. There is now an explicit reservation covering that window, written with MOV only so the entry procedure's carry flag still reaches the loader.
A window can resize itself. OSAPI_WM_RESIZE retires the last place where a package wrote a kernel record behind the kernel's back. The two things that could resize a window -- the grow box and full-screen -- were both kernel-internal, so an app whose content has a size of its own, a picture just opened or a canvas whose shrink must be refused because it would crop artwork, had no legitimate way to say so. The call clamps to the minimum window size and to the screen, re-clamps the position, and draws nothing: the caller is inside its own callback and knows what it is about to repaint.
One sector per call is not enough: the 64KB DMA page (SPEC.md 18.1). Opening a saved BMP answered Disk error, while the save that produced it had worked and the file was byte-exact to a host reader. The floppy driver transfers one sector per BIOS call and had concluded from that -- in writing, in the spec -- that DMA alignment could never matter. The first half of that is true and the second is not: the DMA controller's page register does not increment, so a transfer of any length may not cross a 64KB physical boundary, and a BIOS asked to do it anyway refuses rather than wrapping the buffer. It hid for years because every disk buffer in the tree before this one was 512-aligned by accident. The first that was not was the first to come from an arena grant, where a base can be any paragraph. The driver now detects a sector that would straddle and stages it through a buffer of its own -- at most one extra 512-byte copy per 64KB transferred. This is the kernel's obligation and not the caller's: an application cannot be asked to know about the 8237.
The Task Manager counts what was granted. The RAM line, the arena caption, the per-row size column and the memory map's coloured bands all include grants now. A grant is routinely an order of magnitude larger than the package region beside it, and leaving it out drew a one-pixel sliver where a quarter of the machine had gone.
About lives under the app's own name. Paint puts a pull-down exactly where the menu bar draws an application's name, which is where a Macintosh keeps About. It needs no kernel change -- a menu set whose name is the empty string and whose first menu is titled after the app does it -- and the dock tile, the Task Manager row and the loader all keep reading the name out of the package header. The About window is a second instance-less window of the file dialog's species, and its command is dispatched ahead of the check for whether there was enough memory to start, so a machine too small to fund a canvas can still be told what the program is and who wrote it.
Notes
- Packages built for the previous release still run. The API table grew from 53 slots to 57 and the four new ones are appended, so nothing was renumbered and the format is still v3.
- Paint sizes itself to the memory it can get. On a 640KB machine it opens full size; with less free arena it tiers down, and on a machine with no arena at all it puts up a notice instead of a canvas. Two instances is normal and the second is smaller by design.
- The disk fix matters beyond Paint. Any file read or written into a buffer that a package allocated could previously fail with Disk error depending on where in memory that buffer happened to land. If you have a package of your own that stages file I/O anywhere other than its own static data, this release is the one that makes it reliable.
- Recorded as unexercised: 86Box -- the XT targets and the three AT-class machines -- and the 256KB floor, where the arena is empty and Paint should show its notice. QEMU is the only environment run routinely, and everything above was verified there: launch, draw, resize, a Save As to a 320x280 4bpp BMP that a host reader accepts, close with the grant released, two instances, and Minesweeper loading beside a full-size Paint. The file-system gate package passes 21 of 21 on plain FAT12, a deliberately fragmented volume and FAT16.
Size
Kernel image 45,595 bytes. Image plus .bss is 45,586 of the 65,536-byte segment, leaving 19,950 free. 49,298 lines of assembly across 31 kernel modules.
Downloads
The four floppy images are attached. os8088.img and apps.img are 1.44MB geometry for QEMU; os8088-360.img and apps360.img are 360KB for 86Box and period hardware. The software disk carries MINES, HELLO, NOTEPAD, RECORDER, PIANO, FRACTAL and PAINT.
Boot it in a browser, or read the exact QEMU command line, at https://os8088.com/download/