diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/kernel/devicesegment.H | 35 | ||||
-rw-r--r-- | src/include/kernel/segmentmgr.H | 36 | ||||
-rw-r--r-- | src/include/kernel/vmmmgr.H | 9 | ||||
-rw-r--r-- | src/include/usr/vmmconst.h | 8 | ||||
-rw-r--r-- | src/kernel/devicesegment.C | 50 | ||||
-rw-r--r-- | src/kernel/segmentmgr.C | 48 | ||||
-rw-r--r-- | src/kernel/vmmmgr.C | 42 | ||||
-rw-r--r-- | src/usr/intr/intrrp.C | 24 | ||||
-rw-r--r-- | src/usr/testcore/kernel/segmenttest.H | 29 |
9 files changed, 183 insertions, 98 deletions
diff --git a/src/include/kernel/devicesegment.H b/src/include/kernel/devicesegment.H index c60619705..dcaf78af8 100644 --- a/src/include/kernel/devicesegment.H +++ b/src/include/kernel/devicesegment.H @@ -35,9 +35,14 @@ class DeviceSegment : public Segment { public: /** - * @brief Constructor (Device segment at 2TB) + * @brief Constructor (Device segment at 2TB + N) + * + * @param[in] segId - Segment ID to map this device segment at. + * + * Associates itself with the SegmentManager. */ - DeviceSegment() : Segment(VMM_VADDR_DEVICE_SEGMENT) {}; + explicit DeviceSegment(size_t segId) : Segment(segId * TERABYTE) + { init(segId); }; /** * @brief Destructor @@ -45,9 +50,9 @@ class DeviceSegment : public Segment ~DeviceSegment() {}; /** - * @brief Add the device segment + * @brief Add the device segment to the SegmentManager. */ - static void init(); + void init(size_t segId); /** * @brief Handle a page fault for a device address access @@ -60,19 +65,19 @@ class DeviceSegment : public Segment /** - * @brief Map a device into the device segment(2TB) + * @brief Map a device into the device segment. * @param ra[in] - Void pointer to real address to be mapped in * @param i_devDataSize[in] - Size of device segment block * @return void* - Pointer to beginning virtual address, NULL otherwise */ - static void* devMap(void* ra, uint64_t i_devDataSize); + void* devMap(void* ra, uint64_t i_devDataSize); /** - * @brief Unmap a device from the device segment(2TB) + * @brief Unmap a device from the device segment. * @param ea[in] - Void pointer to effective address * @return int - 0 for successful unmap, non-zero otherwise */ - static int devUnmap(void* ea); + int devUnmap(void* ea); private: /** @@ -100,20 +105,6 @@ class DeviceSegment : public Segment */ void _init(); - /** - * @brief Map a device into the device segment(2TB) - * @param ra[in] - Void pointer to real address to be mapped in - * @param i_devDataSize[in] - Size of device segment block - * @return void* - Pointer to beginning virtual address, NULL otherwise - */ - void* _devMap(void* ra, uint64_t i_devDataSize); - - /** - * @brief Unmap a device from the device segment(2TB) - * @param ea[in] - Void pointer to effective address - * @return int - 0 for successful unmap, non-zero otherwise - */ - int _devUnmap(void* ea); }; #endif diff --git a/src/include/kernel/segmentmgr.H b/src/include/kernel/segmentmgr.H index d2e4be2df..85ecf3269 100644 --- a/src/include/kernel/segmentmgr.H +++ b/src/include/kernel/segmentmgr.H @@ -51,17 +51,18 @@ class SegmentManager BASE_SEGMENT_ID = 0, /** Task Stack Segment (1-2TB). */ STACK_SEGMENT_ID = 1, - /** MMIO Space Segment (2-3TB). */ - MMIO_SEGMENT_ID = 2, + /** MMIO Space Segments (2-11TB). */ + MMIO_FIRST_SEGMENT_ID = 2, + MMIO_LAST_SEGMENT_ID = MMIO_FIRST_SEGMENT_ID + 8, - MAX_SEGMENTS = 4 + MAX_SEGMENTS = 16 }; enum { CI_ACCESS = 0xFFFFFFFF // Set to all F's to identify this type - }; + }; /** * Constructor. Initializes instance variables. @@ -130,12 +131,30 @@ class SegmentManager */ static void castOutPages(uint64_t i_type); + /** + * @brief Map a device into the device segment + * @param ra[in] - Void pointer to real address to be mapped in + * @param i_devDataSize[in] - Size of device segment block + * @return void* - Pointer to beginning virtual address, NULL otherwise + */ + static void* devMap(void* ra, uint64_t i_devDataSize); + + /** + * @brief Unmap a device from the device segment + * @param ea[in] - Void pointer to effective address + * @return int - 0 for successful unmap, non-zero otherwise + */ + static int devUnmap(void* ea); + + private: /** See handlePageFault. */ bool _handlePageFault(task_t* i_task, uint64_t i_addr); /** See addSegment. */ void _addSegment(Segment* i_segment, size_t i_segId); + /** See getSegment. */ + Segment* _getSegment(size_t i_segId); /** See initSLB. */ void _initSLB(); /** See updateRefCount. */ @@ -143,14 +162,19 @@ class SegmentManager PageTableManager::UsageStats_t i_stats ); /** See castOutPages */ void _castOutPages(uint64_t i_type); + /** See devMap */ + void* _devMap(void* ra, uint64_t i_devDataSize); + /** See devUnmap */ + int _devUnmap(void* ea); + /** See findPhysicalAddress */ uint64_t _findPhysicalAddress(uint64_t i_vaddr) const; ALWAYS_INLINE - size_t getSegmentIdFromAddress(uint64_t i_addr) const + static size_t getSegmentIdFromAddress(uint64_t i_addr) { - return i_addr >> SLBE_s; + return i_addr >> SLBE_s; } /** Array of segment objects to associated segment IDs. */ diff --git a/src/include/kernel/vmmmgr.H b/src/include/kernel/vmmmgr.H index 3782bb762..46f283e18 100644 --- a/src/include/kernel/vmmmgr.H +++ b/src/include/kernel/vmmmgr.H @@ -86,7 +86,7 @@ class VmmManager static bool pteMiss(task_t* t, uint64_t effAddr); /** - * @brief Map a device into the device segment(2TB) + * @brief Map a device into the device segment * @param ra[in] - Void pointer to real address to be mapped in * @param i_devDataSize[in] - Size of device segment block * @return void* - Pointer to beginning virtual address, NULL otherwise @@ -94,7 +94,7 @@ class VmmManager static void* devMap(void* ra, uint64_t i_devDataSize); /** - * @brief Unmap a device from the device segment(2TB) + * @brief Unmap a device from the device segment * @param ea[in] - Void pointer to effective address * @return int - 0 for successful unmap, non-zero otherwise */ @@ -198,6 +198,11 @@ class VmmManager int _mmRemovePages(VmmManager::PAGE_REMOVAL_OPS i_op,void* i_vaddr, uint64_t i_size,task_t* i_task); + /** See devMap */ + void* _devMap(void* ra, uint64_t i_devDataSize); + /** See devUnmap */ + int _devUnmap(void* ea); + public: friend class Block; friend class StackSegment; diff --git a/src/include/usr/vmmconst.h b/src/include/usr/vmmconst.h index f490f1301..5036b8146 100644 --- a/src/include/usr/vmmconst.h +++ b/src/include/usr/vmmconst.h @@ -37,8 +37,10 @@ /** Stack Segment is at 1 TB */ #define VMM_VADDR_STACK_SEGMENT (1 * TERABYTE) -/** Device Segment is at 2 TB */ -#define VMM_VADDR_DEVICE_SEGMENT (2 * TERABYTE) +/** Device Segments are at 2 TB - 10 TB */ +#define VMM_VADDR_DEVICE_SEGMENT_FIRST (2 * TERABYTE) +#define VMM_VADDR_DEVICE_SEGMENT_LAST (VMM_VADDR_DEVICE_SEGMENT_FIRST + \ + (8 * TERABYTE)) /** @@ -54,7 +56,7 @@ /** Attribute Resource Provider */ // Note: Not simplified to make it easier to extract with the PNOR targeting -// image generator script +// image generator script #define VMM_VADDR_ATTR_RP (3ul * 1024ul * 1024ul * 1024ul) /** Virtual memory block priorities */ diff --git a/src/kernel/devicesegment.C b/src/kernel/devicesegment.C index 479183d4c..fae4b7032 100644 --- a/src/kernel/devicesegment.C +++ b/src/kernel/devicesegment.C @@ -22,6 +22,7 @@ // IBM_PROLOG_END #include <util/singleton.H> #include <limits.h> +#include <assert.h> #include <kernel/vmmmgr.H> #include <kernel/ptmgr.H> @@ -31,38 +32,14 @@ #include <kernel/console.H> /** - * STATIC - * @brief Add the device segment + * @brief Add the device segment to the SegmentManager. */ -void DeviceSegment::init() +void DeviceSegment::init(size_t segId) { - Singleton<DeviceSegment>::instance()._init(); -} - -/** - * STATIC - * @brief Map a device into the device segment(2TB) - */ -void* DeviceSegment::devMap(void *ra, uint64_t i_devDataSize) -{ - return Singleton<DeviceSegment>::instance()._devMap(ra,i_devDataSize); -} - -/** - * STATIC - * @brief Unmap a device from the device segment(2TB) - */ -int DeviceSegment::devUnmap(void *ea) -{ - return Singleton<DeviceSegment>::instance()._devUnmap(ea); -} + kassert((segId >= SegmentManager::MMIO_FIRST_SEGMENT_ID) && + (segId <= SegmentManager::MMIO_LAST_SEGMENT_ID)); -/** - * @brief Add the device segment - */ -void DeviceSegment::_init() -{ - SegmentManager::addSegment(this, SegmentManager::MMIO_SEGMENT_ID); + SegmentManager::addSegment(this, segId); } /** @@ -101,12 +78,12 @@ bool DeviceSegment::handlePageFault(task_t* i_task, uint64_t i_addr) /** - * @brief Map a device into the device segment(2TB) + * @brief Map a device into the device segment. * @param ra[in] - Void pointer to real address to be mapped in * @param i_devDataSize[in] - Size of device segment block * @return void* - Pointer to beginning virtual address, NULL otherwise */ -void *DeviceSegment::_devMap(void *ra, uint64_t i_devDataSize) +void *DeviceSegment::devMap(void *ra, uint64_t i_devDataSize) { void *segBlock = NULL; if (i_devDataSize <= THIRTYTWO_GB) @@ -125,10 +102,6 @@ void *DeviceSegment::_devMap(void *ra, uint64_t i_devDataSize) break; } } - if (segBlock == NULL) - { - printk("Unable to map device, no empty segment blocks found\n"); - } } else { @@ -139,12 +112,7 @@ void *DeviceSegment::_devMap(void *ra, uint64_t i_devDataSize) return segBlock; } -/** - * @brief Unmap a device from the device segment(2TB) - * @param ea[in] - Void pointer to effective address - * @return int - 0 for successful unmap, non-zero otherwise - */ -int DeviceSegment::_devUnmap(void *ea) +int DeviceSegment::devUnmap(void *ea) { int rc = -EINVAL; uint64_t segment_ea = reinterpret_cast<uint64_t>(ea); diff --git a/src/kernel/segmentmgr.C b/src/kernel/segmentmgr.C index 0b4370cfa..6659c634c 100644 --- a/src/kernel/segmentmgr.C +++ b/src/kernel/segmentmgr.C @@ -24,9 +24,11 @@ #include <errno.h> #include <arch/ppc.H> #include <util/singleton.H> +#include <kernel/console.H> #include <kernel/segmentmgr.H> #include <kernel/segment.H> +#include <kernel/devicesegment.H> bool SegmentManager::handlePageFault(task_t* i_task, uint64_t i_addr) { @@ -60,6 +62,16 @@ void SegmentManager::castOutPages(uint64_t i_type) Singleton<SegmentManager>::instance()._castOutPages(i_type); } +void* SegmentManager::devMap(void* ra, uint64_t i_devDataSize) +{ + return Singleton<SegmentManager>::instance()._devMap(ra, i_devDataSize); +} + +int SegmentManager::devUnmap(void* ea) +{ + return Singleton<SegmentManager>::instance()._devUnmap(ea); +} + bool SegmentManager::_handlePageFault(task_t* i_task, uint64_t i_addr) { size_t segId = getSegmentIdFromAddress(i_addr); @@ -146,3 +158,39 @@ void SegmentManager::_castOutPages(uint64_t i_type) } } } + +void* SegmentManager::_devMap(void* ra, uint64_t i_devDataSize) +{ + void* ea = NULL; + for (size_t i = MMIO_FIRST_SEGMENT_ID; i <= MMIO_LAST_SEGMENT_ID; i++) + { + if (NULL == iv_segments[i]) continue; + + ea = reinterpret_cast<DeviceSegment*>(iv_segments[i])-> + devMap(ra, i_devDataSize); + + if (ea != NULL) break; + } + + if (ea == NULL) + { + printk("SegmentManager: Ran out of device segment blocks.\n"); + } + + return ea; +} + +int SegmentManager::_devUnmap(void* ea) +{ + size_t segId = getSegmentIdFromAddress(reinterpret_cast<uint64_t>(ea)); + if ((segId < MMIO_FIRST_SEGMENT_ID) || + (segId > MMIO_LAST_SEGMENT_ID) || + (NULL == iv_segments[segId])) + { + return -EINVAL; + } + + return reinterpret_cast<DeviceSegment*>(iv_segments[segId])->devUnmap(ea); +} + + diff --git a/src/kernel/vmmmgr.C b/src/kernel/vmmmgr.C index b0fe28415..b1f13f1a3 100644 --- a/src/kernel/vmmmgr.C +++ b/src/kernel/vmmmgr.C @@ -45,7 +45,11 @@ void VmmManager::init() BaseSegment::init(); StackSegment::init(); - DeviceSegment::init(); + for (size_t i = SegmentManager::MMIO_FIRST_SEGMENT_ID; + i < SegmentManager::MMIO_LAST_SEGMENT_ID; ++i) + { + new DeviceSegment(i); // Self-registers with SegmentManager. + } SegmentManager::initSLB(); v.initPTEs(); @@ -82,23 +86,14 @@ void VmmManager::flushPageTable( void ) Singleton<VmmManager>::instance()._flushPageTable(); } - -/** - * STATIC - * @brief A facade to map a device into the device segment(2TB) - */ void* VmmManager::devMap(void* ra, uint64_t i_devDataSize) { - return DeviceSegment::devMap(ra, i_devDataSize); + return Singleton<VmmManager>::instance()._devMap(ra, i_devDataSize); } -/** - * STATIC - * @brief A facade to unmap a device from the device segment(2TB) - */ int VmmManager::devUnmap(void* ea) { - return DeviceSegment::devUnmap(ea); + return Singleton<VmmManager>::instance()._devUnmap(ea); } void VmmManager::initPTEs() @@ -211,3 +206,26 @@ void VmmManager::_flushPageTable( void ) lock.unlock(); } + +void* VmmManager::_devMap(void* ra, uint64_t i_devDataSize) +{ + void* ea = NULL; + + lock.lock(); + ea = SegmentManager::devMap(ra, i_devDataSize); + lock.unlock(); + + return ea; +} + +int VmmManager::_devUnmap(void* ea) +{ + int rc = 0; + + lock.lock(); + rc = SegmentManager::devUnmap(ea); + lock.unlock(); + + return rc; +} + diff --git a/src/usr/intr/intrrp.C b/src/usr/intr/intrrp.C index d328c75ae..5099c437c 100644 --- a/src/usr/intr/intrrp.C +++ b/src/usr/intr/intrrp.C @@ -54,7 +54,7 @@ void IntrRp::init( void * i_taskArgs ) { errlHndl_t err = NULL; err = Singleton<IntrRp>::instance()._init(); - INITSERVICE::TaskArgs* args = + INITSERVICE::TaskArgs* args = static_cast<INITSERVICE::TaskArgs*>(i_taskArgs); if(err) { @@ -68,7 +68,7 @@ void IntrRp::init( void * i_taskArgs ) // BaseAddress: // BA[18:43] = ICPBAR (P8 says [14:43] (30 bits)) // BA[47:49] = COREid (0-7) -// BA[50:51] = cpu thread (0-3) +// BA[50:51] = cpu thread (0-3) // // BA+0 = XIRR (poll - Read/Write has no side effects)) // BA+4 = XIRR (Read locks HW, Write -> EOI to HW)) @@ -108,7 +108,7 @@ errlHndl_t IntrRp::_init() //targetService.masterProcChipTargetHandle( procTarget ); // // TODO What if this does not jive with with the PIR? - + // TODO Does this need to be read here? //err = deviceRead(procTarget, // &realAddr, @@ -116,7 +116,7 @@ errlHndl_t IntrRp::_init() // DEVICE_SCOM_ADDRESS(ICPBAR_SCOM_ADDR)); //if(err) return err; - if(realAddr == 0) + if(realAddr == 0) { realAddr = (static_cast<uint64_t>(ICPBAR_VAL)) << 34; } @@ -132,7 +132,7 @@ errlHndl_t IntrRp::_init() // The realAddr is the base address for the whole system. - // Therefore the realAddr must be based on the processor with + // Therefore the realAddr must be based on the processor with // lowest BAR value in the system. (usually n0p0) // TODO Adjust the realAddr if the BAR came from a processor other // than cpuid 0 @@ -151,7 +151,7 @@ errlHndl_t IntrRp::_init() // Set up the interrupt provider registers // NOTE: Simics only supports 4 threads, and two cores per proc chip. - // + // // NOTE: P7 register address format only supports 4 threads per core. // This will change for P8 // @@ -178,7 +178,7 @@ errlHndl_t IntrRp::_init() // Get the kernel msg queue for ext intr // Create a task to handle the messages - iv_msgQ = msg_q_create(); + iv_msgQ = msg_q_create(); msg_q_register(iv_msgQ, INTR_MSGQ); task_create(IntrRp::msg_handler, NULL); @@ -384,7 +384,7 @@ errlHndl_t IntrRp::registerInterrupt(msg_q_t i_msgQ, ext_intr_t i_type) 0 ); } - + } return err; } @@ -427,11 +427,11 @@ void IntrRp::initInterruptPresenter(const PIR_t i_pir) const // where it started, it gets rejected by hardware. // // According to BOOK IV, The links regs are setup by firmware. - // + // // Should be possible to link all interrupt forwarding directly to // the master core and either make them direct (lspec = 0) or by setting // the LOOPTRIP bit to stop the forwarding at the masterProc. - // + // LinkReg_t linkReg; linkReg.word = 0; linkReg.loopTrip = 1; // needed? @@ -450,7 +450,7 @@ errlHndl_t IntrRp::checkAddress(uint64_t i_addr) { errlHndl_t err = NULL; - if(i_addr < VMM_VADDR_DEVICE_SEGMENT) + if(i_addr < VMM_VADDR_DEVICE_SEGMENT_FIRST) { /*@ errorlog tag * @errortype ERRL_SEV_INFORMATIONAL @@ -480,7 +480,7 @@ errlHndl_t IntrRp::checkAddress(uint64_t i_addr) errlHndl_t INTR::registerMsgQ(msg_q_t i_msgQ, ext_intr_t i_type) { errlHndl_t err = NULL; - // Can't add while handling an interrupt, so + // Can't add while handling an interrupt, so // send msg instead of direct call msg_q_t intr_msgQ = msg_q_resolve(INTR_MSGQ); if(intr_msgQ) diff --git a/src/usr/testcore/kernel/segmenttest.H b/src/usr/testcore/kernel/segmenttest.H index effa34e2e..e5b9ff64a 100644 --- a/src/usr/testcore/kernel/segmenttest.H +++ b/src/usr/testcore/kernel/segmenttest.H @@ -34,6 +34,8 @@ #include <sys/mmio.h> #include <usr/vmmconst.h> +#include <list> + class segmenttest: public CxxTest::TestSuite { public: @@ -82,6 +84,33 @@ class segmenttest: public CxxTest::TestSuite } } + // Verify we can allocate a block from the second device segment. + void testManyDeviceBlocks() + { + std::list<void*> blocks; + + void* block = NULL; + while (reinterpret_cast<uint64_t>(block) + < (VMM_VADDR_DEVICE_SEGMENT_FIRST + TERABYTE)) + { + block = mmio_dev_map(reinterpret_cast<void*>(10 * TERABYTE), + THIRTYTWO_GB); + + if (block == NULL) + { + TS_FAIL("Unable to allocate device block."); + break; + } + blocks.push_back(block); + } + + while(!blocks.empty()) + { + mmio_dev_unmap(blocks.front()); + blocks.pop_front(); + } + } + }; #endif |