1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef PARTITION_ALLOC_PARTITION_SUPERPAGE_EXTENT_ENTRY_H_
6 #define PARTITION_ALLOC_PARTITION_SUPERPAGE_EXTENT_ENTRY_H_
7 
8 #include <cstdint>
9 
10 #include "partition_alloc/address_pool_manager.h"
11 #include "partition_alloc/address_pool_manager_types.h"
12 #include "partition_alloc/partition_alloc_constants.h"
13 #include "partition_alloc/partition_alloc_forward.h"
14 #include "partition_alloc/partition_dcheck_helper.h"
15 #include "partition_alloc/reservation_offset_table.h"
16 
17 // Should not include partition_root.h, partition_bucket.h, partition_page.h.
18 // For IsQuarantineAllowed(), use partition_dcheck_helper.h instead of
19 // partition_root.h.
20 
21 namespace partition_alloc::internal {
22 
23 // An "extent" is a span of consecutive superpages. We link the partition's next
24 // extent (if there is one) to the very start of a superpage's metadata area.
25 struct PartitionSuperPageExtentEntry {
26   PartitionRoot* root;
27   PartitionSuperPageExtentEntry* next;
28   uint16_t number_of_consecutive_super_pages;
29   uint16_t number_of_nonempty_slot_spans;
30 
IncrementNumberOfNonemptySlotSpansPartitionSuperPageExtentEntry31   PA_ALWAYS_INLINE void IncrementNumberOfNonemptySlotSpans() {
32     DCheckNumberOfPartitionPagesInSuperPagePayload(
33         this, root, number_of_nonempty_slot_spans);
34     ++number_of_nonempty_slot_spans;
35   }
36 
DecrementNumberOfNonemptySlotSpansPartitionSuperPageExtentEntry37   PA_ALWAYS_INLINE void DecrementNumberOfNonemptySlotSpans() {
38     PA_DCHECK(number_of_nonempty_slot_spans);
39     --number_of_nonempty_slot_spans;
40   }
41 };
42 
43 static_assert(
44     sizeof(PartitionSuperPageExtentEntry) <= kPageMetadataSize,
45     "PartitionSuperPageExtentEntry must be able to fit in a metadata slot");
46 static_assert(kMaxSuperPagesInPool / kSuperPageSize <=
47                   std::numeric_limits<
48                       decltype(PartitionSuperPageExtentEntry ::
49                                    number_of_consecutive_super_pages)>::max(),
50               "number_of_consecutive_super_pages must be big enough");
51 
52 // Returns the base of the first super page in the range of consecutive super
53 // pages.
54 //
55 // CAUTION! |extent| must point to the extent of the first super page in the
56 // range of consecutive super pages.
57 PA_ALWAYS_INLINE uintptr_t
SuperPagesBeginFromExtent(const PartitionSuperPageExtentEntry * extent)58 SuperPagesBeginFromExtent(const PartitionSuperPageExtentEntry* extent) {
59   PA_DCHECK(0 < extent->number_of_consecutive_super_pages);
60   uintptr_t extent_as_uintptr = reinterpret_cast<uintptr_t>(extent);
61   PA_DCHECK(IsManagedByNormalBuckets(extent_as_uintptr));
62   return base::bits::AlignDown(extent_as_uintptr, kSuperPageAlignment);
63 }
64 
65 // Returns the end of the last super page in the range of consecutive super
66 // pages.
67 //
68 // CAUTION! |extent| must point to the extent of the first super page in the
69 // range of consecutive super pages.
70 PA_ALWAYS_INLINE uintptr_t
SuperPagesEndFromExtent(const PartitionSuperPageExtentEntry * extent)71 SuperPagesEndFromExtent(const PartitionSuperPageExtentEntry* extent) {
72   return SuperPagesBeginFromExtent(extent) +
73          (extent->number_of_consecutive_super_pages * kSuperPageSize);
74 }
75 
76 }  // namespace partition_alloc::internal
77 
78 #endif  // PARTITION_ALLOC_PARTITION_SUPERPAGE_EXTENT_ENTRY_H_
79