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,115200n8 on the bootloader/kernel command line. You get kernel messages there, and the generator instantiates serial-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.device and After=dev-%i.device, so it follows the device unit. No device → no lasting getty.
  • Virtual terminals (/dev/tty0 family) belong with getty@.service. Serial and hypervisor consoles use serial-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 and agetty(8)).
  • $TERM: Match the host emulator (vt100, linux, xterm are 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:

  1. Wiring / TX-RX swap / power / GND — hardware before software.
  2. /proc/cmdline console= — the last console= still matters for console policy; both the kernel and systemd read the cmdline.
  3. Device node — ls /dev/ttyS0 and friends. SoCs use names like ttyAMA0 / ttymxc0.
  4. Unit state
systemctl status serial-getty@ttyS0.service
journalctl -u serial-getty@ttyS0.service -b --no-pager
systemctl list-units 'serial-getty@*' --all
  1. Generator vs manual — serial console= on the cmdline usually auto-starts getty. Manual enable is fine when that port is not the kernel console.
  2. Kernel text but no login — suspect getty/unit/BindsTo device failure. Neither kernel nor login — suspect baud, port, wiring, or wrong TTY name.
  3. Missing agetty/getty — if the image omitted the binary, the unit fails immediately. Check the image package list.
SymptomLook first
Totally deadWiring, port index, host device node
Garbage charactersBaud/parity mismatch
Kernel log only, no loginserial-getty@ status/journal, agetty present
Unit faileddev-%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?