diff --git a/src/mx/util/atomic.h b/src/mx/util/atomic.h new file mode 100644 index 0000000..350eab3 --- /dev/null +++ b/src/mx/util/atomic.h @@ -0,0 +1,61 @@ +/* + * Atomic Operations + * + * Copyright (C) 2009-2011 Udo Steinberg + * Economic rights: Technische Universitaet Dresden (Germany) + * + * This file is part of the NOVA microhypervisor. + * + * NOVA is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2 for more details. + */ + +#pragma once + +#include "compiler.h" + +class Atomic +{ + public: + template + + static inline bool cmp_swap (T &ptr, T o, T n) { return __sync_bool_compare_and_swap (&ptr, o, n); } + + template + + static inline T add (T &ptr, T v) { return __sync_add_and_fetch (&ptr, v); } + + template + + static inline T sub (T &ptr, T v) { return __sync_sub_and_fetch (&ptr, v); } + + template + + static inline void set_mask (T &ptr, T v) { __sync_or_and_fetch (&ptr, v); } + + template + + static inline void clr_mask (T &ptr, T v) { __sync_and_and_fetch (&ptr, ~v); } + + template + static inline bool test_set_bit (T &val, unsigned long bit) + { + bool ret; + asm volatile ("lock; bts %2, %1; setc %0" : "=q" (ret), "+m" (val) : "ir" (bit) : "cc"); + return ret; + } + + template + static inline bool test_clr_bit (T &val, unsigned long bit) + { + bool ret; + asm volatile ("lock; btr %2, %1; setc %0" : "=q" (ret), "+m" (val) : "ir" (bit) : "cc"); + return ret; + } +}; diff --git a/src/mx/util/bit_alloc.h b/src/mx/util/bit_alloc.h new file mode 100644 index 0000000..8285a6d --- /dev/null +++ b/src/mx/util/bit_alloc.h @@ -0,0 +1,154 @@ +/* + * Bit allocator + * + * Copyright (C) 2020 Alexander Boettcher, Genode Labs GmbH + * + * This file is part of the NOVA microhypervisor. + * + * NOVA is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2 for more details. + */ + + +#pragma once + +#include "bits.h" +#include "atomic.h" + +namespace mx::util { + template class Bit_alloc; +} + +template +class mx::util::Bit_alloc +{ + private: + + alignas(64) std::uint64_t bits [C / 8 / sizeof(std::uint64_t)]; + std::uint64_t last { 0 }; + + enum { + BITS_CNT = sizeof(bits[0]) * 8, + MAX = sizeof(bits) / sizeof(bits [0]) + }; + + public: + + + inline std::uint64_t max() const { return C; } + + + inline Bit_alloc() + { + static_assert(MAX*BITS_CNT == C, "bit allocator"); + static_assert(INV < C, "bit allocator"); + + Atomic::test_set_bit(bits[INV / BITS_CNT], INV % BITS_CNT); + } + + + inline std::uint64_t alloc_with_mask(std::uint64_t bitmask[C/8/sizeof(std::uint64_t)], bool inverse = false) + { + for (std::uint64_t i = ACCESS_ONCE(last), j = 0; j < MAX; i++, j++) + { + i %= MAX; + + std::uint64_t mask = ~bits[i] & (inverse ? ~bitmask[i] : bitmask[i]); + + if (mask == 0UL) + continue; + + + long b = bit_scan_forward (mask); + if (b < 0 || b >= BITS_CNT || Atomic::test_set_bit (bits[i], b)) { + j--; + i--; + continue; + } + + if (bits[i] != ~0UL && last != i) + last = i; + + return i * BITS_CNT + b; + } + + return INV; + } + + + inline std::uint64_t alloc() + { + return alloc_with_mask(bits, true); + } + + + inline void release(std::uint64_t const id) + { + if (id == INV || id >= C) + return; + + std::uint64_t i = id / BITS_CNT; + std::uint64_t b = id % BITS_CNT; + + while (ACCESS_ONCE(bits[i]) & (1ul << b)) + Atomic::test_clr_bit (ACCESS_ONCE(bits[i]), b); + } + + + inline bool reserve(std::uint64_t const id) + { + + if (id == INV || id >= C) + return false; + + std::uint64_t i = id / BITS_CNT; + std::uint64_t b = id % BITS_CNT; + + return Atomic::test_set_bit (ACCESS_ONCE(bits[i]), b); + } + + void reserve(std::uint64_t const start, std::uint64_t const count) + { + if (start >= C) + return; + + std::uint64_t i = start / BITS_CNT; + std::uint64_t b = start % BITS_CNT; + + std::uint64_t cnt = count > C ? C : count; + if (start + cnt > C) + cnt = C - start; + + while (cnt) { + std::uint64_t const c = (cnt > BITS_CNT) ? std::uint64_t(BITS_CNT) : cnt; + std::uint64_t const bc = (c > (BITS_CNT - b)) ? std::uint64_t(BITS_CNT - b) : c; + if (bits[i] != ~0UL) { + if (bc >= BITS_CNT) { + bits[i] = ~0UL; + } else { + bits[i] |= ((1ul << bc) - 1) << b; + } + } + i++; + cnt -= bc; + b = 0; + } + } + + void reserve_with_mask(std::uint64_t const mask, std::uint64_t const offset) + { + Atomic::set_mask(bits[offset], mask); + } + + void dump_trace() + { + for (int i = 0; i < MAX; i++) + trace(0, "bitmap[%d]: %lx", i, bits[i]); + } +}; diff --git a/src/mx/util/bits.old b/src/mx/util/bits.old new file mode 100644 index 0000000..95065e2 --- /dev/null +++ b/src/mx/util/bits.old @@ -0,0 +1,14 @@ +#pragma once +#include + +namespace mx::util { +inline long int bit_scan_forward(std::uint64_t val) +{ + if (!val) + return -1; + + asm volatile("bsf %1, %0" : "=r"(val) : "rm"(val)); + + return val; +} +} \ No newline at end of file diff --git a/src/mx/util/compiler.h b/src/mx/util/compiler.h new file mode 100644 index 0000000..33bd091 --- /dev/null +++ b/src/mx/util/compiler.h @@ -0,0 +1,26 @@ +/* + * Compiler Macros + * + * Copyright (C) 2009-2011 Udo Steinberg + * Economic rights: Technische Universitaet Dresden (Germany) + * + * Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation. + * + * This file is part of the NOVA microhypervisor. + * + * NOVA is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2 for more details. + */ + +#pragma once + + #define EXPECT_FALSE(X) __builtin_expect(!!(X), 0) + #define EXPECT_TRUE(X) __builtin_expect(!!(X), 1) + + #define ACCESS_ONCE(x) (*static_cast(&(x))) diff --git a/src/mx/util/util.h b/src/mx/util/util.h new file mode 100644 index 0000000..3221f74 --- /dev/null +++ b/src/mx/util/util.h @@ -0,0 +1,33 @@ +/* + * Utility Functions + * + * Copyright (C) 2009-2011 Udo Steinberg + * Economic rights: Technische Universitaet Dresden (Germany) + * + * This file is part of the NOVA microhypervisor. + * + * NOVA is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2 for more details. + */ + +#pragma once + +#include "compiler.h" + +template +static inline T min (T v1, T v2) +{ + return v1 < v2 ? v1 : v2; +} + +template +static inline T max (T v1, T v2) +{ + return v1 > v2 ? v1 : v2; +}