1.\" $NetBSD: versioningsyscalls.9,v 1.7 2024/05/23 06:35:45 pgoyette Exp $ 2.\" 3.\" Copyright (c) 2023 The NetBSD Foundation, Inc. 4.\" All rights reserved. 5.\" 6.\" This code is derived from software contributed to The NetBSD Foundation 7.\" by Theodore Preduta. 8.\" 9.\" Redistribution and use in source and binary forms, with or without 10.\" modification, are permitted provided that the following conditions 11.\" are met: 12.\" 1. Redistributions of source code must retain the above copyright 13.\" notice, this list of conditions and the following disclaimer. 14.\" 2. Redistributions in binary form must reproduce the above copyright 15.\" notice, this list of conditions and the following disclaimer in the 16.\" documentation and/or other materials provided with the distribution. 17.\" 18.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28.\" POSSIBILITY OF SUCH DAMAGE. 29.\" 30.Dd May 20, 2024 31.Dt VERSIONINGSYSCALLS 9 32.Os 33. 34.Sh NAME 35.Nm versioningsyscalls 36.Nd guide on versioning syscalls 37. 38.Sh DESCRIPTION 39.Nx 40has the ability to change the ABI of a syscall whilst retaining backwards 41compatibility with existing code. 42This means that existing code keeps working the same way as before, and 43new code can use new features and/or functionality. 44In the past this has allowed 45.Ft dev_t 46to move from 16 bits to 32 bits, 47.Ft ino_t 48and 49.Ft time_t 50to move from 32 bits to 64 bits, 51and adding fields to 52.Ft struct kevent 53without disturbing existing binaries. 54To achieve this both kernel and userland changes are required. 55.Pp 56In the kernel, a new syscall is added with a new ABI, and the old syscall 57is retained and moved to a new location that holds the compatibility syscalls 58.Pq Pa src/sys/compat . 59Kernels can be compiled with or without backwards compatibility syscalls. 60See the 61.Dv COMPAT_ Ns Ar XX 62options in 63.Xr options 4 . 64.Pp 65In userland, the original syscall stub is moved into 66.Pa src/lib/libc/compat 67retaining the same symbol name and ABI. 68The new stub is added to libc, and in the header file the syscall symbol is 69made to point to the new name with the new ABI. 70.Pp 71This is done via symbol renaming instead of ELF versioned symbols for 72historical reasons. 73.Nx 74has retained binary compatibility with most syscalls since 75.Nx 0.9 76with the exception of Scheduler Activation syscalls which are not being 77emulated because of the cost and safety of doing so. 78.Pp 79To avoid confusion, the following words are used to disambiguate which version 80of the system call is being described. 81.Bl -tag -offset indent -width Em 82.It Em old 83Any previous versions of the syscall, which have already been versioned and 84superseded by the current version of the syscall. 85.It Em current 86The version of the syscall currently in use. 87.It Em next 88The version of the syscall that will become standard in the next release. 89.El 90.Pp 91Additionally, 92.Ar CNUM 93always represents the last 94.Nx 95release where the current 96version of the system call is the default, multiplied by ten and retaining a 97leading zero. 98For example 99.Nx 0.9 100has 101.Dv COMPAT_09 102whereas 103.Nx 10.0 104has 105.Dv COMPAT_100 . 106. 107.Sh VERSIONING THE SYSCALL 108This section describes what needs to be modified to add the new version of the 109syscall. 110It assumes the current version of the syscall is 111.Fn my_syscall "struct my_struct *ms" 112and that 113.Ft my_struct 114will be versioned. 115If not versioning a struct, passages that mention 116.Ft my_struct 117can be ignored. 118.Pp 119The syscall version suffix 120.Dv VNUM 121indicates the first release of 122.Nx 123the system call will appear in. 124The compat version 125.Dv CNUM 126is the last version of 127.Nx the old system call was used. 128Typically VNUM = CNUM + 1 . 129.Pp 130For example if you are versioning 131.Xr getcontext 2 132just after 133.Nx 11 134was released, and the original system call was called 135.Fn getcontext , 136the system call will become 137.Fn __getcontext12 138and the compat entry point will become 139.Fn compat_11_getcontext . 140.Pp 141Next time 142.Xr getcontext 2 143needs versioning, for example just after 144.Nx 15 145was released, it will become 146.Fn __getcontext16 147and the compat entry will become 148.Fn compat_15___getcontext12 . 149.Pp 150Please note that the historical practice up to 151.Nx 11 152has been that the syscall suffix matched the version when the syscall 153was last used. 154. 155.Ss Versioning structs 156To version 157.Ft struct my_struct , 158first make a copy of 159.Ft my_struct 160renamed to 161.Ft my_structCNUM 162in an equivalent header in 163.Pa sys/compat/sys . 164After that, you can freely modify 165.Ft my_struct 166as desired. 167. 168.Ss Versioning the entry point 169The stub for the next version of the syscall will be 170.Fn __my_syscallVNUM , 171and will have entry point 172.Fn sys___my_syscallVNUM . 173. 174.Ss Modifying syscalls.conf 175.Pa sys/kern/syscalls.conf 176may need to be modified to contain 177.Li compat_CNUM 178in the 179.Va compatopts 180variable. 181. 182.Ss Modifying syscalls.master 183First, add the next syscall to 184.Pa sys/kern/syscalls.master 185keeping 186.Fn my_syscall 187as the name, and set the (optional) compat field of the declaration to 188.Ar CNUM . 189.Pp 190Next, modify the current version of the syscall, and replace the type 191field 192.Pq usually just Li STD 193with 194.Dv COMPAT_CNUM MODULAR compat_CNUM . 195.Pp 196The keyword 197.Dv MODULAR 198indicates that the system call can be part of a kernel module. 199Even if the system call was not part of a module before, now it will be part 200of the 201.Dv COMPAT_CNUM 202module. 203.Pp 204Finally, if applicable, replace the types of the current and old versions of the 205syscall with the compat type. 206.Pp 207Overall, the final diff should look like 208.Bd -literal 209- 123 STD { int|sys||my_syscall(struct my_struct *ms); } 210+ 123 COMPAT_CNUM MODULAR compat_CNUM { int|sys||my_syscall(struct my_structCNUM *ms); } 211\&... 212+ 456 STD { int|sys|VNUM|my_syscall(struct my_struct *ms); } 213.Ed 214. 215.Ss Modifying Makefile.rump 216If the current syscall is rump, 217.Pa sys/rump/Makefile.rump 218must contain 219.Ar CNUM 220in the 221.Dv RUMP_NBCOMPAT 222variable. 223. 224.Ss Regenerating the system calls 225If versioning structs, then modify 226.Pa sys/kern/makesyscalls.sh 227by adding an entry for 228.Ft struct my_structCNUM 229type to 230.Va uncompattypes . 231.Pp 232The 233.Va uncompattypes 234map is used in 235.Xr rump 7 236system call table generation, to map from the versioned types to the original 237names since 238.Xr rump 7 239wants to have a non-versioned copy of the system call table. 240.Pp 241Then regenerate the syscall tables in the usual way, first by running 242.Pa sys/kern/makesyscalls.sh , 243then if the system call is rump, doing a build in 244.Pa sys/rump 245and then running 246.Pa sys/rump/makerumpsyscalls.sh 247passing it the path to the result of the build you just did as its first 248argument. 249. 250.Sh KERNEL COMPATIBILITY 251This section covers maintaining compatibility at the kernel level, by 252adding an entry point for the current syscall in an appropriate compat 253module. 254For the purposes of this section, we assume the current 255syscall has entry point 256.Fn sys_my_syscall 257and lives inside 258.Pa sys/kern/my_file.c . 259. 260.Ss Creating the compat current syscall 261The compat version of the current syscall has entry point 262.Fn compat_CNUM_sys_my_syscall , 263and should be implemented in 264.Pa sys/compat/common/my_file_CNUM.c 265with the same semantics as the current syscall. 266Often this involves translating the arguments to the next syscall, 267and then calling that syscall's entry point. 268. 269.Ss Adding it to the compat module 270.Pa sys/compat/common/my_file_CNUM.c 271must contain an array of 272.Ft struct syscall_package 273that declares the mapping between syscall number and entry point, 274terminating in a zero element (see sample diff below). 275.Pp 276Additionally, 277.Pa sys/compat/common/my_file_CNUM.c 278must contain two functions, 279.Fn my_file_CNUM_init 280and 281.Fn my_file_CNUM_fini 282that are used to initialize/clean up anything related to this syscall. 283At the minimum they must make calls to 284.Fn syscall_establish 285and 286.Fn syscall_disestablish 287respectively, adding and removing the syscalls. 288The stubs for these functions should be located in 289.Pa sys/compat/common/compat_mod.h . 290.Pp 291Overall, 292.Pa sys/compat/common/my_file_CNUM.c 293must at the minimum contain 294.Bd -literal -offset indent 295static const struct syscall_package my_file_CNUM_syscalls[] = { 296 { SYS_compat_CNUM_my_syscall, 0, 297 (sy_call_t *)compat_CNUM_sys_my_syscall }, 298 { 0, 0, NULL }, 299}; 300 301int 302compat_CNUM_my_syscall(...) 303{ /* Compat implementation goes here. */ } 304 305int 306my_file_CNUM_init(void) 307{ return syscall_establish(NULL, my_file_CNUM_syscalls); } 308 309int 310my_file_CNUM_fini(void) 311{ return syscall_disestablish(NULL, my_file_CNUM_syscalls); } 312.Ed 313.Pp 314Finally, 315.Pa sys/compat/common/compat_CNUM_mod.c 316needs to be modified to have its 317.Fn compat_CNUM_init 318and 319.Fn compat_CNUM_fini 320functions call 321.Fn my_file_CNUM_init 322and 323.Fn my_file_CNUM_fini 324respectively. 325. 326.Ss Modifying old compat syscalls 327If the current syscall has already been versioned, you might need to 328modify the old compat syscalls in 329.Pa sys/compat/common 330to either use the next syscall or the current compat syscall. 331Note that compat code can be made to depend on compat code for more 332recent releases. 333.Sh USERLAND COMPATIBILITY 334With the exception of the libraries described below, making the rest 335of userland work will just involve recompiling, and perhaps changing a 336constant or a 337.Li #define . 338. 339.Ss libc 340A userland version of any old and current versions of the syscall must be 341implemented. 342For the current syscall with stub 343.Fn my_syscall struct\ my_struct\ *ms 344in 345.Pa sys/sys/my_header.h , 346an implementation of 347.Fn my_syscall 348must be written in 349.Pa lib/libc/compat/sys/compat_my_syscall.c . 350.Pp 351Additionally, a call to 352.Fn __warn_references 353must be added in 354.Pa lib/libc/compat/sys/compat_my_syscall.c 355to warn of any uses of the compat syscall and mention how to use the next 356version of the syscall. 357In almost all cases the instructions on how to use the next version of the 358syscall will be 359.Dq include <sys/my_header.h> to generate correct reference . 360.Pp 361Overall, 362.Pa lib/libc/compat/sys/compat_my_syscall.c 363must at the minimum include 364.Bd -literal -offset indent 365#include <sys/compat/my_header.h> 366 367__warn_references(my_syscall, 368 "warning: reference to compatibility my_syscall();" 369 " message on how to use the next my_syscall()"); 370 371int 372my_syscall() 373{ /* Compat implementation goes here. */ } 374.Ed 375