arch/powerpc/mm/book3s64/slice.c

Source file repositories/reference/linux-study-clean/arch/powerpc/mm/book3s64/slice.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/mm/book3s64/slice.c
Extension
.c
Size
23139 bytes
Lines
820
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

static void slice_print_mask(const char *label, const struct slice_mask *mask) {}
#define slice_dbg(fmt...)

#endif

static inline notrace bool slice_addr_is_low(unsigned long addr)
{
	u64 tmp = (u64)addr;

	return tmp < SLICE_LOW_TOP;
}

static void slice_range_to_mask(unsigned long start, unsigned long len,
				struct slice_mask *ret)
{
	unsigned long end = start + len - 1;

	ret->low_slices = 0;
	if (SLICE_NUM_HIGH)
		bitmap_zero(ret->high_slices, SLICE_NUM_HIGH);

	if (slice_addr_is_low(start)) {
		unsigned long mend = min(end,
					 (unsigned long)(SLICE_LOW_TOP - 1));

		ret->low_slices = (1u << (GET_LOW_SLICE_INDEX(mend) + 1))
			- (1u << GET_LOW_SLICE_INDEX(start));
	}

	if (SLICE_NUM_HIGH && !slice_addr_is_low(end)) {
		unsigned long start_index = GET_HIGH_SLICE_INDEX(start);
		unsigned long align_end = ALIGN(end, (1UL << SLICE_HIGH_SHIFT));
		unsigned long count = GET_HIGH_SLICE_INDEX(align_end) - start_index;

		bitmap_set(ret->high_slices, start_index, count);
	}
}

static int slice_area_is_free(struct mm_struct *mm, unsigned long addr,
			      unsigned long len)
{
	struct vm_area_struct *vma;

	if ((mm_ctx_slb_addr_limit(&mm->context) - len) < addr)
		return 0;
	vma = find_vma(mm, addr);
	return (!vma || (addr + len) <= vm_start_gap(vma));
}

static int slice_low_has_vma(struct mm_struct *mm, unsigned long slice)
{
	return !slice_area_is_free(mm, slice << SLICE_LOW_SHIFT,
				   1ul << SLICE_LOW_SHIFT);
}

static int slice_high_has_vma(struct mm_struct *mm, unsigned long slice)
{
	unsigned long start = slice << SLICE_HIGH_SHIFT;
	unsigned long end = start + (1ul << SLICE_HIGH_SHIFT);

	/* Hack, so that each addresses is controlled by exactly one
	 * of the high or low area bitmaps, the first high area starts
	 * at 4GB, not 0 */
	if (start == 0)
		start = (unsigned long)SLICE_LOW_TOP;

	return !slice_area_is_free(mm, start, end - start);
}

static void slice_mask_for_free(struct mm_struct *mm, struct slice_mask *ret,
				unsigned long high_limit)
{
	unsigned long i;

	ret->low_slices = 0;
	if (SLICE_NUM_HIGH)
		bitmap_zero(ret->high_slices, SLICE_NUM_HIGH);

	for (i = 0; i < SLICE_NUM_LOW; i++)
		if (!slice_low_has_vma(mm, i))
			ret->low_slices |= 1u << i;

	if (slice_addr_is_low(high_limit - 1))
		return;

	for (i = 0; i < GET_HIGH_SLICE_INDEX(high_limit); i++)
		if (!slice_high_has_vma(mm, i))
			__set_bit(i, ret->high_slices);
}

Annotation

Implementation Notes