Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
X
xv6-public
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
问题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
银宸时代
OS Lab Group
奖励实验
xv6-public
提交
99b11b6c
提交
99b11b6c
8月 27, 2007
创建
作者:
rsc
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Simplify MP hardware code.
Mainly delete unused constants and code. Move mp_startthem to main.c as bootothers.
上级
b63bb0fd
显示空白字符变更
内嵌
并排
正在显示
6 个修改的文件
包含
207 行增加
和
447 行删除
+207
-447
ioapic.c
ioapic.c
+47
-50
ioapic.h
ioapic.h
+0
-88
lapic.c
lapic.c
+61
-90
main.c
main.c
+31
-3
mp.c
mp.c
+58
-142
mp.h
mp.h
+10
-74
没有找到文件。
ioapic.c
浏览文件 @
99b11b6c
// The I/O APIC manages hardware interrupts for an SMP system.
// http://www.intel.com/design/chipsets/datashts/29056601.pdf
#include "types.h"
#include "types.h"
#include "mp.h"
#include "mp.h"
#include "defs.h"
#include "defs.h"
#include "x86.h"
#include "x86.h"
#include "traps.h"
#include "traps.h"
#include "ioapic.h"
struct
ioapic
{
#define IOAPIC 0xFEC00000 // Default physical address of IO APIC
uint
ioregsel
;
uint
p01
;
uint
p02
;
uint
p03
;
uint
iowin
;
uint
p11
;
uint
p12
;
uint
p13
;
};
#define REG_ID 0x00 // Register index: ID
#define REG_VER 0x01 // Register index: version
#define REG_TABLE 0x10 // Redirection table base
#define IOAPIC_REDTBL_LO(i) (IOAPIC_REDTBL + (i) * 2)
// The redirection table starts at REG_TABLE and uses
#define IOAPIC_REDTBL_HI(i) (IOAPIC_REDTBL_LO(i) + 1)
// two registers to configure each interrupt.
// The first (low) register in a pair contains configuration bits.
// The second (high) register contains a bitmask telling which
// CPUs can serve that interrupt.
#define INT_DISABLED 0x00100000 // Interrupt disabled
#define INT_LEVEL 0x00008000 // Level-triggered (vs edge-)
#define INT_ACTIVELOW 0x00002000 // Active low (vs high)
#define INT_LOGICAL 0x00000800 // Destination is CPU id (vs APIC ID)
volatile
struct
ioapic
*
ioapic
;
// IO APIC MMIO structure: write reg, then read or write data.
struct
ioapic
{
uint
reg
;
uint
pad
[
3
];
uint
data
;
};
static
uint
static
uint
ioapic_read
(
struct
ioapic
*
io
,
int
reg
)
ioapic_read
(
int
reg
)
{
{
io
->
ioregsel
=
reg
;
io
apic
->
reg
=
reg
;
return
io
->
iowin
;
return
io
apic
->
data
;
}
}
static
void
static
void
ioapic_write
(
struct
ioapic
*
io
,
int
reg
,
uint
val
)
ioapic_write
(
int
reg
,
uint
data
)
{
{
io
->
ioregsel
=
reg
;
io
apic
->
reg
=
reg
;
io
->
iowin
=
val
;
io
apic
->
data
=
data
;
}
}
void
void
ioapic_init
(
void
)
ioapic_init
(
void
)
{
{
struct
ioapic
*
io
;
int
i
,
id
,
maxintr
;
uint
l
,
h
;
int
nintr
;
uchar
id
;
int
i
;
if
(
!
ismp
)
if
(
!
ismp
)
return
;
return
;
io
=
(
struct
ioapic
*
)
IO_APIC_BASE
;
ioapic
=
(
volatile
struct
ioapic
*
)
IOAPIC
;
l
=
ioapic_read
(
io
,
IOAPIC_VER
);
maxintr
=
(
ioapic_read
(
REG_VER
)
>>
16
)
&
0xFF
;
nintr
=
((
l
&
IOART_VER_MAXREDIR
)
>>
MAXREDIRSHIFT
)
+
1
;
id
=
ioapic_read
(
REG_ID
)
>>
24
;
id
=
ioapic_read
(
io
,
IOAPIC_ID
)
>>
APIC_ID_SHIFT
;
if
(
id
!=
ioapic_id
)
if
(
id
!=
ioapic_id
)
cprintf
(
"ioapic_init: id isn't equal to ioapic_id; not a MP
\n
"
);
cprintf
(
"ioapic_init: id isn't equal to ioapic_id; not a MP
\n
"
);
for
(
i
=
0
;
i
<
nintr
;
i
++
)
{
// active-hi and edge-triggered for ISA interrupts
// Mark all interrupts edge-triggered, active high, disabled,
// Assume that pin 0 on the first I/O APIC is an ExtINT pin.
// and not routed to any CPUs.
// Assume that pins 1-15 are ISA interrupts
for
(
i
=
0
;
i
<=
maxintr
;
i
++
){
l
=
ioapic_read
(
io
,
IOAPIC_REDTBL_LO
(
i
));
ioapic_write
(
REG_TABLE
+
2
*
i
,
INT_DISABLED
|
(
IRQ_OFFSET
+
i
));
l
=
l
&
~
IOART_INTMASK
;
// allow INTs
ioapic_write
(
REG_TABLE
+
2
*
i
+
1
,
0
);
l
|=
IOART_INTMSET
;
l
=
l
&
~
IOART_INTPOL
;
// active hi
l
=
l
&
~
IOART_TRGRMOD
;
// edgee triggered
l
=
l
&
~
IOART_DELMOD
;
// fixed
l
=
l
&
~
IOART_DESTMOD
;
// physical mode
l
=
l
|
(
IRQ_OFFSET
+
i
);
// vector
ioapic_write
(
io
,
IOAPIC_REDTBL_LO
(
i
),
l
);
h
=
ioapic_read
(
io
,
IOAPIC_REDTBL_HI
(
i
));
h
&=
~
IOART_DEST
;
ioapic_write
(
io
,
IOAPIC_REDTBL_HI
(
i
),
h
);
}
}
}
}
void
void
ioapic_enable
(
int
irq
,
int
cpunum
)
ioapic_enable
(
int
irq
,
int
cpunum
)
{
{
uint
l
,
h
;
struct
ioapic
*
io
;
if
(
!
ismp
)
if
(
!
ismp
)
return
;
return
;
io
=
(
struct
ioapic
*
)
IO_APIC_BASE
;
// Mark interrupt edge-triggered, active high,
l
=
ioapic_read
(
io
,
IOAPIC_REDTBL_LO
(
irq
));
// enabled, and routed to the given cpunum,
l
=
l
&
~
IOART_INTMASK
;
// allow INTs
// which happens to be that cpu's APIC ID.
ioapic_write
(
io
,
IOAPIC_REDTBL_LO
(
irq
),
l
);
ioapic_write
(
REG_TABLE
+
2
*
irq
,
IRQ_OFFSET
+
irq
);
h
=
ioapic_read
(
io
,
IOAPIC_REDTBL_HI
(
irq
));
ioapic_write
(
REG_TABLE
+
2
*
irq
+
1
,
cpunum
<<
24
);
h
&=
~
IOART_DEST
;
h
|=
(
cpunum
<<
APIC_ID_SHIFT
);
ioapic_write
(
io
,
IOAPIC_REDTBL_HI
(
irq
),
h
);
}
}
ioapic.h
deleted
100644 → 0
浏览文件 @
b63bb0fd
#define IO_APIC_BASE 0xFEC00000 // Default phys addr of IO APIC
#define IOAPIC_WINDOW 0x10 // Window register offset
// Constants relating to APIC ID registers
#define APIC_ID_MASK 0xff000000
#define APIC_ID_SHIFT 24
#define APIC_ID_CLUSTER 0xf0
#define APIC_ID_CLUSTER_ID 0x0f
#define APIC_MAX_CLUSTER 0xe
#define APIC_MAX_INTRACLUSTER_ID 3
#define APIC_ID_CLUSTER_SHIFT 4
// Fields in VER
#define APIC_VER_VERSION 0x000000ff
#define APIC_VER_MAXLVT 0x00ff0000
#define MAXLVTSHIFT 16
// Indexes into IO APIC
#define IOAPIC_ID 0x00
#define IOAPIC_VER 0x01
#define IOAPIC_ARB 0x02
#define IOAPIC_REDTBL 0x10
#define IOAPIC_REDTBL0 IOAPIC_REDTBL
#define IOAPIC_REDTBL1 (IOAPIC_REDTBL+0x02)
#define IOAPIC_REDTBL2 (IOAPIC_REDTBL+0x04)
#define IOAPIC_REDTBL3 (IOAPIC_REDTBL+0x06)
#define IOAPIC_REDTBL4 (IOAPIC_REDTBL+0x08)
#define IOAPIC_REDTBL5 (IOAPIC_REDTBL+0x0a)
#define IOAPIC_REDTBL6 (IOAPIC_REDTBL+0x0c)
#define IOAPIC_REDTBL7 (IOAPIC_REDTBL+0x0e)
#define IOAPIC_REDTBL8 (IOAPIC_REDTBL+0x10)
#define IOAPIC_REDTBL9 (IOAPIC_REDTBL+0x12)
#define IOAPIC_REDTBL10 (IOAPIC_REDTBL+0x14)
#define IOAPIC_REDTBL11 (IOAPIC_REDTBL+0x16)
#define IOAPIC_REDTBL12 (IOAPIC_REDTBL+0x18)
#define IOAPIC_REDTBL13 (IOAPIC_REDTBL+0x1a)
#define IOAPIC_REDTBL14 (IOAPIC_REDTBL+0x1c)
#define IOAPIC_REDTBL15 (IOAPIC_REDTBL+0x1e)
#define IOAPIC_REDTBL16 (IOAPIC_REDTBL+0x20)
#define IOAPIC_REDTBL17 (IOAPIC_REDTBL+0x22)
#define IOAPIC_REDTBL18 (IOAPIC_REDTBL+0x24)
#define IOAPIC_REDTBL19 (IOAPIC_REDTBL+0x26)
#define IOAPIC_REDTBL20 (IOAPIC_REDTBL+0x28)
#define IOAPIC_REDTBL21 (IOAPIC_REDTBL+0x2a)
#define IOAPIC_REDTBL22 (IOAPIC_REDTBL+0x2c)
#define IOAPIC_REDTBL23 (IOAPIC_REDTBL+0x2e)
// Fields in the IO APIC's redirection table entries
#define IOART_DEST APIC_ID_MASK // broadcast addr: all APICs
#define IOART_RESV 0x00fe0000 // reserved
#define IOART_INTMASK 0x00010000 // R/W: INTerrupt mask
#define IOART_INTMCLR 0x00000000 // clear, allow INTs
#define IOART_INTMSET 0x00010000 // set, inhibit INTs
#define IOART_TRGRMOD 0x00008000 // R/W: trigger mode
#define IOART_TRGREDG 0x00000000 // edge
#define IOART_TRGRLVL 0x00008000 // level
#define IOART_REM_IRR 0x00004000 // RO: remote IRR
#define IOART_INTPOL 0x00002000 // R/W: INT input pin polarity
#define IOART_INTAHI 0x00000000 // active high
#define IOART_INTALO 0x00002000 // active low
#define IOART_DELIVS 0x00001000 // RO: delivery status
#define IOART_DESTMOD 0x00000800 // R/W: destination mode
#define IOART_DESTPHY 0x00000000 // physical
#define IOART_DESTLOG 0x00000800 // logical
#define IOART_DELMOD 0x00000700 // R/W: delivery mode
#define IOART_DELFIXED 0x00000000 // fixed
#define IOART_DELLOPRI 0x00000100 // lowest priority
#define IOART_DELSMI 0x00000200 // System Management INT
#define IOART_DELRSV1 0x00000300 // reserved
#define IOART_DELNMI 0x00000400 // NMI signal
#define IOART_DELINIT 0x00000500 // INIT signal
#define IOART_DELRSV2 0x00000600 // reserved
#define IOART_DELEXINT 0x00000700 // External INTerrupt
#define IOART_INTVEC 0x000000ff // R/W: INTerrupt vector field
// Fields in VER
#define IOART_VER_VERSION 0x000000ff
#define IOART_VER_MAXREDIR 0x00ff0000
#define MAXREDIRSHIFT 16
lapic.c
浏览文件 @
99b11b6c
// The local APIC manages internal (non-I/O) interrupts.
// See Chapter 8 & Appendix C of Intel processor manual volume 3.
#include "types.h"
#include "types.h"
#include "mp.h"
#include "defs.h"
#include "defs.h"
#include "param.h"
#include "param.h"
#include "x86.h"
#include "x86.h"
#include "traps.h"
#include "traps.h"
#include "mmu.h"
#include "mmu.h"
#include "proc.h"
#include "proc.h"
#include "lapic.h"
// Local APIC registers, divided by 4 for use as uint[] indices.
// Local APIC registers, divided by 4 for use as uint[] indices.
#define ID (0x0020/4) // ID
#define ID (0x0020/4) // ID
#define VER (0x0030/4) // Version
#define VER (0x0030/4) // Version
#define TPR (0x0080/4) // Task Priority
#define TPR (0x0080/4) // Task Priority
#define APR (0x0090/4) // Arbitration Priority
#define PPR (0x00A0/4) // Processor Priority
#define EOI (0x00B0/4) // EOI
#define EOI (0x00B0/4) // EOI
#define LDR (0x00D0/4) // Logical Destination
#define DFR (0x00E0/4) // Destination Format
#define SVR (0x00F0/4) // Spurious Interrupt Vector
#define SVR (0x00F0/4) // Spurious Interrupt Vector
#define ISR (0x0100/4) // Interrupt Status (8 registers)
#define ENABLE 0x00000100 // Unit Enable
#define TMR (0x0180/4) // Trigger Mode (8 registers)
#define IRR (0x0200/4) // Interrupt Request (8 registers)
#define ESR (0x0280/4) // Error Status
#define ESR (0x0280/4) // Error Status
#define ICRLO (0x0300/4) // Interrupt Command
#define ICRLO (0x0300/4) // Interrupt Command
#define INIT 0x00000500 // INIT/RESET
#define STARTUP 0x00000600 // Startup IPI
#define DELIVS 0x00001000 // Delivery status
#define ASSERT 0x00004000 // Assert interrupt (vs deassert)
#define LEVEL 0x00008000 // Level triggered
#define BCAST 0x00080000 // Send to all APICs, including self.
#define ICRHI (0x0310/4) // Interrupt Command [63:32]
#define ICRHI (0x0310/4) // Interrupt Command [63:32]
#define TIMER (0x0320/4) // Local Vector Table 0 (TIMER)
#define TIMER (0x0320/4) // Local Vector Table 0 (TIMER)
#define X1 0x0000000B // divide counts by 1
#define PERIODIC 0x00020000 // Periodic
#define PCINT (0x0340/4) // Performance Counter LVT
#define PCINT (0x0340/4) // Performance Counter LVT
#define LINT0 (0x0350/4) // Local Vector Table 1 (LINT0)
#define LINT0 (0x0350/4) // Local Vector Table 1 (LINT0)
#define LINT1 (0x0360/4) // Local Vector Table 2 (LINT1)
#define LINT1 (0x0360/4) // Local Vector Table 2 (LINT1)
#define ERROR (0x0370/4) // Local Vector Table 3 (ERROR)
#define ERROR (0x0370/4) // Local Vector Table 3 (ERROR)
#define MASKED 0x00010000 // Interrupt masked
#define TICR (0x0380/4) // Timer Initial Count
#define TICR (0x0380/4) // Timer Initial Count
#define TCCR (0x0390/4) // Timer Current Count
#define TCCR (0x0390/4) // Timer Current Count
#define TDCR (0x03E0/4) // Timer Divide Configuration
#define TDCR (0x03E0/4) // Timer Divide Configuration
// SVR
#define ENABLE 0x00000100 // Unit Enable
#define FOCUS 0x00000200 // Focus Processor Checking Disable
// ICRLO
// [14] IPI Trigger Mode Level (RW)
#define DEASSERT 0x00000000 // Deassert level-sensitive interrupt
#define ASSERT 0x00004000 // Assert level-sensitive interrupt
// [17:16] Remote Read Status
#define INVALID 0x00000000 // Invalid
#define WAIT 0x00010000 // In-Progress
#define VALID 0x00020000 // Valid
// [19:18] Destination Shorthand
#define FIELD 0x00000000 // No shorthand
#define SELF 0x00040000 // Self is single destination
#define ALLINC 0x00080000 // All including self
#define ALLEXC 0x000C0000 // All Excluding self
// ESR
#define SENDCS 0x00000001 // Send CS Error
#define RCVCS 0x00000002 // Receive CS Error
#define SENDACCEPT 0x00000004 // Send Accept Error
#define RCVACCEPT 0x00000008 // Receive Accept Error
#define SENDVECTOR 0x00000020 // Send Illegal Vector
#define RCVVECTOR 0x00000040 // Receive Illegal Vector
#define REGISTER 0x00000080 // Illegal Register Address
// [17] Timer Mode (RW)
#define ONESHOT 0x00000000 // One-shot
#define PERIODIC 0x00020000 // Periodic
// [19:18] Timer Base (RW)
#define CLKIN 0x00000000 // use CLKIN as input
#define TMBASE 0x00040000 // use TMBASE
#define DIVIDER 0x00080000 // use output of the divider
#define X2 0x00000000 // divide by 2
#define X4 0x00000001 // divide by 4
#define X8 0x00000002 // divide by 8
#define X16 0x00000003 // divide by 16
#define X32 0x00000008 // divide by 32
#define X64 0x00000009 // divide by 64
#define X128 0x0000000A // divide by 128
#define X1 0x0000000B // divide by 1
//PAGEBREAK!
volatile
uint
*
lapic
;
// Initialized in mp.c
volatile
uint
*
lapic
;
// Initialized in mp.c
//PAGEBREAK!
void
void
lapic_init
(
int
c
)
lapic_init
(
int
c
)
{
{
uint
r
,
lvt
;
if
(
!
lapic
)
if
(
!
lapic
)
return
;
return
;
lapic
[
DFR
]
=
0xFFFFFFFF
;
// Set dst format register
// Enable local APIC; set spurious interrupt vector.
r
=
(
lapic
[
ID
]
>>
24
)
&
0xFF
;
// Read APIC ID
lapic
[
LDR
]
=
(
1
<<
r
)
<<
24
;
lapic
[
TPR
]
=
0xFF
;
// No interrupts for now
// Enable APIC
lapic
[
SVR
]
=
ENABLE
|
(
IRQ_OFFSET
+
IRQ_SPURIOUS
);
lapic
[
SVR
]
=
ENABLE
|
(
IRQ_OFFSET
+
IRQ_SPURIOUS
);
// In virtual wire mode, set up the LINT0 and LINT1 as follows:
// The timer repeatedly counts down at bus frequency
lapic
[
LINT0
]
=
APIC_IMASK
|
APIC_EXTINT
;
// from lapic[TICR] and then issues an interrupt.
lapic
[
LINT1
]
=
APIC_IMASK
|
APIC_NMI
;
// Lapic[TCCR] is the current counter value.
// If xv6 cared more about precise timekeeping, the
// values of TICR and TCCR would be calibrated using
// an external time source.
lapic
[
TDCR
]
=
X1
;
lapic
[
TICR
]
=
10000000
;
lapic
[
TCCR
]
=
10000000
;
lapic
[
TIMER
]
=
PERIODIC
|
(
IRQ_OFFSET
+
IRQ_TIMER
);
lapic
[
EOI
]
=
0
;
// Ack any outstanding interrupts.
// Disable logical interrupt lines.
lapic
[
LINT0
]
=
MASKED
;
lapic
[
LINT1
]
=
MASKED
;
lvt
=
(
lapic
[
VER
]
>>
16
)
&
0xFF
;
// Disable performance counter overflow interrupts
if
(
lvt
>=
4
)
// on machines that provide that interrupt entry.
lapic
[
PCINT
]
=
APIC_IMASK
;
if
(((
lapic
[
VER
]
>>
16
)
&
0xFF
)
>=
4
)
lapic
[
PCINT
]
=
MASKED
;
// Map error interrupt to IRQ_ERROR.
lapic
[
ERROR
]
=
IRQ_OFFSET
+
IRQ_ERROR
;
lapic
[
ERROR
]
=
IRQ_OFFSET
+
IRQ_ERROR
;
// Clear error status register (requires back-to-back writes).
lapic
[
ESR
]
=
0
;
lapic
[
ESR
]
=
0
;
lapic
[
ESR
]
=
0
;
lapic
[
ESR
];
// Issue an INIT Level De-Assert to synchronise arbitration ID's.
// Ack any outstanding interrupts.
lapic
[
EOI
]
=
0
;
// Send an Init Level De-Assert to synchronise arbitration ID's.
lapic
[
ICRHI
]
=
0
;
lapic
[
ICRHI
]
=
0
;
lapic
[
ICRLO
]
=
ALLINC
|
APIC_LEVEL
|
lapic
[
ICRLO
]
=
BCAST
|
INIT
|
LEVEL
;
DEASSERT
|
APIC_INIT
;
while
(
lapic
[
ICRLO
]
&
DELIVS
)
while
(
lapic
[
ICRLO
]
&
APIC_DELIVS
)
;
;
// Initialize the interrupt timer.
// Enable interrupts on the APIC (but not on the processor).
// On real hardware would need to do more XXX.
lapic
[
TDCR
]
=
X1
;
lapic
[
TIMER
]
=
CLKIN
|
PERIODIC
|
(
IRQ_OFFSET
+
IRQ_TIMER
);
lapic
[
TCCR
]
=
10000000
;
lapic
[
TICR
]
=
10000000
;
// Enable interrupts on the APIC (but not on processor).
lapic
[
TPR
]
=
0
;
lapic
[
TPR
]
=
0
;
}
}
...
@@ -146,22 +105,34 @@ lapic_eoi(void)
...
@@ -146,22 +105,34 @@ lapic_eoi(void)
lapic
[
EOI
]
=
0
;
lapic
[
EOI
]
=
0
;
}
}
// Spin for a given number of microseconds.
// On real hardware would want to tune this dynamically.
static
void
microdelay
(
int
us
)
{
volatile
int
j
=
0
;
while
(
us
--
>
0
)
for
(
j
=
0
;
j
<
10000
;
j
++
);
}
// Start additional processor running bootstrap code at addr.
// Start additional processor running bootstrap code at addr.
// See Appendix B of MultiProcessor Specification.
void
void
lapic_startap
(
uchar
apicid
,
uint
addr
)
lapic_startap
(
uchar
apicid
,
uint
addr
)
{
{
int
i
;
int
i
;
volatile
int
j
=
0
;
volatile
int
j
=
0
;
// Send INIT interrupt to reset other CPU.
lapic
[
ICRHI
]
=
apicid
<<
24
;
lapic
[
ICRHI
]
=
apicid
<<
24
;
lapic
[
ICRLO
]
=
FIELD
|
APIC_LEVEL
|
ASSERT
|
APIC_INIT
;
lapic
[
ICRLO
]
=
INIT
|
LEVEL
;
for
(
j
=
0
;
j
<
10000
;
j
++
);
// 200us
microdelay
(
10
);
lapic
[
ICRLO
]
=
FIELD
|
APIC_LEVEL
|
DEASSERT
|
APIC_INIT
;
for
(
j
=
0
;
j
<
1000000
;
j
++
);
// 10ms
// Send startup IPI (twice!) to enter bootstrap code.
for
(
i
=
0
;
i
<
2
;
i
++
){
for
(
i
=
0
;
i
<
2
;
i
++
){
lapic
[
ICRHI
]
=
apicid
<<
24
;
lapic
[
ICRHI
]
=
apicid
<<
24
;
lapic
[
ICRLO
]
=
FIELD
|
APIC_EDGE
|
APIC_STARTUP
|
(
addr
/
4096
);
lapic
[
ICRLO
]
=
STARTUP
|
(
addr
>>
12
);
for
(
j
=
0
;
j
<
10000
;
j
++
);
// 200us
for
(
j
=
0
;
j
<
10000
;
j
++
);
// 200us
}
}
}
}
main.c
浏览文件 @
99b11b6c
...
@@ -12,6 +12,8 @@
...
@@ -12,6 +12,8 @@
extern
char
edata
[],
end
[];
extern
char
edata
[],
end
[];
void
bootothers
(
void
);
// Bootstrap processor starts running C code here.
// Bootstrap processor starts running C code here.
// This is called main0 not main so that it can have
// This is called main0 not main so that it can have
// a void return type. Gcc can't handle functions named
// a void return type. Gcc can't handle functions named
...
@@ -37,7 +39,7 @@ main0(void)
...
@@ -37,7 +39,7 @@ main0(void)
asm
volatile
(
"movl %0, %%ebp"
:
:
"r"
(
cpus
[
bcpu
].
mpstack
+
MPSTACK
));
asm
volatile
(
"movl %0, %%ebp"
:
:
"r"
(
cpus
[
bcpu
].
mpstack
+
MPSTACK
));
lapic_init
(
bcpu
);
lapic_init
(
bcpu
);
cprintf
(
"
\
n
cpu%d: starting xv6
\n
\n
"
,
cpu
());
cprintf
(
"
\
\
ncpu%d: starting xv6
\\
n
\
\
n"
,
cpu
());
pinit
();
// process table
pinit
();
// process table
binit
();
// buffer cache
binit
();
// buffer cache
...
@@ -51,7 +53,7 @@ main0(void)
...
@@ -51,7 +53,7 @@ main0(void)
setupsegs
(
0
);
// segments & TSS
setupsegs
(
0
);
// segments & TSS
console_init
();
// I/O devices & their interrupts
console_init
();
// I/O devices & their interrupts
ide_init
();
// disk
ide_init
();
// disk
mp_startthem
();
//
other CPUs
bootothers
();
// boot
other CPUs
if
(
!
ismp
)
if
(
!
ismp
)
pit8253_timerinit
();
// uniprocessor timer
pit8253_timerinit
();
// uniprocessor timer
userinit
();
// first user process
userinit
();
// first user process
...
@@ -67,7 +69,7 @@ main0(void)
...
@@ -67,7 +69,7 @@ main0(void)
void
void
mpmain
(
void
)
mpmain
(
void
)
{
{
cprintf
(
"cpu%d: starting
\n
"
,
cpu
());
cprintf
(
"cpu%d: starting
\
\
n"
,
cpu
());
idtinit
();
idtinit
();
lapic_init
(
cpu
());
lapic_init
(
cpu
());
setupsegs
(
0
);
setupsegs
(
0
);
...
@@ -82,3 +84,29 @@ mpmain(void)
...
@@ -82,3 +84,29 @@ mpmain(void)
scheduler
();
scheduler
();
}
}
void
bootothers
(
void
)
{
extern
uchar
_binary_bootother_start
[],
_binary_bootother_size
[];
uchar
*
code
;
struct
cpu
*
c
;
// Write bootstrap code to unused memory at 0x7000.
code
=
(
uchar
*
)
0x7000
;
memmove
(
code
,
_binary_bootother_start
,
(
uint
)
_binary_bootother_size
);
for
(
c
=
cpus
;
c
<
cpus
+
ncpu
;
c
++
){
if
(
c
==
cpus
+
cpu
())
// We've started already.
continue
;
// Set target %esp, %eip
*
(
void
**
)(
code
-
4
)
=
c
->
mpstack
+
MPSTACK
;
*
(
void
**
)(
code
-
8
)
=
mpmain
;
lapic_startap
(
c
->
apicid
,
(
uint
)
code
);
// Wait for cpu to get through bootstrap.
while
(
c
->
booted
==
0
)
;
}
}
mp.c
浏览文件 @
99b11b6c
// http://developer.intel.com/design/pentium/datashts/24201606.pdf
#include "types.h"
#include "types.h"
#include "mp.h"
#include "mp.h"
#include "defs.h"
#include "defs.h"
...
@@ -7,52 +9,39 @@
...
@@ -7,52 +9,39 @@
#include "mmu.h"
#include "mmu.h"
#include "proc.h"
#include "proc.h"
static
char
*
buses
[]
=
{
"CBUSI "
,
"CBUSII"
,
"EISA "
,
"FUTURE"
,
"INTERN"
,
"ISA "
,
"MBI "
,
"MBII "
,
"MCA "
,
"MPI "
,
"MPSA "
,
"NUBUS "
,
"PCI "
,
"PCMCIA"
,
"TC "
,
"VL "
,
"VME "
,
"XPRESS"
,
0
,
};
struct
cpu
cpus
[
NCPU
];
struct
cpu
cpus
[
NCPU
];
static
struct
cpu
*
bcpu
;
int
ismp
;
int
ismp
;
int
ncpu
;
int
ncpu
;
uchar
ioapic_id
;
uchar
ioapic_id
;
static
struct
cpu
*
bcpu
;
int
static
struct
mp
*
mp
;
// The floating MP structure
mp_bcpu
(
void
)
{
return
bcpu
-
cpus
;
}
static
uchar
sum
(
uchar
*
addr
,
int
len
)
{
int
i
,
sum
;
sum
=
0
;
for
(
i
=
0
;
i
<
len
;
i
++
)
sum
+=
addr
[
i
];
return
sum
;
}
// Look for an MP structure in the len bytes at addr.
static
struct
mp
*
static
struct
mp
*
mp_s
can
(
uchar
*
addr
,
int
len
)
mp_s
earch1
(
uchar
*
addr
,
int
len
)
{
{
uchar
*
e
,
*
p
,
sum
;
uchar
*
e
,
*
p
;
int
i
;
e
=
addr
+
len
;
e
=
addr
+
len
;
for
(
p
=
addr
;
p
<
e
;
p
+=
sizeof
(
struct
mp
)){
for
(
p
=
addr
;
p
<
e
;
p
+=
sizeof
(
struct
mp
))
if
(
memcmp
(
p
,
"_MP_"
,
4
))
if
(
memcmp
(
p
,
"_MP_"
,
4
)
==
0
&&
sum
(
p
,
sizeof
(
struct
mp
))
==
0
)
continue
;
sum
=
0
;
for
(
i
=
0
;
i
<
sizeof
(
struct
mp
);
i
++
)
sum
+=
p
[
i
];
if
(
sum
==
0
)
return
(
struct
mp
*
)
p
;
return
(
struct
mp
*
)
p
;
}
return
0
;
return
0
;
}
}
...
@@ -68,16 +57,16 @@ mp_search(void)
...
@@ -68,16 +57,16 @@ mp_search(void)
uint
p
;
uint
p
;
struct
mp
*
mp
;
struct
mp
*
mp
;
bda
=
(
uchar
*
)
0x400
;
bda
=
(
uchar
*
)
0x400
;
if
((
p
=
(
bda
[
0x0F
]
<<
8
)
|
bda
[
0x0E
])){
if
((
p
=
(
bda
[
0x0F
]
<<
8
)
|
bda
[
0x0E
])){
if
((
mp
=
mp_s
can
((
uchar
*
)
p
,
1024
)))
if
((
mp
=
mp_s
earch1
((
uchar
*
)
p
,
1024
)))
return
mp
;
return
mp
;
}
else
{
}
else
{
p
=
((
bda
[
0x14
]
<<
8
)
|
bda
[
0x13
])
*
1024
;
p
=
((
bda
[
0x14
]
<<
8
)
|
bda
[
0x13
])
*
1024
;
if
((
mp
=
mp_s
can
((
uchar
*
)
p
-
1024
,
1024
)))
if
((
mp
=
mp_s
earch1
((
uchar
*
)
p
-
1024
,
1024
)))
return
mp
;
return
mp
;
}
}
return
mp_s
can
((
uchar
*
)
0xF0000
,
0x10000
);
return
mp_s
earch1
((
uchar
*
)
0xF0000
,
0x10000
);
}
}
// Search for an MP configuration table. For now,
// Search for an MP configuration table. For now,
...
@@ -85,93 +74,64 @@ mp_search(void)
...
@@ -85,93 +74,64 @@ mp_search(void)
// Check for correct signature, calculate the checksum and,
// Check for correct signature, calculate the checksum and,
// if correct, check the version.
// if correct, check the version.
// To do: check extended table checksum.
// To do: check extended table checksum.
static
int
static
struct
mpconf
*
mp_
detect
(
void
)
mp_
config
(
struct
mp
**
pmp
)
{
{
struct
mpctb
*
pcmp
;
struct
mpconf
*
conf
;
uchar
*
p
,
sum
;
struct
mp
*
mp
;
uint
length
;
if
((
mp
=
mp_search
())
==
0
||
mp
->
physaddr
==
0
)
if
((
mp
=
mp_search
())
==
0
||
mp
->
physaddr
==
0
)
return
-
1
;
pcmp
=
(
struct
mpctb
*
)
mp
->
physaddr
;
if
(
memcmp
(
pcmp
,
"PCMP"
,
4
)
!=
0
)
return
-
1
;
if
(
pcmp
->
version
!=
1
&&
pcmp
->
version
!=
4
)
return
-
1
;
length
=
pcmp
->
length
;
sum
=
0
;
for
(
p
=
(
uchar
*
)
pcmp
;
length
;
length
--
)
sum
+=
*
p
++
;
if
(
sum
!=
0
)
return
-
1
;
return
0
;
return
0
;
conf
=
(
struct
mpconf
*
)
mp
->
physaddr
;
if
(
memcmp
(
conf
,
"PCMP"
,
4
)
!=
0
)
return
0
;
if
(
conf
->
version
!=
1
&&
conf
->
version
!=
4
)
return
0
;
if
(
sum
((
uchar
*
)
conf
,
conf
->
length
)
!=
0
)
return
0
;
*
pmp
=
mp
;
return
conf
;
}
}
void
void
mp_init
(
void
)
mp_init
(
void
)
{
{
int
i
;
uchar
*
p
,
*
e
;
uchar
*
p
,
*
e
;
struct
mp
ctb
*
mpctb
;
struct
mp
*
mp
;
struct
mp
pe
*
proc
;
struct
mp
conf
*
conf
;
struct
mp
be
*
bus
;
struct
mp
proc
*
proc
;
struct
mpioapic
*
ioapic
;
struct
mpioapic
*
ioapic
;
struct
mpie
*
intr
;
ncpu
=
0
;
bcpu
=
&
cpus
[
ncpu
]
;
if
(
mp_detect
()
<
0
)
if
(
(
conf
=
mp_config
(
&
mp
))
==
0
)
return
;
return
;
ismp
=
1
;
ismp
=
1
;
lapic
=
(
uint
*
)
conf
->
lapicaddr
;
// Run through the table saving information needed for starting
for
(
p
=
(
uchar
*
)(
conf
+
1
),
e
=
(
uchar
*
)
conf
+
conf
->
length
;
p
<
e
;
){
// application processors and initialising any I/O APICs. The table
// is guaranteed to be in order such that only one pass is necessary.
mpctb
=
(
struct
mpctb
*
)
mp
->
physaddr
;
lapic
=
(
uint
*
)
mpctb
->
lapicaddr
;
p
=
(
uchar
*
)
mpctb
+
sizeof
(
*
mpctb
);
e
=
(
uchar
*
)
mpctb
+
mpctb
->
length
;
while
(
p
<
e
)
{
switch
(
*
p
){
switch
(
*
p
){
case
MPPROC
ESSOR
:
case
MPPROC
:
proc
=
(
struct
mpp
e
*
)
p
;
proc
=
(
struct
mpp
roc
*
)
p
;
cpus
[
ncpu
].
apicid
=
proc
->
apicid
;
cpus
[
ncpu
].
apicid
=
proc
->
apicid
;
if
(
proc
->
flags
&
MPB
P
)
{
if
(
proc
->
flags
&
MPB
OOT
)
bcpu
=
&
cpus
[
ncpu
];
bcpu
=
&
cpus
[
ncpu
];
}
ncpu
++
;
ncpu
++
;
p
+=
sizeof
(
struct
mppe
);
p
+=
sizeof
(
struct
mpproc
);
continue
;
case
MPBUS
:
bus
=
(
struct
mpbe
*
)
p
;
for
(
i
=
0
;
buses
[
i
];
i
++
){
if
(
strncmp
(
buses
[
i
],
bus
->
string
,
sizeof
(
bus
->
string
))
==
0
)
break
;
}
p
+=
sizeof
(
struct
mpbe
);
continue
;
continue
;
case
MPIOAPIC
:
case
MPIOAPIC
:
ioapic
=
(
struct
mpioapic
*
)
p
;
ioapic
=
(
struct
mpioapic
*
)
p
;
ioapic_id
=
ioapic
->
apicno
;
ioapic_id
=
ioapic
->
apicno
;
p
+=
sizeof
(
struct
mpioapic
);
p
+=
sizeof
(
struct
mpioapic
);
continue
;
continue
;
case
MPBUS
:
case
MPIOINTR
:
case
MPIOINTR
:
intr
=
(
struct
mpie
*
)
p
;
case
MPLINTR
:
p
+=
sizeof
(
struct
mpie
)
;
p
+=
8
;
continue
;
continue
;
default:
default:
cprintf
(
"mp_init: unknown PCMP type 0x%x (e-p 0x%x)
\n
"
,
*
p
,
e
-
p
);
cprintf
(
"mp_init: unknown config type %x
\n
"
,
*
p
);
while
(
p
<
e
){
panic
(
"mp_init"
);
cprintf
(
"%uX "
,
*
p
);
p
++
;
}
break
;
}
}
}
}
...
@@ -182,47 +142,3 @@ mp_init(void)
...
@@ -182,47 +142,3 @@ mp_init(void)
outb
(
0x23
,
inb
(
0x23
)
|
1
);
// Mask external interrupts.
outb
(
0x23
,
inb
(
0x23
)
|
1
);
// Mask external interrupts.
}
}
}
}
int
mp_bcpu
(
void
)
{
if
(
ismp
)
return
bcpu
-
cpus
;
return
0
;
}
extern
void
mpmain
(
void
);
// Write bootstrap code to unused memory at 0x7000.
#define APBOOTCODE 0x7000
void
mp_startthem
(
void
)
{
extern
uchar
_binary_bootother_start
[],
_binary_bootother_size
[];
extern
int
main
();
int
c
;
memmove
((
void
*
)
APBOOTCODE
,
_binary_bootother_start
,
(
uint
)
_binary_bootother_size
);
for
(
c
=
0
;
c
<
ncpu
;
c
++
){
// Our current cpu has already started.
if
(
c
==
cpu
())
continue
;
// Set target %esp
*
(
uint
*
)(
APBOOTCODE
-
4
)
=
(
uint
)
(
cpus
[
c
].
mpstack
)
+
MPSTACK
;
// Set target %eip
*
(
uint
*
)(
APBOOTCODE
-
8
)
=
(
uint
)
mpmain
;
// Go!
lapic_startap
(
cpus
[
c
].
apicid
,
(
uint
)
APBOOTCODE
);
// Wait for cpu to get through bootstrap.
while
(
cpus
[
c
].
booted
==
0
)
;
}
}
mp.h
浏览文件 @
99b11b6c
// See MultiProcessor Specification Version 1.[14]
.
// See MultiProcessor Specification Version 1.[14]
struct
mp
{
// floating pointer
struct
mp
{
// floating pointer
uchar
signature
[
4
];
// "_MP_"
uchar
signature
[
4
];
// "_MP_"
...
@@ -11,7 +11,7 @@ struct mp { // floating pointer
...
@@ -11,7 +11,7 @@ struct mp { // floating pointer
uchar
reserved
[
3
];
uchar
reserved
[
3
];
};
};
struct
mpc
tb
{
// configuration table header
struct
mpc
onf
{
// configuration table header
uchar
signature
[
4
];
// "PCMP"
uchar
signature
[
4
];
// "PCMP"
ushort
length
;
// total table length
ushort
length
;
// total table length
uchar
version
;
// [14]
uchar
version
;
// [14]
...
@@ -26,22 +26,17 @@ struct mpctb { // configuration table header
...
@@ -26,22 +26,17 @@ struct mpctb { // configuration table header
uchar
reserved
;
uchar
reserved
;
};
};
struct
mpp
e
{
// processor table entry
struct
mpp
roc
{
// processor table entry
uchar
type
;
// entry type (0)
uchar
type
;
// entry type (0)
uchar
apicid
;
// local APIC id
uchar
apicid
;
// local APIC id
uchar
version
;
// local APIC verison
uchar
version
;
// local APIC verison
uchar
flags
;
// CPU flags
uchar
flags
;
// CPU flags
#define MPBOOT 0x02 // This proc is the bootstrap processor.
uchar
signature
[
4
];
// CPU signature
uchar
signature
[
4
];
// CPU signature
uint
feature
;
// feature flags from CPUID instruction
uint
feature
;
// feature flags from CPUID instruction
uchar
reserved
[
8
];
uchar
reserved
[
8
];
};
};
struct
mpbe
{
// bus table entry
uchar
type
;
// entry type (1)
uchar
busno
;
// bus id
char
string
[
6
];
// bus type string
};
struct
mpioapic
{
// I/O APIC table entry
struct
mpioapic
{
// I/O APIC table entry
uchar
type
;
// entry type (2)
uchar
type
;
// entry type (2)
uchar
apicno
;
// I/O APIC id
uchar
apicno
;
// I/O APIC id
...
@@ -50,69 +45,10 @@ struct mpioapic { // I/O APIC table entry
...
@@ -50,69 +45,10 @@ struct mpioapic { // I/O APIC table entry
uint
*
addr
;
// I/O APIC address
uint
*
addr
;
// I/O APIC address
};
};
struct
mpie
{
// interrupt table entry
// Table entry types
uchar
type
;
// entry type ([34])
#define MPPROC 0x00 // One per processor
uchar
intr
;
// interrupt type
#define MPBUS 0x01 // One per bus
ushort
flags
;
// interrupt flag
#define MPIOAPIC 0x02 // One per I/O APIC
uchar
busno
;
// source bus id
#define MPIOINTR 0x03 // One per bus interrupt source
uchar
irq
;
// source bus irq
#define MPLINTR 0x04 // One per system interrupt source
uchar
apicno
;
// destination APIC id
uchar
intin
;
// destination APIC [L]INTIN#
};
enum
{
// table entry types
MPPROCESSOR
=
0x00
,
// one entry per processor
MPBUS
=
0x01
,
// one entry per bus
MPIOAPIC
=
0x02
,
// one entry per I/O APIC
MPIOINTR
=
0x03
,
// one entry per bus interrupt source
MPLINTR
=
0x04
,
// one entry per system interrupt source
MPSASM
=
0x80
,
MPHIERARCHY
=
0x81
,
MPCBASM
=
0x82
,
// PCMPprocessor and PCMPioapic flags
MPEN
=
0x01
,
// enabled
MPBP
=
0x02
,
// bootstrap processor
// PCMPiointr and PCMPlintr flags
MPPOMASK
=
0x03
,
// polarity conforms to bus specs
MPHIGH
=
0x01
,
// active high
MPLOW
=
0x03
,
// active low
MPELMASK
=
0x0C
,
// trigger mode of APIC input signals
MPEDGE
=
0x04
,
// edge-triggered
MPLEVEL
=
0x0C
,
// level-triggered
// PCMPiointr and PCMPlintr interrupt type
MPINT
=
0x00
,
// vectored interrupt from APIC Rdt
MPNMI
=
0x01
,
// non-maskable interrupt
MPSMI
=
0x02
,
// system management interrupt
MPExtINT
=
0x03
,
// vectored interrupt from external PIC
};
// Common bits for
// I/O APIC Redirection Table Entry;
// Local APIC Local Interrupt Vector Table;
// Local APIC Inter-Processor Interrupt;
// Local APIC Timer Vector Table.
enum
{
APIC_FIXED
=
0x00000000
,
// [10:8] Delivery Mode
APIC_LOWEST
=
0x00000100
,
// Lowest priority
APIC_SMI
=
0x00000200
,
// System Management Interrupt
APIC_RR
=
0x00000300
,
// Remote Read
APIC_NMI
=
0x00000400
,
APIC_INIT
=
0x00000500
,
// INIT/RESET
APIC_STARTUP
=
0x00000600
,
// Startup IPI
APIC_EXTINT
=
0x00000700
,
APIC_PHYSICAL
=
0x00000000
,
// [11] Destination Mode (RW)
APIC_LOGICAL
=
0x00000800
,
APIC_DELIVS
=
0x00001000
,
// [12] Delivery Status (RO)
APIC_HIGH
=
0x00000000
,
// [13] Interrupt Input Pin Polarity (RW)
APIC_LOW
=
0x00002000
,
APIC_REMOTEIRR
=
0x00004000
,
// [14] Remote IRR (RO)
APIC_EDGE
=
0x00000000
,
// [15] Trigger Mode (RW)
APIC_LEVEL
=
0x00008000
,
APIC_IMASK
=
0x00010000
,
// [16] Interrupt Mask
};
编写
预览
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论