memory size detection problem on 2.3.16+ and 2.4.x
Hi, summary: e801 memory size detection call failure, but bios doesnt set carry flag on error and hence get an incorrect memory size. Since the 2.3.16 kernel, my PC has been unable to run any newer kernels (>2.3.16 or 2.4.x) without using the mem=64M command line parameter. This was when the new bigmem support was added which changed the memory detection routines somewhat. I have traced this down to a problem with the way in which the kernel calls the e801 memory size detection bios call. The kernel assumes that the bios will set the carry flag on the return from the call should there be an error. However, the BIOS on my PC doesnt do this- infact it seems to simply return from the call without changing any registers. As a result, my memory size being used is approx 1GB which is derived from the values in the CX and DX registers before the call. My BIOS does not clear them (CX or DX) nor does it set the carry flag. I have included a pretty harmless patch below (taken against 2.4.2) for arch/i386/boot/setup.S which works around this buggy BIOS issue. The patch clears CX and DX before the call to the e801 routine. This should be harmless for any machines which currently work correctly. Please could this patch be included in the next 2.4.x kernel source tree, as I would guess that it is not only me affected by this... Many thanks. Michael Miller --- linux-2.4.2-orig/arch/i386/boot/setup.S Sat Jan 27 18:51:35 2001 +++ linux/arch/i386/boot/setup.SWed Apr 4 00:13:52 2001 @@ -32,6 +32,10 @@ * * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999. * <[EMAIL PROTECTED]> + * + * Workaround flakey BIOSes for e801 call - which don't use carry flag + * on errors. Michael Miller ([EMAIL PROTECTED]), April 2001 + * */ #define __ASSEMBLY__ @@ -341,6 +345,11 @@ # to write everything into the same place.) meme801: + xorl%edx, %edx # Clear regs to work around + xorl%ecx, %ecx # flakey BIOSes which don't + # use carry bit correctly + # This way we get 0MB ram on + # call failure movw$0xe801, %ax int $0x15 jc mem88 - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: memory size detection problem on 2.3.16+ and 2.4.x
Hi, >> the bios will set the carry flag on the return from the call should >> there be an error. However, the BIOS on my PC doesnt do this- infact >> it seems to simply return from the call without changing any registers. > > Your BIOS is faulty. No new suprises. Hmm- not as wrong as I had at first thought... > >> meme801: >> + xorl%edx, %edx # Clear regs to work around >> + xorl%ecx, %ecx # flakey BIOSes which don't >> + # use carry bit correctly >> + # This way we get 0MB ram on >> + # call failure > >Wouldn't setting the carry flag be clearer ? Yup- so I gave it a try and I was surprised that my OOPs happened again. Turns out (after doing loads of tests using ms debug!!!) that my BIOS does clear the carry flag (correctly!) and sets the memory size in AX and BX as opposed to CX and DX (correct? possibly) which is what the Linux kernel uses. The crunch which got my machine, was that CX and DX are returned unchanged. Thus my xorl above was making the problem go away. I looked on various sites (including Grub and Ralf Brown(?) interrupt lists) and it seems that AX and BX are for 'extended memory' and CX/DX are for 'configured' memory... No one seemed clear on the difference. Since CX/DX are currently being used byu the kernel, I thought I would make my patch have minimal impact on users who are currently working fine. As a result I have a second patch, which I would like to propose for kernel addition, below. This patch basically sets cx/dx to 0x0 before the e801 call and then tests to see if they are still both 0, if so ax/bx are used instead. Obviously the carry test for sucess is still in place. Many thanks for suggesting an alternate solution, which although did not solve the problem (due to my original wrong info) it did result in, what I consider to be, a better solution... Mike --- linux-2.4.2-orig/arch/i386/boot/setup.S Sat Jan 27 18:51:35 2001 +++ linux/arch/i386/boot/setup.SWed Apr 4 22:30:31 2001 @@ -32,6 +32,16 @@ * * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999. * <[EMAIL PROTECTED]> + * + * Fix to work around buggy BIOSes which dont use carry bit correctly + * and/or report extended memory in CX/DX for e801h memory size detection + * call. As a result the kernel got wrong figures. The int15/e801h docs + * from Ralf Brown interrupt list seem to indicate AX/BX should be used + * anyway. So to avoid breaking many machines (presumably there was a reason + * to orginally use CX/DX instead of AX/BX), we do a kludge to see + * if CX/DX have been changed in the e801 call and if so use AX/BX . + * Michael Miller, April 2001 <[EMAIL PROTECTED]> + * */ #define __ASSEMBLY__ @@ -341,10 +351,24 @@ # to write everything into the same place.) meme801: + stc # fix to work around buggy + xorw%cx,%cx # BIOSes which dont clear/set + xorw%dx,%dx # carry on pass/error of + # e801h memory size call + # or merely pass cx,dx though + # without changing them. movw$0xe801, %ax int $0x15 jc mem88 + cmpw$0x0, %cx # Kludge to handle BIOSes + jne e801usecxdx # which report their extended + cmpw$0x0, %dx # memory in AX/BX rather than + jne e801usecxdx # CX/DX. The spec I have read + movw%ax, %cx# seems to indicate AX/BX + movw%bx, %dx# are more reasonable anyway... + +e801usecxdx: andl$0x, %edx # clear sign extend shll$6, %edx# and go from 64k to 1k chunks movl%edx, (0x1e0) # store extended memory size - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
curedump configuration additions
Hi, I have added some configuration options to the coredump abilities of the kernel. Please can this patch be considered for addition to the kernel. I have added three sysctl variables which control the 'features' I have added. These are: kernel.coredump_enabled kernel.coredump_log kernel.coredump_file_name The first two are 'boolean' options which control if the creation of core files is globally enabled and if corefile generation if logged respectively. The third option controls the filename of the coredump. It allows the use of a few tokens within the filename. Please find the patch below and attached for convenience. This is a diff against a 2.4.4 kernel. Many thanks mike -- diff -ru -x *.o -x *.s -x *.flags -x *.a -x *.map -x *.depend linux-2.4.4-orig/Documentation/sysctl/kernel.txt linux/Documentation/sysctl/kernel.txt --- linux-2.4.4-orig/Documentation/sysctl/kernel.txtTue Jan 11 02:15:58 2000 +++ linux/Documentation/sysctl/kernel.txt Sat May 5 19:48:37 2001 @@ -41,6 +41,9 @@ - shmmax [ sysv ipc ] - version - zero-paged [ PPC only ] +- coredump_enabled +- coredump_file_name +- coredump_log == @@ -226,3 +229,60 @@ the idle loop, possibly speeding up get_free_pages. Since this only affects what the idle loop is doing, you should enable this and see if anything changes. + +== + +coredump_enabled: + +When enabled (which is the default), Linux will produce +coredumps. This mimics the previous behavior. Coredumps +will not be produced if processes have had their coredump +limit set. + +If disabled, no coredumps will be produced at all. This is +useful for systems where increased security is needed so +that coredumps are not produced, or for systems where coredumps +are unwanted due to disk space shortages. I'm sure there are +other reasons why you would want to disable coredumps too... + +== + +coredump_file_name: + +Coredump filenames are now configurable using this sysctl. + +For starters, to set the variable to emulate previous behavior (which +is still the default) you need to do: + sysctl -w kernel.coredump_filename=core + +The filename can either be a relative or absolute filename. The filename +can contain meta characters which will be expanded when the corefile is +written. The meta characters are: + + %c which is expanded to the process's command name + %p which is expanded to the process's PID + %u which is expanded to the process's UID + %U which is expanded to the process's EUID + %g which is expanded to the process's GID + %G which is expanded to the process's EGID + +Note that this is a global setting, so all coredumps are affected by +this. A future modification would be to enable per process coredump +parameters. + +== + +coredump_log: + +This controls if coredumps get logged by the kernel. Note that even +if coredump_enabled=0, you can still log attempts to generate a coredump. + +This sysctl variable is useful on machines which may be targets of hacking. +Hackers may cause a process to crash and generate a coredump. This option +allows such events to be logged, and hopefully alert sysadmins to hack +attempts. + +The default is to log coredumps. + +== + diff -ru -x *.o -x *.s -x *.flags -x *.a -x *.map -x *.depend linux-2.4.4-orig/fs/exec.c linux/fs/exec.c --- linux-2.4.4-orig/fs/exec.c Sat May 5 14:01:45 2001 +++ linux/fs/exec.c Sat May 5 19:07:07 2001 @@ -20,6 +20,10 @@ * table to check for several different types of binary formats. We keep * trying until we recognize the file or we run out of supported binary * formats. + * + * Configurable coredump_file_name, coredump_log and coredump_enabled + * support added by Michael Miller, May 2001, [EMAIL PROTECTED] + * */ #include @@ -48,6 +52,10 @@ static struct linux_binfmt *formats; static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED; +int coredump_enabled = 1; +char coredump_file_name[256] = "core"; +int coredump_log = 1; + int register_binfmt(struct linux_binfmt * fmt) { struct linux_binfmt ** tmp = &formats; @@ -924,11 +932,23 @@ int do_coredump(long signr, struct pt_regs * regs) { struct linux_binfmt * binfmt; - char corename[6+sizeof(current->comm)]; + char corename[256]=""; struct file * file; struct inode * inode; +int i,j,k; + + /* Calculate the min buffer free to handle an expanded token from + coredump_file_name. 22 comes from the max number of digits + for a 64bit integer. + */ + k=sizeof(current->comm); + if (k<22) +
Re: curedump configuration additions
fs/exec.c linux/fs/exec.c --- linux-2.4.4-orig/fs/exec.c Sat May 5 14:01:45 2001 +++ linux/fs/exec.c Mon May 7 18:51:21 2001 @@ -20,6 +20,11 @@ * table to check for several different types of binary formats. We keep * trying until we recognize the file or we run out of supported binary * formats. + * + * Configurable coredump_file_name, coredump_log and coredump_enabled + * coredump_suid_enabled support added by Michael Miller, + * May 2001, [EMAIL PROTECTED] + * */ #include @@ -48,6 +53,11 @@ static struct linux_binfmt *formats; static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED; +int coredump_enabled = 1; +char coredump_file_name[256] = "core"; +int coredump_log = 0; +int coredump_suid_enabled = 0; + int register_binfmt(struct linux_binfmt * fmt) { struct linux_binfmt ** tmp = &formats; @@ -924,26 +934,85 @@ int do_coredump(long signr, struct pt_regs * regs) { struct linux_binfmt * binfmt; - char corename[6+sizeof(current->comm)]; + char corename[256]=""; + char tmpbuf[256]="\n"; struct file * file; struct inode * inode; +int i,j,k; + + /* Calculate the min buffer free to handle an expanded token from + coredump_file_name. 22 comes from the max number of digits + for a 64bit integer. + */ + k=sizeof(current->comm); + if (k<22) + k=22; + k=sizeof(corename) - k; lock_kernel(); + + sprintf(tmpbuf, "process %s, pid %d, uid %d, gid %d", + current->comm,current->pid,current->uid,current->gid); + if ( (current->uid != current->euid) || + (current->gid != current->egid) ) { + sprintf(&tmpbuf[strlen(tmpbuf)], ", euid %d, egid %d", + current->euid,current->egid); + } + + if (!coredump_enabled) + goto fail; binfmt = current->binfmt; if (!binfmt || !binfmt->core_dump) goto fail; - if (!current->dumpable || atomic_read(¤t->mm->mm_users) != 1) + if ((!current->dumpable && !coredump_suid_enabled) + || atomic_read(¤t->mm->mm_users) != 1) goto fail; current->dumpable = 0; if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) goto fail; - memcpy(corename,"core.", 5); -#if 0 - memcpy(corename+5,current->comm,sizeof(current->comm)); -#else - corename[4] = '\0'; -#endif + j=0; + for (i=0; (coredump_file_name[i] != '\0') && + (jcomm); + break; + case 'g': + j += sprintf(&corename[j],"%u", current->gid); + break; + case 'G': + j += sprintf(&corename[j],"%u", current->egid); + break; + case 'p': + j += sprintf(&corename[j],"%u", current->pid); + break; + case 'u': + j += sprintf(&corename[j],"%u", current->uid); + break; + case 'U': + j += sprintf(&corename[j],"%u", current->euid); + break; + case '%': + corename[j++]=coredump_file_name[i];; + break; + default: + corename[j++]=coredump_file_name[--i]; + } + } + +} + + if (j==0) { + memcpy(corename,"core",4); + j=4; + } + corename[j] = '\0'; + file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW, 0600); if (IS_ERR(file)) goto fail; @@ -963,13 +1032,20 @@ goto close_fail; if (!binfmt->core_dump(signr, regs, file)) goto close_fail; + if (coredump_log) + printk("Coredump to file %s for %s", corename, tmpbuf); unlock_kernel(); filp_close(file, NULL); return 1; close_fail: filp_close(file, NULL); + if (coredump_log && (corename[0]!='\0')) + printk("Coredump failed to dump to file %s\n",corename); + fail: + if (coredump_log) + printk("Coredump not dumped for %s\n", tmpbuf); unlock_kernel(); return 0; } diff -ru -x *.o -