2 Copyright (C) 2008 Mathias Gottschlag
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in the
6 Software without restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
8 Software, and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include "mm/memory.h"
32 extern uint32_t kernel_directory
[1024];
34 char bootstrap_stack
[0x4000] __attribute__ ((aligned (4096)));
36 volatile uint32_t start_aps
= 0;
38 void keInitPIC2(void);
46 char *cpusign
= (char*)0xC00B8000 + keAPICGetCPU() * 2;
51 asm volatile("ltrw %%ax"::"a"(0x28 + keAPICGetCPU() * 8));
53 char *vidmem
= (char*)0xc00B8000;
55 char *cpusign
= vidmem
+ keAPICGetCPU() * 2;
59 keAPICWrite(0x80, 0x20);
60 keAPICWrite(0x320, 0x10000);
61 keAPICWrite(0x340, 0x10000);
62 keAPICWrite(0x350, 0x8700);
63 keAPICWrite(0x360, 0x400);
64 keAPICWrite(0x370, 0x10000);
66 keAPICWrite(0xF0, 0x10F);
73 static FloatingPointerStruct
*keFindFloatingPointerStruct(void);
75 extern uint32_t kernel_stack
[];
80 FloatingPointerStruct
*fps
= keFindFloatingPointerStruct();
84 keAddCPU(keAPICGetCPU());
89 kePrint("SMP configuration table: %X\n", fps
->configtable
);
90 if (fps
->configtable
== 0)
92 kePrint("Error: Default SMP configurations not supported.\n");
93 mmMapKernelMemory(0, (uint32_t)fps
& ~0xFFF, 0);
97 // Load configuration table
98 SMPConfigTable
*config
= (SMPConfigTable
*)mmFindFreeKernelPages(MM_MAX_KERNEL_PAGE
,
99 MM_MIN_KERNEL_PAGE
, 1, 0x1000);
100 mmMapKernelMemory(fps
->configtable
& ~0xFFF, (uintptr_t)config
,
101 MM_MAP_READ
| MM_MAP_WRITE
);
102 config
= (SMPConfigTable
*)((char*)config
+ (fps
->configtable
& 0xFFF));
104 kePrint("Table entries: %d\n", config
->entrycount
);
106 // TODO: This still can crash when we step upon the next page!
107 uint32_t max_lapic_id
= 0;
108 uint32_t bootstrap_id
= 0;
109 uintptr_t *stacks
= malloc(sizeof(uintptr_t));
110 uint8_t *entry
= (uint8_t*)config
+ sizeof(SMPConfigTable
);
112 for (i
= 0; i
< config
->entrycount
; i
++)
119 SMPProcessorEntry
*processor
= (SMPProcessorEntry
*)entry
;
120 if (processor
->flags
& KE_SMP_PROCESSOR_ENABLED
)
122 kePrint("Processor (%d).\n", processor
->lapicid
);
123 if (processor
->lapicid
> max_lapic_id
)
125 max_lapic_id
= processor
->lapicid
;
126 stacks
= realloc(stacks
, sizeof(uintptr_t) * (max_lapic_id
+ 1));
128 if (processor
->flags
& KE_SMP_PROCESSOR_BOOTSTRAP
)
130 // Add bootstrap processor to the list
131 keAddCPU(processor
->lapicid
);
132 bootstrap_id
= processor
->lapicid
;
136 // Add application processor
137 uintptr_t stack
= mmFindFreeKernelPages(MM_MAX_KERNEL_PAGE
,
138 MM_MIN_KERNEL_PAGE
, 1, 0x1000);
139 uintptr_t paddr
= mmAllocPhysicalMemory(0, 0, 0x1000);
140 mmMapKernelMemory(paddr
, stack
, MM_MAP_READ
| MM_MAP_WRITE
);
141 keAddCPU(processor
->lapicid
);
142 stacks
[processor
->lapicid
] = stack
+ 0x1000;
154 extern void *_binary_smpstart_o_start
;
155 extern void *_binary_smpstart_o_end
;
157 // Load startup code to physical address 0x1000
158 uintptr_t smpstart
= mmFindFreeKernelPages(MM_MAX_KERNEL_PAGE
,
159 MM_MIN_KERNEL_PAGE
, 1, 0x1000);
160 mmMapKernelMemory(0x1000, smpstart
,
161 MM_MAP_READ
| MM_MAP_WRITE
);
163 kePrint("start: %x, end: %x\n", &_binary_smpstart_o_start
, &_binary_smpstart_o_end
);
164 kePrint("Copying %d bytes from %x to %x\n", (uintptr_t)&_binary_smpstart_o_end
- (uintptr_t)&_binary_smpstart_o_start
, &_binary_smpstart_o_start
, 0x2000);
165 memcpy((void*)smpstart
, &_binary_smpstart_o_start
, (uintptr_t)&_binary_smpstart_o_end
- (uintptr_t)&_binary_smpstart_o_start
);
166 kePrint("Copied memory.\n");
168 *((volatile void**)(smpstart
+ 2)) = keSMPEntry
;
169 *((volatile void**)(smpstart
+ 6)) = (uintptr_t*)((uintptr_t)kernel_directory
- MM_KERNEL_BASE
);
170 *((volatile void**)(smpstart
+ 10)) = stacks
;
172 mmMapKernelMemory(0x1000, 0x1000,
173 MM_MAP_READ
| MM_MAP_WRITE
);
175 // Send start signal to processors
178 for (i
= 0; i
< 100000; i
++)
182 keAPICWriteStartup(0x1000);
183 // TODO: Send second startup IPI after some time
184 //keAPICWriteStartup(0x1000);
187 mmMapKernelMemory(0, smpstart
, 0);
188 mmMapKernelMemory(0, (uint32_t)config
& ~0xFFF, 0);
189 mmMapKernelMemory(0, (uint32_t)fps
& ~0xFFF, 0);
190 // TODO: Wait until all procesors are running and are set up correctly
191 //mmMapKernelMemory(0, 0x1000, 0);
196 void keStartAPs(void)
201 static uintptr_t keFindFloatingPointerStructRange(uintptr_t addr
, uintptr_t size
)
204 uintptr_t vaddr
= mmFindFreeKernelPages(MM_MAX_KERNEL_PAGE
,
205 MM_MIN_KERNEL_PAGE
, 1, (size
+ 4095) & ~0xFFF);
207 for (i
= 0; i
< (size
+ 4095) / 0x1000; ++i
)
209 mmMapKernelMemory((addr
& ~0xFFF) + i
* 0x1000, vaddr
+ i
* 0x1000, MM_MAP_READ
| MM_MAP_WRITE
);
211 vaddr
+= addr
& 0xFFF;
212 // Loop through possible addresses
213 uintptr_t currentaddr
= vaddr
;
214 currentaddr
= ((currentaddr
+ 15) / 16) * 16;
215 uintptr_t fps_phys
= 0;
216 while (currentaddr
<= (vaddr
+ size
- 16))
218 FloatingPointerStruct
*currentfps
= (FloatingPointerStruct
*)currentaddr
;
220 if (!memcmp(currentfps
->signature
, "_MP_", 4))
224 uint8_t checksum
= 0;
225 for (i
= 0; i
< 16; i
++)
227 checksum
+= ((char*)currentaddr
)[i
];
231 fps_phys
= (uintptr_t)currentfps
- vaddr
+ addr
;
239 for (i
= 0; i
< (size
+ 4095) / 0x1000; ++i
)
241 mmMapKernelMemory(0, vaddr
+ i
* 0x1000, 0);
247 static FloatingPointerStruct
*keFindFloatingPointerStruct(void)
250 uintptr_t vaddr
= mmFindFreeKernelPages(MM_MAX_KERNEL_PAGE
,
251 MM_MIN_KERNEL_PAGE
, 1, 0x1000);
252 mmMapKernelMemory(0, vaddr
, MM_MAP_READ
| MM_MAP_WRITE
);
254 /*halMapPage(kernel_directory, 0x1000, 0x0, 0x3);*/
255 uint16_t ebdasegment
= *(uint16_t*)(vaddr
+ 0x400 + 0x0E);
256 mmMapKernelMemory(0, vaddr
, 0);
257 kePrint("EDBA: 0x%X\n", ((uint32_t)ebdasegment
) << 4);
259 uintptr_t fps_phys
= 0;
263 fps_phys
= keFindFloatingPointerStructRange(((uint32_t)ebdasegment
) << 4, 1024);
267 // Search in last kB of main memory
268 fps_phys
= keFindFloatingPointerStructRange(0x9FC00, 1024);
272 // Search in BIOS area
273 fps_phys
= keFindFloatingPointerStructRange(0xE0000, 0x20000);
275 if (!fps_phys
) return 0;
277 /*FloatingPointerStruct *fps = (FloatingPointerStruct*)halFindContinuousPages(kernel_directory, 1, 0xE0000000, 0xFFFFFFFF);
278 halMapPage(kernel_directory, (uint32_t)fps, fps_phys & ~0xFFF, 0x3);
279 fps = (FloatingPointerStruct*)((char*)fps + (fps_phys & 0xFFF));*/
280 FloatingPointerStruct
*fps
= (void*)mmFindFreeKernelPages(MM_MAX_KERNEL_PAGE
,
281 MM_MIN_KERNEL_PAGE
, 1, 0x1000);
282 mmMapKernelMemory(fps_phys
& ~0xFFF, (uintptr_t)fps
,
283 MM_MAP_READ
| MM_MAP_WRITE
);
284 fps
= (FloatingPointerStruct
*)((char*)fps
+ (fps_phys
& 0xFFF));