diff --git a/src/add-ons/kernel/bus_managers/scsi/busses.cpp b/src/add-ons/kernel/bus_managers/scsi/busses.cpp index 52c599e556..14a09c6310 100644 --- a/src/add-ons/kernel/bus_managers/scsi/busses.cpp +++ b/src/add-ons/kernel/bus_managers/scsi/busses.cpp @@ -217,6 +217,9 @@ scsi_init_bus(device_node *node, void **cookie) if (pnp->get_attr_uint32(node, B_DMA_MAX_SEGMENT_COUNT, &bus->dma_params.max_sg_blocks, true) != B_OK) bus->dma_params.max_sg_blocks = ~0; + if (pnp->get_attr_uint64(node, B_DMA_HIGH_ADDRESS, + &bus->dma_params.high_address, true) != B_OK) + bus->dma_params.high_address = ~0; // do some sanity check: bus->dma_params.max_sg_block_size &= ~bus->dma_params.alignment; diff --git a/src/add-ons/kernel/bus_managers/scsi/dma_buffer.cpp b/src/add-ons/kernel/bus_managers/scsi/dma_buffer.cpp index 8f66bf17a9..b652a25cf8 100644 --- a/src/add-ons/kernel/bus_managers/scsi/dma_buffer.cpp +++ b/src/add-ons/kernel/bus_managers/scsi/dma_buffer.cpp @@ -39,10 +39,10 @@ is_sg_list_dma_safe(scsi_ccb *request) scsi_bus_info *bus = request->bus; const physical_entry *sg_list = request->sg_list; uint32 sg_count = request->sg_count; - uint32 dma_boundary = bus->dma_params.dma_boundary; - uint32 alignment = bus->dma_params.alignment; - uint32 max_sg_block_size = bus->dma_params.max_sg_block_size; - uint32 cur_idx; + const uint32 dma_boundary = bus->dma_params.dma_boundary; + const uint32 alignment = bus->dma_params.alignment; + const uint32 max_sg_block_size = bus->dma_params.max_sg_block_size; + const uint64 high_address = bus->dma_params.high_address; // not too many S/G list entries if (sg_count > bus->dma_params.max_sg_blocks) { @@ -54,8 +54,8 @@ is_sg_list_dma_safe(scsi_ccb *request) if (dma_boundary == ~(uint32)0 && alignment == 0 && max_sg_block_size == 0) return true; - // argh - controller is a bit picky, so make sure he likes us - for (cur_idx = sg_count; cur_idx >= 1; --cur_idx, ++sg_list) { + // argh - controller is a bit picky, so make sure it likes us + for (uint32 cur_idx = sg_count; cur_idx >= 1; --cur_idx, ++sg_list) { phys_addr_t max_len; // calculate space upto next dma boundary crossing and @@ -81,6 +81,12 @@ is_sg_list_dma_safe(scsi_ccb *request) return false; } + if ((sg_list->address + sg_list->size) > high_address) { + SHOW_FLOW(0, "S/G-entry above high address @%" B_PRIxPHYSADDR, + sg_list->address + sg_list->size); + return false; + } + // verify entry size if (sg_list->size > max_sg_block_size) { SHOW_FLOW(0, "S/G-entry is too long (%" B_PRIuPHYSADDR "/%" B_PRIu32 diff --git a/src/add-ons/kernel/bus_managers/scsi/scsi_internal.h b/src/add-ons/kernel/bus_managers/scsi/scsi_internal.h index 9983ad5dca..5113a9d7ce 100644 --- a/src/add-ons/kernel/bus_managers/scsi/scsi_internal.h +++ b/src/add-ons/kernel/bus_managers/scsi/scsi_internal.h @@ -79,6 +79,7 @@ typedef struct dma_params { uint32 dma_boundary; uint32 max_sg_block_size; uint32 max_sg_blocks; + uint64 high_address; } dma_params;