summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/insmod-modutils/util/sys_cm.c
blob: d19a5ba4b7e58c1daff96cbf14dfacb749b6b6b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/* Functions for the Linux module syscall interface.
   Copyright 1996, 1997 Linux International.
   Contributed by Richard Henderson <rth@tamu.edu>

   This file is part of the Linux modutils.

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2 of the License, or (at your
   option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#include <stdlib.h>
#include <errno.h>

#include "module.h"

/* Kernel headers before 2.1.mumble need this on the Alpha to get
   _syscall* defined.  */
#define __LIBRARY__

#include <asm/unistd.h>


/*======================================================================*/

#if defined(__i386__) || defined(__m68k__) || defined(__arm__)

#define __NR__create_module  __NR_create_module
static inline _syscall2(long, _create_module, const char *, name, size_t, size)

unsigned long create_module(const char *name, size_t size)
{
  /* Why all this fuss?

     In linux 2.1, the address returned by create module point in
     kernel space which is now mapped at the top of user space (at
     0xc0000000 on i386). This looks like a negative number for a
     long. The normal syscall macro of linux 2.0 (and all libc compile
     with linux 2.0 or below) consider that the return value is a
     negative number and consider it is an error number (A kernel
     convention, return value are positive or negative, indicating the
     error number).

     By checking the value of errno, we know if we have been fooled by
     the syscall2 macro and we fix it.  */

  long ret = _create_module(name, size);
  if (ret == -1 && errno > 125)
    {
      ret = -errno;
      errno = 0;
    }
  return ret;
}

#elif defined(__alpha__)

/* Alpha doesn't have the same problem, exactly, but a bug in older
   kernels fails to clear the error flag.  Clear it here explicitly.  */

#define __NR__create_module  __NR_create_module
static inline _syscall4(unsigned long, _create_module, const char *, name,
			size_t, size, size_t, dummy, size_t, err);

unsigned long create_module(const char *name, size_t size)
{
  return _create_module(name, size, 0, 0);
}

#else

/* Sparc, MIPS, (and Alpha, but that's another problem) don't mistake
   return values for errors due to the nature of the system call.  */

_syscall2(unsigned long, create_module, const char *, name, size_t, size)

#endif