3.2 seL4-Untyped 练习

204 阅读11分钟

初始化程序

./init --tut untyped 
cd untyped_build
ninja 
./simulate

创建一个untyped capability

我们首次运行这一节的教程的时候会看到下面的输出,他列举除了所有这个root task被给予的untyped capability。

Booting all finished, dropped to user space
    CSlot       Paddr                   Size    Type
   0x139                       0        2^20    device untyped
   0x13a              0x1ffe0000        2^17    device untyped
   0x13b              0x20000000        2^29    device untyped
   0x13c              0x40000000        2^30    device untyped
   0x13d              0x80000000        2^30    device untyped
   0x13e              0xc0000000        2^29    device untyped
   0x13f              0xe0000000        2^28    device untyped
   0x140              0xf0000000        2^27    device untyped
   0x141              0xf8000000        2^26    device untyped
   0x142              0xfc000000        2^25    device untyped
   0x143              0xfe000000        2^23    device untyped
   0x144              0xfe800000        2^22    device untyped
   0x145              0xfec01000        2^12    device untyped
   0x146              0xfec02000        2^13    device untyped
   0x147              0xfec04000        2^14    device untyped
   0x148              0xfec08000        2^15    device untyped
   0x149              0xfec10000        2^16    device untyped
   0x14a              0xfec20000        2^17    device untyped
   0x14b              0xfec40000        2^18    device untyped
   0x14c              0xfec80000        2^19    device untyped
   0x14d              0xfed00000        2^20    device untyped
   0x14e              0xfee01000        2^12    device untyped
   0x14f              0xfee02000        2^13    device untyped
   0x150              0xfee04000        2^14    device untyped
   0x151              0xfee08000        2^15    device untyped
   0x152              0xfee10000        2^16    device untyped
   0x153              0xfee20000        2^17    device untyped
   0x154              0xfee40000        2^18    device untyped
   0x155              0xfee80000        2^19    device untyped
   0x156              0xfef00000        2^20    device untyped
   0x157              0xff000000        2^23    device untyped
   0x158              0xff800000        2^22    device untyped
   0x159              0xffc00000        2^21    device untyped
   0x15a              0xffe00000        2^20    device untyped
   0x15b              0xfff00000        2^19    device untyped
   0x15c              0xfff80000        2^18    device untyped
   0x15d              0xfffc0000        2^17    device untyped
   0x15e              0xfffe0000        2^16    device untyped
   0x15f              0xffff0000        2^15    device untyped
   0x160              0xffff8000        2^14    device untyped
   0x161              0xffffc000        2^13    device untyped
   0x162              0xffffe000        2^12    device untyped
   0x163              0xfffff000        2^11    device untyped
   0x164              0xfffff800        2^10    device untyped
   0x165              0xfffffc00        2^9     device untyped
   0x166              0xfffffe00        2^8     device untyped
   0x167              0xffffff00        2^7     device untyped
   0x168              0xffffff80        2^6     device untyped
   0x169              0xffffffc0        2^5     device untyped
   0x16a              0xffffffe0        2^4     device untyped
   0x16b             0x100000000        2^32    device untyped
   0x16c             0x200000000        2^33    device untyped
   0x16d             0x400000000        2^34    device untyped
   0x16e             0x800000000        2^35    device untyped
   0x16f            0x1000000000        2^36    device untyped
   0x170            0x2000000000        2^37    device untyped
   0x171            0x4000000000        2^38    device untyped
   0x172            0x8000000000        2^46    device untyped
   0x173          0x408000000000        2^45    device untyped
   0x174          0x608000000000        2^44    device untyped
   0x175          0x708000000000        2^43    device untyped
   0x176          0x788000000000        2^42    device untyped
   0x177          0x7c8000000000        2^41    device untyped
   0x178          0x7e8000000000        2^40    device untyped
   0x179          0x7f8000000000        2^39    device untyped
   0x17a                0x100000        2^20    untyped
   0x17b                0x200000        2^21    untyped
   0x17c                0x400000        2^22    untyped
   0x17d                0xb38000        2^15    untyped
   0x17e                0xb40000        2^18    untyped
   0x17f                0xb80000        2^19    untyped
   0x180                0xc00000        2^22    untyped
   0x181               0x1000000        2^24    untyped
   0x182               0x2000000        2^25    untyped
   0x183               0x4000000        2^26    untyped
   0x184               0x8000000        2^27    untyped
   0x185              0x10000000        2^27    untyped
   0x186              0x18000000        2^26    untyped
   0x187              0x1c000000        2^25    untyped
   0x188              0x1e000000        2^24    untyped
   0x189              0x1f000000        2^23    untyped
   0x18a              0x1f800000        2^22    untyped
   0x18b              0x1fe08800        2^11    untyped
   0x18c              0x1fe09000        2^12    untyped
   0x18d              0x1fe0a000        2^13    untyped
   0x18e              0x1fe0c000        2^14    untyped
   0x18f              0x1fe10000        2^16    untyped
   0x190              0x1fe20000        2^17    untyped
   0x191              0x1fe40000        2^18    untyped
   0x192              0x1fe80000        2^19    untyped
   0x193              0x1ff00000        2^19    untyped
   0x194              0x1ff80000        2^18    untyped
   0x195              0x1ffc0000        2^17    untyped

