You are browsing as a guest. Sign up (or log in) to start making projects!

AmethystOS

  • 4 Devlogs
  • 24 Total hours

A tiny x86-64 operating system written in pure assembly (NASM), booting from real mode through protected mode into 64-bit long mode with no bootloader dependencies beyond the code in this repo.

Open comments for this post

9h 44m 46s logged

Mass storage groundwork. “Added ls/dir commands with FAT read support over USB mass storage” pulled the xHCI bring-up out of commands_usb.asm’s cmd_usb into a shared xhci_controller_init (caps parse, halt/reset, scratchpad, DCBAA, command+event ring, run — CF on failure) so the new commands_fs.asm could drive the same controller for bulk-only mass storage: Enable Slot → Address Device → GET_DESCRIPTOR → bulk CBW/CSW SCSI READ(10), one 512-byte sector at a time, feeding a FAT12/16/32 root-directory listing.

Filesystem support broadened fast, one commit per format. “Added exFAT support” added MBR partition-type detection plus a GPT path (header at LBA 1, 4 entries/sector, first entry that parses as a valid VBR wins) alongside “EXFAT “ OEM-ID detection. “Added NTFS support” added MFT-cluster/record-size parsing and an AML-free walk of root record 5’s INDEX_ROOT/INDEX_ALLOCATION B-tree entries. “Added cat command” threaded an fs_action/fs_cat_found flag through all three listing walkers (FAT, exFAT, NTFS) so the same traversal either prints every entry or stops at the first name match and streams that file’s clusters instead.

Write support, one format at a time. “Added FAT32 write support” added fs_write_sector (SCSI WRITE(10)) and echo-to-file: create-or-overwrite a root-directory entry, allocating a fresh cluster chain via the FAT. “Added FAT16 write support” reused the same path, adding a fs_is_fat16 mount-time branch (FAT12 vs FAT16 disambiguated by the classic <4085-cluster rule; FAT12’s packed 12-bit entries stayed explicitly unsupported). “Added exFAT write support” extended fs_build_target_name to track a display-cased name (fs_target_disp) alongside the raw match name, and added its own root-entry alloc/overwrite path capped at 15-char names. “Added NTFS write support” was the big one (~1500 lines) and the slowest by far — about 8 hours to get right: update-sequence fixup read/write (fs_write_fixup, inverse of the existing fixup-apply), MFT record allocation via $MFT’s $BITMAP, resident $DATA overwrite-in-place, and — for new files — a full FILE record build plus INDEX_ROOT insertion into record 5, gated to root-only files with no INDEX_ALLOCATION. The attached screenshot is an NTFS volume end to end: ls listing System Volume Information and test.txt, an echo ... > file.txt walking through the debug trace (search → create path → alloc ref → build record → indx-alloc insert → ok), and cat file.txt reading the freshly written content back.

0
1
16
Ship #1

What did you make?
AmethystOS — a tiny x86-64 operating system written in pure NASM assembly, booting through real mode → protected mode → 64-bit long mode with zero bootloader dependencies (works on both legacy BIOS and UEFI). It has a hand-rolled text-mode shell (history, arrow-key editing, a calculator, ACPI-powered real shutdown, a PS/2 mouse cursor, sysinfo/date/time/draw), and — newest — a full USB stack: UHCI/OHCI/EHCI/xHCI controller detection plus real device enumeration down to fetching each device's actual vendor/product name strings live over the wire.

What was challenging?
Getting the boot chain right with nothing to lean on: A20 gate, GDT setup, the jump into 32-bit protected mode, then PAE paging and EFER.LME into 64-bit long mode — all before there's a print function to debug with. Later, building a hybrid BIOS+UEFI image meant maintaining two completely different boot paths in one ISO. The USB3/xHCI work resurfaced that same "no debugger" pain: three silent bugs (a clobbered PCI write, an event-type mixup, an untracked ring cycle-state bit) that each looked like dead hardware until traced by hand.

What are you proud of?
That every layer — boot chain, shell, ACPI shutdown, USB3 device enumeration — is hand-written with no OS framework, no bootloader, no libc. Including the small detail that USB vendor/product names shown by the usb command aren't hardcoded: they're decoded live from each device's real USB string descriptor.

How people can test it:
Easiest: try the demo website first — a React reimplementation of the shell that runs in-browser, no VM setup needed.

Note to Shipwrecks: development is ongoing, so by the time this is reviewed, the project may have changed — lightly or heavily — for the better. Treat this ship as a snapshot, not the final state.

  • 3 devlogs
  • 14h
  • 7.65x multiplier
  • 108 Stardust
Try project → See source code →
Open comments for this post

2h 27m 2s logged

Demo website. “Added demo website” added a React 19 + TypeScript + Vite frontend under frontend/ that reimplements the shell in-browser rather than just describing it: a simulated 1MB memory buffer seeded with a fake IVT/BDA/boot sector/RSDP, a virtual 0xB8000 VGA text buffer, and a boot sequence (blank POST screen → “Hello, Amethyst!” → prompt) mirroring entry.asm. Reuses the real ASCII art strings from data_commands.asm and tracks cursor/attribute/scrollback state parallel to the kernel’s own globals.

