Commit 8b81576c authored by Huacai Chen's avatar Huacai Chen
Browse files

LoongArch: Add HIGHMEM (PKMAP and FIX_KMAP) support



Add HIGHMEM (High Memory) support for LoongArch, mostly needed by 32BIT
kernel because the size of kernel virtual memory space is only 512MB and
the size of usable physical memory is only 256MB in this case.

HIGHMEM adds permanent kernel mapping (PKMAP) and fixed kernel mapping
(FIX_KMAP), which increase usable physical memory up to 2.25GB (2304MB).

We can just use the generic copy_user_highpage(), so remove the custom
version.

Signed-off-by: default avatarHuacai Chen <chenhuacai@loongson.cn>
parent 3d9aba66
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -348,6 +348,11 @@ config RUSTC_HAS_ANNOTATE_TABLEJUMP

source "kernel/Kconfig.hz"

config HIGHMEM
	bool "High Memory Support"
	depends on 32BIT
	select KMAP_LOCAL

choice
	prompt "Page Table Layout"
	default 16KB_2LEVEL if 32BIT
+14 −0
Original line number Diff line number Diff line
@@ -8,10 +8,19 @@
#ifndef _ASM_FIXMAP_H
#define _ASM_FIXMAP_H

#ifdef CONFIG_HIGHMEM
#include <linux/threads.h>
#include <asm/kmap_size.h>
#endif

#define NR_FIX_BTMAPS 64

enum fixed_addresses {
	FIX_HOLE,
#ifdef CONFIG_HIGHMEM
	FIX_KMAP_BEGIN,
	FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_MAX_IDX * NR_CPUS) - 1,
#endif
	FIX_EARLYCON_MEM_BASE,
	__end_of_fixed_addresses
};
@@ -25,4 +34,9 @@ extern void __set_fixmap(enum fixed_addresses idx,

#include <asm-generic/fixmap.h>

/*
 * Called from pagetable_init()
 */
extern void fixrange_init(unsigned long start, unsigned long end, pgd_t *pgd_base);

#endif
+43 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * highmem.h: virtual kernel memory mappings for high memory
 *
 * Used in CONFIG_HIGHMEM systems for memory pages which
 * are not addressable by direct kernel virtual addresses.
 *
 * Copyright (C) 2025 Loongson Technology Corporation Limited
 */
#ifndef _ASM_HIGHMEM_H
#define _ASM_HIGHMEM_H

#ifdef __KERNEL__

#include <asm/kmap_size.h>

#ifndef __ASSEMBLER__

extern pte_t *pkmap_page_table;

#define ARCH_HAS_KMAP_FLUSH_TLB
void kmap_flush_tlb(unsigned long addr);

#endif /* !__ASSEMBLER__ */

/*
 * Right now we initialize only a single pte table. It can be extended
 * easily, subsequent pte tables have to be allocated in one physical
 * chunk of RAM.
 */
#define LAST_PKMAP 1024
#define LAST_PKMAP_MASK (LAST_PKMAP - 1)
#define PKMAP_NR(virt)	((virt - PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr)	(PKMAP_BASE + ((nr) << PAGE_SHIFT))

#define flush_cache_kmaps() do {} while (0)

#define arch_kmap_local_post_map(vaddr, pteval)	local_flush_tlb_one(vaddr)
#define arch_kmap_local_post_unmap(vaddr)	local_flush_tlb_one(vaddr)

#endif /* __KERNEL__ */

#endif /* _ASM_HIGHMEM_H */
+0 −4
Original line number Diff line number Diff line
@@ -36,10 +36,6 @@ extern unsigned long shm_align_mask;

struct page;
struct vm_area_struct;
void copy_user_highpage(struct page *to, struct page *from,
	      unsigned long vaddr, struct vm_area_struct *vma);

#define __HAVE_ARCH_COPY_USER_HIGHPAGE

typedef struct { unsigned long pte; } pte_t;
#define pte_val(x)	((x).pte)
+12 −0
Original line number Diff line number Diff line
@@ -23,6 +23,10 @@
#include <asm-generic/pgtable-nop4d.h>
#endif

#ifdef CONFIG_HIGHMEM
#include <asm/highmem.h>
#endif

#if CONFIG_PGTABLE_LEVELS == 2
#define PGDIR_SHIFT	(PAGE_SHIFT + (PAGE_SHIFT - PTRLOG))
#elif CONFIG_PGTABLE_LEVELS == 3
@@ -86,7 +90,15 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
#ifdef CONFIG_32BIT

#define VMALLOC_START	(vm_map_base + PCI_IOSIZE + (2 * PAGE_SIZE))

#ifdef CONFIG_HIGHMEM
#define VMALLOC_END	(PKMAP_BASE - (2 * PAGE_SIZE))
#else
#define VMALLOC_END	(FIXADDR_START - (2 * PAGE_SIZE))
#endif

#define PKMAP_BASE	(PKMAP_END - (PAGE_SIZE * LAST_PKMAP))
#define PKMAP_END	((FIXADDR_START) & ~((LAST_PKMAP << PAGE_SHIFT)-1))

#endif

Loading