1 /*
2  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *               Alexander Warg <warg@os.inf.tu-dresden.de>,
4  *               Frank Mehnert <fm3@os.inf.tu-dresden.de>,
5  *               Michael Hohmuth <hohmuth@os.inf.tu-dresden.de>,
6  *               Jork Löser <jork@os.inf.tu-dresden.de>,
7  *               Lars Reuther <reuther@os.inf.tu-dresden.de>
8  *     economic rights: Technische Universität Dresden (Germany)
9  * This file is part of TUD:OS and distributed under the terms of the
10  * GNU Lesser General Public License 2.1.
11  * Please see the COPYING-LGPL-2.1 file for details.
12  */
13 /*
14  */
15 
16 /*****************************************************************************
17  * libl4util/src/micros2l4to.c                                               *
18  * calculate L4 timeout                                                      *
19  *****************************************************************************/
20 
21 #include <l4/sys/compiler.h> /* for static_assert() */
22 #include <l4/sys/types.h>
23 #include <l4/util/util.h>
24 #include <l4/util/bitops.h>
25 
26 L4_CV l4_timeout_s
l4util_micros2l4to(unsigned int mus)27 l4util_micros2l4to(unsigned int mus)
28 {
29   static_assert(sizeof(mus) <= 4,
30                 "Verify the correctness of log2(mus) and the number of bits for e!");
31   l4_timeout_s t;
32   if (mus == 0)
33     t = L4_IPC_TIMEOUT_0;
34   else if (mus == ~0U)
35     t = L4_IPC_TIMEOUT_NEVER;
36   else
37     {
38       /* Here it is certain that at least one bit in 'mus' is set. */
39       int e = l4util_log2(mus) - 7;
40       if (e < 0) e = 0;
41       /* Here it is certain that '0 <= e <= 24' and '1 <= 2^e <= 2^24'. */
42 
43       unsigned m = mus >> e;
44       /* Here it is certain that '1 <= m <= 255. Consider the following cases:
45        *  o    1 <= mus <=  255: e = 0; 2^e = 1;   1 <= mus/1 <= 255
46        *  o  256 <= mus <=  511: e = 1; 2^e = 2; 128 <= mus/2 <= 255
47        *  o  512 <= mus <= 1023: e = 2; 2^e = 4; 128 <= mus/4 <= 255
48        *  o 1024 <= mus <= 2047: e = 3; 2^e = 8; 128 <= mus/8 <= 255
49        *  ...
50        *  o 2^31 <= mus <= 2^32-1: e = 24;       128 <= mus/2^24 <= 255
51        *
52        * Dividing by (1<<e) ensures that for all mus < 2^32: m < 2^8.
53        *
54        * As we have 10 bits for m we could also use 'e = log2(mus) - 9':
55        *  o    1 <= mus <= 1023: e = 0; 2^e = 1;   1 <= mus/1 <= 1023
56        *  o 1024 <= mus <= 2047: e = 1; 2^e = 2; 512 <= mus/2 <= 1023
57        *  o 2048 <= mus <= 4095: e = 2; 2^e = 4; 512 <= mus/4 <= 1023
58        *  ...
59        *  o 2^31 <= mus <= 2^32-1: e = 22;       512 <= mus/2^22 <= 1023
60        *
61        * What about sizeof(mus) == 8? 'e = log2(mus) - 7':
62        *  o 2^63 <= mus <= 2^64-1: e = 56;       128 <= mus/2^56 <= 255.
63        *
64        * That means that this function would even work for 64-bit values of
65        * 'mus' as long as l4util_log2(mus) works correctly for that range.
66        * But the number of bits available for the exponent is limited:
67        *  o bits 0..9 (10 bits) are used for 'm'
68        *  o bits 10..14 (5 bits) are used for 'e'
69        *  o bit 15 is used to distinguish between absolute timeouts and
70        *    relative timeouts (see l4_timeout_is_absolute())
71        *
72        * That means 'e <= 31' and thus it's not possible to encode timeouts
73        * represented by 64-bit values.
74        */
75 
76       t.t = (e << 10) | m;
77     }
78   return t;
79 }
80