Hello,
I have been trying to get some sensible behaviour from various programs running in L4Re that wish to read from standard input, hopefully using the UART, since standard output is successfully sent across the serial connection. However, it appears that Ned does something rather undesirable with the input stream.
If I modify the hello example to use fgets and deploy it without Ned (the hello.cfg example in conf/examples), as long as some kind of serial initialisation has occurred, I can enter characters at the serial console and have the program read them. However, if I deploy the same code using Ned (the hello.cfg example in conf/examples), fgets repeatedly returns NULL.
Strangely, if I follow the instructions in the L4Re documentation...
https://l4re.org/doc/l4re_servers_ned.html#l4re_ned_interactive
The ned-prompt program itself just prints "Cmd>" over and over again, failing to read anything. It is as if non-blocking I/O has been enabled, although ned- prompt appears to use readline, so I imagine that there is likely to be a somewhat different explanation. Attempting to enforce non-blocking input using fcntl in the hello example also does not help.
Has anyone any suggestions as to why these things do not work? I have tried this on physical hardware as well as in QEMU.
Thanks in advance,
Paul
Hi Paul,
thanks for bringing this up. I can reproduce this on my machine. I don't fully understand the root cause for this behavior quite yet, but I can provide a way to continue.
First, there is a fault in the documentation for the ned-prompt startup, the correct lua line is:
l:start({ log = L4.Env.log, caps = { svr = cmd} }, "rom/ned-prompt")
Contrary to the documentation you linked to, `log` must be declared outside of the `caps` table. With this fix, ned-prompt waits for input.
For the hello startup the same fix applies. Explicitly specifying the log capability within the table parameter of the call to `start()` leads to a working input:
L4.default_loader:start({ log = L4.Env.log }, "rom/hello")
The difference between the case with log parameter set to L4.Env.log and without log parameter - so an implicit/default log capability - is that L4.Env.log references Moe to handle the log interactions. Otherwise, the kernel's log is directly used, which seems to behave differently. I don't know why yet.
Cheers, Philipp
On 9/19/23 00:05, Paul Boddie wrote:
Hello,
I have been trying to get some sensible behaviour from various programs running in L4Re that wish to read from standard input, hopefully using the UART, since standard output is successfully sent across the serial connection. However, it appears that Ned does something rather undesirable with the input stream.
If I modify the hello example to use fgets and deploy it without Ned (the hello.cfg example in conf/examples), as long as some kind of serial initialisation has occurred, I can enter characters at the serial console and have the program read them. However, if I deploy the same code using Ned (the hello.cfg example in conf/examples), fgets repeatedly returns NULL.
Strangely, if I follow the instructions in the L4Re documentation...
https://l4re.org/doc/l4re_servers_ned.html#l4re_ned_interactive
The ned-prompt program itself just prints "Cmd>" over and over again, failing to read anything. It is as if non-blocking I/O has been enabled, although ned- prompt appears to use readline, so I imagine that there is likely to be a somewhat different explanation. Attempting to enforce non-blocking input using fcntl in the hello example also does not help.
Has anyone any suggestions as to why these things do not work? I have tried this on physical hardware as well as in QEMU.
Thanks in advance,
Paul
l4-hackers mailing list l4-hackers@os.inf.tu-dresden.de https://os.inf.tu-dresden.de/mailman/listinfo/l4-hackers
Hi Paul,
I was a tad to quick on the send button. I have to correct myself.
Moe starts the init task (ned or e.g. hello) and provides the kernel's log interface in Env::Log. When ned starts a program we have to differentiate two cases: A) we explicitly provide a log capability, and B) we do not provide a log capability or we provide arguments of the format {'tag', 'color'}.
The invocations of `start()` I mentioned in my previous email use case A) and provide L4.Env.log, which references the kernel's log interface. (contrary to my last email). Because ned is started as init task and thus gets access to the kernel log interface via this capability. Specifying this again forwards the kernel's log interface to the new application (Nothing to recommend in a productive setup, of course).
In case B) (and assuming L4.default_loader), ned issues a call to moe to create a new log interface for this new application. Thus, all log calls are routed through moe. Now moe's log interface is only able to do output and cannot provide input.
In my understanding, fgets() is implemented to call onto the log capability to read data from it. In case B), reads are not supported and an error is returned which results in the perceived return value of NULL.
So it's actually the other way round than described in my last email.
Cheers, Philipp
On 9/19/23 11:56, Philipp Eppelt wrote:
Hi Paul,
thanks for bringing this up. I can reproduce this on my machine. I don't fully understand the root cause for this behavior quite yet, but I can provide a way to continue.
First, there is a fault in the documentation for the ned-prompt startup, the correct lua line is:
l:start({ log = L4.Env.log, caps = { svr = cmd} }, "rom/ned-prompt")
Contrary to the documentation you linked to, `log` must be declared outside of the `caps` table. With this fix, ned-prompt waits for input.
For the hello startup the same fix applies. Explicitly specifying the log capability within the table parameter of the call to `start()` leads to a working input:
L4.default_loader:start({ log = L4.Env.log }, "rom/hello")
The difference between the case with log parameter set to L4.Env.log and without log parameter - so an implicit/default log capability - is that L4.Env.log references Moe to handle the log interactions. Otherwise, the kernel's log is directly used, which seems to behave differently. I don't know why yet.
Cheers, Philipp
On 9/19/23 00:05, Paul Boddie wrote:
Hello,
I have been trying to get some sensible behaviour from various programs running in L4Re that wish to read from standard input, hopefully using the UART, since standard output is successfully sent across the serial connection. However, it appears that Ned does something rather undesirable with the input stream.
If I modify the hello example to use fgets and deploy it without Ned (the hello.cfg example in conf/examples), as long as some kind of serial initialisation has occurred, I can enter characters at the serial console and have the program read them. However, if I deploy the same code using Ned (the hello.cfg example in conf/examples), fgets repeatedly returns NULL.
Strangely, if I follow the instructions in the L4Re documentation...
https://l4re.org/doc/l4re_servers_ned.html#l4re_ned_interactive
The ned-prompt program itself just prints "Cmd>" over and over again, failing to read anything. It is as if non-blocking I/O has been enabled, although ned- prompt appears to use readline, so I imagine that there is likely to be a somewhat different explanation. Attempting to enforce non-blocking input using fcntl in the hello example also does not help.
Has anyone any suggestions as to why these things do not work? I have tried this on physical hardware as well as in QEMU.
Thanks in advance,
Paul
l4-hackers mailing list l4-hackers@os.inf.tu-dresden.de https://os.inf.tu-dresden.de/mailman/listinfo/l4-hackers
l4-hackers mailing list l4-hackers@os.inf.tu-dresden.de https://os.inf.tu-dresden.de/mailman/listinfo/l4-hackers
On Tuesday, 19 September 2023 14:34:42 CEST Philipp Eppelt wrote:
I was a tad to quick on the send button. I have to correct myself.
No problem! I appreciated both replies.
Moe starts the init task (ned or e.g. hello) and provides the kernel's log interface in Env::Log. When ned starts a program we have to differentiate two cases: A) we explicitly provide a log capability, and B) we do not provide a log capability or we provide arguments of the format {'tag', 'color'}.
OK. This makes sense. I previously modified the ned.lua file to allow the log capability to be specified in certain cases, allowing programs to display their output in a graphical terminal (fbterminal), for example. It occurs to me now that I didn't need to make this modification: I previously thought that the log item was only there to specify format parameters.
The invocations of `start()` I mentioned in my previous email use case A) and provide L4.Env.log, which references the kernel's log interface. (contrary to my last email). Because ned is started as init task and thus gets access to the kernel log interface via this capability. Specifying this again forwards the kernel's log interface to the new application (Nothing to recommend in a productive setup, of course).
From the behaviour, I had assumed that a program started directly by moe would
get the same log interface as the one used by the kernel. The clue was in the way the kernel debugger could be invoked using Escape with the -serial_esc option and then used, suggesting that the reception of data over the UART was not broken. Indeed, I think that omitting the -serial_esc option seems to prevent input from working.
As far as whether passing the log to the application is productive, it might be adequate in the specific situation I am dealing with, which is to provide some interaction with a single-board computer over a UART connection.
In case B) (and assuming L4.default_loader), ned issues a call to moe to create a new log interface for this new application. Thus, all log calls are routed through moe. Now moe's log interface is only able to do output and cannot provide input.
Right. I had suspected that some kind of write-only log had been introduced.
In my understanding, fgets() is implemented to call onto the log capability to read data from it. In case B), reads are not supported and an error is returned which results in the perceived return value of NULL.
So it's actually the other way round than described in my last email.
I do have some idea of the architectural details, having looked into the C library support in the past, but I do not find it particularly straightforward to track down the exact places where the generic C library support meets the L4Re abstractions.
I imagine that there would have to be some kind of process hierarchy and perhaps some multiplexing to be introduced to manage kernel log access amongst user-level applications. In my own experiments, one of the next things I plan to do is to provide standard input and output streams to processes via pipes, which follows on from my investigations into creating and invoking tasks. I suppose that such facilities are beyond the scope of the C library support in L4Re, however.
Providing L4.Env.log to my application does indeed allow interactive communication over the UART, so this simple adjustment fixed my immediate problem. Thank you for your guidance on this matter!
Regards,
Paul
l4-hackers@os.inf.tu-dresden.de