- char dcss_name[8];
- struct list_head *l;
- struct dcss_segment *seg, *tmp;
- unsigned long dummy;
- unsigned long segstart, segend;
- int rc = 0,i;
- int rwattr, shattr;
-
- if (!MACHINE_IS_VM)
- return -ENOSYS;
- dcss_mkname(name, dcss_name);
- /* search for the dcss in list of currently loaded segments */
- spin_lock(&dcss_lock);
- seg = NULL;
- list_for_each(l, &dcss_list) {
- tmp = list_entry(l, struct dcss_segment, list);
- if (memcmp(tmp->dcss_name, dcss_name, 8) == 0) {
- seg = tmp;
- break;
- }
- }
-
- if (seg == NULL) {
- /* find out the attributes of this
- shared segment */
- dcss_diag_query(dcss_name, &rwattr, &shattr, &segstart, &segend);
- /* does segment collide with main memory? */
- for (i=0; i < MEMORY_CHUNKS; i++) {
- if (memory_chunk[i].type != 0)
- continue;
- if (memory_chunk[i].addr > segend)
- continue;
- if (memory_chunk[i].addr + memory_chunk[i].size <= segstart)
- continue;
- spin_unlock(&dcss_lock);
- return -ENOENT;
- }
- /* or does it collide with other (loaded) segments? */
- list_for_each(l, &dcss_list) {
- tmp = list_entry(l, struct dcss_segment, list);
- if ((segstart <= tmp->end && segstart >= tmp->start_addr) ||
- (segend <= tmp->end && segend >= tmp->start_addr) ||
- (segstart <= tmp->start_addr && segend >= tmp->end)) {
- PRINT_ERR("Segment Overlap!\n");
- spin_unlock(&dcss_lock);
- return -ENOENT;
- }
- }
-
- /* do case statement on segtype */
- /* if asking for shared ro,
- shared rw works */
- /* if asking for exclusive ro,
- exclusive rw works */
-
- switch(segtype) {
- case SEGMENT_SHARED_RO:
- if (shattr > 1 || rwattr > 1) {
- spin_unlock(&dcss_lock);
- return -ENOENT;
- } else {
- if (shattr == 0 && rwattr == 0)
- rc = SEGMENT_EXCLUSIVE_RO;
- if (shattr == 0 && rwattr == 1)
- rc = SEGMENT_EXCLUSIVE_RW;
- if (shattr == 1 && rwattr == 0)
- rc = SEGMENT_SHARED_RO;
- if (shattr == 1 && rwattr == 1)
- rc = SEGMENT_SHARED_RW;
- }
- break;
- case SEGMENT_SHARED_RW:
- if (shattr > 1 || rwattr != 1) {
- spin_unlock(&dcss_lock);
- return -ENOENT;
- } else {
- if (shattr == 0)
- rc = SEGMENT_EXCLUSIVE_RW;
- if (shattr == 1)
- rc = SEGMENT_SHARED_RW;
- }
- break;
-
- case SEGMENT_EXCLUSIVE_RO:
- if (shattr > 0 || rwattr > 1) {
- spin_unlock(&dcss_lock);
- return -ENOENT;
- } else {
- if (rwattr == 0)
- rc = SEGMENT_EXCLUSIVE_RO;
- if (rwattr == 1)
- rc = SEGMENT_EXCLUSIVE_RW;
- }
- break;
-
- case SEGMENT_EXCLUSIVE_RW:
-/* if (shattr != 0 || rwattr != 1) {
- spin_unlock(&dcss_lock);
- return -ENOENT;
- } else {
-*/
- rc = SEGMENT_EXCLUSIVE_RW;
-// }
- break;
-
- default:
- spin_unlock(&dcss_lock);
- return -ENOENT;
- } /* end switch */
-
- seg = kmalloc(sizeof(struct dcss_segment), GFP_DMA);
- if (seg != NULL) {
- memcpy(seg->dcss_name, dcss_name, 8);
- if (rc == SEGMENT_EXCLUSIVE_RW) {
- if (dcss_diag(DCSS_LOADNSR, seg->dcss_name,
- &seg->start_addr, &seg->end) == 0) {
- if (seg->end < max_low_pfn*PAGE_SIZE ) {
- atomic_set(&seg->ref_count, 1);
- list_add(&seg->list, &dcss_list);
- *addr = seg->start_addr;
- *end = seg->end;
- seg->dcss_attr = rc;
- if (shattr == 1 && rwattr == 1)
- seg->shared_attr = SEGMENT_SHARED_RW;
- else if (shattr == 1 && rwattr == 0)
- seg->shared_attr = SEGMENT_SHARED_RO;
- else
- seg->shared_attr = SEGMENT_EXCLUSIVE_RW;
- } else {
- dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
- kfree (seg);
- rc = -ENOENT;
- }
- } else {
- kfree(seg);
- rc = -ENOENT;
- }
- goto out;
- }
- if (dcss_diag(DCSS_LOADNOLY, seg->dcss_name,
- &seg->start_addr, &seg->end) == 0) {
- if (seg->end < max_low_pfn*PAGE_SIZE ) {
- atomic_set(&seg->ref_count, 1);
- list_add(&seg->list, &dcss_list);
- *addr = seg->start_addr;
- *end = seg->end;
- seg->dcss_attr = rc;
- seg->shared_attr = rc;
- } else {
- dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
- kfree (seg);
- rc = -ENOENT;
- }
- } else {
- kfree(seg);
- rc = -ENOENT;
- }
- } else rc = -ENOMEM;
- } else {
- /* found */
- if ((segtype == SEGMENT_EXCLUSIVE_RW) && (seg->dcss_attr != SEGMENT_EXCLUSIVE_RW)) {
- PRINT_ERR("Segment already loaded in other mode than EXCLUSIVE_RW!\n");
- rc = -EPERM;
- goto out;
- /* reload segment in exclusive mode */
-/* dcss_diag(DCSS_LOADNSR, seg->dcss_name,
- &seg->start_addr, &seg->end);
- seg->dcss_attr = SEGMENT_EXCLUSIVE_RW;*/