USB enumeration. “Added usb command with USB 1.1/2.0/3.x device enumeration” is the big one (~1200 lines, mostly new commands_usb.asm): brute-force PCI scan for class 0x0C/subclass 0x03 controllers, printing bus:dev.func, controller type (UHCI/OHCI/EHCI/xHCI), and vendor:device IDs. EHCI drives a real async QH/qTD control transfer to fetch each device’s descriptor. xHCI goes further — full register setup, command ring + polled event ring, per-port reset/speed detection, then a genuine Enable Slot → Address Device → GET_DESCRIPTOR(Device) sequence per port. Getting this working surfaced and fixed three bugs in one commit: pci_write32 clobbering its own value through a scratch register pci_config_addr also used; xhci_wait_event returning any event regardless of type, mistaking a stray Port Status Change Event for a command completion; and an untracked Cycle State bit that silently dropped every second transfer on the reused control-transfer ring.

Vendor/product names, without hardcoding. “Added iManufacturer string fetch for USB vendor names” factored the existing iProduct fetch into a shared xhci_print_string_desc helper, called once for iManufacturer and once for iProduct — decoding the real UTF-16LE string descriptor live over a control transfer, no lookup table. Also cleaned up the register-dump and completion-code debug prints left over from chasing the bugs above, so cmd_usb’s output is just the device/vendor/name lines.

0
1
25
Open comments for this post

2h 28m 10s logged

Previously in devlog #1: Boot chain transitioned from 16-bit real mode to 64-bit long mode; shell got core commands (echo, run, clear, mem, peek/poke, cpuid, uptime); ACPI power-off enabled true hardware shutdown; UI/UX gained text input, PS/2 mouse cursor, scrolling, and draw/sysinfo; infrastructure achieved hybrid BIOS+UEFI boot.

Codebase organization. The second “Organized src/” commit dismantled the monolithic kernel.asm by extracting components into modular topic files (%included under defs.inc.asm, entry.asm, interrupts.asm, input.asm, display.asm, data_strings.asm, data_commands.asm, and command handlers divided by category).

Shell features. “Added command history” implemented a 16-slot ring buffer for commands up to 128 bytes each. Arrow Up recalls older lines while caching the current unsaved prompt; Arrow Down moves back forward, restoring the saved prompt at position 0, with cursor positioning aligned to the end of the text. Shift+arrow keys are bypassed to maintain viewport scrollback.

Calculator. “Added calc command” introduced signed decimal parsing (parse_dec_arg) and printing to support signed 64-bit integer binary operations (+, -, *, /, %). It also implements an integer square root (isqrt64) working as a prefix or postfix (calc sqrt N or calc N sqrt) with error-checking for division-by-zero and negative parameters.

Infra & Licensing. “Updated LICENSE” adopted the custom TreeSoft Open Source License. “Added release workflow” standardized output file names to lowercase kebab-case (amethyst-os.iso/.img) and introduced a GitHub Actions pipeline that builds both ISO and raw USB images on ubuntu-latest, calculates SHA256 checksums, and publishes nightly prereleases via the GitHub CLI.

0
2
95
Open comments for this post

9h 12m 5s logged

Boot chain. Started as a 16-bit MBR sector that set VGA mode 3 and printed “Hello, Amethyst!” via BIOS teletype. Added protected mode (A20 gate, GDT, CR0.PE, far jump to [BITS 32], direct 0xB8000 VGA writes replacing BIOS calls), then long mode (PAE paging, identity-mapped first 1GB, EFER.LME). Later split the monolithic boot.asm into stage1.asm (real→protected→long mode handoff) + kernel.asm (%included, everything from protected mode on) — that was “Cleaned codebase”; “Organized src/” was purely a file move (src/boot/kernel.asm → src/kernel/kernel.asm), no logic change.

Shell core. echo came first, then run — decodes a hex-byte string into a scratch buffer and calls into it directly, no sandboxing, on purpose. “Added more commands” was one big commit landing nine at once: clear, help, reboot, halt, mem, peek, poke, cpuid, uptime, shutdown.

ACPI. “Improved shutdown” was misleadingly named — it’s where real ACPI support landed: RSDP scanning, RSDT/XSDT parsing with checksum validation, a brute-force table scan fallback, _S5 AML decoding, and the acpi command to probe/display it all. This is what makes shutdown actually power off real hardware instead of just halting.

UI/UX. color added named presets (red/green/blue/yellow/white) plus raw hex attribute bytes, with input validation and a usage message. Arrow-key navigation added cursor movement, word-jump (Ctrl+arrow), selection, insert/delete-at-cursor, and full input-line redraw logic — the single largest diff in the history (~343 lines). Then PS/2 mouse cursor support, scrolling, and scrollback.

Later additions. date/time, sysinfo (cpu/ram/gpu/general, using the BIOS memory map stage1 captures in real mode), draw. “Doubled stage1 budget; Fixed bugs” doubled KERNEL_SECTORS 16→32 (and the matching -boot-load-size/times padding) to make room for growth, and in the same commit reworked help to print aligned two-column output with per-command descriptions (command_descriptions table) and tightened color’s argument validation.

Infra. Hybrid BIOS+UEFI boot support: uefi.asm linked as a PE32+ EFI app, packed into a FAT ESP image, combined with the BIOS MBR into one hybrid ISO, plus a raw .img for USB writes and three separate QEMU run scripts for each boot path.

0
2
235

Delete project?

Are you sure you want to permanently delete this project? This action cannot be undone.

All devlogs, followers, and associated data will be removed.

Followers

Loading…