# Conflicts: # crate/memory/src/cow.rs # crate/memory/src/memory_set.rs # crate/memory/src/paging/mod.rs # crate/memory/src/swap/mod.rs # crate/process/src/lib.rs # crate/process/src/process_manager.rs # crate/process/src/processor.rs # crate/process/src/thread.rs # crate/riscv # kernel/Cargo.lock # kernel/src/arch/riscv32/compiler_rt.rs # kernel/src/arch/riscv32/consts.rs # kernel/src/arch/riscv32/context.rs # kernel/src/arch/riscv32/interrupt.rs # kernel/src/arch/riscv32/memory.rs # kernel/src/arch/riscv32/mod.rs # kernel/src/arch/riscv32/paging.rs # kernel/src/arch/x86_64/driver/ide.rs # kernel/src/arch/x86_64/interrupt/handler.rs # kernel/src/arch/x86_64/mod.rs # kernel/src/console.rs # kernel/src/consts.rs # kernel/src/fs.rs # kernel/src/lib.rs # kernel/src/memory.rs # kernel/src/process/context.rs # kernel/src/process/mod.rs # kernel/src/syscall.rs # kernel/src/trap.rsmaster
commit
205f90a264
@ -1,3 +0,0 @@
|
||||
[submodule "crate/riscv"]
|
||||
path = crate/riscv
|
||||
url = https://github.com/riscv-and-rust-and-decaf/riscv.git
|
@ -1,15 +0,0 @@
|
||||
use core::fmt::Debug;
|
||||
|
||||
/// Get values by 2 diff keys at the same time
|
||||
pub trait GetMut2<Idx: Debug + Eq> {
|
||||
type Output;
|
||||
fn get_mut(&mut self, id: Idx) -> &mut Self::Output;
|
||||
fn get_mut2(&mut self, id1: Idx, id2: Idx) -> (&mut Self::Output, &mut Self::Output) {
|
||||
assert_ne!(id1, id2);
|
||||
let self1 = self as *mut Self;
|
||||
let self2 = self1;
|
||||
let p1 = unsafe { &mut *self1 }.get_mut(id1);
|
||||
let p2 = unsafe { &mut *self2 }.get_mut(id2);
|
||||
(p1, p2)
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
Subproject commit a37a65fa13a00c5aa0068c3f2b5d55af6a37dd93
|
Binary file not shown.
@ -0,0 +1,57 @@
|
||||
--- atomic_backup.rs 2018-10-06 19:59:14.000000000 +0800
|
||||
+++ atomic.rs 2018-10-26 14:34:31.000000000 +0800
|
||||
@@ -125,6 +125,9 @@
|
||||
#[cfg(target_has_atomic = "8")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct AtomicBool {
|
||||
+ #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||
+ v: UnsafeCell<u32>,
|
||||
+ #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
|
||||
v: UnsafeCell<u8>,
|
||||
}
|
||||
|
||||
@@ -265,6 +268,44 @@
|
||||
pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
#[cfg(target_has_atomic = "8")]
|
||||
+#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||
+impl AtomicBool {
|
||||
+ ///
|
||||
+ #[inline]
|
||||
+ #[stable(feature = "rust1", since = "1.0.0")]
|
||||
+ pub const fn new(v: bool) -> AtomicBool {
|
||||
+ AtomicBool { v: UnsafeCell::new(v as u32) }
|
||||
+ }
|
||||
+
|
||||
+ ///
|
||||
+ #[inline]
|
||||
+ #[stable(feature = "rust1", since = "1.0.0")]
|
||||
+ pub fn load(&self, order: Ordering) -> bool {
|
||||
+ unsafe { atomic_load(self.v.get(), order) != 0 }
|
||||
+ }
|
||||
+
|
||||
+ ///
|
||||
+ #[inline]
|
||||
+ #[stable(feature = "rust1", since = "1.0.0")]
|
||||
+ pub fn store(&self, val: bool, order: Ordering) {
|
||||
+ unsafe { atomic_store(self.v.get(), val as u32, order); }
|
||||
+ }
|
||||
+
|
||||
+ ///
|
||||
+ #[inline]
|
||||
+ #[stable(feature = "rust1", since = "1.0.0")]
|
||||
+ #[cfg(target_has_atomic = "cas")]
|
||||
+ pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
|
||||
+ loop {
|
||||
+ if let Ok(val) = unsafe { atomic_compare_exchange(self.v.get(), current as u32, new as u32, order, order) } {
|
||||
+ return val != 0;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#[cfg(target_has_atomic = "8")]
|
||||
+#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
|
||||
impl AtomicBool {
|
||||
/// Creates a new `AtomicBool`.
|
||||
///
|
@ -0,0 +1,38 @@
|
||||
// http://llvm.org/docs/Atomics.html#libcalls-atomic
|
||||
|
||||
int __atomic_load_4(int *src) {
|
||||
int res = 0;
|
||||
__asm__ __volatile__("amoadd.w.rl %0, zero, (%1)" : "=r"(res) : "r"(src) : "memory");
|
||||
return res;
|
||||
}
|
||||
|
||||
int __atomic_store_4(int *dst, int val) {
|
||||
__asm__ __volatile__("amoswap.w.aq zero, %0, (%1)" :: "r"(val), "r"(dst) : "memory");
|
||||
}
|
||||
|
||||
char __atomic_compare_exchange_4(int* dst, int* expected, int desired) {
|
||||
int val;
|
||||
// val = *dst
|
||||
__asm__ __volatile__("lr.w %0, (%1)" : "=r"(val) : "r"(dst) : "memory");
|
||||
if (val == *expected) {
|
||||
int result;
|
||||
// Try: *dst = desired. If success, result = 0, otherwise result != 0.
|
||||
__asm__ __volatile__("sc.w %0, %1, (%2)" : "=r"(result) : "r"(desired), "r"(dst) : "memory");
|
||||
return result == 0;
|
||||
}
|
||||
// *expected should always equal to the previous value of *dst
|
||||
*expected = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __atomic_fetch_add_4(int* ptr, int val) {
|
||||
int res;
|
||||
__asm__ __volatile__("amoadd.w.rl %0, %1, (%2)" : "=r"(res) : "r"(val), "r"(ptr) : "memory");
|
||||
return res;
|
||||
}
|
||||
|
||||
int __atomic_fetch_sub_4(int* ptr, int val) {
|
||||
int res;
|
||||
__asm__ __volatile__("amoadd.w.rl %0, %1, (%2)" : "=r"(res) : "r"(-val), "r"(ptr) : "memory");
|
||||
return res;
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
//! Migrate from xv6 ioapic.c
|
||||
|
||||
/// The I/O APIC manages hardware interrupts for an SMP system.
|
||||
/// http://www.intel.com/design/chipsets/datashts/29056601.pdf
|
||||
/// See also picirq.c.
|
||||
|
||||
use super::super::redox_syscall::io::{Io, Mmio};
|
||||
use bit_field::BitField;
|
||||
use arch::interrupt::consts::T_IRQ0;
|
||||
use spin::Mutex;
|
||||
|
||||
pub fn init()
|
||||
{
|
||||
let mut ioapic = IOAPIC.lock();
|
||||
|
||||
// Mark all interrupts edge-triggered, active high, disabled,
|
||||
// and not routed to any CPUs.
|
||||
for i in 0.. ioapic.maxintr() + 1 {
|
||||
ioapic.write_irq(i, RedirectionEntry::DISABLED, 0);
|
||||
}
|
||||
info!("ioapic: init end");
|
||||
}
|
||||
|
||||
const IOAPIC_ADDRESS : u32 = 0xFEC00000; // Default physical address of IO APIC
|
||||
|
||||
const REG_ID : u8 = 0x00; // Register index: ID
|
||||
const REG_VER : u8 = 0x01; // Register index: version
|
||||
const REG_TABLE : u8 = 0x10; // Redirection table base
|
||||
|
||||
// The redirection table starts at REG_TABLE and uses
|
||||
// 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.
|
||||
|
||||
bitflags! {
|
||||
struct RedirectionEntry: u32 {
|
||||
const DISABLED = 0x00010000; // Interrupt disabled
|
||||
const LEVEL = 0x00008000; // Level-triggered (vs edge-)
|
||||
const ACTIVELOW = 0x00002000; // Active low (vs high)
|
||||
const LOGICAL = 0x00000800; // Destination is CPU id (vs APIC ID)
|
||||
const NONE = 0x00000000;
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref IOAPIC: Mutex<IoApic> = Mutex::new(unsafe{IoApic::new()});
|
||||
}
|
||||
|
||||
// IO APIC MMIO structure: write reg, then read or write data.
|
||||
#[repr(C)]
|
||||
struct IoApicMmio {
|
||||
reg: Mmio<u32>,
|
||||
pad: [Mmio<u32>; 3],
|
||||
data: Mmio<u32>,
|
||||
}
|
||||
|
||||
pub struct IoApic {
|
||||
mmio: &'static mut IoApicMmio
|
||||
}
|
||||
|
||||
impl IoApic {
|
||||
unsafe fn new() -> Self {
|
||||
IoApic { mmio: &mut *(IOAPIC_ADDRESS as *mut IoApicMmio) }
|
||||
}
|
||||
fn read(&mut self, reg: u8) -> u32
|
||||
{
|
||||
self.mmio.reg.write(reg as u32);
|
||||
self.mmio.data.read()
|
||||
}
|
||||
fn write(&mut self, reg: u8, data: u32)
|
||||
{
|
||||
self.mmio.reg.write(reg as u32);
|
||||
self.mmio.data.write(data);
|
||||
}
|
||||
fn write_irq(&mut self, irq: u8, flags: RedirectionEntry, dest: u8)
|
||||
{
|
||||
self.write(REG_TABLE+2*irq, (T_IRQ0 + irq) as u32 | flags.bits());
|
||||
self.write(REG_TABLE+2*irq+1, (dest as u32) << 24);
|
||||
}
|
||||
pub fn enable(&mut self, irq: u8, cpunum: u8)
|
||||
{
|
||||
info!("ioapic: enable irq {} @ cpu{}", irq, cpunum);
|
||||
// Mark interrupt edge-triggered, active high,
|
||||
// enabled, and routed to the given cpunum,
|
||||
// which happens to be that cpu's APIC ID.
|
||||
self.write_irq(irq, RedirectionEntry::NONE, cpunum);
|
||||
}
|
||||
fn id(&mut self) -> u8 {
|
||||
self.read(REG_ID).get_bits(24..28) as u8
|
||||
}
|
||||
fn version(&mut self) -> u8 {
|
||||
self.read(REG_VER).get_bits(0..8) as u8
|
||||
}
|
||||
fn maxintr(&mut self) -> u8 {
|
||||
self.read(REG_VER).get_bits(16..24) as u8
|
||||
}
|
||||
}
|
@ -1,165 +0,0 @@
|
||||
// The local APIC manages internal (non-I/O) interrupts.
|
||||
// See Chapter 8 & Appendix C of Intel processor manual volume 3.
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned short ushort;
|
||||
|
||||
static inline void
|
||||
outb(ushort port, uchar data)
|
||||
{
|
||||
asm volatile("out %0,%1" : : "a" (data), "d" (port));
|
||||
}
|
||||
|
||||
#define KERNBASE 0xFFFFFF0000000000 // First kernel virtual address
|
||||
#define P2V(a) (((void *) (a)) + KERNBASE)
|
||||
|
||||
#define T_IRQ0 32 // IRQ 0 corresponds to int T_IRQ
|
||||
|
||||
#define IRQ_TIMER 0
|
||||
#define IRQ_KBD 1
|
||||
#define IRQ_COM1 4
|
||||
#define IRQ_IDE 14
|
||||
#define IRQ_ERROR 19
|
||||
#define IRQ_SPURIOUS 31
|
||||
|
||||
// Local APIC registers, divided by 4 for use as uint[] indices.
|
||||
#define ID (0x0020/4) // ID
|
||||
#define VER (0x0030/4) // Version
|
||||
#define TPR (0x0080/4) // Task Priority
|
||||
#define EOI (0x00B0/4) // EOI
|
||||
#define SVR (0x00F0/4) // Spurious Interrupt Vector
|
||||
#define ENABLE 0x00000100 // Unit Enable
|
||||
#define ESR (0x0280/4) // Error Status
|
||||
#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 DEASSERT 0x00000000
|
||||
#define LEVEL 0x00008000 // Level triggered
|
||||
#define BCAST 0x00080000 // Send to all APICs, including self.
|
||||
#define BUSY 0x00001000
|
||||
#define FIXED 0x00000000
|
||||
#define ICRHI (0x0310/4) // Interrupt Command [63:32]
|
||||
#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 LINT0 (0x0350/4) // Local Vector Table 1 (LINT0)
|
||||
#define LINT1 (0x0360/4) // Local Vector Table 2 (LINT1)
|
||||
#define ERROR (0x0370/4) // Local Vector Table 3 (ERROR)
|
||||
#define MASKED 0x00010000 // Interrupt masked
|
||||
#define TICR (0x0380/4) // Timer Initial Count
|
||||
#define TCCR (0x0390/4) // Timer Current Count
|
||||
#define TDCR (0x03E0/4) // Timer Divide Configuration
|
||||
|
||||
volatile uint *lapic; // Initialized in mp.c
|
||||
|
||||
static void
|
||||
lapicw(int index, int value)
|
||||
{
|
||||
lapic[index] = value;
|
||||
lapic[ID]; // wait for write to finish, by reading
|
||||
}
|
||||
//PAGEBREAK!
|
||||
|
||||
void
|
||||
lapicinit(void)
|
||||
{
|
||||
if(!lapic)
|
||||
return;
|
||||
|
||||
// Enable local APIC; set spurious interrupt vector.
|
||||
lapicw(SVR, ENABLE | (T_IRQ0 + IRQ_SPURIOUS));
|
||||
|
||||
// The timer repeatedly counts down at bus frequency
|
||||
// from lapic[TICR] and then issues an interrupt.
|
||||
// If xv6 cared more about precise timekeeping,
|
||||
// TICR would be calibrated using an external time source.
|
||||
lapicw(TDCR, X1);
|
||||
lapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER));
|
||||
lapicw(TICR, 10000000);
|
||||
|
||||
// Disable logical interrupt lines.
|
||||
lapicw(LINT0, MASKED);
|
||||
lapicw(LINT1, MASKED);
|
||||
|
||||
// Disable performance counter overflow interrupts
|
||||
// on machines that provide that interrupt entry.
|
||||
if(((lapic[VER]>>16) & 0xFF) >= 4)
|
||||
lapicw(PCINT, MASKED);
|
||||
|
||||
// Map error interrupt to IRQ_ERROR.
|
||||
lapicw(ERROR, T_IRQ0 + IRQ_ERROR);
|
||||
|
||||
// Clear error status register (requires back-to-back writes).
|
||||
lapicw(ESR, 0);
|
||||
lapicw(ESR, 0);
|
||||
|
||||
// Ack any outstanding interrupts.
|
||||
lapicw(EOI, 0);
|
||||
|
||||
// Send an Init Level De-Assert to synchronise arbitration ID's.
|
||||
lapicw(ICRHI, 0);
|
||||
lapicw(ICRLO, BCAST | INIT | LEVEL);
|
||||
while(lapic[ICRLO] & DELIVS)
|
||||
;
|
||||
|
||||
// Enable interrupts on the APIC (but not on the processor).
|
||||
lapicw(TPR, 0);
|
||||
}
|
||||
|
||||
// Acknowledge interrupt.
|
||||
void
|
||||
lapiceoi(void)
|
||||
{
|
||||
if(lapic)
|
||||
lapicw(EOI, 0);
|
||||
}
|
||||
|
||||
// Spin for a given number of microseconds.
|
||||
// On real hardware would want to tune this dynamically.
|
||||
void
|
||||
microdelay(int us)
|
||||
{
|
||||
}
|
||||
|
||||
#define CMOS_PORT 0x70
|
||||
#define CMOS_RETURN 0x71
|
||||
|
||||
// Start additional processor running entry code at addr.
|
||||
// See Appendix B of MultiProcessor Specification.
|
||||
void
|
||||
lapicstartap(uchar apicid, uint addr)
|
||||
{
|
||||
int i;
|
||||
ushort *wrv;
|
||||
|
||||
// "The BSP must initialize CMOS shutdown code to 0AH
|
||||
// and the warm reset vector (DWORD based at 40:67) to point at
|
||||
// the AP startup code prior to the [universal startup algorithm]."
|
||||
outb(CMOS_PORT, 0xF); // offset 0xF is shutdown code
|
||||
outb(CMOS_PORT+1, 0x0A);
|
||||
wrv = (ushort*)P2V((0x40<<4 | 0x67)); // Warm reset vector
|
||||
wrv[0] = 0;
|
||||
wrv[1] = addr >> 4;
|
||||
|
||||
// "Universal startup algorithm."
|
||||
// Send INIT (level-triggered) interrupt to reset other CPU.
|
||||
lapicw(ICRHI, apicid<<24);
|
||||
lapicw(ICRLO, INIT | LEVEL | ASSERT);
|
||||
microdelay(200);
|
||||
lapicw(ICRLO, INIT | LEVEL);
|
||||
microdelay(10000);
|
||||
|
||||
// Send startup IPI (twice!) to enter code.
|
||||
// Regular hardware is supposed to only accept a STARTUP
|
||||
// when it is in the halted state due to an INIT. So the second
|
||||
// should be ignored, but it is part of the official Intel algorithm.
|
||||
for(i = 0; i < 2; i++){
|
||||
lapicw(ICRHI, apicid<<24);
|
||||
lapicw(ICRLO, STARTUP | (addr>>12));
|
||||
microdelay(200);
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
extern {
|
||||
//noinspection RsStaticConstNaming
|
||||
static mut lapic: *const ();
|
||||
fn lapicinit(); // must set `lapic` first
|
||||
fn lapiceoi(); // ack
|
||||
fn lapicstartap(apicid: u8, addr: u32);
|
||||
}
|
||||
|
||||
pub fn set_addr(lapic_addr: usize) {
|
||||
unsafe {
|
||||
// lapic = lapic_addr;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
warn!("lapic::init use C lib");
|
||||
unsafe {
|
||||
// lapicinit();
|
||||
}
|
||||
info!("lapic: init end");
|
||||
}
|
||||
|
||||
pub fn ack(_irq: u8) {
|
||||
unsafe {
|
||||
// lapiceoi();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_ap(apicid: u8, addr: u32) {
|
||||
warn!("lapic::start_ap use C lib");
|
||||
unsafe {
|
||||
// lapicstartap(apicid, addr);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lapic_id() -> u8 {
|
||||
0
|
||||
// unsafe{
|
||||
// if lapic.is_null() {
|
||||
// warn!("lapic is null. return lapic id = 0");
|
||||
// return 0;
|
||||
// }
|
||||
// let ptr = (lapic as *const u32).offset(0x0020 / 4);
|
||||
// (ptr.read_volatile() >> 24) as u8
|
||||
// }
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
use core::intrinsics::{volatile_load, volatile_store};
|
||||
use x86::cpuid::CpuId;
|
||||
use x86::msr::*;
|
||||
|
||||
use memory::Frame;
|
||||
use paging::{ActivePageTable, PhysAddr, Page, VirtualAddress};
|
||||
use paging::entry::EntryFlags;
|
||||
|
||||
pub static mut LOCAL_APIC: LocalApic = LocalApic {
|
||||
address: 0,
|
||||
x2: false
|
||||
};
|
||||
|
||||
pub unsafe fn init(active_table: &mut ActivePageTable) {
|
||||
LOCAL_APIC.init(active_table);
|
||||
}
|
||||
|
||||
pub unsafe fn init_ap() {
|
||||
LOCAL_APIC.init_ap();
|
||||
}
|
||||
|
||||
/// Local APIC
|
||||
pub struct LocalApic {
|
||||
pub address: usize,
|
||||
pub x2: bool
|
||||
}
|
||||
|
||||
impl LocalApic {
|
||||
unsafe fn init(&mut self, active_table: &mut ActivePageTable) {
|
||||
self.address = (rdmsr(IA32_APIC_BASE) as usize & 0xFFFF_0000) + ::KERNEL_OFFSET;
|
||||
self.x2 = CpuId::new().get_feature_info().unwrap().has_x2apic();
|
||||
|
||||
if ! self.x2 {
|
||||
let page = Page::containing_address(VirtualAddress::new(self.address));
|
||||
let frame = Frame::containing_address(PhysAddr::new(self.address - ::KERNEL_OFFSET));
|
||||
let result = active_table.map_to(page, frame, EntryFlags::PRESENT | EntryFlags::WRITABLE | EntryFlags::NO_EXECUTE);
|
||||
result.flush(active_table);
|
||||
}
|
||||
|
||||
self.init_ap();
|
||||
}
|
||||
|
||||
unsafe fn init_ap(&mut self) {
|
||||
if self.x2 {
|
||||
wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 10);
|
||||
wrmsr(IA32_X2APIC_SIVR, 0x100);
|
||||
} else {
|
||||
self.write(0xF0, 0x100);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn read(&self, reg: u32) -> u32 {
|
||||
volatile_load((self.address + reg as usize) as *const u32)
|
||||
}
|
||||
|
||||
unsafe fn write(&mut self, reg: u32, value: u32) {
|
||||
volatile_store((self.address + reg as usize) as *mut u32, value);
|
||||
}
|
||||
|
||||
pub fn id(&self) -> u32 {
|
||||
if self.x2 {
|
||||
unsafe { rdmsr(IA32_X2APIC_APICID) as u32 }
|
||||
} else {
|
||||
unsafe { self.read(0x20) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn version(&self) -> u32 {
|
||||
if self.x2 {
|
||||
unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 }
|
||||
} else {
|
||||
unsafe { self.read(0x30) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn icr(&self) -> u64 {
|
||||
if self.x2 {
|
||||
unsafe { rdmsr(IA32_X2APIC_ICR) }
|
||||
} else {
|
||||
unsafe {
|
||||
(self.read(0x310) as u64) << 32 | self.read(0x300) as u64
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_icr(&mut self, value: u64) {
|
||||
if self.x2 {
|
||||
unsafe { wrmsr(IA32_X2APIC_ICR, value); }
|
||||
} else {
|
||||
unsafe {
|
||||
while self.read(0x300) & 1 << 12 == 1 << 12 {}
|
||||
self.write(0x310, (value >> 32) as u32);
|
||||
self.write(0x300, value as u32);
|
||||
while self.read(0x300) & 1 << 12 == 1 << 12 {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ipi(&mut self, apic_id: usize) {
|
||||
let mut icr = 0x4040;
|
||||
if self.x2 {
|
||||
icr |= (apic_id as u64) << 32;
|
||||
} else {
|
||||
icr |= (apic_id as u64) << 56;
|
||||
}
|
||||
self.set_icr(icr);
|
||||
}
|
||||
|
||||
pub unsafe fn eoi(&mut self) {
|
||||
if self.x2 {
|
||||
wrmsr(IA32_X2APIC_EOI, 0);
|
||||
} else {
|
||||
self.write(0xB0, 0);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
pub use self::ioapic::IOAPIC;
|
||||
pub use self::lapic::{ack, start_ap, lapic_id};
|
||||
|
||||
mod lapic;
|
||||
mod ioapic;
|
||||
|
||||
pub fn init() {
|
||||
assert_has_not_been_called!("apic::init must be called only once");
|
||||
use consts::KERNEL_OFFSET;
|
||||
self::lapic::set_addr(KERNEL_OFFSET + 0xfee00000);
|
||||
self::lapic::init();
|
||||
self::ioapic::init();
|
||||
}
|
||||
|
||||
pub fn other_init() {
|
||||
self::lapic::init();
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
use arch::driver::{acpi::AcpiResult, apic::start_ap};
|
||||
use consts::MAX_CPU_NUM;
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
use memory::*;
|
||||
use x86_64::registers::control::Cr3;
|
||||
|
||||
pub const ENTRYOTHER_ADDR: usize = 0x7000;
|
||||
|
||||
pub fn start_other_cores(acpi: &AcpiResult) {
|
||||
let args = unsafe { &mut *(0x8000 as *mut EntryArgs).offset(-1) };
|
||||
for i in 1 .. acpi.cpu_num {
|
||||
let apic_id = acpi.cpu_acpi_ids[i as usize];
|
||||
let ms = MemorySet::new();
|
||||
*args = EntryArgs {
|
||||
kstack: ms.kstack_top() as u64,
|
||||
page_table: Cr3::read().0.start_address().as_u64() as u32,
|
||||
stack: args as *const _ as u32, // just enough stack to get us to entry64mp
|
||||
};
|
||||
unsafe { MS = Some(ms); }
|
||||
start_ap(apic_id, ENTRYOTHER_ADDR as u32);
|
||||
while unsafe { !read_volatile(&STARTED[i as usize]) } {}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
struct EntryArgs {
|
||||
kstack: u64,
|
||||
page_table: u32,
|
||||
stack: u32,
|
||||
}
|
||||
|
||||
static mut STARTED: [bool; MAX_CPU_NUM] = [false; MAX_CPU_NUM];
|
||||
static mut MS: Option<MemorySet> = None;
|
||||
|
||||
pub unsafe fn notify_started(cpu_id: u8) -> MemorySet {
|
||||
write_volatile(&mut STARTED[cpu_id as usize], true);
|
||||
let ms = MS.take().unwrap();
|
||||
ms.activate();
|
||||
ms
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
use core::ops::Deref;
|
||||
use alloc::string::String;
|
||||
use arch::io::getchar;
|
||||
use alloc::collections::VecDeque;
|
||||
use sync::Condvar;
|
||||
use sync::SpinNoIrqLock as Mutex;
|
||||
|
||||
pub fn get_line() -> String {
|
||||
let mut s = String::new();
|
||||
loop {
|
||||
let c = get_char();
|
||||
match c {
|
||||
'\u{7f}' /* '\b' */ => {
|
||||
if s.pop().is_some() {
|
||||
print!("\u{7f}");
|
||||
}
|
||||
}
|
||||
' '...'\u{7e}' => {
|
||||
s.push(c);
|
||||
print!("{}", c);
|
||||
}
|
||||
'\n' | '\r' => {
|
||||
print!("\n");
|
||||
return s;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct InputQueue {
|
||||
buf: Mutex<VecDeque<char>>,
|
||||
pushed: Condvar,
|
||||
}
|
||||
impl InputQueue {
|
||||
pub fn push(&self, c: char) {
|
||||
self.buf.lock().push_back(c);
|
||||
self.pushed.notify_one();
|
||||
}
|
||||
pub fn pop(&self) -> char {
|
||||
loop {
|
||||
let ret = self.buf.lock().pop_front();
|
||||
match ret {
|
||||
Some(c) => return c,
|
||||
None => self.pushed._wait(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lazy_static! {
|
||||
pub static ref CONSOLE_INPUT: InputQueue = InputQueue::default();
|
||||
}
|
||||
pub fn get_char() -> char {
|
||||
CONSOLE_INPUT.pop()
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
//! Kernel shell
|
||||
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use fs::{ROOT_INODE, INodeExt};
|
||||
use process::*;
|
||||
|
||||
pub fn run_user_shell() {
|
||||
let inode = ROOT_INODE.lookup("sh").unwrap();
|
||||
let data = inode.read_as_vec().unwrap();
|
||||
processor().manager().add(ContextImpl::new_user(data.as_slice(), "sh".split(' ')));
|
||||
}
|
||||
|
||||
pub fn shell() {
|
||||
let files = ROOT_INODE.list().unwrap();
|
||||
println!("Available programs: {:?}", files);
|
||||
|
||||
loop {
|
||||
print!(">> ");
|
||||
let cmd = get_line();
|
||||
if cmd == "" {
|
||||
continue;
|
||||
}
|
||||
let name = cmd.split(' ').next().unwrap();
|
||||
if let Ok(file) = ROOT_INODE.lookup(name) {
|
||||
let data = file.read_as_vec().unwrap();
|
||||
let pid = processor().manager().add(ContextImpl::new_user(data.as_slice(), cmd.split(' ')));
|
||||
unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap();
|
||||
} else {
|
||||
println!("Program not exist");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_line() -> String {
|
||||
let mut s = String::new();
|
||||
loop {
|
||||
let c = get_char();
|
||||
match c {
|
||||
'\u{7f}' /* '\b' */ => {
|
||||
if s.pop().is_some() {
|
||||
print!("\u{7f}");
|
||||
}
|
||||
}
|
||||
' '...'\u{7e}' => {
|
||||
s.push(c);
|
||||
print!("{}", c);
|
||||
}
|
||||
'\n' | '\r' => {
|
||||
print!("\n");
|
||||
return s;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_char() -> char {
|
||||
::fs::STDIN.pop()
|
||||
}
|
Loading…
Reference in new issue