- Anonymous memory can be reserved without being backed: large mappings, MAP_NORESERVE and PROT_NONE are recorded and each page appears, zeroed, on first touch -- from trap() for the program, from uva2ka() for the kernel on its behalf. WebKit reserves 4 GB at start and touches a sliver; backing it all failed with ENOMEM and Epiphany aborted. - r8169: the 8168G generation and later (the laptop's 8168H, XID 541) are taken from the firmware's out-of-band mode, get their PLL powered, the receive gate opened, and their PHY reached through the OCP window. The PHY's power-down bit is cleared; the old code kept it while restarting autonegotiation. Untested on the hardware so far. - The network thread follows each device's link into lwIP. The link was read once at attach, 0.02 s into boot; real autonegotiation takes seconds, so on hardware the interface stayed down for good. - Twelve terminals, switched with Ctrl+Alt+F1..F12 by default: the keys X uses, so the console and the desktop agree. AltGr+F-key is gone from the defaults (chvt -c altgr+F brings it back). - SO_PASSCRED on Unix sockets, with SCM_CREDENTIALS delivered by recvmsg. WebKit sets it on its IPC sockets and aborted when refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
205 lines
6.5 KiB
C
205 lines
6.5 KiB
C
#include "core/types.h"
|
|
#include "arch/x86.h"
|
|
#include "core/defs.h"
|
|
#include "dev/kbd.h"
|
|
#include "uapi/posix.h"
|
|
#include "dev/vt.h" /* NVT -- how many terminals the chords reach */
|
|
#include "dev/input.h"
|
|
#include "dev/keymap.h"
|
|
|
|
// The chord, settable at run time through VT_SETCHORD.
|
|
//
|
|
// Ctrl+Alt+F1..F12 by default, the same keys X switches with. It used to be
|
|
// AltGr+F-key, chosen because nothing else claimed it -- but under X the
|
|
// server owns the keyboard and only Ctrl+Alt+F-key works, so the console and
|
|
// the desktop answered different keys for the same thing.
|
|
//
|
|
// Ctrl+Alt+minus and Ctrl+Alt+equals step to the previous and next terminal,
|
|
// for when you have two and do not care which number they are.
|
|
//
|
|
// Zero modifiers disables the chord; `chvt N` still works.
|
|
uint vt_chord_mods = CTL | ALT;
|
|
uint vt_chord_base = SCAN_F1;
|
|
|
|
// Which terminal an F-key scancode names: F1..F10 are 0x3B..0x44 and F11 and
|
|
// F12 sit apart, at 0x57 and 0x58. -1 for anything else.
|
|
static int
|
|
fkey_index(uint data)
|
|
{
|
|
if (data >= SCAN_F1 && data < SCAN_F1 + 10) return (int)(data - SCAN_F1);
|
|
if (data == 0x57) return 10;
|
|
if (data == 0x58) return 11;
|
|
return -1;
|
|
}
|
|
|
|
// The terminal a chord key names, from `base`: the F-keys by fkey_index, any
|
|
// other base as a run of ten consecutive scancodes -- a digit row is 1..9, 0,
|
|
// and the minus and equals after it are already the previous and next keys.
|
|
static int
|
|
chord_index(uint data, uint base)
|
|
{
|
|
int i = base == SCAN_F1 ? fkey_index(data)
|
|
: (data >= base && data < base + 10 ? (int)(data - base) : -1);
|
|
return i < NVT ? i : -1;
|
|
}
|
|
|
|
// Which scancodes are modifiers, and which are locks. Hardware facts rather
|
|
// than layout ones -- every layout agrees that 0x2A is a Shift key -- so they
|
|
// stay here while the character tables live in keymap.c.
|
|
static const uchar shiftcode[256] = {
|
|
[0x1D] = CTL,
|
|
[0x2A] = SHIFT,
|
|
[0x36] = SHIFT,
|
|
[0x38] = ALT,
|
|
[0x9D] = CTL,
|
|
[0xB8] = RALT // right Alt / AltGr -- see RALT in kbd.h
|
|
};
|
|
|
|
static const uchar togglecode[256] = {
|
|
[0x3A] = CAPSLOCK,
|
|
[0x45] = NUMLOCK,
|
|
[0x46] = SCROLLLOCK
|
|
};
|
|
|
|
// A key can produce more than one byte.
|
|
//
|
|
// consoleintr's contract with getc() is bytes: the serial line hands it raw
|
|
// UTF-8 already, and it would have no way to tell an encoded codepoint apart
|
|
// from a byte that happened to have the same value. So the keyboard encodes
|
|
// here and hands the bytes over one call at a time -- kbdintr loops until
|
|
// getc() returns negative, so a queue of at most four drains on its own
|
|
// before the next scancode is read.
|
|
static uchar pend[4];
|
|
static int pend_n, pend_i;
|
|
|
|
static int
|
|
queue_utf8(uint32 cp)
|
|
{
|
|
pend_i = 0;
|
|
if (cp < 0x80) {
|
|
pend_n = 0;
|
|
return (int)cp; // the common case: no queue at all
|
|
}
|
|
if (cp < 0x800) {
|
|
pend[0] = 0xC0 | (cp >> 6);
|
|
pend[1] = 0x80 | (cp & 0x3F);
|
|
pend_n = 2;
|
|
} else if (cp < 0x10000) {
|
|
pend[0] = 0xE0 | (cp >> 12);
|
|
pend[1] = 0x80 | ((cp >> 6) & 0x3F);
|
|
pend[2] = 0x80 | (cp & 0x3F);
|
|
pend_n = 3;
|
|
} else {
|
|
pend[0] = 0xF0 | (cp >> 18);
|
|
pend[1] = 0x80 | ((cp >> 12) & 0x3F);
|
|
pend[2] = 0x80 | ((cp >> 6) & 0x3F);
|
|
pend[3] = 0x80 | (cp & 0x3F);
|
|
pend_n = 4;
|
|
}
|
|
return pend[pend_i++];
|
|
}
|
|
|
|
int
|
|
kbdgetc(void)
|
|
{
|
|
static uint shift;
|
|
uint st, data;
|
|
uint32 cp;
|
|
|
|
if (pend_i < pend_n)
|
|
return pend[pend_i++]; // finish the last key first
|
|
pend_i = pend_n = 0;
|
|
|
|
st = inb(KBSTATP);
|
|
if((st & KBS_DIB) == 0)
|
|
return -1;
|
|
|
|
if(st & 0x20)
|
|
return -1;
|
|
|
|
data = inb(KBDATAP);
|
|
|
|
if(data == 0xE0){
|
|
shift |= E0ESC;
|
|
return 0;
|
|
}
|
|
|
|
// Feed /dev/input/event0 before the byte is turned into a character. This
|
|
// has to happen here rather than in a second handler because the byte can
|
|
// only be read from the port once -- whoever reads it owes it to everyone
|
|
// else. The console path below is untouched: both consumers see every key.
|
|
input_ps2_scancode(data, (shift & E0ESC) != 0);
|
|
|
|
// While something holds an exclusive grab on the keyboard, the console gets
|
|
// nothing. The shift/caps state below is still tracked, so releasing the
|
|
// grab does not leave the line discipline believing a modifier is held.
|
|
if(input_is_grabbed(INPUT_KBD)){
|
|
if(data & 0x80){
|
|
data = (shift & E0ESC ? data : data & 0x7F);
|
|
shift &= ~(shiftcode[data] | E0ESC);
|
|
} else {
|
|
shift |= shiftcode[data];
|
|
shift ^= togglecode[data];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if(data & 0x80){
|
|
data = (shift & E0ESC ? data : data & 0x7F);
|
|
shift &= ~(shiftcode[data] | E0ESC);
|
|
return 0;
|
|
} else if(shift & E0ESC){
|
|
data |= 0x80;
|
|
shift &= ~E0ESC;
|
|
}
|
|
|
|
shift |= shiftcode[data];
|
|
shift ^= togglecode[data];
|
|
|
|
// The switch chord, before the character tables, because there is no
|
|
// character to look up: it is a combination that means "show me a different
|
|
// terminal". What it means is decided in console.c, which is where the
|
|
// terminals are; this only has to name it. See console_vt_hotkey().
|
|
//
|
|
// The modifier test is an equality, not a mask. `shift & ALT` would fire on
|
|
// Ctrl+Alt+1 and on AltGr+1 as well, so a chord aimed at the host -- or a
|
|
// Polish keystroke -- would switch terminals behind your back. Exactly the
|
|
// modifiers named, and nothing else held.
|
|
if (vt_chord_mods != 0 &&
|
|
(shift & (CTL | SHIFT | ALT | RALT)) == vt_chord_mods) {
|
|
int i = chord_index(data, vt_chord_base);
|
|
if (i >= 0)
|
|
return KBD_VT_SWITCH + i;
|
|
if (data == SCAN_MINUS) return KBD_VT_PREV;
|
|
if (data == SCAN_EQUALS) return KBD_VT_NEXT;
|
|
}
|
|
|
|
// And Linux's own: Alt+F-key and Ctrl+Alt+F-key, whatever the chord is set
|
|
// to. Under X the terminal is in VT_PROCESS, console_vt_hotkey() lets the
|
|
// keys through, and X switches with them itself -- as on Linux.
|
|
if (chord_index(data, SCAN_F1) >= 0 &&
|
|
((shift & (CTL | SHIFT | ALT | RALT)) == ALT ||
|
|
(shift & (CTL | SHIFT | ALT | RALT)) == (CTL | ALT)))
|
|
return KBD_VT_SWITCH + chord_index(data, SCAN_F1);
|
|
|
|
cp = keymap_lookup(data, shift);
|
|
if (cp == 0)
|
|
return 0;
|
|
if (cp >= KBD_SPECIAL)
|
|
return (int)cp; // arrows and the rest, not characters
|
|
|
|
return queue_utf8(cp);
|
|
}
|
|
|
|
void
|
|
kbdintr(void)
|
|
{
|
|
consoleintr(kbdgetc);
|
|
}
|
|
|
|
// The two headers describe the same bits to two different audiences, and a
|
|
// mismatch would be silent: a chord set from userspace would simply never
|
|
// match, and the only symptom would be a key that does nothing.
|
|
_Static_assert(VTC_SHIFT == SHIFT && VTC_CTRL == CTL &&
|
|
VTC_ALT == ALT && VTC_RALT == RALT,
|
|
"include/uapi/posix.h VTC_* must mirror include/dev/kbd.h modifiers");
|