Add Kunit tests for the kernel's implementation of the standard CRC-16
algorithm (<linux/crc16.h>). The test data consists of 100
randomly-generated test cases, validated against a naive CRC-16
implementation.
This test follows roughly the same logic as lib/crc32test.c, but
without the performance measurements.
Signed-off-by: Vinicius Peixoto <vpeixoto(a)lkcamp.dev>
Co-developed-by: Enzo Bertoloti <ebertoloti(a)lkcamp.dev>
Signed-off-by: Enzo Bertoloti <ebertoloti(a)lkcamp.dev>
Co-developed-by: Fabricio Gasperin <fgasperin(a)lkcamp.dev>
Signed-off-by: Fabricio Gasperin <fgasperin(a)lkcamp.dev>
Suggested-by: David Laight <David.Laight(a)ACULAB.COM>
---
This patch was developed during a hackathon organized by LKCAMP [1],
with the objective of writing KUnit tests, both to introduce people to
the kernel development process and to learn about different subsystems
(with the positive side effect of improving the kernel test coverage, of
course).
We noticed there were tests for CRC32 in lib/crc32test.c and thought it
would be nice to have something similar for CRC16, since it seems to be
widely used in network drivers (as well as in some ext4 code).
We would really appreciate any feedback/suggestions on how to improve
this. Thanks! :-)
Changes in v2 (suggested by David Laight):
- Use the PRNG from include/linux/prandom.h to generate pseudorandom
data/test cases instead of having them hardcoded as large static
arrays
- Add a naive CRC16 implementation used to validate the kernel's
implementation (instead of having the test case results be hard-coded)
- Link to v1: https://lore.kernel.org/linux-kselftest/20240922232643.535329-1-vpeixoto@lk…
Changes in v3:
- Fix compilation warnings about function documentation
- Link to v2: https://lore.kernel.org/r/20241003-crc16-kunit-v2-1-5fe74b113e1e@lkcamp.dev
[1] https://lkcamp.dev/about
---
lib/Kconfig.debug | 9 ++++
lib/Makefile | 1 +
lib/crc16_kunit.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 165 insertions(+)
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 7315f643817ae1021f1e4b3dd27b424f49e3f761..f9617e3054948ce43090f524dc67650e9549cee8 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2850,6 +2850,15 @@ config USERCOPY_KUNIT_TEST
on the copy_to/from_user infrastructure, making sure basic
user/kernel boundary testing is working.
+config CRC16_KUNIT_TEST
+ tristate "KUnit tests for CRC16"
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ select CRC16
+ help
+ Enable this option to run unit tests for the kernel's CRC16
+ implementation (<linux/crc16.h>).
+
config TEST_UDELAY
tristate "udelay test driver"
help
diff --git a/lib/Makefile b/lib/Makefile
index 773adf88af41665b2419202e5427e0513c6becae..1faed6414a85fd366b4966a00e8ba231d7546e14 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -389,6 +389,7 @@ CFLAGS_fortify_kunit.o += $(DISABLE_STRUCTLEAK_PLUGIN)
obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o
obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o
obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o
+obj-$(CONFIG_CRC16_KUNIT_TEST) += crc16_kunit.o
obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o
diff --git a/lib/crc16_kunit.c b/lib/crc16_kunit.c
new file mode 100644
index 0000000000000000000000000000000000000000..0918c98a96d26f4e795e3eb92923db7c549ac01f
--- /dev/null
+++ b/lib/crc16_kunit.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnits tests for CRC16.
+ *
+ * Copyright (C) 2024, LKCAMP
+ * Author: Vinicius Peixoto <vpeixoto(a)lkcamp.dev>
+ * Author: Fabricio Gasperin <fgasperin(a)lkcamp.dev>
+ * Author: Enzo Bertoloti <ebertoloti(a)lkcamp.dev>
+ */
+#include <kunit/test.h>
+#include <linux/crc16.h>
+#include <linux/prandom.h>
+
+#define CRC16_KUNIT_DATA_SIZE 4096
+#define CRC16_KUNIT_TEST_SIZE 100
+#define CRC16_KUNIT_SEED 0x12345678
+
+/**
+ * struct crc16_test - CRC16 test data
+ * @crc: initial input value to CRC16
+ * @start: Start index within the data buffer
+ * @length: Length of the data
+ */
+static struct crc16_test {
+ u16 crc;
+ u16 start;
+ u16 length;
+} tests[CRC16_KUNIT_TEST_SIZE];
+
+u8 data[CRC16_KUNIT_DATA_SIZE];
+
+
+/* Naive implementation of CRC16 for validation purposes */
+static inline u16 _crc16_naive_byte(u16 crc, u8 data)
+{
+ u8 i = 0;
+
+ crc ^= (u16) data;
+ for (i = 0; i < 8; i++) {
+ if (crc & 0x01)
+ crc = (crc >> 1) ^ 0xa001;
+ else
+ crc = crc >> 1;
+ }
+
+ return crc;
+}
+
+
+static inline u16 _crc16_naive(u16 crc, u8 *buffer, size_t len)
+{
+ while (len--)
+ crc = _crc16_naive_byte(crc, *buffer++);
+ return crc;
+}
+
+
+/* Small helper for generating pseudorandom 16-bit data */
+static inline u16 _rand16(void)
+{
+ static u32 rand = CRC16_KUNIT_SEED;
+
+ rand = next_pseudo_random32(rand);
+ return rand & 0xFFFF;
+}
+
+
+static int crc16_init_test_data(struct kunit_suite *suite)
+{
+ size_t i;
+
+ /* Fill the data buffer with random bytes */
+ for (i = 0; i < CRC16_KUNIT_DATA_SIZE; i++)
+ data[i] = _rand16() & 0xFF;
+
+ /* Generate random test data while ensuring the random
+ * start + length values won't overflow the 4096-byte
+ * buffer (0x7FF * 2 = 0xFFE < 0x1000)
+ */
+ for (size_t i = 0; i < CRC16_KUNIT_TEST_SIZE; i++) {
+ tests[i].crc = _rand16();
+ tests[i].start = _rand16() & 0x7FF;
+ tests[i].length = _rand16() & 0x7FF;
+ }
+
+ return 0;
+}
+
+static void crc16_test_empty(struct kunit *test)
+{
+ u16 crc;
+
+ /* The result for empty data should be the same as the
+ * initial crc
+ */
+ crc = crc16(0x00, data, 0);
+ KUNIT_EXPECT_EQ(test, crc, 0);
+ crc = crc16(0xFF, data, 0);
+ KUNIT_EXPECT_EQ(test, crc, 0xFF);
+}
+
+static void crc16_test_correctness(struct kunit *test)
+{
+ size_t i;
+ u16 crc, crc_naive;
+
+ for (i = 0; i < CRC16_KUNIT_TEST_SIZE; i++) {
+ /* Compare results with the naive crc16 implementation */
+ crc = crc16(tests[i].crc, data + tests[i].start,
+ tests[i].length);
+ crc_naive = _crc16_naive(tests[i].crc, data + tests[i].start,
+ tests[i].length);
+ KUNIT_EXPECT_EQ(test, crc, crc_naive);
+ }
+}
+
+
+static void crc16_test_combine(struct kunit *test)
+{
+ size_t i, j;
+ u16 crc, crc_naive;
+
+ /* Make sure that combining two consecutive crc16 calculations
+ * yields the same result as calculating the crc16 for the whole thing
+ */
+ for (i = 0; i < CRC16_KUNIT_TEST_SIZE; i++) {
+ crc_naive = crc16(tests[i].crc, data + tests[i].start, tests[i].length);
+ for (j = 0; j < tests[i].length; j++) {
+ crc = crc16(tests[i].crc, data + tests[i].start, j);
+ crc = crc16(crc, data + tests[i].start + j, tests[i].length - j);
+ KUNIT_EXPECT_EQ(test, crc, crc_naive);
+ }
+ }
+}
+
+
+static struct kunit_case crc16_test_cases[] = {
+ KUNIT_CASE(crc16_test_empty),
+ KUNIT_CASE(crc16_test_combine),
+ KUNIT_CASE(crc16_test_correctness),
+ {},
+};
+
+static struct kunit_suite crc16_test_suite = {
+ .name = "crc16",
+ .test_cases = crc16_test_cases,
+ .suite_init = crc16_init_test_data,
+};
+kunit_test_suite(crc16_test_suite);
+
+MODULE_AUTHOR("Fabricio Gasperin <fgasperin(a)lkcamp.dev>");
+MODULE_AUTHOR("Vinicius Peixoto <vpeixoto(a)lkcamp.dev>");
+MODULE_AUTHOR("Enzo Bertoloti <ebertoloti(a)lkcamp.dev>");
+MODULE_DESCRIPTION("Unit tests for crc16");
+MODULE_LICENSE("GPL");
---
base-commit: 9852d85ec9d492ebef56dc5f229416c925758edc
change-id: 20241003-crc16-kunit-127a4dc2b72c
Best regards,
--
Vinicius Peixoto <vpeixoto(a)lkcamp.dev>
PASID (Process Address Space ID) is a PCIe extension to tag the DMA
transactions out of a physical device, and most modern IOMMU hardware
have supported PASID granular address translation. So a PASID-capable
device can be attached to multiple hwpts (a.k.a. domains), and each
attachment is tagged with a pasid.
This series is based on the preparation series [1] [2], it first adds a
missing iommu API to replace the domain for a pasid. Based on the iommu
pasid attach/ replace/detach APIs, this series adds iommufd APIs for device
drivers to attach/replace/detach pasid to/from hwpt per userspace's request,
and adds selftest to validate the iommufd APIs.
While this series has a missing part which is to enforce the domain
allocation with special flag if it will be used by PASID [3]. This is due
to special requirements by AMD. Since it is still in mailing discussion [4],
so let's mark it here. Once it's finalized, this series needs to enforce
the domain flag check to ensure the AMD pasid support is not broken from
day-1.
The completed code can be found in the below link [5]. Heads up! The existing
iommufd selftest was broken, there was a fix [6] to it, but not been
upstreamed yet. If want to run the iommufd selftest, please apply that fix.
Sorry for the inconvenience.
[1] https://lore.kernel.org/linux-iommu/20240912130427.10119-1-yi.l.liu@intel.c…
[2] https://lore.kernel.org/linux-iommu/20240912130653.11028-1-yi.l.liu@intel.c…
[3] https://lore.kernel.org/linux-iommu/20240822124433.GD3468552@ziepe.ca/
[4] https://lore.kernel.org/linux-iommu/20240911101911.6269-3-vasant.hegde@amd.…
[5] https://github.com/yiliu1765/iommufd/tree/iommufd_pasid
[6] https://lore.kernel.org/linux-iommu/20240111073213.180020-1-baolu.lu@linux.…
Change log:
v4:
- Replace remove_dev_pasid() by supporting set_dev_pasid() for blocking domain (Kevin)
- This is done by the preparation series "Support attaching PASID to the blocked_domain"
- Misc tweaks to foil the merging of the iommufd iopf series. Three new patches are added:
- iommufd: Always pass iommu_attach_handle to iommu core
- iommufd: Move the iommufd_handle helpers to iommufd_private.h
- iommufd: Refactor __fault_domain_replace_dev() to be a wrapper of iommu_replace_group_handle()
- Renmae patch 03 of v3 to be "iommufd: Support pasid attach/replace"
- Add test case for attaching/replacing iopf-capable hwpt to pasid
v3: https://lore.kernel.org/kvm/20240628090557.50898-1-yi.l.liu@intel.com/
- Split the set_dev_pasid op enhancements for domain replacement to be a
separate series "Make set_dev_pasid op supportting domain replacement" [1].
The below changes are made in the separate series.
*) set_dev_pasid() callback should keep the old config if failed to attach to
a domain. This simplifies the caller a lot as caller does not need to attach
it back to old domain explicitly. This also avoids some corner cases in which
the core may do duplicated domain attachment as described in below link (Jason)
https://lore.kernel.org/linux-iommu/BN9PR11MB52768C98314A95AFCD2FA6478C0F2@…
*) Drop patch 10 of v2 as it's a bug fix and can be submitted separately (Kevin)
*) Rebase on top of Baolu's domain_alloc_paging refactor series (Jason)
- Drop the attach_data which includes attach_fn and pasid, insteadly passing the
pasid through the device attach path. (Jason)
- Add a pasid-num-bits property to mock dev to make pasid selftest work (Kevin)
v2: https://lore.kernel.org/linux-iommu/20240412081516.31168-1-yi.l.liu@intel.c…
- Domain replace for pasid should be handled in set_dev_pasid() callbacks
instead of remove_dev_pasid and call set_dev_pasid afteward in iommu
layer (Jason)
- Make xarray operations more self-contained in iommufd pasid attach/replace/detach
(Jason)
- Tweak the dev_iommu_get_max_pasids() to allow iommu driver to populate the
max_pasids. This makes the iommufd selftest simpler to meet the max_pasids
check in iommu_attach_device_pasid() (Jason)
v1: https://lore.kernel.org/kvm/20231127063428.127436-1-yi.l.liu@intel.com/#r
- Implemnet iommu_replace_device_pasid() to fall back to the original domain
if this replacement failed (Kevin)
- Add check in do_attach() to check corressponding attach_fn per the pasid value.
rfc: https://lore.kernel.org/linux-iommu/20230926092651.17041-1-yi.l.liu@intel.c…
Regards,
Yi Liu
Yi Liu (10):
iommu: Introduce a replace API for device pasid
iommufd: Refactor __fault_domain_replace_dev() to be a wrapper of
iommu_replace_group_handle()
iommufd: Move the iommufd_handle helpers to iommufd_private.h
iommufd: Always pass iommu_attach_handle to iommu core
iommufd: Pass pasid through the device attach/replace path
iommufd: Support pasid attach/replace
iommufd/selftest: Add set_dev_pasid and remove_dev_pasid in mock iommu
iommufd/selftest: Add a helper to get test device
iommufd/selftest: Add test ops to test pasid attach/detach
iommufd/selftest: Add coverage for iommufd pasid attach/detach
drivers/iommu/iommu-priv.h | 4 +
drivers/iommu/iommu.c | 90 +++++-
drivers/iommu/iommufd/Makefile | 1 +
drivers/iommu/iommufd/device.c | 46 ++--
drivers/iommu/iommufd/fault.c | 90 ++----
drivers/iommu/iommufd/hw_pagetable.c | 5 +-
drivers/iommu/iommufd/iommufd_private.h | 129 ++++++++-
drivers/iommu/iommufd/iommufd_test.h | 30 ++
drivers/iommu/iommufd/pasid.c | 157 +++++++++++
drivers/iommu/iommufd/selftest.c | 208 +++++++++++++-
include/linux/iommufd.h | 7 +
tools/testing/selftests/iommu/iommufd.c | 256 ++++++++++++++++++
.../selftests/iommu/iommufd_fail_nth.c | 29 +-
tools/testing/selftests/iommu/iommufd_utils.h | 78 ++++++
14 files changed, 1005 insertions(+), 125 deletions(-)
create mode 100644 drivers/iommu/iommufd/pasid.c
--
2.34.1
Hi Linus,
Please pull this kselftest fixes update for Linux 6.12-rc3.
This kselftest update for Linux 6.12-rc3 consists of several fixes
for build, run-time errors, and reporting errors:
-- ftrace: regression test for a kernel crash when running function graph
tracing and then enabling function profiler.
-- rseq: fix for mm_cid test failure.
-- vDSO:
- fixes to reporting skip and other error conditions.
- changes to unconditionally build chacha and getrandom tests on
all architectures to make it easier for them to run in CIs.
- build error when sched.h to bring in CLONE_NEWTIME define.
diff is attached.
Note: Had to fix a commit message last minute on rseq patch right
before generating the pull request. The last 2 patches have been in
my tree longer than just a few hours. :)
thanks,
-- Shuah
----------------------------------------------------------------
The following changes since commit c66be905cda24fb782b91053b196bd2e966f95b7:
selftests: breakpoints: use remaining time to check if suspend succeed (2024-10-02 14:37:30 -0600)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest tags/linux_kselftest-fixes-6.12-rc3
for you to fetch changes up to 4ee5ca9a29384fcf3f18232fdf8474166dea8dca:
ftrace/selftest: Test combination of function_graph tracer and function profiler (2024-10-11 15:05:16 -0600)
----------------------------------------------------------------
linux_kselftest-fixes-6.12-rc3
This kselftest update for Linux 6.12-rc3 consists of several fixes
for build, run-time errors, and reporting errors:
-- ftrace: regression test for a kernel crash when running function graph
tracing and then enabling function profiler.
-- rseq: fix for mm_cid test failure.
-- vDSO:
- fixes to reporting skip and other error conditions.
- changes unconditionally build chacha and getrandom tests on
all architectures to make it easier for them to run in CIs.
- build error when sched.h to bring in CLONE_NEWTIME define.
----------------------------------------------------------------
Jason A. Donenfeld (3):
selftests: vDSO: unconditionally build chacha test
selftests: vDSO: unconditionally build getrandom test
selftests: vDSO: improve getrandom and chacha error messages
Mathieu Desnoyers (1):
selftests/rseq: Fix mm_cid test failure
Steven Rostedt (1):
ftrace/selftest: Test combination of function_graph tracer and function profiler
Yu Liao (1):
selftests: vDSO: Explicitly include sched.h
tools/arch/arm64/vdso | 1 -
tools/arch/loongarch/vdso | 1 -
tools/arch/powerpc/vdso | 1 -
tools/arch/s390/vdso | 1 -
tools/arch/x86/vdso | 1 -
.../ftrace/test.d/ftrace/fgraph-profiler.tc | 31 ++++++
tools/testing/selftests/rseq/rseq.c | 110 ++++++++++++++-------
tools/testing/selftests/rseq/rseq.h | 10 +-
tools/testing/selftests/vDSO/Makefile | 6 +-
tools/testing/selftests/vDSO/vdso_test_chacha.c | 36 ++++---
tools/testing/selftests/vDSO/vdso_test_getrandom.c | 76 +++++++-------
tools/testing/selftests/vDSO/vgetrandom-chacha.S | 18 ++++
12 files changed, 183 insertions(+), 109 deletions(-)
delete mode 120000 tools/arch/arm64/vdso
delete mode 120000 tools/arch/loongarch/vdso
delete mode 120000 tools/arch/powerpc/vdso
delete mode 120000 tools/arch/s390/vdso
delete mode 120000 tools/arch/x86/vdso
create mode 100644 tools/testing/selftests/ftrace/test.d/ftrace/fgraph-profiler.tc
create mode 100644 tools/testing/selftests/vDSO/vgetrandom-chacha.S
----------------------------------------------------------------
This fix solves this error, when calling kselftest with targets "net/rds":
The error was found by running tests manually with the command:
make kselftest TARGETS="net/rds"
The patch also specifies to import ip() function from the utils module.
Signed-off-by: Alessandro Zanni <alessandro.zanni87(a)gmail.com>
---
Notes:
v2:
modified the way the parent path is added
added test to reproduce the error
tools/testing/selftests/net/rds/test.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/net/rds/test.py b/tools/testing/selftests/net/rds/test.py
index e6bb109bcead..4a7178d11193 100755
--- a/tools/testing/selftests/net/rds/test.py
+++ b/tools/testing/selftests/net/rds/test.py
@@ -14,8 +14,11 @@ import sys
import atexit
from pwd import getpwuid
from os import stat
-from lib.py import ip
+# Allow utils module to be imported from different directory
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(this_dir, "../"))
+from lib.py.utils import ip
libc = ctypes.cdll.LoadLibrary('libc.so.6')
setns = libc.setns
--
2.43.0
This fix solves this error, when calling kselftest with targets
"drivers/net":
File "tools/testing/selftests/net/lib/py/nsim.py", line 64, in __init__
if e.errno == errno.ENOSPC:
NameError: name 'errno' is not defined
The error was found by running tests manually with the command:
make kselftest TARGETS="drivers/net"
The module errno makes available standard error system symbols.
Reviewed-by: Petr Machata <petrm(a)nvidia.com>
Signed-off-by: Alessandro Zanni <alessandro.zanni87(a)gmail.com>
---
Notes:
v2: added how to run the test
tools/testing/selftests/net/lib/py/nsim.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/testing/selftests/net/lib/py/nsim.py b/tools/testing/selftests/net/lib/py/nsim.py
index f571a8b3139b..1a8cbe9acc48 100644
--- a/tools/testing/selftests/net/lib/py/nsim.py
+++ b/tools/testing/selftests/net/lib/py/nsim.py
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
+import errno
import json
import os
import random
--
2.43.0
This patchset creates a selftest for the robust list interface, to track
regressions and assure that the interface keeps working as expected.
In this version I removed the kselftest_harness include, but I expanded the
current futex selftest API a little bit with basic ASSERT_ macros to make the
test easier to write and read. In the future, hopefully we can move all futex
selftests to the kselftest_harness API anyway.
Changes from v2:
- Create ASSERT_ macros for futex selftests
- Dropped kselftest_harness include, using just futex test API
- This is the expected output:
TAP version 13
1..6
ok 1 test_robustness
ok 2 test_set_robust_list_invalid_size
ok 3 test_get_robust_list_self
ok 4 test_get_robust_list_child
ok 5 test_set_list_op_pending
ok 6 test_robust_list_multiple_elements
# Totals: pass:6 fail:0 xfail:0 xpass:0 skip:0 error:0
https://lore.kernel.org/lkml/20240903134033.816500-1-andrealmeid@igalia.com
André Almeida (2):
selftests/futex: Add ASSERT_ macros
selftests/futex: Create test for robust list
.../selftests/futex/functional/.gitignore | 1 +
.../selftests/futex/functional/Makefile | 3 +-
.../selftests/futex/functional/robust_list.c | 512 ++++++++++++++++++
.../testing/selftests/futex/include/logging.h | 28 +
4 files changed, 543 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/futex/functional/robust_list.c
--
2.46.0
From: Steven Rostedt <rostedt(a)goodmis.org>
The addition of recording both the function name and return address to the
function graph tracer updated the selftest to check for "=-5" from "= -5".
But this causes the test to fail on certain configs, as "= -5" is still a
value that can be returned if function addresses are not enabled (older kernels).
Check for both "=-5" and " -5" as a success value.
Fixes: 21e92806d39c6 ("function_graph: Support recording and printing the function return address")
Signed-off-by: Steven Rostedt (Google) <rostedt(a)goodmis.org>
---
Shuah, this update is only for changes in my tree, so you do not need to add it.
tools/testing/selftests/ftrace/test.d/ftrace/fgraph-retval.tc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-retval.tc b/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-retval.tc
index e8e46378b88d..4307d4eef417 100644
--- a/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-retval.tc
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-retval.tc
@@ -29,7 +29,7 @@ set -e
: "Test printing the error code in signed decimal format"
echo 0 > options/funcgraph-retval-hex
-count=`cat trace | grep 'proc_reg_write' | grep '=-5' | wc -l`
+count=`cat trace | grep 'proc_reg_write' | grep -e '=-5 ' -e '= -5 ' | wc -l`
if [ $count -eq 0 ]; then
fail "Return value can not be printed in signed decimal format"
fi
--
2.45.2