]> git.sesse.net Git - pistorm/blob - a314/a314device/fix_mem_region.c
Add missing copyright to A314 source files
[pistorm] / a314 / a314device / fix_mem_region.c
1 /*
2  * Copyright 2020-2021 Niklas Ekström
3  */
4
5 #include <exec/types.h>
6 #include <exec/execbase.h>
7 #include <exec/memory.h>
8 #include <proto/exec.h>
9 #include <proto/graphics.h>
10
11 #include "a314.h"
12 #include "fix_mem_region.h"
13 #include "protocol.h"
14
15 struct MemChunkList
16 {
17         struct MemChunk *first;
18         struct MemChunk *last;
19         ULONG free;
20 };
21
22 void add_chunk(struct MemChunkList *l, struct MemChunk *mc)
23 {
24         if (l->first == NULL)
25                 l->first = mc;
26         else
27                 l->last->mc_Next = mc;
28         l->last = mc;
29         l->free += mc->mc_Bytes;
30 }
31
32 struct MemHeader *split_region(struct MemHeader *lower, ULONG split_at)
33 {
34         struct MemHeader *upper = (struct MemHeader *)AllocMem(sizeof(struct MemHeader), MEMF_PUBLIC | MEMF_CLEAR);
35
36         struct MemChunkList ll = {NULL, NULL, 0};
37         struct MemChunkList ul = {NULL, NULL, 0};
38
39         struct MemChunk *mc = lower->mh_First;
40
41         while (mc != NULL)
42         {
43                 struct MemChunk *next_chunk = mc->mc_Next;
44                 mc->mc_Next = NULL;
45
46                 ULONG start = (ULONG)mc;
47                 ULONG end = start + mc->mc_Bytes;
48
49                 if (end <= split_at)
50                         add_chunk(&ll, mc);
51                 else if (split_at <= start)
52                         add_chunk(&ul, mc);
53                 else
54                 {
55                         mc->mc_Bytes = split_at - start;
56                         add_chunk(&ll, mc);
57
58                         struct MemChunk *new_chunk = (struct MemChunk *)split_at;
59                         new_chunk->mc_Next = NULL;
60                         new_chunk->mc_Bytes = end - split_at;
61                         add_chunk(&ul, new_chunk);
62                 }
63                 mc = next_chunk;
64         }
65
66         upper->mh_Node.ln_Type = NT_MEMORY;
67         upper->mh_Node.ln_Pri = lower->mh_Node.ln_Pri;
68         upper->mh_Node.ln_Name = lower->mh_Node.ln_Name; // Use a custom name?
69         upper->mh_Attributes = lower->mh_Attributes;
70
71         lower->mh_First = ll.first;
72         upper->mh_First = ul.first;
73
74         upper->mh_Lower = (APTR)split_at;
75         upper->mh_Upper = lower->mh_Upper;
76         lower->mh_Upper = (APTR)split_at;
77
78         lower->mh_Free = ll.free;
79         upper->mh_Free = ul.free;
80
81         return upper;
82 }
83
84 BOOL overlap(struct MemHeader *mh, ULONG lower, ULONG upper)
85 {
86         return lower < (ULONG)(mh->mh_Upper) && (ULONG)(mh->mh_Lower) < upper;
87 }
88
89 void mark_region_a314(ULONG address, ULONG size)
90 {
91         struct List *memlist = &(SysBase->MemList);
92
93         for (struct Node *node = memlist->lh_Head; node->ln_Succ != NULL; node = node->ln_Succ)
94         {
95                 struct MemHeader *mh = (struct MemHeader *)node;
96                 if (overlap(mh, address, address + size))
97                 {
98                         if ((ULONG)mh->mh_Lower < address)
99                         {
100                                 mh->mh_Attributes &= ~MEMF_A314;
101                                 mh = split_region(mh, address);
102                         }
103                         else
104                                 Remove((struct Node *)mh);
105
106                         if (address + size < (ULONG)mh->mh_Upper)
107                         {
108                                 struct MemHeader *new_mh = split_region(mh, address + size);
109                                 new_mh->mh_Attributes &= ~MEMF_A314;
110                                 Enqueue(memlist, (struct Node *)new_mh);
111                         }
112
113                         mh->mh_Attributes |= MEMF_A314;
114                         Enqueue(memlist, (struct Node *)mh);
115                         return;
116                 }
117         }
118 }
119
120 BOOL fix_memory()
121 {
122         Forbid();
123         mark_region_a314(ca->mem_base, ca->mem_size);
124         Permit();
125         return TRUE;
126 }
127
128 ULONG translate_address_a314(__reg("a0") void *address)
129 {
130         ULONG offset = (ULONG)address - ca->mem_base;
131         if (offset < ca->mem_size)
132                 return offset;
133         return -1;
134 }