1 /*
2  *  FreeLoader
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  *  Note: much of this code was based on knowledge and/or code developed
19  *  by the Xbox Linux group: http://www.xbox-linux.org
20  */
21 
22 #include <freeldr.h>
23 #include <debug.h>
24 
25 DBG_DEFAULT_CHANNEL(MEMORY);
26 
27 static ULONG InstalledMemoryMb = 0;
28 static ULONG AvailableMemoryMb = 0;
29 extern multiboot_info_t * MultibootInfoPtr;
30 extern PVOID FrameBuffer;
31 extern ULONG FrameBufferSize;
32 
33 #define TEST_SIZE     0x200
34 #define TEST_PATTERN1 0xAA
35 #define TEST_PATTERN2 0x55
36 
37 extern VOID
38 SetMemory(
39     PFREELDR_MEMORY_DESCRIPTOR MemoryMap,
40     ULONG_PTR BaseAddress,
41     SIZE_T Size,
42     TYPE_OF_MEMORY MemoryType);
43 
44 extern VOID
45 ReserveMemory(
46     PFREELDR_MEMORY_DESCRIPTOR MemoryMap,
47     ULONG_PTR BaseAddress,
48     SIZE_T Size,
49     TYPE_OF_MEMORY MemoryType,
50     PCHAR Usage);
51 
52 extern ULONG
53 PcMemFinalizeMemoryMap(
54     PFREELDR_MEMORY_DESCRIPTOR MemoryMap);
55 
56 VOID
57 XboxMemInit(VOID)
58 {
59     UCHAR ControlRegion[TEST_SIZE];
60     PVOID MembaseTop = (PVOID)(64 * 1024 * 1024);
61     PVOID MembaseLow = (PVOID)0;
62 
63     (*(PULONG)(0xfd000000 + 0x100200)) = 0x03070103;
64     (*(PULONG)(0xfd000000 + 0x100204)) = 0x11448000;
65 
66     WRITE_PORT_ULONG((ULONG*) 0xcf8, CONFIG_CMD(0, 0, 0x84));
67     WRITE_PORT_ULONG((ULONG*) 0xcfc, 0x7ffffff);             /* Prep hardware for 128 Mb */
68 
69     InstalledMemoryMb = 64;
70     memset(ControlRegion, TEST_PATTERN1, TEST_SIZE);
71     memset(MembaseTop, TEST_PATTERN1, TEST_SIZE);
72     __wbinvd();
73 
74     if (memcmp(MembaseTop, ControlRegion, TEST_SIZE) == 0)
75     {
76         /* Looks like there is memory .. maybe a 128MB box */
77         memset(ControlRegion, TEST_PATTERN2, TEST_SIZE);
78         memset(MembaseTop, TEST_PATTERN2, TEST_SIZE);
79         __wbinvd();
80         if (memcmp(MembaseTop, ControlRegion, TEST_SIZE) == 0)
81         {
82             /* Definitely looks like there is memory */
83             if (memcmp(MembaseLow, ControlRegion, TEST_SIZE) == 0)
84             {
85                 /* Hell, we find the Test-string at 0x0 too! */
86                 InstalledMemoryMb = 64;
87             }
88             else
89             {
90                 InstalledMemoryMb = 128;
91             }
92         }
93     }
94 
95     /* Set hardware for amount of memory detected */
96     WRITE_PORT_ULONG((ULONG*) 0xcf8, CONFIG_CMD(0, 0, 0x84));
97     WRITE_PORT_ULONG((ULONG*) 0xcfc, InstalledMemoryMb * 1024 * 1024 - 1);
98 
99     AvailableMemoryMb = InstalledMemoryMb;
100 }
101 
102 memory_map_t *
103 XboxGetMultibootMemoryMap(INT * Count)
104 {
105     memory_map_t * MemoryMap;
106 
107     if (!MultibootInfoPtr)
108     {
109         ERR("Multiboot info structure not found!\n");
110         return NULL;
111     }
112 
113     if (!(MultibootInfoPtr->flags & MB_INFO_FLAG_MEMORY_MAP))
114     {
115         ERR("Multiboot memory map is not passed!\n");
116         return NULL;
117     }
118 
119     MemoryMap = (memory_map_t *)MultibootInfoPtr->mmap_addr;
120 
121     if (!MemoryMap ||
122         MultibootInfoPtr->mmap_length == 0 ||
123         MultibootInfoPtr->mmap_length % sizeof(memory_map_t) != 0)
124     {
125         ERR("Multiboot memory map structure is malformed!\n");
126         return NULL;
127     }
128 
129     *Count = MultibootInfoPtr->mmap_length / sizeof(memory_map_t);
130     return MemoryMap;
131 }
132 
133 TYPE_OF_MEMORY
134 XboxMultibootMemoryType(ULONG Type)
135 {
136     switch (Type)
137     {
138         case 0: // Video RAM
139             return LoaderFirmwarePermanent;
140         case 1: // Available RAM
141             return LoaderFree;
142         case 3: // ACPI area
143             return LoaderFirmwareTemporary;
144         case 4: // Hibernation area
145             return LoaderSpecialMemory;
146         case 5: // Reserved or invalid memory
147             return LoaderSpecialMemory;
148         default:
149             return LoaderFirmwarePermanent;
150     }
151 }
152 
153 FREELDR_MEMORY_DESCRIPTOR XboxMemoryMap[MAX_BIOS_DESCRIPTORS + 1];
154 
155 PFREELDR_MEMORY_DESCRIPTOR
156 XboxMemGetMemoryMap(ULONG *MemoryMapSize)
157 {
158     memory_map_t * MbMap;
159     INT Count, i;
160 
161     TRACE("XboxMemGetMemoryMap()\n");
162 
163     MbMap = XboxGetMultibootMemoryMap(&Count);
164     if (MbMap)
165     {
166         /* Obtain memory map via multiboot spec */
167 
168         for (i = 0; i < Count; i++, MbMap++)
169         {
170             TRACE("i = %d, base_addr_low = 0x%p, length_low = 0x%p\n", i, MbMap->base_addr_low, MbMap->length_low);
171 
172             if (MbMap->base_addr_high > 0 || MbMap->length_high > 0)
173             {
174                 ERR("Memory descriptor base or size is greater than 4 GB, should not happen on Xbox!\n");
175                 ASSERT(FALSE);
176             }
177 
178             SetMemory(XboxMemoryMap,
179                       MbMap->base_addr_low,
180                       MbMap->length_low,
181                       XboxMultibootMemoryType(MbMap->type));
182         }
183     }
184     else
185     {
186         /* Synthesize memory map */
187 
188         /* Available RAM block */
189         SetMemory(XboxMemoryMap,
190                   0,
191                   AvailableMemoryMb * 1024 * 1024,
192                   LoaderFree);
193 
194         if (FrameBufferSize != 0)
195         {
196             /* Video memory */
197             ReserveMemory(XboxMemoryMap,
198                           (ULONG_PTR)FrameBuffer,
199                           FrameBufferSize,
200                           LoaderFirmwarePermanent,
201                           "Video memory");
202         }
203     }
204 
205     *MemoryMapSize = PcMemFinalizeMemoryMap(XboxMemoryMap);
206     return XboxMemoryMap;
207 }
208 
209 /* EOF */
210