hubble@cae780.TEK.COM (Larry Hubble) (04/30/87)
I have managed to get my root file system to run in extended memory of my AT clone. (NOTE that extended memory, not expanded memory). In addition, I set up one partition of my hard disk to have a 384K copy of the root file system. When booting, the hard disk partition (/dev/hd2 in my case) is copied to the RAM disk which has been moved to extended memory. 384K is large enough that MINIX now runs very well and copying from hard disk during bootup takes only a few seconds. (Of course, now only one floppy disk is required to get MINIX up and running. This required changes to: 1) kernel/memory.c to call new routines to tranfer from extended memory rather than normal RAM. 2) fs/main.c to tell mm that the RAM disk is zero length, copy hard disk for root filesystem, and a new origin for RAM disk. 3) kernel/em_xfer.s is a new routine to transfer to/from extended AT memory 4) kernel/makefile to include em_xfer.s in link of kernel --------------------------------------------------------------------------- Here are the specific changes to kernel/memory.c. Change the last six lines of routine do_mem() to: /* Copy the data. */ if (device != RAM_DEV) { if (m_ptr->m_type == DISK_READ) phys_copy(mem_phys, user_phys, (long) count); else phys_copy(user_phys, mem_phys, (long) count); } else { if (count & 1) panic("RAM disk got odd byte count", m_ptr); words = ( (unsigned)count ) >> 1; if (m_ptr->m_type == DISK_READ) status = em_xfer(mem_phys, user_phys, words); else status = em_xfer(user_phys, mem_phys, words); if (status != 0) count = -1; } return(count); --------------------------------------------------------------------------- Here are the specific changes to fs/main.c. Replace the whole routine load_ram() to (Don't forget to change the define ROOT_COPY for your hard disk, or simply define to BOOT_DEV if you still want to use floppies): #define ROOT_COPY 0x302 /* Copy of root partition on hd part. 2 */ #define EM_ORIGIN 0x0100000 /* Origin of AT extended memory */ PRIVATE load_ram() { /* The root diskette contains a block-by-block image of the root file system * starting at 0. Go get it and copy it to the RAM disk. */ register struct buf *bp, *bp1; int count; long k_loaded; struct super_block *sp; block_nr i; phys_clicks ram_clicks, init_org, init_text_clicks, init_data_clicks; extern phys_clicks data_org[INFO + 2]; extern struct buf *get_block(); /* Get size of INIT by reading block on diskette where 'build' put it. */ init_org = data_org[INFO]; init_text_clicks = data_org[INFO + 1]; init_data_clicks = data_org[INFO + 2]; /* Get size of RAM disk by reading root file system's super block */ bp = get_block(ROOT_COPY, SUPER_BLOCK, NORMAL); /* get RAM super block */ copy(super_block, bp->b_data, sizeof(struct super_block)); sp = &super_block[0]; if (sp->s_magic != SUPER_MAGIC) panic("Diskette in drive 0 is not root file system", NO_NUM); count = sp->s_nzones << sp->s_log_zone_size; /* # blocks on root dev */ if (count > MAX_RAM) panic("RAM disk is too big. # blocks = ", count); ram_clicks = count * (BLOCK_SIZE/CLICK_SIZE); put_block(bp, FULL_DATA_BLOCK); /* Tell MM the origin and size of INIT, and the amount of memory used for the * system plus RAM disk combined, so it can remove all of it from the map. */ m1.m_type = BRK2; m1.m1_i1 = init_text_clicks; m1.m1_i2 = init_data_clicks; m1.m1_i3 = init_org + init_text_clicks + init_data_clicks; m1.m1_p1 = (char *) init_org; if (sendrec(MM_PROC_NR, &m1) != OK) panic("FS Can't report to MM", NO_NUM); /* Tell RAM driver where RAM disk is and how big it is. */ m1.m_type = DISK_IOCTL; m1.DEVICE = RAM_DEV; m1.POSITION = EM_ORIGIN; m1.COUNT = count; if (sendrec(MEM, &m1) != OK) panic("Can't report size to MEM", NO_NUM); /* Copy the blocks one at a time from the root diskette to the RAM */ printf("Loading RAM disk from partition 2 of hard disk. Loaded: 0K "); for (i = 0; i < count; i++) { bp = get_block(ROOT_COPY, (block_nr) i, NORMAL); bp1 = get_block(ROOT_DEV, i, NO_READ); copy(bp1->b_data, bp->b_data, BLOCK_SIZE); bp1->b_dirt = DIRTY; put_block(bp, I_MAP_BLOCK); put_block(bp1, I_MAP_BLOCK); k_loaded = ( (long) i * BLOCK_SIZE)/1024L; /* K loaded so far */ if (k_loaded % 5 == 0) printf("\b\b\b\b\b%3DK %c", k_loaded, 0); } printf("\rRAM disk loaded. It resides in AT Extended memory. \n\n"); } ---------------------------------------------------------------------------- And finally, the new routine: |--------------------------------------------------------------------------- | New routine kernel/em_xfer.s |--------------------------------------------------------------------------- | | This file contains one routine which transfers words between user memory | and extended memory on an AT or clone. A BIOS call (INT 15h, Func 87h) | is used to accomplish the transfer. The BIOS call is "faked" by pushing | the processor flags on the stack and then doing a far call to the actual | BIOS location. An actual INT 15h would get a MINIX complaint from an | unexpected trap. | | NOTE: WARNING: CAUTION: ... | Before using this routine, you must find your BIOS address for INT 15h. | The debug command "d 0:54 57" will give you the segment and address of | the BIOS call. On my machine this generates: | 0000:0050 59 F8 00 F0 Y... | These values are then plugged into the two strange ".word xxxx" lines | near the end of this routine. They correspond to offset=0xf859 and | seg=0xf000. The offset is the first two bytes and the segment is the | last two bytes (Note the byte swap). | | This particular BIOS routine runs with interrupts off since the 80286 | must be placed in protected mode to access the memory above 1 Mbyte. | So there should be no problems using the BIOS call. | .text gdt: | Begin global descriptor table | Dummy descriptor .word 0 | segment length (limit) .word 0 | bits 15-0 of physical address .byte 0 | bits 23-16 of physical address .byte 0 | access rights byte .word 0 | reserved | descriptor for GDT itself .word 0 | segment length (limit) .word 0 | bits 15-0 of physical address .byte 0 | bits 23-16 of physical address .byte 0 | access rights byte .word 0 | reserved src: | source descriptor srcsz: .word 0 | segment length (limit) srcl: .word 0 | bits 15-0 of physical address srch: .byte 0 | bits 23-16 of physical address .byte 0x93 | access rights byte .word 0 | reserved tgt: | target descriptor tgtsz: .word 0 | segment length (limit) tgtl: .word 0 | bits 15-0 of physical address tgth: .byte 0 | bits 23-16 of physical address .byte 0x93 | access rights byte .word 0 | reserved | BIOS CS descriptor .word 0 | segment length (limit) .word 0 | bits 15-0 of physical address .byte 0 | bits 23-16 of physical address .byte 0 | access rights byte .word 0 | reserved | stack segment descriptor .word 0 | segment length (limit) .word 0 | bits 15-0 of physical address .byte 0 | bits 23-16 of physical address .byte 0 | access rights byte .word 0 | reserved | | | Execute a transfer between user memory and extended memory. | | status = em_xfer(source, dest, count); | | Where: | status => return code (0 => OK) | source => Physical source address (32-bit) | dest => Physical destination address (32-bit) | count => Number of words to transfer | | | .globl _em_xfer _em_xfer: | push bp | Save registers mov bp,sp push si push es push cx | | Pick up source and destination addresses and update descriptor tables | mov ax,4(bp) seg cs mov srcl,ax mov ax,6(bp) seg cs movb srch,al mov ax,8(bp) seg cs mov tgtl,ax mov ax,10(bp) seg cs movb tgth,al | | Update descriptor table segment limits | mov cx,12(bp) mov ax,cx add ax,ax seg cs mov tgtsz,ax seg cs mov srcsz,ax | | Now do actual DOS call | push cs pop es seg cs mov si,#gdt movb ah,#0x87 pushf .byte 0x9a | Do a far call to BIOS routine .word 0xf859 | " .word 0xf000 | " | | All done, return to caller. | pop cx | restore registers pop es pop si mov sp,bp pop bp ret ---------------------------------------------------------------------------- That's all. Good luck if you try it. --------------------------------------------------------------------------- Larry R. Hubble Tektronix/CAE Systems Division (408) 748-4782 5302 Betsy Ross Dr. {hplabs,tektronix}hubble@cae780 Santa Clara, CA 95054