13539d84dSAlex Bennée /*
23539d84dSAlex Bennée * linux-user semihosting checks
33539d84dSAlex Bennée *
4*542b10bdSAlex Bennée * Copyright (c) 2019, 2024
53539d84dSAlex Bennée * Written by Alex Bennée <alex.bennee@linaro.org>
63539d84dSAlex Bennée *
7*542b10bdSAlex Bennée * SPDX-License-Identifier: GPL-2.0-or-later
83539d84dSAlex Bennée */
93539d84dSAlex Bennée
103539d84dSAlex Bennée #define SYS_WRITE0 0x04
114593f4d7SAlex Bennée #define SYS_HEAPINFO 0x16
123539d84dSAlex Bennée #define SYS_REPORTEXC 0x18
133539d84dSAlex Bennée
143539d84dSAlex Bennée #include <stdint.h>
154593f4d7SAlex Bennée #include <stdlib.h>
164593f4d7SAlex Bennée #include <stdio.h>
174593f4d7SAlex Bennée #include <string.h>
183539d84dSAlex Bennée #include "semicall.h"
193539d84dSAlex Bennée
main(int argc,char * argv[argc])203539d84dSAlex Bennée int main(int argc, char *argv[argc])
213539d84dSAlex Bennée {
223539d84dSAlex Bennée #if UINTPTR_MAX == UINT32_MAX
233539d84dSAlex Bennée uintptr_t exit_code = 0x20026;
243539d84dSAlex Bennée #else
253539d84dSAlex Bennée uintptr_t exit_block[2] = {0x20026, 0};
263539d84dSAlex Bennée uintptr_t exit_code = (uintptr_t) &exit_block;
273539d84dSAlex Bennée #endif
284593f4d7SAlex Bennée struct {
294593f4d7SAlex Bennée void *heap_base;
304593f4d7SAlex Bennée void *heap_limit;
314593f4d7SAlex Bennée void *stack_base;
324593f4d7SAlex Bennée void *stack_limit;
334593f4d7SAlex Bennée } info;
344593f4d7SAlex Bennée void *ptr_to_info = (void *) &info;
353539d84dSAlex Bennée
364593f4d7SAlex Bennée __semi_call(SYS_WRITE0, (uintptr_t) "Checking HeapInfo\n");
374593f4d7SAlex Bennée
384593f4d7SAlex Bennée memset(&info, 0, sizeof(info));
394593f4d7SAlex Bennée __semi_call(SYS_HEAPINFO, (uintptr_t) &ptr_to_info);
404593f4d7SAlex Bennée
414593f4d7SAlex Bennée if (info.heap_base == NULL || info.heap_limit == NULL) {
424593f4d7SAlex Bennée printf("null heap: %p -> %p\n", info.heap_base, info.heap_limit);
434593f4d7SAlex Bennée exit(1);
444593f4d7SAlex Bennée }
454593f4d7SAlex Bennée
464593f4d7SAlex Bennée /* Error if heap base is above limit */
474593f4d7SAlex Bennée if ((uintptr_t) info.heap_base >= (uintptr_t) info.heap_limit) {
484593f4d7SAlex Bennée printf("heap base %p >= heap_limit %p\n",
494593f4d7SAlex Bennée info.heap_base, info.heap_limit);
504593f4d7SAlex Bennée exit(2);
514593f4d7SAlex Bennée }
524593f4d7SAlex Bennée
534593f4d7SAlex Bennée if (info.stack_base == NULL || info.stack_limit) {
544593f4d7SAlex Bennée printf("null stack: %p -> %p\n", info.stack_base, info.stack_limit);
554593f4d7SAlex Bennée exit(3);
564593f4d7SAlex Bennée }
574593f4d7SAlex Bennée
584593f4d7SAlex Bennée /* check our local variables are indeed inside the reported stack */
594593f4d7SAlex Bennée if (ptr_to_info > info.stack_base) {
604593f4d7SAlex Bennée printf("info appears to be above stack: %p > %p\n", ptr_to_info,
614593f4d7SAlex Bennée info.stack_base);
624593f4d7SAlex Bennée exit(4);
634593f4d7SAlex Bennée } else if (ptr_to_info < info.stack_limit) {
644593f4d7SAlex Bennée printf("info appears to be outside stack: %p < %p\n", ptr_to_info,
654593f4d7SAlex Bennée info.stack_limit);
664593f4d7SAlex Bennée exit(5);
674593f4d7SAlex Bennée }
684593f4d7SAlex Bennée
694593f4d7SAlex Bennée if (ptr_to_info > info.heap_base && ptr_to_info < info.heap_limit) {
704593f4d7SAlex Bennée printf("info appears to be inside the heap: %p in %p:%p\n",
714593f4d7SAlex Bennée ptr_to_info, info.heap_base, info.heap_limit);
724593f4d7SAlex Bennée exit(6);
734593f4d7SAlex Bennée }
744593f4d7SAlex Bennée
754593f4d7SAlex Bennée printf("heap: %p -> %p\n", info.heap_base, info.heap_limit);
764593f4d7SAlex Bennée printf("stack: %p -> %p\n", info.stack_base, info.stack_limit);
774593f4d7SAlex Bennée
784593f4d7SAlex Bennée __semi_call(SYS_WRITE0, (uintptr_t) "Passed HeapInfo checks");
793539d84dSAlex Bennée __semi_call(SYS_REPORTEXC, exit_code);
803539d84dSAlex Bennée /* if we get here we failed */
813539d84dSAlex Bennée return -1;
823539d84dSAlex Bennée }
83