| 
									
										
										
										
											2018-12-20 12:10:15 -08:00
										 |  |  | /* | 
					
						
							|  |  |  |  * safe-syscall.inc.S : host-specific assembly fragment | 
					
						
							|  |  |  |  * to handle signals occurring at the same time as system calls. | 
					
						
							| 
									
										
										
										
											2021-11-17 16:14:00 +01:00
										 |  |  |  * This is intended to be included by common-user/safe-syscall.S | 
					
						
							| 
									
										
										
										
											2018-12-20 12:10:15 -08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Written by Richard Henderson <rth@twiddle.net>
 | 
					
						
							|  |  |  |  * Copyright (C) 2018 Linaro, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This work is licensed under the terms of the GNU GPL, version 2 or later. | 
					
						
							|  |  |  |  * See the COPYING file in the top-level directory. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-23 11:44:55 +01:00
										 |  |  |         .global safe_syscall_base
 | 
					
						
							|  |  |  |         .global safe_syscall_start
 | 
					
						
							|  |  |  |         .global safe_syscall_end
 | 
					
						
							|  |  |  |         .type   safe_syscall_base, @function
 | 
					
						
							|  |  |  |         .type   safe_syscall_start, @function
 | 
					
						
							|  |  |  |         .type   safe_syscall_end, @function
 | 
					
						
							| 
									
										
										
										
											2018-12-20 12:10:15 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-23 11:44:55 +01:00
										 |  |  |         /* | 
					
						
							|  |  |  |          * This is the entry point for making a system call. The calling | 
					
						
							|  |  |  |          * convention here is that of a C varargs function with the | 
					
						
							|  |  |  |          * first argument an 'int *' to the signal_pending flag, the | 
					
						
							|  |  |  |          * second one the system call number (as a 'long'), and all further | 
					
						
							|  |  |  |          * arguments being syscall arguments (also 'long'). | 
					
						
							|  |  |  |          */ | 
					
						
							| 
									
										
										
										
											2018-12-20 12:10:15 -08:00
										 |  |  | safe_syscall_base: | 
					
						
							| 
									
										
										
										
											2021-11-23 11:44:55 +01:00
										 |  |  |         .cfi_startproc | 
					
						
							|  |  |  |         /* | 
					
						
							|  |  |  |          * The syscall calling convention is nearly the same as C: | 
					
						
							| 
									
										
										
										
											2021-11-15 14:08:52 +01:00
										 |  |  |          * we enter with a0 == &signal_pending | 
					
						
							| 
									
										
										
										
											2021-11-23 11:44:55 +01:00
										 |  |  |          *               a1 == syscall number | 
					
						
							|  |  |  |          *               a2 ... a7 == syscall arguments | 
					
						
							|  |  |  |          *               and return the result in a0 | 
					
						
							|  |  |  |          * and the syscall instruction needs | 
					
						
							|  |  |  |          *               a7 == syscall number | 
					
						
							|  |  |  |          *               a0 ... a5 == syscall arguments | 
					
						
							|  |  |  |          *               and returns the result in a0 | 
					
						
							|  |  |  |          * Shuffle everything around appropriately. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         mv      t0, a0          /* signal_pending pointer */ | 
					
						
							|  |  |  |         mv      t1, a1          /* syscall number */ | 
					
						
							|  |  |  |         mv      a0, a2          /* syscall arguments */ | 
					
						
							|  |  |  |         mv      a1, a3 | 
					
						
							|  |  |  |         mv      a2, a4 | 
					
						
							|  |  |  |         mv      a3, a5 | 
					
						
							|  |  |  |         mv      a4, a6 | 
					
						
							|  |  |  |         mv      a5, a7 | 
					
						
							|  |  |  |         mv      a7, t1 | 
					
						
							| 
									
										
										
										
											2018-12-20 12:10:15 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-23 11:44:55 +01:00
										 |  |  |         /* | 
					
						
							|  |  |  |          * This next sequence of code works in conjunction with the | 
					
						
							|  |  |  |          * rewind_if_safe_syscall_function(). If a signal is taken | 
					
						
							|  |  |  |          * and the interrupted PC is anywhere between 'safe_syscall_start' | 
					
						
							|  |  |  |          * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'. | 
					
						
							|  |  |  |          * The code sequence must therefore be able to cope with this, and | 
					
						
							|  |  |  |          * the syscall instruction must be the final one in the sequence. | 
					
						
							|  |  |  |          */ | 
					
						
							| 
									
										
										
										
											2018-12-20 12:10:15 -08:00
										 |  |  | safe_syscall_start: | 
					
						
							| 
									
										
										
										
											2021-11-23 11:44:55 +01:00
										 |  |  |         /* If signal_pending is non-zero, don't do the call */ | 
					
						
							|  |  |  |         lw      t1, 0(t0) | 
					
						
							| 
									
										
										
										
											2021-11-15 14:08:52 +01:00
										 |  |  |         bnez    t1, 2f | 
					
						
							| 
									
										
										
										
											2021-11-23 11:44:55 +01:00
										 |  |  |         scall | 
					
						
							| 
									
										
										
										
											2018-12-20 12:10:15 -08:00
										 |  |  | safe_syscall_end: | 
					
						
							| 
									
										
										
										
											2021-11-23 11:44:55 +01:00
										 |  |  |         /* code path for having successfully executed the syscall */ | 
					
						
							| 
									
										
										
										
											2021-11-15 14:08:52 +01:00
										 |  |  |         li      t2, -4096 | 
					
						
							|  |  |  |         bgtu    a0, t2, 0f | 
					
						
							| 
									
										
										
										
											2021-11-23 11:44:55 +01:00
										 |  |  |         ret | 
					
						
							| 
									
										
										
										
											2018-12-20 12:10:15 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-15 14:08:52 +01:00
										 |  |  |         /* code path setting errno */ | 
					
						
							|  |  |  | 0:      neg     a0, a0 | 
					
						
							|  |  |  |         j       safe_syscall_set_errno_tail | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-23 11:44:55 +01:00
										 |  |  |         /* code path when we didn't execute the syscall */ | 
					
						
							| 
									
										
										
										
											2021-11-22 19:47:33 +01:00
										 |  |  | 2:      li      a0, QEMU_ERESTARTSYS | 
					
						
							| 
									
										
										
										
											2021-11-15 14:08:52 +01:00
										 |  |  |         j       safe_syscall_set_errno_tail | 
					
						
							| 
									
										
										
										
											2018-12-20 12:10:15 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-15 14:08:52 +01:00
										 |  |  |         .cfi_endproc | 
					
						
							| 
									
										
										
										
											2021-11-23 11:44:55 +01:00
										 |  |  |         .size   safe_syscall_base, .-safe_syscall_base |