[Barrelfish-users] How to write user space driver for ARM?

Gerd Zellweger gerd.zellweger at inf.ethz.ch
Thu Jul 4 12:04:43 CEST 2013


Hi Wang Nan,

You are right, there are currently no user-space drivers for ARM in the
tree and an easy way for user-space programs to access device register is
currently missing (as well as interrupt forwarding to user-space). We are
currently investing some effort in better support for the pandaboard
platform. Therefore, we need this as well. I am currently working on a
solution that works similar to what we have for PCI on x86 right now. I
hope this will be ready soon and we can release it with the next release.

If you want to test my changes prematurely, let me know. I can probably
send you patches in a couple of days.

Gerd


On Wed, Jul 3, 2013 at 3:03 PM, Wang Nan <wangnan0 at huawei.com> wrote:

> Hi,
> I can't find a reference implementation of ARM driver. I implement an UART
> driver my self. Here I want you to provide some suggestion on my design.
>
> The key problem is to allow user space program to access ARM's memory
> mapping registers.
>
> Following is my design and code fragment:
>
> 1. Export RegionType_PlatformData to init during booting:
>
> --------------
> /* called by spawn_bsp_init() */
> static void
> create_arch_caps(void)
> {
>         errval_t err;
>         /* sysctl */
>         err = create_caps_to_cnode(0x20000000, 0x1000,
> RegionType_PlatformData, &spawn_state, bootinfo);
>         assert(err_is_ok(err));
>
>         /* uart 0~2 */
>         err = create_caps_to_cnode(0x20001000, 0x1000,
> RegionType_PlatformData, &spawn_state, bootinfo);
>         assert(err_is_ok(err));
>         err = create_caps_to_cnode(0x20002000, 0x1000,
> RegionType_PlatformData, &spawn_state, bootinfo);
>         assert(err_is_ok(err));
>         err = create_caps_to_cnode(0x20003000, 0x1000,
> RegionType_PlatformData, &spawn_state, bootinfo);
>         assert(err_is_ok(err));
> }
> --------------
>
> 2. pass pacn to mem_serv in init:
> --------------
> diff --git a/usr/init/spawn.c b/usr/init/spawn.c
> index e343bbe..4bf35b4 100644
> --- a/usr/init/spawn.c
> +++ b/usr/init/spawn.c
> @@ -35,6 +35,21 @@ errval_t initialize_mem_serv(struct spawninfo *si)
>          return err_push(err, INIT_ERR_COPY_SUPERCN_CAP);
>      }
>
> +    /* copy physcn to memory server */
> +    struct capref init_pacn_cap = {
> +       .cnode = cnode_root,
> +        .slot  = ROOTCN_SLOT_PACN,
> +    };
> +
> +    struct capref child_pacn_cap = {
> +        .cnode = si->rootcn,
> +        .slot  = ROOTCN_SLOT_PACN,
> +    };
> +
> +    err = cap_copy(child_pacn_cap, init_pacn_cap);
> +    if (err_is_fail(err)) {
> +        return err_push(err, INIT_ERR_COPY_SUPERCN_CAP);
> +    }
>      return SYS_ERR_OK;
>  }
> ------------
>
> 3. add a new function to mem_serv to let it alloc PhysAddr
>
>
> --------------
> diff --git a/if/mem.if b/if/mem.if
> index e487bf5..71469cf 100644
> --- a/if/mem.if
> +++ b/if/mem.if
> @@ -23,4 +23,10 @@ interface mem "Memory allocation RPC interface" {
>    // XXX: Trusted call, may only be called by monitor.
>    // Should move this to its own binding.
>    rpc free_monitor(in give_away_cap mem_cap, in genpaddr base, in uint8
> bits, out errval err);
> +
> +  rpc allocate_devram( in genpaddr addr,
> +                       in uint8 sizebit,
> +                       out errval ret,
> +                       out give_away_cap devmem_cap );
>  }
> --------------
>
>
>
> 4. ugly code: let mem_serv alloc devram: I put the code fragment at the
> end of this mail.
>
> 5. driver: use devram:
>
> +       struct mem_rpc_client *mem = get_mem_client();
> +       assert(mem != NULL);
> +
> +       errval_t errrpc, err;
> +       struct capref serial_cap;
> +       errrpc = mem->vtbl.allocate_devram(mem, 0x20001000ULL, 12, &err,
> &serial_cap);
> +       printf("allocate_devram rpc end\n");
> +       assert(err_is_ok(errrpc));
> +       assert(err_is_ok(err));
> +       void *uart_base;
> +       err = vspace_map_one_frame_attr(&uart_base,
> +                       0x1000,
> +                       serial_cap,
> +                       KPI_PAGING_FLAGS_READ | KPI_PAGING_FLAGS_WRITE |
> KPI_PAGING_FLAGS_NOCACHE,
> +                       NULL,
> +                       NULL);
> +       assert(err_is_ok(err));
> +
> +       printf("after vspace_map_one_frame_attr\n");
> +       printf("uart_base=%p\n", uart_base);
> +       assert(uart_base != NULL);
> +
> +       struct hi1380_uart_t *dev;
> +       hi1380_uart_initialize(dev, uart_base);
>
>
> My driver works, but code is ugly, especially the mem_serv part. I think
> the additional rpc interface
> should be avoid.
>
> Could anyone can provide a 'standard way' to write such driver?
>
>
>
>
>
> Following code allows mem_serv management devram:
> --------------
> diff --git a/usr/mem_serv/mem_serv.c b/usr/mem_serv/mem_serv.c
> index fba93e2..556a506 100644
> --- a/usr/mem_serv/mem_serv.c
> +++ b/usr/mem_serv/mem_serv.c
> @@ -467,6 +467,96 @@ initialize_ram_alloc(void)
>      return SYS_ERR_OK;
>  }
>
> +struct alloc_devram_response_reply {
> +       struct mem_binding *b;
> +       errval_t err;
> +       struct capref cap;
> +};
> +static void
> +mem_allocate_devram_handler_response_done(void *args)
> +{
> +       errval_t err;
> +       struct alloc_devram_response_reply *r = args;
> +       if(!capref_is_null(r->cap)) {
> +               err = cap_delete(r->cap);
> +               if(err_is_fail(err)) {
> +                       DEBUG_ERR(err, "cap_delete failed after send. This
> memory will leak.");
> +               }
> +               err = msa.a.free(&msa.a, r->cap);
> +               if(err_is_fail(err)) {
> +                       DEBUG_ERR(err, "msa.a.free failed after send. This
> memory will leak.");
> +               }
> +       }
> +       free(r);
> +}
> +static void
> +mem_allocate_devram_handler_reply(void *args)
> +{
> +       struct alloc_devram_response_reply *r = args;
> +       struct mem_binding *b = r->b;
> +       errval_t err;
> +
> +       err = b->tx_vtbl.allocate_devram_response(b,
> MKCONT(mem_allocate_devram_handler_response_done, r),
> +                       r->err, r->cap);
> +       if (err_is_fail(err)) {
> +               if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
> +                       err = b->register_send(b, get_default_waitset(),
> MKCONT(mem_allocate_devram_handler_reply ,r));
> +                       assert(err_is_ok(err));
> +               } else {
> +                       DEBUG_ERR(err, "failed to reply to memory
> request");
> +                       mem_allocate_devram_handler_response_done(r);
> +               }
> +       }
> +}
> +
> +static void
> +mem_allocate_devram_handler(struct mem_binding *_binding, mem_genpaddr_t
> addr, uint8_t sizebit)
> +{
> +       /* find the device */
> +       struct capref phyaddr_cap = {
> +               .cnode = cnode_phyaddr,
> +               .slot = 0,
> +       };
> +
> +       errval_t err = SYS_ERR_KERNEL_MEM_INVALID;
> +       for (int i = 0; i < bi->regions_length; i++) {
> +               if (bi->regions[i].mr_type != RegionType_PlatformData)
> +                       continue;
> +
> +               if (bi->regions[i].mr_base == addr) {
> +                       if (bi->regions[i].mr_bits != sizebit)
> +                               break;
> +                       err = SYS_ERR_OK;
> +                       break;
> +               }
> +               phyaddr_cap.slot++;
> +       }
> +
> +       struct capref devframe;
> +       err = msa.a.alloc(&msa.a, &devframe);
> +       if (err_is_fail(err))
> +               goto out;
> +
> +       err = cap_retype(devframe, phyaddr_cap, ObjType_DevFrame, sizebit);
> +
> +
> +       struct alloc_devram_response_reply *r;
> +out:
> +       r = malloc(sizeof(*r));
> +       assert(r != NULL);
> +       r->b = _binding;
> +       if (err_is_ok(err)) {
> +
> +
> +               r->err = err;
> +               r->cap = devframe;
> +               /* need delete?? */
> +       } else {
> +               r->err = SYS_ERR_KERNEL_MEM_LOOKUP;
> +               r->cap = NULL_CAP;
> +       }
> +       mem_allocate_devram_handler_reply(r);
> +}
> +
>  static void export_callback(void *st, errval_t err, iref_t iref)
>  {
>      assert(err_is_ok(err));
> @@ -479,6 +569,7 @@ static struct mem_rx_vtbl rx_vtbl = {
>      .allocate_call = mem_allocate_handler,
>      .available_call = mem_available_handler,
>      .free_monitor_call = mem_free_handler,
> +    .allocate_devram_call = mem_allocate_devram_handler,
>  };
>  static errval_t connect_callback(void *st, struct mem_binding *b)
> --------------
>
>
>
> _______________________________________________
> Barrelfish-users mailing list
> Barrelfish-users at lists.inf.ethz.ch
> https://lists.inf.ethz.ch/mailman/listinfo/barrelfish-users
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: https://lists.inf.ethz.ch/pipermail/barrelfish-users/attachments/20130704/bdd90724/attachment.html 


More information about the Barrelfish-users mailing list