.\" $NetBSD: uvm_hotplug.9,v 1.4 2016/12/24 08:05:47 wiz Exp $ .\" .\" Copyright (c) 2016 The NetBSD Foundation, Inc. .\" All rights reserved. .\" .\" This code is derived from software contributed to The NetBSD Foundation .\" by Cherry G Mathew and Santhosh N Raju. .\" .\" 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. .\" .Dd November 20, 2016 .Dt UVM_HOTPLUG 9 .Os .Sh NAME .Nm uvm_physseg_init , .Nm uvm_physseg_valid , .Nm uvm_physseg_get_start , .Nm uvm_physseg_get_end , .Nm uvm_physseg_get_avail_start , .Nm uvm_physseg_get_avail_end , .Nm uvm_physseg_get_pg , .Nm uvm_physseg_get_pmseg , .Nm uvm_physseg_get_free_list , .Nm uvm_physseg_get_start_hint , .Nm uvm_physseg_set_start_hint , .Nm uvm_physseg_get_next , .Nm uvm_physseg_get_prev , .Nm uvm_physseg_get_first , .Nm uvm_physseg_get_last , .Nm uvm_physseg_get_highest_frame , .Nm uvm_physseg_find , .Nm uvm_page_physload , .Nm uvm_page_physunload , .Nm uvm_page_physunload_force , .Nm uvm_physseg_plug , .Nm uvm_physseg_unplug , .Nm uvm_physseg_set_avail_start , .Nm uvm_physseg_set_avail_end .Nd memory hotplug manager .Sh SYNOPSIS .In uvm/uvm_physseg.h .Ft void .Fn uvm_physseg_init "void" .Ft uvm_physseg_t .Fn uvm_page_physload "paddr_t start" "paddr_t end" "paddr_t avail_start" \ "paddr_t avail_end" "int free_list" .Ft bool .Fn uvm_page_physunload "uvm_physseg_t upm" "int free_list" \ "paddr_t *paddrp" .Ft bool .Fn uvm_page_physunload_force "uvm_physseg_t upm" "int free_list" \ "paddr_t *paddrp" .Ft bool .Fn uvm_physseg_plug "paddr_t pfn" "size_t npages" "uvm_physseg_t *upmp" .Ft bool .Fn uvm_physseg_unplug "paddr_t pfn" "size_t npages" .Sh DESCRIPTION These utility routines provide the ability to tell .Xr uvm 9 about system memory segments. When the kernel is compiled with .Cd 'options UVM_HOTPLUG' , memory segments are handled in a dynamic data structure .Pq Xr rbtree 3 compared to a static array when not. This enables kernel code to add or remove information about memory segments at any point after boot - thus "hotplug". .Pp .Fn uvm_page_physload , .Fn uvm_page_physunload , and .Fn uvm_page_physunload_force are legacy interfaces which may be removed in the future. They must never be used after .Xr uvm_init 9 . .Pp .Em WARNING : This is an experimental feature and should not be used in production environments. Furthermore, attempting to "hotplug" without .Cd 'options UVM_HOTPLUG' after boot will almost certainly end in a .Xr panic 9 . .Sh USAGE .Ss INITIALIZING HOTPLUG The function .Fn uvm_physseg_init initializes the hotplug subsystem. This is expected to happen exactly once, at boot time, and from MD code. .Ss PLUGGING IN MEMORY .Fn uvm_page_physload registers .Xr uvm 9 with a memory segment span, and on a specified .Fa free_list . It must be called at system boot time as part of setting up memory management. The arguments describe the start and end of the physical addresses of the segment, and the available start and end addresses of pages not already in use. If a system has memory banks of different speeds the slower memory should be given a higher .Fa free_list value. .Bl -tag -offset indent -width "avail_start" .It Fa start Starting page frame number of the physical memory segments. .It Fa end Ending page frame number of the physical memory segments. .It Fa avail_start Available starting page frame number of the physical memory segments. .It Fa avail_end Available ending page frame number of the physical memory segments. .It Fa free_list The free list types are defined in the Machine Dependent code. .El .Pp This function returns a valid .Dv uvm_physseg_t handle when a successful plug occurs, else it will return .Dv UVM_PHYSSEG_TYPE_INVALID when the plug fails. .Pp .Fn uvm_physseg_plug registers .Xr uvm 9 with a memory segment span. It can also be called to initiate a hotplug and register a newly "hotplugged" physical memory range into the VM. Unlike .Fn uvm_page_physload this function can, if .Cd 'options UVM_HOTPLUG' is enabled at compile time, be used after .Xr uvm_init 9 . The arguments describe the start page frame, the number of pages to plug starting from the start page frame and an optional return variable, which points to a valid .Fa uvm_physseg_t handle when a successful plug occurs. .Bl -tag -offset indent -width "npages" .It Fa pfn Starting page frame number of the physical memory segment. .It Fa npages Total number of pages from the starting page frame number to plug in. .It Fa upmp If upmp is not .Dv NULL , then on a successful plug, a valid pointer to the uvm_physseg_t handle for the segment which was plugged is returned. .El .Pp This function returns .Fa true when a successful plug occurs, .Fa false otherwise. .Ss UNPLUGGING MEMORY The functions .Fn uvm_page_physunload , .Fn uvm_page_physunload_force , and .Fn uvm_physseg_unplug make .Xr uvm 9 forget about previously registered memory segments or portions of such. .Pp .Fn uvm_page_physunload unloads pages from a segment (from the front or from the back) depending on its availability. When the last page is removed, the segment handle is invalidated and supporting metadata is freed. .Pp Note: This function can only be used during boot time. Pages, once unloaded, are unregistered from uvm and are therefore assumed to be managed by the code which called .Fn uvm_page_physunload 9 (usually boot time MD code, for boottime memory "allocation"). .Pp The arguments are: .Bl -tag -offset indent -width "free_list" .It Fa upm The handle identifying segment from which we are trying to unload memory. .It Fa free_list The free list types are defined in the Machine Dependent code. .It Fa paddrp The pointer to the physical address that was unloaded. .El .Pp If the unload was successful, .Fa true is returned, .Fa false otherwise. .Pp .Fn uvm_page_physunload_force unconditionally unloads pages from a segment. When the last page is removed, the segment handle is invalidated and supporting metadata is freed. .Pp Note: This function can only be used during boot time. Pages, once unloaded, are unregistered from uvm and are therefore assumed to be managed by the code which called .Fn uvm_page_physunload_force 9 (usually boot time MD code, for boottime memory "allocation"). .Pp The arguments are: .Bl -tag -offset indent -width "free_list" .It Fa upm The handle identifying segment from which we are trying to unload memory. .It Fa free_list The free list types are defined in the Machine Dependent code. .It Fa paddrp The pointer to the physical address that was unloaded. .El .Pp If the unload was successful .Fa true is returned, .Fa false otherwise. .Pp .Fn uvm_physseg_unplug can be called to unplug an existing physical memory segment. Unlike .Fn uvm_page_physunload and .Fn uvm_page_physunload_force , it can be called after .Xr uvm_init 9 , if .Cd 'options UVM_HOTPLUG' is enabled at compile time. .Fn uvm_hotplug 9 makes no effort to manage the state of the underlying physical memory. It is up to the caller to ensure that it is not in use, either by .Xr uvm 9 , or by any other sub-system. Further, any hardware quiescing that may be required is the responsibility of MD code. The arguments describe the start page frame and the number of pages to unplug. The arguments are: .Bl -tag -offset indent -width "npages" .It Fa pfn Starting page frame number of the physical memory segment. .It Fa npages Total number of pages from the starting page frame number to unplug. .El .Pp Returns .Fa true or .Fa false depending on success or failure respectively. .Sh UTILITY FUNCTIONS .Bl -ohang .It Ft bool .Fn uvm_physseg_valid "uvm_physseg_t upm" .It Ft paddr_t .Fn uvm_physseg_get_start "uvm_physseg_t upm" .It Ft paddr_t .Fn uvm_physseg_get_end "uvm_physseg_t upm" .It Ft paddr_t .Fn uvm_physseg_get_avail_start "uvm_physseg_t upm" .It Ft paddr_t .Fn uvm_physseg_get_avail_end "uvm_physseg_t upm" .It Ft struct vm_page * .Fn uvm_physseg_get_pg "uvm_physseg_t upm" "paddr_t index" .It Ft struct pmap_physseg * .Fn uvm_physseg_get_pmesg "uvm_physseg_t upm" .It Ft int .Fn uvm_physseg_get_free_list "uvm_physseg_t upm" .It Ft u_int .Fn uvm_physseg_get_start_hint "uvm_physseg_t upm" .It Ft bool .Fn uvm_physseg_set_start_hint "uvm_physseg_t upm" "u_int start_hint" .It Ft uvm_physseg_t .Fn uvm_physseg_get_next "uvm_physseg_t upm" .It Ft uvm_physseg_t .Fn uvm_physseg_get_prev "uvm_physseg_t upm" .It Ft uvm_physseg_t .Fn uvm_physseg_get_first "void" .It Ft uvm_physseg_t .Fn uvm_physseg_get_last "void" .It Ft paddr_t .Fn uvm_physseg_get_highest_frame "void" .It Ft paddr_t .Fn uvm_physseg_find "paddr pframe" "psize_t *offsetp" .It Ft void .Fn uvm_physseg_set_avail_start "uvm_physseg_t upm" "paddr_t avail_start" .It Ft void .Fn uvm_physseg_set_avail_end "uvm_physseg_t upm" "paddr_t avail_end" .El .Pp .Fn uvm_physseg_valid validates a handle that is passed in, returns .Fa true if the given handle is valid, .Fa false otherwise. .Pp .Fn uvm_physseg_get_start if a valid .Fa uvm_physseg_t handle is passed in, it returns the starting physical address of the segment. The returned value is of type .Ft paddr_t . In case the handle is invalid the returned value will match .Ft ( paddr_t ) \-1. .Pp .Fn uvm_physseg_get_end if a valid .Fa uvm_physseg_t handle is passed in, it returns the ending physical address of the segment. The returned value is of type .Ft paddr_t . In case the handle is invalid the returned value will match .Ft ( paddr_t ) \-1. .Pp .Fn uvm_physseg_get_avail_start if a valid .Fa uvm_physseg_t handle is passed in, it returns the available starting physical address of the segment. The returned value is of type .Ft paddr_t . In case the handle is invalid the returned value will match .Ft ( paddr_t ) \-1. .Pp .Fn uvm_physseg_get_avail_end if a valid .Fa uvm_physseg_t handle is passed in, it returns the available ending physical address of the segment. The returned value is of type .Ft paddr_t . In case the handle is invalid the returned value will match .Ft ( paddr_t ) \-1. .Pp .Fn uvm_physseg_get_pg if a valid .Fa uvm_physseg_t handle along with an index value is passed in, it returns the .Fa struct vm_page * object contained in that location. .Pp .Fn uvm_physseg_get_pmseg if a valid .Fa uvm_physseg_t handle is passed in, it returns the .Fa struct pmap_physseg * object contained in the handle. .Pp .Fn uvm_physseg_get_free_list if a valid .Fa uvm_physseg_t handle is passed in, it returns the .Fa free_list type for which the current segment is associated with. The returned value is of type .Fa int . .Pp .Fn uvm_physseg_get_start_hint if a valid .Fa uvm_physseg_t handle is passed in, it returns the .Fa start_hint type for the current segment. The returned value is of type .Fa u_int . .Pp .Fn uvm_physseg_set_start_hint if a valid handle along with the .Fa start_hint is passed in, the value is set in the segment. And a .Fa true is returned to indicate a successful value setting. In case the handle is invalid a .Fa false is returned. .Pp .Fn uvm_physseg_get_next if a valid handle is passed in, it returns the next valid .Fa uvm_physseg_t handle in the sequence. However if the handle passed is the last segment in the sequence the function returns .Fa UVM_PHYSSEG_TYPE_INVALID_OVERFLOW . Passing an invalid handle is not fatal, and returns .Fa UVM_PHYSSEG_TYPE_INVALID . . .Pp .Fn uvm_physseg_get_prev if a valid handle is passed in, it returns the previous validh .Fa uvm_physseg_t handle in the sequence. However if the handle passed is the first segment in the sequence the function returns .Fa UVM_PHYSSEG_TYPE_INVALID_EMPTY . Passing an invalid handle is not fatal, and returns .Fa UVM_PHYSSEG_TYPE_INVALID . . .Pp .Fn uvm_physseg_get_first returns the first valid .Fa uvm_physseg_t handle in the sequence. However if there are no valid handles in the sequence yet, the function returns .Fa UVM_PHYSSEG_TYPE_INVALID_EMPTY . .Pp .Fn uvm_physseg_get_last returns the last valid .Fa uvm_physseg_t handle in the sequence. However if there are no valid handles in the sequence yet, the function returns .Fa UVM_PHYSSEG_TYPE_INVALID_EMPTY . .Pp .Fn uvm_physseg_get_highest_frame returns the frame number of the highest registered physical page frame which is of type .Ft paddr_t . XXX: Searching on empty sequences are not yet processed in the function. .Pp .Fn uvm_physseg_find searches for a given segment containing the page frame .Ft ( paddr_t ) passed in. If a segment that falls between starting and ending addresses is found, the corresponding .Fa uvm_physseg_t handle is returned else a .Fa UVM_PHYSSEG_TYPE_INVALID is returned. The second parameter, if not set to .Dv NULL , the offset value of the page frame passed in with respect to the starting address is set to the appropriate .Fa psize_t value if the search was successful in finding the segment. .Pp .Fn uvm_physseg_set_avail_start if a valid .Fa uvm_physseg_t handle is passed in along with the available starting physical address of the segment of type .Ft paddr_t , the value is set in the segment. .Pp .Fn uvm_physseg_set_avail_end if a valid .Fa uvm_physseg_t handle is passed in along with the available ending physical address of the segment of type .Ft paddr_t , the value is set in the segment. .Sh NOTES .Fn uvm_physseg_plug and .Fn uvm_physseg_unplug must never be used after .Xr uvm_init 9 in a kernel build where .Cd 'options UVM_HOTPLUG' is not enabled. .Sh DIAGNOSTICS Tests for .Nm are in .Pa tests/sys/uvm . .Pp Unit / functional tests are in .Pa tests/sys/uvm/t_uvm_physseg.c . These tests focus on the expected working of the .Nm API and its utility functions. .Pp Load tests can be found in .Pa tests/sys/uvm/t_uvm_physseg_load.c . These tests focus on stressing the .Nm implementation in order to make performance comparisons between kernel builds with and without .Cd 'options UVM_HOTPLUG' . .\" .Sh RETURN VALUES .\" .Sh EXAMPLES .Sh CODE REFERENCES The uvm hotplug feature is implemented in the file .Pa sys/uvm/uvm_physseg.c . The uvm hotplug API is exported via .Pa sys/uvm/uvm_physseg.h . .Sh SEE ALSO .Xr extent 9 , .Xr free 9 , .Xr malloc 9 , .Xr memoryallocators 9 , .Xr uvm 9 .Sh HISTORY This API emerged out of the need to insert new pages at runtime in the Xen .Xr x86/balloon 4 driver. .Sh AUTHORS .An -nosplit .An Cherry G. Mathew .Aq Mt cherry@NetBSD.org designed and integrated the API. .Pp .An Santhosh N. Raju .Aq Mt santhosh.raju@gmail.com implemented the dynamic segment handling code and all tests for this API. .Pp .An Nick Hudson .Aq Mt skrll@NetBSD.org contributed bugfixes and testing on a wide range of hardware ports.