Commit graph SchOS/kernel/dev/mouse.c
Author SHA1 Message Date
Nexoniarz
94c936ed98 boot: stop assuming the machine is an emulator
Every one of these works under QEMU and stops a real machine:

- MADT processors that are "online capable" but not enabled were
  counted as CPUs. AMD firmware lists absent cores that way (so does
  QEMU with maxcpus), and startothers() then waited for ever for an
  AP that does not exist. Only enabled entries count now, x2APIC
  (type 9) entries are read too, and the wait is bounded to a second;
  an AP that misses it is parked with INIT and the boot goes on.
- The PIT calibration loop had no bound. Recent boards clock-gate the
  8254: the output never rises (a hang) or floats high (TSC "0 MHz"
  and every clock thousands of times fast). The loop is bounded and
  checked, and falls back to the ACPI PM timer, then CPUID 0x15/0x16.
  Under QEMU pit=off the PM timer gives the same figures the PIT did.
- Firmware that hands over in x2APIC mode left lapic[] reading
  garbage: cpunum() panicked or the timer never started. Each CPU is
  switched back to xAPIC first (x2APIC -> disabled -> xAPIC).
- The IOAPIC was always at 0xFEC00000 and interrupts were aimed at
  APIC ID "0". Both now come from the firmware's tables.
- INIT-to-STARTUP was 100 us ("Bochs is slow"); it is the 10 ms the
  MP specification asks for.
- mouseinit() drained the 8042 with an unbounded loop. With no
  controller the port reads 0xFF and the loop never ends. It now
  notices there is no controller and skips the mouse.

Tested in QEMU: i440fx and q35, -smp 4, -smp 2,maxcpus=4, pit=off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HH7xukt4aaiGj1nQEAoQf1
2026-10-22 10:29:12 +02:00
Nexoniarz
817d666068 gfx: the console and the crash screen stop drawing on a driver by name
Same disease as the network stack, one subsystem over. kernel/dev/vga.c
was three things wearing one name: the owner of the framebuffer, a
bitmap drawing library, and the text console. Only the first is a
driver, and because they shared a file they shared a prefix -- so
panic.c drew the crash screen with vga_fill_rect, console.c printed with
vga_putc, /dev/fb0 handed out vga_fb_phys, and every one of those files
named a display driver it had no business knowing about.

Split three ways:

  - kernel/drivers/gpu/vga/vga_fb.c owns the VBE framebuffer -- the mode
    the loader programmed and handed over, the aperture, and the display
    class vtable. It is a driver and now lives with the driver that
    finds the card on the bus.
  - kernel/dev/gfx.c draws: pixels, shapes, glyphs, the cursor, scroll,
    the ANSI erase operations. It names no driver. The framebuffer
    arrives through gfx_attach_scanout(), so a driver publishes what it
    owns and this file draws on it without knowing what it is.
  - include/gfx.h is the interface, and says why it is deliberately not
    the display class: that one is about frames -- acquire, present,
    vblank -- and the crash screen has to work when nothing else does.

main() no longer calls a display driver. platform_register_devices()
takes the framebuffer address and brings up whatever owns it, which is
where driver names belong; kernel/drivers/registry.c is the file whose
entire job is naming every driver in the kernel.

virtio-gpu got the e1000 treatment as well: instances in an array, the
instance hung on dev->priv by an `attached` hook, and every op reading
it rather than a file-static. It refused the second adapter outright
before, which is not hypothetical -- integrated plus discrete is an
ordinary laptop. The VGA driver deliberately has no such hook, and says
so: there is one framebuffer the loader programmed however many
VGA-class controllers the bus turns up, and a second one publishing the
same scanout is the truth rather than a bug.

Private headers moved next to their drivers: include/virtio.h and
include/xhci.h each had exactly one includer. include/ is for headers
the rest of the kernel needs.

Deleted rather than moved: consoleinit() programmed the sixteen ANSI
colours into the VGA DAC and disabled text-mode blink, by writing ports
0x3C0-0x3C9 from the console. The comment three lines above the colour
table already said this does nothing in a 32bpp linear mode -- there is
no palette to index -- so it was both dead and in the wrong file.

Verified, and this is a refactor so the evidence is that nothing moved:
  - bootcheck -Fb -Net: 59 [ok], no failures. That covers the console
    through every command, /dev/fb0's geometry, writing pixels through
    write() and mapping the framebuffer through mmap.
  - make crashshot: the crash screen renders exactly as before --
    shapes, glyphs, logo and QR code -- which is the whole of gfx.c
    exercised at once, in a panic, with the scanout attached by a driver.
  - make schcom-test: five pixel assertions from the host oracle still
    pass, so the display class and the compositor above it are unmoved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 17:04:10 +02:00
Nexoniarz
ad2b321d56 dev: raw disks are 64-bit, so a real drive stops wrapping at 4 GB
struct file already carried a uint64 offset and bread already took a
uint64 block number. The narrowing was one boundary in the middle:
devsw's read and write took a 32-bit uint, so fileread passed a 64-bit
f->off into a 32-bit parameter and the top half was discarded.