在程序输出的log的末尾,有一个报错:

<<seL4(CPU 0) [decodeUntypedInvocation/98 T0xffffff801fe08400 "rootserver" @4012d5]: Untyped Retype: Requested UntypedItem size too s>
main@main.c:49 [Cond failed: error != seL4_NoError]
        Failed to retype

这个错误产生的原因是在程序中尝试了创建一个大小为0的untyped。

    error = seL4_Untyped_Retype(parent_untyped, // the untyped capability to retype
                                seL4_UntypedObject, // type
                                untyped_size_bits,  //size
                                seL4_CapInitThreadCNode, // root
                                0, // node_index
                                0, // node_depth
                                child_untyped, // node_offset
                                1 // num_caps
                                );
    ZF_LOGF_IF(error != seL4_NoError, "Failed to retype");

练习: 计算子untyped需要的空间大小,以便子untyped能用于创建列表中所有的object。需要注意的是,object的大小是用bit衡量的,2的幂那个。

所以我们看看怎么计算下这个东西的大小:

    // TODO work out what size object we need to create to be able to create all of the objects
    // listed above. Remember that sizes are in bits, that is, the exponents of powers of two.
    seL4_Word untyped_size_bits = 0;
    seL4_CPtr parent_untyped = 0;
    seL4_CPtr child_untyped = info->empty.start;

我们看这个列表

    // list of general seL4 objects
    seL4_Word objects[] = {seL4_TCBObject, seL4_EndpointObject, seL4_NotificationObject};
    // list of general seL4 object size_bits
    seL4_Word sizes[] = {seL4_TCBBits, seL4_EndpointBits, seL4_NotificationBits};

他这里seL4_TCBBits是11,后面两个分别是5和4,显然这两个加起来还不够一个11,我们只需要两个seL4_TCBBits大小的untype就行了。为啥是两个呢,因为实在是没法表示为整数了(话说这个计算方法还真是麻烦)

seL4_Word untyped_size_bits = seL4_TCBBits + 1;

运行成功后,我们看到如下的输出:

<<seL4(CPU 0) [decodeInvocation/645 T0xffffff801fe08400 "rootserver" @4012d5]: Attempted to invoke a null cap #407.>>
main@main.c:57 [Cond failed: error != seL4_NoError]
        Failed to set priority

创建一个TCB Object

先来看看错误的原因是啥。

    // use the slot after child_untyped for the new TCB cap:
    seL4_CPtr child_tcb = child_untyped + 1;
    /* TODO create a TCB in CSlot child_tcb */

    // try to set the TCB priority
    error = seL4_TCB_SetPriority(child_tcb, seL4_CapInitThreadTCB, 10);
    ZF_LOGF_IF(error != seL4_NoError, "Failed to set priority");

这里的child_tcb只是一个空的slot,用其设定属性肯定是不行的。 练习:child_untyped创建一个TCB object,并且把它的capability放置到child_tcbslot里。

    // use the slot after child_untyped for the new TCB cap:
    seL4_CPtr child_tcb = child_untyped + 1;
    seL4_Untyped_Retype(child_untyped, seL4_TCBObject, 0, seL4_CapInitThreadCNode, 0, 0, child_tcb, 1);

在这里,我们首先是从child_untyped上面来创建于一个seL4_TCBObject类型的对象。我们这个child_untyped是刚才retyped那一块大的untyped得来的。 然后seL4_CapInitThreadCNode和后面的两个参数指定了要把新生成的node放到我们的这个CNode里面,放置的位置是untyped后面一个的slot位置,这个位置就是child_untyped后面的那个空位置。为啥他知道这个是空的,因为刚才child_untyped是这么来的:

seL4_CPtr child_untyped = info->empty.start;

然后我再运行看一下:

main@main.c:65 [Cond failed: cap_id == 0]
        Endpoint cap is null cap

嗯,这次属性设定就成功了。我们可以接着往下看了。

创建一个endpoint object

