summaryrefslogtreecommitdiffstats
path: root/sys/mips
diff options
context:
space:
mode:
authorgonzo <gonzo@FreeBSD.org>2012-01-06 01:23:26 +0000
committergonzo <gonzo@FreeBSD.org>2012-01-06 01:23:26 +0000
commit3d21003ba1534507e8bfc041be782c59b31ca15e (patch)
tree45dde1707c19803c1cf01dddbc0dea96b24a815c /sys/mips
parent0c24320ceb635484927f19b79b413a85e040aa15 (diff)
downloadFreeBSD-src-3d21003ba1534507e8bfc041be782c59b31ca15e.zip
FreeBSD-src-3d21003ba1534507e8bfc041be782c59b31ca15e.tar.gz
- Add better COP2 (crypto coprocessor) context handler for Octeon. Keep
COP2 disabled and lazily allocate COP2 context structure in exception handler. Keep kernel and userland contexts separated.
Diffstat (limited to 'sys/mips')
-rw-r--r--sys/mips/cavium/cryptocteon/cavium_crypto.c86
-rw-r--r--sys/mips/cavium/files.octeon12
-rw-r--r--sys/mips/cavium/octeon_cop2.S225
-rw-r--r--sys/mips/cavium/octeon_cop2.h210
-rw-r--r--sys/mips/include/cpuregs.h1
-rw-r--r--sys/mips/include/frame.h5
-rw-r--r--sys/mips/include/octeon_cop2.h215
-rw-r--r--sys/mips/include/proc.h12
-rw-r--r--sys/mips/mips/exception.S14
-rw-r--r--sys/mips/mips/genassym.c71
-rw-r--r--sys/mips/mips/locore.S4
-rw-r--r--sys/mips/mips/octeon_cop2.c62
-rw-r--r--sys/mips/mips/octeon_cop2_swtch.S246
-rw-r--r--sys/mips/mips/pm_machdep.c2
-rw-r--r--sys/mips/mips/swtch.S55
-rw-r--r--sys/mips/mips/trap.c83
-rw-r--r--sys/mips/mips/vm_machdep.c49
17 files changed, 1231 insertions, 111 deletions
diff --git a/sys/mips/cavium/cryptocteon/cavium_crypto.c b/sys/mips/cavium/cryptocteon/cavium_crypto.c
index f983cfa..ea01b8d 100644
--- a/sys/mips/cavium/cryptocteon/cavium_crypto.c
+++ b/sys/mips/cavium/cryptocteon/cavium_crypto.c
@@ -87,22 +87,6 @@ __FBSDID("$FreeBSD$");
} \
} while (0)
-static inline unsigned long octeon_crypto_enable(void)
-{
- register_t s;
-
- s = intr_disable();
- mips_wr_status(mips_rd_status() | MIPS_SR_COP_2_BIT);
-
- return (s);
-}
-
-static inline void octeon_crypto_disable(register_t s)
-{
- mips_wr_status(mips_rd_status() & ~MIPS_SR_COP_2_BIT);
- intr_restore(s);
-}
-
#define ESP_HEADER_LENGTH 8
#define DES_CBC_IV_LENGTH 8
#define AES_CBC_IV_LENGTH 16
@@ -252,14 +236,12 @@ octo_calc_hash(uint8_t auth, unsigned char *key, uint64_t *inner, uint64_t *oute
uint64_t *key1;
register uint64_t xor1 = 0x3636363636363636ULL;
register uint64_t xor2 = 0x5c5c5c5c5c5c5c5cULL;
- register_t s;
dprintf("%s()\n", __func__);
memset(hash_key, 0, sizeof(hash_key));
memcpy(hash_key, (uint8_t *) key, (auth ? 20 : 16));
key1 = (uint64_t *) hash_key;
- s = octeon_crypto_enable();
if (auth) {
CVMX_MT_HSH_IV(0x67452301EFCDAB89ULL, 0);
CVMX_MT_HSH_IV(0x98BADCFE10325476ULL, 1);
@@ -332,7 +314,6 @@ octo_calc_hash(uint8_t auth, unsigned char *key, uint64_t *inner, uint64_t *oute
outer[2] = 0;
CVMX_MF_HSH_IV(outer[2], 2);
}
- octeon_crypto_disable(s);
return;
}
@@ -349,7 +330,6 @@ octo_des_cbc_encrypt(
{
uint64_t *data;
int data_i, data_l;
- register_t s;
dprintf("%s()\n", __func__);
@@ -367,7 +347,6 @@ octo_des_cbc_encrypt(
CVMX_PREFETCH0(ivp);
CVMX_PREFETCH0(od->octo_enckey);
- s = octeon_crypto_enable();
/* load 3DES Key */
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
@@ -378,7 +357,6 @@ octo_des_cbc_encrypt(
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1);
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2);
} else {
- octeon_crypto_disable(s);
dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen);
return -EINVAL;
}
@@ -397,7 +375,6 @@ octo_des_cbc_encrypt(
crypt_len -= 8;
}
- octeon_crypto_disable(s);
return 0;
}
@@ -412,7 +389,6 @@ octo_des_cbc_decrypt(
{
uint64_t *data;
int data_i, data_l;
- register_t s;
dprintf("%s()\n", __func__);
@@ -430,8 +406,6 @@ octo_des_cbc_decrypt(
CVMX_PREFETCH0(ivp);
CVMX_PREFETCH0(od->octo_enckey);
- s = octeon_crypto_enable();
-
/* load 3DES Key */
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
if (od->octo_encklen == 24) {
@@ -441,7 +415,6 @@ octo_des_cbc_decrypt(
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1);
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2);
} else {
- octeon_crypto_disable(s);
dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen);
return -EINVAL;
}
@@ -460,7 +433,6 @@ octo_des_cbc_decrypt(
crypt_len -= 8;
}
- octeon_crypto_disable(s);
return 0;
}
@@ -477,7 +449,6 @@ octo_aes_cbc_encrypt(
{
uint64_t *data, *pdata;
int data_i, data_l;
- register_t s;
dprintf("%s()\n", __func__);
@@ -495,8 +466,6 @@ octo_aes_cbc_encrypt(
CVMX_PREFETCH0(ivp);
CVMX_PREFETCH0(od->octo_enckey);
- s = octeon_crypto_enable();
-
/* load AES Key */
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
@@ -511,7 +480,6 @@ octo_aes_cbc_encrypt(
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3);
} else {
- octeon_crypto_disable(s);
dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen);
return -EINVAL;
}
@@ -536,7 +504,6 @@ octo_aes_cbc_encrypt(
crypt_len -= 16;
}
- octeon_crypto_disable(s);
return 0;
}
@@ -551,7 +518,6 @@ octo_aes_cbc_decrypt(
{
uint64_t *data, *pdata;
int data_i, data_l;
- register_t s;
dprintf("%s()\n", __func__);
@@ -569,8 +535,6 @@ octo_aes_cbc_decrypt(
CVMX_PREFETCH0(ivp);
CVMX_PREFETCH0(od->octo_enckey);
- s = octeon_crypto_enable();
-
/* load AES Key */
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
@@ -585,7 +549,6 @@ octo_aes_cbc_decrypt(
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3);
} else {
- octeon_crypto_disable(s);
dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen);
return -EINVAL;
}
@@ -610,7 +573,6 @@ octo_aes_cbc_decrypt(
crypt_len -= 16;
}
- octeon_crypto_disable(s);
return 0;
}
@@ -629,7 +591,6 @@ octo_null_md5_encrypt(
uint64_t *data;
uint64_t tmp1, tmp2;
int data_i, data_l, alen = auth_len;
- register_t s;
dprintf("%s()\n", __func__);
@@ -644,8 +605,6 @@ octo_null_md5_encrypt(
IOV_INIT(iov, data, data_i, data_l);
- s = octeon_crypto_enable();
-
/* Load MD5 IV */
CVMX_MT_HSH_IV(od->octo_hminner[0], 0);
CVMX_MT_HSH_IV(od->octo_hminner[1], 1);
@@ -716,7 +675,6 @@ octo_null_md5_encrypt(
CVMX_MF_HSH_IV(tmp1, 1);
*(uint32_t *)data = (uint32_t) (tmp1 >> 32);
- octeon_crypto_disable(s);
return 0;
}
@@ -735,7 +693,6 @@ octo_null_sha1_encrypt(
uint64_t *data;
uint64_t tmp1, tmp2, tmp3;
int data_i, data_l, alen = auth_len;
- register_t s;
dprintf("%s()\n", __func__);
@@ -750,8 +707,6 @@ octo_null_sha1_encrypt(
IOV_INIT(iov, data, data_i, data_l);
- s = octeon_crypto_enable();
-
/* Load SHA1 IV */
CVMX_MT_HSH_IV(od->octo_hminner[0], 0);
CVMX_MT_HSH_IV(od->octo_hminner[1], 1);
@@ -825,7 +780,6 @@ octo_null_sha1_encrypt(
CVMX_MF_HSH_IV(tmp1, 1);
*(uint32_t *)data = (uint32_t) (tmp1 >> 32);
- octeon_crypto_disable(s);
return 0;
}
@@ -849,7 +803,6 @@ octo_des_cbc_md5_encrypt(
uint32_t *data32;
uint64_t tmp1, tmp2;
int data_i, data_l, alen = auth_len;
- register_t s;
dprintf("%s()\n", __func__);
@@ -870,8 +823,6 @@ octo_des_cbc_md5_encrypt(
CVMX_PREFETCH0(ivp);
CVMX_PREFETCH0(od->octo_enckey);
- s = octeon_crypto_enable();
-
/* load 3DES Key */
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
if (od->octo_encklen == 24) {
@@ -881,7 +832,6 @@ octo_des_cbc_md5_encrypt(
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1);
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2);
} else {
- octeon_crypto_disable(s);
dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen);
return -EINVAL;
}
@@ -981,7 +931,6 @@ octo_des_cbc_md5_encrypt(
CVMX_MF_HSH_IV(tmp1, 1);
*data32 = (uint32_t) (tmp1 >> 32);
- octeon_crypto_disable(s);
return 0;
}
@@ -1002,7 +951,6 @@ octo_des_cbc_md5_decrypt(
uint32_t *data32;
uint64_t tmp1, tmp2;
int data_i, data_l, alen = auth_len;
- register_t s;
dprintf("%s()\n", __func__);
@@ -1023,8 +971,6 @@ octo_des_cbc_md5_decrypt(
CVMX_PREFETCH0(ivp);
CVMX_PREFETCH0(od->octo_enckey);
- s = octeon_crypto_enable();
-
/* load 3DES Key */
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
if (od->octo_encklen == 24) {
@@ -1034,7 +980,6 @@ octo_des_cbc_md5_decrypt(
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1);
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2);
} else {
- octeon_crypto_disable(s);
dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen);
return -EINVAL;
}
@@ -1134,7 +1079,6 @@ octo_des_cbc_md5_decrypt(
CVMX_MF_HSH_IV(tmp1, 1);
*data32 = (uint32_t) (tmp1 >> 32);
- octeon_crypto_disable(s);
return 0;
}
@@ -1158,7 +1102,6 @@ octo_des_cbc_sha1_encrypt(
uint32_t *data32;
uint64_t tmp1, tmp2, tmp3;
int data_i, data_l, alen = auth_len;
- register_t s;
dprintf("%s()\n", __func__);
@@ -1179,8 +1122,6 @@ octo_des_cbc_sha1_encrypt(
CVMX_PREFETCH0(ivp);
CVMX_PREFETCH0(od->octo_enckey);
- s = octeon_crypto_enable();
-
/* load 3DES Key */
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
if (od->octo_encklen == 24) {
@@ -1190,7 +1131,6 @@ octo_des_cbc_sha1_encrypt(
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1);
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2);
} else {
- octeon_crypto_disable(s);
dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen);
return -EINVAL;
}
@@ -1293,7 +1233,6 @@ octo_des_cbc_sha1_encrypt(
CVMX_MF_HSH_IV(tmp1, 1);
*data32 = (uint32_t) (tmp1 >> 32);
- octeon_crypto_disable(s);
return 0;
}
@@ -1314,7 +1253,6 @@ octo_des_cbc_sha1_decrypt(
uint32_t *data32;
uint64_t tmp1, tmp2, tmp3;
int data_i, data_l, alen = auth_len;
- register_t s;
dprintf("%s()\n", __func__);
@@ -1335,8 +1273,6 @@ octo_des_cbc_sha1_decrypt(
CVMX_PREFETCH0(ivp);
CVMX_PREFETCH0(od->octo_enckey);
- s = octeon_crypto_enable();
-
/* load 3DES Key */
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
if (od->octo_encklen == 24) {
@@ -1346,7 +1282,6 @@ octo_des_cbc_sha1_decrypt(
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1);
CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2);
} else {
- octeon_crypto_disable(s);
dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen);
return -EINVAL;
}
@@ -1448,7 +1383,6 @@ octo_des_cbc_sha1_decrypt(
CVMX_MF_HSH_IV(tmp1, 1);
*data32 = (uint32_t) (tmp1 >> 32);
- octeon_crypto_disable(s);
return 0;
}
@@ -1473,7 +1407,6 @@ octo_aes_cbc_md5_encrypt(
uint32_t *data32;
uint64_t tmp1, tmp2;
int data_i, data_l, alen = auth_len;
- register_t s;
dprintf("%s()\n", __func__);
@@ -1494,8 +1427,6 @@ octo_aes_cbc_md5_encrypt(
CVMX_PREFETCH0(ivp);
CVMX_PREFETCH0(od->octo_enckey);
- s = octeon_crypto_enable();
-
/* load AES Key */
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
@@ -1510,7 +1441,6 @@ octo_aes_cbc_md5_encrypt(
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3);
} else {
- octeon_crypto_disable(s);
dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen);
return -EINVAL;
}
@@ -1633,7 +1563,6 @@ octo_aes_cbc_md5_encrypt(
CVMX_MF_HSH_IV(tmp1, 1);
*data32 = (uint32_t) (tmp1 >> 32);
- octeon_crypto_disable(s);
return 0;
}
@@ -1655,7 +1584,6 @@ octo_aes_cbc_md5_decrypt(
uint32_t *data32;
uint64_t tmp1, tmp2;
int data_i, data_l, alen = auth_len;
- register_t s;
dprintf("%s()\n", __func__);
@@ -1676,8 +1604,6 @@ octo_aes_cbc_md5_decrypt(
CVMX_PREFETCH0(ivp);
CVMX_PREFETCH0(od->octo_enckey);
- s = octeon_crypto_enable();
-
/* load AES Key */
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
@@ -1692,7 +1618,6 @@ octo_aes_cbc_md5_decrypt(
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3);
} else {
- octeon_crypto_disable(s);
dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen);
return -EINVAL;
}
@@ -1811,7 +1736,6 @@ octo_aes_cbc_md5_decrypt(
CVMX_MF_HSH_IV(tmp1, 1);
*data32 = (uint32_t) (tmp1 >> 32);
- octeon_crypto_disable(s);
return 0;
}
@@ -1836,7 +1760,6 @@ octo_aes_cbc_sha1_encrypt(
uint32_t *data32;
uint64_t tmp1, tmp2, tmp3;
int data_i, data_l, alen = auth_len;
- register_t s;
dprintf("%s()\n", __func__);
@@ -1857,8 +1780,6 @@ octo_aes_cbc_sha1_encrypt(
CVMX_PREFETCH0(ivp);
CVMX_PREFETCH0(od->octo_enckey);
- s = octeon_crypto_enable();
-
/* load AES Key */
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
@@ -1873,7 +1794,6 @@ octo_aes_cbc_sha1_encrypt(
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3);
} else {
- octeon_crypto_disable(s);
dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen);
return -EINVAL;
}
@@ -2015,7 +1935,6 @@ octo_aes_cbc_sha1_encrypt(
CVMX_MF_HSH_IV(tmp1, 1);
*data32 = (uint32_t) (tmp1 >> 32);
- octeon_crypto_disable(s);
return 0;
}
@@ -2037,7 +1956,6 @@ octo_aes_cbc_sha1_decrypt(
uint32_t *data32;
uint64_t tmp1, tmp2, tmp3;
int data_i, data_l, alen = auth_len;
- register_t s;
dprintf("%s()\n", __func__);
@@ -2058,8 +1976,6 @@ octo_aes_cbc_sha1_decrypt(
CVMX_PREFETCH0(ivp);
CVMX_PREFETCH0(od->octo_enckey);
- s = octeon_crypto_enable();
-
/* load AES Key */
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
@@ -2074,7 +1990,6 @@ octo_aes_cbc_sha1_decrypt(
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3);
} else {
- octeon_crypto_disable(s);
dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen);
return -EINVAL;
}
@@ -2215,7 +2130,6 @@ octo_aes_cbc_sha1_decrypt(
CVMX_MF_HSH_IV(tmp1, 1);
*data32 = (uint32_t) (tmp1 >> 32);
- octeon_crypto_disable(s);
return 0;
}
diff --git a/sys/mips/cavium/files.octeon1 b/sys/mips/cavium/files.octeon1
index acf8275..1e4fdb0 100644
--- a/sys/mips/cavium/files.octeon1
+++ b/sys/mips/cavium/files.octeon1
@@ -21,6 +21,8 @@ mips/cavium/octeon_nmi.S optional octeon_wdog
mips/cavium/cryptocteon/cavium_crypto.c optional cryptocteon
mips/cavium/cryptocteon/cryptocteon.c optional cryptocteon
+mips/mips/octeon_cop2_swtch.S standard
+mips/mips/octeon_cop2.c standard
mips/cavium/octe/ethernet.c optional octe
mips/cavium/octe/ethernet-mv88e61xx.c optional octe octeon_vendor_lanner
diff --git a/sys/mips/cavium/octeon_cop2.S b/sys/mips/cavium/octeon_cop2.S
new file mode 100644
index 0000000..0a983f9
--- /dev/null
+++ b/sys/mips/cavium/octeon_cop2.S
@@ -0,0 +1,225 @@
+/*-
+ * Copyright (c) 2011 Oleksandr Tymoshenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <machine/asm.h>
+#include <mips/cavium/octeon_cop2.h>
+
+#include "assym.s"
+
+.set noreorder
+
+#define SAVE_COP2_REGISTER(reg) \
+ dmfc2 t1, reg; sd t1, reg##_OFFSET(a0)
+
+
+#define RESTORE_COP2_REGISTER(reg) \
+ ld t1, reg##_OFFSET(a0); dmtc2 t1, reg##_SET
+
+LEAF(octeon_cop2_save)
+ /* Get CvmCtl register */
+ dmfc0 t0, $9, 7
+
+ /* CRC state */
+ SAVE_COP2_REGISTER(COP2_CRC_IV)
+ SAVE_COP2_REGISTER(COP2_CRC_LENGTH)
+ SAVE_COP2_REGISTER(COP2_CRC_POLY)
+
+ /* if CvmCtl[NODFA_CP2] -> save_nodfa */
+ bbit1 t0, 28, save_nodfa
+ nop
+
+ /* LLM state */
+ SAVE_COP2_REGISTER(COP2_LLM_DAT0)
+ SAVE_COP2_REGISTER(COP2_LLM_DAT1)
+
+save_nodfa:
+ /* crypto stuff is irrelevant if CvmCtl[NOCRYPTO] */
+ bbit1 t0, 26, save_done
+ nop
+
+ SAVE_COP2_REGISTER(COP2_3DES_IV)
+ SAVE_COP2_REGISTER(COP2_3DES_KEY0)
+ SAVE_COP2_REGISTER(COP2_3DES_KEY1)
+ SAVE_COP2_REGISTER(COP2_3DES_KEY2)
+ SAVE_COP2_REGISTER(COP2_3DES_RESULT)
+
+ SAVE_COP2_REGISTER(COP2_AES_INP0)
+ SAVE_COP2_REGISTER(COP2_AES_IV0)
+ SAVE_COP2_REGISTER(COP2_AES_IV1)
+ SAVE_COP2_REGISTER(COP2_AES_KEY0)
+ SAVE_COP2_REGISTER(COP2_AES_KEY1)
+ SAVE_COP2_REGISTER(COP2_AES_KEY2)
+ SAVE_COP2_REGISTER(COP2_AES_KEY3)
+ SAVE_COP2_REGISTER(COP2_AES_KEYLEN)
+ SAVE_COP2_REGISTER(COP2_AES_RESULT0)
+ SAVE_COP2_REGISTER(COP2_AES_RESULT1)
+
+ dmfc0 t0, $15
+ li t1, 0x000d0000 /* Octeon Pass1 */
+ beq t0, t1, save_pass1
+ nop
+
+ SAVE_COP2_REGISTER(COP2_HSH_DATW0)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW1)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW2)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW3)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW4)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW5)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW6)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW7)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW8)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW9)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW10)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW11)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW12)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW13)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW14)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW0)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW1)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW2)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW3)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW4)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW5)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW6)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW7)
+ SAVE_COP2_REGISTER(COP2_GFM_MULT0)
+ SAVE_COP2_REGISTER(COP2_GFM_MULT1)
+ SAVE_COP2_REGISTER(COP2_GFM_POLY)
+ SAVE_COP2_REGISTER(COP2_GFM_RESULT0)
+ SAVE_COP2_REGISTER(COP2_GFM_RESULT1)
+ jr ra
+ nop
+
+save_pass1:
+ SAVE_COP2_REGISTER(COP2_HSH_DATW0_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW1_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW2_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW3_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW4_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW5_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW6_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW0_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW1_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW2_PASS1)
+
+save_done:
+ jr ra
+ nop
+END(octeon_cop2_save)
+
+LEAF(octeon_cop2_restore)
+ /* Get CvmCtl register */
+ dmfc0 t0, $9, 7
+
+ /* CRC state */
+ RESTORE_COP2_REGISTER(COP2_CRC_IV)
+ RESTORE_COP2_REGISTER(COP2_CRC_LENGTH)
+ RESTORE_COP2_REGISTER(COP2_CRC_POLY)
+
+ /* if CvmCtl[NODFA_CP2] -> save_nodfa */
+ bbit1 t0, 28, restore_nodfa
+ nop
+
+ /* LLM state */
+ RESTORE_COP2_REGISTER(COP2_LLM_DAT0)
+ RESTORE_COP2_REGISTER(COP2_LLM_DAT1)
+
+restore_nodfa:
+ /* crypto stuff is irrelevant if CvmCtl[NOCRYPTO] */
+ bbit1 t0, 26, restore_done
+ nop
+
+ RESTORE_COP2_REGISTER(COP2_3DES_IV)
+ RESTORE_COP2_REGISTER(COP2_3DES_KEY0)
+ RESTORE_COP2_REGISTER(COP2_3DES_KEY1)
+ RESTORE_COP2_REGISTER(COP2_3DES_KEY2)
+ RESTORE_COP2_REGISTER(COP2_3DES_RESULT)
+
+ RESTORE_COP2_REGISTER(COP2_AES_INP0)
+ RESTORE_COP2_REGISTER(COP2_AES_IV0)
+ RESTORE_COP2_REGISTER(COP2_AES_IV1)
+ RESTORE_COP2_REGISTER(COP2_AES_KEY0)
+ RESTORE_COP2_REGISTER(COP2_AES_KEY1)
+ RESTORE_COP2_REGISTER(COP2_AES_KEY2)
+ RESTORE_COP2_REGISTER(COP2_AES_KEY3)
+ RESTORE_COP2_REGISTER(COP2_AES_KEYLEN)
+ RESTORE_COP2_REGISTER(COP2_AES_RESULT0)
+ RESTORE_COP2_REGISTER(COP2_AES_RESULT1)
+
+ dmfc0 t0, $15
+ li t1, 0x000d0000 /* Octeon Pass1 */
+ beq t0, t1, restore_pass1
+ nop
+
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW0)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW1)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW2)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW3)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW4)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW5)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW6)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW7)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW8)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW9)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW10)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW11)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW12)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW13)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW14)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW0)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW1)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW2)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW3)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW4)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW5)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW6)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW7)
+ RESTORE_COP2_REGISTER(COP2_GFM_MULT0)
+ RESTORE_COP2_REGISTER(COP2_GFM_MULT1)
+ RESTORE_COP2_REGISTER(COP2_GFM_POLY)
+ RESTORE_COP2_REGISTER(COP2_GFM_RESULT0)
+ RESTORE_COP2_REGISTER(COP2_GFM_RESULT1)
+ jr ra
+ nop
+
+restore_pass1:
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW0_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW1_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW2_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW3_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW4_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW5_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW6_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW0_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW1_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW2_PASS1)
+
+restore_done:
+ jr ra
+ nop
+END(octeon_cop2_restore)
diff --git a/sys/mips/cavium/octeon_cop2.h b/sys/mips/cavium/octeon_cop2.h
new file mode 100644
index 0000000..b7aa031
--- /dev/null
+++ b/sys/mips/cavium/octeon_cop2.h
@@ -0,0 +1,210 @@
+/*-
+ * Copyright (c) 2011, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef __OCTEON_COP2_H__
+#define __OCTEON_COP2_H__
+
+/*
+ * COP2 registers of interest
+ */
+#define COP2_CRC_IV 0x201
+#define COP2_CRC_IV_SET COP2_CRC_IV
+#define COP2_CRC_LENGTH 0x202
+#define COP2_CRC_LENGTH_SET 0x1202
+#define COP2_CRC_POLY 0x200
+#define COP2_CRC_POLY_SET 0x4200
+#define COP2_LLM_DAT0 0x402
+#define COP2_LLM_DAT0_SET COP2_LLM_DAT0
+#define COP2_LLM_DAT1 0x40A
+#define COP2_LLM_DAT1_SET COP2_LLM_DAT1
+#define COP2_3DES_IV 0x084
+#define COP2_3DES_IV_SET COP2_3DES_IV
+#define COP2_3DES_KEY0 0x080
+#define COP2_3DES_KEY0_SET COP2_3DES_KEY0
+#define COP2_3DES_KEY1 0x081
+#define COP2_3DES_KEY1_SET COP2_3DES_KEY1
+#define COP2_3DES_KEY2 0x082
+#define COP2_3DES_KEY2_SET COP2_3DES_KEY2
+#define COP2_3DES_RESULT 0x088
+#define COP2_3DES_RESULT_SET 0x098
+#define COP2_AES_INP0 0x111
+#define COP2_AES_INP0_SET COP2_AES_INP0
+#define COP2_AES_IV0 0x102
+#define COP2_AES_IV0_SET COP2_AES_IV0
+#define COP2_AES_IV1 0x103
+#define COP2_AES_IV1_SET COP2_AES_IV1
+#define COP2_AES_KEY0 0x104
+#define COP2_AES_KEY0_SET COP2_AES_KEY0
+#define COP2_AES_KEY1 0x105
+#define COP2_AES_KEY1_SET COP2_AES_KEY1
+#define COP2_AES_KEY2 0x106
+#define COP2_AES_KEY2_SET COP2_AES_KEY2
+#define COP2_AES_KEY3 0x107
+#define COP2_AES_KEY3_SET COP2_AES_KEY3
+#define COP2_AES_KEYLEN 0x110
+#define COP2_AES_KEYLEN_SET COP2_AES_KEYLEN
+#define COP2_AES_RESULT0 0x100
+#define COP2_AES_RESULT0_SET COP2_AES_RESULT0
+#define COP2_AES_RESULT1 0x101
+#define COP2_AES_RESULT1_SET COP2_AES_RESULT1
+#define COP2_HSH_DATW0 0x240
+#define COP2_HSH_DATW0_SET COP2_HSH_DATW0
+#define COP2_HSH_DATW1 0x241
+#define COP2_HSH_DATW1_SET COP2_HSH_DATW1
+#define COP2_HSH_DATW2 0x242
+#define COP2_HSH_DATW2_SET COP2_HSH_DATW2
+#define COP2_HSH_DATW3 0x243
+#define COP2_HSH_DATW3_SET COP2_HSH_DATW3
+#define COP2_HSH_DATW4 0x244
+#define COP2_HSH_DATW4_SET COP2_HSH_DATW4
+#define COP2_HSH_DATW5 0x245
+#define COP2_HSH_DATW5_SET COP2_HSH_DATW5
+#define COP2_HSH_DATW6 0x246
+#define COP2_HSH_DATW6_SET COP2_HSH_DATW6
+#define COP2_HSH_DATW7 0x247
+#define COP2_HSH_DATW7_SET COP2_HSH_DATW7
+#define COP2_HSH_DATW8 0x248
+#define COP2_HSH_DATW8_SET COP2_HSH_DATW8
+#define COP2_HSH_DATW9 0x249
+#define COP2_HSH_DATW9_SET COP2_HSH_DATW9
+#define COP2_HSH_DATW10 0x24A
+#define COP2_HSH_DATW10_SET COP2_HSH_DATW10
+#define COP2_HSH_DATW11 0x24B
+#define COP2_HSH_DATW11_SET COP2_HSH_DATW11
+#define COP2_HSH_DATW12 0x24C
+#define COP2_HSH_DATW12_SET COP2_HSH_DATW12
+#define COP2_HSH_DATW13 0x24D
+#define COP2_HSH_DATW13_SET COP2_HSH_DATW13
+#define COP2_HSH_DATW14 0x24E
+#define COP2_HSH_DATW14_SET COP2_HSH_DATW14
+#define COP2_HSH_IVW0 0x250
+#define COP2_HSH_IVW0_SET COP2_HSH_IVW0
+#define COP2_HSH_IVW1 0x251
+#define COP2_HSH_IVW1_SET COP2_HSH_IVW1
+#define COP2_HSH_IVW2 0x252
+#define COP2_HSH_IVW2_SET COP2_HSH_IVW2
+#define COP2_HSH_IVW3 0x253
+#define COP2_HSH_IVW3_SET COP2_HSH_IVW3
+#define COP2_HSH_IVW4 0x254
+#define COP2_HSH_IVW4_SET COP2_HSH_IVW4
+#define COP2_HSH_IVW5 0x255
+#define COP2_HSH_IVW5_SET COP2_HSH_IVW5
+#define COP2_HSH_IVW6 0x256
+#define COP2_HSH_IVW6_SET COP2_HSH_IVW6
+#define COP2_HSH_IVW7 0x257
+#define COP2_HSH_IVW7_SET COP2_HSH_IVW7
+#define COP2_GFM_MULT0 0x258
+#define COP2_GFM_MULT0_SET COP2_GFM_MULT0
+#define COP2_GFM_MULT1 0x259
+#define COP2_GFM_MULT1_SET COP2_GFM_MULT1
+#define COP2_GFM_POLY 0x25E
+#define COP2_GFM_POLY_SET COP2_GFM_POLY
+#define COP2_GFM_RESULT0 0x25A
+#define COP2_GFM_RESULT0_SET COP2_GFM_RESULT0
+#define COP2_GFM_RESULT1 0x25B
+#define COP2_GFM_RESULT1_SET COP2_GFM_RESULT1
+#define COP2_HSH_DATW0_PASS1 0x040
+#define COP2_HSH_DATW0_PASS1_SET COP2_HSH_DATW0_PASS1
+#define COP2_HSH_DATW1_PASS1 0x041
+#define COP2_HSH_DATW1_PASS1_SET COP2_HSH_DATW1_PASS1
+#define COP2_HSH_DATW2_PASS1 0x042
+#define COP2_HSH_DATW2_PASS1_SET COP2_HSH_DATW2_PASS1
+#define COP2_HSH_DATW3_PASS1 0x043
+#define COP2_HSH_DATW3_PASS1_SET COP2_HSH_DATW3_PASS1
+#define COP2_HSH_DATW4_PASS1 0x044
+#define COP2_HSH_DATW4_PASS1_SET COP2_HSH_DATW4_PASS1
+#define COP2_HSH_DATW5_PASS1 0x045
+#define COP2_HSH_DATW5_PASS1_SET COP2_HSH_DATW5_PASS1
+#define COP2_HSH_DATW6_PASS1 0x046
+#define COP2_HSH_DATW6_PASS1_SET COP2_HSH_DATW6_PASS1
+#define COP2_HSH_IVW0_PASS1 0x048
+#define COP2_HSH_IVW0_PASS1_SET COP2_HSH_IVW0_PASS1
+#define COP2_HSH_IVW1_PASS1 0x049
+#define COP2_HSH_IVW1_PASS1_SET COP2_HSH_IVW1_PASS1
+#define COP2_HSH_IVW2_PASS1 0x04A
+#define COP2_HSH_IVW2_PASS1_SET COP2_HSH_IVW2_PASS1
+
+#ifndef LOCORE
+
+struct octeon_cop2_state {
+ /* 3DES */
+ /* 0x0084 */
+ unsigned long _3des_iv;
+ /* 0x0080..0x0082 */
+ unsigned long _3des_key[3];
+ /* 0x0088, set: 0x0098 */
+ unsigned long _3des_result;
+
+ /* AES */
+ /* 0x0111 */
+ unsigned long aes_inp0;
+ /* 0x0102..0x0103 */
+ unsigned long aes_iv[2];
+ /* 0x0104..0x0107 */
+ unsigned long aes_key[4];
+ /* 0x0110 */
+ unsigned long aes_keylen;
+ /* 0x0100..0x0101 */
+ unsigned long aes_result[2];
+
+ /* CRC */
+ /* 0x0201 */
+ unsigned long crc_iv;
+ /* 0x0202, set: 0x1202 */
+ unsigned long crc_length;
+ /* 0x0200, set: 0x4200 */
+ unsigned long crc_poly;
+
+ /* Low-latency memory stuff */
+ /* 0x0402, 0x040A */
+ unsigned long llm_dat[2];
+
+ /* SHA & MD5 */
+ /* 0x0240..0x024E */
+ unsigned long hsh_datw[15];
+ /* 0x0250..0x0257 */
+ unsigned long hsh_ivw[8];
+
+ /* GFM */
+ /* 0x0258..0x0259 */
+ unsigned long gfm_mult[2];
+ /* 0x025E */
+ unsigned long gfm_poly;
+ /* 0x025A..0x025B */
+ unsigned long gfm_result[2];
+};
+
+/* Prototypes */
+
+void octeon_cop2_save(struct octeon_cop2_state *);
+void octeon_cop2_restore(struct octeon_cop2_state *);
+
+#endif /* LOCORE */
+#endif /* __OCTEON_COP2_H__ */
diff --git a/sys/mips/include/cpuregs.h b/sys/mips/include/cpuregs.h
index b47b264..eec9621 100644
--- a/sys/mips/include/cpuregs.h
+++ b/sys/mips/include/cpuregs.h
@@ -233,6 +233,7 @@
#define MIPS3_CR_EXC_CODE 0x0000007C /* five bits */
#define MIPS_CR_IP 0x0000FF00
#define MIPS_CR_EXC_CODE_SHIFT 2
+#define MIPS_CR_COP_ERR_SHIFT 28
/*
* The bits in the status register. All bits are active when set to 1.
diff --git a/sys/mips/include/frame.h b/sys/mips/include/frame.h
index b08d88c..de7f94c 100644
--- a/sys/mips/include/frame.h
+++ b/sys/mips/include/frame.h
@@ -122,11 +122,6 @@ struct trapframe {
f_register_t f31;
register_t fsr;
register_t fdummy;
- /*
- * COP2 registers may need to be saved here based on the CPU, and those
- * might need to be per process, or even for the kernel, so we need
- * some thought here.
- */
};
/* REVISIT */
diff --git a/sys/mips/include/octeon_cop2.h b/sys/mips/include/octeon_cop2.h
new file mode 100644
index 0000000..d5161dc
--- /dev/null
+++ b/sys/mips/include/octeon_cop2.h
@@ -0,0 +1,215 @@
+/*-
+ * Copyright (c) 2011, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef __OCTEON_COP2_H__
+#define __OCTEON_COP2_H__
+
+/*
+ * COP2 registers of interest
+ */
+#define COP2_CRC_IV 0x201
+#define COP2_CRC_IV_SET COP2_CRC_IV
+#define COP2_CRC_LENGTH 0x202
+#define COP2_CRC_LENGTH_SET 0x1202
+#define COP2_CRC_POLY 0x200
+#define COP2_CRC_POLY_SET 0x4200
+#define COP2_LLM_DAT0 0x402
+#define COP2_LLM_DAT0_SET COP2_LLM_DAT0
+#define COP2_LLM_DAT1 0x40A
+#define COP2_LLM_DAT1_SET COP2_LLM_DAT1
+#define COP2_3DES_IV 0x084
+#define COP2_3DES_IV_SET COP2_3DES_IV
+#define COP2_3DES_KEY0 0x080
+#define COP2_3DES_KEY0_SET COP2_3DES_KEY0
+#define COP2_3DES_KEY1 0x081
+#define COP2_3DES_KEY1_SET COP2_3DES_KEY1
+#define COP2_3DES_KEY2 0x082
+#define COP2_3DES_KEY2_SET COP2_3DES_KEY2
+#define COP2_3DES_RESULT 0x088
+#define COP2_3DES_RESULT_SET 0x098
+#define COP2_AES_INP0 0x111
+#define COP2_AES_INP0_SET COP2_AES_INP0
+#define COP2_AES_IV0 0x102
+#define COP2_AES_IV0_SET COP2_AES_IV0
+#define COP2_AES_IV1 0x103
+#define COP2_AES_IV1_SET COP2_AES_IV1
+#define COP2_AES_KEY0 0x104
+#define COP2_AES_KEY0_SET COP2_AES_KEY0
+#define COP2_AES_KEY1 0x105
+#define COP2_AES_KEY1_SET COP2_AES_KEY1
+#define COP2_AES_KEY2 0x106
+#define COP2_AES_KEY2_SET COP2_AES_KEY2
+#define COP2_AES_KEY3 0x107
+#define COP2_AES_KEY3_SET COP2_AES_KEY3
+#define COP2_AES_KEYLEN 0x110
+#define COP2_AES_KEYLEN_SET COP2_AES_KEYLEN
+#define COP2_AES_RESULT0 0x100
+#define COP2_AES_RESULT0_SET COP2_AES_RESULT0
+#define COP2_AES_RESULT1 0x101
+#define COP2_AES_RESULT1_SET COP2_AES_RESULT1
+#define COP2_HSH_DATW0 0x240
+#define COP2_HSH_DATW0_SET COP2_HSH_DATW0
+#define COP2_HSH_DATW1 0x241
+#define COP2_HSH_DATW1_SET COP2_HSH_DATW1
+#define COP2_HSH_DATW2 0x242
+#define COP2_HSH_DATW2_SET COP2_HSH_DATW2
+#define COP2_HSH_DATW3 0x243
+#define COP2_HSH_DATW3_SET COP2_HSH_DATW3
+#define COP2_HSH_DATW4 0x244
+#define COP2_HSH_DATW4_SET COP2_HSH_DATW4
+#define COP2_HSH_DATW5 0x245
+#define COP2_HSH_DATW5_SET COP2_HSH_DATW5
+#define COP2_HSH_DATW6 0x246
+#define COP2_HSH_DATW6_SET COP2_HSH_DATW6
+#define COP2_HSH_DATW7 0x247
+#define COP2_HSH_DATW7_SET COP2_HSH_DATW7
+#define COP2_HSH_DATW8 0x248
+#define COP2_HSH_DATW8_SET COP2_HSH_DATW8
+#define COP2_HSH_DATW9 0x249
+#define COP2_HSH_DATW9_SET COP2_HSH_DATW9
+#define COP2_HSH_DATW10 0x24A
+#define COP2_HSH_DATW10_SET COP2_HSH_DATW10
+#define COP2_HSH_DATW11 0x24B
+#define COP2_HSH_DATW11_SET COP2_HSH_DATW11
+#define COP2_HSH_DATW12 0x24C
+#define COP2_HSH_DATW12_SET COP2_HSH_DATW12
+#define COP2_HSH_DATW13 0x24D
+#define COP2_HSH_DATW13_SET COP2_HSH_DATW13
+#define COP2_HSH_DATW14 0x24E
+#define COP2_HSH_DATW14_SET COP2_HSH_DATW14
+#define COP2_HSH_IVW0 0x250
+#define COP2_HSH_IVW0_SET COP2_HSH_IVW0
+#define COP2_HSH_IVW1 0x251
+#define COP2_HSH_IVW1_SET COP2_HSH_IVW1
+#define COP2_HSH_IVW2 0x252
+#define COP2_HSH_IVW2_SET COP2_HSH_IVW2
+#define COP2_HSH_IVW3 0x253
+#define COP2_HSH_IVW3_SET COP2_HSH_IVW3
+#define COP2_HSH_IVW4 0x254
+#define COP2_HSH_IVW4_SET COP2_HSH_IVW4
+#define COP2_HSH_IVW5 0x255
+#define COP2_HSH_IVW5_SET COP2_HSH_IVW5
+#define COP2_HSH_IVW6 0x256
+#define COP2_HSH_IVW6_SET COP2_HSH_IVW6
+#define COP2_HSH_IVW7 0x257
+#define COP2_HSH_IVW7_SET COP2_HSH_IVW7
+#define COP2_GFM_MULT0 0x258
+#define COP2_GFM_MULT0_SET COP2_GFM_MULT0
+#define COP2_GFM_MULT1 0x259
+#define COP2_GFM_MULT1_SET COP2_GFM_MULT1
+#define COP2_GFM_POLY 0x25E
+#define COP2_GFM_POLY_SET COP2_GFM_POLY
+#define COP2_GFM_RESULT0 0x25A
+#define COP2_GFM_RESULT0_SET COP2_GFM_RESULT0
+#define COP2_GFM_RESULT1 0x25B
+#define COP2_GFM_RESULT1_SET COP2_GFM_RESULT1
+#define COP2_HSH_DATW0_PASS1 0x040
+#define COP2_HSH_DATW0_PASS1_SET COP2_HSH_DATW0_PASS1
+#define COP2_HSH_DATW1_PASS1 0x041
+#define COP2_HSH_DATW1_PASS1_SET COP2_HSH_DATW1_PASS1
+#define COP2_HSH_DATW2_PASS1 0x042
+#define COP2_HSH_DATW2_PASS1_SET COP2_HSH_DATW2_PASS1
+#define COP2_HSH_DATW3_PASS1 0x043
+#define COP2_HSH_DATW3_PASS1_SET COP2_HSH_DATW3_PASS1
+#define COP2_HSH_DATW4_PASS1 0x044
+#define COP2_HSH_DATW4_PASS1_SET COP2_HSH_DATW4_PASS1
+#define COP2_HSH_DATW5_PASS1 0x045
+#define COP2_HSH_DATW5_PASS1_SET COP2_HSH_DATW5_PASS1
+#define COP2_HSH_DATW6_PASS1 0x046
+#define COP2_HSH_DATW6_PASS1_SET COP2_HSH_DATW6_PASS1
+#define COP2_HSH_IVW0_PASS1 0x048
+#define COP2_HSH_IVW0_PASS1_SET COP2_HSH_IVW0_PASS1
+#define COP2_HSH_IVW1_PASS1 0x049
+#define COP2_HSH_IVW1_PASS1_SET COP2_HSH_IVW1_PASS1
+#define COP2_HSH_IVW2_PASS1 0x04A
+#define COP2_HSH_IVW2_PASS1_SET COP2_HSH_IVW2_PASS1
+
+#ifndef LOCORE
+
+struct octeon_cop2_state {
+ /* 3DES */
+ /* 0x0084 */
+ unsigned long _3des_iv;
+ /* 0x0080..0x0082 */
+ unsigned long _3des_key[3];
+ /* 0x0088, set: 0x0098 */
+ unsigned long _3des_result;
+
+ /* AES */
+ /* 0x0111 */
+ unsigned long aes_inp0;
+ /* 0x0102..0x0103 */
+ unsigned long aes_iv[2];
+ /* 0x0104..0x0107 */
+ unsigned long aes_key[4];
+ /* 0x0110 */
+ unsigned long aes_keylen;
+ /* 0x0100..0x0101 */
+ unsigned long aes_result[2];
+
+ /* CRC */
+ /* 0x0201 */
+ unsigned long crc_iv;
+ /* 0x0202, set: 0x1202 */
+ unsigned long crc_length;
+ /* 0x0200, set: 0x4200 */
+ unsigned long crc_poly;
+
+ /* Low-latency memory stuff */
+ /* 0x0402, 0x040A */
+ unsigned long llm_dat[2];
+
+ /* SHA & MD5 */
+ /* 0x0240..0x024E */
+ unsigned long hsh_datw[15];
+ /* 0x0250..0x0257 */
+ unsigned long hsh_ivw[8];
+
+ /* GFM */
+ /* 0x0258..0x0259 */
+ unsigned long gfm_mult[2];
+ /* 0x025E */
+ unsigned long gfm_poly;
+ /* 0x025A..0x025B */
+ unsigned long gfm_result[2];
+};
+
+/* Prototypes */
+
+struct octeon_cop2_state* octeon_cop2_alloc_ctx(void);
+void octeon_cop2_free_ctx(struct octeon_cop2_state *);
+/*
+ * Save/restore part
+ */
+void octeon_cop2_save(struct octeon_cop2_state *);
+void octeon_cop2_restore(struct octeon_cop2_state *);
+
+#endif /* LOCORE */
+#endif /* __OCTEON_COP2_H__ */
diff --git a/sys/mips/include/proc.h b/sys/mips/include/proc.h
index 8b575dd..beba9167 100644
--- a/sys/mips/include/proc.h
+++ b/sys/mips/include/proc.h
@@ -39,6 +39,10 @@
#ifndef _MACHINE_PROC_H_
#define _MACHINE_PROC_H_
+#ifdef CPU_CNMIPS
+#include <machine/octeon_cop2.h>
+#endif
+
/*
* Machine-dependent part of the proc structure.
*/
@@ -58,10 +62,18 @@ struct mdthread {
int md_pc_count; /* performance counter */
int md_pc_spill; /* performance counter spill */
void *md_tls;
+#ifdef CPU_CNMIPS
+ struct octeon_cop2_state *md_cop2; /* kernel context */
+ struct octeon_cop2_state *md_ucop2; /* userland context */
+#define COP2_OWNER_USERLAND 0x0000 /* Userland owns COP2 */
+#define COP2_OWNER_KERNEL 0x0001 /* Kernel owns COP2 */
+ int md_cop2owner;
+#endif
};
/* md_flags */
#define MDTD_FPUSED 0x0001 /* Process used the FPU */
+#define MDTD_COP2USED 0x0002 /* Process used the COP2 */
struct mdproc {
/* empty */
diff --git a/sys/mips/mips/exception.S b/sys/mips/mips/exception.S
index 8b7307c..b73b3d3 100644
--- a/sys/mips/mips/exception.S
+++ b/sys/mips/mips/exception.S
@@ -375,15 +375,15 @@ NNON_LEAF(MipsKernGenException, KERN_EXC_FRAME_SIZE, ra)
REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging
/*
- * Update interrupt mask in saved status register
+ * Update interrupt and CPU mask in saved status register
* Some of interrupts could be disabled by
* intr filters if interrupts are enabled later
* in trap handler
*/
mfc0 a0, MIPS_COP_0_STATUS
- and a0, a0, MIPS_SR_INT_MASK
+ and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
RESTORE_REG(a1, SR, sp)
- and a1, a1, ~MIPS_SR_INT_MASK
+ and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
or a1, a1, a0
SAVE_REG(a1, SR, sp)
RESTORE_CPU # v0 contains the return address.
@@ -469,6 +469,7 @@ NNON_LEAF(MipsUserGenException, CALLFRAME_SIZ, ra)
# Turn off fpu and enter kernel mode
and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS3_SR_KSU_MASK | MIPS_SR_INT_IE)
#if defined(CPU_CNMIPS)
+ and t0, t0, ~(MIPS_SR_COP_2_BIT)
or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX)
#elif defined(CPU_RMI) || defined(CPU_NLM)
or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT)
@@ -631,15 +632,15 @@ NNON_LEAF(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra)
REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging
/*
- * Update interrupt mask in saved status register
+ * Update interrupt and CPU mask in saved status register
* Some of interrupts could be disabled by
* intr filters if interrupts are enabled later
* in trap handler
*/
mfc0 a0, MIPS_COP_0_STATUS
- and a0, a0, MIPS_SR_INT_MASK
+ and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
RESTORE_REG(a1, SR, sp)
- and a1, a1, ~MIPS_SR_INT_MASK
+ and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
or a1, a1, a0
SAVE_REG(a1, SR, sp)
REG_L v0, CALLFRAME_RA + KERN_REG_SIZE(sp)
@@ -727,6 +728,7 @@ NNON_LEAF(MipsUserIntr, CALLFRAME_SIZ, ra)
# Turn off fpu, disable interrupts, set kernel mode kernel mode, clear exception level.
and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_INT_IE | MIPS3_SR_KSU_MASK)
#ifdef CPU_CNMIPS
+ and t0, t0, ~(MIPS_SR_COP_2_BIT)
or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX)
#elif defined(CPU_RMI) || defined(CPU_NLM)
or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT)
diff --git a/sys/mips/mips/genassym.c b/sys/mips/mips/genassym.c
index 2cb046d..58b1d86 100644
--- a/sys/mips/mips/genassym.c
+++ b/sys/mips/mips/genassym.c
@@ -58,11 +58,14 @@ __FBSDID("$FreeBSD$");
#include <machine/sigframe.h>
#include <machine/proc.h>
+#ifdef CPU_CNMIPS
+#include <machine/octeon_cop2.h>
+#endif
+
#ifndef offsetof
#define offsetof(t,m) (int)((&((t *)0L)->m))
#endif
-
ASSYM(TD_PCB, offsetof(struct thread, td_pcb));
ASSYM(TD_UPTE, offsetof(struct thread, td_md.md_upte));
ASSYM(TD_KSTACK, offsetof(struct thread, td_kstack));
@@ -70,6 +73,7 @@ ASSYM(TD_FLAGS, offsetof(struct thread, td_flags));
ASSYM(TD_LOCK, offsetof(struct thread, td_lock));
ASSYM(TD_FRAME, offsetof(struct thread, td_frame));
ASSYM(TD_TLS, offsetof(struct thread, td_md.md_tls));
+ASSYM(TD_MDFLAGS, offsetof(struct thread, td_md.md_flags));
ASSYM(TF_REG_SR, offsetof(struct trapframe, sr));
@@ -99,8 +103,73 @@ ASSYM(TDF_NEEDRESCHED, TDF_NEEDRESCHED);
ASSYM(TDF_ASTPENDING, TDF_ASTPENDING);
ASSYM(PCPU_SIZE, sizeof(struct pcpu));
ASSYM(MAXCOMLEN, MAXCOMLEN);
+ASSYM(MDTD_COP2USED, MDTD_COP2USED);
ASSYM(MIPS_KSEG0_START, MIPS_KSEG0_START);
ASSYM(MIPS_KSEG1_START, MIPS_KSEG1_START);
ASSYM(MIPS_KSEG2_START, MIPS_KSEG2_START);
ASSYM(MIPS_XKSEG_START, MIPS_XKSEG_START);
+
+#ifdef CPU_CNMIPS
+ASSYM(TD_COP2OWNER, offsetof(struct thread, td_md.md_cop2owner));
+ASSYM(TD_COP2, offsetof(struct thread, td_md.md_cop2));
+ASSYM(TD_UCOP2, offsetof(struct thread, td_md.md_ucop2));
+ASSYM(COP2_CRC_IV_OFFSET, offsetof(struct octeon_cop2_state, crc_iv));
+ASSYM(COP2_CRC_LENGTH_OFFSET, offsetof(struct octeon_cop2_state, crc_length));
+ASSYM(COP2_CRC_POLY_OFFSET, offsetof(struct octeon_cop2_state, crc_poly));
+ASSYM(COP2_LLM_DAT0_OFFSET, offsetof(struct octeon_cop2_state, llm_dat));
+ASSYM(COP2_LLM_DAT1_OFFSET, offsetof(struct octeon_cop2_state, llm_dat) + 8);
+ASSYM(COP2_3DES_IV_OFFSET, offsetof(struct octeon_cop2_state, _3des_iv));
+ASSYM(COP2_3DES_KEY0_OFFSET, offsetof(struct octeon_cop2_state, _3des_key));
+ASSYM(COP2_3DES_KEY1_OFFSET, offsetof(struct octeon_cop2_state, _3des_key) + 8);
+ASSYM(COP2_3DES_KEY2_OFFSET, offsetof(struct octeon_cop2_state, _3des_key) + 16);
+ASSYM(COP2_3DES_RESULT_OFFSET, offsetof(struct octeon_cop2_state, _3des_result));
+ASSYM(COP2_AES_INP0_OFFSET, offsetof(struct octeon_cop2_state, aes_inp0));
+ASSYM(COP2_AES_IV0_OFFSET, offsetof(struct octeon_cop2_state, aes_iv));
+ASSYM(COP2_AES_IV1_OFFSET, offsetof(struct octeon_cop2_state, aes_iv) + 8);
+ASSYM(COP2_AES_KEY0_OFFSET, offsetof(struct octeon_cop2_state, aes_key));
+ASSYM(COP2_AES_KEY1_OFFSET, offsetof(struct octeon_cop2_state, aes_key) + 8);
+ASSYM(COP2_AES_KEY2_OFFSET, offsetof(struct octeon_cop2_state, aes_key) + 16);
+ASSYM(COP2_AES_KEY3_OFFSET, offsetof(struct octeon_cop2_state, aes_key) + 24);
+ASSYM(COP2_AES_KEYLEN_OFFSET, offsetof(struct octeon_cop2_state, aes_keylen));
+ASSYM(COP2_AES_RESULT0_OFFSET, offsetof(struct octeon_cop2_state, aes_result));
+ASSYM(COP2_AES_RESULT1_OFFSET, offsetof(struct octeon_cop2_state, aes_result) + 8);
+ASSYM(COP2_HSH_DATW0_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw));
+ASSYM(COP2_HSH_DATW1_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 8);
+ASSYM(COP2_HSH_DATW2_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 16);
+ASSYM(COP2_HSH_DATW3_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 24);
+ASSYM(COP2_HSH_DATW4_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 32);
+ASSYM(COP2_HSH_DATW5_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 40);
+ASSYM(COP2_HSH_DATW6_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 48);
+ASSYM(COP2_HSH_DATW7_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 56);
+ASSYM(COP2_HSH_DATW8_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 64);
+ASSYM(COP2_HSH_DATW9_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 72);
+ASSYM(COP2_HSH_DATW10_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 80);
+ASSYM(COP2_HSH_DATW11_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 88);
+ASSYM(COP2_HSH_DATW12_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 96);
+ASSYM(COP2_HSH_DATW13_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 104);
+ASSYM(COP2_HSH_DATW14_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 112);
+ASSYM(COP2_HSH_IVW0_OFFSET, offsetof(struct octeon_cop2_state, hsh_ivw));
+ASSYM(COP2_HSH_IVW1_OFFSET, offsetof(struct octeon_cop2_state, hsh_ivw) + 8);
+ASSYM(COP2_HSH_IVW2_OFFSET, offsetof(struct octeon_cop2_state, hsh_ivw) + 16);
+ASSYM(COP2_HSH_IVW3_OFFSET, offsetof(struct octeon_cop2_state, hsh_ivw) + 24);
+ASSYM(COP2_HSH_IVW4_OFFSET, offsetof(struct octeon_cop2_state, hsh_ivw) + 32);
+ASSYM(COP2_HSH_IVW5_OFFSET, offsetof(struct octeon_cop2_state, hsh_ivw) + 40);
+ASSYM(COP2_HSH_IVW6_OFFSET, offsetof(struct octeon_cop2_state, hsh_ivw) + 48);
+ASSYM(COP2_HSH_IVW7_OFFSET, offsetof(struct octeon_cop2_state, hsh_ivw) + 56);
+ASSYM(COP2_GFM_MULT0_OFFSET, offsetof(struct octeon_cop2_state, gfm_mult));
+ASSYM(COP2_GFM_MULT1_OFFSET, offsetof(struct octeon_cop2_state, gfm_mult) + 8);
+ASSYM(COP2_GFM_POLY_OFFSET, offsetof(struct octeon_cop2_state, gfm_poly));
+ASSYM(COP2_GFM_RESULT0_OFFSET, offsetof(struct octeon_cop2_state, gfm_result));
+ASSYM(COP2_GFM_RESULT1_OFFSET, offsetof(struct octeon_cop2_state, gfm_result) + 8);
+ASSYM(COP2_HSH_DATW0_PASS1_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw));
+ASSYM(COP2_HSH_DATW1_PASS1_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 8);
+ASSYM(COP2_HSH_DATW2_PASS1_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 16);
+ASSYM(COP2_HSH_DATW3_PASS1_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 24);
+ASSYM(COP2_HSH_DATW4_PASS1_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 32);
+ASSYM(COP2_HSH_DATW5_PASS1_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 40);
+ASSYM(COP2_HSH_DATW6_PASS1_OFFSET, offsetof(struct octeon_cop2_state, hsh_datw) + 48);
+ASSYM(COP2_HSH_IVW0_PASS1_OFFSET, offsetof(struct octeon_cop2_state, hsh_ivw));
+ASSYM(COP2_HSH_IVW1_PASS1_OFFSET, offsetof(struct octeon_cop2_state, hsh_ivw) + 8);
+ASSYM(COP2_HSH_IVW2_PASS1_OFFSET, offsetof(struct octeon_cop2_state, hsh_ivw) + 16);
+#endif
diff --git a/sys/mips/mips/locore.S b/sys/mips/mips/locore.S
index 4b28f19..c6e78a2 100644
--- a/sys/mips/mips/locore.S
+++ b/sys/mips/mips/locore.S
@@ -95,10 +95,10 @@ VECTOR(_locore, unknown)
*/
/* Set these bits */
- li t1, (MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT | MIPS_SR_PX | MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_SX | MIPS_SR_BEV)
+ li t1, (MIPS_SR_COP_0_BIT | MIPS_SR_PX | MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_SX | MIPS_SR_BEV)
/* Reset these bits */
- li t0, ~(MIPS_SR_DE | MIPS_SR_SOFT_RESET | MIPS_SR_ERL | MIPS_SR_EXL | MIPS_SR_INT_IE)
+ li t0, ~(MIPS_SR_DE | MIPS_SR_SOFT_RESET | MIPS_SR_ERL | MIPS_SR_EXL | MIPS_SR_INT_IE | MIPS_SR_COP_2_BIT)
#elif defined (CPU_RMI) || defined (CPU_NLM)
/* Set these bits */
li t1, (MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT | MIPS_SR_KX | MIPS_SR_UX)
diff --git a/sys/mips/mips/octeon_cop2.c b/sys/mips/mips/octeon_cop2.c
new file mode 100644
index 0000000..c85522d
--- /dev/null
+++ b/sys/mips/mips/octeon_cop2.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2011, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <vm/uma.h>
+
+#include <machine/octeon_cop2.h>
+
+static uma_zone_t ctxzone;
+
+static void
+octeon_cop2_init(void* dummy)
+{
+ printf("Create COP2 context zone\n");
+ ctxzone = uma_zcreate("COP2 context",
+ sizeof(struct octeon_cop2_state),
+ NULL, NULL, NULL, NULL, 8, 0);
+}
+
+struct octeon_cop2_state *
+octeon_cop2_alloc_ctx()
+{
+ return uma_zalloc(ctxzone, M_NOWAIT);
+}
+
+void
+octeon_cop2_free_ctx(struct octeon_cop2_state *ctx)
+{
+ uma_zfree(ctxzone, ctx);
+}
+
+SYSINIT(octeon_cop2, SI_SUB_CPU, SI_ORDER_FIRST, octeon_cop2_init, NULL);
diff --git a/sys/mips/mips/octeon_cop2_swtch.S b/sys/mips/mips/octeon_cop2_swtch.S
new file mode 100644
index 0000000..688db6b
--- /dev/null
+++ b/sys/mips/mips/octeon_cop2_swtch.S
@@ -0,0 +1,246 @@
+/*-
+ * Copyright (c) 2011 Oleksandr Tymoshenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <machine/asm.h>
+#include <machine/cpuregs.h>
+#include <machine/octeon_cop2.h>
+
+#include "assym.s"
+
+.set noreorder
+
+#define SAVE_COP2_REGISTER(reg) \
+ dmfc2 t1, reg; sd t1, reg##_OFFSET(a0)
+
+
+#define RESTORE_COP2_REGISTER(reg) \
+ ld t1, reg##_OFFSET(a0); dmtc2 t1, reg##_SET
+
+LEAF(octeon_cop2_save)
+
+ /* save original cop2 status in t2*/
+ mfc0 t2, MIPS_COP_0_STATUS
+ or t0, t2, MIPS_SR_COP_2_BIT
+ and t0, t0, ~MIPS_SR_INT_IE
+ mtc0 t0, MIPS_COP_0_STATUS
+
+ /* Get CvmCtl register */
+ dmfc0 t0, $9, 7
+
+ /* CRC state */
+ SAVE_COP2_REGISTER(COP2_CRC_IV)
+ SAVE_COP2_REGISTER(COP2_CRC_LENGTH)
+ SAVE_COP2_REGISTER(COP2_CRC_POLY)
+
+ /* if CvmCtl[NODFA_CP2] -> save_nodfa */
+ bbit1 t0, 28, save_nodfa
+ nop
+
+ /* LLM state */
+ SAVE_COP2_REGISTER(COP2_LLM_DAT0)
+ SAVE_COP2_REGISTER(COP2_LLM_DAT1)
+
+save_nodfa:
+ /* crypto stuff is irrelevant if CvmCtl[NOCRYPTO] */
+ bbit1 t0, 26, save_done
+ nop
+
+ SAVE_COP2_REGISTER(COP2_3DES_IV)
+ SAVE_COP2_REGISTER(COP2_3DES_KEY0)
+ SAVE_COP2_REGISTER(COP2_3DES_KEY1)
+ SAVE_COP2_REGISTER(COP2_3DES_KEY2)
+ SAVE_COP2_REGISTER(COP2_3DES_RESULT)
+
+ SAVE_COP2_REGISTER(COP2_AES_INP0)
+ SAVE_COP2_REGISTER(COP2_AES_IV0)
+ SAVE_COP2_REGISTER(COP2_AES_IV1)
+ SAVE_COP2_REGISTER(COP2_AES_KEY0)
+ SAVE_COP2_REGISTER(COP2_AES_KEY1)
+ SAVE_COP2_REGISTER(COP2_AES_KEY2)
+ SAVE_COP2_REGISTER(COP2_AES_KEY3)
+ SAVE_COP2_REGISTER(COP2_AES_KEYLEN)
+ SAVE_COP2_REGISTER(COP2_AES_RESULT0)
+ SAVE_COP2_REGISTER(COP2_AES_RESULT1)
+
+ dmfc0 t0, $15
+ li t1, 0x000d0000 /* Octeon Pass1 */
+ beq t0, t1, save_pass1
+ nop
+
+ SAVE_COP2_REGISTER(COP2_HSH_DATW0)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW1)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW2)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW3)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW4)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW5)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW6)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW7)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW8)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW9)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW10)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW11)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW12)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW13)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW14)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW0)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW1)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW2)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW3)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW4)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW5)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW6)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW7)
+ SAVE_COP2_REGISTER(COP2_GFM_MULT0)
+ SAVE_COP2_REGISTER(COP2_GFM_MULT1)
+ SAVE_COP2_REGISTER(COP2_GFM_POLY)
+ SAVE_COP2_REGISTER(COP2_GFM_RESULT0)
+ SAVE_COP2_REGISTER(COP2_GFM_RESULT1)
+ /* restore saved COP2 status */
+ mtc0 t2, MIPS_COP_0_STATUS
+ jr ra
+ nop
+
+save_pass1:
+ SAVE_COP2_REGISTER(COP2_HSH_DATW0_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW1_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW2_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW3_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW4_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW5_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_DATW6_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW0_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW1_PASS1)
+ SAVE_COP2_REGISTER(COP2_HSH_IVW2_PASS1)
+
+save_done:
+ /* restore saved COP2 status */
+ mtc0 t2, MIPS_COP_0_STATUS
+ jr ra
+ nop
+END(octeon_cop2_save)
+
+LEAF(octeon_cop2_restore)
+ /* save original cop2 status in t2*/
+ mfc0 t2, MIPS_COP_0_STATUS
+ or t0, t2, MIPS_SR_COP_2_BIT
+ and t0, t0, ~MIPS_SR_INT_IE
+ mtc0 t0, MIPS_COP_0_STATUS
+ /* Get CvmCtl register */
+ dmfc0 t0, $9, 7
+
+ /* CRC state */
+ RESTORE_COP2_REGISTER(COP2_CRC_IV)
+ RESTORE_COP2_REGISTER(COP2_CRC_LENGTH)
+ RESTORE_COP2_REGISTER(COP2_CRC_POLY)
+
+ /* if CvmCtl[NODFA_CP2] -> save_nodfa */
+ bbit1 t0, 28, restore_nodfa
+ nop
+
+ /* LLM state */
+ RESTORE_COP2_REGISTER(COP2_LLM_DAT0)
+ RESTORE_COP2_REGISTER(COP2_LLM_DAT1)
+
+restore_nodfa:
+ /* crypto stuff is irrelevant if CvmCtl[NOCRYPTO] */
+ bbit1 t0, 26, restore_done
+ nop
+
+ RESTORE_COP2_REGISTER(COP2_3DES_IV)
+ RESTORE_COP2_REGISTER(COP2_3DES_KEY0)
+ RESTORE_COP2_REGISTER(COP2_3DES_KEY1)
+ RESTORE_COP2_REGISTER(COP2_3DES_KEY2)
+ RESTORE_COP2_REGISTER(COP2_3DES_RESULT)
+
+ RESTORE_COP2_REGISTER(COP2_AES_INP0)
+ RESTORE_COP2_REGISTER(COP2_AES_IV0)
+ RESTORE_COP2_REGISTER(COP2_AES_IV1)
+ RESTORE_COP2_REGISTER(COP2_AES_KEY0)
+ RESTORE_COP2_REGISTER(COP2_AES_KEY1)
+ RESTORE_COP2_REGISTER(COP2_AES_KEY2)
+ RESTORE_COP2_REGISTER(COP2_AES_KEY3)
+ RESTORE_COP2_REGISTER(COP2_AES_KEYLEN)
+ RESTORE_COP2_REGISTER(COP2_AES_RESULT0)
+ RESTORE_COP2_REGISTER(COP2_AES_RESULT1)
+
+ dmfc0 t0, $15
+ li t1, 0x000d0000 /* Octeon Pass1 */
+ beq t0, t1, restore_pass1
+ nop
+
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW0)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW1)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW2)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW3)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW4)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW5)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW6)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW7)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW8)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW9)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW10)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW11)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW12)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW13)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW14)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW0)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW1)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW2)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW3)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW4)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW5)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW6)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW7)
+ RESTORE_COP2_REGISTER(COP2_GFM_MULT0)
+ RESTORE_COP2_REGISTER(COP2_GFM_MULT1)
+ RESTORE_COP2_REGISTER(COP2_GFM_POLY)
+ RESTORE_COP2_REGISTER(COP2_GFM_RESULT0)
+ RESTORE_COP2_REGISTER(COP2_GFM_RESULT1)
+ /* restore saved COP2 status */
+ mtc0 t2, MIPS_COP_0_STATUS
+ jr ra
+ nop
+
+restore_pass1:
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW0_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW1_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW2_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW3_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW4_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW5_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_DATW6_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW0_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW1_PASS1)
+ RESTORE_COP2_REGISTER(COP2_HSH_IVW2_PASS1)
+
+restore_done:
+ /* restore saved COP2 status */
+ mtc0 t2, MIPS_COP_0_STATUS
+ jr ra
+ nop
+END(octeon_cop2_restore)
diff --git a/sys/mips/mips/pm_machdep.c b/sys/mips/mips/pm_machdep.c
index d730ccb..d136f5f 100644
--- a/sys/mips/mips/pm_machdep.c
+++ b/sys/mips/mips/pm_machdep.c
@@ -520,7 +520,7 @@ exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
td->td_frame->sr |= MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX;
#endif
#ifdef CPU_CNMIPS
- td->td_frame->sr |= MIPS_SR_COP_2_BIT | MIPS_SR_PX | MIPS_SR_UX |
+ td->td_frame->sr |= MIPS_SR_PX | MIPS_SR_UX |
MIPS_SR_KX | MIPS_SR_SX;
#endif
/*
diff --git a/sys/mips/mips/swtch.S b/sys/mips/mips/swtch.S
index 699c206..8b285dd 100644
--- a/sys/mips/mips/swtch.S
+++ b/sys/mips/mips/swtch.S
@@ -250,6 +250,61 @@ NON_LEAF(cpu_switch, CALLFRAME_SIZ, ra)
getpc:
SAVE_U_PCB_CONTEXT(ra, PREG_PC, a0) # save return address
+#ifdef CPU_CNMIPS
+
+ lw t2, TD_MDFLAGS(a3) # get md_flags
+ and t1, t2, MDTD_COP2USED
+ beqz t1, cop2_untouched
+ nop
+
+ /* Clear cop2used flag */
+ and t2, t2, ~MDTD_COP2USED
+ sw t2, TD_MDFLAGS(a3)
+
+ and t2, t0, ~MIPS_SR_COP_2_BIT # clear COP_2 enable bit
+ SAVE_U_PCB_CONTEXT(t2, PREG_SR, a0) # save status register
+
+ RESTORE_U_PCB_REG(t0, PS, a0) # get CPU status register
+ and t2, t0, ~MIPS_SR_COP_2_BIT # clear COP_2 enable bit
+ SAVE_U_PCB_REG(t2, PS, a0) # save stratus register
+
+ /* preserve a0..a3 */
+ move s0, a0
+ move s1, a1
+ move s2, a2
+ move s3, a3
+
+ /* does kernel own COP2 context? */
+ lw t1, TD_COP2OWNER(a3) # get md_cop2owner
+ beqz t1, userland_cop2 # 0 - it's userland context
+ nop
+
+ PTR_L a0, TD_COP2(a3)
+ beqz a0, no_cop2_context
+ nop
+
+ j do_cop2_save
+ nop
+
+userland_cop2:
+
+ PTR_L a0, TD_UCOP2(a3)
+ beqz a0, no_cop2_context
+ nop
+
+do_cop2_save:
+ jal octeon_cop2_save
+ nop
+
+no_cop2_context:
+ move a3, s3
+ move a2, s2
+ move a1, s1
+ move a0, s0
+
+cop2_untouched:
+#endif
+
PTR_S a2, TD_LOCK(a3) # Switchout td_lock
mips_sw1:
diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c
index 97374a7..3b632d0 100644
--- a/sys/mips/mips/trap.c
+++ b/sys/mips/mips/trap.c
@@ -251,6 +251,9 @@ char *access_name[] = {
"Store Doubleword"
};
+#ifdef CPU_CNMIPS
+#include <machine/octeon_cop2.h>
+#endif
static int allow_unaligned_acc = 1;
@@ -410,6 +413,7 @@ trap(struct trapframe *trapframe)
char *msg = NULL;
intptr_t addr = 0;
register_t pc;
+ int cop;
trapdebug_enter(trapframe, 0);
@@ -767,28 +771,91 @@ dofault:
goto err;
break;
case T_COP_UNUSABLE:
+#ifdef CPU_CNMIPS
+ cop = (trapframe->cause & MIPS_CR_COP_ERR) >> MIPS_CR_COP_ERR_SHIFT;
+ /* Handle only COP2 exception */
+ if (cop != 2)
+ goto err;
+
+ addr = trapframe->pc;
+ /* save userland cop2 context if it has been touched */
+ if ((td->td_md.md_flags & MDTD_COP2USED) &&
+ (td->td_md.md_cop2owner == COP2_OWNER_USERLAND)) {
+ if (td->td_md.md_ucop2)
+ octeon_cop2_save(td->td_md.md_ucop2);
+ else
+ panic("COP2 was used in user mode but md_ucop2 is NULL");
+ }
+
+ if (td->td_md.md_cop2 == NULL) {
+ td->td_md.md_cop2 = octeon_cop2_alloc_ctx();
+ if (td->td_md.md_cop2 == NULL)
+ panic("Failed to allocate COP2 context");
+ memset(td->td_md.md_cop2, 0, sizeof(*td->td_md.md_cop2));
+ }
+
+ octeon_cop2_restore(td->td_md.md_cop2);
+
+ /* Make userland re-request its context */
+ td->td_frame->sr &= ~MIPS_SR_COP_2_BIT;
+ td->td_md.md_flags |= MDTD_COP2USED;
+ td->td_md.md_cop2owner = COP2_OWNER_KERNEL;
+ /* Enable COP2, it will be disabled in cpu_switch */
+ mips_wr_status(mips_rd_status() | MIPS_SR_COP_2_BIT);
+ return (trapframe->pc);
+#else
goto err;
break;
+#endif
+
case T_COP_UNUSABLE + T_USER:
+ cop = (trapframe->cause & MIPS_CR_COP_ERR) >> MIPS_CR_COP_ERR_SHIFT;
+ if (cop == 1) {
#if !defined(CPU_HAVEFPU)
/* FP (COP1) instruction */
- if ((trapframe->cause & MIPS_CR_COP_ERR) == 0x10000000) {
log_illegal_instruction("COP1_UNUSABLE", trapframe);
i = SIGILL;
break;
+#else
+ addr = trapframe->pc;
+ MipsSwitchFPState(PCPU_GET(fpcurthread), td->td_frame);
+ PCPU_SET(fpcurthread, td);
+ td->td_frame->sr |= MIPS_SR_COP_1_BIT;
+ td->td_md.md_flags |= MDTD_FPUSED;
+ goto out;
+#endif
+ }
+#ifdef CPU_CNMIPS
+ else if (cop == 2) {
+ addr = trapframe->pc;
+ if ((td->td_md.md_flags & MDTD_COP2USED) &&
+ (td->td_md.md_cop2owner == COP2_OWNER_KERNEL)) {
+ if (td->td_md.md_cop2)
+ octeon_cop2_save(td->td_md.md_cop2);
+ else
+ panic("COP2 was used in kernel mode but md_cop2 is NULL");
+ }
+
+ if (td->td_md.md_ucop2 == NULL) {
+ td->td_md.md_ucop2 = octeon_cop2_alloc_ctx();
+ if (td->td_md.md_ucop2 == NULL)
+ panic("Failed to allocate userland COP2 context");
+ memset(td->td_md.md_ucop2, 0, sizeof(*td->td_md.md_ucop2));
+ }
+
+ octeon_cop2_restore(td->td_md.md_ucop2);
+
+ td->td_frame->sr |= MIPS_SR_COP_2_BIT;
+ td->td_md.md_flags |= MDTD_COP2USED;
+ td->td_md.md_cop2owner = COP2_OWNER_USERLAND;
+ goto out;
}
#endif
- if ((trapframe->cause & MIPS_CR_COP_ERR) != 0x10000000) {
+ else {
log_illegal_instruction("COPn_UNUSABLE", trapframe);
i = SIGILL; /* only FPU instructions allowed */
break;
}
- addr = trapframe->pc;
- MipsSwitchFPState(PCPU_GET(fpcurthread), td->td_frame);
- PCPU_SET(fpcurthread, td);
- td->td_frame->sr |= MIPS_SR_COP_1_BIT;
- td->td_md.md_flags |= MDTD_FPUSED;
- goto out;
case T_FPE:
#if !defined(SMP) && (defined(DDB) || defined(DEBUG))
diff --git a/sys/mips/mips/vm_machdep.c b/sys/mips/mips/vm_machdep.c
index 47058ee..bdd73e7 100644
--- a/sys/mips/mips/vm_machdep.c
+++ b/sys/mips/mips/vm_machdep.c
@@ -163,7 +163,36 @@ cpu_fork(register struct thread *td1,register struct proc *p2,
td2->td_md.md_saved_intr = MIPS_SR_INT_IE;
td2->td_md.md_spinlock_count = 1;
#ifdef CPU_CNMIPS
- pcb2->pcb_context[PCB_REG_SR] |= MIPS_SR_COP_2_BIT | MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX;
+ if (td1->td_md.md_flags & MDTD_COP2USED) {
+ if (td1->td_md.md_cop2owner == COP2_OWNER_USERLAND) {
+ if (td1->td_md.md_ucop2)
+ octeon_cop2_save(td1->td_md.md_ucop2);
+ else
+ panic("cpu_fork: ucop2 is NULL but COP2 is enabled");
+ }
+ else {
+ if (td1->td_md.md_cop2)
+ octeon_cop2_save(td1->td_md.md_cop2);
+ else
+ panic("cpu_fork: cop2 is NULL but COP2 is enabled");
+ }
+ }
+
+ if (td1->td_md.md_cop2) {
+ td2->td_md.md_cop2 = octeon_cop2_alloc_ctx();
+ memcpy(td2->td_md.md_cop2, td1->td_md.md_cop2,
+ sizeof(*td1->td_md.md_cop2));
+ }
+ if (td1->td_md.md_ucop2) {
+ td2->td_md.md_ucop2 = octeon_cop2_alloc_ctx();
+ memcpy(td2->td_md.md_ucop2, td1->td_md.md_ucop2,
+ sizeof(*td1->td_md.md_ucop2));
+ }
+ td2->td_md.md_cop2owner = td1->td_md.md_cop2owner;
+ pcb2->pcb_context[PCB_REG_SR] |= MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX;
+ /* Clear COP2 bits for userland & kernel */
+ td2->td_frame->sr &= ~MIPS_SR_COP_2_BIT;
+ pcb2->pcb_context[PCB_REG_SR] &= ~MIPS_SR_COP_2_BIT;
#endif
}
@@ -195,11 +224,27 @@ cpu_thread_exit(struct thread *td)
if (PCPU_GET(fpcurthread) == td)
PCPU_GET(fpcurthread) = (struct thread *)0;
+#ifdef CPU_CNMIPS
+ if (td->td_md.md_cop2)
+ memset(td->td_md.md_cop2, 0,
+ sizeof(*td->td_md.md_cop2));
+ if (td->td_md.md_ucop2)
+ memset(td->td_md.md_ucop2, 0,
+ sizeof(*td->td_md.md_ucop2));
+#endif
}
void
cpu_thread_free(struct thread *td)
{
+#ifdef CPU_CNMIPS
+ if (td->td_md.md_cop2)
+ octeon_cop2_free_ctx(td->td_md.md_cop2);
+ if (td->td_md.md_ucop2)
+ octeon_cop2_free_ctx(td->td_md.md_ucop2);
+ td->td_md.md_cop2 = NULL;
+ td->td_md.md_ucop2 = NULL;
+#endif
}
void
@@ -357,7 +402,7 @@ cpu_set_upcall(struct thread *td, struct thread *td0)
(MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_INT_MASK);
#ifdef CPU_CNMIPS
- pcb2->pcb_context[PCB_REG_SR] |= MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT |
+ pcb2->pcb_context[PCB_REG_SR] |= MIPS_SR_COP_0_BIT |
MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX;
#endif
OpenPOWER on IntegriCloud