Commit c94ae4f7 authored by Zi Shen Lim's avatar Zi Shen Lim Committed by David S. Miller

arm64: insn: remove BUG_ON from codegen

During code generation, we used to BUG_ON unknown/unsupported encoding
or invalid parameters.

Instead, now we report these as errors and simply return the
instruction AARCH64_BREAK_FAULT. Users of these codegen helpers should
check for and handle this failure condition as appropriate.

Otherwise, unhandled codegen failure will result in trapping at
run-time due to AARCH64_BREAK_FAULT, which is arguably better than a
BUG_ON.
Signed-off-by: default avatarZi Shen Lim <zlim.lnx@gmail.com>
Acked-by: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent dd7445ad
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Copyright (C) 2013 Huawei Ltd. * Copyright (C) 2013 Huawei Ltd.
* Author: Jiang Liu <liuj97@gmail.com> * Author: Jiang Liu <liuj97@gmail.com>
* *
* Copyright (C) 2014 Zi Shen Lim <zlim.lnx@gmail.com> * Copyright (C) 2014-2016 Zi Shen Lim <zlim.lnx@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -363,6 +363,9 @@ u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, ...@@ -363,6 +363,9 @@ u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
u32 immlo, immhi, mask; u32 immlo, immhi, mask;
int shift; int shift;
if (insn == AARCH64_BREAK_FAULT)
return AARCH64_BREAK_FAULT;
switch (type) { switch (type) {
case AARCH64_INSN_IMM_ADR: case AARCH64_INSN_IMM_ADR:
shift = 0; shift = 0;
...@@ -377,7 +380,7 @@ u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, ...@@ -377,7 +380,7 @@ u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
if (aarch64_get_imm_shift_mask(type, &mask, &shift) < 0) { if (aarch64_get_imm_shift_mask(type, &mask, &shift) < 0) {
pr_err("aarch64_insn_encode_immediate: unknown immediate encoding %d\n", pr_err("aarch64_insn_encode_immediate: unknown immediate encoding %d\n",
type); type);
return 0; return AARCH64_BREAK_FAULT;
} }
} }
...@@ -394,9 +397,12 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type, ...@@ -394,9 +397,12 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type,
{ {
int shift; int shift;
if (insn == AARCH64_BREAK_FAULT)
return AARCH64_BREAK_FAULT;
if (reg < AARCH64_INSN_REG_0 || reg > AARCH64_INSN_REG_SP) { if (reg < AARCH64_INSN_REG_0 || reg > AARCH64_INSN_REG_SP) {
pr_err("%s: unknown register encoding %d\n", __func__, reg); pr_err("%s: unknown register encoding %d\n", __func__, reg);
return 0; return AARCH64_BREAK_FAULT;
} }
switch (type) { switch (type) {
...@@ -417,7 +423,7 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type, ...@@ -417,7 +423,7 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type,
default: default:
pr_err("%s: unknown register type encoding %d\n", __func__, pr_err("%s: unknown register type encoding %d\n", __func__,
type); type);
return 0; return AARCH64_BREAK_FAULT;
} }
insn &= ~(GENMASK(4, 0) << shift); insn &= ~(GENMASK(4, 0) << shift);
...@@ -446,7 +452,7 @@ static u32 aarch64_insn_encode_ldst_size(enum aarch64_insn_size_type type, ...@@ -446,7 +452,7 @@ static u32 aarch64_insn_encode_ldst_size(enum aarch64_insn_size_type type,
break; break;
default: default:
pr_err("%s: unknown size encoding %d\n", __func__, type); pr_err("%s: unknown size encoding %d\n", __func__, type);
return 0; return AARCH64_BREAK_FAULT;
} }
insn &= ~GENMASK(31, 30); insn &= ~GENMASK(31, 30);
...@@ -460,14 +466,17 @@ static inline long branch_imm_common(unsigned long pc, unsigned long addr, ...@@ -460,14 +466,17 @@ static inline long branch_imm_common(unsigned long pc, unsigned long addr,
{ {
long offset; long offset;
/* if ((pc & 0x3) || (addr & 0x3)) {
* PC: A 64-bit Program Counter holding the address of the current pr_err("%s: A64 instructions must be word aligned\n", __func__);
* instruction. A64 instructions must be word-aligned. return range;
*/ }
BUG_ON((pc & 0x3) || (addr & 0x3));
offset = ((long)addr - (long)pc); offset = ((long)addr - (long)pc);
BUG_ON(offset < -range || offset >= range);
if (offset < -range || offset >= range) {
pr_err("%s: offset out of range\n", __func__);
return range;
}
return offset; return offset;
} }
...@@ -484,6 +493,8 @@ u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr, ...@@ -484,6 +493,8 @@ u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr,
* texts are within +/-128M. * texts are within +/-128M.
*/ */
offset = branch_imm_common(pc, addr, SZ_128M); offset = branch_imm_common(pc, addr, SZ_128M);
if (offset >= SZ_128M)
return AARCH64_BREAK_FAULT;
switch (type) { switch (type) {
case AARCH64_INSN_BRANCH_LINK: case AARCH64_INSN_BRANCH_LINK:
...@@ -493,7 +504,7 @@ u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr, ...@@ -493,7 +504,7 @@ u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr,
insn = aarch64_insn_get_b_value(); insn = aarch64_insn_get_b_value();
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown branch encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -510,6 +521,8 @@ u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr, ...@@ -510,6 +521,8 @@ u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr,
long offset; long offset;
offset = branch_imm_common(pc, addr, SZ_1M); offset = branch_imm_common(pc, addr, SZ_1M);
if (offset >= SZ_1M)
return AARCH64_BREAK_FAULT;
switch (type) { switch (type) {
case AARCH64_INSN_BRANCH_COMP_ZERO: case AARCH64_INSN_BRANCH_COMP_ZERO:
...@@ -519,7 +532,7 @@ u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr, ...@@ -519,7 +532,7 @@ u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr,
insn = aarch64_insn_get_cbnz_value(); insn = aarch64_insn_get_cbnz_value();
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown branch encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -530,7 +543,7 @@ u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr, ...@@ -530,7 +543,7 @@ u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr,
insn |= AARCH64_INSN_SF_BIT; insn |= AARCH64_INSN_SF_BIT;
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -550,7 +563,10 @@ u32 aarch64_insn_gen_cond_branch_imm(unsigned long pc, unsigned long addr, ...@@ -550,7 +563,10 @@ u32 aarch64_insn_gen_cond_branch_imm(unsigned long pc, unsigned long addr,
insn = aarch64_insn_get_bcond_value(); insn = aarch64_insn_get_bcond_value();
BUG_ON(cond < AARCH64_INSN_COND_EQ || cond > AARCH64_INSN_COND_AL); if (cond < AARCH64_INSN_COND_EQ || cond > AARCH64_INSN_COND_AL) {
pr_err("%s: unknown condition encoding %d\n", __func__, cond);
return AARCH64_BREAK_FAULT;
}
insn |= cond; insn |= cond;
return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_19, insn, return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_19, insn,
...@@ -583,7 +599,7 @@ u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg, ...@@ -583,7 +599,7 @@ u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg,
insn = aarch64_insn_get_ret_value(); insn = aarch64_insn_get_ret_value();
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown branch encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -606,7 +622,7 @@ u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg, ...@@ -606,7 +622,7 @@ u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg,
insn = aarch64_insn_get_str_reg_value(); insn = aarch64_insn_get_str_reg_value();
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown load/store encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -645,26 +661,30 @@ u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1, ...@@ -645,26 +661,30 @@ u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1,
insn = aarch64_insn_get_stp_post_value(); insn = aarch64_insn_get_stp_post_value();
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown load/store encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
switch (variant) { switch (variant) {
case AARCH64_INSN_VARIANT_32BIT: case AARCH64_INSN_VARIANT_32BIT:
/* offset must be multiples of 4 in the range [-256, 252] */ if ((offset & 0x3) || (offset < -256) || (offset > 252)) {
BUG_ON(offset & 0x3); pr_err("%s: offset must be multiples of 4 in the range of [-256, 252] %d\n",
BUG_ON(offset < -256 || offset > 252); __func__, offset);
return AARCH64_BREAK_FAULT;
}
shift = 2; shift = 2;
break; break;
case AARCH64_INSN_VARIANT_64BIT: case AARCH64_INSN_VARIANT_64BIT:
/* offset must be multiples of 8 in the range [-512, 504] */ if ((offset & 0x7) || (offset < -512) || (offset > 504)) {
BUG_ON(offset & 0x7); pr_err("%s: offset must be multiples of 8 in the range of [-512, 504] %d\n",
BUG_ON(offset < -512 || offset > 504); __func__, offset);
return AARCH64_BREAK_FAULT;
}
shift = 3; shift = 3;
insn |= AARCH64_INSN_SF_BIT; insn |= AARCH64_INSN_SF_BIT;
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -702,7 +722,7 @@ u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst, ...@@ -702,7 +722,7 @@ u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst,
insn = aarch64_insn_get_subs_imm_value(); insn = aarch64_insn_get_subs_imm_value();
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown add/sub encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -713,11 +733,14 @@ u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst, ...@@ -713,11 +733,14 @@ u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst,
insn |= AARCH64_INSN_SF_BIT; insn |= AARCH64_INSN_SF_BIT;
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
BUG_ON(imm & ~(SZ_4K - 1)); if (imm & ~(SZ_4K - 1)) {
pr_err("%s: invalid immediate encoding %d\n", __func__, imm);
return AARCH64_BREAK_FAULT;
}
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst); insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
...@@ -746,7 +769,7 @@ u32 aarch64_insn_gen_bitfield(enum aarch64_insn_register dst, ...@@ -746,7 +769,7 @@ u32 aarch64_insn_gen_bitfield(enum aarch64_insn_register dst,
insn = aarch64_insn_get_sbfm_value(); insn = aarch64_insn_get_sbfm_value();
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown bitfield encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -759,12 +782,18 @@ u32 aarch64_insn_gen_bitfield(enum aarch64_insn_register dst, ...@@ -759,12 +782,18 @@ u32 aarch64_insn_gen_bitfield(enum aarch64_insn_register dst,
mask = GENMASK(5, 0); mask = GENMASK(5, 0);
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
BUG_ON(immr & ~mask); if (immr & ~mask) {
BUG_ON(imms & ~mask); pr_err("%s: invalid immr encoding %d\n", __func__, immr);
return AARCH64_BREAK_FAULT;
}
if (imms & ~mask) {
pr_err("%s: invalid imms encoding %d\n", __func__, imms);
return AARCH64_BREAK_FAULT;
}
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst); insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
...@@ -793,23 +822,33 @@ u32 aarch64_insn_gen_movewide(enum aarch64_insn_register dst, ...@@ -793,23 +822,33 @@ u32 aarch64_insn_gen_movewide(enum aarch64_insn_register dst,
insn = aarch64_insn_get_movn_value(); insn = aarch64_insn_get_movn_value();
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown movewide encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
BUG_ON(imm & ~(SZ_64K - 1)); if (imm & ~(SZ_64K - 1)) {
pr_err("%s: invalid immediate encoding %d\n", __func__, imm);
return AARCH64_BREAK_FAULT;
}
switch (variant) { switch (variant) {
case AARCH64_INSN_VARIANT_32BIT: case AARCH64_INSN_VARIANT_32BIT:
BUG_ON(shift != 0 && shift != 16); if (shift != 0 && shift != 16) {
pr_err("%s: invalid shift encoding %d\n", __func__,
shift);
return AARCH64_BREAK_FAULT;
}
break; break;
case AARCH64_INSN_VARIANT_64BIT: case AARCH64_INSN_VARIANT_64BIT:
insn |= AARCH64_INSN_SF_BIT; insn |= AARCH64_INSN_SF_BIT;
BUG_ON(shift != 0 && shift != 16 && shift != 32 && if (shift != 0 && shift != 16 && shift != 32 && shift != 48) {
shift != 48); pr_err("%s: invalid shift encoding %d\n", __func__,
shift);
return AARCH64_BREAK_FAULT;
}
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -843,20 +882,28 @@ u32 aarch64_insn_gen_add_sub_shifted_reg(enum aarch64_insn_register dst, ...@@ -843,20 +882,28 @@ u32 aarch64_insn_gen_add_sub_shifted_reg(enum aarch64_insn_register dst,
insn = aarch64_insn_get_subs_value(); insn = aarch64_insn_get_subs_value();
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown add/sub encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
switch (variant) { switch (variant) {
case AARCH64_INSN_VARIANT_32BIT: case AARCH64_INSN_VARIANT_32BIT:
BUG_ON(shift & ~(SZ_32 - 1)); if (shift & ~(SZ_32 - 1)) {
pr_err("%s: invalid shift encoding %d\n", __func__,
shift);
return AARCH64_BREAK_FAULT;
}
break; break;
case AARCH64_INSN_VARIANT_64BIT: case AARCH64_INSN_VARIANT_64BIT:
insn |= AARCH64_INSN_SF_BIT; insn |= AARCH64_INSN_SF_BIT;
BUG_ON(shift & ~(SZ_64 - 1)); if (shift & ~(SZ_64 - 1)) {
pr_err("%s: invalid shift encoding %d\n", __func__,
shift);
return AARCH64_BREAK_FAULT;
}
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -885,11 +932,15 @@ u32 aarch64_insn_gen_data1(enum aarch64_insn_register dst, ...@@ -885,11 +932,15 @@ u32 aarch64_insn_gen_data1(enum aarch64_insn_register dst,
insn = aarch64_insn_get_rev32_value(); insn = aarch64_insn_get_rev32_value();
break; break;
case AARCH64_INSN_DATA1_REVERSE_64: case AARCH64_INSN_DATA1_REVERSE_64:
BUG_ON(variant != AARCH64_INSN_VARIANT_64BIT); if (variant != AARCH64_INSN_VARIANT_64BIT) {
pr_err("%s: invalid variant for reverse64 %d\n",
__func__, variant);
return AARCH64_BREAK_FAULT;
}
insn = aarch64_insn_get_rev64_value(); insn = aarch64_insn_get_rev64_value();
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown data1 encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -900,7 +951,7 @@ u32 aarch64_insn_gen_data1(enum aarch64_insn_register dst, ...@@ -900,7 +951,7 @@ u32 aarch64_insn_gen_data1(enum aarch64_insn_register dst,
insn |= AARCH64_INSN_SF_BIT; insn |= AARCH64_INSN_SF_BIT;
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -937,7 +988,7 @@ u32 aarch64_insn_gen_data2(enum aarch64_insn_register dst, ...@@ -937,7 +988,7 @@ u32 aarch64_insn_gen_data2(enum aarch64_insn_register dst,
insn = aarch64_insn_get_rorv_value(); insn = aarch64_insn_get_rorv_value();
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown data2 encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -948,7 +999,7 @@ u32 aarch64_insn_gen_data2(enum aarch64_insn_register dst, ...@@ -948,7 +999,7 @@ u32 aarch64_insn_gen_data2(enum aarch64_insn_register dst,
insn |= AARCH64_INSN_SF_BIT; insn |= AARCH64_INSN_SF_BIT;
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -976,7 +1027,7 @@ u32 aarch64_insn_gen_data3(enum aarch64_insn_register dst, ...@@ -976,7 +1027,7 @@ u32 aarch64_insn_gen_data3(enum aarch64_insn_register dst,
insn = aarch64_insn_get_msub_value(); insn = aarch64_insn_get_msub_value();
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown data3 encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -987,7 +1038,7 @@ u32 aarch64_insn_gen_data3(enum aarch64_insn_register dst, ...@@ -987,7 +1038,7 @@ u32 aarch64_insn_gen_data3(enum aarch64_insn_register dst,
insn |= AARCH64_INSN_SF_BIT; insn |= AARCH64_INSN_SF_BIT;
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
...@@ -1037,20 +1088,28 @@ u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst, ...@@ -1037,20 +1088,28 @@ u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst,
insn = aarch64_insn_get_bics_value(); insn = aarch64_insn_get_bics_value();
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown logical encoding %d\n", __func__, type);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
switch (variant) { switch (variant) {
case AARCH64_INSN_VARIANT_32BIT: case AARCH64_INSN_VARIANT_32BIT:
BUG_ON(shift & ~(SZ_32 - 1)); if (shift & ~(SZ_32 - 1)) {
pr_err("%s: invalid shift encoding %d\n", __func__,
shift);
return AARCH64_BREAK_FAULT;
}
break; break;
case AARCH64_INSN_VARIANT_64BIT: case AARCH64_INSN_VARIANT_64BIT:
insn |= AARCH64_INSN_SF_BIT; insn |= AARCH64_INSN_SF_BIT;
BUG_ON(shift & ~(SZ_64 - 1)); if (shift & ~(SZ_64 - 1)) {
pr_err("%s: invalid shift encoding %d\n", __func__,
shift);
return AARCH64_BREAK_FAULT;
}
break; break;
default: default:
BUG_ON(1); pr_err("%s: unknown variant encoding %d\n", __func__, variant);
return AARCH64_BREAK_FAULT; return AARCH64_BREAK_FAULT;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment