Conversation
With NONOS_LINUX_GUESTS=1 the kernel was still built with the setup profile. Under it the apps, the Linux personality among them, spawn only once first-boot setup exits, and setup waits for keys. An unattended guest boot therefore never started its guest: in 180 s after `[INIT] Capsules spawned` the log had `[SETUP] keyboard held` and no `[APP-LINUX]` or `[LINUX]` line. That image now builds `microkernel-desktop-gui` with `nonos-stark-attest`, the same capsule set without setup, so the apps spawn at boot. Every other build of nonos-mk-desktop-gui-prod is unchanged.
Threads run on their leader's tables without owning an address space entry, so release freed the tables when the leader was finalized, whatever its threads were doing. A thread still in the process table can be on the CPU under those tables, taking its own kill. When a Go guest exited, the personality killed its threads and then its leader, and the timer drain finalized the leader while a Go thread was running. The kernel then took a page fault fetching the double fault gate, and the machine reset: CR3 was the guest's, FS held the Go thread's TLS, and CR2 was the IDT's entry for vector 8. Release now hands the address space to another process in the table that runs on the same tables, and rebinds that process's capability token to the ASID it now owns. The last holder's release frees the tables.
A Linux clone child resumes after its parent's `syscall` holding the parent's registers, with rax zero and rsp the new stack. MkForeignThread started the child on fresh registers instead, and both runtimes that start threads here call through a register in the child: Go's `runtime.clone` calls r12 and reads m and g from r13 and r9, and musl 1.2.4's `__clone` calls r9. The first gohello boot started two threads, and they faulted at `rip=0` and at a heap address on an NX page. MkForeignThread takes a fifth argument, the guest thread parked in the call that asked. Given, the new thread starts on a copy of that thread's parked registers, with rax zero, the entry and stack given, and the parent's FS base unless a TLS is named. The source thread must be supervised by the caller and in the same thread group as the target, so no guest receives another's register contents. Zero keeps the fresh start. The personality passes the calling thread, and passes a TLS only when CLONE_SETTLS is set; before, a clone without it installed the fifth argument, whatever it held, as the child's FS base.
MkKill admitted a parent or a holder of ProcessControl. A guest thread's parent is its group leader, not the supervisor, so when a Linux guest exited, the personality's kill of each thread was refused with EPERM, and the refusal was dropped. The threads outlived their process. Once the personality had exited, their parked calls were abandoned and they ran Go code with no one to answer them: a second goconc boot showed a guest thread faulting at 0x1006 and then at address zero after `[LINUX] guest exited`. MkKill now also admits the caller the foreign registry names as the target's supervisor. The personality prints a refused kill as `[LINUX] kill refused: pid <n> outlives its process, errno <e>`, so a thread that survives its process is named in the log.
Pressing the close button now asks the app first, through close_requested. An app holding unsaved work returns false and says so in its own window; the next press closes. The default closes as before, so no other app changes.
A failed open no longer renames the tab, so the next save cannot write the old text over the file that failed, and a failed open from the tree opens no tab. Opening puts the file in its own tab and never replaces text; a load resets undo, redo and selection. A new document is untitled instead of carrying /notes.txt unread, and saving it asks for a path. Save As asks before replacing another file, and a document takes a new name only once the write lands. Undo and redo track a save point, so undoing back to the saved text is clean and undoing past it is not, even after old steps are dropped. Every close control and the window close button ask once before discarding unsaved text, and Esc no longer closes the window. editor_proofs compiles again, with save-point proofs: 34 pass.
A no_std crate the terminal will draw from. The parser is the DEC state machine: CSI with private markers, colon sub-parameters and intermediates, OSC, DCS, SOS/PM/APC swallowed, CAN/SUB/ESC aborting any sequence, UTF-8 split across reads. The screen defers the wrap at the last column, so a full-screen program can fill the bottom-right cell, and implements IL, DL, RI, SU, SD, ICH, DCH, ECH, REP, tab stops, origin and insert modes, DECSC/DECRC, the 47/1047/1048/1049 alternate screens, DEC line drawing, wide characters kept whole, and combining marks and ZWJ sequences in one cell. Resize re-wraps the normal screen and its history. It answers DA1, DA2, DSR, DECRQM, XTVERSION, XTGETTCAP, DECRQSS, size reports and OSC colour queries, since editors wait for them. A program may not move or resize its window, and a clipboard read (OSC 52 ?) is refused and counted. Keys, mouse (X10 and SGR), focus and paste encode per mode; paste strips escape bytes so pasted text cannot end the bracket and run as commands. Every buffer output can grow has a ceiling in limits. 69 tests, including a seeded mutation fuzz that interleaves hostile output with resizes, copies and searches and checks the cursor and row widths after every step; it found a cursor left below the screen after a resize, fixed here.
The PS/2 keymap already emits Insert as 0x1209 and F1 to F12 as 0x1101 to 0x110C. Apps had no names for them, so none handled them.
The fixed 96x40 grid and its partial VT layer give way to nonos_vt. The screen follows the window size and zoom, re-wrapping on resize, with 3000 lines of history a tab on a 64 MiB heap, and draws bold, dim, every underline style, strikethrough, overline, inverse, hidden, wide and combining characters, and the cursor shape a program sets. A program in the foreground or on the alternate screen owns the body; the prompt returns when it ends, with any modes it left on reset, and output is read up to 64 KiB a tick instead of 256 bytes. A program reading raw gets keys as xterm sends them (taken as raw once it asks for the alternate screen, application cursor keys, bracketed paste or mouse reports, as there is no path for its tty settings yet); any other gets lines edited as a tty's canonical mode edits them. Ctrl+C interrupts, and a program's queries are answered on its stdin. The pointer selects text (double click a word or path, triple click a line, Alt for a block), or goes to a program that asked for mouse reports unless Shift is held. Ctrl+Shift+C copies, Ctrl+Shift+V pastes, Ctrl+Shift+F searches history across wrapped lines, and the wheel scrolls history or sends cursor keys on the alternate screen. Proofs for the line editing and selection added to terminal_line_proofs.
A launcher that renders a child's output knows which of the child's standard streams reach its screen; the child had no way to ask. MTTY lets the parent record that, with the size in cells, under the same parent rule that lets it drain the child's output, and it needs IPC as MTRN does. MTTQ answers the caller about its own stream 0, 1 or 2 with the size, or ENOTTY. The record is dropped as the process is finalized, so a reused pid starts with no terminal. Both calls are published in the ABI with libc wrappers, and the syscall checks pass with the unreachable count unchanged.
Three answers disagreed on NONOS: std's IsTerminal fell to the unsupported arm and said no, the vendored is-terminal said no, and the atty shim said yes for every stream, so one tool could colour a pipe while another printed plain text to a person. std now asks MTTQ for streams 0 to 2, and both is-terminal copies and atty go through std, so there is one answer and it is the launcher's.
Noto Sans has no arrows, no triangles and no not-equal sign, so every app that printed one showed an empty box. A character the chosen built-in face lacks is drawn from the other one when that has it, cached under the face it came from, and measured the same way so layout and paint agree. Kerning only pairs glyphs of one face.
The explorer drew its chevrons as characters the UI font does not have, so every folder showed a box. They are now drawn on the pixel grid. The code lexer ran over every buffer, so a note coloured `from` as a keyword and a Markdown heading as a comment; plain text and Markdown are now left as typed.
A Ctrl or Alt chord the line editor did not bind fell through to the printable arm, so Ctrl-F typed an f. Unbound chords are now swallowed, AltGr excepted since some layouts type characters with it. Ctrl-F and Ctrl-H step and rub out a character, Ctrl-P and Ctrl-N walk history, and Alt-B, Alt-F and Alt-D move and cut by word, with Alt-D's cut going to the ring Ctrl-Y reads. The skeleton exports MOD_ALTGR, which the PS/2 driver already sets. The arrow and page keys move to their own file.
The help tests parsed writeln calls that the table-driven help no longer makes, so they read three rows and failed. The tables and row layout now live in a file the proofs include, and the tests render every row the terminal prints. That found the files and system rows at 82 and 85 columns; they are regrouped into files, disk, text, system and session. The tools row names each program once. help keys now covers selection, the clipboard, search and the readline keys.
rg and ripgrep mapped to tool.ripgrep, which the kernel's tool registry has never held: the ripgrep capsule is a boot-time service MkToolRun cannot reach. Typing either printed "tool: launch failed" in every build. A proof now checks each tool the terminal offers against apps.list, and a refused launch names the tool and says whether it is missing from the build or was refused.
A press a few pixels left of the first column landed outside the cell grid and started nothing. The hit area now takes in the margin painted around the text, and the column clamps to the edge cell. The pixel to cell maths moves to its own file.
A tool, store tool or exec'd program whose output this terminal renders is told, through MTTY, that its three standard streams reach a terminal of the current size, so it chooses colour and columns for a person. A pipeline stage or redirected command is never told and writes plain bytes. When the window resizes, the program in front is told the new size.
-Zbuild-std fingerprints the sysroot crates by version rather than by their sources, so a tool whose target dir already held a std kept linking it after the NONOS std layer changed. Six of the tools shipped that way without the new terminal query, and pastel still printed its pipe output to a person. Applying the layer now clears the per-tool std caches it just made stale.
The line buffer, the history and the kill ring were sized by COLS, the screen's starting width of 96, so a longer command was cut at column 96. An echo with a redirect lost its file name there and wrote to a different file. Typed input now holds LINE_MAX, 1024 bytes, and the prompt already scrolls sideways across a line wider than the window.
Programs name colours 0 to 15 and got xterm's, whose blue is #0000EE: 2.2:1 against the dark themes, so tokei's table headers could not be read. Each theme's ground now picks a dark or a light set, and a proof holds every text colour at 4.5:1 or better on every shipped ground.
A font draws a line character inside its glyph box, so the line gap left a break between rows and csview's tables did not join. The light, heavy, double and rounded line characters are now stroked from edge to edge of the cell, arms meeting at the centre, and anything else still comes from the font.
The chain, anchor, hostname and validity checks ran only on the probe connection, where they set status text. The connection that reads balances, the nonce and the fee, and broadcasts, checked nothing but the server's Finished, and CertificateVerify was never checked anywhere. A server that replays the real chain and finishes the handshake on keys of its own passed, and could name any gas price the wallet then signed at. CertificateVerify is now verified with the leaf's own key over the transcript to the Certificate, and every RPC call requires it together with the chain, the pinned root, the hostname, validity against the clock, and Finished. ClientHello offers only the ECDSA schemes there is a verifier for.
Creating a wallet set the backup flag, but the Etna Receive screen was drawn over it, so the phrase never appeared, and the next Enter wiped it. On a machine that cannot seal keys the account then lived only in RAM with no way back. The phrase now has its own screen, straight after creation, with no back button: confirming is the only way on, and it wipes the words. Esc used to close the window before any handler saw it, so every "Esc to cancel" on screen was dead. It now closes an open panel, returns other screens home, and does nothing at home.
The fee cap is twice the node's gas price with no upper bound, so a broken node's reading would be signed as given. A transfer is now refused above 1000 gwei, and the reason the refresh failed is the one shown, instead of a single message for every cause.
Shield opened the old dashboard. It now has its own Etna screens: home with shielded balances first and the nox1 receive address, deposit and withdraw in the pool's standard sizes only (0.01 to 10 ETH, 1,000 to 5,000,000 NOX), private send with the sentence the pool asks every wallet to show, review, proof progress, history and the Sepolia contracts in full. The spend wait is a meter of 20 new notes and 6 hours; spending early needs the typed words "spend early". A nox1 address is pasted with Ctrl+V, since it is too long to type. Nothing here pretends. Balances read from the note store show a dash until notes exist, history and proofs show only what the shield service reports, and Confirm goes through one request seam that refuses with a sentence while this build cannot yet speak the service's format.
A withdrawal spends a note, so it now waits for the same 20 new notes and 6 hours as a private payment, or the typed "spend early", before it can be reviewed. The walk-through on the live image let one through with the wait not even counted. Each choosing screen starts with no size picked; the 10,000 NOX picked on Deposit had been carried into Withdraw. The no-service banner's Dismiss now hides it until Shield is next opened, where it did nothing. The Sepolia page's labels are capitals like every other label.
Swap opened the old dashboard. It now has its own screen: the token paid and the amount typed, the token bought and what the pool says comes back, then rate, price impact, minimum received, slippage, network fee and route in one tile, with a warning in words when the impact is large. Picking the token already on the other side swaps the pair, so a token is never traded for itself. The quote source is still the stub, so an amount gets no price. The screen says that in a banner instead of showing zero, and the button stays "Enter an amount". Nothing signs a swap in this build.
The Swap screen's no-price banner drew a Dismiss that did nothing; it now hides the banner until the amount is edited. The early-spend warning said "this payment" on the Withdraw screen too, and now reads for either.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #567. This PR targets
linux/store-installso it shows only its own 29 commits: 9 terminal commits that were already onui/terminal, and 20 new ones. When #567 merges intomain, retarget this PR tomain.Each commit builds on its own. The wallet and terminal were checked live on a 1920x1080 QEMU boot of the image built from this branch.
Kernel and std
kernel: tell a program whether its streams reach a terminaladds a tty table,sys_tty_set(parent only, needs the IPC capability) andsys_tty_query, which answers rows and columns or ENOTTY.std: ask the kernel whether a standard stream is a terminalmakesis_terminalreal in the std layer. Tools such as pastel now colour their output on a screen and stay plain in a pipe, without being patched.build: drop std build caches when the std layer changesfixes a stale-std hazard:-Zbuild-stddid not rebuild std when rust-src changed underneath it.Terminal and toolkit
rgdropped, since no build registers it, and refusals named.Wallet
talk to the RPC only after the server proves it is the host: TLS 1.3 CertificateVerify is now checked (RFC 8446 4.4.3) before any request is written. Before this, the chain was checked but the server never had to prove it held the key.show the recovery phrase, and make Esc go back: the phrase is shown once, in a numbered grid. Esc goes back one step instead of closing the window.refuse to sign a transfer above a 1000 gwei gas price.draw the Shield screens and say when no shield service answers:Spending a note before the 20-note, 6-hour wait needs the typed words "spend early". A nox1 address is pasted with Ctrl+V.
make a withdrawal wait like a payment: found on the live boot, where Review withdrawal was enabled with the wait not even counted. The same commit resets the size between screens and makes the banner's Dismiss work.draw Swap on the Etna frame: rate, price impact, minimum received, slippage, fee and route in one open tile. Picking the token already on the other side swaps the pair.What is not wired, and says so
screen/shield/request.rs. It refuses with a sentence while no shield service answers, and while this build cannot yet speak the service's request format.Checked
cargo checkfor x86_64-nonos-user, with no new errors; the only new warnings are dead code for history states the shield service will fill.