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 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 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 * 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 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 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