
#include "include/assembly.h"
#include "include/options.h"

@
@ Exception defs taken from ARM DDI 0406B
@ 
.section .init
interrupt_vector_table:
ivt_reset:	b _start	@ 0x00 Reset
ivt_undef:	b Undef_Handler	@ 0x04 #UD
ivt_svc:	b SVC_Handler	@ 0x08 SVC (used to be called SWI)
ivt_prefetch:	b PrefetchAbort	@ 0x0C Prefetch abort
ivt_data:	b DataAbort	@ 0x10 Data abort
ivt_unused:	b .     	@ 0x14 Not Used
ivt_irq:	b IRQHandler	@ 0x18 IRQ
ivt_fiq:	b .     	@ 0x1C FIQ (Fast interrupt)

.globl _start
_start:
	ldr r2, =UART0_PADDR
	mov r1, #'A'
	str r1, [r2]	

	ldr r0, =kernel_table0-KERNEL_BASE
	mcr p15, 0, r0, c2, c0, 1	@ Set TTBR1 to r0
	mcr p15, 0, r0, c2, c0, 0	@ Set TTBR0 to r0 too (for identity)

	mov r1, #'c'
	str r1, [r2]	

	mov r0, #1
	mcr p15, 0, r0, c2, c0, 2	@ Set TTCR to 1 (50/50 split)

	mov r1, #'e'
	str r1, [r2]	
	
	mov r0, #3
	mcr p15, 0, r0, c3, c0, 0	@ Set Domain 0 to Manager

	mov r1, #'s'
	str r1, [r2]	

	@ Enable VMSA
	mrc p15, 0, r0, c1, c0, 0
	orr r0, r0, #1
	orr r0, r0, #1 << 23
	mcr p15, 0, r0, c1, c0, 0

	@ HACK: Set ASID to non zero
	mov r0, #1
	MCR p15,0,r0,c13,c0,1

	ldr r2, =0xF1000000
	mov r1, #'s'
	str r1, [r2]	

	@ Enable access faults on domains 0 & 1
	mov r0, #0x55	@ 01010101b
	mcr p15, 0, r0, c3, c0, 0

	mov r1, #'2'
	str r1, [r2]	

	@
	@ Check for security extensions
	@
	mrc p15, 0, r0, c0, c1, 1
	and r0, #0xF0
	@ - Present
	ldrne r0,=KERNEL_BASE
	mcrne p15, 0, r0, c12, c0, 0	@ Set the VBAR (brings exceptions into high memory)
	@ - Absent
	mrceq p15, 0, r0, c1, c0, 0	@ Set SCTLR.V
	orreq r0, #0x2000
	mcreq p15, 0, r0, c1, c0, 0

	mov r1, #'-'
	str r1, [r2]	

	@ Prepare for interrupts
	cps #18	@ IRQ Mode
	ldr sp, =irqstack+0x1000	@ Set up stack
	cps #23	@ Abort Mode
	ldr sp, =abortstack+0x1000
	cps #19

	mov r1, #'a'
	str r1, [r2]	
	mov r1, #'r'
	str r1, [r2]	
	mov r1, #'m'
	str r1, [r2]	
	mov r1, #13
	str r1, [r2]	
	mov r1, #10
	str r1, [r2]	

.extern bss_start
.extern bss_size_div_4
.zero_bss:
	ldr r0, =bss_start
	ldr r1, =bss_end
	mov r3, #0
.zero_bss_loop:
	str r3, [r0],#4
	cmp r0, r1
	bls .zero_bss_loop

.goto_c:
	ldr sp, =0x80000000-8	@ Set up stack (top of user range)
	ldr r0, =kmain
	mov pc, r0
1:	b 1b	@ Infinite loop

.comm irqstack, 0x1000	@ ; 4KiB Stack
.comm abortstack, 0x1000	@ ; 4KiB Stack

