Skip to content

Resource Management

opencode-agent[bot] edited this page May 10, 2026 · 2 revisions

Resource-Management

How JNode drivers claim and release hardware resources (IRQ, I/O, DMA, memory) to avoid conflicts and enable device access.

Overview

JNode provides a platform-independent resource management framework under core/src/core/org/jnode/system/resource/. Drivers use ResourceManager to claim exclusive access to hardware resources before performing I/O operations. The framework prevents conflicts by tracking allocations in linked lists and throwing ResourceNotFreeException on duplicate claims.

The resource system covers four hardware resource types:

  • I/O ports — ISA/PCI port ranges for device registers, accessed via inPortByte/Word/Dword and outPortByte/Word/Dword
  • IRQ lines — Hardware interrupt request lines with optional sharing, dispatched via IRQThread to IRQHandler callbacks
  • DMA channels — x86 DMA controller channels 0-7 with address/page register setup and transfer modes
  • Memory regions — MMIO regions and buffer memory with hierarchical child resource support

Key Components

Class / File Role
Resource.java Base interface; defines getOwner(), release(), getParent()
ResourceOwner.java Identifies who owns a resource; SYSTEM singleton for kernel, SimpleResourceOwner for drivers
IOResource.java I/O port access; getStartPort(), getLength(), raw inPort*()/outPort*() methods
IRQResource.java Interrupt handling; getIRQ(), isShared()
IRQHandler.java Callback interface; handleInterrupt(int irq) — runs with interrupts disabled
DMAResource.java DMA channel; setup(), enable(), getLength(), MODE_READ/MODE_WRITE
MemoryResource.java Memory region access; read/write primitives (getInt, setByte, etc.), child resource support
ResourceManager.java Main entry point; bound in InitialNaming as ResourceManager.class; claim*() methods
DMAManager.java DMA channel allocation interface; claimDMAChannel()
ResourceNotFreeException.java Thrown when a resource is already claimed
ResourcePermission.java Java Security permission for resource access
ResourceManagerImpl.java (org.jnode.vm) Main implementation; singleton with initialize()
IOResourceImpl.java (org.jnode.vm) I/O port resource implementation; extends Region with static linked list tracking
IRQManager.java (org.jnode.vm.scheduler) IRQ handler registration and dispatch; claimIRQ() creates IRQThread
X86IRQManager.java (org.jnode.vm.x86) x86 IRQ manager; integrates with PIC8259A for EOI (End Of Interrupt)
DMAPlugin.java (org.jnode.system.x86) x86 DMA plugin; manages channels 0-7, pre-creates channel 4 as cascade
DMA.java (org.jnode.system.x86) x86 DMA controller access; address/page register I/O, 16MB address limit
X86DMAChannel.java (org.jnode.system.x86) Per-channel DMA implementation; delegates to DMAPlugin
DMAConstants.java (org.jnode.system.x86) I/O port addresses for both DMA controllers, mode constants, page registers
IRQThread.java (org.jnode.vm.scheduler) Thread that waits for IRQ signal, dispatches to registered handlers
MemoryScanner.java Scans physical memory for device information

How It Works

Resource Allocation Lifecycle

1. Driver obtains ResourceManager from InitialNaming
   └─ InitialNaming.get(ResourceManager.class)

2. Driver claims resource
   └─ ResourceManager.claimIOResource(owner, startPort, length)
   └─ ResourceManager.claimIRQ(owner, irq, handler, shared)
   └─ ResourceManager.claimMemoryResource(owner, start, size, mode)
   └─ DMAManager.claimDMAChannel(owner, dmanr)
   └─ Throws ResourceNotFreeException if already in use

3. Driver uses resource via interface methods
   └─ IOResource: outPortByte(port, value)
   └─ IRQResource: handler invoked on interrupt (keep short!)
   └─ MemoryResource: setInt(offset, value), copy(src, dst, size)
   └─ DMAResource: setup(memory, len, mode), enable()

4. Driver releases resource
   └─ resource.release()
   └─ Resource removed from global tracking list
   └─ Memory child resources cascade release to parent

I/O Port Resources

IOResourceImpl extends Region and maintains a static linked list of all claimed port ranges. The claim operation synchronizes access and validates port ranges with testPort().

ResourceManager rm = (ResourceManager) InitialNaming.get(ResourceManager.class);
IOResource io = rm.claimIOResource(this, 0x3F8, 8);
io.outPortByte(0, (byte) 0x55);  // Write to port 0x3F8
// ... use the port ...
io.release();

IRQ Resources

IRQManager (in org.jnode.vm.scheduler) manages IRQ handler registration. When claimIRQ() is called, it either creates a new IRQThread (starts the thread) or adds the handler to an existing thread if sharing is allowed. Supports shared IRQs by maintaining a list of handlers per IRQ line. When an interrupt fires, IRQManager.dispatchInterrupts() signals the appropriate IRQThread which calls all registered handlers.

