📄 mk_deviceprivs.cxx
字号:
/* * Copyright (C) 2001, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * This program 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 2, * or (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <kerninc/kernel.hxx>#include <kerninc/Key.hxx>#include <kerninc/Invocation.hxx>#include <kerninc/Thread.hxx>#include <kerninc/ThreadPile.hxx>#include <kerninc/IRQ.hxx>#include <kerninc/PhysMem.hxx>#include <disk/DiskKey.hxx>#include <kerninc/BootInfo.h>#include <kerninc/ObjectSource.hxx>#include <kerninc/ObjectCache.hxx>#include <eros/target.h>#include <eros/Invoke.h>#include <eros/StdKeyType.h>#if 0#include <kerninc/MsgLog.hxx>#include <kerninc/Thread.hxx>#include <eros/StdKeyType.h>#include <eros/DiscrimKey.h>#include <kerninc/Persist.hxx>#endif#include <eros/DevicePrivs.h>#define dbg_wakeup 0x1u#define dbg_alloc 0x2u#define dbg_sleep 0x4u#define dbg_error 0x8u/* Following should be an OR of some of the above */#define dbg_flags ( 0u )#define DEBUG(x) if (dbg_##x & dbg_flags)struct UserIrq { bool isPending; bool isAlloc; ThreadPile sleepers;} UserIrqEntries[NUM_HW_INTERRUPT];static voidDoUsermodeInterrupt(fixregs_t *ia){ uint32_t irq = IRQ_FROM_EXCEPTION(ia->ExceptNo); UserIrq& uirq = UserIrqEntries[irq]; assert(IRQ::GetHandler(irq) == DoUsermodeInterrupt); DEBUG(wakeup) printf("Waking sleepers for IRQ %d\n", irq); uirq.isPending = true; uirq.sleepers.WakeAll();}voidDevicePrivsKey(Invocation& inv){ if (inv.entry.code != OC_DevPrivs_WaitIRQ) COMMIT_POINT(); unsigned irq = inv.entry.w1; /* NOTE: we haven't yet range checked irq, because this isn't used * in all paths, so the resulting reference may well be out of * range. Must range check before using. */ UserIrq& uirq = UserIrqEntries[irq]; switch(inv.entry.code) { case OC_DevPrivs_AllocIRQ: { DEBUG(alloc) printf("DevPrivs: Allocating IRQ %d\n", irq); if (irq >= NUM_HW_INTERRUPT) { inv.exit.code = RC_RequestError; break; } if (uirq.isAlloc || IRQ::GetHandler(irq) != IRQ::UnboundInterrupt) { inv.exit.code = RC_DevPrivs_AllocFail; break; } uirq.isPending = false; IRQ::SetHandler(irq, DoUsermodeInterrupt); IRQ::Enable(irq);#if 0 static bool WireShared(IntAction*); static void Unwire(IntAction*);#endif } inv.exit.code = RC_OK; break; case OC_DevPrivs_ReleaseIRQ: { if (irq >= NUM_HW_INTERRUPT) { inv.exit.code = RC_RequestError; break; } if (!uirq.isAlloc) { inv.exit.code = RC_DevPrivs_AllocFail; break; } IRQ::UnsetHandler(irq); uirq.isPending = false; inv.exit.code = RC_OK; break; } case OC_DevPrivs_EnableIRQ: { if (irq >= NUM_HW_INTERRUPT) { inv.exit.code = RC_RequestError; break; } if (!uirq.isAlloc) { inv.exit.code = RC_DevPrivs_AllocFail; break; } IRQ::Enable(irq); inv.exit.code = RC_OK; break; } case OC_DevPrivs_DisableIRQ: { if (irq >= NUM_HW_INTERRUPT) { inv.exit.code = RC_RequestError; break; } if (!uirq.isAlloc) { inv.exit.code = RC_DevPrivs_AllocFail; break; } IRQ::Disable(irq); inv.exit.code = RC_OK; break; } case OC_DevPrivs_WaitIRQ: { IRQ::Enable(irq); IRQ::DISABLE(); if (irq < NUM_HW_INTERRUPT && !uirq.isPending) { DEBUG(sleep) printf("DevPrivs: Sleeping for IRQ %d\n", irq); Thread::Current()->SleepOn(uirq.sleepers); IRQ::ENABLE(); Thread::Current()->Yield(); } IRQ::ENABLE(); COMMIT_POINT(); if (irq >= NUM_HW_INTERRUPT) { DEBUG(error) printf("IRQ %d is invalid, bogon\n", irq); inv.exit.code = RC_RequestError; break; } assert(uirq.isPending); DEBUG(sleep) printf("IRQ %d was pending already\n", irq); IRQ::DISABLE(); uirq.isPending = false; IRQ::ENABLE(); /* Else return RC_OK per below */ inv.exit.code = RC_OK; break; } case OC_DevPrivs_PublishMem: { kpa_t base = inv.entry.w1; kpa_t bound = inv.entry.w2; bool readOnly = inv.entry.w3; if ((base % EROS_PAGE_SIZE) || (bound % EROS_PAGE_SIZE)) { inv.exit.code = RC_RequestError; break; } if (base >= bound) { inv.exit.code = RC_RequestError; break; } PmemInfo *pmi = PhysMem::AddRegion(base, bound, MI_DEVICEMEM, readOnly); if (pmi) { ObjectSource *source; ObjectCache::AddDevicePages(pmi); source = new ((void *) 1) PhysPageSource(pmi); ObjectCache::AddSource(source); inv.exit.code = RC_OK; } else { inv.exit.code = RC_NoAccess; } break; } case OC_KeyType: inv.exit.code = RC_OK; inv.exit.w1 = inv.keyType; break; default: inv.exit.code = RC_UnknownRequest; break; } return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -