Files
eugenios/arch/riscv/common.s

315 lines
5.2 KiB
ArmAsm

# This Source Code Form is subject to the terms of the Mozilla Public License,
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at https://mozilla.org/MPL/2.0/.
.include "./arch/riscv/constants.s"
.section .data
.globl pmem_address
pmem_address: .word
.section .text
# a0 - First pointer.
# a1 - Second pointer.
# a2 - The length to compare.
#
# Returns 0 in a0 if memory regions are equal.
.type memcmp, @function
.globl memcmp
memcmp:
mv t0, a0
li a0, 0
.Lmemcmp_loop:
beqz a2, .Lmemcmp_end
lbu t1, (t0)
lbu t2, (a1)
sub a0, t1, t2
bnez a0, .Lmemcmp_end
addi t0, t0, 1
addi a1, a1, 1
addi a2, a2, -1
j .Lmemcmp_loop
.Lmemcmp_end:
ret
# Prints a string.
#
# Parameters:
# a0 - String pointer.
# a1 - Length of the string.
.type write_s, @function
.globl write_s
write_s:
# Prologue.
addi sp, sp, -32
sw ra, 28(sp)
sw s0, 24(sp)
addi s0, sp, 32
sw s1, 20(sp)
sw s2, 16(sp)
mv s1, a1
mv s2, a0
.Lwrite_s_if:
beqz s1, .Lwrite_s_end
lw a0, (s2)
call write_c
addi s1, s1, -1
addi s2, s2, 1
j .Lwrite_s_if
.Lwrite_s_end:
lw s1, 20(sp)
lw s2, 16(sp)
# Epilogue.
lw ra, 28(sp)
lw s0, 24(sp)
addi sp, sp, 32
ret
# Prints a character from a0.
#
# Arguments:
# a0 - Character.
.type write_c, @function
.globl write_c
write_c:
li a1, 0
li a2, 0
li a3, 0
li a4, 0
li a5, 0
li a6, 0
li a7, 1 # sbi_console_putchar.
ecall
ret
# Searches for the occurences of a character in the given memory block.
#
# Parameters:
# a0 - Memory block.
# a1 - Needle.
# a2 - Memory size.
#
# Sets a0 to the pointer to the found character or to null if the character
# doesn't occur in the memory block.
.type memchr, @function
.globl memchr
memchr:
.Lmemchr_loop:
beqz a2, .Lmemchr_nil # Exit if the length is 0.
lbu t0, (a0) # Load the character from the memory block.
beq t0, a1, .Lmemchr_end # Exit if the character was found.
# Otherwise, continue with the next character.
addi a0, a0, 1
addi a2, a2, -1
j .Lmemchr_loop
.Lmemchr_nil:
li a0, 0
.Lmemchr_end:
ret
# Locates a substring.
#
# Parameters:
# a0 - Haystack.
# a1 - Haystack size.
# a2 - Needle.
# a3 - Needle size.
#
# Sets a0 to the pointer to the beginning of the substring in memory or to 0
# if the substring doesn't occur in the block.
.type memmem, @function
.globl memmem
memmem:
# Prologue.
addi sp, sp, -24
sw ra, 20(sp)
sw s0, 16(sp)
addi s0, sp, 24
# Save preserved registers. They are used to keep arguments.
sw s1, 12(sp)
sw s2, 8(sp)
sw s3, 4(sp)
sw s4, 0(sp)
mv s1, a0
mv s2, a1
mv s3, a2
mv s4, a3
.Lmemmem_loop:
blt s2, s3, .Lmemmem_nil # Exit if the needle length is greater than memory.
mv a0, s1
mv a1, s3
mv a2, s4
call memcmp
mv t0, a0 # memcmp result.
mv a0, s1 # Memory pointer for the case the substring was found.
beqz t0, .Lmemmem_end
addi s1, s1, 1
add s2, s2, -1
j .Lmemmem_loop
.Lmemmem_nil:
li a0, 0
.Lmemmem_end:
# Restore the preserved registers.
lw s1, 12(sp)
lw s2, 8(sp)
lw s3, 4(sp)
lw s4, 0(sp)
# Epilogue.
lw ra, 20(sp)
lw s0, 16(sp)
add sp, sp, 24
ret
# Copies memory.
#
# Parameters:
# a0 - Destination.
# a1 - Source.
# a2 - Size.
#
# Preserves a0.
.type memcpy, @function
.globl memcpy
memcpy:
mv t0, a0
.Lmemcpy_loop:
beqz a2, .Lmemcpy_end
lbu t1, (a1)
sb t1, (t0)
addi t0, t0, 1
addi a1, a1, 1
addi a2, a2, -1
j .Lmemcpy_loop
.Lmemcpy_end:
ret
# Sets a memory region to the given byte value.
#
# Parameters:
# a0 - Memory chunk to fill.
# a1 - Constant byte.
# a2 - Memory size.
.type memset, @function
.globl memset
memset:
mv t0, a0
.Lmemset_loop:
beqz a2, .Lmemset_end
sb a1, (t0)
addi a2, a2, -1
addi t0, t0, 1
j .Lmemset_loop
.Lmemset_end:
ret
# Maps a page of physical memory to the identical virtual memory.
#
# Parameters:
# a0 - Corresponding virtual address.
# a1 - Physical page address.
# a2 - Page table level. If a2 is 0 a superpage is allocated, otherwise a normal page.
# a3 - Flags.
#
# If the function creates new page tables in a2, it advances a2 by the page size and
# returns it in a0.
.type pmem_map_at, @function
.globl pmem_map_at
pmem_map_at:
csrr t0, satp
slli t0, t0, 12 # Root table address.
li t4, 0xfffffc00
li t5, 0xffc # 10 bit * PTESIZE mask.
li t1, 20
.Lpmem_map_at_loop:
# Multiply VPN[i] by 4 and add to the start address of the page table.
# This gives the physical address of the page table entry.
srl t2, a0, t1
and t2, t2, t5 # VPN[i] * PTESIZE.
add t2, t0, t2 # a + VPN[i] * PTESIZE.
beqz a2, .Lpmem_map_at_leaf
lw t3, (t2)
andi t6, t3, 0b1
beqz t6, .Lpmem_map_at_create
and t0, t3, t4
slli t0, t0, 2
j .Lpmem_map_at_next
.Lpmem_map_at_create:
la a7, pmem_address
# Take a chunk of free memory and use it as the next page table.
# The beginning addres off the chunk is the base address (a) for the next level.
lw t0, (a7)
srli t3, t0, 2
ori t3, t3, 0b1
sw t3, (t2)
li t6, PAGE_SIZE
add t0, t0, t6
sw t0, (a7)
.Lpmem_map_at_next:
# Calculate the next page table address for the next level.
addi t1, t1, -10
addi a2, a2, -1
j .Lpmem_map_at_loop
.Lpmem_map_at_leaf:
srli t3, a1, 2 # Physical page number mapped to 12 bits of the page table entry.
ori a3, a3, 0b1
or t3, t3, a3 # Execute, write, read and valid.
sw t3, (t2)
mv a0, a2
ret