git subrepo pull --force deps/lightrec
[pcsx_rearmed.git] / deps / libretro-common / libco / psp2.c
CommitLineData
3719602c
PC
1/*
2libco.arm (2015-06-18)
3license: public domain
4*/
5
6#define LIBCO_C
7#include "libco.h"
8
9#include <assert.h>
10#include <stdlib.h>
11#include <unistd.h>
12#include <psp2/kernel/sysmem.h>
13#include <stdio.h>
14#include <string.h>
15
16#define FOUR_KB_ALIGN(x) align(x, 12)
17#define MB_ALIGN(x) align(x, 20)
18
19#ifdef __cplusplus
20extern "C" {
21#endif
22
23 static inline int align(int x, int n)
24 {
25 return (((x >> n) + 1) << n);
26 }
27
28 static thread_local unsigned long co_active_buffer[64];
29 static thread_local cothread_t co_active_handle = 0;
30 static void(*co_swap)(cothread_t, cothread_t) = 0;
31 static int block;
32 static uint32_t co_swap_function[] = {
33 0xe8a16ff0, /* stmia r1!, {r4-r11,sp,lr} */
34 0xe8b0aff0, /* ldmia r0!, {r4-r11,sp,pc} */
35 0xe12fff1e, /* bx lr */
36 };
37
38 static void co_init(void)
39 {
40 int ret;
41 void *base;
42
43 block = sceKernelAllocMemBlockForVM("libco",
44 MB_ALIGN(FOUR_KB_ALIGN(sizeof co_swap_function)));
45 if (block < 0)
46 return;
47
48 /* Get base address */
49 if ((ret = sceKernelGetMemBlockBase(block, &base)) < 0)
50 return;
51
52 /* Set domain to be writable by user */
53 if ((ret = sceKernelOpenVMDomain()) < 0)
54 return;
55
56 memcpy(base, co_swap_function, sizeof co_swap_function);
57
58 /* Set domain back to read-only */
59 if ((ret = sceKernelCloseVMDomain()) < 0)
60 return;
61
62 /* Flush icache */
63 ret = sceKernelSyncVMDomain(block, base,
64 MB_ALIGN(FOUR_KB_ALIGN(sizeof co_swap_function)));
65 if (ret < 0)
66 return;
67
68 co_swap = (void(*)(cothread_t, cothread_t))base;
69 }
70
71 cothread_t co_active(void)
72 {
73 if (!co_active_handle)
74 co_active_handle = &co_active_buffer;
75 return co_active_handle;
76 }
77
78 cothread_t co_create(unsigned int size, void(*entrypoint)(void))
79 {
80 unsigned long* handle = 0;
81 if (!co_swap)
82 co_init();
83 if (!co_active_handle)
84 co_active_handle = &co_active_buffer;
85 size += 256;
86 size &= ~15;
87
88 if ((handle = (unsigned long*)malloc(size)))
89 {
90 unsigned long *p = (unsigned long*)((unsigned char*)handle + size);
91 handle[8] = (unsigned long)p;
92 handle[9] = (unsigned long)entrypoint;
93 }
94
95 return handle;
96 }
97
98 void co_delete(cothread_t handle)
99 {
100 free(handle);
101 sceKernelFreeMemBlock(block);
102 }
103
104 void co_switch(cothread_t handle)
105 {
106 cothread_t co_previous_handle = co_active_handle;
107 co_swap(co_active_handle = handle, co_previous_handle);
108 }
109
110#ifdef __cplusplus
111}
112#endif