Initial commit

This commit is contained in:
Val Packett 2022-10-12 18:15:32 +03:00
commit 671bf2fab8
36 changed files with 2092 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
_site/
# Local Netlify folder
.netlify

10
404.njk Normal file
View file

@ -0,0 +1,10 @@
---
layout: layouts/base.njk
url: /404.html
title: 404 Not Found
mainClass: bigerror
---
<h1>4 0 4</h1>
<h2>Page not found</h2>

52
_config.ts Normal file
View file

@ -0,0 +1,52 @@
import lume from "lume/mod.ts";
import date from "lume/plugins/date.ts";
import code_highlight from "lume/plugins/code_highlight.ts";
import { createSlugifier } from "lume/plugins/slugify_urls.ts";
import { encode } from "std/encoding/base64.ts";
import { basename } from "std/path/mod.ts";
import { default as anchor } from "npm:[email protected]";
import { default as ins } from "npm:[email protected]";
const site = lume({}, {
markdown: {
options: {
typographer: true,
},
keepDefaultPlugins: true,
plugins: [[anchor, {
permalink: anchor.permalink.headerLink({ safariReaderFix: true }),
slugify: createSlugifier(),
}], ins],
},
});
site.helper(
"asset",
async (name) =>
`/x/${name}?v=${
encode(
(await crypto.subtle.digest(
"SHA-256",
await Deno.readFile(site.root(`x/${name}`)),
)).slice(0, 8),
)
}`,
{ type: "tag", async: true },
);
site.filter(
"reading_time",
(content) => Math.ceil(content.trim().split(/\s+/).length / 250),
);
site.filter("take", (x, n) => x.slice(0, n));
site.filter("drop", (x, n) => x.slice(n, x.length));
site.filter("basename", basename);
site
.copy("x")
.copy([".jpg", ".png", ".webp", ".avif", ".jxl"])
.use(date())
.use(code_highlight());
export default site;

5
_data/site.yml Normal file
View file

@ -0,0 +1,5 @@
author: Val Packett
title: Home of Val Packett
feedTitle: Val Packett's Blog
pfp: /x/val.1.png
color: "#9B70FF"

12
_includes/blog.njk Normal file
View file

@ -0,0 +1,12 @@
{% macro preview(post) -%}
<li class="showcase-card h-entry">
<a href="{{ post.url }}" class="showcase-spread u-url u-uid">
<h3 class="p-name">{{ post.title }}</h3>
</a>
<p class="preview-meta">
<time datetime="{{ post.date | date }}" class="dt-published">{{ post.date | date('HUMAN_DATE') }}</time>
✦ {{ post.content | md | striptags | reading_time }} min read
</p>
<p class="p-summary">{{ post.desc }} ✦&nbsp;<a href="{{ post.url }}">read more&nbsp;→</a></p>
</li>
{%- endmacro %}

View file

@ -0,0 +1,50 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="{{ site.color }}">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: img.shields.io; script-src 'none'; object-src 'none'">
<title>{{ title }}{% if title %} - {% endif %}{{ site.title }}</title>
<link rel="stylesheet" href="{% asset "s.css" %}">
<link rel="shortcut icon" href="{{ site.pfp }}">
<link rel="canonical" href="{{ url }}">
<link rel="alternate feed" href="/feed.xml" type="application/atom+xml" title="{{ site.feedTitle }}">
<link rel="alternate feed" href="/feed.json" type="application/feed+json" title="{{ site.feedTitle }}">
</head>
<body>
<header id="𝖍𝖊𝖆𝖉𝖊𝖗">
<div>
<a href="/" rel="home" id="𝖍𝖔𝖒𝖊" {%- if url == "/" %} aria-current="page"{% endif %}>
<div>{{ site.title | lower }}</div>
&nbsp;
<div class="logo-wrap">
<img alt="" role="presentation" src="{{ site.pfp }}" width="48" height="48">
</div>
</a>
</div>
<nav>
&nbsp;&nbsp;
<a href="/blog/" {%- if url == "/blog/" %} aria-current="page"{% endif %}>blog</a>
✦
<a href="https://codeberg.org/valpackett">code</a>
</nav>
</header>
<main class="{{ mainClass }}">
{{ content | safe }}
</main>
<footer id="𝖋𝖔𝖔𝖙𝖊𝖗">
<p>
© 2022 Val Packett
✦ <a href="#">↑↑↑</a>
✦ <a href="/" {%- if url == "/" %} aria-current="page"{% endif %}>home</a>
✦ <a href="/blog/" {%- if url == "/blog/" %} aria-current="page"{% endif %}>blog</a>
✦ <a href="/colophon/" {%- if url == "/colophon/" %} aria-current="page"{% endif %}>colophon</a>
</p>
<p>
<a href="https://www.mozilla.org/en-US/firefox/new/" class="ᵇᵈᵍ ᶠˣ"><span>Get</span><span>Firefox</span></a>
<a href="https://nonbinary.wiki/wiki/Main_Page" class="ᵇᵈᵍ ⁿᵇ" aria-label="non-binary"></a>
</p>
</footer>
</body>
</html>

View file

@ -0,0 +1,18 @@
---
layout: layouts/base.njk
---
<article class="h-entry">
<h1 class="post-title p-name">{{ title }}</h1>
{%- if desc %}
<p class="post-subhead p-summary">{{ desc }}</p>
{%- endif %}
<p class="post-meta">
<time datetime="{{ date | date }}" class="dt-published">{{ date | date('HUMAN_DATE') }}</time>
✦ {{ content | striptags | reading_time }} min read
</p>
<div class="e-content post-content">
{{ content | safe }}
</div>
</article>

View file

@ -0,0 +1,8 @@
---
layout: layouts/base.njk
---
<article class="post-content">
<h1>{{ title }}</h1>
{{ content | safe }}
</article>

17
_includes/media.njk Normal file
View file

@ -0,0 +1,17 @@
{% macro picture(pic, inFeed=false) -%}
<figure class="lqip" style="--ratio:{{ pic.width }}/{{ pic.height }};
{%- if pic.color or pic.lqip -%}
background:
{%- endif -%}
{{- pic.color -}}
{%- if pic.lqip %} url({{ pic.lqip | safe }}){% endif -%}
">
<picture>
{%- for src in pic.sources %}
<source type="{{ src.type }}" srcset="{{ src.srcset }}">
{%- endfor %}
<img alt="{{ pic.alt }}" src="{{ pic.src }}" width="{{ pic.width }}" height="{{ pic.height }}"
class="u-photo" loading="lazy" decoding="async">
</picture>
</figure>
{%- endmacro %}

View file