.extern SyscallHandler
SVC_Handler:
@	sub lr, #4
	srsdb sp!, #19	@ Save state to stack
	cpsie ifa, #19	@ Ensure we're in supervisor with interrupts enabled (should already be there)
	push {r0-r12}

	ldr r4, [lr,#-4]
	mvn r5, #0xFF000000
	and r4, r5

	tst r4, #0x1000 
	bne .arm_specifics

	push {r4}

	mov r0, sp
	ldr r4, =SyscallHandler
	blx r4
	
@	ldr r0, =csSyscallPrintRetAddr
@	ldr r1, [sp,#9*4+5*4]
@	ldr r4, =Log
@	blx r4
	
	pop {r2}	@ errno
	pop {r0,r1}	@ Ret/RetHi
	add sp, #2*4	@ Saved r2/r3

	pop {r4-r12}
	rfeia sp!	@ Pop state (actually RFEFD)
.arm_specifics:
	and r4, #0xFF
	mov r0, r4	@ Number
	mov r1, sp	@ Arguments
	
	ldr r4, =ARMv7_int_HandleSyscalls
	blx r4

	add sp, #4*4
	pop {r4-r12}
	rfeia sp!


.globl gpIRQHandler
gpIRQHandler:	.long	0
IRQ_saved_sp:	.long	0
IRQ_saved_lr: 	.long	0
.globl IRQHandler
IRQHandler:
	sub lr, #4	@ Adjust LR to the correct value
	srsdb sp!, #19	@ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
	cps #19

	PUSH_GPRS

@	ldr r0, =csIRQ_Tag
@	ldr r1, =csIRQ_Fmt
@	ldr r4, =Log_Debug
@	blx r4
	
	@ Call the registered handler
	ldr r0, gpIRQHandler
	blx r0

	@ Restore CPU state
	POP_GPRS
	cpsie i
	rfeia sp!	@ Pop state (actually RFEFD)
	bx lr

.globl DataAbort
DataAbort:
	sub lr, #8	@ Adjust LR to the correct value
	srsdb sp!, #23	@ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
@	cpsid ifa, #19
	PUSH_GPRS

	mov r3, #0	@ not a prefetch abort
	mrc p15, 0, r2, c5, c0, 0	@ Read DFSR (Data Fault Status Register) to R2
	mrc p15, 0, r1, c6, c0, 0	@ Read DFAR (Data Fault Address Register) into R1
	mov r0, lr	@ PC
	ldr r4, =MM_PageFault
	blx r4

	POP_GPRS
	rfeia sp!	@ Pop state (actually RFEFD)

.globl PrefetchAbort
PrefetchAbort:
	sub lr, #4	@ Adjust LR to the correct value
	srsdb sp!, #23	@ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
@	cpsid ifa, #19
	PUSH_GPRS

	ldr r0, =csAbort_Tag
	ldr r1, =csPrefetchAbort_Fmt
#	mov r2, lr
	mrc p15, 0, r2, c6, c0, 2	@ Read IFAR (Instruction Fault Address Register) into R3
	mrc p15, 0, r3, c5, c0, 1	@ Read IFSR (Instruction Fault Status Register) into R3
	ldr r5, =Log_Error
	blx r5

.loop:
	wfi
	b .loop
.globl Undef_Handler
Undef_Handler:
	wfi
	b Undef_Handler

.globl abort
abort:
	wfi
	b abort


.section .rodata
csIRQ_Tag:
csAbort_Tag:
	.asciz "ARMv7"
csIRQ_Fmt:
	.asciz "IRQ"
csDataAbort_Fmt:
	.asciz "Data Abort - %p accessed %p, DFSR=%x Unk:%x Unk:%x"
csPrefetchAbort_Fmt:
	.asciz "Prefetch Abort at %p, IFSR=%x"
csSyscallPrintRetAddr:
	.asciz "Syscall ret to %p"

.section .padata
.globl kernel_table0

kernel_table0:
	.long 0x00000402	@ Identity map the first 1 MiB
	.rept 0x7FC - 1
		.long 0
	.endr
	.long user_table1_map + 0x000 - KERNEL_BASE + 1	@ 0x7FC00000
	.long user_table1_map + 0x400 - KERNEL_BASE + 1	@ 0x7FD00000
	.long user_table1_map + 0x800 - KERNEL_BASE + 1	@ KStacks
	.long user_table1_map + 0xC00 - KERNEL_BASE + 1
	@ 0x80000000 - User/Kernel split
	.long 0x00000402	@ Map first 4 MiB to 2GiB (KRW only)
	.long 0x00100402 	@ 
	.long 0x00200402	@ 
	.long 0x00300402	@ 
	.rept 0xF00 - 0x800 - 4
		.long 0
	.endr
#if PCI_PADDR
	.long PCI_PADDR +  0*(1 << 20) + 0x402	@ Map PCI config space
	.long PCI_PADDR +  1*(1 << 20) + 0x402
	.long PCI_PADDR +  2*(1 << 20) + 0x402
	.long PCI_PADDR +  3*(1 << 20) + 0x402
	.long PCI_PADDR +  4*(1 << 20) + 0x402
	.long PCI_PADDR +  5*(1 << 20) + 0x402
	.long PCI_PADDR +  6*(1 << 20) + 0x402
	.long PCI_PADDR +  7*(1 << 20) + 0x402
	.long PCI_PADDR +  8*(1 << 20) + 0x402
	.long PCI_PADDR +  9*(1 << 20) + 0x402
	.long PCI_PADDR + 10*(1 << 20) + 0x402
	.long PCI_PADDR + 11*(1 << 20) + 0x402
	.long PCI_PADDR + 12*(1 << 20) + 0x402
	.long PCI_PADDR + 13*(1 << 20) + 0x402
	.long PCI_PADDR + 14*(1 << 20) + 0x402
	.long PCI_PADDR + 15*(1 << 20) + 0x402
#else
	.rept 16
		.long 0
	.endr
#endif
	.long hwmap_table_0 + 0x000 - KERNEL_BASE + 1
	.long hwmap_table_0 + 0x400 - KERNEL_BASE + 1
	.long hwmap_table_0 + 0x800 - KERNEL_BASE + 1
	.long hwmap_table_0 + 0xC00 - KERNEL_BASE + 1
	.rept 0xFF8 - 0xF00 - 16 - 4
		.long 0
	.endr
	@ Page fractals
	.long kernel_table1_map + 0x000 - KERNEL_BASE + 1
	.long kernel_table1_map + 0x400 - KERNEL_BASE + 1
	.long kernel_table1_map + 0x800 - KERNEL_BASE + 1
	.long kernel_table1_map + 0xC00 - KERNEL_BASE + 1
	.long kernel_exception_map + 0x000 - KERNEL_BASE + 1
	.long kernel_exception_map + 0x400 - KERNEL_BASE + 1
	.long kernel_exception_map + 0x800 - KERNEL_BASE + 1
	.long kernel_exception_map + 0xC00 - KERNEL_BASE + 1

@ PID0 user table
.globl user_table1_map
@ User table1 data table (only the first half is needed)
@ - Abused to provide kernel stacks in the unused half of the table
user_table1_map:	@ Size = 4KiB (only 2KiB used)
	.rept 0x800/4-1
		.long 0
	.endr
	.long user_table1_map - KERNEL_BASE + 0x13  	@ ...1FF000 = 0x7FDFF000
	@ Kernel stack zone
	.long kernel_table0 + 0x0000 - KERNEL_BASE + 0x13	@ ...200000 = 0x7FE00000
	.long kernel_table0 + 0x1000 - KERNEL_BASE + 0x13	@ ...201000 = 0x7FE01000
	.rept (0x800/4)-(MM_KSTACK_SIZE/0x1000)-2
		.long 0
	.endr
	#if MM_KSTACK_SIZE != 0x2000
	#error Kernel stack size not changed in start.S
	#endif
	.long stack + 0x0000 - KERNEL_BASE + 0x13	@ Kernel Stack
	.long stack + 0x1000 - KERNEL_BASE + 0x13	@ 

.globl kernel_table1_map
kernel_table1_map:	@ Size = 4KiB
	.rept (0xF00+16)/4
		.long 0
	.endr
	.long hwmap_table_0 - KERNEL_BASE + 0x13
	.rept 0xFF8/4 - (0xF00+16)/4 - 1
		.long 0
	.endr
	.long kernel_table1_map - KERNEL_BASE + 0x13
	.long kernel_exception_map - KERNEL_BASE + 0x13

@ Hardware mappings 
.globl hwmap_table_0
hwmap_table_0:
	.long UART0_PADDR + 0x13	@ UART0
	.rept 1024 - 1
		.long 0
	.endr
.globl kernel_exception_map
kernel_exception_map:
	@ Padding
	.rept 1024-256
		.long 0
	.endr
	@ Align to nearly the end
	.rept 256-16
		.long	0
	.endr
	.long 0x212	@ Map first page for exceptions (Kernel RO, Execute)
	.rept 16-1-2
		.long 0
	.endr
	.long gUsertextPhysStart + 0x22	@ User .text (User RO, Kernel RW, because both is COW)
	.long 0
	
.section .padata
stack:
	.space MM_KSTACK_SIZE, 0	@ Original kernel stack

// vim: ts=8 ft=armv7

