On 03/05/2017 12:45 PM, Nadav Har'El wrote:

On Fri, Mar 3, 2017 at 11:45 AM, 'Sergiy Kibrik' via OSv Development 
<[email protected] <mailto:[email protected]>> wrote:

    Complete driver to properly work with xl console utility, i.e. full 
read/write
    access. Driver is extended to work with shared structure (ring) and event 
channel.

    Signed-off-by: Sergiy Kibrik <[email protected] 
<mailto:[email protected]>>
    ---
     drivers/xenconsole.cc | 65 
+++++++++++++++++++++++++++++++++++++++++++++++----
     drivers/xenconsole.hh | 14 +++++++++--
     2 files changed, 72 insertions(+), 7 deletions(-)

    diff --git a/drivers/xenconsole.cc b/drivers/xenconsole.cc
    index fe7c5bf..6ddac85 100644
    --- a/drivers/xenconsole.cc
    +++ b/drivers/xenconsole.cc
    @@ -5,32 +5,87 @@
      * BSD license as described in the LICENSE file in the top-level directory.
      */

    +#define XENHVM //FIXME hack to reveal hvm_get_parameter()
     #include <bsd/porting/netport.h> /* __dead2 defined here */
    +#include <bsd/porting/bus.h>
    +#include <machine/xen/xen-os.h>
     #include <xen/hypervisor.h>
    -
    +#include <xen/interface/hvm/params.h>
    +#include <xen/interface/io/console.h>
    +#include <xen/xen_intr.h>
    +#include <xen/evtchn.h>
    +#include <osv/mmio.hh>
     #include "xenconsole.hh"

     namespace console {

    +XEN_Console::
    +XEN_Console::XEN_Console()
    +    : _interface(0)
    +     , _evtchn(-1)
    +     , _irq(0)
    +     , _pfn(0)
    +{}
    +
    +void XEN_Console::handle_intr()
    +{
    +    _thread->wake();
    +}
    +
     void XEN_Console::write(const char *str, size_t len) {
    -       HYPERVISOR_console_write(str, len);
    +    assert(len > 0);
    +    if (!_interface) {
    +        HYPERVISOR_console_write(str, len);
    +        return;
    +    }
    +
    +    XENCONS_RING_IDX cons, prod;
    +    prod = _interface->out_prod;
    +    cons = _interface->out_cons;
    +    mb();
    +    while (len-- > 0)
    +        _interface->out[MASK_XENCONS_IDX(prod++, _interface->out)] = 
*str++;


It looks like your implementation has no flow control, and if you write too quickly before Xen empties the buffer, you abort instead of waiting for the buffer to be empties. I guess this is fine as a first implementation, but please add a FIXME on this limitation.
I should probably add some flow control right away. BTW, is there any way in 
OSv to check if we're in atomic/interrupt context? I suppose write() may also 
be executed in critical sections..

    +    wmb();
    +    assert(prod - cons <= sizeof(_interface->out));


I guess this assert() is related to my question about. I am curious why test it 
here instead of up-front, using len?

I will fix that.

    +    _interface->out_prod = prod;
     }

     void XEN_Console::dev_start()
     {
    +    _pfn = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN);
    +    _evtchn = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN);
    +
    +    if (!_pfn || !_evtchn)
    +        throw std::runtime_error("fail to get console params");
    +
    +     if (bind_caller_port_to_irqhandler(_evtchn, "xenconsole",
    +            XEN_Console::console_intr,
    +            static_cast<void*>(this),
    +            INTR_TYPE_MISC, &_irq) != 0)
    +        throw std::runtime_error("fail to bind evtchn");
    +
    +    _interface = (xencons_interface*)mmio_map(_pfn << PAGE_SHIFT, 
PAGE_SIZE);
     }

     void XEN_Console::flush()
     {
    +    notify_remote_via_evtchn(_evtchn);
     }

     bool XEN_Console::input_ready()
     {
    -       return false; /*TODO: support input */
    +    mb();


What does this memory barrier, with nothing above it, do?


I double checked console-multiplexer and mb is indeed redundant here.

    +    return _interface->in_cons != _interface->in_prod;
     }

     char XEN_Console::readch() {
    -    return '\0'; /*TODO: support input */
    +    XENCONS_RING_IDX cons;
    +    char c;
    +    assert(_interface);
    +    cons = _interface->in_cons;
    +    c = _interface->in[MASK_XENCONS_IDX(cons, _interface->in)];


I think you should gracefully handle the case where you had a false wakeup and called readch() when nothing is available, and return 0 in this case (as you can see, LineDiscipline::read_poll handles 0 being returned). I guess you need to check if cons is actually beyond prod?


I will do that.

    +    mb();
    +    _interface->in_cons = cons + 1;
    +    return c;
     }
    -
     }
    diff --git a/drivers/xenconsole.hh b/drivers/xenconsole.hh
    index ec43893..ca6d8cf 100644
    --- a/drivers/xenconsole.hh
    +++ b/drivers/xenconsole.hh
    @@ -9,13 +9,14 @@
     #define XEN_CONSOLE_HH

     #include "console-driver.hh"
    -#include "exceptions.hh"
    -#include <osv/interrupt.hh>
    +#include <xen/interface/xen.h>
    +#include <xen/interface/grant_table.h>

     namespace console {

     class XEN_Console : public console_driver {
     public:
    +    XEN_Console();
         virtual void write(const char *str, size_t len);
         virtual void flush();
         virtual bool input_ready();
    @@ -24,6 +25,15 @@ public:
     private:
         virtual void dev_start();
         virtual const char *thread_name() { return "xen-input"; }
    +    void handle_intr();
    +    static void console_intr(void *arg) {
    +        static_cast<XEN_Console*>(arg)->handle_intr();
    +    }
    +
    +    struct xencons_interface *_interface;
    +    int _evtchn;
    +    unsigned int _irq;
    +    unsigned long _pfn;
     };

Thank you for taking a look at this series!

--
regards,
Sergiy

--
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to