@ -0,0 +1,317 @@
---
title: FreeBSD on the ThinkPad X240
desc: The beginning of my FreeBSD laptop adventure. 2016 was an awkward time for this but I have contributed to fixing that.
---
So, I bought a laptop to run FreeBSD.
I was going to get a [C720 Chromebook](http://blog.grem.de/pages/c720.html), but I got a good deal for an X240. Yeah, yeah, a laptop from the preinstalled-insecure-adware company, whatever. Anyway, it’s a ThinkPad, so it feels very solid, has an excellent keyboard and good free software support.
So, let’s get FreeBSD running!
## Installation
I’ve replaced the stock HDD with an SSD, compiled the [drm-i915-update-38](https://github.com/freebsd/freebsd-base-graphics/tree/drm-i915-update-38) branch of FreeBSD on a different machine, wrote the memstick image to an old USB flash drive, booted it and installed FreeBSD on the ThinkPad.
++**UPDATE**: that landed in head a long time ago, I think you can just pick up the latest release now.++
The first installation, with ZFS root + UFS `/boot`, did not work because the EFI loader couldn’t load `zfs.ko`. After reinstalling on UFS, the loader does load `zfs.ko`… Oh well.
++**UPDATE**: now ZFS root works out of the box.++
GRUB 2 is also an option (and _the_ option for using [sysutils/beadm](https://www.freshports.org/sysutils/beadm)), but [the recent “backspace 28 times to bypass boot passphrase” vulnerability](https://unix.stackexchange.com/questions/250028/grub2-security-vulnerability-pressing-backspace-28-times-what-are-my-risks-wh/250079) really discouraged me from installing it. Of course, [what are you even trying to protect with that passphrase](https://twitter.com/rootkovska/status/677780387804901377), but ugh, GNU code “quality”.
## Power management
The usual laptop settings for `/etc/rc.conf`:
```
powerd_enable="YES"
powerd_flags="-a hiadaptive -b adaptive -i 75 -r 85 -p 500"
performance_cx_lowest="Cmax"
economy_cx_lowest="Cmax"
```
++**UPDATE**: [powerd++](https://github.com/lonkamikaze/powerdxx) is a better powerd!++
And for `/boot/loader.conf`:
```
hw.pci.do_power_nodriver=3
drm.i915.enable_rc6=7
hw.snd.latency=7
hint.pcm.0.buffersize=65536
hint.pcm.1.buffersize=65536
hint.pcm.2.buffersize=65536
hw.snd.feeder_buffersize=65536
```
Battery life with the internal + big external battery: ~8 - 8.5 hours of mostly surfing the web with Firefox on Wi-Fi with 50% screen brightness. (Obviously, more hours without Firefox :D) I don’t know how some reviewers got 20 hours of Wi-Fi browsing on Windows. Linux users say it’s [6-7 hours](https://www.reddit.com/r/Ubuntu/comments/2oheiu/linux_os_suggestion_for_lenovo_x240/cmn7n0o) or [above 8 hours](http://www.splitbrain.org/blog/2014-03/08-lenovo_thinkpad_x240_xubuntu), so FreeBSD is not worse than Linux there. That’s good :-)
I couldn’t get suspend/resume to work. It does suspend but doesn’t resume (pressing the power button makes the fans spin, but the power button is still blinking).
But putting the X240 into sleep mode for short breaks is not really necessary. With the huge battery and the ultra-low-power processor, just leaving it running for 15-30 minutes won’t drain the battery much.
Oh, and the power consumption can be measured with Intel’s performance counters. Install [sysutils/intel-pcm](https://freshports.org/sysutils/intel-pcm/) and run:
```
$ sudo kldload cpuctl
$ sudo pcm.x
```
Power consumption of the CPU (and GPU, and everything else on the chip) when idle and running Xorg is around 3 Watt.
## Ethernet and Wi-Fi
Works. This laptop has Intel’s networking hardware, which is great news for free operating systems. Not that I like Intel (super evil Management Engine!!) but they do write open source drivers for Linux, and BSD developers port them to the BSDs.
The Intel PRO/1000 Ethernet card is supported by the `em` driver.
The Intel 7260 wireless card is supported by the `iwm` driver.
Only `802.11a/b/g` is supported in `iwm` for now (IIRC because the driver is imported from OpenBSD, and they’re still working on `802.11n` support).
## Bluetooth
Doesn’t work.
Apparently, it’s [this one](http://www.ubuntu.com/certification/catalog/component/usb/4103/8087%3A07dc/).
It’s not even connecting as a USB device:
```
usbd_req_re_enumerate: addr=1, set address failed! (USB_ERR_TIMEOUT, ignored)
usbd_setup_device_desc: getting device descriptor at addr 1 failed, USB_ERR_TIMEOUT
ugen0.2: <Unknown> at usbus0 (disconnected)
uhub_reattach_port: could not allocate new device
```
I never use Bluetooth on laptops, anyway.
## Graphics (Intel HD Graphics on Haswell!)
Works. <s>Well, there’s a reason I’m using the `drm-i915-update-38` branch ;-) This is not in a release yet — it’s not even in `-CURRENT`! — so I’m not expecting perfect quality.</s>
++**UPDATE**: this was merged a long time ago. There's a new `drm-next` in [the graphics team's fork](https://github.com/FreeBSDDesktop/freebsd-base-graphics) though, and it brings Skylake support, Wayland…++
But it works fine with correct settings.
Do not load `i915kms` in the boot loader!! The system won’t boot. Instead, use the `kld_list` setting in `/etc/rc.conf` to load the module later in the boot process.
When you load `i915kms`, it will repeat this error for less than a second:
```
error: [drm:pid51453:intel_sbi_read] *ERROR* timeout waiting for SBI to complete read transaction
error: [drm:pid51453:intel_sbi_write] *ERROR* timeout waiting for SBI to complete write transaction
```
That’s okay, it works anyway. Looks like [this is not even Haswell specific](https://github.com/freebsd/freebsd/commit/4ef184b756b083683d4bac92ab02330aa08c4427).
So, here’s the `xorg.conf` part:
```
Section "Device"
Option "AccelMethod" "sna"
Option "TripleBuffer" "true"
Option "HotPlug" "true"
Option "TearFree" "false"
Identifier "Card0"
Driver "intel"
BusID "PCI:0:2:0"
EndSection
```
++**UPDATE**: with `drm-next`, the `modesetting` driver with `glamor` acceleration works!++
Brightness adjustment works via ~~both~~ [graphics/intel-backlight](https://www.freshports.org/graphics/intel-backlight/) ~~and `acpi_video` (`sysctl hw.acpi.video.lcd0.brightness`)~~. ~~The brightness keys on the keyboard don’t work properly though. The fn key on F5 (lower brightness) just sets the brightness to maximum, F6 (raise brightness) does nothing. Here’s the error that’s shown when pressing the lower brightness key with `drm.debug=3` in `/boot/loader.conf`:~~
```
[drm:KMS:pid12:intel_panel_get_max_backlight] max backlight PWM = 852
[drm:KMS:pid12:intel_panel_actually_set_backlight] set backlight PWM = 841
[drm:pid12:intel_opregion_gse_intr] PWM freq is not supported
```
~~So I’ve configured F5 and F6 (the real function keys, FnLock mode) to call `intel_backlight`.~~
++**UPDATE**: `acpi_video` is the one incorrectly changing the brightness to max! Don't load it. `acpi_ibm` changes the brightness correctly!++
HDMI output works with a Mini DisplayPort adapter. 1080p video playback on an HDMI TV using `mpv` is smooth.
VAAPI video output and hardware accelerated decoding works. With `mpv --vo=vaapi --hwdec=vaapi`, CPU usage is around 20% for a 1080p H.264 video (vs. 60% with software decoding), the fans stay silent. You’ll need to install [multimedia/libva-intel-driver](https://www.freshports.org/multimedia/libva-intel-driver/) and [multimedia/mpv](https://www.freshports.org/multimedia/mpv) from pkg, and rebuild [multimedia/ffmpeg](https://www.freshports.org/multimedia/ffmpeg) with the VAAPI option.
~~OpenCL on the Haswell GPU (powered by Beignet) doesn’t work yet. `clinfo` shows:~~
```
Beignet: self-test failed: (3, 7, 5) + (5, 7, 3) returned (3, 7, 5)
```
++**UPDATE**: OpenCL was fixed a long time ago.++
## Audio
Works. The built-in Realtek ALC292 sound card just works. FreeBSD’s audio support is good.
The internal microphone is recognized as a separate device:
```
$ cat /dev/sndstat
Installed devices:
pcm0: <Intel Haswell (HDMI/DP 8ch)> (play)
pcm1: <Realtek ALC292 (Analog 2.0+HP/2.0)> (play/rec) default
pcm2: <Realtek ALC292 (Internal Analog Mic)> (rec)
```
HDMI audio works too (`sysctl hw.snd.default_unit` to switch the sound card; applications that play sound have to be restarted.)
## Webcam
Works. With `webcamd`, of course. But I don’t need it, so I’ve disabled it in the BIOS Setup.
## SD card reader
Doesn’t work.
`pciconf` detects it as:
```
none2@pci0:2:0:0: class=0xff0000 card=0x221417aa chip=0x522710ec rev=0x01 hdr=0x00
vendor = 'Realtek Semiconductor Co., Ltd.'
device = 'RTS5227 PCI Express Card Reader'
```
It’s supported in OpenBSD with [rtsx(4)](http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man4/rtsx.4?query=rtsx&sec=4). FreeBSD bugs for this: [161719](https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=161719), [204521](https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=204521).
It should be possible to use it with OpenBSD/NetBSD/Linux in a bhyve VM with PCI passthrough, like [the Wi-Fi card before iwm was added](http://0xfeedface.org/2014/12/11/FreeBSD-Intel-wifi-via-bhyve.html). That would also be more secure (that’s what [Qubes](https://www.qubes-os.org) does for all the hardware.) But I don’t need to use SD cards on this laptop.
## Trackpad and TrackPoint
~~Oh, this is the most interesting part. Well, it works, sure. But there are at least three ways of using them, none of which is perfect.~~
++**UPDATE**: [evdev synaptics landed in current](https://github.com/freebsd/freebsd/commit/bc8448b7c73bbbcaf15b375eb9648e963bcc8334)!++
### moused
FreeBSD includes `moused`, a little daemon that watches the mouse device you tell it to watch and forwards all events to a virtualized mouse, which is accessible to Xorg at `/dev/sysmouse` and also works on the text console. It has advanced support (like sensitivity settings) for Synaptics touchpads and ThinkPad TrackPoints (set `hw.psm.synaptics_support=1` and `hw.psm.trackpoint_support=1` in `/boot/loader.conf` to enable).
Sadly, it forwards all events to a virtualized _mouse_. Not a trackpad, just a mouse, so the experience is not as good.
`xorg.conf`:
```
Section "InputDevice"
Identifier "SysMouse"
Driver "mouse"
Option "Device" "/dev/sysmouse"
EndSection
```
### xf86-input-synaptics
This is the Synaptics driver that provides a great trackpad experience. Inertial scrolling, horizontal scrolling, natural scrolling, perfectly smooth cursor movement… Everything is as good as in OS X on a MacBook.
~~But the TrackPoint doesn’t work. On the X240, it’s attached to the trackpad as a guest mouse. The trackpad forwards the TrackPoint’s PS/2 events with a special mark (IIRC, it’s W = 3).~~
And the Synaptics driver [stopped supporting guest devices in 2010](http://cgit.freedesktop.org/xorg/driver/xf86-input-synaptics/commit/?id=b19e3782a77c171ca20fc962f95923495fdb7978).
++**UPDATE**: [added the guest mouse support back to xf86-input-synaptics](https://github.com/myfreeweb/xf86-input-synaptics)! Also adds ClickPad support to the raw PS/2 protocol used by the driver on the BSDs (on Linux, it uses evdev, and they only added clickpad support there).++
~~Also, clicking doesn’t work, but I don’t care. I’m used to tapping.~~
`xorg.conf`:
```
Section "InputDevice"
Identifier "Touchpad"
Driver "synaptics"
Option "Protocol" "psm"
Option "Device" "/dev/psm0"
Option "VertEdgeScroll" "off"
Option "VertTwoFingerScroll" "on"
Option "HorizEdgeScroll" "off"
Option "HorizTwoFingerScroll" "on"
Option "VertScrollDelta" "-111"
Option "HorizScrollDelta" "-111"
Option "ClickPad" "on"
Option "SoftButtonAreas" "4201 0 0 1950 2710 4200 0 1950"
Option "AreaTopEdge" "5%"
EndSection
```
### evdevfbsd
I accidentally found [evdevfbsd](https://github.com/jiixyj/evdevfbsd), a little program that exposes PS/2 devices as `evdev` devices via CUSE (**C**haracter Device in **Use**rspace).
`evdev` is a protocol that comes from Linux. It allows kernel (or CUSE) drivers to provide a standardized interface for devices so that Xorg wouldn’t care about any particular vendor.
`evdevfbsd` correctly separates the trackpad and the TrackPoint. Cursor movement works. But only cursor movement. No touch scrolling, no tapping, no clicking. And it looks like it might be `xf86-input-evdev`’s fault, because [evtest.py](https://github.com/gvalkov/python-evdev/blob/master/bin/evtest.py) shows tap events when tapping!
### ~~Something else?~~
~~I’ve tried to write a CUSE program that works as a proxy between `/dev/psm0` and the Synaptics driver, extracting guest (TrackPoint) events in the process.~~
~~It almost works… the only problem is that the Synaptics driver locks the whole X server while reading from my proxy, so only mouse movement works and nothing else, not even Ctrl+Alt+F1 to switch to a console. Well, the power button works. And SSHing into the laptop.~~
~~Seems like the problem with CUSE is that there’s no way to find out, in the `poll` method, that the process that polls your device wants to stop. So, when `moused` reads from the proxy, it works, but when you stop `moused` with Ctrl-C, it doesn’t stop until you touch the TrackPoint or the trackpad a little to send an event.~~
++**UPDATE**: [added the guest mouse support back to xf86-input-synaptics](https://github.com/myfreeweb/xf86-input-synaptics)!++
## Touchscreen
Works. It’s recognized as a USB HID device at `/dev/uhid0`. There are two ways to use it in Xorg.
### Mouse emulation
The simple way: you can use it with the `mouse` driver, as a regular mouse. Obviously, this does not provide multi-touch.
`xorg.conf`:
```
Section "InputDevice"
Identifier "Touchscreen"
Driver "mouse"
Option "Protocol" "usb"
Option "Device" "/dev/uhid0"
EndSection
```
### Multi-touch
The other way: you can use it with `webcamd` and the `evdev` driver. This will actually support multi-touch.
Recompile [x11-drivers/xf86-input-evdev](https://freshports.org/x11-drivers/xf86-input-evdev) from ports with the `MULTITOUCH` option, start `webcamd` like this (note that CUSE is part of the base system on `11-CURRENT`, so it’s not called `cuse4bsd` anymore):
```
$ sudo make -C /usr/ports/x11-drivers/xf86-input-evdev config deinstall install clean
$ sudo kldload cuse
$ sudo webcamd -d ugen1.3 -N Touchscreen-ELAN -M 0
```
`xorg.conf`:
```
Section "InputDevice"
Identifier "Touchscreen"
Driver "evdev"
Option "Device" "/dev/input/event0"
EndSection
```
Start `chrome --touch-events` and visit the [touch event test](http://www.snappymaria.com/canvas/TouchEventTest.html)! Also, you can scroll in GTK+ 3 applications like [Corebird](http://corebird.baedert.org/).
Unfortunately, it’s really bad at detecting when a touch _ends_. This means that scrolling and tapping [will get stuck](https://www.youtube.com/watch?v=nMR1o5cc2nc). So I’m using the `mouse` driver for now.
**UPDATE:** the new `wmt(4)` kernel driver supports the touchscreen perfectly, without that issue!! Also, `libinput` is better than `evdev` in Xorg.
## TPM (Trusted Platform Module)
Works. (With the dedicated TPM 1.2 module. Haven’t tried Intel’s built-in TPM 2.0 support. The choice between them is in the BIOS/UEFI settings.)
OpenSSH works with a TPM key through [simple-tpm-pk11](https://github.com/ThomasHabets/simple-tpm-pk11).
**UPDATE:** turns out the TPM was preventing the laptop from waking up from suspend! (And I did unload the tpm module before suspend.) Disabled it in firmware settings.
## Conclusion
It’s possible to use a Haswell ThinkPad with FreeBSD right now :-) Everything except Bluetooth, SD cards and ~~waking up from sleep~~ works.
OpenBSD would be better though. They have excellent ThinkPad support, because OpenBSD developers use OpenBSD on ThinkPads. But I’m working on software that uses FreeBSD jails, and I just prefer FreeBSD.

View file

@ -0,0 +1,79 @@
---
title: Moving VMs from VirtualBox to Client Hyper-V
desc: The year of Windows on the desktop? Taking Microsoft's hypervisor for a spin by setting up a modern FreeBSD VM.
---
{% import "media.njk" as media %}
I've decided to move the VMs on my desktop from VirtualBox to Microsoft Hyper-V.
Because reasons.
Actually because I've upgraded my desktop to an AMD Ryzen CPU: first, AMD-V/SVM is not supported by the *Intel* HAXM thing from the Android SDK, so I wanted to try out Microsoft's Hyper-V based Android "emulator" (VM configurator/runner thingy) instead.
Second, giving 16 virtual CPUs on an SMT 8-core to a FreeBSD guest in VirtualBox results in a weird performance issue.
(Though giving 4 vCPUs to *multiple* VMs on a 4-core CPU worked fine.)
Third, it's *Oracle* VM VirtualBox and no one likes Oracle.
{{ media.picture({
height: 1361,
width: 1981,
alt: "Screenshot",
color: "rgb(230,232,233)",
lqip: "data:image/webp;base64,UklGRmIAAABXRUJQVlA4IFYAAABQBQCdASowACAAP+Hq6Gy/vLAptVv4A/A8CWUAAFvoq1QAz3i1Z8XiXfRZhGz5R7FJeYAA/lHT2bCUVBNGZjAIYCm9raJANh9WUjtiCqakB89wXAwAAA==",
src: "scr.png"
}, inFeed) }}
So, here's how you can do it as well.
## How to get Hyper-V
You need Windows 10 Pro, Enterprise or Education.
(Or Windows Server, obviously.)
Just enable it as a feature and restart.
Alternatively, installing the [MS Android "emulator"](https://www.visualstudio.com/vs/msft-android-emulator/) automatically enables it.
## How to migrate a VM (FreeBSD, Linux or Windows with EFI)
(NOTE: older versions of FreeBSD apparently had some loader issue that prevented EFI boot in Hyper-V. Everything works for me on a recent build of 11-STABLE.)
In VirtualBox, go to the Virtual Media Manager (Ctrl+D) and copy your disk as `VHD`.
In the Hyper-V Manager, use the Edit Disk dialog to convert the `VHD` to `VHDX`.
If you haven't done that yet, go to the Virtual Switch Manager and make a virtual switch ("External" is like bridge mode in VBox).
Now make a virtual machine.
Generation 2, no dynamic memory (FreeBSD doesn't support that), select the virtual switch and the VHDX disk.
Click Connect and it should just work.
By the way, it's nice that you can always close the console window without powering off the VM, unlike in VirtualBox where you need a special "Detachable start".
Interestingly, if you create the VM without a disk and attach the disk later, you won't see "boot from hard drive" in the firmware / boot order settings.
And there's no add button! (WTF?)
The fix is to use PowerShell:
```powershell
$vm = Get-VM "YOUR VM NAME"
Set-VMFirmware $vm -FirstBootDevice (Get-VMHardDiskDrive $vm)
```
Speaking of which, it's nice to have a directly integrated PowerShell interface to all the things.
My little [xvmmgr](https://github.com/myfreeweb/xvmmgr) script was initially written for VirtualBox, and that required *COM*.
## How to migrate a VM (other OS)
Well, a similar process, but use Generation 1.
## My experience so far
Client Hyper-V has pleasantly surprised me.
It's a very smooth experience: it *looks* like a Type 2 hypervisor even though it's actually Type 1, it runs VMs without any performance issues… what else could you ask for?
Well, the downside is its lack of flexibility in terms of paravirtualized (MS calls them "synthetic" or something) vs emulated devices.
All you get is the choice between two generations.
Generation 1 means legacy BIOS boot from an emulated *IDE* drive with emulated all the things plus optionally some paravirtualized devices like the NIC.
Generation 2 means EFI boot from a SCSI drive with paravirtualized *everything*.
Oh and the SCSI controller is also on the `vmbus`.
So there's no way to use EFI and SCSI with e.g. OpenBSD, you need full Hyper-V support for at least the disk and network to do that.
Thankfully Microsoft contributed that support to FreeBSD! :)

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

View file

@ -0,0 +1,424 @@
---
title: FreeBSD and custom firmware on the Google Pixelbook
desc: A search for a new thin-and-light laptop, a journey through the Chromebook firmware trust architecture, some FreeBSD kernel development, and finally, something about actually customizing open source firmware.
---
[Back in 2015](/blog/thinkpad-x240/), I jumped on the ThinkPad bandwagon by getting an X240 to run FreeBSD on.
Unlike most people in the ThinkPad crowd, I actually liked the clickpad and didn't use the trackpoint much.
But this summer I've decided that it was time for something newer.
I wanted something..
- lighter and thinner (ha, turns out this is actually important, I got tired of carrying a T H I C C laptop - Apple was right all along);
- with a 3:2 display (why is Lenovo making these Serious Workâ„¢ laptops 16:9 in the first place??
16:9 is **awful** in below-13-inch sizes especially);
- with a HiDPI display (and ideally with a good size for exact 2x scaling instead of fractional);
- with USB-C ports;
- without a dGPU, *especially* without an NVIDIA GPU;
- assembled with screws and not glue (I don't necessarily need expansion and stuff in a laptop all that much,
but being able to replace the battery without dealing with a glued chassis is good);
- supported by FreeBSD of course ("some development required" is okay but I'm not going to write *big* drivers);
- how about something with open source firmware, that would be fun.
The [Qualcomm aarch64 laptops](https://github.com/aarch64-laptops) were out because embedded GPU drivers like freedreno
(and UFS storage drivers, and Qualcomm Wi-Fi..) are not ported to FreeBSD.
And because Qualcomm firmware is very cursed.
[Samsung's RK3399 Chromebook](https://rosenzweig.io/blog/panfrost-on-the-rk3399-meow.html)
or the new [Pinebook Pro](https://www.pine64.org/pinebook-pro/) would've been awesome.. if I were a Linux user.
No embedded GPU drivers on FreeBSD, again. No one has added the stuff needed for FDT/OFW attachment to LinuxKPI.
It's rather tedious work, so we only support PCIe right now.
(Can someone please make an ARM laptop with a PCIe GPU, say with an [MXM slot](https://en.wikipedia.org/wiki/Mobile_PCI_Express_Module)?)
So it's still gonna be amd64 (x86) then.
I really liked the design of the Microsoft Surface Book, but the
[iFixit score of 1 (one)](https://www.ifixit.com/Teardown/Microsoft+Surface+Book+Teardown/51972#s113615)
and especially the Marvell Wi-Fi chip that doesn't have a driver in FreeBSD are dealbreakers.
I was considering a ThinkPad X1 Carbon from an old generation - the one from the same year as the X230 is corebootable, so that's fun.
But going *back* in processor generations just doesn't feel great.
I want something more efficient, not less!
And then I discovered the [Pixelbook](https://en.wikipedia.org/wiki/Google_Pixelbook).
Other than the big huge large bezels around the screen, I liked everything about it.
Thin aluminum design, a 3:2 HiDPI screen, **rubber palm rests** (why isn't every laptop ever doing that?!),
the "convertibleness" (flip the screen around to turn it into.. something rather big for a tablet, but it is useful actually),
a Wacom touchscreen that supports a pen, mostly reasonable hardware (Intel Wi-Fi),
and that famous coreboot support (Chromebooks' stock firmware *is* coreboot + depthcharge).
So here it is, my new laptop, a Google Pixelbook.
## What is a Chromebook, even
The write protect screw is kind of a meme.
All these years later, it's That Thing everyone on various developer forums associates with Chromebooks.
But times have moved on.
As a reaction to glued devices and stuff, the Chrome firmware team has discovered a new innovative way of asserting
physical presence: sitting around for a few minutes, pressing the power button when asked.
Is actually pretty clever though, it *is* more secure than.. not doing that.
Wait, what was that about?
Let's go back to the beginning and look at firmware security in Chromebooks and other laptops.
These devices are designed for the mass market first.
Your average consumer trusts the vendor and (because they've read a lot of scary news) might be afraid of scary attackers
out to install a stealthy rootkit right into their firmware.
Businesses are even more afraid of that, and they push for boot security on company laptops even more.
This is why [Intel Boot Guard](https://github.com/corna/me_cleaner/wiki/Intel-Boot-Guard) is a thing
that the vast majority of laptops have these days.
It's a thing that makes sure only the vendor can update firmware.
Evil rootkits are out. Unfortunately, the user is also out.
Google is not like most laptop vendors.
Yes, Google is kind of a surveillance capitalism / advertising monster, but that's not what I'm talking about here.
Large parts of Google are very much driven by FOSS enthusiasts.
Or something. Anyway, the point is that Chromebooks are based on FOSS firmware and support
user control as much as possible.
(Without compromising regular-user security, but turns out these are not conflicting goals and we can all be happy.)
Instead of Boot Guard, Google has its own way of securing the boot process.
The root of trust in modern (>=2017) devices is a special
[Google Security Chip](https://www.youtube.com/watch?v=gC-lbMNmIsg), which in normal circumstances
also ensures that only Google firmware runs on the machine, but:
- if you sit through the aforementioned power-button-clicking procedure,
you get into Developer Mode: OS verification is off, you have a warning screen at boot,
and you can press Ctrl-D to boot into Chrome OS, or (if you enabled this via a command run as root)
Ctrl-L to open SeaBIOS.
- Here's the fun part.. it doesn't have to be SeaBIOS.
You can flash any Coreboot payload into the `RW_LEGACY` slot right from Chrome OS, reboot, press a key
and you're booting that payload!
- if you also [buy](https://www.sparkfun.com/products/14746) or
[solder](https://chromium.googlesource.com/chromiumos/third_party/hdctools/+/master/docs/ccd.md#making-your-own-suzyq)
a special cable ("SuzyQable") and do the procedure a couple times more, your laptop turns into the
Ultimate Open Intel Firmware Development Machine. Seriously.
- the security chip is a debug chip too!
[Case Closed Debugging](https://chromium.googlesource.com/chromiumos/platform/ec/+/master/docs/case_closed_debugging_cr50.md)
gives you serial consoles for the security chip itself, the embedded controller (EC) and the application processor (AP, i.e. your main CPU),
and it also gives you a flasher
(via [special flashrom](https://aur.archlinux.org/packages/flashrom-chromeos/) for now, but I'm told there's plans to upstream)
that allows you to write AP and EC firmware;
- some security is still preserved with all the debugging: you can (and should) set a CCD password, which lets you
lock-unlock the debug capabilities and change write-protect whenever you want, so that only you can flash firmware
(at least without opening the case and doing **very** invasive things, the flash chip is not even SOIC anymore I think);
- and you can hack without fear: the security chip is not brickable! Yes, yes, that means the chip is only a
"look but don't touch" kind of open source, it will only boot Google-signed firmware.
Some especially paranoid people think this is An NSA Backdoorâ„¢.
I think this is an awesome way to allow FULL control of the main processor and the EC,
over just a cable, with **no way of bricking the device**!
And to solve the paranoia, [reproducible builds](https://reproducible-builds.org/) would be great.
## You mentioned something about FreeBSD in the title?
Okay, okay, let's go.
I didn't even *want* to write an introduction to Chromebooks but here we are.
Anyway, while waiting for the debug cable to arrive, I've done a lot of work on FreeBSD,
using the first method above (`RW_LEGACY`).
SeaBIOS does not have display output working in OSes that don't specifically support the Coreboot framebuffer
(OpenBSD does, FreeBSD doesn't), and I really just hate legacy BIOS, so
I've had to install a UEFI implementation into `RW_LEGACY` since I didn't have the cable yet.
My own EDK2 build did not work (now I see that it's probably because it was a debug build and that has failing assertions).
So I've downloaded [MrChromebox's full ROM image](https://mrchromebox.tech), extracted the payload using `cbfstool`
and flashed that. Boom. Here we go, press Ctrl-L for UEFI. Nice. Let's install FreeBSD.
The live USB booted fine. With the EFI framebuffer, an NVMe SSD and a PS/2 keyboard it was a working basic system.
I've resized the Chrome OS data partition (Chrome OS recovers from that fine, without touching custom partitions),
found that there's already an EFI system partition (with a GRUB2 setup to boot Chrome OS, which didn't boot like that o_0),
installed everything and went on with configuration and developing support for more hardware.
(note: I'm leaving out the desktop configuration part here, it's mostly a development post; I use [Wayfire](https://github.com/WayfireWM/wayfire) as my display server if you're curious.)
So how's the hardware?
### Wi-Fi and Bluetooth
Well, that was easy.
The Pixelbook has an Intel 7265.
The exact same wireless chip that was in my ThinkPad.
So, Wi-Fi works great with `iwm`.
Bluetooth.. if this was the newer 8265, would've already just worked :D
These Intel devices present a "normal" `ubt` USB Bluetooth adapter, except it only becomes normal if you upload firmware
into it, otherwise it's kinda dead.
(And in that dead state, it spews interrupts, raising the idle power consumption by preventing the system
from going into package C7 state! So `usbconfig -d 0.3 power_off` that stuff.)
FreeBSD now has a firmware uploader for the 8260/8265, but it does not support the older protocol used by the 7260/7265.
It wouldn't be that hard to add that, but no one has done it yet.
### Input devices
#### Keyboard
Google kept the keyboard as good old PS/2, which is great for ensuring that you can get started with a custom OS
with a for-sure working keyboard.
About the only interesting thing with the keyboard was the Google Assistant key, where the Win key usually is.
It was not recognized as anything at all.
I used DTrace to detect the scancode without adding prints into the kernel and rebooting:
```
dtrace -n 'fbt::*scancode2key:entry { printf("[st %x] %x?\n", *(int*)arg0, arg1); } \
fbt::*scancode2key:return { printf("%x\n", arg1); }'
```
And wrote [a patch](https://reviews.freebsd.org/D21565) to interpret it as a useful key
(right meta, couldn't think of anything better).
#### Touch*
The touchpad and touchscreen are HID-over-I²C, like on many other modern laptops.
I don't know why this cursed bus from the 80s is *gaining* popularity, but it is.
At least FreeBSD has a driver for Intel (Synopsys DesignWare really) I²C controllers.
(Meanwhile Apple MacBooks now use [*SPI for even the keyboard*](https://github.com/roadrunner2/macbook12-spi-driver).
FreeBSD has an Intel SPI driver but right now it only supports ACPI attachment for Atoms and such, not PCIe yet.)
The even better news is that [there is a nice HID-over-I²C driver in development as well](https://github.com/wulf7/iichid).
(note: the [corresponding patch for configuring the devices via ACPI](https://people.freebsd.org/~wulf/acpi_iicbus.patch)
is pretty much a requirement, uncomment `-DHAVE_ACPI_IICBUS` in the iichid makefile too to get that to work.
Also, [upcoming Intel I²C improvement patch](https://bugs.freebsd.org/bugzilla/attachment.cgi?id=207356&action=diff).)
The touchscreen started working with that driver instantly.
The touchpad was.. a lot more "fun".
The I²C bus it was on would just appear dead.
After some [debugging](https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=240339), it turned out that the in-progress
iichid driver was sending a wrong extra out-of-spec command, which was causing Google's touchpad firmware
to throw up and lock up the whole bus.
But hey, nice bug discovery, if any other device turns out to be as strict in accepting input, no one else would have that problem.
Another touchpad thing: by default, you have to touch it with a lot of pressure.
Easily fixed in libinput:
```
% cat /usr/local/etc/libinput/local-overrides.quirks
[Eve touchpad]
MatchUdevType=touchpad
AttrPressureRange=12:6
```
#### **UPD 2019-10-24** Pixelbook Pen
The touchscreen in the Pixelbook is made by Wacom, and supports stylus input like the usual Wacom tablets.
For USB ones, on FreeBSD you can just use `webcamd` to run the Linux driver in userspace.
Can't exactly do that with I²C.
But! [Thankfully, it exposes generic HID stylus reports](/notes/2019-10-21-20-12-26), zero Wacom specifics required.
I've been able to [write a driver](https://github.com/wulf7/iichid/pull/5) for that quite easily.
Now it works. With pressure, tilt, the button, all the things :)
### Display backlight brightness
This was another "fun" debugging experience.
The `intel_backlight` console utility (which was still the thing to use on FreeBSD) did nothing.
I knew that the i915 driver on Chrome OS could adjust the brightness, so I made it work here too, and all it took is:
- [adding more things to LinuxKPI](https://reviews.freebsd.org/D21564) to allow uncommenting the
brightness controls in i915kms;
- (and naturally, uncommenting them);
- finding out that this panel uses native DisplayPort brightness configured via DPCD (DisplayPort Configuration Data),
enabling `compat.linuxkpi.i915_enable_dpcd_backlight="1"` in `/boot/loader.conf`;
- finding out that there's a fun bug in the.. hardware, sort of:
- the panel reports that it supports both DPCD backlight and a direct PWM line (which is true);
- Google/Quanta/whoever *did not connect* the PWM line;
- (the panel is not aware of that);
- the i915 driver prefers the PWM line when it's reported as available.
Turns out there was [a patch sent to Linux to add a "prefer DPCD" toggle](https://patchwork.kernel.org/patch/9640237/),
but for some reason it was not merged.
The patch does not apply cleanly so I just did a simpler hack version:
```diff
--- i/drivers/gpu/drm/i915/intel_dp_aux_backlight.c
+++ w/drivers/gpu/drm/i915/intel_dp_aux_backlight.c
@@ -252,8 +252,12 @@ intel_dp_aux_display_control_capable(struct intel_connector *connector)
* the panel can support backlight control over the aux channel
*/
if (intel_dp->edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP &&
- (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP) &&
- !(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP)) {
+ (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP)
+/* for Pixelbook (eve), simpler version of https://patchwork.kernel.org/patch/9618065/ */
+#if 0
+ && !(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP)
+#endif
+ ) {
DRM_DEBUG_KMS("AUX Backlight Control Supported!\n");
return true;
}
```
And with that, it works, with 65536 steps of brightness adjustment even.
### Suspend/resume
The Pixelbook uses regular old ACPI S3 sleep, not the [fancy new S0ix thing](https://reviews.freebsd.org/D17676),
so that's good.
On every machine with a [TPM](https://en.wikipedia.org/wiki/Trusted_Platform_Module) though,
you have to tell the TPM to save state before suspending, otherwise you get a reset on resume.
I already knew this because I've [experienced that on the ThinkPad](/notes/2017-11-22-15-11-44).
The Google Security Chip runs an open-source TPM 2.0 implementation (fun fact, written by Microsoft)
and it's connected via… \*drum roll\* I²C. Big surprise (not).
FreeBSD already has TPM 2.0 support in the kernel, the
[userspace tool stack](https://github.com/tpm2-software/tpm2-tools) was recently added to Ports as well.
But of course there was no support for connecting to the TPM over I²C, and especially not to the
Cr50 (GSC) TPM specifically. (it has quirks!)
I [wrote a driver (WIP)](https://github.com/myfreeweb/freebsd/commit/600e6006c1b969b73d3fec86208f37011884f1e1)
hooking up the I²C transport (relies on the aforementioned ACPI-discovery-of-I²C patch).
It does not use the interrupt (I found it buggy: at first attachment, it fires continuously,
and after a reattach it stops completely) and after attach (or after system resume) the *first* command
errors out, but that can be fixed and other than that, it works.
Resume is fixed, entropy can be harvested, it [could be used for SSH keys](https://github.com/tpm2-software/tpm2-pkcs11) too.
Another thing with resume: I've had to build the kernel with `nodevice sdhci` to prevent the
Intel SD/MMC controller (which is not attached to anything here - I've heard that the 128GB model might be using eMMC
instead of NVMe but that's unclear) from [hanging for a couple minutes on resume](https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=211705).
### Dynamic CPU frequency
At least on the stock firmware, the old-school Intel SpeedStep did not work because the driver could not
find some required ACPI nodes (perf or something).
Forget that, the new [Intel Speed Shift](https://reviews.freebsd.org/D18028) (which lets the CPU adjust frequency on its own) works nicely with the linked patch.
### Tablet mode switch
When the lid is flipped around, the keyboard is disabled (unless you turn the display brightness to zero,
I've heard - which is fun because that means you can [connect a montior and have a sort-of
computer-in-a-keyboard look](https://www.reddit.com/r/PixelBook/comments/dalk1l/my_pixelbook_desktop_setup/f1u4nwi/),
like retro computers) and the system gets a notification (Chrome OS reacts to that by enabling tablet mode).
Looking at the DSDT table in ACPI, it was quite obvious how to support that notification:
```
Device (TBMC) {
Name (_HID, "GOOG0006") // _HID: Hardware ID
Name (_UID, One) // _UID: Unique ID
Name (_DDN, "Tablet Motion Control") // _DDN: DOS Device Name
Method (TBMC, 0, NotSerialized) {
If ((RCTM () == One)) { Return (One) }
Else { Return (Zero) }
}
}
```
On Linux, this is exposed as an evdev device with switch events.
I was able to [replicate that](https://reviews.freebsd.org/D21612) quite easily.
My display server does not support doing anything with that yet, but I'd like to do something like
enabling [an on-screen keyboard](https://source.puri.sm/Librem5/squeekboard) to pop up automatically
when tablet mode is active.
### Keyboard backlight brightness
I generally leave it off because I don't look at the keyboard, but this was
[a fun and easy driver to write](https://reviews.freebsd.org/D21746).
Also obvious how it works when looking at ACPI:
```
Device (KBLT) {
Name (_HID, "GOOG0002") // _HID: Hardware ID
Name (_UID, One) // _UID: Unique ID
Method (KBQC, 0, NotSerialized) {
Return (^^PCI0.LPCB.EC0.KBLV) /* \_SB_.PCI0.LPCB.EC0_.KBLV */
}
Method (KBCM, 1, NotSerialized) {
^^PCI0.LPCB.EC0.KBLV = Arg0
}
}
```
### Using the debug cable **on** FreeBSD
The debug cable presents serial consoles as bulk endpoints without any configuration capabilities.
On Linux, they are supported by [the "simple" USB serial driver](https://github.com/torvalds/linux/blob/ba606975938179b1e893e44e190d0001de8e5262/drivers/usb/serial/usb-serial-simple.c).
Adding the device to the "simple" FreeBSD driver `ugensa` [took some debugging](https://reviews.freebsd.org/D21863).
The driver was clearing USB stalls when the port is opened.
That's allowed by the USB spec and quite necessary on some devices.
Unfortunately, the debug interface throws up when it sees that request.
The responsible code in the device [has a `/* Something we need to add support for? */` comment](https://chromium.googlesource.com/chromiumos/platform/ec/+/refs/tags/cr50_v4.5/chip/g/usb.c#835) :D
### Audio?
The only thing that's unsupported is onboard audio.
The usual HDA controller only exposes the DisplayPort audio-through-the-monitor thing.
The speakers, mic and headphone jack are all connected to various codecs exposed via… yet again, I²C.
I am not about to write the drivers for these codecs, since I'm not really interested in audio on laptops.
## Firmware is Fun
After the debug cable arrived, I've spent some time debugging the console-on-FreeBSD thing mentioned above,
and then started messing with coreboot and TianoCore EDK2.
My discoveries so far:
- there's nothing on the AP console on stock firmware because Google compiles release FW with serial output off,
I think to save on power or something;
- `me_cleaner` [needs to be run with `-S -w MFS`](https://github.com/corna/me_cleaner/issues/300).
As mentioned in the `--help`, the `MFS` partition contains PCIe related stuff.
Removing it causes the NVMe drive to detach soon after boot;
- upstream Coreboot (including MrChromebox's builds) fails to initialize the TPM, just gets zero
in response to the vendor ID request. Funnily enough, that would've solved the resume problem
without me having to write the I²C TPM driver for FreeBSD - but now that I've written it, I'd prefer
to actually have the ability to use the TPM;
- EDK2's recent `UefiPayloadPkg` doesn't support [PS/2 keyboard](https://bugzilla.tianocore.org/show_bug.cgi?id=2241)
and [NVMe](https://bugzilla.tianocore.org/show_bug.cgi?id=2240) out of the box, but they're very easy to add
(hopefully someone would add them upstream after seeing my bug reports);
- `UefiPayloadPkg` supports getting the framebuffer from coreboot very well;
- coreboot can run Intel's GOP driver before the payload (it's funny that we're running a UEFI module before
running the UEFI implementation) and that works well;
- but `libgfxinit` - the nice FOSS, written-in-Ada, verified-with-SPARK implementation of Intel GPU
initialization and framebuffer configuration - supports Kaby Lake now!
- however, we have a DPCD thing again with this display panel here - it reports
max lane bandwidth as `0x00`, `libgfxinit` interprets that as the slowest speed and
we end up not having enough bandwidth for the high-res screen;
- I've been told that this is because there's a new way of conveying this information that's unsupported. I'll dig
around in the Linux i915 code and try to implement it properly here but for now, I just did a quick hack,
hardcoding the faster bandwidth. Ta-da! My display is initialized with formally verified open source code!
Minus one blob running at boot!
- persistent storage of EFI variables needs some SMM magic. There's
[a quick patch](https://github.com/MrChromebox/edk2/commit/c792dbf1bd692bb95781a79d5d2d886a4933bc77) that
changes EDK2's emulated variable store to use coreboot's SMM store.
EDK2 has a proper SMM store of its own, I'd like to look into making that coreboot-compatible or at least
just writing a separate coreboot-compatible store module.
- **UPD 2019-10-24** for external displays, DisplayPort alt mode on USB-C can be used. Things to note:
- DP++ (DP cables literally becoming HDMI cables) can't work over USB Type C,
which is why there are no `HDMI-A-n` connectors on the GPU, so a passive HDMI-mDP dongle plugged into a mDP-TypeC dongle won't work;
- the Chrome EC runs the alt mode negotiation, the OS doesn't need any special support;
- for DP dongles to work at all, the EC **must run RW firmware** and that doesn't happen as-is
with upstream coreboot. There is a jump command on the EC console.
Also [this patch](https://github.com/MrChromebox/coreboot/commit/3f6e950980e65980476808938f0395f187f36b3c)
should help?? (+ [this](https://github.com/MrChromebox/coreboot/commit/23e81ecad1e20cd7bfbeb59e06804a5d5ba2f3bb))
### An aside: why mess with firmware?
If you're not the kind of person who's made happy by just the fact that some more code during the boot process
of their laptop is now open and verified, and you just want things to work, you might not be as excited
about open source firmware development as I am.
But you can do cool things with firmware that give you **practical** benefit.
The best example I'm seeing is better Hackintosh support.
Instead of patching macOS to work on your machine, you could patch your machine to pretend to almost be a Mac:
- [Creating hardware where no hardware exists](https://mjg59.dreamwidth.org/52149.html) (using SMM
to emulate Apple's System Management Controller in coreboot);
- [AppleSupportPkg](https://github.com/acidanthera/AppleSupportPkg) (making EDK2 more compatible with Apple things).
Is this cool or what?
## Conclusion
Pixelbook, FreeBSD, coreboot, EDK2 good.
Seriously, I have no big words to say, other than just recommending this laptop to FOSS enthusiasts :)

4
blog/_data.yml Normal file
View file

@ -0,0 +1,4 @@
layout: layouts/blog.njk
templateEngine: [njk, md]
renderOrder: -1
blog: true

17
blog/index.njk Normal file
View file

@ -0,0 +1,17 @@
---
layout: layouts/base.njk
templateEngine: njk
title: Blog
mainClass: h-feed
blog: false
---
{% import "blog.njk" as blog %}
<h1>Blog</h1>
<ul class="showcase-grid">
{%- for post in search.pages("blog=true", "date=desc") | data %}
{{ blog.preview(post) }}
{%- endfor %}
</ul>

56
colophon.md Normal file
View file

@ -0,0 +1,56 @@
---
layout: layouts/info.njk
title: Colophon
---
Here you can find various behind-the-scenes details about this website:
## Inspiration
Many layout ideas on the home page were inspired by the website of my pal [wave](https://www.wavebeem.com/).
They also drew my profile picture :)
## Hosting
This website is currently hosted by [Netlify](https://www.netlify.com/).
I use [Njalla](https://njal.la/) for actually private domain registration
and [Migadu](https://www.migadu.com/) for email.
No third party embeds except [shields.io](https://shields.io/) dynamic SVG images ~~have been hurt~~ are used on this website.
This is even enforced with `Content-Security-Policy`.
And yes, this means there are no analytics whatsoever.
## Content management
This website is generated with [Lume](https://lume.land/), a static site generator that runs on [Deno](https://deno.land/).
The source is available [right there on Codeberg](https://codeberg.org/valpackett/val.packett.cool), you can take a look!
## Typefaces
This website is set in [Recursive by Arrow Type](https://www.recursive.design/)…
yes, including code snippets: this is a variable font that has "monospace-ness" as a variability axis.
Also, [Silkscreen](https://kottke.org/plus/type/silkscreen/) is used for the tiny nostalgic badges at the bottom of the page.
## Icons
Brand icons are from [Simple Icons](https://simpleicons.org/)
while others like "email" are from [Font Awesome](https://fontawesome.com/).
Exceptions: the cohost eggbug [I monochromed from @nex3's vectorization](https://cohost.org/valpackett/post/142420-i-monochromed-the-ve),
the Lobste.rs icon is based on [the official SVG](https://github.com/lobsters/lobsters/blob/master/app/assets/images/logo-bw.svg).
## Helpful tools and tricks
- [Wavy Shapes generator](https://css-generators.com/wavy-shapes/)
- [nnnoise](https://fffuel.co/nnnoise/)
- [SVG to Data URI encoder](https://heyallan.github.io/svg-to-data-uri/)
- [fonttools](https://github.com/fonttools/fonttools) (`pyftsubset`)
- [Building a combined CSS-aspect-ratio-grid](https://9elements.com/blog/combined-aspect-ratio-grid/)
## Browser support
This website is [best viewed in Firefox](https://www.mozilla.org/en-US/firefox/new/)!
But all reasonably popular and recent browsers should be supported.
If you notice a major issue in any browser, contact me using any of the methods listed on [the home page](/).

1
contrib/_data.yml Normal file
View file

@ -0,0 +1 @@
layout: layouts/info.njk

174
contrib/firefox.md Normal file
View file

@ -0,0 +1,174 @@
---
title: Contributions to the Firefox browser
shorttitle: Firefox
desc: Improved Linux/Unix support with kinetic scrolling, GPU power savings, and more
contrib:
order: 0
---
Contributing to [Mozilla Firefox](https://www.mozilla.org/en-US/firefox/browsers/) development
was a very pleasant and interesting experience and I'm happy that the best web browser is run
as a friendly, open project.
On this page, I've attempted to summarize my work on the Firefox codebase.
My involvement was motivated by my [FreeBSD](/contrib/freebsd/) + [Wayland](/contrib/wayland/)
desktop adventures, starting with the touchpad.
## Kinetic scrolling on GTK (Linux/Unix)
Kinetic (or inertial, or fling) scrolling is a big part of what makes touch UIs like on smartphones feel so natural
and fun to use — the content gradually decelerating instead of suddenly stopping after you let go of the
scroll gesture allows you to "fling" content around on the screen.
On laptops with touchpads, Apple was first to support that with two-finger scrolling,
and it worked as smoothly as on an iPhone.
As a quick attempt to catch up, X11 touchpad drivers like xf86-input-synaptics (and Windows drivers too)
have tried to handle that themselves, while still communicating emulated mouse wheel events to applications.
This was never perfectly smooth and clearly was not a permanent solution.
With the adoption of evdev and Wayland however, Linux/Unix desktops gained proper support for touchpad scrolling —
that is, applications started receiving precise pan gesture events instead of emulated scroll wheel events.
But now, the responsibility to implement flings was moved into the applications.
The Gtk UI toolkit was early to support them, and it did that pretty well
(modulo [the lack of framerate sync](https://gitlab.gnome.org/GNOME/gtk/-/issues/2025) that made it a bit jittery on 90Hz touchpads).
Regular Gtk applications gained this feature for free, but web browsers are special beasts.
They barely use the toolkit and do almost everything by themselves.
WebKitGTK was also quick to gain kinetic scrolling support, but Firefox was not.
So my first Firefox contribution was fixing [bug 1213601](https://bugzilla.mozilla.org/show_bug.cgi?id=1213601),
that is, integrating Gtk's touchpad pan gesture events with Firefox's APZ (async pan and zoom) system
in patch [D27983](https://phabricator.services.mozilla.com/D27983).
This required supporting page units for deltas and simulating momentum events which Gtk did not emit.
## Partial rendering on EGL (Wayland/X11/Android)
In 2019, an article from the GFX team at Mozilla came out about
[dramatically reducing power usage on macOS](https://mozillagfx.wordpress.com/2019/10/22/dramatically-reduced-power-usage-in-firefox-70-on-macos-with-core-animation/)
and the primary power saving method used there was *partial rendering* based on *damage tracking* — that is, preventing the GPU
from rerendering things that haven't changed between frames.
emersion has a [detailed article](https://emersion.fr/blog/2019/intro-to-damage-tracking/) explaining the concept,
but basically: graphics APIs like OpenGL were designed for 3D cameras that change entirely from frame to frame,
while flat UIs very often stay mostly the same for lots of frames in a row, so just naively using OpenGL
for UIs results in a lot of pixels being wastefully rerendered all the time.
On a composited desktop, this actually happens *twice*: in the application itself and in the compositor.
To fix this, extra APIs are used that allow for only rendering what has changed.
After seeing the GFX article, I became really interested in bringing the power savings to my Wayland-powered desktops.
(Later, when Firefox switched the X11 backend from GLX to EGL as well, X11 users started benefiting from this work as well.)
The first thing I've done was the compositor side, which is simpler:
it's just about passing buffer damage information (i.e. the changed regions) to the compositor.
EGL provides the `EGL_KHR_swap_buffers_with_damage` (or `EGL_EXT_swap_buffers_with_damage`) extension
for this purpose, and [bug 1484812](https://bugzilla.mozilla.org/show_bug.cgi?id=1484812) existed
for implementing support for it in Firefox.
I have done that in patch [D51517](https://phabricator.services.mozilla.com/D51517).
Then it was time to tackle the application side. There are two different EGL extensions for doing this.
The one supported by desktop GPU drivers in Mesa is called `EGL_EXT_buffer_age`.
As implied by the name, it lets the application know how many frames old the contents of the current buffer
are, which enables the application to confidently skip drawing the regions that haven't changed since.
The WebRender implementation was tracked in [bug 1620076](https://bugzilla.mozilla.org/show_bug.cgi?id=1620076),
for which I authored patch [D61062](https://phabricator.services.mozilla.com/D61062).
WebRender has already supported partial rendering, but it was developed on Windows, which works differently:
it was expecting the OS to handle copying the changed regions from the previous frame into the current buffer.
For EGL, I've had to add an option to make WR render the union of the previous and current frames' damage.
After some interesting debugging, it worked!
## Miscellaneous Wayland support improvements
As I've been using Firefox on [Wayland](/contrib/wayland/) daily, I was obviously interested
in filling the little platform support gaps that I've been noticing.
The first one was Firefox not supporting the Wayland-native solution for idle wakelocks,
the idle-inhibit protocol ([bug 1587360](https://bugzilla.mozilla.org/show_bug.cgi?id=1587360)).
This is what makes it so that when you're watching a video, you don't have to constantly jiggle your
mouse to prevent the system from blanking the screen and preparing to go to sleep.
Firefox supported some D-Bus protocols for this (one freedesktop-branded, one GNOME-specific) in
addition to XScreenSaver, but none of those worked for me as I've been using [Wayfire](https://wayfire.org/).
I've added the implementation in patch [D49095](https://phabricator.services.mozilla.com/D49095).
Around the time I was working on the partial rendering patches, I also became interested in
Firefox's automatic enablement of GPU rendering. Namely, what was bothering me was that Xwayland
was required for it ([bug 1556301](https://bugzilla.mozilla.org/show_bug.cgi?id=1556301)).
To check that the GPU can be used on a system, Firefox forks off a `glxtest` process that attempts
to establish its own connection to the display server, create a GL context and gather GL driver info.
In patch [D57474](https://phabricator.services.mozilla.com/D57474) I have added a Wayland-EGL code path
to that process, dropping the X11 socket requirement.
Around that time, [dma-buf support](https://bugzilla.mozilla.org/show_bug.cgi?id=1572697) was being worked on,
which is something that allows cross-process buffer sharing — necessary for hardware video decoding
acceleration and for running WebGL in the content process without frame copy overhead.
I have fixed one mistake in that code — an incorrect usage of the GBM API that was causing driver crashes
([bug 1590832](https://bugzilla.mozilla.org/show_bug.cgi?id=1590832),
patch [D65239](https://phabricator.services.mozilla.com/D65239)).
The next thing to tackle was lack of mouse pointer grabbing support
([bug 1580595](https://bugzilla.mozilla.org/show_bug.cgi?id=1580595)), which made things like
[3D games](https://media.tojicode.com/q3bsp/) and draggable number input controls in Figma unusable.
All desktop platforms before Wayland just allowed applications to move the cursor around
willy-nilly and the applications used that (constantly warping the cursor to the center of the window)
to implement pointer grabbing, so there wasn't a native API specific to this task.
In Wayland, this is done via relative-pointer and pointer-constraints protocols.
I have contributed patch [D102114](https://phabricator.services.mozilla.com/D102114) that fixed this problem,
adding `Lock/UnlockNativePointer` IPC messages from web content processes to the parent Firefox process
and implementing their receiver using the aforementioned protocols.
Not actually *Wayland*-related, but I have also added the `.desktop` entry name to the MPRIS media control
protocol implementation ([bug 1676045](https://bugzilla.mozilla.org/show_bug.cgi?id=1676045),
patch [D96327](https://phabricator.services.mozilla.com/D96327)), which helps desktop environments match
the media playback session to the application.
## Miscellaneous FreeBSD support improvements
Using Firefox on a Tier 3 platform like a BSD means that there will be some missing things
and changes will be committed to the codebase that break the build on the platform.
The most typical reason for accidental build breakage in a C/C++ project is of course
header differences between platforms (often just in terms of transitive includes).
Sometimes this is related to the OS itself (like [bug 1615462](https://bugzilla.mozilla.org/show_bug.cgi?id=1615462))
and sometimes to things like the C++ library (like [bug 1594027](https://bugzilla.mozilla.org/show_bug.cgi?id=1594027)).
Firefox building but not working was *never* a situation I've encountered, however
there were obscure corners like `about:networking` not working on Tier 3 platforms
([bug 1477593](https://bugzilla.mozilla.org/show_bug.cgi?id=1477593),
patch [D58855](https://phabricator.services.mozilla.com/D58855)).
Two things however were not so obscure and not so trivial.
The first one was FIDO/U2F USB authentication token support
([bug 1468349](https://bugzilla.mozilla.org/show_bug.cgi?id=1468349)), which involved:
- creating the [devd-rs](https://crates.io/crates/devd-rs) Rust crate for listening to FreeBSD device hotplug messages
- adding support for the `uhid` API and devd hotplug to [authenticator-rs](https://github.com/mozilla/authenticator-rs/pull/62) (then called u2f-hid-rs)
- ensuring the new FreeBSD HID stack would [keep the `/dev/uhidN` devices](https://github.com/wulf7/iichid/pull/27)
- coming back much later to [solve occasional hangs by taking a solution from another BSD](https://github.com/mozilla/authenticator-rs/pull/175)
The second one was enabling the [Firefox Profiler](https://profiler.firefox.com/)
([bug 1634205](https://bugzilla.mozilla.org/show_bug.cgi?id=1634205)).
The resulting patch [D73162](https://phabricator.services.mozilla.com/D73162) ended up mostly touching ifdefs
(and adding platform knowledge like the `ucontext_t` structures for the supported architectures, amd64 and aarch64).
But getting there was quite an adventure, with Google Breakpad being involved (but not as much as I initially thought),
multiple ways of symbolication (the preferred way involving WASM-compiled tools which confusingly used to
[choke on debug builds of Firefox as they were over 2GB in size](https://bugzilla.mozilla.org/show_bug.cgi?id=1615066)),
having to figure out that `dli_sname` from the `dladdr` API is unusable on FreeBSD,
and other interesting obstacles.
Speaking of supporting CPU architectures: I also made NSS, Firefox's cryptography library,
detect CPU features on FreeBSD/aarch64 ([bug 1575843](https://bugzilla.mozilla.org/show_bug.cgi?id=1575843),
patch [D55386](https://phabricator.services.mozilla.com/D55386)).
Because I care about doubly obscure platforms and it's really important for me that they use their
cool hardware features when possible :)
Oh, there's also one thing that's actually relevant for Linux users as well, but unfortunately hasn't landed
(as of late 2022) because there sadly doesn't seem to be anyone up for reviewing it.
That is switching the gamepad support from the legacy Linux joystick interface to evdev, which is implemented
by FreeBSD and DragonFlyBSD as well as Linux ([bug 1680982](https://bugzilla.mozilla.org/show_bug.cgi?id=1680982),
patch [D98868](https://phabricator.services.mozilla.com/D98868)).
This patch is, however, currently shipped downstream in FreeBSD Ports, enabling gamepad support for
all users of FreeBSD's officially packaged Firefox out of the box.
Finally, I have experimented with enabling content process sandboxing using Capsicum
([bug 1607980](https://bugzilla.mozilla.org/show_bug.cgi?id=1607980),
patch [D59253](https://phabricator.services.mozilla.com/D59253)).
Based on ideas from [libpreopen](https://github.com/musec/libpreopen), it uses an LD_PRELOAD hook to convert
all the regular POSIX calls into something that does work with the strict Capsicum model of not having any
global namespaces whatsoever and only allowing resources to be created by deriving them from existing ones
(such as `openat()` below a directory you have an open file descriptor to).
This is definitely quite a bit hacky and eventually I came to the conclusion that this kind of translation
is better done in the kernel, and I've experimented in that direction — see [the FreeBSD page](/contrib/freebsd/).

BIN
contrib/freebsd/gpuinfo.jxl Normal file

Binary file not shown.

BIN
contrib/freebsd/gpuinfo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

281
contrib/freebsd/index.md Normal file
View file

@ -0,0 +1,281 @@
---
title: Contributions to FreeBSD
shorttitle: FreeBSD
desc: Worked on graphics, input, support in upstream projects, Arm platform bring-up and more
templateEngine: [njk, md]
contrib:
order: 2
---
{% import "media.njk" as media %}
My first encounter with the [FreeBSD](https://www.freebsd.org/) operating system was when I was a tiny kid:
a computer my dad brought home from a server environment had it on the hard drive.
I haven't done much with it then and quickly installed Windows, of course.
Some time later I became a Linux user, then I got a Mac mini to run macOS on, but after some years in the Apple world
I was looking for more freedom again and… inexplicably landed back on FreeBSD.
Me being me plus non-mainstream desktop platforms being non-mainstream, of course the daily usage was intertwined
with code contributions — both to the FreeBSD project itself and to a bunch of other projects (including
[Firefox](/contrib/firefox/) and [Wayland](/contrib/wayland/)) to improve FreeBSD support upstream.
And because only the OS being non-mainstream is not enough, my interest in the Arm architecture has resulted in
me bringing up the first usable [FreeBSD/aarch64 desktop with an AMD GPU](#macchiatobin).
## The graphics stack
The port of the DRM/KMS GPU driver ecosystem from Linux to FreeBSD has quite a history.
Originally it was done with manual modification of everything to use FreeBSD kernel API everywhere,
which was becoming really unmaintainable: for a long time Sandy/Ivy Bridge was the last supported Intel generation,
and when I bought [a Haswell laptop](/blog/thinkpad-x240/) in late 2015, it was the final upgrade of that port (to Linux version 3.8)
that I used there at first.
After that, it was replaced by a port using LinuxKPI, a compatibility layer that translates Linux kernel APIs to FreeBSD ones.
My first contribution there was [fixing 32-bit app compatibility](https://github.com/FreeBSDDesktop/kms-drm/pull/9) back in 2017.
Around that time I also added more stuff to `linsysfs` to [make graphics work in Linux apps](https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=222375).
In 2018-19 I worked on [monitor hotplug notifications](https://github.com/FreeBSDDesktop/kms-drm/pull/119) for Wayland compositors,
early [kernel-based backlight support](https://github.com/FreeBSDDesktop/kms-drm/pull/184) (via `sysctl`, way before the `backlight` tool), and [64-bit Arm support](#macchiatobin).
In 2020 I landed another Linux app compatibility fix, now [for PRIME `ioctl`s](https://github.com/freebsd/drm-kmod/pull/35).
2021 was quite a fun year, with me adding [a PCI info ioctl like on other BSDs](https://github.com/freebsd/drm-kmod/pull/58),
fighting [amdgpu's FPU usage in the kernel to make AMD Navi GPUs work](https://github.com/freebsd/drm-kmod/pull/103)
(took a couple tries to figure out the right way to implement FPU sections in [D29921](https://reviews.freebsd.org/D29921)),
and finally [solving the baffling "AMD GPU vs EFI framebuffer conflict"](https://github.com/freebsd/drm-kmod/pull/61) that's been annoying users for a few years
(turns out FreeBSD's basic framebuffer console continuing to write to VRAM as the driver was loading could sometimes just result in corrupting the memory that was used for the initialization,
and "sometimes" was indeed influenced by how large the current monitor was).
In 2022 I made AMD RDNA2 "Big Navi" GPUs work by [backporting patches](https://github.com/freebsd/drm-kmod/pull/174) — again FPU related ones.
On the userspace side, I have contributed FreeBSD-related (and general portability related) patches to upstream projects like [Mesa](https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/1598).
## The input stack
Originally, input drivers on FreeBSD exposed their own custom interfaces.
Around 2017, work was happening to adopt the `evdev` protocol from Linux, which was great news for the ability to run Wayland compositors.
Before that however I did [mess around with xf86-input-synaptics a bit](https://github.com/valpackett/xf86-input-synaptics), fixing TrackPoint and ClickPad support on FreeBSD.
After that, I've been doing a lot of tech support on the mailing lists related to enabling evdev, until it was made default :)
I've also contributed various improvements like adding device info `sysctl`s ([D18694](https://reviews.freebsd.org/D18694)) and [using them in libudev-devd](https://github.com/FreeBSDDesktop/libudev-devd/pull/8)
to make it possible for compositors to enumerate devices without having file permissions on them (which was expected because on Linux enumeration happens via actual udev),
[fixing joystick enumeration in libudev-devd](https://github.com/FreeBSDDesktop/libudev-devd/pull/9) and so on.
Also, since the beginning of USB support, HID support has been very… limited.
FreeBSD only had specific drivers like `ukbd` (USB Keyboard) and `ums` (USB Mouse) which took control of a whole USB interface, only supporting one function no matter what else was exposed in the HID descriptor.
When laptops with HID-over-I²C started appearing, the need for a proper HID stack became apparent, and the [iichid](https://github.com/wulf7/iichid) project by wulf@ came to the rescue, bringing a proper HID abstraction to the table.
I have contributed a [few](https://github.com/wulf7/iichid/pull/3) [fixes](https://github.com/wulf7/iichid/pull/23) and a couple drivers: [`hpen`](https://github.com/wulf7/iichid/pull/5) for tablet pens, [`hgame`/`xb360gp`](https://github.com/wulf7/iichid/pull/26) for gamepads.
I have also worked on some Apple trackpad things:
- [Magic Trackpad 1 via bthidd](https://github.com/DankBSD/base/commit/4c60ca2bbf922d326f223d28ca9b4eab8f6df31e), don't remember why it wasn't upstreamed by now…
- [Magic Trackpad 2 over USB](https://reviews.freebsd.org/D34437), needs to be rewritten in an endian-safe way
- [WIP Apple MacBook HID-over-SPI transport](https://github.com/DankBSD/base/commit/5a473b53a7dbc116f0bf9d090e39fb41d695a188), blocked on things like SPI API expansion [D29534](https://reviews.freebsd.org/D29534) and requires some *weird* device relationship trickery on Intel (ACPI) platforms
## Porting various things to FreeBSD
Over the years I have contributed FreeBSD-related improvements and fixes to a variety of upstream projects, like the [Firefox](/contrib/firefox/) browser and [Wayland](/contrib/wayland/) ecosystem projects, as well as many others including:
- [PulseAudio](https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/277) sound server (upstreaming existing downstream fixes, adding FreeBSD to the Meson build files, adding a devd hotplug backend)
- [Heaptrack](https://github.com/KDE/heaptrack/pull/24) memory profiler
- [Lucet](https://github.com/bytecodealliance/lucet/pull/419) WebAssembly compiler
- [ISPC](https://github.com/ispc/ispc/pull/1646) SPMD program compiler
- [LDC](https://github.com/ldc-developers/druntime/pull/146), [OCaml](https://github.com/ocaml/ocaml/pull/1904), [Mono](https://github.com/mono/mono/pull/11638), [libunwind](https://github.com/libunwind/libunwind/pull/83), [libffi](https://github.com/ffi/ffi/pull/644), [zlib-ng](https://github.com/zlib-ng/zlib-ng/pull/808) (64-bit Arm support)
- [Rust `libc`](https://github.com/rust-lang/libc/pulls?q=author%3Avalpackett), [Rust `nix`](https://github.com/nix-rust/nix/pulls?q=author%3Avalpackett), a bunch of smaller crates…
I have also maintained a bunch of packaging recipes in the FreeBSD Ports Collection.
## Arm platform bring-up stories
Some of my most interesting FreeBSD work was related to making (more of) the OS work on Arm-based systems.
Over time, it became more and more involved, getting deeper into various kernel and firmware complexities, and it has paid off:
being the first person to have a working FreeBSD/aarch64 **desktop** system with a fully working AMD GPU felt immensely satisfying.
### Scaleway ThunderX VPS
My first bring-up story from back in 2018 does not yet involve touching kernel code,
as the *hardware* platform was already well supported. The original Cavium (now Marvell) ThunderX
was the first production 64-bit Arm (aarch64) server unit, FreeBSD has actually been using those for
the build farm back then.
When European cloud provider Scaleway had introduced their ThunderX-based VPS product, it didn't officially support
local boot, so installing custom operating systems was not supported.
However, I went ahead to experiment with it and see if I could
"[depenguinate](https://www.daemonology.net/depenguinator/)" a running VPS.
Turns out, yes! This wasn't too hard and I've published my results on the now-defunct (hence the Wayback Machine link)
[Scaleway community forum](https://web.archive.org/web/20191211090725/https://community.scaleway.com/t/freebsd-on-arm64/6678).
Most of the effort was on the Linux side, with carefully copying necessary parts of the running system
to a RAM disk, doing `pivot_root`, and putting the FreeBSD installer onto a disk partition.
Then — luckily — it was possible to select the boot device by pressing Esc on the remote serial console.
The only non-trivial thing on the FreeBSD side was figuring out why storage was awfully slow:
turns out the system was considering the PCIe controller to have broken MSI support and used legacy interrupts,
and it was necessary to set `hw.pci.honor_msi_blacklist="0"`.
After publishing the thread I have even received an email from someone at Scaleway, saying they'd buy me
a beer if I ever was in their city :)
However a few months later local boot became impossible, despite the website claiming
"It will become available for our ARM64 virtual cloud server in a few days".
And then… the Scaleway ARM64 offering was sadly discontinued.
### Pine64 ROCKPro64 (Rockchip RK3399)
I was the first person to boot FreeBSD on the ROCKPro64 SBC.
As an embedded, Device Tree based platform, there was no smart firmware to handle everything in early boot, so
the initial bringup involved things like SoC clock and pin control ([D16732](https://reviews.freebsd.org/D16732)).
I have gotten Ethernet, XHCI USB ([D19335](https://reviews.freebsd.org/D19335)) and SD card ([D19336](https://reviews.freebsd.org/D19336)) peripherals running,
however those experimental patches were completely rewritten by committers (mostly manu@) later.
This work involved more *code* than the ACPI-based things described below, but far less *interesting* debugging.
### AWS EC2 Graviton (a1)
In late 2018, Amazon Web Services launched their first Arm VM instances running on their own SoC called Graviton.
Naturally the FreeBSD community was quite interested in supporting it.
The environment being a SBSA-standard UEFI-ACPI one, all operating systems should "just work".
However, bugs :)
After adding arm64 support to the [EC2 image build tool](https://github.com/cperciva/bsdec2-image-upload/pull/7) and
booting a VM, I was greeted with… nothing on the serial console after the UEFI loader's output.
Which is very "fun" to debug on a completely remote machine.
Patch [D19507](https://reviews.freebsd.org/D19507) is where my UART adventures are documented.
Basically, the problem was that the `AccessWidth` property in the SPCR ACPI table was not used, resulting in
FreeBSD using wrong memory accesses for the EC2 virtual UART.
Oh, and the direct manual configuration via `hw.uart.console` that I was using to first just match all the serial console
settings to Linux manually was broken on aarch64 too.
Other than the serial console, there actually weren't any problems in FreeBSD and the VMs just worked and
I have posted an early [dmesg log](https://dmesgd.nycbug.org/index.cgi?do=view&id=4813) on 2019-03-09.
From there, it was [Colin](https://www.daemonology.net/)'s work to polish everything (especially image build tool) and make everything official.
Now Arm EC2 images are officially published by the FreeBSD project among with the amd64 ones.
### Ampere eMAG
Soon after the Graviton, bare-metal Arm boxes became available from Packet.com (now Equinix Metal), powered by new Ampere eMAG CPUs.
I was first to boot FreeBSD to multi-user on one of these (again starting with a depenguination), starting the
[Bugzilla thread](https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=237055) that was later joined by Ampere engineers.
Bring-up on a completely remote system is always "fun", especially when you start with — once again — the serial console not even working.
However, having had the experience from the Graviton, I knew where to look.
In fact, it was my patch for the Graviton that made it not work on these eMAG servers…
because they had a wrong `AccessWidth` value reported by their firmware.
We have added a quirk for always using the correct value for that kind of UART ([D19507](https://reviews.freebsd.org/D19507)),
and the Ampere employees have fixed later revisions of the firmware as well.
With help from Ampere, missing address translations were added to make PCIe work.
In [D19987](https://reviews.freebsd.org/D19987) I've enabled `ioremap` in the LinuxKPI driver translation layer
to make the Mellanox NIC driver work, getting me to networking on those remote servers which allowed me to post a [dmesg](https://dmesgd.nycbug.org/index.cgi?do=view&id=4864).
I've also landed [D19986](https://reviews.freebsd.org/D19986) adding support for XHCI (USB 3.0) controllers
described in ACPI (not discovered over PCIe) as the eMAG was the first platform where we've encountered that.
Other people have handled various other tricky issues related to EFI memory maps and such, and in the end the platform worked very well.
### SolidRun MACCHIATObin (Marvell Armada A8040) {id=macchiatobin}
Having a fully working Arm desktop machine that works exactly like a regular AMD64 one was *the big dream* (really getting to me in 2019),
and the MACCHIATObin mini-ITX board running Marvell's networking-targeted Armada8k SoC seemed very promising.
The firmware situation was amazing, with upstream TianoCore EDK2 support and nearly everything in the early
boot process being open source (including memory training).
The board was also convenient for firmware development, being able to load firmware from microSD, onboard SPI flash, and over the UART.
And in fact, I have seen reports of people running GPUs on it!
After confirming that its PCIe controller did work as a generic ECAM one, I have ordered the board.
When I got it delivered, I first replaced the stock U-Boot firmware with a [preexisting](https://github.com/MarvellEmbeddedProcessors/edk2-open-platform/wiki/Binaries) EDK2 UEFI build and started trying to run the OS in ACPI mode.
Continuing the UART/SPCR theme… This time FreeBSD didn't like `BaudRate` being zero, which I fixed in [D19914](https://reviews.freebsd.org/D19914).
Because console on Unix systems is complicated, I also needed to add an ACPI entry to recognize the Marvell UART to make the *userspace* console work ([D20765](https://reviews.freebsd.org/D20765)).
On the console, I could see that AHCI SATA just worked, and so did XHCI USB because of my previous work.
Now, PCIe is of course the fun part.
I've started plugging in various cards and… only a basic SATA adapter was seen by the OS.
[Turns out](https://github.com/MarvellEmbeddedProcessors/edk2-open-platform/issues/11) this is due to a firmware workaround for a hilarious hardware bug.
Basically whatever version of the Synopsys DesignWare PCIe controller used on this SoC just *does not do* the expected packet filtering, *some* devices show up multiplied into all 32 slots on bus 0.
Amazing.
And it is *some* devices because others do their own filtering.
The chosen workaround in the firmware was to shift the ECAM base address so that the OS would only see the last slot.
But this obviously only works with the devices-that-are-multiplied.
Unfortunately, there's no good way to add a quirk for this in the ACPI world since Linux maintainers have a very strong "fix your hardware" stance on that.
So we just have to use a modified firmware that does not do the ECAM shift to use any device that does not get multiplied.
With that out of the way, devices started working!
At first with some funky errors like `igb0: failed to allocate 5 MSI-X vectors, err: 3`, but that was easy to figure out: someone forgot to add an attach function to the MSI support "device" for Arm's GICv2 interrupt controller, which I fixed in [D20775](https://reviews.freebsd.org/D20775).
With that patch, an Intel network card worked great.
So did a Mellanox one, as I've already enabled that driver on arm64 for the Packet server.
Then it was [GPU time](https://github.com/FreeBSDDesktop/kms-drm/pull/154) with a Radeon RX 480 that used to be in my main desktop system.
After adding the aarch64 build fixes, building and loading, I was first met with a system hang during initialization.
All I've had to figure out was that it was related to not actually mapping the PCIe memory as "device memory".
After fixing it in [D20789](https://reviews.freebsd.org/D20789), the GPU was fully initialized, showing the console!
Initially there was some display corruption, which had to be fixed by applying [an existing Linux patch](https://patchwork.kernel.org/project/linux-arm-kernel/patch/[email protected]/).
Then I've [enabled MSI](https://github.com/FreeBSDDesktop/kms-drm/pull/163) to avoid the same legacy interrupt problem that was slowing the Scaleway machine down.
<div class="pic-row">
{{ media.picture({
width: 2872,
height: 3454,
alt: "MACCHIATObin board with a graphics card inserted and a little bit of a display visible",
color: "#085d5e",
lqip: "data:image/webp;base64,UklGRtYAAABXRUJQVlA4IMoAAAAwBgCdASogAEAAP5nAzV+5MSilrBqsyyAzCWgAwGRJlwpu+0zuBeAFcE4+Rv4quqlhFSWSYIAOWgGAAM32cjLiXAYwCVQV0fjBt6N9CU/sbpdtOR7yrkDx/+ZckRXtbt00Lw+OMpf3PQUqIySDEDHnLoYc31iM80vTgBqELLAYceYbDbxkuVviUyZ5mr2+6TDWDaEyAnXrkR2OhxK1K1Dew93YuyxnYky/JvxBpeijRXI6JFyxQpbqmHLn588FjyPD2Mbz1ItaQAAA",
sources: [ {type: "image/avif", srcset: "mcbin.avif"} ],
src: "mcbin.jpg"
}, inFeed) }}
{{ media.picture({
width: 1280,
height: 1024,
alt: "Desktop screenshot showing screenfetch mentioning the GPU and the first few lines of dmesg output",
color: "#272822",
lqip: "data:image/webp;base64,UklGRioAAABXRUJQVlA4IB4AAACQAQCdASoMAAoACQCsJZwAAudZt7gA+puZrlAAAAA=",
sources: [ {type: "image/jxl", srcset: "gpuinfo.jxl"} ],
src: "gpuinfo.png"
}, inFeed) }}
</div>
And there it was! ([dmesg](https://dmesgd.nycbug.org/index.cgi?do=view&id=5033))
Later I've actually bought a case and assembled the system properly, adding a bunch of USB devices for missing parts like audio and networking.
And this was a completely usable desktop.
It even actually supported early boot display output, allowing for boot device selection and such, because the firmware runs the amd64 (!) EFI display driver stored on the card through QEMU.
Well. Actually, that initially didn't work on my RX 480 for *some reason*, though it did on another GPU I tried.
It took an email exchange with AMD employees to realize that the problem was that I have modified the VBIOS on my card previously for Overclocking Reasons.
And the EFI GOP driver does check the signature on that, unlike the Linux one.
While working on that machine as an actual desktop, I've contributed a few more general Arm things, such as improving the `armv8crypto` driver:
fixed a locking bug ([D21012](https://reviews.freebsd.org/D21012)) found by enabling tests ([D21018](https://reviews.freebsd.org/D21018)) that I wanted to have for adding the XTS mode ([D21017](https://reviews.freebsd.org/D21017)).
With XTS support, that driver became actually useful for something (that is, full disk encryption).
I have also ported the `sbsawdt` generic watchdog driver from NetBSD ([D20974](https://reviews.freebsd.org/D20974)) however the review process has stalled so it hasn't landed.
### SolidRun Honeycomb LX2K (NXP Layerscape LX2160A)
The next mini-ITX board from SolidRun — also based on a networking SoC (but now a 16-core one!) — made a much bigger splash as it was explicitly marketed as a workstation.
[It worked well on Linux](https://dev.to/lizthegrey/first-experiences-with-honeycomb-lx2k-26be).
I have not actually bought one, as it was a bit too expensive for my "science budget".
Also too expensive to be imported without dealing with customs.
So it was up to other people to try FreeBSD on it, with me around to fix the kernel :)
And one such person eventually turned up on the mailing lists. (Hi Dan!)
This platform has uncovered yet more FreeBSD bugs.
Adding support for multiple interrupt resources per ACPI device ([D25145](https://reviews.freebsd.org/D25145)) was required to make AHCI SATA work.
We also added a quirk for that devices ([D25157](https://reviews.freebsd.org/D25157)).
And for PCIe, interrupts did not work until I figured out (through long collaborative remote debugging sessions) that the IORT table handling code contained an off-by-one error in the range calculations.
The fix was just removing a "minus one" ([D25179](https://reviews.freebsd.org/D25179)).
With PCIe running, it was time to get a graphics card in there.
And initially it would return a very strange error while executing the "ATOMBIOS" interpreter that (big hint here) runs bytecode that it just *read over PCIe from the card*.
One more [exhausting collaborative debugging session](https://github.com/freebsd/drm-kmod/issues/84) later, we figured out what the problem actually was!
On this platform, an offset is required to translate PCIe addresses into raw memory ones.
Because drivers ported from Linux deal with raw addresses, a `BUS_TRANSLATE_RESOURCE` method on the PCIe driver interface was introduced to deal with this on another platform first (PowerPC).
However when the `pci_host_generic` driver that's used on Arm was written, that kind of translation was only implemented internally and was not exposed via that method.
Instead of reading from the GPU, the driver was reading some unrelated memory location.
To fix that, I've landed [D30986](https://reviews.freebsd.org/D30986) and it became a usable desktop!
As an extra, I have also tried adding ACPI attachment for the I2C controller ([D24917](https://reviews.freebsd.org/D24917)) but it was too difficult to debug something like that remotely.
These days, this platform is really well supported: someone even [landed a networking driver](https://reviews.freebsd.org/D36638).
### Raspberry Pi 4 ACPI Mode
When the [ServerReady compatible firmware](https://rpi4-uefi.dev/about/) (TianoCore EDK2 with ACPI tables) was published, I bought a Pi 4 to play with a new platform for FreeBSD to run on.
The Pi did boot FreeBSD quite easily, but XHCI USB (which they expose in an interesting way — hiding the whole PCIe layer from the OS which is nice) did not work out of the box.
Namely the device just wasn't getting initialized.
After tracing what was going on in ACPI and seeing that the memory accesses the `_INI` method was doing were… *weird*, I realized that
[the memory regions used by ACPI weren't being mapped as device memory](https://github.com/pftf/RPi4/issues/50#issuecomment-641469513).
I have solved the problem in patch [D25201](https://reviews.freebsd.org/D25201) by using the UEFI memory map to figure the mode for each region mapped by ACPI.
Then I've added ACPI bindings for the DWC OTG USB driver ([D25203](https://reviews.freebsd.org/D25203)), used on the Pi 4 for the USB-C port.
Now, the most interesting platform quirk on the Pi 4 is that due to weird Broadcom bugs, the XHCI USB controller can only DMA to the first 3GB of memory.
Due to that, by default the firmware limits the memory to 3GB.
My attempt at supporting fully unlocked memory mode was [D25219](https://reviews.freebsd.org/D25219) which interpreted ACPI `_DMA` objects as FreeBSD `bus_dma_tags`.
Apparently it didn't fully solve all problems but it seemed to work fine for me.

BIN
contrib/freebsd/mcbin.avif Normal file

Binary file not shown.

BIN
contrib/freebsd/mcbin.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

48
contrib/wayland.md Normal file
View file

@ -0,0 +1,48 @@
---
title: Contributions to the Wayland ecosystem
shorttitle: Wayland
desc: Ported compositors to FreeBSD, worked on Wayfire, improved Wayland support in apps
contrib:
order: 1
---
The [Wayland](https://wayland.freedesktop.org/) display server protocol has been one of my interests since I've been able to run a compositor on [FreeBSD](/contrib/freebsd/) for the first time.
I have contributed a bunch of little things around the whole ecosystem.
## FreeBSD porting
As I've been using [FreeBSD](/contrib/freebsd/) on the desktop, I've been involved in Wayland porting early on.
Back in late 2016 I started with [Sway](https://github.com/swaywm/sway/pull/985) which was still based on [wlc](https://github.com/Cloudef/wlc/pull/211) then.
Later I maintained a [fork of Weston](https://github.com/valpackett/weston) with FreeBSD support and a bunch of other experiments.
I have landed a few Weston patches upstream since I've been finding and fixing interesting bugs by using Weston daily :)
Later, while considering various options for creating compositors, I have experimented with [making a Rust binding to libweston](https://github.com/valpackett/weston-rs).
I have been upstreaming fixes to other related libraries such as [libinput](https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/36) too.
When Sway switched to its own wlroots library, [I ported it to FreeBSD too](https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/252).
Other wlroots compositors started appearing soon after, and among them I found [Wayfire](https://wayfire.org/).
## Wayfire development
When I saw Wayfire for the first time, I became a big fan instantly — it was a Compiz-inspired compositor, designed to be a flexible base for desktop environments, which is exactly what I wanted.
Wayfire has definitely been one of my favorite projects to work on.
I have landed [a lot of patches](https://github.com/WayfireWM/wayfire/pulls?q=author%3Avalpackett) over the years,
starting of course with [FreeBSD build fixes](https://github.com/WayfireWM/wayfire/pull/121),
perhaps most famously adding [vswipe, the touchpad swipe gesture desktop switcher plugin](https://github.com/WayfireWM/wayfire/pull/249),
and working on other things like [various](https://github.com/WayfireWM/wayfire/pull/369) [bug](https://github.com/WayfireWM/wayfire/pull/477) [fixes](https://github.com/WayfireWM/wayfire/pull/701), tracking wlroots updates, [adding CI](https://github.com/WayfireWM/wayfire/pull/416) and so on.
I've been also involved in [the external plugin world](https://github.com/WayfireWM/wayfire/wiki/Related-projects),
perhaps most notably with the [GSettings config backend](https://codeberg.org/valpackett/wf-gsettings).
## Wayland support everywhere
I have also contributed a bunch of Wayland-related patches to various projects including:
- [Firefox](/contrib/firefox/)
- [WezTerm](https://github.com/wez/wezterm/pulls?q=is%3Apr+author%3Avalpackett)
- [RetroArch](https://github.com/libretro/RetroArch/pulls?q=is%3Apr+author%3Avalpackett)
- [FreeCAD](https://github.com/FreeCAD/FreeCAD/pull/4360) and [Coin3D](https://github.com/coin3d/coin/pull/404)
- [GLFW](https://github.com/glfw/glfw/pull/1235)
- [PPSSPP](https://github.com/hrydgard/ppsspp/pull/10449)
- [RPCS3](https://github.com/RPCS3/rpcs3/pull/3994)

8
deno.json Normal file
View file

@ -0,0 +1,8 @@
{
"importMap": "import_map.json",
"tasks": {
"lume": "deno eval \"import 'lume/task.ts'\" --",
"build": "deno task lume",
"serve": "deno task lume -s"
}
}

37
feed.tmpl.js Normal file
View file

@ -0,0 +1,37 @@
export const url = "/feed.json";
export default async function (
{ site, search },
{ md, njk, url, date, htmlUrl },
) {
const feed = {
version: "https://jsonfeed.org/version/1.1",
title: site.feedTitle,
home_page_url: url("", true),
feed_url: url("feed.json", true),
// description: site.desc,
icon: url(site.pfp, true),
favicon: url(site.pfp, true),
authors: [{
name: site.author,
url: url("", true),
avatar: url(site.pfp, true),
}],
language: "en",
items: await Promise.all(
search.pages("blog=true", "date=desc").map(async (post) => ({
id: url(post.data.url, true),
url: url(post.data.url, true),
title: post.data.title,
summary: post.data.desc,
content_html: htmlUrl(
md(await njk(post.data.content, { inFeed: true })),
true,
),
date_published: date(post.data.date, "ATOM"),
})),
),
};
return JSON.stringify(feed, null, 2);
}

25
feed.xml.njk Normal file
View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{{ site.feedTitle }}</title>
<!--subtitle>{{ site.desc }}</subtitle-->
<link href="{{ url | url(true) }}" rel="self"/>
<link href="{{ "/" | url(true) }}"/>
{% set lastPage = search.pages() | last %}
<updated>{{ lastPage.data.date | date("ATOM") }}</updated>
<id>{{ "/" | url(true) }}</id>
<icon>{{ site.pfp | url(true) }}</icon>
<author>
<name>{{ site.author }}</name>
<uri>{{ "/" | url(true) }}</uri>
</author>
{%- for post in search.pages("blog=true", "date=desc") %}
<entry>
<title>{{ post.data.title }}</title>
<link href="{{ post.data.url | url(true) }}"/>
<updated>{{ post.data.date | date("ATOM") }}</updated>
<id>{{ post.data.url | url(true) }}</id>
<summary>{{ post.data.desc }}</summary>
<content type="html">{{ post.data.content | njk({"inFeed": true}) | md | htmlUrl(true) }}</content>
</entry>
{%- endfor %}
</feed>

6
import_map.json Normal file
View file

@ -0,0 +1,6 @@
{
"imports": {
"lume/": "https://deno.land/x/[email protected]/",
"std/": "https://deno.land/[email protected]/"
}
}

218
index.njk Normal file
View file

@ -0,0 +1,218 @@
---
layout: layouts/base.njk
mainClass: h-card
projects:
- title: SoundFixer
url: https://addons.mozilla.org/en-US/firefox/addon/soundfixer/
shield: https://img.shields.io/amo/users/soundfixer?logo=firefoxbrowser&color=blueviolet&logoColor=white
desc: Firefox add-on for fixing broken sound on YouTube and beyond, recommended by Mozilla
#- title: TiddlyPWA
# url: https://codeberg.org/valpackett/tiddlypwa
# desc: Secure offline storage and cross-device synchronization solution for TiddlyWiki 5
- title: microformats2-parser
url: https://mf2.packett.cool/
desc: Haskell library and HTTP API for parsing for the Microformats 2 semantic HTML markup syntax
- title: systemstat
url: https://crates.io/crates/systemstat
shield: https://img.shields.io/crates/d/systemstat?logo=rust&color=blueviolet&logoColor=white
desc: Rust library for cross-platform system information and statistics collection
- title: secstr
url: https://crates.io/crates/secstr
shield: https://img.shields.io/crates/d/secstr?logo=rust&color=blueviolet&logoColor=white
desc: Rust library for conveniently storing sensitive information in memory
- title: pcre-heavy
url: https://hackage.haskell.org/package/pcre-heavy
shield: https://img.shields.io/hackage/v/pcre-heavy?logo=haskell&color=blueviolet&logoColor=white
desc: Haskell regular expressions library based on PCRE with support for multiple matches and replacements
- title: eslint-plugin-pug
url: https://www.npmjs.com/package/eslint-plugin-pug
shield: https://img.shields.io/npm/dt/eslint-plugin-pug?logo=nodedotjs&color=blueviolet&logoColor=white
desc: ESLint plugin that adds support for inline scripts in Pug templates
- title: httpotion
deprecated: true
url: https://hex.pm/packages/httpotion
shield: https://img.shields.io/hexpm/dt/httpotion?logo=elixir&color=blueviolet&logoColor=white
desc: Elixir HTTP client convenience library (deprecated because the underlying library is unmaintained)
forges:
- place: Codeberg
icon: M11.955.49A12 12 0 0 0 0 12.49a12 12 0 0 0 1.832 6.373L11.838 5.928a.187.14 0 0 1 .324 0l10.006 12.935A12 12 0 0 0 24 12.49a12 12 0 0 0-12-12 12 12 0 0 0-.045 0zm.375 6.467l4.416 16.553a12 12 0 0 0 5.137-4.213z
title: valpackett
url: https://codeberg.org/valpackett
- place: GitHub
icon: M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12
title: valpackett
url: https://github.com/valpackett
- place: GNOME
icon: M 19.703533,0 C 14.71229,0 13.775776,7.1112082 16.584006,7.1112082 19.392237,7.1112082 24.696091,0 19.703533,0 Z m -7.714097,0.8721541 c -0.07881,0 -0.162873,0.00394 -0.250876,0.0157618 -2.8108582,0.3638354 -1.8191774,5.2499999 -0.323117,5.3406304 1.448774,0.089317 3.031523,-5.34719783 0.573993,-5.3563922 z M 7.1229733,2.8029771 C 6.9548832,2.8107004 6.7896707,2.849443 6.6356703,2.9172504 4.3764759,3.8498248 6.2915373,7.6930821 7.5564233,7.4356391 8.7241116,7.1965848 8.8751624,2.7648861 7.1229733,2.8042907 Z M 3.5240241,5.818739 C 3.2947295,5.819492 3.0719584,5.8951328 2.8896109,6.0341505 1.0822554,7.2819613 3.4964409,10.302977 4.5603639,9.8327493 5.4903113,9.422942 4.8979296,5.8660244 3.5227107,5.818739 Z M 13.55511,8.1278457 C 9.719733,8.1606829 4.8388227,10.105954 3.9876844,13.912434 3.0446021,18.139229 7.8756002,24 12.915443,24 c 2.479859,0 5.340629,-2.239492 5.875219,-5.07662 0.408493,-2.16331 -4.809983,-1.295097 -4.623468,0.136602 0.224605,1.715412 -1.258319,2.561296 -2.711034,1.454028 C 6.8326931,16.99387 19.113779,15.23774 18.303359,10.427758 18.040662,8.8686513 16.01264,8.1055165 13.55511,8.1265322 Z
title: valpackett
url: https://gitlab.gnome.org/valpackett
- place: Freedesktop
icon: M23.855 13.112l-2.054-7.875a4.414 4.414 0 0 0-5.379-3.153L3.296 5.509a4.413 4.413 0 0 0-3.153 5.378l2.055 7.875a4.416 4.416 0 0 0 5.379 3.153l13.126-3.425a4.377 4.377 0 0 0 2.69-2.036 4.377 4.377 0 0 0 .462-3.342zm-1.047 3a3.701 3.701 0 0 1-2.277 1.723L7.406 21.26a3.735 3.735 0 0 1-4.551-2.668L.8 10.717a3.734 3.734 0 0 1 2.668-4.552L16.593 2.74a3.727 3.727 0 0 1 4.551 2.668l2.054 7.875a3.7 3.7 0 0 1-.39 2.829zm-2.362-9.893c-.482-2.061-2.122-2.941-4.369-2.437l-11.65 3.04c-2.426.706-3.104 2.014-2.621 4.261l1.748 6.698c.482 2.112 2.281 3.098 4.369 2.437l11.651-3.04c2.121-.504 3.104-2.095 2.622-4.261l-1.75-6.698zm-6.277 3.097l.173.663-4.117.475-.173-.663 4.117-.475zm-9.05 3.861a.639.639 0 0 1-.783-.46l-.777-2.975a.643.643 0 0 1 .459-.783l4.169-1.087a.644.644 0 0 1 .784.458l.776 2.975a.643.643 0 0 1-.459.784l-4.169 1.088zm5.618 1.76l-2.06-1.988.769-.201 2.03 1.959-.519.135a.944.944 0 0 0-.22.095zm3.397 1.93a.212.212 0 0 1-.128.097l-2.336.609a.21.21 0 0 1-.257-.151l-.435-1.667a.21.21 0 0 1 .151-.257l2.336-.609a.211.211 0 0 1 .256.15l.435 1.667a.214.214 0 0 1-.022.161zm.011-2.398a.882.882 0 0 0-.178-.142.882.882 0 0 0-.463-.119l1.562-2.351c.183.147.41.235.649.248l-1.57 2.364zm5.151-3.94l-3.401.887a.462.462 0 0 1-.563-.33l-.633-2.428a.461.461 0 0 1 .33-.563l3.401-.887a.47.47 0 0 1 .35.049.457.457 0 0 1 .213.282l.633 2.428a.46.46 0 0 1-.33.562z
title: unrelentingtech
url: https://gitlab.freedesktop.org/unrelentingtech
social:
- place: Cohost
icon: M16.89.14c-.21 0-.44 0-.68.03-1.87.17-3.13.92-3.87 1.98a6.17 6.17 0 0 0-.94 3.67c0 .57.06 1.15.15 1.7-.38-.05-.74-.1-1.1-.12 1.07 1.93 1.59 3.99 1.73 4.51a.44.44 0 0 1-.32.54.44.44 0 0 1-.54-.32c-.15-.57-.75-2.86-1.92-4.75h-.28a8.6 8.6 0 0 0-4.29 1.16c-.49.29-.9.65-1.27 1.08l.45.27a33.5 33.5 0 0 0 7.29 2.86.44.44 0 0 1 .32.54.44.44 0 0 1-.53.32 33.5 33.5 0 0 1-7.53-2.96l-.53-.32c-.27.45-.5.96-.67 1.53a5.55 5.55 0 0 0 .22 4.12c.35.74.84 1.42 1.45 2.05-.24.15-.45.36-.65.6-.22.3-.41.66-.58 1.08a.46.46 0 0 0 .25.6.46.46 0 0 0 .6-.25c.15-.37.3-.66.46-.87.22-.27.42-.42.64-.5a10.96 10.96 0 0 0 1.96 1.33 3.33 3.33 0 0 0-.52 1.66.46.46 0 0 0 .4.5.46.46 0 0 0 .51-.4c.05-.4.12-.71.22-.95.07-.16.13-.28.2-.38.88.41 1.81.78 2.83 1.08l.41.11c-.1.16-.2.33-.28.52-.14.34-.23.73-.28 1.19a.46.46 0 0 0 .4.51.46.46 0 0 0 .5-.4c.05-.4.13-.71.23-.96.12-.29.27-.48.44-.6 1.35.29 2.64.41 3.88.37a8.62 8.62 0 0 0 4.3-1.16 5.3 5.3 0 0 0 1.23-1.04c.17.03.32.08.44.15.23.13.42.33.57.7.1.25.18.56.23.96a.46.46 0 0 0 .5.4.46.46 0 0 0 .4-.51 4.54 4.54 0 0 0-.28-1.2 2.08 2.08 0 0 0-1.28-1.3c.27-.44.49-.94.65-1.5.46-1.5.39-2.87-.2-4.12a8.4 8.4 0 0 0-2.95-3.28 15.4 15.4 0 0 0-2.3-1.29 26.1 26.1 0 0 0 2-3.52c.62-1.4 1.01-2.73.68-3.83a2.09 2.09 0 0 0-1.15-1.3c-.43-.2-.96-.3-1.6-.3ZM3.03 10.33c.16-.26.34-.5.53-.71C2.54 8.96 1.8 8.25 1.6 7.65c-.11-.34-.1-.64.11-1 .2-.36.64-.78 1.38-1.22 1.46-.85 2.6-.91 3.57-.57.97.34 1.8 1.14 2.47 2.11l.26.4 1 .03h.04a11.7 11.7 0 0 0-.58-.93 6.17 6.17 0 0 0-2.9-2.44 4.17 4.17 0 0 0-2-.2c-.72.1-1.5.36-2.3.84a4.4 4.4 0 0 0-1.7 1.54 2.08 2.08 0 0 0-.18 1.72c.31.94 1.18 1.71 2.25 2.4ZM16.9 1.02c.55 0 .95.08 1.24.21.38.18.56.41.66.75.21.7-.05 1.9-.64 3.22a25.3 25.3 0 0 1-2.02 3.53 20.17 20.17 0 0 0-3.66-1.07c-.11-.6-.19-1.23-.2-1.85-.01-1.18.2-2.31.79-3.16.59-.84 1.55-1.45 3.23-1.6l.6-.03zm3.62 13.3a1.05 1.05 0 0 1 1.05 1.05 1.05 1.05 0 0 1-1.05 1.04 1.05 1.05 0 0 1-1.04-1.04 1.05 1.05 0 0 1 1.04-1.05zm-6.16 1.08a1.05 1.05 0 0 1 1.04 1.05 1.05 1.05 0 0 1-1.04 1.04 1.05 1.05 0 0 1-1.05-1.04 1.05 1.05 0 0 1 1.05-1.05zm3.8 2.1.22.18c.11.1.3.15.49.14.18-.02.34-.1.4-.2a.27.27 0 0 1 .38-.08.27.27 0 0 1 .07.37c-.18.28-.5.41-.8.44-.25.02-.47-.09-.69-.2-.17.15-.36.3-.6.32-.3.03-.62-.07-.93-.26a.27.27 0 0 1-.08-.37.27.27 0 0 1 .37-.08c.23.14.44.2.6.18a.5.5 0 0 0 .4-.22z
title: valpackett
url: https://cohost.org/valpackett
- place: Flickr
icon: M5.334 6.666C2.3884 6.666 0 9.055 0 12c0 2.9456 2.3884 5.334 5.334 5.334 2.9456 0 5.332-2.3884 5.332-5.334 0-2.945-2.3864-5.334-5.332-5.334zm13.332 0c-2.9456 0-5.332 2.389-5.332 5.334 0 2.9456 2.3864 5.334 5.332 5.334C21.6116 17.334 24 14.9456 24 12c0-2.945-2.3884-5.334-5.334-5.334Z
title: valpackett
url: https://www.flickr.com/photos/valpackett/
- place: dev.to
icon: M7.42 10.05c-.18-.16-.46-.23-.84-.23H6l.02 2.44.04 2.45.56-.02c.41 0 .63-.07.83-.26.24-.24.26-.36.26-2.2 0-1.91-.02-1.96-.29-2.18zM0 4.94v14.12h24V4.94H0zM8.56 15.3c-.44.58-1.06.77-2.53.77H4.71V8.53h1.4c1.67 0 2.16.18 2.6.9.27.43.29.6.32 2.57.05 2.23-.02 2.73-.47 3.3zm5.09-5.47h-2.47v1.77h1.52v1.28l-.72.04-.75.03v1.77l1.22.03 1.2.04v1.28h-1.6c-1.53 0-1.6-.01-1.87-.3l-.3-.28v-3.16c0-3.02.01-3.18.25-3.48.23-.31.25-.31 1.88-.31h1.64v1.3zm4.68 5.45c-.17.43-.64.79-1 .79-.18 0-.45-.15-.67-.39-.32-.32-.45-.63-.82-2.08l-.9-3.39-.45-1.67h.76c.4 0 .75.02.75.05 0 .06 1.16 4.54 1.26 4.83.04.15.32-.7.73-2.3l.66-2.52.74-.04c.4-.02.73 0 .73.04 0 .14-1.67 6.38-1.8 6.68z
title: valpackett
url: https://dev.to/valpackett
- place: Lobste.rs
icon: M1.26 0C.56 0 0 .56 0 1.26v21.48C0 23.44.56 24 1.26 24h21.48c.7 0 1.26-.56 1.26-1.26V1.26C24 .56 23.44 0 22.74 0H1.26zM5.4 4.02h7.87c.1 0 .15.01.15.13-.02.29 0 .56 0 .84v.13c-.21.01-.42 0-.62.02-.3.05-.6.1-.88.17-.53.17-.8.53-.86 1.02-.03.23-.04.45-.04.68v9.58c0 .4.04.8.09 1.2.04.43.32.72.73.87.34.14.72.16 1.08.18.94.03 1.88.02 2.8-.22a3.54 3.54 0 0 0 2.63-2.47c.13-.42.2-.85.3-1.28.02-.03.04-.1.07-.1h1c-.04 1.8.02 3.6 0 5.4H5.24v-.94c0-.16 0-.15.15-.17.34-.03.69-.04 1.04-.1.69-.12 1-.47 1.1-1.17.03-.21.05-.44.05-.65V7.04a7 7 0 0 0-.06-.8c-.05-.46-.35-.75-.78-.92-.4-.15-.82-.16-1.24-.19h-.23v-.98c0-.1.03-.13.13-.13z
title: valpackett
url: https://lobste.rs/u/valpackett
contact:
- place: Email
icon: M 21.75 3 L 2.25 3 C 1.007812 3 0 4.007812 0 5.25 L 0 18.75 C 0 19.992188 1.007812 21 2.25 21 L 21.75 21 C 22.992188 21 24 19.992188 24 18.75 L 24 5.25 C 24 4.007812 22.992188 3 21.75 3 Z M 21.75 5.25 L 21.75 7.164062 C 20.699219 8.019531 19.023438 9.347656 15.441406 12.15625 C 14.652344 12.777344 13.089844 14.265625 12 14.25 C 10.914062 14.265625 9.347656 12.773438 8.558594 12.15625 C 4.976562 9.351562 3.300781 8.019531 2.25 7.164062 L 2.25 5.25 Z M 2.25 18.75 L 2.25 10.050781 C 3.324219 10.90625 4.847656 12.105469 7.167969 13.925781 C 8.195312 14.730469 9.988281 16.511719 12 16.5 C 14.003906 16.511719 15.773438 14.757812 16.832031 13.925781 C 19.152344 12.105469 20.675781 10.90625 21.75 10.050781 L 21.75 18.75 Z M 2.25 18.75
title: [email protected]
url: mailto:[email protected]
class: u-email
- place: Matrix
icon: M.632.55v22.9H2.28V24H0V0h2.28v.55zm7.043 7.26v1.157h.033c.309-.443.683-.784 1.117-1.024.433-.245.936-.365 1.5-.365.54 0 1.033.107 1.481.314.448.208.785.582 1.02 1.108.254-.374.6-.706 1.034-.992.434-.287.95-.43 1.546-.43.453 0 .872.056 1.26.167.388.11.716.286.993.53.276.245.489.559.646.951.152.392.23.863.23 1.417v5.728h-2.349V11.52c0-.286-.01-.559-.032-.812a1.755 1.755 0 0 0-.18-.66 1.106 1.106 0 0 0-.438-.448c-.194-.11-.457-.166-.785-.166-.332 0-.6.064-.803.189a1.38 1.38 0 0 0-.48.499 1.946 1.946 0 0 0-.231.696 5.56 5.56 0 0 0-.06.785v4.768h-2.35v-4.8c0-.254-.004-.503-.018-.752a2.074 2.074 0 0 0-.143-.688 1.052 1.052 0 0 0-.415-.503c-.194-.125-.476-.19-.854-.19-.111 0-.259.024-.439.074-.18.051-.36.143-.53.282-.171.138-.319.337-.439.595-.12.259-.18.6-.18 1.02v4.966H5.46V7.81zm15.693 15.64V.55H21.72V0H24v24h-2.28v-.55z
title: "@valpackett:mozilla.org"
url: https://matrix.to/#/@valpackett:mozilla.org
- place: Discord
icon: M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z
title: "Val Packett#1337"
url: https://discord.com/users/680512402017747024
- place: Telegram
icon: M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z
title: val_packett
url: https://t.me/val_packett
---
<link href="{{ site.pfp }}" class="u-photo">
<h1>Hello!</h1>
<p>
Hi, I'm <a href="/" class="p-name u-uid u-url" rel="me">Val Packett</a>
(<span class="p-pronouns"><span class="p-x-pronoun-nominative p-pronoun-nominative p-pronoun">they</span>/<span class="p-pronoun-oblique p-x-pronoun-oblique">them</span></span>)!
</p>
<p>
I am best known for my involvement in the world of open source software, where my inexplicable obsession with
unusual and alternative systems has resulted in experience all across the computing stack — from the web platform
and desktop apps to device drivers, boot firmware, embedded systems, and even circuit board design.
</p>
<p>
My interests include, in no particular order: typed functional programming, operating system kernels, device drivers,
cross-platform portability, SIMD optimizations, sandboxing, offline-capable web applications, free desktop environments and their components…
And I've used too many programming languages to count but Rust is my favorite.
</p>
<p>
This website attempts to present my experience in a reasonably organized way — keep reading and you'll find something interesting!
</p>
<h2>Contributions</h2>
<ul class="showcase-grid">
{%- for cont in search.pages("contrib.order!=undefined", "contrib.order") %}
<li class="showcase-card card-contrib contrib-{{ cont.src.path | basename }}">
<a href="{{ cont.data.url }}" class="showcase-spread">
<h3>{{ cont.data.shorttitle }}</h3>
</a>
<p>{{ cont.data.desc }} ✦&nbsp;<a href="{{ cont.data.url }}">read more&nbsp;→</a></p>
</li>
{%- endfor %}
</ul>
<h2>Projects</h2>
{% macro project(proj) -%}
<li class="showcase-card{% if proj.deprecated %} deprecated{% endif %}">
<a href="{{ proj.url }}" class="showcase-spread">
<h3>{{ proj.title }}</h3>
{%- if proj.shield %}
<div>
<img src="{{ proj.shield }}" alt="" loading="lazy" decoding="async">
</div>
{%- endif %}
</a>
<p>{{ proj.desc | safe }} ✦&nbsp;<a href="{{ proj.url }}">read more&nbsp;→</a></p>
</li>
{%- endmacro %}
<ul class="showcase-grid">
{%- for proj in projects | take(4) %}
{{ project(proj) }}
{%- endfor %}
</ul>
<details>
<summary class="open-more">A few more projects</summary>
<ul class="showcase-grid">
{%- for proj in projects | drop(4) %}
{{ project(proj) }}
{%- endfor %}
</ul>
</details>
Even more projects can be found on my forge accounts (never mind the temporary forks, abandoned experiments, old names and usernames):
{% macro linky(link) -%}
<li class="showcase-card showcase-spread">
<strong>{{ link.place }}</strong>
<a href="{{ link.url }}" rel="me">
{% if link.icon -%}
<svg width="24" role="presentation" aria-hidden="true" viewBox="0 0 24 24"><path d="{{ link.icon }}"/></svg>
{% endif -%}
{{ link.title }}
</a>
</li>
{%- endmacro %}
<ul class="showcase-grid">
{%- for link in forges %}
{{ linky(link) }}
{%- endfor %}
</ul>
<h2>Latest blog posts</h2>
{% import "blog.njk" as blog %}
<div class="h-feed">
<ul class="showcase-grid">
{%- for post in search.pages("blog=true", "date=desc") | take(2) | data %}
{{ blog.preview(post) }}
{%- endfor %}
</ul>
<a href="/blog/" class="u-uid u-url open-more">Read more posts →</a>
</div>
<h2>Find me elsewhere</h2>
<ul class="showcase-grid">
{%- for link in social %}
{{ linky(link) }}
{%- endfor %}
</ul>
<h2>Contact me</h2>
<ul class="showcase-grid">
{%- for link in contact %}
{{ linky(link) }}
{%- endfor %}
</ul>
<p>
<small>
(There is no PGP key here because
<a href="https://latacora.micro.blog/2020/02/19/stop-using-encrypted.html">encrypted email is rather silly</a>.
If you'd like to report a sensitive security vulnerability in any of my projects, just message me on Matrix.)
</small>
</p>

52
netlify.toml Normal file
View file

@ -0,0 +1,52 @@
[build]
publish = "_site"
command = """
curl -fsSL https://deno.land/x/install/install.sh | sh && \
/opt/buildhome/.deno/bin/deno task build --location=https://val.packett.cool/ \
"""
[[headers]]
for = "/*"
[headers.values]
strict-transport-security = "max-age=31536000"
x-content-type-options = "nosniff"
x-frame-options = "SAMEORIGIN"
referrer-policy = "no-referrer-when-downgrade"
permissions-policy = "sync-xhr=(), accelerometer=(), camera=(), geolocation=(), microphone=(), usb=()"
content-security-policy = "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: img.shields.io; script-src 'none'; object-src 'none'"
[[headers]]
for = "/x/*"
values = { cache-control = "public, max-age=31536000, immutable" }
[[headers]]
for = "*.jpg"
values = { cache-control = "public, max-age=31536000, immutable" }
[[headers]]
for = "*.png"
values = { cache-control = "public, max-age=31536000, immutable" }
[[headers]]
for = "*.webp"
values = { cache-control = "public, max-age=31536000, immutable" }
[[headers]]
for = "*.avif"
values = { cache-control = "public, max-age=31536000, immutable" }
[[headers]]
for = "*.jxl"
values = { cache-control = "public, max-age=31536000, immutable" }
[[redirects]]
from = "https://www.packett.cool/*"
to = "https://val.packett.cool/:splat"
[[redirects]]
from = "https://packett.cool/*"
to = "https://val.packett.cool/:splat"
[[redirects]]
from = "/mf2"
to = "https://mf2.packett.cool/"

3
robots.txt.njk Normal file
View file

@ -0,0 +1,3 @@
User-agent: *
Sitemap: {{ 'sitemap.xml' | url(true) }}

9
sitemap.xml.njk Normal file
View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{%- for page in search.pages() %}
<url>
<loc>{{ page.data.url | url(true) }}</loc>
<lastmod>{{ page.data.date | date("DATE") }}</lastmod>
</url>
{%- endfor %}
</urlset>

BIN
x/RecVar1085.woff2 Normal file

Binary file not shown.

157
x/s.css Normal file
View file

@ -0,0 +1,157 @@
/*! val.packett.cool 💜 fonts: https://www.recursive.design/ https://kottke.org/plus/type/silkscreen/ */
@font-face { font-family: RecVar; font-style: oblique 0deg 15deg; font-weight: 300 1000; src: url('RecVar1085.woff2') format('woff2'); }
@font-face { font-family: Slkscr; src: url('slkscr.woff2') format('woff2'); }
:root {
--fnt-mono: 0; --fnt-casl: .2;
--hue-main: 263.85; --hue-accent: 258.3;
--color-fg: hsl(var(--hue-main), 99.8%, 97.3%);
--color-bg: hsl(var(--hue-accent), 20%, 15%);
--color-bg2: hsl(var(--hue-accent), 20%, 10%);
--color-accent: hsl(var(--hue-accent), 100%, 71.9%);
--color-accent2: hsl(var(--hue-accent), 98%, 84%);
--color-accent3: hsl(var(--hue-accent), 88%, 100%);
-webkit-text-size-adjust: none; text-size-adjust: none;
height: 100%;
scrollbar-color: var(--color-accent2) var(--color-bg2);
accent-color: var(--color-accent);
}
*, *:before, *:after { box-sizing: border-box; font-variation-settings: "MONO" var(--fnt-mono), "CASL" var(--fnt-casl); }
::selection { background: var(--color-accent); color: #fff; }
:focus:not(:focus-visible) { outline: none; }
body { margin: 0; min-height: 100vh; min-width: 300px; line-height: 1.5; word-wrap: break-word; font-family: RecVar, system-ui, sans-serif; font-weight: 390; font-feature-settings: "liga", "kern"; background: var(--color-bg); color: var(--color-fg); }
img, video { max-width: 100%; height: auto; display: block; }
.lqip { background-size: cover !important; background-repeat: no-repeat !important; }
.lqip img, .lqip video { backdrop-filter: blur(42px); }
picture { display: contents; }
p, figure, blockquote, details, .pic-row, .post-content > ul, .post-content > ol, article > ul, article > ol, h1, h2, h3, h4 { margin: 1.4rem 0; }
pre { font-family: inherit; }
code { font-family: inherit; --fnt-mono: 1; --fnt-casl: .6; word-wrap: normal; white-space: pre-wrap; font-feature-settings: "dlig", "ss01", "ss02", "ss03", "ss04", "ss05", "ss06", "ss08", "ss11", "ss12"; }
ul { list-style-type: square; padding-left: 1.5ch; }
details summary { display: block; position: relative; cursor: pointer; padding-left: 2rem; }
details summary:before { content: ''; border-width: .6ch; border-style: solid; border-color: transparent transparent transparent var(--color-fg); position: absolute; top: calc(50% - .6ch); left: 1rem; transform-origin: .3ch 50%; }
details[open] > summary:before { transform: rotate(90deg); }
details summary::-webkit-details-marker { display: none; }
a { text-decoration: none; color: var(--color-accent2); }
article a { text-decoration: .5px underline; }
a:hover { text-decoration: 1px wavy underline; }
a svg { fill: currentColor; width: 1.5em; height: 1.5em; margin-bottom: -.45em; }
.header-anchor { text-decoration: none; color: inherit; }
h1 { --fnt-casl: .8; font-size: 1.69em; font-weight: 800; }
h2 { --fnt-casl: .7; font-size: 1.420em; font-weight: 700; }
h3 { --fnt-casl: .6; font-size: 1.2em; font-weight: 550; }
h4 { --fnt-casl: .5; font-size: 1.1em; font-weight: 500; }
article { hyphens: auto; }
resp-cont { display: block; width: 100%; position: relative; }
resp-cont[data-pad] > *, resp-cont[data-pad] img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
#𝖍𝖊𝖆𝖉𝖊𝖗 {
display: flex;
align-items: center;
font-size: 1.15rem;
background: var(--color-accent) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='800' height='400'%3E%3Cdefs%3E%3Cfilter id='nnnoise-filter' x='-20%25' y='-20%25' width='140%25' height='140%25' filterUnits='objectBoundingBox' primitiveUnits='userSpaceOnUse' color-interpolation-filters='linearRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.126' numOctaves='4' seed='15' stitchTiles='stitch' x='0%25' y='0%25' width='100%25' height='100%25' result='turbulence'%3E%3C/feTurbulence%3E%3CfeSpecularLighting surfaceScale='20' specularConstant='0.9' specularExponent='20' lighting-color='hsl(258.3, 90%25, 80%25)' x='0%25' y='0%25' width='100%25' height='100%25' in='turbulence' result='specularLighting'%3E%3CfeDistantLight azimuth='3' elevation='93'%3E%3C/feDistantLight%3E%3C/feSpecularLighting%3E%3C/filter%3E%3C/defs%3E%3Crect width='800' height='400' fill='hsl(258.3, 90%25, 80%25)' filter='url(%23nnnoise-filter)'%3E%3C/rect%3E%3C/svg%3E");
color: var(--color-accent2);
text-shadow: hsl(var(--hue-accent), 100%, 60%) 0 1px 0;
padding: 1rem 1rem calc(1rem + 24px * 1.5);
--mask:
radial-gradient(43.27px at 50% calc(100% - 60.00px),#000 99%,#0000 101%) calc(50% - 48px) 0/96px 100%,
radial-gradient(43.27px at 50% calc(100% + 36.00px),#0000 99%,#000 101%) 50% calc(100% - 24px)/96px 100% repeat-x;
-webkit-mask: var(--mask); mask: var(--mask);
}
#𝖍𝖊𝖆𝖉𝖊𝖗 ::selection { background: #fff; color: var(--color-accent); text-shadow: none; }
#𝖍𝖊𝖆𝖉𝖊𝖗 * { display: inline-block; vertical-align: middle; }
#𝖍𝖊𝖆𝖉𝖊𝖗 a { color: var(--color-accent3); }
#𝖍𝖊𝖆𝖉𝖊𝖗 nav { display: inline-flex; gap: .5ch; }
#𝖍𝖔𝖒𝖊 :last-child { position: relative; }
#𝖍𝖔𝖒𝖊 { text-decoration: none; }
#𝖍𝖔𝖒𝖊:hover > :first-child { text-decoration: 1px wavy underline; }
#𝖍𝖔𝖒𝖊 img { image-rendering: pixelated; image-rendering: crisp-edges; border-radius: 10rem; border: 2px solid var(--color-fg); box-sizing: content-box;}
#𝖍𝖔𝖒𝖊:hover :last-child:after, #𝖍𝖔𝖒𝖊:hover :last-child:before { content: ''; z-index: 69; display: block; position: absolute; top: 22px; left: 15px; width: 9px; height: 5px; image-rendering: pixelated; image-rendering: crisp-edges; background: url(data:image/webp;base64,UklGRi4AAABXRUJQVlA4TCIAAAAvWUAMAIXatm2Yy3275zLaCUZ5EPo/AVhMoqvC9gNFcssC); background-size: contain; }
#𝖍𝖔𝖒𝖊:hover :last-child:after { left: 28px; }
@media screen and (max-width: 60ch) {
#𝖍𝖔𝖒𝖊 { font-size: 0; }
#𝖍𝖔𝖒𝖊 > div:first-child { display: none; }
}
@media screen and (min-width: 60ch) {
#𝖍𝖊𝖆𝖉𝖊𝖗 > :first-child { flex: 1 1 calc(50% + 26px); text-align: right; }
#𝖍𝖊𝖆𝖉𝖊𝖗 > :last-child { flex: 1 1 calc(50% - 26px); text-align: left; }
}
main { margin: 2rem auto; padding: 1px 1ch; max-width: 80ch; }
#𝖋𝖔𝖔𝖙𝖊𝖗 {
position: sticky;
top: 100vh;
text-align: center;
background: var(--color-bg2);
padding: calc(1rem + 24px * 1.5) 1rem 1rem;
font-size: .9rem;
--mask:
radial-gradient(43.27px at 50% 60.00px,#000 99%,#0000 101%) 50% 0/96px 100%,
radial-gradient(43.27px at 50% -36px,#0000 99%,#000 101%) calc(50% - 48px) 24px/96px 100% repeat-x;
-webkit-mask: var(--mask); mask: var(--mask);
}
#𝖋𝖔𝖔𝖙𝖊𝖗 p { margin: .25rem; }
.showcase-card, .post-content > pre, .open-more {
background: hsl(var(--hue-accent), 16%, 12%);
padding: 1.4rem 1rem;
margin: -.2rem 0;
--mask:
radial-gradient(26.83px at 50% 36.00px,#000 99%,#0000 101%) calc(50% - 24px) 0/48px 51% repeat-x,
radial-gradient(26.83px at 50% -24px,#0000 99%,#000 101%) 50% 12px/48px calc(51% - 12px) repeat-x,
radial-gradient(26.83px at 50% calc(100% - 36.00px),#000 99%,#0000 101%) calc(50% - 24px) 100%/48px 51% repeat-x,
radial-gradient(26.83px at 50% calc(100% + 24.00px),#0000 99%,#000 101%) 50% calc(100% - 12px)/48px calc(51% - 12px) repeat-x;
-webkit-mask: var(--mask); mask: var(--mask);
}
.showcase-card, .open-more { transition: ease .5s transform; }
@media screen and not (prefers-reduced-motion) {
.showcase-card:hover { transform: rotateZ(-.3deg) scale(1.02); }
details summary:before { transition: ease .25s transform; }
html:focus-within { scroll-behavior: smooth; }
}
.showcase-spread { display: flex; justify-content: space-between; align-items: center; }
.showcase-card h3 { margin: .5rem .5rem .25rem 0; }
.showcase-card p { margin: .5rem 0; }
.deprecated { filter: grayscale(0.5) brightness(0.9); }
.showcase-grid { display: grid; gap: 0 1.2rem; padding: 0; list-style-type: none; }
.open-more { display: block; text-align: center; color: var(--color-accent2); --color-fg: var(--color-accent2); }
.open-more:focus { -webkit-mask: none; mask: none; }
.open-more:focus:not(:focus-visible) { -webkit-mask: var(--mask); mask: var(--mask); }
@media screen and (min-width: 69ch) {
.showcase-grid { grid-template-columns: 1fr 1fr; }
}
@media screen and (min-width: calc(80ch + 8rem)) {
.showcase-grid, .open-more { margin-left: -1rem; margin-right: -1rem; }
.header-anchor:hover:before { color: var(--color-accent2); padding-right: .5ch; display: inline-block; }
h2 .header-anchor:hover:before { content: '##'; margin-left: -2.5ch; }
h3 .header-anchor:hover:before { content: '###'; margin-left: -3.5ch; }
h4 .header-anchor:hover:before { content: '####'; margin-left: -4.5ch; }
}
@media screen and (min-width: 110ch) {
.post-content > pre, .post-content > figure, .post-content > .pic-row { margin-left: -10ch; margin-right: -10ch; }
}
.post-content { margin: 3rem auto; }
.post-title, .post-meta, .post-subhead { margin: 2rem auto; text-align: center; }
.post-title { max-width: 50ch; letter-spacing: .1px; }
.post-meta, .preview-meta { font-weight: 250; }
.post-subhead { font-weight: 350; max-width: 60ch; font-size: .94em; }
.preview-meta { margin: 0; }
.pic-row { display: flex; gap: 1ch; }
.pic-row > * { margin: 0; flex-basis: 0; flex-grow: calc(var(--ratio)); aspect-ratio: var(--ratio); }
.bigerror { text-align: center; }
a.ᵇᵈᵍ { display: inline-flex; align-items: center; width: 80px; height: 15px; vertical-align: middle; font: 8px Slkscr; text-decoration: none; -webkit-font-smoothing: none; image-rendering: pixelated; }
.ᵇᵈᵍ.ᶠˣ { border: 1px solid #FF7139; color: #EE6129; background: var(--color-accent3) url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAaBAMAAADRS8i8AAAAJ1BMVEUAAAD/lTW1PeT/rDPmo2n/Yi3/5kT/zjb/qR7/iBzCc6OTUvSwPeTLMnzIAAAABnRSTlMAV2il/v4VjkcFAAABJUlEQVR42mXOP0vDQBgG8KuhqLN/wN3RQZAqgmMhUFwPzCYoOXDKlNdVFHLpKoHcLgr6ES5jQWjzoXzuzV0k6VMo4fe+z92JcS5T5GGLJynnfOxR5/djPx74xfD44HuvvSv17xPt/Io/Kc9736/hh9yJiFTvptbcQXaJKHhkTC2u65fgufcTY8qDyrj9ndM5Bqpzg3383oU4a5EPUkrBI4NorUswZ4U3wacVHFfrm9bniygTYpY4L7V+a0PYZeUKNQq3wX/hEynNsDBffMOnUsrEF5bsq/QxZsc5eA7cDz5TlYkj7IMQHmzg6zRnTwBFQe6fNm4Q4/yZ338uCHmytmn4PRK544Ib/NjG4mb2UCCaL6x1hXXwpMb+0nbBDey+4ZkviLM/tM3qTnWcUQgAAAAASUVORK5CYII=) right center / 22.5px 13px no-repeat; padding: 0 22px 0 1px; }
.ᵇᵈᵍ.ᶠˣ span:last-of-type { color: #B933E1; }
.ᵇᵈᵍ.ⁿᵇ { border: 1px solid var(--color-accent3); background: linear-gradient(to right, #f9a31b, #f9a31b 25%, #fef3c0 25%, #fef3c0 50%, #bc4a9b 50%, #bc4a9b 75%, #403353 75%, #403353); }
/*!
Theme: Rebecca
Author: Victor Borja (http://github.com/vic) based on Rebecca Theme (http://github.com/vic/rebecca-theme)
License: ~ MIT (or more permissive) [via base16-schemes-source]
Maintainer: @highlightjs/core-team
Version: 2021.09.0
*/
.hljs{color:#f1eff8}.hljs-comment{color:#669}.hljs-tag{color:#a0a0c5}.hljs-operator,.hljs-punctuation,.hljs-subst{color:#f1eff8}.hljs-operator{opacity:.7}.hljs-bullet,.hljs-deletion,.hljs-name,.hljs-selector-tag,.hljs-template-variable,.hljs-variable{color:#a0a0c5}.hljs-attr,.hljs-link,.hljs-literal,.hljs-number,.hljs-symbol,.hljs-variable.constant_{color:#efe4a1}.hljs-class .hljs-title,.hljs-title,.hljs-title.class_{color:#ae81ff}.hljs-strong{font-weight:700;color:#ae81ff}.hljs-addition,.hljs-code,.hljs-string,.hljs-title.class_.inherited__{color:#6dfedf}.hljs-built_in,.hljs-doctag,.hljs-keyword.hljs-atrule,.hljs-quote,.hljs-regexp{color:#8eaee0}.hljs-attribute,.hljs-function .hljs-title,.hljs-section,.hljs-title.function_,.ruby .hljs-property{color:#2de0a7}.diff .hljs-meta,.hljs-keyword,.hljs-template-tag,.hljs-type{color:#7aa5ff}.hljs-emphasis{color:#7aa5ff;font-style:italic}.hljs-meta,.hljs-meta .hljs-keyword,.hljs-meta .hljs-string{color:#ff79c6}.hljs-meta .hljs-keyword,.hljs-meta-keyword{font-weight:700}

BIN
x/slkscr.woff2 Normal file

Binary file not shown.

BIN
x/val.1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B