我们来看上面的报错是咋回事。

    seL4_CPtr child_ep = child_tcb + 1;
    /* TODO create an endpoint in CSlot child_ep */

    // identify the type of child_ep
    uint32_t cap_id = seL4_DebugCapIdentify(child_ep);
    ZF_LOGF_IF(cap_id == 0, "Endpoint cap is null cap");

问题也很简单,这个child_ep也是刚指定一个空的slot,还没retype。

    // use the slot after child_tcb for the new endpoint cap:
    seL4_CPtr child_ep = child_tcb + 1;
    seL4_Untyped_Retype(child_untyped, seL4_EndpointObject, 0, seL4_CapInitThreadCNode, 0, 0, child_ep, 1);

这很容易理解了,不用重复讲了。不过这个retype还挺有意思的,前面创建了一个之后,后面也不用指定起始地址,直接继续用就行了。

这就又往下进行了:

<<seL4(CPU 0) [decodeBindNotification/1635 T0xffffff801fe08400 "rootserver" @4012d5]: TCB BindNotification: Notification is invalid.>>
main@main.c:75 [Cond failed: error != seL4_NoError]
        Failed to bind notification.

创建一个notification object

到这里应该就很轻车熟路了:

// use the slot after child_ep for the new notification cap:
    seL4_CPtr child_ntfn = child_ep + 1;
    // TODO create a notification object in CSlot child_ntfn

    // try to use child_ntfn
    error = seL4_TCB_BindNotification(child_tcb, child_ntfn);
    ZF_LOGF_IF(error != seL4_NoError, "Failed to bind notification.");

照着上面改吧改吧:

    // use the slot after child_ep for the new notification cap:
    seL4_CPtr child_ntfn = child_ep + 1;
    // TODO create a notification object in CSlot child_ntfn
    seL4_Untyped_Retype(child_untyped, seL4_NotificationObject, 0, seL4_CapInitThreadCNode, 0, 0, child_ntfn, 1);

    // try to use child_ntfn
    error = seL4_TCB_BindNotification(child_tcb, child_ntfn);
    ZF_LOGF_IF(error != seL4_NoError, "Failed to bind notification.");

这就来到了下一步:

<<seL4(CPU 0) [decodeUntypedInvocation/166 T0xffffff801fe08400 "rootserver" @4012d5]: Untyped Retype: Slot #407 in destination window>
main@main.c:84 [Cond failed: error != seL4_NoError]
        Failed to create endpoints.

删除object

    // TODO revoke the child untyped

    // allocate the whole child_untyped as endpoints
    // Remember the sizes are exponents, so this computes 2^untyped_size_bits / 2^seL4_EndpointBits:
    seL4_Word num_eps = BIT(untyped_size_bits - seL4_EndpointBits);
    error = seL4_Untyped_Retype(child_untyped, seL4_EndpointObject, 0, seL4_CapInitThreadCNode, 0, 0, child_tcb, num_eps);
    ZF_LOGF_IF(error != seL4_NoError, "Failed to create endpoints.");

最后一部分代码,是想把整个untyped对象全都创建成seL4_EndpointBits。这肯定是会失败的,因为前面我们已经用了很多对象了。要想这么做需要先把之前的object都删掉。

    error = seL4_CNode_Revoke(seL4_CapInitThreadCNode, child_untyped, seL4_WordBits);
    assert(error == seL4_NoError);

使用seL4_CNode_Revoke删除所有子object。 再次执行,结果就是成功了:

   0x192              0x1fe80000        2^19    untyped
   0x193              0x1ff00000        2^19    untyped
   0x194              0x1ff80000        2^18    untyped
   0x195              0x1ffc0000        2^17    untyped
Success

更多练习

  • 在指定的物理地址分配object
  • 创建一个简单的对象分配器来分配seL4对象

第二个比较简单,其实就是循环遍历数组,没啥好说的,我觉得需要注意的就是要从大到小遍历。 第一个问题从指定的物理地址分配object,我不知道我理解的是否正确,我们在程序中可以获取到每个untyped的地址:

    printf("    CSlot   \tPaddr           \tSize\tType\n");
    for (seL4_CPtr slot = info->untyped.start; slot != info->untyped.end; slot++) {
        seL4_UntypedDesc *desc = &info->untypedList[slot - info->untyped.start];
        printf("%8p\t%16p\t2^%d\t%s\n", (void *) slot, (void *) desc->paddr, desc->sizeBits, desc->isDevice ? "device untyped" : "untyped");
    }
    seL4_Error error;

指定物理地址之后我只要遍历这个数组找到对应的地址应该就是可以的了。