Recovered clean project
* improved Makefile * fixed openocd script - removed uneeded file * minor cosmetic tweaks
This commit is contained in:
parent
de28e1e8c5
commit
f9113fc410
142
Makefile
142
Makefile
@ -1,4 +1,4 @@
|
||||
#-----------------------------------------------------------------------------
|
||||
#-------------------------------------------------------------------------------
|
||||
# this GNU-makefile relies on the GCC toolchain
|
||||
|
||||
# --- control global project settings
|
||||
@ -29,11 +29,12 @@ UADEFS=
|
||||
|
||||
# --- toolchain configuration
|
||||
TARGET=arm-none-eabi-
|
||||
CC=$(TARGET)gcc
|
||||
OBJCOPY=$(TARGET)objcopy
|
||||
AS=$(TARGET)gcc -x assembler-with-cpp -c
|
||||
SIZE=$(TARGET)size
|
||||
OBJDUMP=$(TARGET)objdump
|
||||
CC=${TARGET}gcc
|
||||
CPP=${TARGET}g++
|
||||
OBJCOPY=${TARGET}objcopy
|
||||
AS=${TARGET}gcc -x assembler-with-cpp -c
|
||||
SIZE=${TARGET}size
|
||||
OBJDUMP=${TARGET}objdump
|
||||
|
||||
# --- hardware settings
|
||||
ARCH=armv7-m
|
||||
@ -42,53 +43,76 @@ CPU=cortex-m3
|
||||
CPUFLAGS=-mthumb
|
||||
FPU=fpv4-sp-d16 #"FLOAT-ABI=soft" disable that
|
||||
|
||||
##-----------------------------------------------------------------------------
|
||||
#-------------------------------------------------------------------------------
|
||||
# --- makefile pre-incantation
|
||||
|
||||
# List all default C defines here, like -D_DEBUG=1
|
||||
DDEFS=-march=$(ARCH) -mfloat-abi=$(FLOAT-ABI) -mcpu=$(CPU) -mfpu=$(FPU) $(CPUFLAGS)
|
||||
# List all de:fault C defines here, like -D_DEBUG=1
|
||||
DDEFS=-march=${ARCH} -mfloat-abi=${FLOAT-ABI} -mcpu=${CPU} -mfpu=${FPU} $\
|
||||
${CPUFLAGS}
|
||||
# List all default ASM defines here, like -D_DEBUG=1
|
||||
DADEFS=-D__ASSEMBLY__
|
||||
|
||||
# --- deduce file names
|
||||
MAIN_C_FILES=${wildcard ${SRC}/${strip ${EXE_PREFIX}}*.c}
|
||||
COMMON_C_FILES=${filter-out ${MAIN_C_FILES},${wildcard ${SRC}/*.c} \
|
||||
${foreach dir,${SUBFOLDERS},${wildcard ${SRC}/${dir}/*.c}}}
|
||||
COMMON_ASM_FILES=${filter-out ${MAIN_CXX_FILES},${wildcard *.s} \
|
||||
${foreach dir,${SUBFOLDERS},${wildcard ${SRC}/${dir}/*.s}}}
|
||||
MAIN_OBJECT_FILES=${sort ${patsubst ${SRC}/%.c,${OBJ}/%.o,${MAIN_C_FILES}}}
|
||||
COMMON_OBJECT_FILES=${sort ${patsubst ${SRC}/%.c,${OBJ}/%.o,${COMMON_C_FILES}} \
|
||||
${patsubst ${SRC}/%.s,${OBJ}/%.o,${COMMON_ASM_FILES}}}
|
||||
MAIN_CPP_FILES=${wildcard ${SRC}/${strip ${EXE_PREFIX}}*.cpp}
|
||||
|
||||
COMMON_C_FILES=${filter-out ${MAIN_C_FILES},${wildcard ${SRC}/*.c}}
|
||||
COMMON_C_FILES+=${foreach dir,${SUBFOLDERS},${wildcard ${SRC}/${dir}/*.c}}
|
||||
|
||||
COMMON_CPP_FILES=${filter-out ${MAIN_CPP_FILES},${wildcard ${SRC}/*.cpp}}
|
||||
COMMON_CPP_FILES+=${foreach dir,${SUBFOLDERS},${wildcard ${SRC}/${dir}/*.cpp}}
|
||||
|
||||
COMMON_ASM_FILES=${foreach dir,${SUBFOLDERS},${wildcard ${SRC}/${dir}/*.s}}
|
||||
|
||||
MAIN_OBJECT_FILES=${sort ${patsubst ${src}/%.c,${obj}/%.o,${MAIN_C_FILES}} \
|
||||
${patsubst ${src}/%.cpp,${obj}/%.o,${MAIN_CPP_FILES}}}
|
||||
COMMON_OBJECT_FILES=${sort \
|
||||
${patsubst ${SRC}/%.c,${OBJ}/%.o,${COMMON_C_FILES}} \
|
||||
${patsubst ${SRC}/%.cpp,${OBJ}/%.o,${COMMON_CPP_FILES}} \
|
||||
${patsubst ${SRC}/%s,${OBJ}/%o,${COMMON_ASM_FILES}}}
|
||||
|
||||
LIBRARIES=${foreach dir,${wildcard ${LIB}/*},${wildcard ${LIB}/${dir}/*.a}}
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
OBJECT_FILES=${MAIN_OBJECT_FILES} ${COMMON_OBJECT_FILES}
|
||||
DEPEND_FILES=${OBJECT_FILES:%.o,%.d}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# --- makefile incantation
|
||||
# down here is black magic, you probably don't want to modify anything
|
||||
|
||||
DEFS =$(DDEFS) $(UDEFS)
|
||||
ADEFS =$(DADEFS) $(UADEFS)
|
||||
DEFS=${DDEFS} ${UDEFS}
|
||||
ADEFS=${DADEFS} ${UADEFS}
|
||||
|
||||
# --- otpimisation
|
||||
ifeq (${strip ${RELEASE}},0)
|
||||
CFLAGS=-g3 -O0
|
||||
else
|
||||
CFLAGS=-O3
|
||||
endif
|
||||
|
||||
ASFLAGS = $(LIB) $(DEFS) -Wa,--gdwarf2 $(ADEFS)
|
||||
CFLAGS+=-std=c17 -Wall $(DEFS) -Wextra -Warray-bounds -Wno-unused-parameter -fomit-frame-pointer
|
||||
LDFLAGS= -T$(LDSCRIPT) -lc -lgcc -lgcov -lm -Wl,-Map=$@.map,--gc-sections --specs=nosys.specs
|
||||
INCLUDE=-I${INC}
|
||||
|
||||
# --- c/cpp
|
||||
ifneq (${strip ${MAIN_CPP_FILES} ${COMMON_CPP_FILES}},)
|
||||
CC:=${CPP}
|
||||
CFLAGS+=-std=c++17
|
||||
else
|
||||
CFLAGS+=-std=c17
|
||||
endif
|
||||
|
||||
ASFLAGS=${LIB} $(DEFS) -Wa,--gdwarf2 $(ADEFS)
|
||||
CFLAGS+=-Wall ${DEFS} -Wextra -Warray-bounds -Wno-unused-parameter $\
|
||||
-fomit-frame-pointer
|
||||
LDFLAGS=-T ${LDSCRIPT} -lc -lgcc -lgcov -lm -Wl,-Map=$@.map,--gc-sections $\
|
||||
--specs=nosys.specs
|
||||
INCLUDE=-I ${INC}
|
||||
|
||||
# --- Generate dependency information
|
||||
#CFLAGS += -MD -MP -MF ${DEP}/$(@F0).d
|
||||
#ASFLAGS += -MD -MP -MF ${DEP}/$(@F).d
|
||||
CFLAGS+=-MD -MP -MF ${patsubst %o,%d,$@}
|
||||
ASFLAGS+=#-MD -MP -MF ${patsubst %o,%d,$@}
|
||||
|
||||
# --- folder tree
|
||||
DIR_GUARD=@mkdir -p ${@D}
|
||||
ifeq (${OS},Windows_NT)
|
||||
DIR_GUARD=@md ${@D}
|
||||
endif
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# --- make rules
|
||||
all: ${BIN}/${EXE_PREFIX}.elf ${BIN}/${EXE_PREFIX}.hex ${BIN}/${EXE_PREFIX}.bin
|
||||
|
||||
@ -98,66 +122,68 @@ rebuild : clean all
|
||||
.SECONDARY:
|
||||
.PHONY: all clean rebuild
|
||||
|
||||
# --- compiler command for elf file
|
||||
${BIN}/%.elf : ${MAIN_OBJECT_FILES} ${COMMON_OBJECT_FILES}
|
||||
@echo
|
||||
@echo ==== linking $@ ====
|
||||
@echo -e '\e[32;1m ==== linking $@ ====\e[0m'
|
||||
@echo ${COMMON_OBJECT_FILES}
|
||||
@echo
|
||||
${DIR_GUARD}
|
||||
${CC} ${CFLAGS} -o $@ ${filter-out %ld, $^} ${LIBRARIES} ${LDFLAGS}
|
||||
${CC} ${INCLUDE} ${CFLAGS} -o $@ $^ ${LIBRARIES} ${LDFLAGS}
|
||||
${OBJDUMP} -h $@
|
||||
${SIZE} $@
|
||||
@${SKIP_LINE}
|
||||
@echo
|
||||
|
||||
# --- compiler commands for uploadable files
|
||||
${BIN}/%.hex : ${BIN}/%.elf
|
||||
@echo
|
||||
@echo ==== traducing [opt=${opt}] $< ====
|
||||
@echo
|
||||
@echo -e '\e[33;1m ==== translating $< ====\e[0m'
|
||||
${OBJCOPY} -O ihex $< $@
|
||||
@echo
|
||||
|
||||
${BIN}/%.bin : ${BIN}/%.elf
|
||||
@echo
|
||||
@echo ==== traducing [opt=${opt}] $< ====
|
||||
@echo
|
||||
@echo -e '\e[33;1m ==== translating $< ====\e[0m'
|
||||
${OBJCOPY} -O binary $< $@
|
||||
@echo
|
||||
|
||||
# --- compiler commands for every source file
|
||||
${OBJ}/%.o : ${SRC}/%.cpp
|
||||
@echo -e '\e[36;1m ==== compiling $< ====\e[0m'
|
||||
${DIR_GUARD}
|
||||
${CPP} ${INCLUDE} -c ${CFLAGS} $< -o $@ ${LIBRARIES}
|
||||
@echo
|
||||
|
||||
${BIN}/%.o : ${SRC}/%.cpp
|
||||
@echo -e '\e[36;1m ==== compiling $< ====\e[0m'
|
||||
${DIR_GUARD}
|
||||
${CPP} ${INCLUDE} -c ${CFLAGS} $< -o $@ ${LIBRARIES}
|
||||
@echo
|
||||
|
||||
${OBJ}/%.o : ${SRC}/%.c
|
||||
@echo
|
||||
@echo ==== compiling [opt=${opt}] $< ====
|
||||
@echo
|
||||
@echo -e '\e[34;1m ==== compiling $< ====\e[0m'
|
||||
${DIR_GUARD}
|
||||
${CC} ${INCLUDE} -c ${CFLAGS} $< -o $@ ${LIBRARIES}
|
||||
@${SKIP_LINE}
|
||||
@echo
|
||||
|
||||
${BIN}/%.o : ${SRC}/%.c
|
||||
@echo
|
||||
@echo ==== compiling [opt=${opt}] $< ====
|
||||
@echo
|
||||
@echo -e '\e[34;1m ==== compiling $< ====\e[0m'
|
||||
${DIR_GUARD}
|
||||
${CC} ${INCLUDE} -c ${CFLAGS} $< -o $@ ${LIBRARIES}
|
||||
@${SKIP_LINE}
|
||||
@echo
|
||||
|
||||
${OBJ}/%.o : ${SRC}/%.s
|
||||
@echo
|
||||
@echo ==== compiling [opt=${opt}] $^ $@ ${LIBRARIES}====
|
||||
@echo
|
||||
@echo -e '\e[35;1m ==== compiling $^ ====\e[0m'
|
||||
${DIR_GUARD}
|
||||
${AS} -o ${ASFLAGS} $< -o $@ ${LIBRARIES}
|
||||
@${SKIP_LINE}
|
||||
@echo
|
||||
|
||||
${BIN}/%.o : ${SRC}/%.s
|
||||
@echo
|
||||
@echo ==== compiling [opt=${opt}] $^ $@ ${LIBRARIES}====
|
||||
@echo
|
||||
@echo -e '\e[35;1m ==== compiling $^ ====\e[0m'
|
||||
${DIR_GUARD}
|
||||
${AS} -o ${ASFLAGS} $< -o $@ ${LIBRARIES}
|
||||
@${SKIP_LINE}
|
||||
@echo
|
||||
|
||||
# --- remove generated files
|
||||
clean:
|
||||
-rm -rf ${BIN}/*
|
||||
|
||||
# Include the dependency files, should be the last of the makefile
|
||||
#
|
||||
#-include $(shell mkdir ${DEP}/ 2>/dev/null) $(wildcard ${DEP}/*)
|
||||
-include ${DEPEND_FILES}
|
||||
|
||||
|
||||
@ -1,207 +0,0 @@
|
||||
/******************************************************************************
|
||||
* @file tz_context.c
|
||||
* @brief Context Management for Armv8-M TrustZone - Sample implementation
|
||||
* @version V1.1.1
|
||||
* @date 10. January 2018
|
||||
******************************************************************************/
|
||||
/*
|
||||
* Copyright (c) 2016-2018 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if !TARGET_TFM
|
||||
|
||||
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
|
||||
|
||||
#include "RTE_Components.h"
|
||||
#include CMSIS_device_header
|
||||
#include "tz_context.h"
|
||||
|
||||
/// Number of process slots (threads may call secure library code)
|
||||
#ifndef TZ_PROCESS_STACK_SLOTS
|
||||
#define TZ_PROCESS_STACK_SLOTS 8U
|
||||
#endif
|
||||
|
||||
/// Stack size of the secure library code
|
||||
#ifndef TZ_PROCESS_STACK_SIZE
|
||||
#define TZ_PROCESS_STACK_SIZE 256U
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t sp_top; // stack space top
|
||||
uint32_t sp_limit; // stack space limit
|
||||
uint32_t sp; // current stack pointer
|
||||
} stack_info_t;
|
||||
|
||||
static stack_info_t ProcessStackInfo [TZ_PROCESS_STACK_SLOTS];
|
||||
static uint64_t ProcessStackMemory[TZ_PROCESS_STACK_SLOTS][TZ_PROCESS_STACK_SIZE/8U];
|
||||
static uint32_t ProcessStackFreeSlot = 0xFFFFFFFFU;
|
||||
|
||||
|
||||
/// Initialize secure context memory system
|
||||
/// \return execution status (1: success, 0: error)
|
||||
__attribute__((cmse_nonsecure_entry))
|
||||
uint32_t TZ_InitContextSystem_S (void) {
|
||||
uint32_t n;
|
||||
|
||||
if (__get_IPSR() == 0U) {
|
||||
return 0U; // Thread Mode
|
||||
}
|
||||
|
||||
for (n = 0U; n < TZ_PROCESS_STACK_SLOTS; n++) {
|
||||
ProcessStackInfo[n].sp = 0U;
|
||||
ProcessStackInfo[n].sp_limit = (uint32_t)&ProcessStackMemory[n];
|
||||
ProcessStackInfo[n].sp_top = (uint32_t)&ProcessStackMemory[n] + TZ_PROCESS_STACK_SIZE;
|
||||
*((uint32_t *)ProcessStackMemory[n]) = n + 1U;
|
||||
}
|
||||
*((uint32_t *)ProcessStackMemory[--n]) = 0xFFFFFFFFU;
|
||||
|
||||
ProcessStackFreeSlot = 0U;
|
||||
|
||||
// Default process stack pointer and stack limit
|
||||
__set_PSPLIM((uint32_t)ProcessStackMemory);
|
||||
__set_PSP ((uint32_t)ProcessStackMemory);
|
||||
|
||||
// Privileged Thread Mode using PSP
|
||||
__set_CONTROL(0x02U);
|
||||
|
||||
return 1U; // Success
|
||||
}
|
||||
|
||||
|
||||
/// Allocate context memory for calling secure software modules in TrustZone
|
||||
/// \param[in] module identifies software modules called from non-secure mode
|
||||
/// \return value != 0 id TrustZone memory slot identifier
|
||||
/// \return value 0 no memory available or internal error
|
||||
__attribute__((cmse_nonsecure_entry))
|
||||
TZ_MemoryId_t TZ_AllocModuleContext_S (TZ_ModuleId_t module) {
|
||||
uint32_t slot;
|
||||
|
||||
(void)module; // Ignore (fixed Stack size)
|
||||
|
||||
if (__get_IPSR() == 0U) {
|
||||
return 0U; // Thread Mode
|
||||
}
|
||||
|
||||
if (ProcessStackFreeSlot == 0xFFFFFFFFU) {
|
||||
return 0U; // No slot available
|
||||
}
|
||||
|
||||
slot = ProcessStackFreeSlot;
|
||||
ProcessStackFreeSlot = *((uint32_t *)ProcessStackMemory[slot]);
|
||||
|
||||
ProcessStackInfo[slot].sp = ProcessStackInfo[slot].sp_top;
|
||||
|
||||
return (slot + 1U);
|
||||
}
|
||||
|
||||
|
||||
/// Free context memory that was previously allocated with \ref TZ_AllocModuleContext_S
|
||||
/// \param[in] id TrustZone memory slot identifier
|
||||
/// \return execution status (1: success, 0: error)
|
||||
__attribute__((cmse_nonsecure_entry))
|
||||
uint32_t TZ_FreeModuleContext_S (TZ_MemoryId_t id) {
|
||||
uint32_t slot;
|
||||
|
||||
if (__get_IPSR() == 0U) {
|
||||
return 0U; // Thread Mode
|
||||
}
|
||||
|
||||
if ((id == 0U) || (id > TZ_PROCESS_STACK_SLOTS)) {
|
||||
return 0U; // Invalid ID
|
||||
}
|
||||
|
||||
slot = id - 1U;
|
||||
|
||||
if (ProcessStackInfo[slot].sp == 0U) {
|
||||
return 0U; // Inactive slot
|
||||
}
|
||||
ProcessStackInfo[slot].sp = 0U;
|
||||
|
||||
*((uint32_t *)ProcessStackMemory[slot]) = ProcessStackFreeSlot;
|
||||
ProcessStackFreeSlot = slot;
|
||||
|
||||
return 1U; // Success
|
||||
}
|
||||
|
||||
|
||||
/// Load secure context (called on RTOS thread context switch)
|
||||
/// \param[in] id TrustZone memory slot identifier
|
||||
/// \return execution status (1: success, 0: error)
|
||||
__attribute__((cmse_nonsecure_entry))
|
||||
uint32_t TZ_LoadContext_S (TZ_MemoryId_t id) {
|
||||
uint32_t slot;
|
||||
|
||||
if ((__get_IPSR() == 0U) || ((__get_CONTROL() & 2U) == 0U)) {
|
||||
return 0U; // Thread Mode or using Main Stack for threads
|
||||
}
|
||||
|
||||
if ((id == 0U) || (id > TZ_PROCESS_STACK_SLOTS)) {
|
||||
return 0U; // Invalid ID
|
||||
}
|
||||
|
||||
slot = id - 1U;
|
||||
|
||||
if (ProcessStackInfo[slot].sp == 0U) {
|
||||
return 0U; // Inactive slot
|
||||
}
|
||||
|
||||
// Setup process stack pointer and stack limit
|
||||
__set_PSPLIM(ProcessStackInfo[slot].sp_limit);
|
||||
__set_PSP (ProcessStackInfo[slot].sp);
|
||||
|
||||
return 1U; // Success
|
||||
}
|
||||
|
||||
|
||||
/// Store secure context (called on RTOS thread context switch)
|
||||
/// \param[in] id TrustZone memory slot identifier
|
||||
/// \return execution status (1: success, 0: error)
|
||||
__attribute__((cmse_nonsecure_entry))
|
||||
uint32_t TZ_StoreContext_S (TZ_MemoryId_t id) {
|
||||
uint32_t slot;
|
||||
uint32_t sp;
|
||||
|
||||
if ((__get_IPSR() == 0U) || ((__get_CONTROL() & 2U) == 0U)) {
|
||||
return 0U; // Thread Mode or using Main Stack for threads
|
||||
}
|
||||
|
||||
if ((id == 0U) || (id > TZ_PROCESS_STACK_SLOTS)) {
|
||||
return 0U; // Invalid ID
|
||||
}
|
||||
|
||||
slot = id - 1U;
|
||||
|
||||
if (ProcessStackInfo[slot].sp == 0U) {
|
||||
return 0U; // Inactive slot
|
||||
}
|
||||
|
||||
sp = __get_PSP();
|
||||
if ((sp < ProcessStackInfo[slot].sp_limit) ||
|
||||
(sp > ProcessStackInfo[slot].sp_top)) {
|
||||
return 0U; // SP out of range
|
||||
}
|
||||
ProcessStackInfo[slot].sp = sp;
|
||||
|
||||
// Default process stack pointer and stack limit
|
||||
__set_PSPLIM((uint32_t)ProcessStackMemory);
|
||||
__set_PSP ((uint32_t)ProcessStackMemory);
|
||||
|
||||
return 1U; // Success
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // !TARGET_TFM
|
||||
2
openocd
2
openocd
@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
openocd -f interface/stlink-v2.cfg -f target/cs32f1x.cfg
|
||||
openocd -f interface/stlink.cfg -f target/cs32f1x.cfg
|
||||
|
||||
|
||||
@ -18,7 +18,6 @@ int adc_init(ADC_TypeDef* adc) {
|
||||
|
||||
// set trigger to manual
|
||||
adc->CR1 |= 0x7 << 3;
|
||||
|
||||
adc->SMPR2 |= 0x3FFFFFFF;
|
||||
|
||||
// calibrate
|
||||
@ -38,5 +37,5 @@ uint16_t adc_read(ADC_TypeDef* adc, uint8_t channel) {
|
||||
while(!((adc->SR >> 1) & 0x1)); //waiting for convertion
|
||||
|
||||
return adc->DR & 0xFFF;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1,12 +1,3 @@
|
||||
//target header
|
||||
#include "../target/stm32f103xb.h"
|
||||
|
||||
//custom header
|
||||
#include "../config.h"
|
||||
|
||||
//std headers
|
||||
#include <stdlib.h>
|
||||
|
||||
//driver header
|
||||
#include "io.h"
|
||||
|
||||
|
||||
@ -1,5 +1,15 @@
|
||||
#ifndef _IO_H_
|
||||
#define _IO_H_
|
||||
#ifndef IO_H
|
||||
#define IO_H
|
||||
|
||||
//std headers
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
//target header
|
||||
#include "../target/stm32f103xb.h"
|
||||
|
||||
//custom header
|
||||
#include "../config.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/* GPIO pin mask definitions */
|
||||
|
||||
@ -151,7 +151,7 @@ SECTIONS
|
||||
_ebss = .; /* define a global symbol at bss end */
|
||||
__bss_end__ = _ebss;
|
||||
} >RAM
|
||||
|
||||
|
||||
/* User_heap_stack section, used to check that there is enough "RAM" Ram type
|
||||
* memory left */
|
||||
._user_heap_stack :
|
||||
|
||||
Loading…
Reference in New Issue
Block a user