The effect was not a refusal at 4 GB but silent wraparound past it. A
read at 5 GB returned the bytes at 1 GB, reporting success. disk.c had a
DISK_MAX_BYTES constant documenting the limit, and nothing anywhere
referenced it -- the cap was described but never enforced, which is the
worst of the three options.

The signature is now uint64 across all nine files that carry it, and
diskread/diskwrite no longer narrow the block number on the way to
bread. Widening this is a prerequisite for NVMe and for any real disk:
namespaces start well above 4 GB and the failure mode reads valid data
from the wrong place.

Verified end to end rather than by inspection. A 6 GB sparse image with
"PAST4GB-MARKER-OK" written at byte 5368709120, attached as /dev/hdb to a
ramdisk-root kernel so device 1 was free:

  # dd if=/dev/hdb bs=4096 skip=1310720 count=1 | od -c | head -2
  0000000   P   A   S   T   4   G   B   -   M   A   R   K   E   R   -   O

Under the old code that offset truncates to 1 GB, where the image is
zeroes. The whole path is exercised: f->off, devsw, diskread, bread and
ide.c's LBA48.

Worth recording for next time: `make ramroot` stages the ESP itself, and
running `make esp` afterwards rebuilds the kernel without RAMROOT and
silently undoes it. The tell is a 855 KB kernel where a 25 MB one is
expected.

110 [ok], no failures, on the default build.
2026-08-11 12:15:38 +02:00
Nexoniarz
8b7b8df74f usb-hid: bind an absolute pointer, and plumb EV_ABS through
Groundwork for usb-tablet, which is the fix for the guest cursor and the
host's never being in the same place: a PS/2 mouse reports how far it
moved, two pointers accumulating deltas independently drift apart, and no
amount of care in the compositor can make them agree. An absolute device
reports where it is, so they coincide by construction.

  - the HID driver no longer matches the boot subclass only. usb-tablet
    declares subclass 0 and was refused at the door; hid_probe decides
    what an interface actually is, and still declines what it cannot make
    sense of.
  - a non-boot HID interface is taken to be an absolute pointer and is
    not asked for boot protocol, which it does not have -- that request
    failing is what stopped it binding.
  - tablet_report decodes the fixed 6-byte layout (buttons, 16-bit X,
    16-bit Y, wheel) and scales the logical range to pixels there,
    because it is the only place that knows the range.
  - input_mouse_abs reports EV_ABS/ABS_X/ABS_Y so a reader can tell an
    absolute position from a delta, and mouse_set_abs places the pointer
    rather than nudging it.
  - Schcom treats EV_ABS as authoritative and EV_REL as a nudge.

The device binds and identifies correctly: "usb-hid: tablet (absolute) on
slot 1, endpoint 0x81 every 4 ms".

It is NOT finished, and QEMU_INPUT is empty by default because of it. No
reports have yet been observed arriving on the tablet's interrupt
endpoint, so making it the default pointer would trade a cursor that
drifts for one that does not move at all. Opt in with

  make qemu QEMU_INPUT='-device qemu-xhci,id=xhci -device usb-tablet,bus=xhci.0'

Next step is to find out why nothing arrives: whether the first transfer
is queued but never completes, whether a completion needs re-arming for
this endpoint, or whether QEMU is not routing motion to the tablet at all
(`info mice`).

bootcheck 108 [ok], schcom-test passes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 18:27:01 +02:00
Nexoniarz
eafdddefbc mouse: clamp the pointer to the screen that exists, not to 800x600
kernel/dev/mouse.c held the pointer inside literal 800x600 bounds. That
was correct while 800x600 was the only mode the loader could set, which
it was until the resolution became a boot-time choice. At 1280x800 the
pointer simply stopped two thirds of the way across and would not go
further -- which reads as the cursor drifting away from the host's rather
than as a clamp.

vga.c grows vga_get_width/vga_get_height for it. The mode is chosen at
boot now, so nothing above the framebuffer may hardcode its size, and
these are the first two callers that needed to ask.

Verified that the system still builds and boots at 1280x800, and that
bootcheck is 108 [ok] and schcom-test passes. I did not manage to
photograph the pointer past the old limit in the time available -- there
is no reader for /dev/mouse in the image and the screendump attempt did
not resolve, so the fix rests on inspection rather than on a picture.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 05:46:12 +02:00
Nexoniarz
d0f7acf9eb Initial commit: Schunix as it stands before the SchOS rename
An x86-64 operating system built from xv6, now largely rewritten: SMP,
a copy-on-write root filesystem (SchFS), PCI/USB/virtio drivers, a TTF
rasteriser, and a Linux-numbered syscall ABI.

No history before this point -- the tree was never under version control.
This commit exists so the rename that follows has something to undo to.
2026-08-09 13:47:01 +02:00