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 ULONG NvBase;
31 extern PVOID FrameBuffer;
32 extern ULONG FrameBufferSize;
33
34 #define TEST_SIZE 0x200
35 #define TEST_PATTERN1 0xAA
36 #define TEST_PATTERN2 0x55
37
38 extern VOID
39 SetMemory(
40 PFREELDR_MEMORY_DESCRIPTOR MemoryMap,
41 ULONG_PTR BaseAddress,
42 SIZE_T Size,
43 TYPE_OF_MEMORY MemoryType);
44
45 extern VOID
46 ReserveMemory(
47 PFREELDR_MEMORY_DESCRIPTOR MemoryMap,
48 ULONG_PTR BaseAddress,
49 SIZE_T Size,
50 TYPE_OF_MEMORY MemoryType,
51 PCHAR Usage);
52
53 extern ULONG
54 PcMemFinalizeMemoryMap(
55 PFREELDR_MEMORY_DESCRIPTOR MemoryMap);
56
57 static
58 VOID
XboxInitializePCI(VOID)59 XboxInitializePCI(VOID)
60 {
61 PCI_TYPE1_CFG_BITS PciCfg1;
62 ULONG PciData;
63
64 /* Select PCI to PCI bridge */
65 PciCfg1.u.bits.Enable = 1;
66 PciCfg1.u.bits.BusNumber = 0;
67 PciCfg1.u.bits.DeviceNumber = 8;
68 PciCfg1.u.bits.FunctionNumber = 0;
69 /* Select register VendorID & DeviceID */
70 PciCfg1.u.bits.RegisterNumber = 0x00;
71 PciCfg1.u.bits.Reserved = 0;
72
73 WRITE_PORT_ULONG(PCI_TYPE1_ADDRESS_PORT, PciCfg1.u.AsULONG);
74 PciData = READ_PORT_ULONG((PULONG)PCI_TYPE1_DATA_PORT);
75
76 if (PciData == 0x01B810DE)
77 {
78 /* Select register PrimaryBus/SecondaryBus/SubordinateBus/SecondaryLatency */
79 PciCfg1.u.bits.RegisterNumber = 0x18;
80 WRITE_PORT_ULONG(PCI_TYPE1_ADDRESS_PORT, PciCfg1.u.AsULONG);
81
82 /* Link uninitialized PCI bridge to the empty PCI bus 2,
83 * it's not supposed to have any devices attached anyway */
84 PciData = READ_PORT_ULONG((PULONG)PCI_TYPE1_DATA_PORT);
85 PciData &= 0xFF0000FF;
86 PciData |= 0x00020200;
87 WRITE_PORT_ULONG((PULONG)PCI_TYPE1_DATA_PORT, PciData);
88 }
89
90 /* Select AGP to PCI bridge */
91 PciCfg1.u.bits.DeviceNumber = 30;
92 /* Select register VendorID & DeviceID */
93 PciCfg1.u.bits.RegisterNumber = 0x00;
94
95 WRITE_PORT_ULONG(PCI_TYPE1_ADDRESS_PORT, PciCfg1.u.AsULONG);
96 PciData = READ_PORT_ULONG((PULONG)PCI_TYPE1_DATA_PORT);
97
98 if (PciData == 0x01B710DE)
99 {
100 /* Zero out uninitialized AGP Host bridge BARs */
101
102 /* Select register BAR0 */
103 PciCfg1.u.bits.RegisterNumber = 0x10;
104 WRITE_PORT_ULONG(PCI_TYPE1_ADDRESS_PORT, PciCfg1.u.AsULONG);
105 /* Zero it out */
106 WRITE_PORT_ULONG((PULONG)PCI_TYPE1_DATA_PORT, 0);
107
108 /* Select register BAR1 */
109 PciCfg1.u.bits.RegisterNumber = 0x14;
110 WRITE_PORT_ULONG(PCI_TYPE1_ADDRESS_PORT, PciCfg1.u.AsULONG);
111 /* Zero it out */
112 WRITE_PORT_ULONG((PULONG)PCI_TYPE1_DATA_PORT, 0);
113 }
114 }
115
116 VOID
XboxMemInit(VOID)117 XboxMemInit(VOID)
118 {
119 PCI_TYPE1_CFG_BITS PciCfg1;
120 UCHAR ControlRegion[TEST_SIZE];
121 PVOID MembaseTop = (PVOID)(64 * 1024 * 1024);
122 PVOID MembaseLow = (PVOID)0;
123
124 WRITE_REGISTER_ULONG((PULONG)(NvBase + NV2A_FB_CFG0), 0x03070103);
125 WRITE_REGISTER_ULONG((PULONG)(NvBase + NV2A_FB_CFG0 + 4), 0x11448000);
126
127 /* Select Host to PCI bridge */
128 PciCfg1.u.bits.Enable = 1;
129 PciCfg1.u.bits.BusNumber = 0;
130 PciCfg1.u.bits.DeviceNumber = 0;
131 PciCfg1.u.bits.FunctionNumber = 0;
132 PciCfg1.u.bits.Reserved = 0;
133 /* Prepare hardware for 128 MB */
134 PciCfg1.u.bits.RegisterNumber = 0x84;
135
136 WRITE_PORT_ULONG(PCI_TYPE1_ADDRESS_PORT, PciCfg1.u.AsULONG);
137 WRITE_PORT_ULONG((PULONG)PCI_TYPE1_DATA_PORT, 0x7FFFFFF);
138
139 InstalledMemoryMb = 64;
140 memset(ControlRegion, TEST_PATTERN1, TEST_SIZE);
141 memset(MembaseTop, TEST_PATTERN1, TEST_SIZE);
142 __wbinvd();
143
144 if (memcmp(MembaseTop, ControlRegion, TEST_SIZE) == 0)
145 {
146 /* Looks like there is memory .. maybe a 128MB box */
147 memset(ControlRegion, TEST_PATTERN2, TEST_SIZE);
148 memset(MembaseTop, TEST_PATTERN2, TEST_SIZE);
149 __wbinvd();
150 if (memcmp(MembaseTop, ControlRegion, TEST_SIZE) == 0)
151 {
152 /* Definitely looks like there is memory */
153 if (memcmp(MembaseLow, ControlRegion, TEST_SIZE) == 0)
154 {
155 /* Hell, we find the Test-string at 0x0 too! */
156 InstalledMemoryMb = 64;
157 }
158 else
159 {
160 InstalledMemoryMb = 128;
161 }
162 }
163 }
164
165 /* Set hardware for amount of memory detected */
166 WRITE_PORT_ULONG(PCI_TYPE1_ADDRESS_PORT, PciCfg1.u.AsULONG);
167 WRITE_PORT_ULONG((PULONG)PCI_TYPE1_DATA_PORT, InstalledMemoryMb * 1024 * 1024 - 1);
168
169 AvailableMemoryMb = InstalledMemoryMb;
170
171 XboxInitializePCI();
172 }
173
174 memory_map_t *
XboxGetMultibootMemoryMap(INT * Count)175 XboxGetMultibootMemoryMap(INT * Count)
176 {
177 memory_map_t * MemoryMap;
178
179 if (!MultibootInfoPtr)
180 {
181 ERR("Multiboot info structure not found!\n");
182 return NULL;
183 }
184
185 if (!(MultibootInfoPtr->flags & MB_INFO_FLAG_MEMORY_MAP))
186 {
187 ERR("Multiboot memory map is not passed!\n");
188 return NULL;
189 }
190
191 MemoryMap = (memory_map_t *)MultibootInfoPtr->mmap_addr;
192
193 if (!MemoryMap ||
194 MultibootInfoPtr->mmap_length == 0 ||
195 MultibootInfoPtr->mmap_length % sizeof(memory_map_t) != 0)
196 {
197 ERR("Multiboot memory map structure is malformed!\n");
198 return NULL;
199 }
200
201 *Count = MultibootInfoPtr->mmap_length / sizeof(memory_map_t);
202 return MemoryMap;
203 }
204
205 TYPE_OF_MEMORY
XboxMultibootMemoryType(ULONG Type)206 XboxMultibootMemoryType(ULONG Type)
207 {
208 switch (Type)
209 {
210 case 0: // Video RAM
211 return LoaderFirmwarePermanent;
212 case 1: // Available RAM
213 return LoaderFree;
214 case 3: // ACPI area
215 return LoaderFirmwareTemporary;
216 case 4: // Hibernation area
217 return LoaderSpecialMemory;
218 case 5: // Reserved or invalid memory
219 return LoaderSpecialMemory;
220 default:
221 return LoaderFirmwarePermanent;
222 }
223 }
224
225 FREELDR_MEMORY_DESCRIPTOR XboxMemoryMap[MAX_BIOS_DESCRIPTORS + 1];
226
227 PFREELDR_MEMORY_DESCRIPTOR
XboxMemGetMemoryMap(ULONG * MemoryMapSize)228 XboxMemGetMemoryMap(ULONG *MemoryMapSize)
229 {
230 memory_map_t * MbMap;
231 INT Count, i;
232
233 TRACE("XboxMemGetMemoryMap()\n");
234
235 MbMap = XboxGetMultibootMemoryMap(&Count);
236 if (MbMap)
237 {
238 /* Obtain memory map via multiboot spec */
239
240 for (i = 0; i < Count; i++, MbMap++)
241 {
242 TRACE("i = %d, base_addr_low = 0x%p, length_low = 0x%p\n", i, MbMap->base_addr_low, MbMap->length_low);
243
244 if (MbMap->base_addr_high > 0 || MbMap->length_high > 0)
245 {
246 ERR("Memory descriptor base or size is greater than 4 GB, should not happen on Xbox!\n");
247 ASSERT(FALSE);
248 }
249
250 SetMemory(XboxMemoryMap,
251 MbMap->base_addr_low,
252 MbMap->length_low,
253 XboxMultibootMemoryType(MbMap->type));
254 }
255 }
256 else
257 {
258 /* Synthesize memory map */
259
260 /* Available RAM block */
261 SetMemory(XboxMemoryMap,
262 0,
263 AvailableMemoryMb * 1024 * 1024,
264 LoaderFree);
265
266 if (FrameBufferSize != 0)
267 {
268 /* Video memory */
269 ReserveMemory(XboxMemoryMap,
270 (ULONG_PTR)FrameBuffer,
271 FrameBufferSize,
272 LoaderFirmwarePermanent,
273 "Video memory");
274 }
275 }
276
277 *MemoryMapSize = PcMemFinalizeMemoryMap(XboxMemoryMap);
278 return XboxMemoryMap;
279 }
280
281 /* EOF */
282