Search code examples
linuxembeddedterminalasymmetric

Terminal I/O (how to emulate terminal read/wrtie with specific memory region?)


I'm working on the Embedded platform, where I have full access to directly read/write physical memory.

I'm also working on asymmetric processing, in which I have a real time application running concurrently with Linux but totally isolated from Linux.

I want to display the messages from RT app to Linux console (and perhaps send command from Linux to RT app). My current solution is to output everything from RT app to serial port. Then, in Linux I will read the serial port input.

This works but it seems unnecessary, because the RT apps and Linux is on the same physical machine. Thinking back how serial port works, it has a memory buffer and application can read/write to that buffer. Thus, I was wondering if it is possible to connect a terminal display to a specific memory region (i.e. 0x10000) and when RT app "print" some message to 0x10000, Linux terminal would display the message?


Solution

  • You could construct a sort of virtual serial port using "mailbox" techniques. I'll describe half of a simple working connection, you probably want one of these going in each direction so you can send commands and get responses.

    Reserve a chunk of memory during kernel initialization. Let's say 4k since that's often a page, but 256 or even 16 bytes will work too. Reserve a second for the other direction.

    When the "writer" of a channel wants to say something, it first checks if the first 32-bit word is zero. If it is, then starting from the 5th byte, it writes a message - textual or binary data, whatever, up to a maximum of 4k - 4 = 4092 bytes. Then it sets the first word equal to the count of bytes it has written.

    The receiver watches the byte count in the first word of the channel it is receiving. When it sees a non-zero byte count, it reads that many bytes from memory. Then it sets the byte count to zero, to signify to the writer that a new message may now be written at its convenience.

    The only thing this depends on is that you actually access the real memory or work through the same cache, and that you have an atomic write operation for writing the byte count (if you don't have 32-bit atomic writes, use a 16-bit count which is plenty anyway, or make the buffer smaller and use an 8-bit count). Since the writer can only set it to a nonzero value when it's zero, and the reader can only set it to a zero value when it's non-zero, it all works out.

    This is of course a simple mechanism, and either side can be blocked by the other. But you can design the components that source the messages to take that into account. You can also extend it by coming up with a way to have multiple messages in flight, or adding an additional priority or error-reporting channel in parallel.

    Oh, before you jump in and code this, do some web searching. I am certain there's already some mechanism like this or something else available for connecting your RT and linux components. But learning to do it yourself can be interesting too - and necessary if you run into this kind of problem on a smaller embedded system without an OS that provides the functionality for you.