This source file includes following definitions.
- sim_hrline
- is_jailed
- is_static_linked_selfelf
- is_static_linked_selfmap
- is_static_linked
- is_ntp_sync
- has_linux_capability
- check_cpu_frequencies
- is_raspberry_pi
- check_pi_issues
- check_scaling_governors
- atm_cwords
- processIsTranslated
- show_hints
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include "sim_defs.h"
20
21 #include <ctype.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <limits.h>
26 #include <stdatomic.h>
27 #include <stdbool.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/stat.h>
33 #if !defined(_WIN32)
34 # include <sys/resource.h>
35 #endif
36 #include <time.h>
37 #include <sys/time.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40 #if defined(__APPLE__)
41 # include <sys/sysctl.h>
42 #endif
43 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || \
44 defined(__illumos__) || defined(__linux__) && !defined(__ANDROID__)
45 # include <sys/timex.h>
46 #endif
47 #if defined(__FreeBSD__) || defined(__DragonFly__)
48 # include <sys/sysctl.h>
49 #endif
50
51 #include "linehistory.h"
52
53 #include "../dps8/dps8.h"
54 #include "../dps8/dps8_cpu.h"
55 #include "../dps8/dps8_topo.h"
56
57 #include "../simh/sim_os_mem.h"
58 #include "../simh/scp.h"
59
60
61
62
63
64
65 #include "../dps8/dps8_sir.h"
66
67 #if !defined(HAS_INCLUDE)
68 # if defined __has_include
69 # define HAS_INCLUDE(inc) __has_include(inc)
70 # else
71 # define HAS_INCLUDE(inc) 0
72 # endif
73 #endif
74
75 #if defined(__linux__)
76 # if HAS_INCLUDE(<linux/capability.h>)
77 # include <linux/capability.h>
78 # endif
79 # if !defined(CAP_SYS_NICE)
80 # define CAP_SYS_NICE 23
81 # endif
82 # if !defined(CAP_IPC_LOCK)
83 # define CAP_IPC_LOCK 14
84 # endif
85 #endif
86
87 #if !defined(__APPLE__)
88 # if HAS_INCLUDE(<elf.h>)
89 # include <elf.h>
90 # endif
91 #endif
92
93 #undef USE_ELF_H
94 #if defined(EI_MAG0) && defined(EI_MAG1) && defined(EI_MAG2) && defined(EI_MAG3) && \
95 defined(ELFMAG0) && defined(ELFMAG1) && defined(ELFMAG2) && defined(ELFMAG3) && \
96 defined(PT_DYNAMIC) && !defined(_WIN32)
97 # if defined(USHRT_MAX)
98 # define MAX_HEADERS USHRT_MAX
99 # else
100 # define MAX_HEADERS 65535
101 # endif
102 # define USE_ELF_H
103 #endif
104
105 #if !defined(_WIN32)
106 # include <sys/mman.h>
107 #endif
108
109 #undef PROC_SELF
110 #if defined(__linux__) || defined(__serenity__)
111 # define PROC_SELF "/proc/self/exe"
112 #elif defined(__NetBSD__)
113 # define PROC_SELF "/proc/curproc/exe"
114 #elif defined(__FreeBSD__) || defined(__DragonFly__)
115 # define PROC_SELF "/proc/curproc/file"
116 #elif defined(__sun) || defined(__illumos__)
117 # define PROC_SELF "/proc/self/path/a.out"
118 #endif
119
120 #if defined(__managarm__)
121 # if !defined(FORCE_STATIC)
122 # define FORCE_STATIC
123 # endif
124 #endif
125
126 #if !defined(CHAR_BIT)
127 # define CHAR_BIT 8
128 #endif
129
130 unsigned int hint_count = 0;
131
132
133
134 static inline void
135 sim_hrline(void)
136 {
137 sim_printf("\r\n------------------------------------------------------------------------------\r\n");
138 }
139
140
141
142 static int
143 is_jailed(void)
144 {
145 int jailed = 0;
146 size_t len = sizeof(jailed);
147
148 #if defined(__FreeBSD__) || defined(__DragonFly__)
149 if (-1 == sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0))
150 return false;
151 #endif
152
153 (void)len;
154
155 if (jailed)
156 return true;
157
158 return false;
159 }
160
161
162
163 #if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW64) && !defined(CROSS_MINGW32) && !defined(FORCE_STATIC)
164 static int
165 is_static_linked_selfelf(void)
166 {
167 # if !defined(USE_ELF_H)
168 return -1;
169 # elif defined(__APPLE__)
170 return -1;
171 # else
172 char *self_exe;
173
174 # ifdef PROC_SELF
175 self_exe = PROC_SELF;
176 # else
177 self_exe = sim_appfilename;
178 # endif
179
180 int fd = open(self_exe, O_RDONLY);
181
182 if (fd < 0) {
183 self_exe = sim_appfilename;
184 fd = open(self_exe, O_RDONLY);
185 if (fd < 0)
186 return -1;
187 }
188
189 struct stat st;
190 if (fstat(fd, &st) < 0) {
191 (void)close(fd);
192 return -1;
193 }
194
195 void *map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
196 if (MAP_FAILED == map) {
197 (void)close(fd);
198 return -1;
199 }
200
201 Elf64_Ehdr *ehdr = (Elf64_Ehdr *)map;
202
203 if (ELFMAG0 != ehdr->e_ident[EI_MAG0] ||
204 ELFMAG1 != ehdr->e_ident[EI_MAG1] ||
205 ELFMAG2 != ehdr->e_ident[EI_MAG2] ||
206 ELFMAG3 != ehdr->e_ident[EI_MAG3]) {
207 (void)munmap(map, st.st_size);
208 (void)close(fd);
209 return -1;
210 }
211
212 Elf64_Phdr *phdr;
213 void *phdr_address = (void *)((char *)map + ehdr->e_phoff);
214 (void)memcpy(&phdr, &phdr_address, sizeof(phdr));
215
216 if (0 == ehdr->e_phnum || ehdr->e_phnum > MAX_HEADERS) {
217 (void)munmap(map, st.st_size);
218 (void)close(fd);
219 return -1;
220 }
221
222 for (unsigned int i = 0; i < ehdr->e_phnum; i++)
223 if (PT_DYNAMIC == phdr[i].p_type) {
224 (void)munmap(map, st.st_size);
225 (void)close(fd);
226 return 0;
227 }
228
229 (void)munmap(map, st.st_size);
230 (void)close(fd);
231 return 1;
232 # endif
233 }
234 #endif
235
236
237
238 #if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW64) && !defined(CROSS_MINGW32) && !defined(FORCE_STATIC)
239 static int
240 is_static_linked_selfmap (void)
241 {
242 FILE *maps = fopen ("/proc/self/maps", "r");
243
244 if (!maps)
245 return -1;
246
247 char line[256];
248 while (fgets (line, sizeof (line), maps))
249 if (strstr(line, "/ld-") ||
250 strstr(line, "/system/bin/linker") ||
251 strstr(line, "/lib/ld")) {
252 (void)fclose (maps);
253 return 0;
254 }
255
256 (void)fclose (maps);
257 return 1;
258 }
259 #endif
260
261
262
263 #if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW64) && !defined(CROSS_MINGW32) && !defined(FORCE_STATIC)
264 static int
265 is_static_linked (void)
266 {
267 int map = is_static_linked_selfmap ();
268 int elf = is_static_linked_selfelf ();
269
270 # if defined(STATIC_TESTING)
271 (void)fprintf(stderr, "is_static_linked_selfmap=%d\r\n", map);
272 (void)fprintf(stderr, "is_static_linked_selfelf=%d\r\n", elf);
273 # endif
274
275 if (-1 == map && -1 == elf)
276 return -1;
277
278 if (-1 == map)
279 return elf;
280
281 if (-1 == elf)
282 return map;
283
284 if (map != elf)
285 return -1;
286
287 return map;
288 }
289 #endif
290
291
292
293 static int
294 is_ntp_sync (void)
295 {
296 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || \
297 defined(__illumos__) || defined(__linux__) && !defined(__ANDROID__)
298 struct timex tx = { 0 };
299 # if defined(__FreeBSD__) || defined(__NetBSD__) || \
300 defined(__sun) || defined(__illumos__)
301 int result = ntp_adjtime (&tx);
302 # else
303 int result = adjtimex (&tx);
304 # endif
305 if (-1 == result)
306 return -1;
307 # if defined(__sun) || defined(__illumos__)
308 if (tx.status & STA_UNSYNC)
309 # else
310 if (TIME_OK != result)
311 # endif
312 if (1000000 >= tx.maxerror)
313 return 1;
314 else
315 return 0;
316 else
317 return 2;
318 #else
319 return -1;
320 #endif
321 }
322
323
324
325 #if defined(__linux__) && !defined(__ANDROID__)
326 static int
327 has_linux_capability(const pid_t pid, const int capability)
328 {
329 char filename[SIR_MAXPATH];
330 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
331
332 FILE *file = fopen(filename, "r");
333 if (!file)
334 return -1;
335
336 char line[1024];
337 uint64_t cap_eff = 0;
338
339 while (fgets(line, sizeof(line), file))
340 if (1 == sscanf(line, "CapEff: %llx", (long long unsigned int*)&cap_eff))
341 break;
342
343 fclose(file);
344
345 return 0 != (cap_eff & (1ULL << capability));
346 }
347 #endif
348
349
350
351 static int
352 check_cpu_frequencies (void)
353 {
354 #if !defined(__linux__)
355 return 0;
356 #else
357 struct dirent *entry;
358 char path[SIR_MAXPATH];
359 FILE *file;
360 int min_freq = 0, max_freq = 0;
361 int mismatch = 0;
362
363 DIR *dir = opendir ("/sys/devices/system/cpu");
364
365 if (!dir)
366 return 0;
367
368 while ((entry = readdir (dir)) != NULL) {
369 if (DT_DIR == entry->d_type && 0 == strncmp (entry->d_name, "cpu", 3)
370 && isdigit (entry->d_name[3])) {
371 snprintf (path, sizeof (path), "/sys/devices/system/cpu/%s/cpufreq/cpuinfo_min_freq",
372 entry->d_name);
373 file = fopen (path, "r");
374 if (file) {
375 if (1 != fscanf (file, "%d", &min_freq)) {
376 fclose (file);
377 min_freq = -1;
378 } else {
379 fclose (file);
380 }
381 }
382 snprintf (path, sizeof (path), "/sys/devices/system/cpu/%s/cpufreq/cpuinfo_max_freq",
383 entry->d_name);
384 file = fopen (path, "r");
385 if (file) {
386 if (1 != fscanf (file, "%d", &max_freq)) {
387 fclose (file);
388 max_freq = -1;
389 } else {
390 fclose (file);
391 }
392 }
393 if (-1 != min_freq && -1 != max_freq && min_freq != max_freq) {
394 mismatch = 1;
395 }
396 }
397 }
398 closedir (dir);
399
400 if (mismatch) {
401 return 1;
402 } else {
403 return 0;
404 }
405 #endif
406 }
407
408
409
410 #define RPI_TEXT "Raspberry Pi"
411
412 static int
413 is_raspberry_pi (void)
414 {
415 FILE *file;
416 char line[1024];
417 int is_pi = 0;
418
419 file = fopen("/proc/device-tree/model", "r");
420 if (file) {
421 if (fgets(line, sizeof(line), file) && strstr(line, RPI_TEXT))
422 is_pi = 1;
423 fclose(file);
424 if (is_pi)
425 return 1;
426 }
427
428 file = fopen("/proc/cpuinfo", "r");
429 if (!file)
430 return 0;
431
432 while (fgets(line, sizeof(line), file)) {
433 if (strncmp(line, "Model", 5) == 0 && strstr(line, RPI_TEXT)) {
434 is_pi = 1;
435 break;
436 }
437 }
438 fclose(file);
439
440 return is_pi;
441 }
442
443
444
445 static uint32_t
446 check_pi_issues (void)
447 {
448 uint32_t a_issues = 0;
449
450 FILE *fp = popen("vcgencmd get_throttled 2> /dev/null", "r");
451 if (!fp)
452 return a_issues;
453
454 char buffer[1024];
455 if (NULL == fgets(buffer, sizeof(buffer), fp)) {
456 pclose(fp);
457 return a_issues;
458 }
459 pclose(fp);
460
461 char *p = strstr(buffer, "0x");
462 if (!p)
463 return a_issues;
464
465 uint32_t throttle = (uint32_t)strtoul(p, NULL, 16);
466 uint32_t c_issues = throttle & 0xF;
467 uint32_t p_issues = (throttle >> 16) & 0xF;
468 a_issues = c_issues | p_issues;
469
470 return a_issues;
471 }
472
473
474
475 static uint32_t
476 check_scaling_governors (void)
477 {
478 #if !defined(__linux__)
479 return 0;
480 #else
481 struct dirent *entry;
482 char path[SIR_MAXPATH];
483 FILE *file;
484 char governor[256];
485 static uint32_t bad_govs;
486
487 DIR *dir = opendir ("/sys/devices/system/cpu");
488
489 if (!dir)
490 return 0;
491
492 bad_govs = 0;
493 while ((entry = readdir (dir)) != NULL) {
494 if (DT_DIR == entry->d_type && 0 == strncmp (entry->d_name, "cpu", 3)
495 && isdigit (entry->d_name[3])) {
496 snprintf (path, sizeof (path), "/sys/devices/system/cpu/%s/cpufreq/scaling_governor",
497 entry->d_name);
498 file = fopen (path, "r");
499 if (file) {
500 if (fgets (governor, sizeof (governor), file)) {
501 governor[strcspn (governor, "\n")] = '\0';
502 if ( 0 == strcmp (governor, "powersave" )
503 || 0 == strcmp (governor, "conservative") ) {
504 bad_govs++;
505 }
506 }
507 fclose (file);
508 }
509 }
510 }
511 closedir (dir);
512
513 return bad_govs;
514 #endif
515 }
516
517
518
519 const char *
520 atm_cwords (int count)
521 {
522 static const char *words[] = { "Zero", "One", "Two", "Three", "Four", "Five", "Six" };
523 static char buffer[20];
524
525 if (count >= 0 && count <= 6) {
526 return words[count];
527 } else {
528 snprintf (buffer, sizeof (buffer), "%d", count);
529 return buffer;
530 }
531 }
532
533
534
535 #if defined(__APPLE__)
536 static int
537 processIsTranslated (void)
538 {
539 int ret = 0;
540 size_t size = sizeof(ret);
541 if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
542 if (errno == ENOENT)
543 return 0;
544 return -1;
545 }
546 return ret;
547 }
548 #endif
549
550
551
552 t_stat
553 show_hints (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
554 {
555
556
557 hint_count = 0;
558
559
560
561
562 if (64 > (sizeof (time_t) * CHAR_BIT)) {
563 if (!flag) {
564 sim_hrline ();
565 sim_printf ("\r\n* Hint #%u - LESS THAN 64-BIT TIME REPRESENTATION DETECTED\r\n", ++hint_count);
566 sim_printf ("\r\n");
567 sim_printf (" The simulator has detected timekeeping using a %ld-bit representation.\r\n",
568 (long)(sizeof (time_t) * CHAR_BIT));
569 } else {
570 ++hint_count;
571 }
572 }
573
574
575
576
577 #if !defined(__HAIKU__) && !defined(_WIN32)
578 if (0 == geteuid ()) {
579 if (!flag) {
580 sim_hrline ();
581 sim_printf ("\r\n* Hint #%u - SIMULATOR RUNNING AS ROOT OR SUPERUSER DETECTED\r\n", ++hint_count);
582 sim_printf ("\r\n");
583 sim_printf (" You are running the simulator as `root` (or equivalent superuser).\r\n");
584 sim_printf ("\r\n");
585 sim_printf (" We highly recommend running the simulator as a non-privileged user.\r\n");
586 } else {
587 ++hint_count;
588 }
589 }
590 #endif
591
592
593
594
595 #if defined(TESTING)
596 if (!flag) {
597 sim_hrline ();
598 sim_printf ("\r\n* Hint #%u - TESTING BUILD DETECTED\r\n", ++hint_count);
599 sim_printf ("\r\n");
600 sim_printf (" You are running a TESTING build.\r\n");
601 sim_printf ("\r\n");
602 sim_printf (" TESTING builds intended strictly for development purposes.\r\n");
603 sim_printf ("\r\n");
604 sim_printf (" Reliability, stability, and performance will be adversely impacted.\r\n");
605 } else {
606 ++hint_count;
607 }
608 #endif
609
610
611
612
613 #if defined(WITH_ABSI_DEV) || defined(WITH_MGP_DEV)
614 if (!flag) {
615 sim_hrline ();
616 sim_printf ("\r\n* Hint #%u - UNSUPPORTED OR EXPERIMENTAL BUILD OPTIONS DETECTED\r\n", ++hint_count);
617 sim_printf ("\r\n");
618 sim_printf (" You are running a build with unsupported or experimental options enabled:\r\n");
619 sim_printf ("\r\n");
620 # if defined(WITH_ABSI_DEV)
621 sim_printf (" * WITH_ABSI_DEV is enabled.\r\n");
622 # endif
623 # if defined(WITH_MGP_DEV)
624 sim_printf (" * WITH_MGP_DEV is enabled.\r\n");
625 # endif
626 sim_printf ("\r\n");
627 sim_printf (" Reliability, stability, and performance will be adversely impacted.\r\n");
628 } else {
629 ++hint_count;
630 }
631 #endif
632
633
634
635
636 #if defined(__CYGWIN__)
637 if (!flag) {
638 sim_hrline ();
639 sim_printf ("\r\n* Hint #%u - CYGWIN WINDOWS BUILD DETECTED\r\n", ++hint_count);
640 sim_printf ("\r\n");
641 sim_printf (" You are using a Cygwin Windows build.\r\n");
642 sim_printf ("\r\n");
643 sim_printf (" The simulator supports native Windows builds (using the MinGW toolchain).\r\n");
644 sim_printf (" Unless you have a specific reason for using a Cygwin build, we recommend\r\n");
645 sim_printf (" using a native build instead, which has better performance for most users.\r\n");
646 } else {
647 ++hint_count;
648 }
649 #endif
650
651
652
653
654 if (check_scaling_governors ()) {
655 if (!flag) {
656 unsigned long long reduced = (unsigned long long)check_scaling_governors();
657 unsigned long long total = (unsigned long long)nprocs;
658 sim_hrline ();
659 sim_printf ("\r\n* Hint #%u - POWER-SAVING CPU GOVERNOR CONFIGURATION DETECTED\r\n", ++hint_count);
660 sim_printf ("\r\n");
661 if (total > reduced)
662 sim_printf(" You have %llu (out of %llu) processors using a power-saving governor.\r\n",
663 reduced, total);
664 else
665 sim_printf(" You have %llu logical processors configured using a power-saving governor.\r\n",
666 reduced);
667 } else {
668 ++hint_count;
669 }
670 }
671
672
673
674
675 #if defined(LOCKLESS)
676 if (nprocs < 2 && ncores < 2) {
677 if (!flag) {
678 sim_hrline ();
679 sim_printf ("\r\n* Hint #%u - UNIPROCESSOR HOST SYSTEM DETECTED\r\n", ++hint_count);
680 sim_printf ("\r\n");
681 sim_printf (" You seem to be running the simulator on a uniprocessor host system.\r\n");
682 sim_printf ("\r\n");
683 sim_printf (" The simulator supports a single-threaded build option (`NO_LOCKLESS`)\r\n");
684 sim_printf (" which may perform better on uniprocessor systems such as this one.\r\n");
685 } else {
686 ++hint_count;
687 }
688 }
689 #endif
690
691
692
693
694 #if defined(HAVE_LINEHISTORY) && !defined(_WIN32)
695 const char *term = getenv ("TERM");
696 if (NULL == term || 0 == strcmp (term, "dumb") || 0 == strcmp (term, "") || 0 == strcmp (term, "cons25")) {
697 if (!flag) {
698 sim_hrline ();
699 sim_printf ("\r\n* Hint #%u - TERM ENVIRONMENT VARIABLE SET TO UNSUPPORTED VALUE\r\n", ++hint_count);
700 sim_printf ("\r\n");
701 sim_printf (" The TERM environment variable is unset (or is set to an unsupported value).\r\n");
702 sim_printf ("\r\n");
703 sim_printf (" This disables the line-editing and history recall functionality of the\r\n");
704 sim_printf (" simulator shell. This is usually an unintentional misconfiguration.\r\n");
705 } else {
706 ++hint_count;
707 }
708 }
709 #endif
710
711
712
713
714 #if !defined(_WIN32) && !defined(__HAIKU__)
715 struct rlimit core_limit;
716 if (getrlimit(RLIMIT_CORE, &core_limit) == 0) {
717 if (core_limit.rlim_cur == 0) {
718 if (!flag) {
719 sim_hrline();
720 sim_printf("\r\n* Hint #%u - CORE DUMPS ARE DISABLED\r\n", ++hint_count);
721 sim_printf("\r\n");
722 sim_printf(" Core dumps are disabled. If the simulator crashes, it will not be able\r\n");
723 sim_printf(" to produce a core file, which can help determine the cause of the crash.\r\n");
724 sim_printf("\r\n");
725 sim_printf(" Try setting `ulimit -c unlimited` (or sometimes `ulimit -Hc unlimited`)\r\n");
726 sim_printf(" in your shell to remove this restriction.\r\n");
727 } else {
728 ++hint_count;
729 }
730 }
731 else if (core_limit.rlim_cur != RLIM_INFINITY) {
732 if (!flag) {
733 sim_hrline();
734 sim_printf("\r\n* Hint #%u - CORE DUMPS ARE RESTRICTED\r\n", ++hint_count);
735 sim_printf("\r\n");
736 sim_printf(" Core dumps are restricted. If the simulator crashes, it may not be able\r\n");
737 sim_printf(" to produce a core file, which can help determine the cause of the crash.\r\n");
738 sim_printf("\r\n");
739 sim_printf(" Your configuration is currently restricting core dumps to %llu KB.\r\n",
740 (unsigned long long)core_limit.rlim_cur / 1024);
741 sim_printf("\r\n");
742 sim_printf(" Try setting `ulimit -c unlimited` (or sometimes `ulimit -Hc unlimited`)\r\n");
743 sim_printf(" in your shell to remove this restriction.\r\n");
744 } else {
745 ++hint_count;
746 }
747 }
748 }
749 #endif
750
751
752
753
754 if (is_raspberry_pi ()) {
755 uint32_t a_issues;
756 if (check_cpu_frequencies()) {
757 if (!flag) {
758 sim_hrline ();
759 sim_printf ("\r\n* Hint #%u - RASPBERRY PI FIXED FREQUENCY CONFIGURATION\r\n", ++hint_count);
760 sim_printf ("\r\n");
761 sim_printf (" The simulator has detected it is running on a Raspberry Pi single-board\r\n");
762 sim_printf (" computer, which is not configured for fixed frequency operation.\r\n");
763 sim_printf (" Using a fixed-frequency configuration allows for more deterministic\r\n");
764 sim_printf (" response times and enhances performance and simulation fidelity.\r\n");
765 sim_printf ("\r\n");
766 sim_printf (" Use `cpupower frequency-info` (from the `linux-cpupower` package) to view\r\n");
767 sim_printf (" the current configuration, or `sudo cpupower frequency-set -f` to change\r\n");
768 sim_printf (" it, for example, `sudo cpupower frequency-set -f 1200Mhz`. Refer to the\r\n");
769 sim_printf (" documentation for your specific Raspberry Pi model for proper values.\r\n");
770 } else {
771 ++hint_count;
772 }
773 }
774 a_issues = check_pi_issues ();
775 if ( a_issues & (1 << 0) ||
776 #if defined(RPI_CAPPING)
777 a_issues & (1 << 1) ||
778 #endif
779 a_issues & (1 << 2) ||
780 a_issues & (1 << 3) ) {
781 if (!flag) {
782 sim_hrline ();
783 sim_printf ("\r\n* Hint #%u - RASPBERRY PI ADVERSE HARDWARE EVENTS RECORDED\r\n", ++hint_count);
784 sim_printf ("\r\n");
785 sim_printf (" Your Raspberry Pi has recorded the following adverse hardware event(s):\r\n");
786 sim_printf ("\r\n");
787 if (a_issues & (1 << 0))
788 sim_printf(" * Undervoltage events have occurred since boot.\r\n");
789 #if defined(RPI_CAPPING)
790 if (a_issues & (1 << 1))
791 sim_printf(" * CPU frequency capping events have occurred since boot.\r\n");
792 #endif
793 if (a_issues & (1 << 2))
794 sim_printf(" * Throttling events have occurred since boot.\r\n");
795 if (a_issues & (1 << 3))
796 sim_printf(" * Soft temperature limits have been reached or exceeded since boot.\r\n");
797 } else {
798 ++hint_count;
799 }
800 }
801 }
802
803
804
805
806 #if !defined(_WIN32) && !defined(FORCE_STATIC)
807 if (1 < nprocs && false == dps8_topo_used && 1 != is_static_linked()) {
808 if (!flag) {
809 sim_hrline ();
810 sim_printf ("\r\n* Hint #%u - UNABLE TO DETERMINE SYSTEM TOPOLOGY USING LIBHWLOC\r\n", ++hint_count);
811 sim_printf ("\r\n");
812 sim_printf (" No overall topology information could be determined for this system.\r\n");
813 sim_printf (" The simulator is aware this system has %llu logical processors available,\r\n",
814 (unsigned long long)nprocs);
815 sim_printf (" but it was not able to determine the number of actual physical cores.\r\n");
816 sim_printf ("\r\n");
817 sim_printf (" The simulator uses topology information to optimize performance and\r\n");
818 sim_printf (" to warn about potentially dangerous or suboptimal configurations.\r\n");
819 sim_printf (" We use libhwloc (https://www-lb.open-mpi.org/projects/hwloc/) to query\r\n");
820 sim_printf (" this information in an architecture and operating system agnostic way.\r\n");
821 # if defined(__APPLE__)
822 sim_printf ("\r\n");
823 sim_printf (" On macOS, you can install the libhwloc library using the Homebrew\r\n");
824 sim_printf (" package manager (https://brew.sh/) by running `brew install hwloc`.\r\n");
825 # elif defined(__FreeBSD__)
826 sim_printf ("\r\n");
827 sim_printf (" On FreeBSD, you can install the hwloc from packages (`pkg install hwloc`)\r\n");
828 sim_printf (" or build from ports (`cd /usr/ports/devel/hwloc/ && make install clean`).\r\n");
829 # elif defined(__linux__)
830 sim_printf ("\r\n");
831 sim_printf (" Linux distributions usually provide this library as the `hwloc` package.\r\n");
832 # endif
833 sim_printf ("\r\n");
834 sim_printf (" No recompilation of the simulator is necessary for it to use libhwloc.\r\n");
835 } else {
836 ++hint_count;
837 }
838 }
839 #endif
840
841
842
843
844 #if defined(__linux__) && defined(CAP_SYS_NICE) && !defined(__ANDROID__)
845 const pid_t pid = _sir_getpid();
846 const int cap_sys_nice = CAP_SYS_NICE;
847
848 if (nprocs > 1 && !has_linux_capability(pid, cap_sys_nice)) {
849 if (!flag) {
850 sim_hrline ();
851 sim_printf ("\r\n* Hint #%u - LINUX REAL-TIME SCHEDULING CAPABILITY IS NOT ENABLED\r\n", ++hint_count);
852 sim_printf ("\r\n");
853 sim_printf (" Linux real-time scheduling capability is not enabled.\r\n");
854 sim_printf (" Real-time support allows for accurate and deterministic response times\r\n");
855 sim_printf (" and improved thread scheduling behavior, enhancing simulation fidelity.\r\n");
856 if (nprocs > 2) {
857 if ((unsigned long long)ncores > 1 && (unsigned long long)ncores != (unsigned long long)nprocs) {
858 sim_printf(" Since this system seems to have %llu logical (and %llu physical) processors,\r\n",
859 (unsigned long long)nprocs, (unsigned long long)ncores);
860 } else {
861 sim_printf(" Since this system seems to have at least %llu logical processors available,\r\n",
862 (unsigned long long)nprocs);
863 }
864 sim_printf (" the real-time mode (requested by the `-p` argument) may be considered.\r\n");
865 }
866 sim_printf ("\r\n");
867 sim_printf (" To enable the real-time capability, run the following shell command:\r\n");
868 sim_printf ("\r\n");
869 sim_printf (" sudo setcap 'cap_sys_nice,cap_ipc_lock+ep' %s\r\n", sim_appfilename);
870 } else {
871 ++hint_count;
872 }
873 }
874 #endif
875
876
877
878
879 #if !defined(__ANDROID__)
880 if (true == mlock_failure) {
881 if (!flag) {
882 sim_hrline ();
883 sim_printf ("\r\n* Hint #%u - UNABLE TO LOCK SIMULATOR MEMORY WITH MLOCK()\r\n", ++hint_count);
884 sim_printf ("\r\n");
885 sim_printf (" The simulator attempted, but failed, to use memory locking with mlock().\r\n");
886 sim_printf (" Memory locking prevents the simulated memory from being swapped out to\r\n");
887 sim_printf (" disk. This avoids page faults and enables more deterministic performance.\r\n");
888 sim_printf (" Memory locking also enhances response times for real-time mode operation.\r\n");
889 # if defined(__linux__) && defined(CAP_IPC_LOCK)
890 const pid_t pid = _sir_getpid();
891 const int cap_ipc_lock = CAP_IPC_LOCK;
892 if (!has_linux_capability(pid, cap_ipc_lock)) {
893 sim_printf ("\r\n");
894 sim_printf (" You can enable real-time and memory locking by running this shell command:\r\n");
895 sim_printf ("\r\n");
896 sim_printf (" sudo setcap 'cap_sys_nice,cap_ipc_lock+ep' %s\r\n", sim_appfilename);
897 }
898 # elif defined(__FreeBSD__)
899 sim_printf ("\r\n");
900 sim_printf (" See https://man.freebsd.org/cgi/man.cgi?login.conf(5) for details.\r\n");
901 # elif defined(__sun) || defined(__illumos__)
902 sim_printf ("\r\n");
903 sim_printf (" You can allow memory locking by running the following shell commands:\r\n");
904 sim_printf ("\r\n");
905 sim_printf (" sudo chown root:root %s\r\n", sim_appfilename);
906 sim_printf (" sudo chmod u+s %s\r\n", sim_appfilename);
907 sim_printf ("\r\n");
908 sim_printf (" This is safe - we drop all unnecessary privileges immediately at start-up.\r\n");
909 # else
910 sim_printf("\r\n");
911 sim_printf(" You can check `ulimit -l` in your shell to verify locking is unrestricted.\r\n");
912 # endif
913 } else {
914 ++hint_count;
915 }
916 }
917 #endif
918
919
920
921
922 #if defined(LOCKLESS) && !defined(__SUNPRO_C) && !defined(__SUNPRO_CC)
923 # define CHECK_LOCK_FREE(var, type_name, counter, names, index) \
924 do { \
925 if (!atomic_is_lock_free (&var)) { \
926 names[index] = type_name; \
927 index++; \
928 counter++; \
929 } \
930 } while (0)
931
932 atomic_uint_fast32_t af32_t = 0;
933 atomic_size_t asize_t = 0;
934 atomic_bool abool = 0;
935 atomic_int aint = 0;
936 atomic_long along = 0;
937 int *naptr;
938 atomic_uintptr_t aptr;
939
940 atomic_init (&aptr, (uintptr_t)&naptr);
941 (void)naptr;
942
943 const char *non_lock_free_names[6];
944 int non_lock_free_count = 0;
945 int index = 0;
946
947 CHECK_LOCK_FREE (af32_t, "atomic_uint_fast32_t",
948 non_lock_free_count, non_lock_free_names, index);
949 CHECK_LOCK_FREE (asize_t, "atomic_size_t",
950 non_lock_free_count, non_lock_free_names, index);
951 CHECK_LOCK_FREE (abool, "atomic_bool",
952 non_lock_free_count, non_lock_free_names, index);
953 CHECK_LOCK_FREE (aint, "atomic_int",
954 non_lock_free_count, non_lock_free_names, index);
955 CHECK_LOCK_FREE (along, "atomic_long",
956 non_lock_free_count, non_lock_free_names, index);
957 CHECK_LOCK_FREE (aptr, "atomic_uintptr_t",
958 non_lock_free_count, non_lock_free_names, index);
959
960 if (non_lock_free_count > 0) {
961 if (!flag) {
962 const char *count_str = atm_cwords (non_lock_free_count);
963 sim_hrline ();
964 sim_printf ("\r\n* Hint #%u - ATOMIC TYPES DO NOT SUPPORT LOCK-FREE OPERATION\r\n", ++hint_count);
965 sim_printf ("\r\n %s atomic type%s %s not lock-free on this system:\r\n\r\n",
966 count_str, (non_lock_free_count == 1) ? "" : "s",
967 (non_lock_free_count == 1) ? "is" : "are");
968 for (unsigned int i = 0; i < non_lock_free_count; i++)
969 sim_printf (" * %s\r\n", non_lock_free_names[i]);
970 sim_printf ("\r\n");
971 sim_printf (" Atomic operations are lock-free only if the CPU provides the appropriate\r\n");
972 sim_printf (" instructions and your compiler knows how to take advantage of them.\r\n");
973 sim_printf ("\r\n");
974 sim_printf (" You could try upgrading the compiler, but this is usually a hardware\r\n");
975 sim_printf (" limitation. When the CPU does not support atomic operations, they rely\r\n");
976 sim_printf (" on locking, which adversely impacts the performance of threaded programs.\r\n");
977 if (1 == nprocs) {
978 sim_printf ("\r\n");
979 sim_printf (" Since it seems this system only has a single processor, you should try\r\n");
980 sim_printf (" building the `NO_LOCKLESS` non-threaded simulator for better performance.\r\n");
981 }
982 } else {
983 ++hint_count;
984 }
985 }
986 #endif
987
988
989
990
991 #if defined(__APPLE__)
992 if (1 == processIsTranslated()) {
993 if (!flag) {
994 sim_hrline ();
995 sim_printf ("\r\n* Hint #%u - APPLE ROSETTA BINARY TRANSLATION DETECTED\r\n", ++hint_count);
996 sim_printf ("\r\n Rosetta is an x86_64 to ARM64 (Apple Silicon) binary translation process.\r\n");
997 sim_printf ("\r\n");
998 sim_printf (" This means that the simulator binary you are executing was not compiled\r\n");
999 sim_printf (" for the native architecture of your system. Although fully functional\r\n");
1000 sim_printf (" performance will be significantly reduced. It is highly recommended to\r\n");
1001 sim_printf (" use a native Apple Silicon (ARM64) build of the simulator.\r\n");
1002 } else {
1003 ++hint_count;
1004 }
1005 }
1006 #endif
1007
1008
1009
1010
1011 if (sim_free_memory < 192000000 && sim_free_memory > 0) {
1012 if (!flag) {
1013 sim_hrline ();
1014 sim_printf ("\r\n* Hint #%u - LOW SYSTEM MEMORY DETECTED\r\n", ++hint_count);
1015 sim_printf ("\r\n");
1016 sim_printf (" Currently %llu MB of memory is available (%llu MB at process start-up).\r\n",
1017 ((long long unsigned)sim_memory_available() / 1000000),
1018 ((long long unsigned)sim_free_memory / 1000000));
1019 sim_printf ("\r\n");
1020 sim_printf (" We recommend a minimum of 192 MB of available physical system memory\r\n");
1021 sim_printf (" for optimum simulator performance. Additionally, memory locking is not\r\n");
1022 sim_printf (" attempted when less than 192 MB of memory is available at start-up time.\r\n");
1023 } else {
1024 ++hint_count;
1025 }
1026 }
1027
1028
1029
1030
1031 if (0 == is_ntp_sync()) {
1032 if (!flag) {
1033 sim_hrline ();
1034 sim_printf ("\r\n* Hint #%u - NO EXTERNAL CLOCK SYNCHRONIZATION DETECTED\r\n", ++hint_count);
1035 sim_printf ("\r\n");
1036 sim_printf (" The system is reporting that your clock is NOT externally synchronized.\r\n");
1037 sim_printf (" Accurate time synchronization is critical for proper simulator operation.\r\n");
1038 sim_printf (" This can usually be resolved by ensuring that NTP (Network Time Protocol)\r\n");
1039 sim_printf (" software (e.g. ntpd, chrony, timesyncd, etc.) is installed and configured.\r\n");
1040 if (is_jailed()) {
1041 sim_printf ("\r\n");
1042 sim_printf (" NOTE: The simulator is running in a BSD jail. The time synchronization\r\n");
1043 sim_printf (" daemon must be installed and configured on the host, and not in the jail.\r\n");
1044 }
1045 } else {
1046 ++hint_count;
1047 }
1048 }
1049
1050
1051
1052
1053 if (hint_count) {
1054 if (!flag) {
1055 sim_hrline ();
1056 if (getenv("DPS8M_NO_HINTS") == NULL) {
1057 sim_printf ("\r\n");
1058 sim_printf ("To disable hint notifications, set the environment variable `DPS8M_NO_HINTS=1`\r\n");
1059 }
1060 sim_printf ("\r\n");
1061 } else {
1062 sim_printf("There %s %d %s available; use \"%s\" to view %s.\r\n\r\n",
1063 (hint_count == 1) ? "is" : "are", hint_count, (hint_count == 1) ? "hint" : "hints",
1064 (hint_count == 1) ? "SHOW HINT" : "SHOW HINTS", (hint_count == 1) ? "it" : "them");
1065 }
1066 } else {
1067 if (!flag) {
1068 sim_printf ("No hints are currently available.\r\n");
1069 }
1070 }
1071
1072 return 0;
1073 }