mirror of
https://github.com/acpica/acpica/
synced 2025-02-24 17:34:43 +03:00
iASL: Add generic data types to the Data Table compiler.
Add "generic" data types such as UINT32, String, Unicode, etc., to simplify the generation of platform-defined tables such as UEFI. Lin Ming.
This commit is contained in:
parent
a90085ba04
commit
a39fa5a0a6
@ -667,7 +667,7 @@ AdCreateTableHeader (
|
||||
|
||||
if (ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_DSDT))
|
||||
{
|
||||
AcpiOsPrintf (" **** ACPI 1.0, no 64-bit math support");
|
||||
AcpiOsPrintf (" **** 32-bit table (V1), no 64-bit math support");
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -348,7 +348,7 @@ ACPI_DMTABLE_DATA AcpiDmTableData[] =
|
||||
{ACPI_SIG_SPMI, AcpiDmTableInfoSpmi, NULL, NULL, TemplateSpmi, "Server Platform Management Interface table"},
|
||||
{ACPI_SIG_SRAT, NULL, AcpiDmDumpSrat, DtCompileSrat, TemplateSrat, "System Resource Affinity Table"},
|
||||
{ACPI_SIG_TCPA, AcpiDmTableInfoTcpa, NULL, NULL, TemplateTcpa, "Trusted Computing Platform Alliance table"},
|
||||
{ACPI_SIG_UEFI, AcpiDmTableInfoUefi, NULL, NULL, TemplateUefi, "UEFI Boot Optimization Table"},
|
||||
{ACPI_SIG_UEFI, AcpiDmTableInfoUefi, NULL, DtCompileUefi, TemplateUefi, "UEFI Boot Optimization Table"},
|
||||
{ACPI_SIG_WAET, AcpiDmTableInfoWaet, NULL, NULL, TemplateWaet, "Windows ACPI Emulated Devices Table"},
|
||||
{ACPI_SIG_WDAT, NULL, AcpiDmDumpWdat, DtCompileWdat, TemplateWdat, "Watchdog Action Table"},
|
||||
{ACPI_SIG_WDDT, AcpiDmTableInfoWddt, NULL, NULL, TemplateWddt, "Watchdog Description Table"},
|
||||
@ -647,6 +647,7 @@ AcpiDmDumpTable (
|
||||
const char *Name;
|
||||
BOOLEAN LastOutputBlankLine = FALSE;
|
||||
char RepairedName[8];
|
||||
UINT32 i;
|
||||
|
||||
|
||||
if (!Info)
|
||||
@ -719,6 +720,7 @@ AcpiDmDumpTable (
|
||||
ByteLength = 8;
|
||||
break;
|
||||
case ACPI_DMT_BUF16:
|
||||
case ACPI_DMT_UUID:
|
||||
ByteLength = 16;
|
||||
break;
|
||||
case ACPI_DMT_STRING:
|
||||
@ -836,6 +838,27 @@ AcpiDmDumpTable (
|
||||
AcpiOsPrintf ("\n");
|
||||
break;
|
||||
|
||||
case ACPI_DMT_UUID:
|
||||
|
||||
/* Convert 16-byte UUID buffer to 36-byte formatted UUID string */
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
MsgBuffer[OpcMapToUUID[i]] = (UINT8) HexLookup[(Target[i] >> 4) & 0xF];
|
||||
MsgBuffer[OpcMapToUUID[i] + 1] = (UINT8) HexLookup[Target[i] & 0xF];
|
||||
}
|
||||
|
||||
MsgBuffer[36] = 0; /* Null terminate */
|
||||
|
||||
/* Insert required hyphens (dashes) */
|
||||
|
||||
MsgBuffer[8] = '-';
|
||||
MsgBuffer[13] = '-';
|
||||
MsgBuffer[18] = '-';
|
||||
MsgBuffer[23] = '-';
|
||||
AcpiOsPrintf ("%s\n", MsgBuffer);
|
||||
break;
|
||||
|
||||
case ACPI_DMT_STRING:
|
||||
|
||||
AcpiOsPrintf ("\"%s\"\n", ACPI_CAST_PTR (char, Target));
|
||||
|
@ -1503,7 +1503,7 @@ ACPI_DMTABLE_INFO AcpiDmTableInfoTcpa[] =
|
||||
|
||||
ACPI_DMTABLE_INFO AcpiDmTableInfoUefi[] =
|
||||
{
|
||||
{ACPI_DMT_BUF16, ACPI_UEFI_OFFSET (Identifier[0]), "UUID Identifier", 0},
|
||||
{ACPI_DMT_UUID, ACPI_UEFI_OFFSET (Identifier[0]), "UUID Identifier", 0},
|
||||
{ACPI_DMT_UINT16, ACPI_UEFI_OFFSET (DataOffset), "Data Offset", 0},
|
||||
ACPI_DMT_TERMINATOR
|
||||
};
|
||||
@ -1623,3 +1623,42 @@ ACPI_DMTABLE_INFO AcpiDmTableInfoWdrt[] =
|
||||
{ACPI_DMT_UINT8, ACPI_WDRT_OFFSET (Units), "Counter Units", 0},
|
||||
ACPI_DMT_TERMINATOR
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic types (used in UEFI)
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* Buffer : cc 04 ff bb
|
||||
* UINT8 : 11
|
||||
* UINT16 : 1122
|
||||
* UINT24 : 112233
|
||||
* UINT32 : 11223344
|
||||
* UINT56 : 11223344556677
|
||||
* UINT64 : 1122334455667788
|
||||
*
|
||||
* String : "This is string"
|
||||
* Unicode : "This string encoded to Unicode"
|
||||
*
|
||||
* GUID : 11223344-5566-7788-99aa-bbccddeeff00
|
||||
* DevicePath : "\PciRoot(0)\Pci(0x1f,1)\Usb(0,0)"
|
||||
*/
|
||||
|
||||
#define ACPI_DM_GENERIC_ENTRY(FieldType, FieldName)\
|
||||
{{FieldType, 0, FieldName, 0}, ACPI_DMT_TERMINATOR}
|
||||
|
||||
ACPI_DMTABLE_INFO AcpiDmTableInfoGeneric[][2] =
|
||||
{
|
||||
ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UINT8, "UINT8"),
|
||||
ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UINT16, "UINT16"),
|
||||
ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UINT24, "UINT24"),
|
||||
ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UINT32, "UINT32"),
|
||||
ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UINT56, "UINT56"),
|
||||
ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UINT64, "UINT64"),
|
||||
ACPI_DM_GENERIC_ENTRY (ACPI_DMT_STRING, "String"),
|
||||
ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UNICODE, "Unicode"),
|
||||
ACPI_DM_GENERIC_ENTRY (ACPI_DMT_BUFFER, "Buffer"),
|
||||
ACPI_DM_GENERIC_ENTRY (ACPI_DMT_UUID, "GUID"),
|
||||
ACPI_DM_GENERIC_ENTRY (ACPI_DMT_STRING, "DevicePath"),
|
||||
{ACPI_DMT_TERMINATOR}
|
||||
};
|
||||
|
@ -123,9 +123,20 @@
|
||||
ACPI_MODULE_NAME ("aslopcodes")
|
||||
|
||||
|
||||
/* UUID support */
|
||||
|
||||
static UINT8 OpcMapToUUID[16] =
|
||||
/*
|
||||
* UUID support. The input ascii string will be converted to a 16 byte
|
||||
* buffer. This table maps an output buffer index 0-15 to the index
|
||||
* within the input string where the associated 2-byte hex value can be
|
||||
* found.
|
||||
*
|
||||
* Input string is of the form:
|
||||
* aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
|
||||
* Where aa-pp are one byte hex numbers, made up of two hex digits
|
||||
*
|
||||
* Note: This table is basically the inverse of the string-to-offset table
|
||||
* found in the ACPI spec in the description of the ToUUID macro.
|
||||
*/
|
||||
UINT8 OpcMapToUUID[16] =
|
||||
{
|
||||
6,4,2,0,11,9,16,14,19,21,24,26,28,30,32,34
|
||||
};
|
||||
|
@ -142,6 +142,9 @@
|
||||
#define DT_FIELD_TYPE_FLAG 4
|
||||
#define DT_FIELD_TYPE_FLAGS_INTEGER 5
|
||||
#define DT_FIELD_TYPE_INLINE_SUBTABLE 6
|
||||
#define DT_FIELD_TYPE_UUID 7
|
||||
#define DT_FIELD_TYPE_UNICODE 8
|
||||
#define DT_FIELD_TYPE_DEVICE_PATH 9
|
||||
|
||||
|
||||
/*
|
||||
@ -438,6 +441,10 @@ ACPI_STATUS
|
||||
DtCompileSrat (
|
||||
void **PFieldList);
|
||||
|
||||
ACPI_STATUS
|
||||
DtCompileUefi (
|
||||
void **PFieldList);
|
||||
|
||||
ACPI_STATUS
|
||||
DtCompileWdat (
|
||||
void **PFieldList);
|
||||
@ -446,6 +453,8 @@ ACPI_STATUS
|
||||
DtCompileXsdt (
|
||||
void **PFieldList);
|
||||
|
||||
extern UINT8 OpcMapToUUID[16];
|
||||
|
||||
/* ACPI Table templates */
|
||||
|
||||
extern const unsigned char TemplateAsf[];
|
||||
@ -480,8 +489,4 @@ extern const unsigned char TemplateWddt[];
|
||||
extern const unsigned char TemplateWdrt[];
|
||||
extern const unsigned char TemplateXsdt[];
|
||||
|
||||
/* Debug */
|
||||
|
||||
#define MYDEBUG printf
|
||||
|
||||
#endif
|
||||
|
@ -130,6 +130,18 @@ DtCompileString (
|
||||
DT_FIELD *Field,
|
||||
UINT32 ByteLength);
|
||||
|
||||
static void
|
||||
DtCompileUnicode (
|
||||
UINT8 *Buffer,
|
||||
DT_FIELD *Field,
|
||||
UINT32 ByteLength);
|
||||
|
||||
static ACPI_STATUS
|
||||
DtCompileUuid (
|
||||
UINT8 *Buffer,
|
||||
DT_FIELD *Field,
|
||||
UINT32 ByteLength);
|
||||
|
||||
static char *
|
||||
DtNormalizeBuffer (
|
||||
char *Buffer,
|
||||
@ -159,6 +171,7 @@ DtCompileOneField (
|
||||
UINT8 Type,
|
||||
UINT8 Flags)
|
||||
{
|
||||
ACPI_STATUS Status;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
@ -170,10 +183,26 @@ DtCompileOneField (
|
||||
DtCompileString (Buffer, Field, ByteLength);
|
||||
break;
|
||||
|
||||
case DT_FIELD_TYPE_UUID:
|
||||
Status = DtCompileUuid (Buffer, Field, ByteLength);
|
||||
if (ACPI_SUCCESS (Status))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fall through. */
|
||||
|
||||
case DT_FIELD_TYPE_BUFFER:
|
||||
DtCompileBuffer (Buffer, Field->Value, Field, ByteLength);
|
||||
break;
|
||||
|
||||
case DT_FIELD_TYPE_UNICODE:
|
||||
DtCompileUnicode (Buffer, Field, ByteLength);
|
||||
break;
|
||||
|
||||
case DT_FIELD_TYPE_DEVICE_PATH:
|
||||
break;
|
||||
|
||||
default:
|
||||
DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid field type");
|
||||
break;
|
||||
@ -219,6 +248,117 @@ DtCompileString (
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: DtCompileUnicode
|
||||
*
|
||||
* PARAMETERS: Buffer - Output buffer
|
||||
* Field - String to be copied to buffer
|
||||
* ByteLength - Maximum length of string
|
||||
*
|
||||
* RETURN: None
|
||||
*
|
||||
* DESCRIPTION: Convert ASCII string to Unicode string
|
||||
*
|
||||
* Note: The Unicode string is 16 bits per character, no leading signature,
|
||||
* with a 16-bit terminating NULL.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
static void
|
||||
DtCompileUnicode (
|
||||
UINT8 *Buffer,
|
||||
DT_FIELD *Field,
|
||||
UINT32 ByteLength)
|
||||
{
|
||||
UINT32 Count;
|
||||
UINT32 i;
|
||||
char *AsciiString;
|
||||
UINT16 *UnicodeString;
|
||||
|
||||
|
||||
AsciiString = Field->Value;
|
||||
UnicodeString = (UINT16 *) Buffer;
|
||||
Count = ACPI_STRLEN (AsciiString) + 1;
|
||||
|
||||
/* Convert to Unicode string (including null terminator) */
|
||||
|
||||
for (i = 0; i < Count; i++)
|
||||
{
|
||||
UnicodeString[i] = (UINT16) AsciiString[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: DtCompileUuid
|
||||
*
|
||||
* PARAMETERS: Buffer - Output buffer
|
||||
* Field - String to be copied to buffer
|
||||
* ByteLength - Maximum length of string
|
||||
*
|
||||
* RETURN: None
|
||||
*
|
||||
* DESCRIPTION: Convert UUID string to 16-byte buffer
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static ACPI_STATUS
|
||||
DtCompileUuid (
|
||||
UINT8 *Buffer,
|
||||
DT_FIELD *Field,
|
||||
UINT32 ByteLength)
|
||||
{
|
||||
char *InString;
|
||||
ACPI_STATUS Status = AE_OK;
|
||||
UINT32 i;
|
||||
|
||||
|
||||
InString = Field->Value;
|
||||
|
||||
if (ACPI_STRLEN (InString) != 36)
|
||||
{
|
||||
Status = AE_BAD_PARAMETER;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check all 36 characters for correct format */
|
||||
|
||||
for (i = 0; i < 36; i++)
|
||||
{
|
||||
if ((i == 8) || (i == 13) || (i == 18) || (i == 23))
|
||||
{
|
||||
if (InString[i] != '-')
|
||||
{
|
||||
Status = AE_BAD_PARAMETER;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ACPI_IS_XDIGIT ((int) InString[i]))
|
||||
{
|
||||
Status = AE_BAD_PARAMETER;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ACPI_FAILURE (Status))
|
||||
{
|
||||
sprintf (MsgBuffer, "%s", Field->Value);
|
||||
DtNameError (ASL_ERROR, ASL_MSG_INVALID_UUID, Field, MsgBuffer);
|
||||
}
|
||||
else for (i = 0; i < 16; i++)
|
||||
{
|
||||
Buffer[i] = (char) (UtHexCharToValue (InString[OpcMapToUUID[i]]) << 4);
|
||||
Buffer[i] |= (char) UtHexCharToValue (InString[OpcMapToUUID[i] + 1]);
|
||||
}
|
||||
|
||||
return (Status);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: DtCompileInteger
|
||||
|
@ -324,7 +324,7 @@ DtParseLine (
|
||||
}
|
||||
|
||||
Colon = strchr (LineBuffer, ':');
|
||||
if (!Colon || *(Colon - 1) != ' ')
|
||||
if (!Colon)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -351,7 +351,6 @@ DtParseLine (
|
||||
|
||||
if (Start == Colon)
|
||||
{
|
||||
MYDEBUG ("ERROR: right bracket reaches colon position\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1348,6 +1348,127 @@ DtCompileSrat (
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: DtTableInfoGeneric
|
||||
*
|
||||
* PARAMETERS: Name - Generic type name
|
||||
*
|
||||
* RETURN: Info entry
|
||||
*
|
||||
* DESCRIPTION: Obtain table info for a generic name entry
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
static ACPI_DMTABLE_INFO *
|
||||
DtTableInfoGeneric (
|
||||
char *Name)
|
||||
{
|
||||
ACPI_DMTABLE_INFO *Info;
|
||||
UINT32 i;
|
||||
|
||||
|
||||
if (!Name)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Search info table for name match */
|
||||
|
||||
for (i = 0; ; i++)
|
||||
{
|
||||
Info = AcpiDmTableInfoGeneric[i];
|
||||
if (Info->Opcode == ACPI_DMT_EXIT)
|
||||
{
|
||||
Info = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ACPI_STRCMP (Name, Info->Name))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (Info);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: DtCompileUefi
|
||||
*
|
||||
* PARAMETERS: List - Current field list pointer
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Compile UEFI.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
ACPI_STATUS
|
||||
DtCompileUefi (
|
||||
void **List)
|
||||
{
|
||||
ACPI_STATUS Status;
|
||||
DT_SUBTABLE *Subtable;
|
||||
DT_SUBTABLE *ParentTable;
|
||||
DT_FIELD **PFieldList = (DT_FIELD **) List;
|
||||
ACPI_DMTABLE_INFO *Info;
|
||||
UINT16 *DataOffset;
|
||||
|
||||
|
||||
Status = DtCompileTable (PFieldList, AcpiDmTableInfoUefi,
|
||||
&Subtable, TRUE);
|
||||
if (ACPI_FAILURE (Status))
|
||||
{
|
||||
return (Status);
|
||||
}
|
||||
|
||||
DataOffset = (UINT16 *) (Subtable->Buffer + 16);
|
||||
*DataOffset = sizeof (ACPI_TABLE_UEFI);
|
||||
|
||||
ParentTable = DtPeekSubtable ();
|
||||
DtInsertSubtable (ParentTable, Subtable);
|
||||
|
||||
while (*PFieldList)
|
||||
{
|
||||
Info = DtTableInfoGeneric ((*PFieldList)->Name);
|
||||
if (!Info)
|
||||
{
|
||||
sprintf (MsgBuffer, "Generic data type \"%s\" not found",
|
||||
(*PFieldList)->Name);
|
||||
DtNameError (ASL_ERROR, ASL_MSG_INVALID_FIELD_NAME,
|
||||
(*PFieldList), MsgBuffer);
|
||||
|
||||
*PFieldList = (*PFieldList)->Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
Status = DtCompileTable (PFieldList, Info,
|
||||
&Subtable, TRUE);
|
||||
if (ACPI_SUCCESS (Status))
|
||||
{
|
||||
DtInsertSubtable (ParentTable, Subtable);
|
||||
}
|
||||
else
|
||||
{
|
||||
*PFieldList = (*PFieldList)->Next;
|
||||
|
||||
if (Status == AE_NOT_FOUND)
|
||||
{
|
||||
sprintf (MsgBuffer, "Generic data type \"%s\" not found",
|
||||
(*PFieldList)->Name);
|
||||
DtNameError (ASL_ERROR, ASL_MSG_INVALID_FIELD_NAME,
|
||||
(*PFieldList), MsgBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: DtCompileWdat
|
||||
|
@ -481,6 +481,18 @@ DtGetFieldType (
|
||||
Type = DT_FIELD_TYPE_INLINE_SUBTABLE;
|
||||
break;
|
||||
|
||||
case ACPI_DMT_UNICODE:
|
||||
Type = DT_FIELD_TYPE_UNICODE;
|
||||
break;
|
||||
|
||||
case ACPI_DMT_UUID:
|
||||
Type = DT_FIELD_TYPE_UUID;
|
||||
break;
|
||||
|
||||
case ACPI_DMT_DEVICE_PATH:
|
||||
Type = DT_FIELD_TYPE_DEVICE_PATH;
|
||||
break;
|
||||
|
||||
default:
|
||||
Type = DT_FIELD_TYPE_INTEGER;
|
||||
break;
|
||||
@ -619,10 +631,16 @@ DtGetFieldLength (
|
||||
|
||||
case ACPI_DMT_STRING:
|
||||
Value = DtGetFieldValue (Field, Info->Name);
|
||||
if (Value)
|
||||
{
|
||||
ByteLength = ACPI_STRLEN (Value) + 1;
|
||||
}
|
||||
else
|
||||
{ /* At this point, this is a fatal error */
|
||||
|
||||
/* TBD: error if Value is NULL? (as below?) */
|
||||
|
||||
ByteLength = ACPI_STRLEN (Value) + 1;
|
||||
sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
|
||||
DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_DMT_GAS:
|
||||
@ -648,9 +666,18 @@ DtGetFieldLength (
|
||||
break;
|
||||
|
||||
case ACPI_DMT_BUF16:
|
||||
case ACPI_DMT_UUID:
|
||||
ByteLength = 16;
|
||||
break;
|
||||
|
||||
case ACPI_DMT_UNICODE:
|
||||
Value = DtGetFieldValue (Field, Info->Name);
|
||||
|
||||
/* TBD: error if Value is NULL? (as below?) */
|
||||
|
||||
ByteLength = (ACPI_STRLEN (Value) + 1) * sizeof(UINT16);
|
||||
break;
|
||||
|
||||
default:
|
||||
DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid table opcode");
|
||||
break;
|
||||
|
@ -190,6 +190,9 @@ typedef const struct acpi_dmtable_info
|
||||
#define ACPI_DMT_ERSTACT 39
|
||||
#define ACPI_DMT_ERSTINST 40
|
||||
#define ACPI_DMT_ACCWIDTH 41
|
||||
#define ACPI_DMT_UNICODE 42
|
||||
#define ACPI_DMT_UUID 43
|
||||
#define ACPI_DMT_DEVICE_PATH 44
|
||||
|
||||
|
||||
typedef
|
||||
@ -340,6 +343,8 @@ extern ACPI_DMTABLE_INFO AcpiDmTableInfoWdat0[];
|
||||
extern ACPI_DMTABLE_INFO AcpiDmTableInfoWddt[];
|
||||
extern ACPI_DMTABLE_INFO AcpiDmTableInfoWdrt[];
|
||||
|
||||
extern ACPI_DMTABLE_INFO AcpiDmTableInfoGeneric[][2];
|
||||
|
||||
|
||||
/*
|
||||
* dmtable
|
||||
|
Loading…
x
Reference in New Issue
Block a user