/*
 * hal_boot.h - General values used by the boot procedure
 *
 * Copyright (c) 2017 Maxime Villard
 *
 * This file is part of ALMOS-MKH.
 *
 * ALMOS-MKH is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2.0 of the License.
 *
 * ALMOS-MKH 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#define PAGE_SIZE	4096
#define PGOFSET		(PAGE_SIZE-1)
#define PGSHIFT		12

#define KERNBASE	0xfffff00000000000
#define KERNBASE_HI	0xfffff000
#define KERNBASE_LO	0x00000000

#define	KERNTEXTOFF	0xfffff00000200000
#define KERNTEXTOFF_HI	0xfffff000
#define KERNTEXTOFF_LO	0x00200000

/* -------------------------------------------------------------------------- */

#define ASM_ALIGN_TEXT	.align 16
#define ASM_ENTRY(x) \
	.text; ASM_ALIGN_TEXT; .globl x; .type x,@function; x:

#define LABEL(x) \
	.globl x; .type x,@function; x:

/* -------------------------------------------------------------------------- */

#define STKPAGES	4
#define STKSIZE		(PAGE_SIZE * STKPAGES)

#define NKL4_KIMG_ENTRIES	1
#define NKL3_KIMG_ENTRIES	1
#define NKL2_KIMG_ENTRIES	32

/* -------------------------------------------------------------------------- */

#define L1_SHIFT	12
#define L2_SHIFT	21
#define L3_SHIFT	30
#define L4_SHIFT	39
#define NBPD_L1		(1UL << L1_SHIFT) /* # bytes mapped by L1 ent (4K) */
#define NBPD_L2		(1UL << L2_SHIFT) /* # bytes mapped by L2 ent (2MB) */
#define NBPD_L3		(1UL << L3_SHIFT) /* # bytes mapped by L3 ent (1G) */
#define NBPD_L4		(1UL << L4_SHIFT) /* # bytes mapped by L4 ent (512G) */

#define L4_MASK		0x0000ff8000000000
#define L3_MASK		0x0000007fc0000000
#define L2_MASK		0x000000003fe00000
#define L1_MASK		0x00000000001ff000

#define L4_FRAME	L4_MASK
#define L3_FRAME	(L4_FRAME|L3_MASK)
#define L2_FRAME	(L3_FRAME|L2_MASK)
#define L1_FRAME	(L2_FRAME|L1_MASK)

#define PDE_SIZE	8

/* PDE/PTE bits. */
#define PG_V		0x0000000000000001	/* valid */
#define PG_RO		0x0000000000000000	/* read-only */
#define PG_RW		0x0000000000000002	/* read-write */
#define PG_u		0x0000000000000004	/* user accessible */
#define PG_PROT		0x0000000000000006
#define PG_WT		0x0000000000000008	/* write-through */
#define PG_N		0x0000000000000010	/* non-cacheable */
#define PG_U		0x0000000000000020	/* used */
#define PG_M		0x0000000000000040	/* modified */
#define PG_PAT		0x0000000000000080	/* PAT (on pte) */
#define PG_PS		0x0000000000000080	/* 2MB page size (on pde) */
#define PG_G		0x0000000000000100	/* not flushed */
#define PG_AVAIL1	0x0000000000000200
#define PG_AVAIL2	0x0000000000000400
#define PG_AVAIL3	0x0000000000000800
#define PG_LGPAT	0x0000000000001000	/* PAT on large pages */
#define PG_FRAME	0x000ffffffffff000
#define PG_NX		0x8000000000000000

#define PG_2MFRAME	0x000fffffffe00000	/* large (2M) page frame mask */
#define PG_1GFRAME	0x000fffffc0000000	/* large (1G) page frame mask */
#define PG_LGFRAME	PG_2MFRAME

/* Short forms of protection codes. */
#define PG_KR		0x0000000000000000	/* kernel read-only */
#define PG_KW		0x0000000000000002	/* kernel read-write */

/* -------------------------------------------------------------------------- */

#define	IOM_BEGIN	0x0a0000		/* Start of I/O Memory "hole" */
#define	IOM_END		0x100000		/* End of I/O Memory "hole" */
#define	IOM_SIZE	(IOM_END - IOM_BEGIN)

/* -------------------------------------------------------------------------- */

#define VA_SIGN_MASK		0xffff000000000000
#define VA_SIGN_POS(va)		((va) & ~VA_SIGN_MASK)

#define pl1_i(VA)	(((VA_SIGN_POS(VA)) & L1_FRAME) >> L1_SHIFT)
#define pl2_i(VA)	(((VA_SIGN_POS(VA)) & L2_FRAME) >> L2_SHIFT)
#define pl3_i(VA)	(((VA_SIGN_POS(VA)) & L3_FRAME) >> L3_SHIFT)
#define pl4_i(VA)	(((VA_SIGN_POS(VA)) & L4_FRAME) >> L4_SHIFT)

#define L4_SLOT_PTE		255
#define L4_SLOT_KERNBASE	pl4_i(KERNBASE)
#define L3_SLOT_KERNBASE	(pl3_i(KERNBASE) % 512)
#define L2_SLOT_KERNBASE	(pl2_i(KERNBASE) % 512)

#define PDIR_SLOT_PTE	L4_SLOT_PTE

#define PTE_BASE	((pt_entry_t *)(L4_SLOT_PTE * NBPD_L4))
#define L1_BASE	PTE_BASE
#define L2_BASE	((pt_entry_t *)((char *)L1_BASE + L4_SLOT_PTE * NBPD_L3))
#define L3_BASE	((pt_entry_t *)((char *)L2_BASE + L4_SLOT_PTE * NBPD_L2))
#define L4_BASE	((pt_entry_t *)((char *)L3_BASE + L4_SLOT_PTE * NBPD_L1))

#define NPDPG	(PAGE_SIZE / sizeof (pt_entry_t))

/* -------------------------------------------------------------------------- */

#define SMP_TRAMPOLINE_PA	(2 * PAGE_SIZE)

/* -------------------------------------------------------------------------- */

#define KERNEL_VA_SIZE		(NKL2_KIMG_ENTRIES * NBPD_L2)
#define CLUSTERS_BASE_VA	HAL_VA_BASE

/* These parameters are configurable. */
#define CLUSTER_VA_SIZE	0x1000000000 /* 64GB */
#define CLUSTER_PA_SIZE	0x0200000000 /* 8GB */

/* Macros to get the VA ranges for a cluster */
#define CLUSTER_MIN_VA(n) \
	(CLUSTERS_BASE_VA + n * CLUSTER_VA_SIZE)
#define CLUSTER_MAX_VA(n) \
	(CLUSTER_MIN_VA(n) + CLUSTER_VA_SIZE)

