1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright 2014 Sony Mobile Communications Inc.
4  *
5  * Selftest for runtime system size
6  *
7  * Prints the amount of RAM that the currently running system is using.
8  *
9  * This program tries to be as small as possible itself, to
10  * avoid perturbing the system memory utilization with its
11  * own execution.  It also attempts to have as few dependencies
12  * on kernel features as possible.
13  *
14  * It should be statically linked, with startup libs avoided.  It uses
15  * no library calls except the syscall() function for the following 3
16  * syscalls:
17  *   sysinfo(), write(), and _exit()
18  *
19  * For output, it avoids printf (which in some C libraries
20  * has large external dependencies) by  implementing it's own
21  * number output and print routines, and using __builtin_strlen()
22  *
23  * The test may crash if any of the above syscalls fails because in some
24  * libc implementations (e.g. the GNU C Library) errno is saved in
25  * thread-local storage, which does not get initialized due to avoiding
26  * startup libs.
27  */
28 
29 #include <sys/sysinfo.h>
30 #include <unistd.h>
31 #include <sys/syscall.h>
32 
33 #define STDOUT_FILENO 1
34 
print(const char * s)35 static int print(const char *s)
36 {
37 	size_t len = 0;
38 
39 	while (s[len] != '\0')
40 		len++;
41 
42 	return syscall(SYS_write, STDOUT_FILENO, s, len);
43 }
44 
num_to_str(unsigned long num,char * buf,int len)45 static inline char *num_to_str(unsigned long num, char *buf, int len)
46 {
47 	unsigned int digit;
48 
49 	/* put digits in buffer from back to front */
50 	buf += len - 1;
51 	*buf = 0;
52 	do {
53 		digit = num % 10;
54 		*(--buf) = digit + '0';
55 		num /= 10;
56 	} while (num > 0);
57 
58 	return buf;
59 }
60 
print_num(unsigned long num)61 static int print_num(unsigned long num)
62 {
63 	char num_buf[30];
64 
65 	return print(num_to_str(num, num_buf, sizeof(num_buf)));
66 }
67 
print_k_value(const char * s,unsigned long num,unsigned long units)68 static int print_k_value(const char *s, unsigned long num, unsigned long units)
69 {
70 	unsigned long long temp;
71 	int ccode;
72 
73 	print(s);
74 
75 	temp = num;
76 	temp = (temp * units)/1024;
77 	num = temp;
78 	ccode = print_num(num);
79 	print("\n");
80 	return ccode;
81 }
82 
83 /* this program has no main(), as startup libraries are not used */
_start(void)84 void _start(void)
85 {
86 	int ccode;
87 	struct sysinfo info;
88 	unsigned long used;
89 	static const char *test_name = " get runtime memory use\n";
90 
91 	print("TAP version 13\n");
92 	print("# Testing system size.\n");
93 
94 	ccode = syscall(SYS_sysinfo, &info);
95 	if (ccode < 0) {
96 		print("not ok 1");
97 		print(test_name);
98 		print(" ---\n reason: \"could not get sysinfo\"\n ...\n");
99 		syscall(SYS_exit, ccode);
100 	}
101 	print("ok 1");
102 	print(test_name);
103 
104 	/* ignore cache complexities for now */
105 	used = info.totalram - info.freeram - info.bufferram;
106 	print("# System runtime memory report (units in Kilobytes):\n");
107 	print(" ---\n");
108 	print_k_value(" Total:  ", info.totalram, info.mem_unit);
109 	print_k_value(" Free:   ", info.freeram, info.mem_unit);
110 	print_k_value(" Buffer: ", info.bufferram, info.mem_unit);
111 	print_k_value(" In use: ", used, info.mem_unit);
112 	print(" ...\n");
113 	print("1..1\n");
114 
115 	syscall(SYS_exit, 0);
116 }
117