Embedded Serial Console Getty — How Do You Enable It?
Embedded serial getty setup is about aligning “where the kernel prints” with “where you get a login prompt.” In short: a serial TTY named in the kernel console= parameter usually gets serial-getty@.service from systemd-getty-generator; any other port needs an explicit systemctl enable --now serial-getty@<tty>.service. This is a minimal howto from systemd-getty-generator(8), the serial-getty@.service template, and the kernel Serial Console guide. No board baud folklore, pricing, or affiliates.
Which unit and which serial device?
One-line answer: The device is a kernel TTY node such as /dev/ttyS0, /dev/ttyAMA0, or /dev/ttymxc0. The unit is an instance of the serial-getty@.service template (for example serial-getty@ttyS0.service). If that TTY is a kernel console, the generator pulls the instance in at boot.
Split the paths:
- Kernel console path: Put something like
console=ttyS0,115200n8on the bootloader/kernel command line. You get kernel messages there, and the generator instantiatesserial-getty@ttyS0.service(systemd-getty-generator). - Extra port path: For a second UART that is not the kernel console, enable explicitly:
systemctl enable --now serial-getty@ttyS1.service
- The unit uses
BindsTo=dev-%i.deviceandAfter=dev-%i.device, so it follows the device unit. No device → no lasting getty. - Virtual terminals (
/dev/tty0family) belong withgetty@.service. Serial and hypervisor consoles useserial-getty@.
Quick checks:
ls -l /dev/ttyS* /dev/ttyAMA* /dev/ttymxc* 2>/dev/null
cat /proc/cmdline
systemctl status 'serial-getty@*.service'
The node name (%I) must match the instance name. Enabling serial-getty@ttyUSB0 while the console is ttyS0 targets a different device.
Baud rate and terminal settings?
One-line answer: Set speed/parity/bits first via kernel console=device,options. Stock getty uses --keep-baud, so it keeps the rate the kernel already opened. $TERM is passed through on the agetty command line.
Kernel options look like BBBBPNF (for example 115200n8). Default is 9600n8; the serial documentation caps baud at 115200 (Serial Console).
Typical serial-getty@.service ExecStart (paths/options can vary slightly by distro):
agetty --keep-baud 115200,57600,38400,9600 - $TERM
What that means:
--keep-baud: Keep the already configured rate (usually from the cmdline). The listed rates are BREAK-cycle candidates.- Need a fixed rate? Override ExecStart with a drop-in (for example
agetty 115200 %I $TERM—confirm against your unit andagetty(8)). $TERM: Match the host emulator (vt100,linux,xtermare common). A wrong TERM breaks curses/control sequences; it is not the same as a completely dead line.
The host serial client must use the same baud and 8N1. Mismatch between kernel, stty, and the client shows as garbage or a blank-looking screen.
# On the target (when another login path exists)
stty -F /dev/ttyS0 -a
# Host example (flag names differ by tool)
# picocom -b 115200 /dev/ttyUSB0
Do not invent a “this board must be X baud” story. Verify that cmdline, getty, and client agree.
What to check when nothing appears?
One-line answer: On a blank prompt, walk (1) device exists (2) console= / serial-getty@ name that device (3) baud and wiring (4) unit Active/Logs. Matching the kernel console TTY to the login TTY matters more than “just enable getty.”
Checklist:
- Wiring / TX-RX swap / power / GND — hardware before software.
/proc/cmdlineconsole=— the lastconsole=still matters for console policy; both the kernel and systemd read the cmdline.- Device node —
ls /dev/ttyS0and friends. SoCs use names likettyAMA0/ttymxc0. - Unit state
systemctl status serial-getty@ttyS0.service
journalctl -u serial-getty@ttyS0.service -b --no-pager
systemctl list-units 'serial-getty@*' --all
- Generator vs manual — serial
console=on the cmdline usually auto-starts getty. Manual enable is fine when that port is not the kernel console. - Kernel text but no login — suspect getty/unit/
BindsTodevice failure. Neither kernel nor login — suspect baud, port, wiring, or wrong TTY name. - Missing
agetty/getty— if the image omitted the binary, the unit fails immediately. Check the image package list.
| Symptom | Look first |
|---|---|
| Totally dead | Wiring, port index, host device node |
| Garbage characters | Baud/parity mismatch |
| Kernel log only, no login | serial-getty@ status/journal, agetty present |
| Unit failed | dev-%i.device, ExecStart path |
echo "cmdline: $(cat /proc/cmdline)"
systemctl is-active serial-getty@ttyS0.service || true
journalctl -u serial-getty@ttyS0.service -b -n 30 --no-pager
Frequently asked questions
Does console= alone start getty?
For a serial kernel console that is not a VT, systemd-getty-generator is designed to instantiate serial-getty@.service. Containers and some virtualized setups follow different rules.
getty@ttyS0 or serial-getty@ttyS0?
Use serial-getty@ for serial/non-VT. The VT getty@ template and options differ.
Can I change baud only in the unit? Yes, but early kernel console and login speed can diverge. Prefer keeping cmdline and getty aligned.
What should you remember?
Embedded serial getty is the triangle of TTY node + serial-getty@ instance + (usually) console=. Start baud with kernel options and --keep-baud. On a blank screen, check device, unit journal, and client speed in that order.
Where are the official sources?
- systemd-getty-generator(8)
- systemd for Administrators, Part XVI: Gettys on Serial Consoles
- Linux Serial Console
- Unit template:
serial-getty@.service(man agetty, distro path under/usr/lib/systemd/system/)