diff -Naur ../linux/CREDITS ./linux/CREDITS --- ../linux/CREDITS Tue Oct 13 19:15:47 1998 +++ ./linux/CREDITS Fri Apr 23 09:36:09 1999 @@ -1091,6 +1091,14 @@ S: Perth, Western Australia S: Australia +N: Matthew M. Ogilvie +E: mmogilvi@elbert.uccs.edu +D: Patched bootup code to boot on machines with any amount of conventional +D: memory, not just 640K. +S: 722 Pioneer Lane +S: Colorado Springs, CO 80904 +S: USA + N: Greg Page E: greg@caldera.com D: IPX development and support diff -Naur ../linux/arch/i386/boot/Makefile ./linux/arch/i386/boot/Makefile --- ../linux/arch/i386/boot/Makefile Wed Jul 17 04:59:14 1996 +++ ./linux/arch/i386/boot/Makefile Fri Apr 23 09:36:09 1999 @@ -29,16 +29,16 @@ endif sync -bzImage: $(CONFIGURE) bbootsect setup compressed/bvmlinux tools/bbuild +bzImage: $(CONFIGURE) bootsect setup compressed/bvmlinux tools/bbuild ifdef CONFIG_KERNEL_ELF if hash $(ENCAPS) 2> /dev/null; then \ $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(IMAGE_OFFSET) compressed/bvmlinux > compressed/bvmlinux.out; \ else \ $(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out; \ fi - tools/bbuild bbootsect setup compressed/bvmlinux.out $(ROOT_DEV) > bzImage + tools/bbuild bootsect setup compressed/bvmlinux.out $(ROOT_DEV) > bzImage else - tools/bbuild bbootsect setup compressed/bvmlinux $(ROOT_DEV) > bzImage + tools/bbuild bootsect setup compressed/bvmlinux $(ROOT_DEV) > bzImage endif sync @@ -85,20 +85,10 @@ bootsect.s: bootsect.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ -bbootsect: bbootsect.o - $(LD86) -s -o $@ $< - -bbootsect.o: bbootsect.s - $(AS86) -o $@ $< - -bbootsect.s: bootsect.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile - $(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ - dep: clean: rm -f bootsect setup - rm -f bbootsect rm -f zImage tools/build compressed/vmlinux.out rm -f bzImage tools/bbuild compressed/bvmlinux.out @$(MAKE) -C compressed clean diff -Naur ../linux/arch/i386/boot/bootsect.S ./linux/arch/i386/boot/bootsect.S --- ../linux/arch/i386/boot/bootsect.S Sat Mar 9 03:31:42 1996 +++ ./linux/arch/i386/boot/bootsect.S Fri Apr 23 09:36:09 1999 @@ -9,12 +9,15 @@ ! bootsect.s Copyright (C) 1991, 1992 Linus Torvalds ! modified by Drew Eckhardt ! modified by Bruce Evans (bde) +! Modified to boot on non-640K machines; moved system load code (but not +! setup load code) into setup.S: +! Matthew M. Ogilvie, mmogilvi@elbert.uccs.edu, (mmo), Aug 1996 ! ! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves ! itself out of the way to address 0x90000, and jumps there. -! -! bde - should not jump blindly, there may be systems with only 512K low -! memory. Use int 0x12 to get the top of memory, etc. +! ^^^^^^^ +! It now loads itself at a position dependent on amount of conventional +! ram returned by int 12. (mmo) ! ! It then loads 'setup' directly after itself (0x90200), and the system ! at 0x10000, using BIOS interrupts. @@ -31,11 +34,19 @@ .text +! I'm not sure, but I think 4 SETUPSECS is obsolete. Is this set in build? SETUPSECS = 4 ! nr of setup-sectors BOOTSEG = 0x07C0 ! original address of boot-sector +#if 0 /* This is an obsolete method of locating things: */ INITSEG = DEF_INITSEG ! we move boot here - out of the way SETUPSEG = DEF_SETUPSEG ! setup starts here + +! SYSSEG isn't used because system load code has been moved to setup.S SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). +#endif /*0*/ + +#define S_HDR_base_mem_sz 0x226 /* points to setup.S header */ +#define S_HDR_bootsect_load 0x220 ! ROOT_DEV & SWAP_DEV are now written by "build". ROOT_DEV = 0 @@ -56,17 +67,59 @@ #if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */ int 3 #endif +! figure out how much mem in machine; move this there instead. mov ax,#BOOTSEG mov ds,ax - mov ax,#INITSEG - mov es,ax + +! figure out how much base (conventional) memory machine has + int 0x12 ! get base mem in K +#if 0 + mov ax,#0x100 ! fake it into thinking its a 256K machine for testing. +#endif + pushf + cli + and eax,#0xffff ! adjust to bytes + shl eax,#10 + mov base_mem_sz,eax ! save for later + +! where to move myself: + shr eax,#4 ! to segs + popf + ! (this is meant to go to 0x9000 even if we're a little short of 640k) + sub ax,#0xe00 + and ax,#0xf000 + mov es,ax + cmp ax,#0x3000 ! at least 192K needed + jae enough_mem + mov ax,ds + mov es,ax + mov bp,#no_mem_msg + mov ax,#0x1300 + mov bx,#7 + mov cx,#35 + mov dx,0x400 /* at 5th row first column */ + int 0x10 ! display string + sti ! wait for user to reboot +loop1: + jmp loop1 + +enough_mem: + +! adjust segment references: +! minor self modifiing code!! Adjust segment in "jmpi xx:seg" instr. + add adjust_far_jmp1+3,ax + jmp flush_cache1 ! might not be needed to flush cache, but can't hurt +flush_cache1: + +! do move mov cx,#256 sub si,si sub di,di cld rep movsw - jmpi go,INITSEG +adjust_far_jmp1: + jmpi go,0 ! aka go,INITSEG ! ax and es already contain INITSEG @@ -152,6 +205,15 @@ ok_load_setup: +! store memory size in a more permanent location: + pushf + cli + mov eax,base_mem_sz + mov [S_HDR_base_mem_sz],eax + popf + mov ax,cs ! adjust entrence sector + add S_HDR_bootsect_load+2,ax + ! Get disk drive parameters, specifically nr of sectors/track #if 0 @@ -193,8 +255,7 @@ got_sectors: ! Restore es - - mov ax,#INITSEG + mov ax,cs ! aka INITSEG mov es,ax ! Print some inane message @@ -209,14 +270,7 @@ mov ax,#0x1301 ! write string, move cursor int 0x10 -! ok, we've written the message, now -! we want to load the system (at 0x10000) - - mov ax,#SYSSEG - mov es,ax ! segment of 0x010000 - call read_it - call kill_motor - call print_nl +! ok, we've written the message ! After that we check which root-device to use. If the device is ! defined (!= 0), nothing is done and the given device is used. @@ -243,158 +297,14 @@ seg cs mov root_dev,ax -! after that (everything loaded), we jump to -! the setup-routine loaded directly after -! the bootblock: - - jmpi 0,SETUPSEG - -! This routine loads the system at address 0x10000, making sure -! no 64kB boundaries are crossed. We try to load it as fast as -! possible, loading whole tracks whenever we can. -! -! in: es - starting address segment (normally 0x1000) -! -sread: .word 0 ! sectors read of current track -head: .word 0 ! current head -track: .word 0 ! current track - -read_it: - mov al,setup_sects - inc al - mov sread,al - mov ax,es - test ax,#0x0fff -die: jne die ! es must be at 64kB boundary - xor bx,bx ! bx is starting address within segment -rp_read: -#ifdef __BIG_KERNEL__ -#define CALL_HIGHLOAD_KLUDGE .word 0x1eff,0x220 ! call far * bootsect_kludge - ! NOTE: as86 can't assemble this - CALL_HIGHLOAD_KLUDGE ! this is within setup.S -#else - mov ax,es - sub ax,#SYSSEG -#endif - cmp ax,syssize ! have we loaded all yet? - jbe ok1_read - ret -ok1_read: - mov ax,sectors - sub ax,sread - mov cx,ax - shl cx,#9 - add cx,bx - jnc ok2_read - je ok2_read - xor ax,ax - sub ax,bx - shr ax,#9 -ok2_read: - call read_track - mov cx,ax - add ax,sread - cmp ax,sectors - jne ok3_read - mov ax,#1 - sub ax,head - jne ok4_read - inc track -ok4_read: - mov head,ax - xor ax,ax -ok3_read: - mov sread,ax - shl cx,#9 - add bx,cx - jnc rp_read - mov ax,es - add ah,#0x10 - mov es,ax - xor bx,bx - jmp rp_read - -read_track: - pusha - pusha - mov ax, #0xe2e ! loading... message 2e = . - mov bx, #7 - int 0x10 - popa - - mov dx,track - mov cx,sread - inc cx - mov ch,dl - mov dx,head - mov dh,dl - and dx,#0x0100 - mov ah,#2 - - push dx ! save for error dump - push cx - push bx - push ax - - int 0x13 - jc bad_rt - add sp, #8 - popa - ret - -bad_rt: push ax ! save error code - call print_all ! ah = error, al = read - - - xor ah,ah - xor dl,dl - int 0x13 - - - add sp, #10 - popa - jmp read_track - -/* - * print_all is for debugging purposes. - * It will print out all of the registers. The assumption is that this is - * called from a routine, with a stack frame like - * dx - * cx - * bx - * ax - * error - * ret <- sp - * -*/ - -print_all: - mov cx, #5 ! error code + 4 registers - mov bp, sp - -print_loop: - push cx ! save count left - call print_nl ! nl for readability - - cmp cl, #5 - jae no_reg ! see if register name is needed - - mov ax, #0xe05 + 'A - 1 - sub al, cl - int 0x10 - - mov al, #'X - int 0x10 - - mov al, #': - int 0x10 + seg cs + mov bx,sectors -no_reg: - add bp, #2 ! next register - call print_hex ! print it - pop cx - loop print_loop - ret +! Loading of setup was done above. The main chunk will +! be loaded from setup. (use a special entrence point in setup for this) + ! jmp far [S_HDR_bootsect_load]; (don't know how to code this) + db 0xff,0x2e + .word S_HDR_bootsect_load print_nl: mov ax, #0xe0d ! CR @@ -423,19 +333,8 @@ loop print_digit ret - -/* - * This procedure turns off the floppy drive motor, so - * that we enter the kernel in a known state, and - * don't have to worry about it later. - */ -kill_motor: - push dx - mov dx,#0x3f2 - xor al, al - outb - pop dx - ret +base_mem_sz: + .long 0 sectors: .word 0 @@ -446,6 +345,10 @@ msg1: .byte 13,10 .ascii "Loading" + +no_mem_msg: + .byte 13,10 + .ascii "Insufficient conventional memory" .org 497 setup_sects: diff -Naur ../linux/arch/i386/boot/compressed/head.S ./linux/arch/i386/boot/compressed/head.S --- ../linux/arch/i386/boot/compressed/head.S Tue Oct 13 19:15:41 1998 +++ ./linux/arch/i386/boot/compressed/head.S Fri Apr 23 09:36:09 1999 @@ -20,6 +20,11 @@ * laptops may need to access the BIOS data stored there. This is also * useful for future device drivers that either access the BIOS via VM86 * mode. + * + * On entrence: + * dx - segment of boot parameter block + * On exit: + * edx - address of boot parameter block */ /* @@ -41,6 +46,7 @@ mov %ax,%es mov %ax,%fs mov %ax,%gs + #ifdef __SMP__ orw %bx,%bx # What state are we in BX=1 for SMP # 0 for boot @@ -59,6 +65,13 @@ 2: #endif + + /* send initseg stuff to C code; and adjust stack setting instr */ + and $0xffff,%edx + shl $4,%edx + mov %edx,SYMBOL_NAME(initseg_posn) + mov %edx,adjust_stack + lss SYMBOL_NAME(stack_start),%esp xorl %eax,%eax 1: incl %eax # check that A20 really IS enabled @@ -91,6 +104,7 @@ orl %eax,%eax jnz 3f xorl %ebx,%ebx + mov SYMBOL_NAME(initseg_posn),%edx ljmp $(KERNEL_CS), $0x100000 /* @@ -100,7 +114,7 @@ * which we got from the stack. */ 3: - movl $move_routine_start,%esi + movl $move_routine_start,%esi # put movement routine out of the way. movl $0x1000,%edi movl $move_routine_end,%ecx subl %esi,%ecx @@ -122,8 +136,10 @@ * if we were high loaded. This _must_ PIC-code ! */ move_routine_start: - rep + rep # move low buffer movsb + + # move high buffer movl %edx,%esi movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0 rep @@ -134,6 +150,16 @@ * with the decompressor loaded high this is no longer true, * so we set esp here. */ - mov $0x90000,%esp + + # mov esp,(const_filled_earlier) + .byte 0xbc +adjust_stack: # will be set to point to bootsect parameter block + .long 0 # was 0x90000 + + mov %esp,%edx # pass boot sect posn on + ljmp $(KERNEL_CS), $0x100000 move_routine_end: + +ENTRY(initseg_posn) +.long 0 diff -Naur ../linux/arch/i386/boot/compressed/misc.c ./linux/arch/i386/boot/compressed/misc.c --- ../linux/arch/i386/boot/compressed/misc.c Tue Oct 13 19:15:41 1998 +++ ./linux/arch/i386/boot/compressed/misc.c Fri Apr 23 09:38:26 1999 @@ -96,15 +96,17 @@ /* * This is set up by the setup-routine at boot-time */ -#define EXT_MEM_K (*(unsigned short *)0x90002) +#define EXT_MEM_K (*(unsigned short *)(initseg_posn + 0x002)) #ifndef STANDARD_MEMORY_BIOS_CALL -#define ALT_MEM_K (*(unsigned long *) 0x901e0) +#define ALT_MEM_K (*(unsigned long *)(initseg_posn + 0x1e0)) #endif -#define DRIVE_INFO (*(struct drive_info *)0x90080) -#define SCREEN_INFO (*(struct screen_info *)0x90000) -#define RAMDISK_SIZE (*(unsigned short *)0x901F8) -#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC) -#define AUX_DEVICE_INFO (*(unsigned char *)0x901FF) +#define DRIVE_INFO (*(struct drive_info *)(initseg_posn + 0x080)) +#define SCREEN_INFO (*(struct screen_info *)(initseg_posn)) +#define RAMDISK_SIZE (*(unsigned short *)(initseg_posn + 0x1F8)) +#define ORIG_ROOT_DEV (*(unsigned short *)(initseg_posn + 0x1FC)) +#define AUX_DEVICE_INFO (*(unsigned char *)(initseg_posn + 0x1FF)) + +extern int initseg_posn; /* initialized in head.S */ extern char input_data[]; extern int input_len; @@ -124,11 +126,11 @@ extern int end; static long free_mem_ptr = (long)&end; -static long free_mem_end_ptr = 0x90000; +static long free_mem_end_ptr /* = 0x90000 */; #define INPLACE_MOVE_ROUTINE 0x1000 #define LOW_BUFFER_START 0x2000 -#define LOW_BUFFER_END 0x90000 +#define LOW_BUFFER_END initseg_posn /* was 0x90000 */ #define LOW_BUFFER_SIZE ( LOW_BUFFER_END - LOW_BUFFER_START ) #define HEAP_SIZE 0x2000 static int high_loaded =0; @@ -361,6 +363,7 @@ int decompress_kernel(struct moveparams *mv) { + free_mem_end_ptr=initseg_posn; /* might be changed later */ if (SCREEN_INFO.orig_video_mode == 7) { vidmem = (char *) 0xb0000; vidport = 0x3b4; diff -Naur ../linux/arch/i386/boot/setup.S ./linux/arch/i386/boot/setup.S --- ../linux/arch/i386/boot/setup.S Tue Oct 13 19:15:41 1998 +++ ./linux/arch/i386/boot/setup.S Fri Apr 23 09:36:09 1999 @@ -4,12 +4,16 @@ ! setup.s is responsible for getting the system data from the BIOS, ! and putting them into the appropriate places in system memory. ! both setup.s and system has been loaded by the bootblock. +! ^^^^^^ no longer completely true. setup is now +! responsible for loading the system when bootsect.S is used for loading. (mmo) ! ! This code asks the bios for memory/disk/other parameters, and ! puts them in a "safe" place: 0x90000-0x901FF, ie where the ! boot-block used to be. It is then up to the protected mode ! system to read them from there before the area is overwritten ! for buffer-blocks. +! It is no longer 0x90000. Instead it is (calling_cs<<4)-0x200. +! It often winds up at 0x90000, however. (mmo) ! ! Move PS/2 aux init code to psaux.c ! (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92 @@ -26,6 +30,9 @@ ! ! Video handling moved to video.S by Martin Mares, March 1996 ! +! +! Non-640K machine booting by Matthew M. Ogilvie (mmo), Aug 1996 +! ! NOTE! These had better be the same as in bootsect.s! #define __ASSEMBLY__ @@ -38,6 +45,7 @@ #define SIG1 0xAA55 #define SIG2 0x5A5A +! note: only SYSSEG and DELTA_INITSEG should actually be used INITSEG = DEF_INITSEG ! 0x9000, we move boot here - out of the way SYSSEG = DEF_SYSSEG ! 0x1000, system loaded at 0x10000 (65536). SETUPSEG = DEF_SETUPSEG ! 0x9020, this is the current segment @@ -60,16 +68,22 @@ ! ! SETUP-header, must start at CS:2 (old 0x9020:2) ! + +! [2] .ascii "HdrS" ! Signature for SETUP-header +! [6] .word 0x0201 ! Version number of header format ! (must be >= 0x0105 ! else old loadlin-1.5 will fail) +! [8] realmode_swtch: .word 0,0 ! default_switch,SETUPSEG +! [0xc] start_sys_seg: .word SYSSEG .word kernel_version ! pointing to kernel version string ! note: above part of header is compatible with loadlin-1.5 (header v1.5), ! must not change it +! [0x10] type_of_loader: .byte 0 ! = 0, old one (LILO, Loadlin, ! Bootlin, SYSLX, bootsect...) ! else it is set by the loader: @@ -79,6 +93,7 @@ ! T=3 for SYSLX ! T=4 for ETHERBOOT ! V = version +! [0x11] loadflags: .byte 0 ! unused bits =0 (reserved for future development) LOADED_HIGH = 1 ! bit within loadflags, ! if set, then the kernel is loaded high @@ -86,26 +101,36 @@ ! to tell how much space behind setup.S | can be used for heap purposes. ! Only the loader knows what is free! +! [0x12] setup_move_size: .word 0x8000 ! size to move, when we (setup) are not ! loaded at 0x90000. We will move ourselves ! to 0x90000 then just before jumping into ! the kernel. However, only the loader ! know how much of data behind us also needs ! to be loaded. +! [0x14] + ! this is set by build.c code32_start: .long 0x1000 ! here loaders can put a different ! start address for 32-bit code. ! 0x1000 = default for zImage ! 0x100000 = default for big kernel +! [0x18] ramdisk_image: .long 0 ! address of loaded ramdisk image ! Here the loader (or kernel generator) puts ! the 32-bit address were it loaded the image. ! This only will be interpreted by the kernel. +! [0x1c] ramdisk_size: .long 0 ! its size in bytes -bootsect_kludge: - .word bootsect_helper,SETUPSEG +! [0x20] +bootsect_load: + .word bootsect_entrence,DELTA_INITSEG ! aka SETUPSEG +! [0x24] heap_end_ptr: .word modelist+1024 ! space from here (exclusive) down to ! end of setup code can be used by setup ! for local heap purposes. +! [0x26] +base_mem_sz: .long 0 ! in bytes. (mmo) + ! ------------------------ end of header ---------------------------------- start_of_setup: @@ -125,7 +150,31 @@ mov ax,cs ! aka #SETUPSEG mov ds,ax +! if loader didn't figure memory, figure it now. + cmp dword ptr base_mem_sz,#0 + bne got_base_mem_sz + int 0x12 ! BIOS get conv. mem size in K + pushf + cli + and eax,#0xffff ! adjust to bytes + shl eax,#10 + mov base_mem_sz,eax + popf + + ! print that its an old loader: + mov si,#loader_640_msg + call prtstr + br got_base_mem_sz +loader_640_msg: + db 13,10 + .ascii "You are using an old loader which assumes 640K of base memory." + db 13,10 + .ascii " If it's available, you should upgrade to a newer loader." + db 13,10,0 +got_base_mem_sz: + ! Check signature at end of setup + cmp setup_sig1,#SIG1 jne bad_sig cmp setup_sig2,#SIG2 @@ -380,7 +429,7 @@ callf far * realmode_swtch jmp rmodeswtch_end rmodeswtch_normal: - push cs + push cs call default_switch rmodeswtch_end: @@ -429,45 +478,13 @@ mov ax,cs ! aka #SETUPSEG ! right, forgot this at first. didn't work :-) mov ds,ax -! If we have our code not at 0x90000, we need to move it there now. -! We also then need to move the params behind it (commandline) -! Because we would overwrite the code on the current IP, we move -! it in two steps, jumping high after the first one. - mov ax,cs - cmp ax,#SETUPSEG - je end_move_self - cli ! make sure we really have interrupts disabled ! - ! because after this the stack should not be used - sub ax,#DELTA_INITSEG ! aka #INITSEG - mov dx,ss - cmp dx,ax - jb move_self_1 - add dx,#INITSEG - sub dx,ax ! this will be SS after the move -move_self_1: - mov ds,ax - mov ax,#INITSEG ! real INITSEG - mov es,ax - seg cs - mov cx,setup_move_size - std ! we have to move up, so we use direction down - ! because the areas may overlap - mov di,cx - dec di - mov si,di - sub cx,#move_self_here+0x200 - rep - movsb - jmpi move_self_here,SETUPSEG ! jump to our final place -move_self_here: - mov cx,#move_self_here+0x200 - rep - movsb - mov ax,#SETUPSEG - mov ds,ax - mov ss,dx - ! now we are at the right place -end_move_self: + ! adjust gdt pointer + pushf + cli + and eax,#0xffff + shl eax,#4 + add gdt_48+2,eax + popf lidt idt_48 ! load idt with 0,0 lgdt gdt_48 ! load gdt with whatever appropriate @@ -531,6 +548,11 @@ ! The BIOS-routine wants lots of unnecessary data, and it's less ! "interesting" anyway. This is how REAL programmers do it. ! + + ! pass location of setup and stuff to next boot stage in cx + mov dx,cs + sub dx,#DELTA_INITSEG + ! Well, now's the time to actually move into protected mode. To make ! things as simple as possible, we do no register set-up or anything, ! we let the gnu-compiled 32-bit programs do that. We just jump to @@ -555,7 +577,7 @@ ! take our 48 bit far pointer. (INTeL 80386 Programmer's Reference ! Manual, Mixing 16-bit and 32-bit code, page 16-6) db 0x66,0xea ! prefix + jmpi-opcode -code32: dd 0x1000 ! will be set to 0x100000 for big kernels +code32: dd 0x1000 ! will be set to code32_start's value (from build): dw KERNEL_CS @@ -577,12 +599,70 @@ out #0x70,al retf + ! This routine loads the main chunk when using the bootsector, and then + ! jumps to the standard entrence. The boot sector is no longer at + ! all responsible for this anymore. +bootsect_entrence: + ! get stuff from boot sector +#define B_setup_sects 497 /* offsets in bootsect */ +#define B_syssize 500 + + mov ax,B_setup_sects + seg cs + mov setup_sects,ax + mov ax,B_syssize + seg cs + mov syssize,ax + + ! fix sectors + push cs + pop ds + +! we want to load the system (at 0x10000) + mov ax,#SYSSEG + mov es,ax ! segment of 0x010000 + mov sectors,bx + + mov ax,cs + sub ax,#DELTA_INITSEG + and ax,#0xf000 + mov load_cutoff,ax + call read_it + call kill_motor + call print_nl + br start_of_setup + +! This routine loads the system at address 0x10000, making sure +! no 64kB boundaries are crossed. We try to load it as fast as +! possible, loading whole tracks whenever we can. +! +! in: es - starting address segment (normally 0x1000) +! +sread: .word 0 ! sectors read of current track +head: .word 0 ! current head +track: .word 0 ! current track +load_cutoff: .word 0 ! place where bootsector put +sectors: .word 0 ! sectors per track +setup_sects: .word 0 ! sectors in setup +syssize: .word 0 ! system size (in sectors) + +read_it: + mov al,setup_sects + inc al + mov sread,al + mov ax,es + test ax,#0x0fff +die: jne die ! es must be at 64kB boundary + xor bx,bx ! bx is starting address within segment +rp_read: +! #ifdef __BIG_KERNEL__ + cmp code32_start,#0x1000 ! normal kernel load place + je not_big_kernel ! This routine only gets called, if we get loaded by the simple ! bootsect loader _and_ have a bzImage to load. ! Because there is no place left in the 512 bytes of the boot sector, ! we must emigrate to code space here. ! -bootsect_helper: seg cs cmp word ptr bootsect_es,#0 jnz bootsect_second @@ -596,7 +676,7 @@ seg cs mov bootsect_es,ax sub ax,#SYSSEG - retf ! nothing else to do for now + jmp big_bootsect_done ! nothing else to do for now bootsect_second: push cx push si @@ -609,7 +689,7 @@ mov si,#bootsect_gdt mov ax,#0x8700 int 0x15 - jc bootsect_panic ! this, if INT15 fails + bcs bootsect_panic ! this, if INT15 fails seg cs mov es,bootsect_es ! we reset es to always point to 0x10000 seg cs @@ -622,7 +702,195 @@ pop bx pop si pop cx - retf + jmp big_bootsect_done +! #else /* not __BIG_KERNEL__ */ +not_big_kernel: + mov ax,es + sub ax,#SYSSEG +! #endif /* __BIG_KERNEL__ */ +big_bootsect_done: + cmp ax,syssize ! have we loaded all yet? + jbe ok1_read + ret +ok1_read: + mov ax,es + cmp ax,load_cutoff ! watch out for out of memory + bcc no_mem_normal_kern ! jae + + mov ax,sectors + sub ax,sread + mov cx,ax + shl cx,#9 ! cx=bytes unread on this track + add cx,bx + jnc ok2_read + je ok2_read + xor ax,ax + sub ax,bx + shr ax,#9 +ok2_read: ! here, ax==sectors to read (either to end of track or end of seg) + call read_track + mov cx,ax ! make extra copy of # of segments read + ! adjust head and track: + add ax,sread + cmp ax,sectors + jne ok3_read + mov ax,#1 + sub ax,head + jne ok4_read + inc track +ok4_read: + mov head,ax + xor ax,ax +ok3_read: + mov sread,ax ! now head,track, and sread are correct + shl cx,#9 + add bx,cx ! adjust offset in seg + bcc rp_read + + mov ax,es ! adjust seg + add ah,#0x10 + mov es,ax + xor bx,bx + br rp_read + +no_mem_norm_msg: + db 13,10 + .ascii "Out of conventional memory." +#ifdef __BIG_KERNEL__ + .ascii " This shouldn't happen with big kernel :(" +#else /* not __BIG_KERNEL__ */ + .ascii " Try recompiling with make bzimage." +#endif /* __BIG_KERNEL__ */ + db 0 + +no_mem_normal_kern: + mov si,#no_mem_norm_msg + call prtstr + sti ! wait for C-A-Delete +infi_loop1: +jmp infi_loop1 + +read_track: + pusha + pusha + mov ax, #0xe2e ! loading... message 2e = . + mov bx, #7 + int 0x10 + popa + + mov dx,track + mov cx,sread + inc cx + mov ch,dl + mov dx,head + mov dh,dl + and dx,#0x0100 + mov ah,#2 + + push dx ! save for error dump + push cx + push bx + push ax + + int 0x13 + jc bad_rt + add sp, #8 + popa + ret + +bad_rt: push ax ! save error code + call print_all ! ah = error, al = read + + + xor ah,ah + xor dl,dl + int 0x13 + + + add sp, #10 + popa + jmp read_track + +/* + * print_all is for debugging purposes. + * It will print out all of the registers. The assumption is that this is + * called from a routine, with a stack frame like + * dx + * cx + * bx + * ax + * error + * ret <- sp + * +*/ + +print_all: + mov cx, #5 ! error code + 4 registers + mov bp, sp + +print_loop: + push cx ! save count left + call print_nl ! nl for readability + + cmp cl, #5 + jae no_reg ! see if register name is needed + + mov ax, #0xe05 + 'A - 1 + sub al, cl + int 0x10 + + mov al, #'X + int 0x10 + + mov al, #': + int 0x10 + +no_reg: + add bp, #2 ! next register + call print_hex ! print it + pop cx + loop print_loop + ret + +print_nl: + mov ax, #0xe0d ! CR + int 0x10 + mov al, #0xa ! LF + int 0x10 + ret + +/* + * print_hex is for debugging purposes, and prints the word + * pointed to by ss:bp in hexadecimal. +*/ + +print_hex: + mov cx, #4 ! 4 hex digits + mov dx, (bp) ! load word into dx +print_digit: + rol dx, #4 ! rotate so that lowest 4 bits are used + mov ax, #0xe0f ! ah = request, al = mask for nybble + and al, dl + add al, #0x90 ! convert al to ascii hex (four instructions) + daa + adc al, #0x40 + daa + int 0x10 + loop print_digit + ret + +/* + * This procedure turns off the floppy drive motor, so + * that we enter the kernel in a known state, and + * don't have to worry about it later. + */ +kill_motor: + push dx + mov dx,#0x3f2 + xor al, al + outb + pop dx + ret bootsect_gdt: .word 0,0,0,0 @@ -722,7 +990,7 @@ gdt_48: .word 0x800 ! gdt limit=2048, 256 GDT entries - .word 512+gdt,0x9 ! gdt base = 0X9xxxx + .word gdt,0 ! gdt base = 0X9xxxx ! ! Include video setup & detection code diff -Naur ../linux/arch/i386/boot/tools/build.c ./linux/arch/i386/boot/tools/build.c --- ../linux/arch/i386/boot/tools/build.c Tue Oct 13 19:15:41 1998 +++ ./linux/arch/i386/boot/tools/build.c Fri Apr 23 09:39:52 1999 @@ -202,7 +202,7 @@ memcpy(&tmp_int, &buf[6], sizeof(int)); if (tmp_int < intel_int(0x200)) die("Wrong version of loader header of 'setup'"); - buf[0x11] = 1; /* LOADED_HIGH */ + buf[0x11] |= 1; /* LOADED_HIGH */ tmp_long = intel_long(0x100000); memcpy(&buf[0x14], &tmp_long, sizeof(long)); /* code32_start */ } diff -Naur ../linux/arch/i386/kernel/head.S ./linux/arch/i386/kernel/head.S --- ../linux/arch/i386/kernel/head.S Mon Jul 13 13:47:27 1998 +++ ./linux/arch/i386/kernel/head.S Fri Apr 23 09:36:09 1999 @@ -14,10 +14,9 @@ #include #include -#define CL_MAGIC_ADDR 0x90020 +#define CL_OFFSET 0x22 /* offsets in boot seg */ +#define CL_MAGIC_ADDR 0x20 #define CL_MAGIC 0xA33F -#define CL_BASE_ADDR 0x90000 -#define CL_OFFSET 0x90022 /* * swapper_pg_dir is the main page directory, address 0x00001000 (or at @@ -26,6 +25,9 @@ ENTRY(stext) ENTRY(_stext) startup_32: +/* In/out: + * edx=address of bootsect + */ cld movl $(KERNEL_DS),%eax mov %ax,%ds @@ -48,6 +50,7 @@ 1: lss stack_start,%esp #endif __SMP__ + mov %edx,initseg_posn /* * Clear BSS first so that there are no surprises... */ @@ -80,7 +83,7 @@ * _empty_zero_page is for boot parameters, second 2kB * is for the command line. */ - movl $0x90000,%esi + movl initseg_posn,%esi movl $ SYMBOL_NAME(empty_zero_page),%edi movl $512,%ecx cld @@ -90,11 +93,12 @@ movl $512,%ecx rep stosl - cmpw $(CL_MAGIC),CL_MAGIC_ADDR + mov initseg_posn,%edx + cmpw $(CL_MAGIC),CL_MAGIC_ADDR(%edx) jne 1f movl $ SYMBOL_NAME(empty_zero_page)+2048,%edi - movzwl CL_OFFSET,%esi - addl $(CL_BASE_ADDR),%esi + movzwl CL_OFFSET(%edx),%esi + addl %edx,%esi movl $2048,%ecx rep movsb @@ -451,6 +455,9 @@ popl %ecx popl %eax iret + +initseg_posn: # position of boot sector stuff + .long 0 /* * The interrupt descriptor table has room for 256 idt's diff -Naur ../linux/arch/i386/kernel/setup.c ./linux/arch/i386/kernel/setup.c --- ../linux/arch/i386/kernel/setup.c Tue Oct 13 19:15:41 1998 +++ ./linux/arch/i386/kernel/setup.c Fri Apr 23 09:36:09 1999 @@ -87,6 +87,7 @@ extern int root_mountflags; extern int _etext, _edata, _end; +extern int base_mem_sz; extern char empty_zero_page[PAGE_SIZE]; @@ -111,6 +112,7 @@ #define KERNEL_START (*(unsigned long *) (PARAM+0x214)) #define INITRD_START (*(unsigned long *) (PARAM+0x218)) #define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c)) +#define BASE_MEM_SZ (*(unsigned long *) (PARAM+0x226)) #define COMMAND_LINE ((char *) (PARAM+2048)) #define COMMAND_LINE_SIZE 256 @@ -141,6 +143,7 @@ ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); drive_info = DRIVE_INFO; screen_info = SCREEN_INFO; + base_mem_sz = BASE_MEM_SZ&0xfffff000; #ifdef CONFIG_APM apm_bios_info = APM_BIOS_INFO; #endif diff -Naur ../linux/arch/i386/mm/init.c ./linux/arch/i386/mm/init.c --- ../linux/arch/i386/mm/init.c Tue Aug 12 13:06:54 1997 +++ ./linux/arch/i386/mm/init.c Fri Apr 23 09:36:09 1999 @@ -2,6 +2,9 @@ * linux/arch/i386/mm/init.c * * Copyright (C) 1995 Linus Torvalds + * + * Minor modifications to boot on non-640K machines (Aug 1996) by + * Matthew M. Ogilvie (mmo), mmogilvi@elbert.uccs.edu */ #include @@ -40,6 +43,8 @@ extern void die_if_kernel(char *,struct pt_regs *,long); extern void show_net_buffers(void); +int base_mem_sz; /* filled in by setup_arch() */ + /* * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a @@ -137,6 +142,12 @@ /* * FIXME: Linux assumes you have 640K of base ram.. this continues * the error... + * + * I fixed the 640K assumption for normal + * machines, but I don't know anything about SMP. Also, + * any machine new enough to have SMP isn't very likely + * to have other then 640K of memory. + * So I haven't touched this. (mmo) */ if (!smp_scan_config(639*0x400,0x400)) /* Scan the top 1K of base RAM */ smp_scan_config(0xF0000,0x10000); /* Scan the 64K of bios */ @@ -214,6 +225,7 @@ int datapages = 0; unsigned long tmp; extern int _etext; + /* offset in setup.S header: */ end_mem &= PAGE_MASK; high_memory = end_mem; @@ -233,12 +245,11 @@ #endif start_mem = PAGE_ALIGN(start_mem); - /* - * IBM messed up *AGAIN* in their thinkpad: 0xA0000 -> 0x9F000. - * They seem to have done something stupid with the floppy - * controller as well.. - */ - while (start_low_mem < 0x9f000) { + /* There was a comment here about thinkpad: 0xa0000 -> 0x9f000, + * but under the assumption that the thinkpad's int12 takes + * this into account, I'm not worrying about it. (mmo) + */ + while (start_low_mem < base_mem_sz) { clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags); start_low_mem += PAGE_SIZE; } @@ -251,7 +262,7 @@ if (tmp >= MAX_DMA_ADDRESS) clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); if (PageReserved(mem_map+MAP_NR(tmp))) { - if (tmp >= 0xA0000 && tmp < 0x100000) + if (tmp >= base_mem_sz && tmp < 0x100000) reservedpages++; else if (tmp < (unsigned long) &_etext) codepages++;