diff --git a/testcases/kernel/hotplug/acpi_hotplug/ACPIHOTPLUG_lib.sh b/testcases/kernel/hotplug/acpi_hotplug/ACPIHOTPLUG_lib.sh
new file mode 100755
index 000000000..8c5dc1d89
--- /dev/null
+++ b/testcases/kernel/hotplug/acpi_hotplug/ACPIHOTPLUG_lib.sh
@@ -0,0 +1,310 @@
+#!/bin/sh
+
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2018, FUJITSU LIMITED. All rights reserved.
+
+export HOTPLUGABLE_CONTAINER=
+export HOTPLUGABLE_NODES=()
+RETRY=5
+RETRY_TIME=60
+
+# $1: node number
+is_memoryless_node()
+{
+	local node=$1
+
+	numactl -H | awk '
+		/node '$node' size:/ {
+			if ($4 == 0)
+				prine 1
+			else
+				print 0
+		}'
+}
+
+# $1: node number
+is_movable_node()
+{
+	local node=$1
+
+	awk '
+	BEGIN {
+		zone = ""
+		NotMovableFound = 0
+		nextnode = '$node' + 1
+	}
+	/^Node '$node'/{
+		zone = $4
+	}
+	/present/ {
+		if (zone != "") {
+			if ((zone != "Movable") && ($2 != 0)) {
+				NotMovableFound = 1
+				exit
+			}
+		}
+	}
+	match($0, "^Node " nextnode) {
+		exit
+	}
+
+	END {
+		if (NotMovableFound == 0)
+			print 1
+		else
+			print 0
+	}
+	' /proc/zoneinfo
+}
+
+stop_udev()
+{
+	systemctl stop systemd-udevd-kernel.socket
+	systemctl stop systemd-udevd-control.socket
+	systemctl stop systemd-udevd.service
+}
+
+resume_udev()
+{
+	systemctl start systemd-udevd.service
+	systemctl start systemd-udevd-kernel.socket
+	systemctl start systemd-udevd-control.socket
+}
+
+_setup()
+{
+	local ACPI_CONTAINERS=()
+	local ONLINE_CONTAINERS=()
+	local CPUS=()
+	local tmp_NODES=()
+	local NODES=()
+	local movable_node=
+	local NOHP_NODES=0
+
+	ACPI_CONTAINERS=( $(find /sys/devices/LNXSYSTM\:00/ -name 'ACPI0004:*') )
+
+	ONLINE_CONTAINERS=()
+	for c in ${ACPI_CONTAINERS[@]}; do
+		status=$(cat $c/status)
+		if [[ $status -ne 0 ]]; then
+			ONLINE_CONTAINERS=( ${ONLINE_CONTAINERS[@]} $c )
+		fi
+	done
+
+	if [[ ${#ONLINE_CONTAINERS[@]} -lt 2 ]]; then
+		tst_brk TCONF "The number of online ACPI containers is not enough. 2 or more online ACPI containers are needed, but this system has ${#ONLINE_CONTAINERS[@]} contianers."
+	fi
+
+	for c in ${ONLINE_CONTAINERS[@]}; do
+		CPUS=( $(find $c -name 'ACPI0007:*' ) )
+		tmp_NODES=()
+		NODES=()
+		NOHP_NODES=0
+		for cpu in ${CPUS[@]}; do
+			tmp_NODES=( ${tmp_NODES[@]} $(ls $cpu/physical_node/ 2> /dev/null | grep ^node | sed -e 's/node//') )
+		done
+		NODES=( $(echo ${tmp_NODES[@]} | tr ' ' '\n' | sort | uniq ) )
+
+		# Memory device ID is PNP0C80, however, the memory ID is not used here
+		# but the node ID is used.
+		# The hotplugable memory section has ACPI_SRAT_MEM_HOT_PLUGGABLE flag
+		# and the zone is handled as Movable zone. Following assumes that
+		# the node has only Movable zone or it is memory less node.
+		# So using the node ID gets this test cleared rather than using memory ID.
+		for n in ${NODES[@]}; do
+			if [[ $(is_movable_node $n) -eq 0 ]] && [[ $(is_memoryless_node $n) -eq 0 ]]; then
+				NOHP_NODES=1
+				break
+			fi
+		done
+		if [[ $NOHP_NODES -eq 0 ]]; then
+			HOTPLUGABLE_CONTAINER=$(basename $c)
+			HOTPLUGABLE_NODES=( ${NODES[@]} )
+			break
+		fi
+	done
+
+	# Some hotplug udev rules may disturb for this test.
+	# Let's stop them.
+	stop_udev
+
+	tst_res TINFO "TARGET ACPI CONTANIER: $HOTPLUGABLE_CONTAINER"
+	tst_res TINFO "TARGET NODES: ${HOTPLUGABLE_NODES[@]}"
+}
+
+_cleanup()
+{
+	resume_udev
+}
+
+cpu_hp()
+{
+	local hpop=
+	local CPUS=( $(echo /sys/bus/acpi/devices/$HOTPLUGABLE_CONTAINER/ACPI0007:*/physical_node/online) )
+
+	local hp_cpus=${#CPUS[@]}
+	local current_cpus=$(nproc)
+	local expected_cpus=
+	local ACPI_CPU=
+	local force=0
+	local hotplugedcpus=0
+
+	if [[ $1 == "hotremove" ]]; then
+		hpop=0
+	else
+		hpop=1
+	fi
+	if [[ $2 == "force" ]]; then
+		force=1
+	fi
+
+	if [[ $hpop -eq 0 ]]; then
+		expected_cpus=$(( current_cpus - hp_cpus ))
+	else
+		expected_cpus=$(( current_cpus + hp_cpus ))
+	fi
+
+	for cpu in ${CPUS[@]}; do
+		echo -n $hpop > $cpu 2> /dev/null
+		ACPI_CPU=$( echo $cpu | sed -e 's#/sys/bus/acpi/devices/ACPI0004:[0-9a-f]\+/\(ACPI0007:.*\)/physical_node/online#\1#')
+		if [[ $? -ne 0 ]]; then
+			tst_res TINFO "CPU: $ACPI_CPU $1 failed."
+			if [[ $force -eq 0 ]]; then
+				return 1
+			fi
+		else
+			if [[ $force -ne 0 ]]; then
+				tst_res TINFO "CPU: $ACPI_CPU $1 successed."
+			fi
+			hotplugedcpus=$(( hotplugedcpus  + 1 ))
+		fi
+	done
+
+	tst_res TINFO "CPU: current: $(nproc) hotpluged: $hotplugedcpus"
+	if [[ $(nproc) -eq $expected_cpus ]]; then
+		return 0
+	else
+		return 1
+	fi
+}
+
+# $1: node number
+# $2: expected memory size (MB)
+memhp_result()
+{
+	local node=$1
+	local expected=$2
+	local current=
+
+	current=$(numactl -H | awk '
+	/^node '$node' size/ {
+		print $4
+	}
+	')
+
+	if [[ $current -eq $expected ]]; then
+		echo 1
+	else
+		echo 0
+	fi
+}
+
+memory_hp()
+{
+	local hpop=
+	local memory=()
+	local memhpdone=
+	local expected=
+	local block_size_bytes=$(cat /sys/devices/system/memory/block_size_bytes )
+	block_size_bytes=$(echo "obase=10;ibase=16;$block_size_bytes" | bc)
+	local result=0
+	local force=0
+	local hotplugedsections=
+	local removable=
+
+	declare -A mem_hotpluged
+
+	if [[ $1 == "hotremove" ]]; then
+		hpop="offline"
+	else
+		hpop="online_movable"
+	fi
+	if [[ $2 == "force" ]]; then
+		force=1
+	fi
+
+	for node in ${HOTPLUGABLE_NODES[@]}; do
+		memory=$(ls /sys/devices/system/node/node$node/ | grep memory | sort -n -r)
+		for mem in ${memory[@]}; do
+			if [[ $force -eq 1 ]]; then
+				echo -n $hpop > /sys/devices/system/node/node$node/$mem/state 2> /dev/null
+				mem_hotpluged[$node]=$(( mem_hotpluged[$node] + 1 ))
+				hotplugedsections=$(( hotplugedsections + 1 ))
+			else
+				memhpdone=0
+				for ((i = 1; i <= RETRY; i++)); do
+					echo -n $hpop > /sys/devices/system/node/node$node/$mem/state
+					if [[ $? -eq 0 ]]; then
+						memhpdone=1
+						break
+					else
+						removable=$(cat /sys/devices/system/node/node$node/$mem/removable)
+						if [[ $removable -ne 1 ]]; then
+							tst_res TINFO "memory: Node: $node section: $mem something wrong..."
+							return 1
+						fi
+						tst_res TINFO "memory: Node: $node section: $mem $1 failed ($i times). Retry..."
+					fi
+					sleep $RETRY_TIME
+				done
+				if [[ $memhpdone -eq 0 ]]; then
+					tst_res TINFO "memory: Node: $node section: $mem $1 failed."
+					return 1
+				else
+					tst_res TINFO "memory: Node: $node section: $mem $1 successed."
+					mem_hotpluged[$node]=$(( mem_hotpluged[$node] + 1 ))
+					hotplugedsections=$(( hotplugedsections + 1 ))
+				fi
+			fi
+		done
+	done
+
+	for node in ${HOTPLUGABLE_NODES[@]}; do
+		if [[ $hpop == "offline" ]]; then
+			expected=0
+		else
+			expected=$(echo "${mem_hotpluged[$node]} * $block_size_bytes/1024/1024" | bc)
+		fi
+		if [[ $(memhp_result $node $expected) -ne 1 ]]; then
+			result=$((result + 1))
+		fi
+		tst_res TINFO "Memory: Node: $node $hotplugedsections sections hotpluged."
+	done
+
+	return $result
+}
+
+container_hp()
+{
+	local hpop=
+	local online_ret=0
+
+	if [[ $1 == "hotremove" ]]; then
+		hpop=0
+	else
+		hpop=1
+	fi
+
+	echo $hpop > /sys/bus/acpi/devices/$HOTPLUGABLE_CONTAINER/physical_node/online
+	online_ret=$?
+
+	if [[ $online_ret -ne 0 ]]; then
+		tst_res TINFO "ACPI container: $HOTPLUGABLE_CONTAINER $1 failed."
+		numactl -H
+		return 1
+	else
+		tst_res TINFO "ACPI container: $HOTPLUGABLE_CONTAINER $1 successed."
+	fi
+
+	return 0
+}
