-
Notifications
You must be signed in to change notification settings - Fork 0
/
mp.c
155 lines (109 loc) · 3.87 KB
/
mp.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*Copyright 2018 2019 Juan Bosco Garcia, Almudena Garcia Jurado-Centurion
*This file is part of Min_SMP.
*Min_SMP is free software: you can redistribute it and/or modify
*it under the terms of the GNU General Public License as published by
*the Free Software Foundation, either version 3 of the License, or
*(at your option) any later version.
*Min_SMP is distributed in the hope that it will be useful,
*but WITHOUT ANY WARRANTY; without even the implied warranty of
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*GNU General Public License for more details.
*You should have received a copy of the GNU General Public License
*along with Min_SMP. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mp.h>
#include <ioapic.h>
#include <video.h>
#include <list.h>
#include <mem.h>
#include <cpu.h>
#define AP_BOOT_ADDR (0x7000)
extern volatile ApicLocalUnit* lapic;
extern uint32 nioapic;
extern struct list ioapics;
extern void* *apboot, *apbootend;
extern void dummyf(uint32);
extern struct cpu cpus[NCPU];
extern void* *stack_ptr;
extern void *stack_bsp;
int mp_setup(){
int i=0;
/* setup BSP processor */
cpus[i].stack_base = &stack_bsp;
if(cpu_setup()) return -1;
//TODO: Start CPUs
memcpy((void*)AP_BOOT_ADDR, (void*)&apboot, (uint32)&apbootend - (uint32)&apboot);
for(i = 1; i < ncpu; i++){
#define STACK_SIZE (4096 * 2)
*stack_ptr = malloc(STACK_SIZE);
cpus[i].stack_base = *stack_ptr;
//send IPI to start CPU
startup_cpu(cpus[i].apic_id);
//wait until new cpu is enabled
volatile uint32 *flags_p = &cpus[i].flags;
while(!(*flags_p & CPU_ENABLE));
}
return 0;
}
void
mp_print_info(){
printf("LAPIC\n");
printf(" lapic_addr = %x\n", lapic);
printf("CPU:\n");
int i;
for(i=0;i<ncpu;i++){
printf(" cpu %x: apic_id = %x", i, cpus[i].apic_id);
if(cpus[i].flags & CPU_ENABLE) printf(" ENABLE");
printf("\n");
}
printf("IOAPIC:\n");
struct list *node;
list_foreach(&ioapics, node){
struct ioapic *ioapic;
ioapic = list_get_entry(node, struct ioapic);
printf(" ioapic: apic_id= %x addr = %x, base = %x\n",
ioapic->apic_id, ioapic->addr,
ioapic->base);
}
}
/*TODO: Add delay between IPI*/
void startup_cpu(uint32 apic_id){
/* First INIT IPI */
send_ipi(NO_SHORTHAND, INIT, PHYSICAL, ASSERT, LEVEL, 0 , apic_id);
dummyf(lapic->apic_id.r);
/* Second INIT IPI */
send_ipi(NO_SHORTHAND, INIT, PHYSICAL, ASSERT, LEVEL, 0 , apic_id);
dummyf(lapic->apic_id.r);
/* First StartUp IPI */
send_ipi(NO_SHORTHAND, STARTUP, PHYSICAL, ASSERT, LEVEL, AP_BOOT_ADDR >>12 , apic_id);
dummyf(lapic->apic_id.r);
/* Second StartUp IPI */
send_ipi(NO_SHORTHAND, STARTUP, PHYSICAL, ASSERT, LEVEL, AP_BOOT_ADDR >>12 , apic_id);
dummyf(lapic->apic_id.r);
}
int16 cpu_number(){
uint32 apic_id;
uint16 i = 0;
//Read apic id from the current cpu, using its lapic
apic_id = lapic->apic_id.r >>24;
printf("apic id: %x ", apic_id);
printf("version: %x ", lapic->version.r);
//Search apic id in cpu2apic vector
while(cpus[i].apic_id != apic_id && i < ncpu) i = i+1;
if(i == ncpu) return -1;
else return i;
}
void send_ipi(unsigned dest_shorthand, unsigned deliv_mode, unsigned dest_mode, unsigned level, unsigned trig_mode, unsigned vector, unsigned dest_id)
{
IcrLReg icrl_values;
IcrHReg icrh_values;
icrl_values.destination_shorthand = dest_shorthand;
icrl_values.delivery_mode = deliv_mode;
icrl_values.destination_mode = dest_mode;
icrl_values.level = level;
icrl_values.trigger_mode = trig_mode;
icrl_values.vector = vector;
icrh_values.destination_field = dest_id;
lapic->icr_high = icrh_values;
lapic->icr_low = icrl_values;
}