X86IRQManager extends IRQManager and integrates with PIC8259A for End Of Interrupt (EOI) signaling. The abstract eoi(int irq) method is implemented by the x86 subclass.

IRQResource irq = rm.claimIRQ(this, 12, new IRQHandler() {
    public void handleInterrupt(int irq) {
        // handle the interrupt — keep this short!
    }
}, false);
int irqNum = irq.getIRQ();  // returns 12
irq.release();

DMA Resources

The x86 DMA system uses two cascaded 8237 DMA controllers:

  • Controller 1: Channels 0-3, I/O ports 0x00-0x0F (address/count) and 0x80-0x83 (page registers)
  • Controller 2: Channels 4-7, I/O ports 0xC0-0xCF (address/count) and 0x84-0x86,0x89-0x8A (page registers)

Channel 4 is reserved as the cascade channel (connects controller 2 to controller 1). Channels 0-3 are 8-bit; channels 5-7 are 16-bit.

The DMAPlugin (org.jnode.system.x86) pre-creates channel 4 as cascade at startup. DMA transfers are limited to the lower 16MB of physical memory (addressed via page registers + 8-bit address registers = 24-bit physical address).

DMAManager dmaManager = (DMAManager) InitialNaming.get(DMAManager.NAME);
DMAResource dma = dmaManager.claimDMAChannel(this, 2);
MemoryResource buf = rm.asMemoryResource(byteArray);
dma.setup(buf, 1024, DMAResource.MODE_READ);
dma.enable();
// ... DMA transfers ...
dma.release();

Memory Resources

MemoryResourceImpl supports hierarchical parent-child relationships. Child resources are allocated from free sub-regions of the parent. Release cascades: children must be released before the parent (enforced by parent tracking). claimChildResource() supports alignment and overlap options.

MemoryResource mmio = rm.claimMemoryResource(this, 0xFED00000L, 0x10000, ResourceManager.MEMMODE_NORMAL);
// Read a 32-bit register at offset 0x10
int val = mmio.getInt(0x10);
// Claim a sub-region (child)
MemoryResource child = mmio.claimChildResource(0x1000, 0x100);
child.release();  // release child first
mmio.release();   // then release parent

ResourceOwner

Every claim requires a ResourceOwner to identify the consumer. Use SimpleResourceOwner for one-off drivers or define a custom class.

ResourceOwner owner = new SimpleResourceOwner("MyDeviceDriver");
IOResource io = rm.claimIOResource(owner, startPort, length);

ResourceOwner.SYSTEM is reserved for kernel-level resources.

Gotchas & Non-Obvious Behavior

  • IRQ handler brevity: IRQHandler.handleInterrupt() runs with interrupts disabled. Keep it as short as possible — signal a thread, set a flag, or push data to a queue. Never block or perform long I/O.
  • Memory child release order: Children must be released before their parent. The parent tracks children and the release will throw if children remain.
  • DMA channel 4 is reserved: Do not claim channel 4 — it's the cascading channel for the secondary DMA controller.
  • 8-bit vs 16-bit DMA: Channels 0-3 are 8-bit (channels 0-3 use DMA controller 1); channels 5-7 are 16-bit (use controller 2). Claiming a 16-bit operation on an 8-bit channel will fail.
  • DMA 16MB limit: Physical addresses above 16MB cannot be used for DMA without bounce buffering, as page registers provide only 8 bits of the 24-bit address.
  • Shared IRQ caveat: isShared() only reports whether sharing was requested at claim time. Actual sharing depends on hardware and wiring.
  • SecurityManager checks: ResourceManagerImpl checks IOPORTS_PERM and MEMSCAN_PERM before granting access if a SecurityManager is installed.
  • Static resource lists: IOResourceImpl uses a static linked list to track allocations. This means I/O port claims persist across isolate boundaries.
  • InitialNaming binding: ResourceManager is bound as ResourceManager.class in InitialNaming, not as a string key.
  • Port range validation: IOResourceImpl.testPort() throws IndexOutOfBoundsException if an out-of-range port is accessed — the port must be within [startPort, startPort + length).
  • IRQ thread creation: IRQManager.claimIRQ() creates and starts a new IRQThread synchronously. The first claim for an IRQ will block briefly while the thread starts.

Related Pages

  • Driver-Framework — Parent hub page for device driver architecture
  • Interrupt-Handling — How hardware IRQs are dispatched through the IDT, PIC/APIC to handlers
  • Bus-Drivers — PCI and USB bus drivers that allocate IRQ/IO/DMA resources
  • Architecture — System overview and subsystem interactions

Clone this wiki locally