I'm trying to boot the linux kernel (v3.16.1) on a simulation model of a Sparc v8 processor for an academic project.
The simulation model consists of a cpu, memory, timer and a simple polling based output device. We've modified the kernel so that a bootloader is not necessary. We directly put the kernel image in memory, set up some necessary variables and jump into kernel code. We have a rudimentary polling based output-device, and we've been able to direct output of printk to this device.
The kernel boots all the way up to the start of "/init". After this point no output is visible. Just before this point, there's a warning displayed : "Warning: unable to open an initial console." My filesystem image seems to be fine, and contains a /dev/console node (I checked this with Qemu).
My understanding is that while printk works fine (using an early console), user processes need a device node with a proper device driver to be set up. Printk works fine, so is there a way to see all writes by user processes to the console via printk ? There's an existing driver called "ttyprintk" which sends all writes to printk. I enabled it and tried using it by passing "console=ttyprintk" kernel argument, but this gives the same warning. The kernel is not able to open "/dev/console" for writing.
My questions are :
Can I write a simple character device driver and use it as my console ? Inside this driver I plan to send all writes to printk. Is this possible ?
How can I ask the kernel to use this as my console ? Would kernel argument "console = /dev/MyDriver" work ?
Is there a simpler way to have /init and other user processes use my rudimentary output device as a console ?
4.Is there some other reason that could be causing the "Warning: unable to open an initial console." message ?
Thanks for any hints. I am new to kernel programming.
-neha
They way the /dev/console
driver works is to attach to some other tty device (or devices!), which is/are then used for the console. The sysfs attribute active
of the console device (try /sys/class/tty/console/active
) will tell you what device the console is attached to at the moment.
The kernel also tends to log console changes:
[ 0.186989] dw-apb-uart ffc02000.serial0: ttyS0 at MMIO 0xffc02000 (irq = 194, base_baud = 6250000) is a 16550A
[ 0.755529] console [ttyS0] enabled
In the above log, once the serial port device was created the kernel decided to use it as a console. This refers to the binding of the device to the driver in the kernel, not the device node in /dev. The latter does not matter here. Also understand that the attachment of the console device to a tty happens in the kernel. /dev/console
is not a symlink to another device node.
The kernel has chosen ttyS0 because I told it to via the kernel command line, console=ttyS0,115200n8
. Without a console argument, the kernel uses the first console that registers with register_console()
.
So the question here is how can one get /dev/ttyprintk to be attached to /dev/console. And the answer appears to be you can't.
A work around might be to create a custom initramfs that changes the /dev/console device node from major 5 minor 1 to use minor 3, thus changing it into /dev/ttyprintk. Or symlink to achieve the same thing. This should get init to use ttyprintk as its stdin/stdout/stderr.
In your example, writing a tty/console driver for your output device would be the right way. Make it the console and then the kernel sends printk there.