add directory Linux-0.98

This commit is contained in:
gohigh
2024-02-19 00:21:16 -05:00
parent 265896c4ae
commit 56596ada90
13765 changed files with 3471432 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
#ifndef _ASM_BITOPS_H
/*
* Copyright 1992, Linus Torvalds.
*/
#ifdef i386
/*
* These have to be done with inline assembly: that way the bit-setting
* is guaranteed to be atomic. Both set_bit and clear_bit return 0
* if the bit-setting went ok, != 0 if the bit already was set/cleared.
*
* bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
*/
extern inline int set_bit(int nr,int * addr)
{
char ok;
__asm__ __volatile__("btsl %1,%2\n\tsetb %0":
"=q" (ok):"r" (nr),"m" (*(addr)));
return ok;
}
extern inline int clear_bit(int nr, int * addr)
{
char ok;
__asm__ __volatile__("btrl %1,%2\n\tsetnb %0":
"=q" (ok):"r" (nr),"m" (*(addr)));
return ok;
}
/*
* This routine doesn't need to be atomic, but it's faster to code it
* this way.
*/
extern inline int test_bit(int nr, int * addr)
{
char ok;
__asm__ __volatile__("btl %1,%2\n\tsetb %0":
"=q" (ok):"r" (nr),"m" (*(addr)));
return ok;
}
#else
/*
* For the benefit of those who are trying to port Linux to another
* architecture, here are some C-language equivalents. You should
* recode these in the native assmebly language, if at all possible.
* To guarantee atomicity, these routines call cli() and sti() to
* disable interrupts while they operate. (You have to provide inline
* routines to cli() and sti().)
*
* Also note, these routines assume that you have 32 bit integers.
* You will have to change this if you are trying to port Linux to the
* Alpha architecture or to a Cray. :-)
*
* C language equivalents written by Theodore Ts'o, 9/26/92
*/
extern inline int set_bit(int nr,int * addr)
{
int mask, retval;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
cli();
retval = (mask & *addr) != 0;
*addr |= mask;
sti();
return retval;
}
extern inline int clear_bit(int nr, int * addr)
{
int mask, retval;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
cli();
retval = (mask & *addr) == 0;
*addr &= ~mask;
sti();
return retval;
}
extern inline int test_bit(int nr, int * addr)
{
int mask;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
return ((mask & *addr) != 0);
}
#endif /* i386 */
#endif /* _ASM_BITOPS_H */

View File

@@ -0,0 +1,192 @@
/* $Header: /sys/linux-0.97/include/asm/RCS/dma.h,v 1.4 1992/09/21 03:15:46 root Exp root $
* linux/include/asm/dma.h: Defines for using and allocating dma channels.
* Written by Hennus Bergman, 1992.
*/
#ifndef _ASM_DMA_H
#define _ASM_DMA_H
#include <asm/io.h> /* need byte IO */
#include <linux/kernel.h> /* need panic() [FIXME] */
#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
#define outb outb_p
#endif
/* FIXME: better fix this code for dma channels>3!!!!!!! */
/*
* The routines below should in most cases (with optimizing on) result
* in equal or better code than similar code using macros.
*
* NOTE about DMA transfers: The DMA controller cannot handle transfers
* that cross a 64k boundary. When the address reaches 0xNffff, it will wrap
* around to 0xN0000, rather than increment to 0x(N+1)0000 !
* Make sure you align your buffers properly! Runtime check recommended.
*
* NOTE2: DMA1..3 can only use the lower 1MB of physical memory. DMA4..7
* can access the lower 16MB. There are people with >16MB, so beware!
*/
#define MAX_DMA_CHANNELS 8
/* SOMEBODY should check the following:
* Channels 0..3 are on the first DMA controller, channels 4..7 are
* on the second. Channel 0 is for refresh, 4 is for cascading.
* The first DMA controller uses bytes, the second words.
*
* Where are the page regs for the second DMA controller?????
*/
/* 8237 DMA controllers */
#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */
/* DMA controller registers */
#define DMA1_CMD_REG 0x08 /* DMA command register */
#define DMA1_STAT_REG 0x08 /* DMA status register */
#define DMA1_MASK_REG 0x0A /* mask individual channels */
#define DMA1_MODE_REG 0x0B /* set modes for individual channels */
#define DMA1_CLEAR_FF_REG 0x0C /* Write 0 for LSB, 1 for MSB */
#define DMA1_RESET_REG 0x0D /* Write here to reset DMA controller */
/* don't have much info on the second DMA controller... */
#define DMA2_MASK_REG 0xD4
#define DMA2_MODE_REG 0xD6
/* #define DMA2_CLEAR_FF_REG 0xD8 -- pure guessing.... */
/************* #error This needs more work!!!!!!!*************/
#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
#define DMA_MODE_CASCADE 0xC0 /* cascade mode (for DMA2 controller only) */
/* enable/disable a specific DMA channel */
static __inline__ void enable_dma(unsigned int dmanr)
{
if (dmanr<=3)
outb(dmanr, DMA1_MASK_REG);
else
outb(dmanr & 3, DMA2_MASK_REG);
}
static __inline__ void disable_dma(unsigned int dmanr)
{
if (dmanr<=3)
outb(dmanr | 4, DMA1_MASK_REG);
else
outb((dmanr & 3) | 4, DMA2_MASK_REG);
}
/* Clear the 'DMA Pointer Flip Flop'.
* Write 0 for LSB/MSB, 1 for MSB/LSB access.
* Use this once to initialize the FF to a know state.
* After that, keep track of it. :-) In order to do that,
* dma_set_addr() and dma_set_count() should only be used wile
* interrupts are disbled.
*/
static __inline__ void clear_dma_ff(unsigned int dmanr)
{
if (dmanr<=3)
outb(0, DMA1_CLEAR_FF_REG);
else
#ifdef DMA2_CLEAR_FF_REG
outb(0, DMA2_CLEAR_FF_REG);
#else
panic("dma.h: Don't have CLEAR_FF for high dma channels!\n");
#endif
}
/* set mode (above) for a specific DMA channel */
static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
{
if (dmanr<=3)
outb(mode | dmanr, DMA1_MODE_REG);
else
outb(DMA_MODE_CASCADE | mode | (dmanr&3), DMA2_MODE_REG);
}
/* Set only the page register bits of the transfer address.
* This is used for successive transfers when we know the contents of
* the lower 16 bits of the DMA current address register, but a 64k boundary
* may have been crossed.
*/
static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
{
switch(dmanr) {
case 0:
outb(pagenr, 0x80);
break;
case 1:
outb(pagenr, 0x83);
break;
case 2:
outb(pagenr, 0x81);
break;
case 3:
outb(pagenr, 0x82);
break;
case 4:
case 5:
case 6:
case 7:
panic("dma.h: don't know how to set DMA page regs for channels>3");
break;
}
}
/* Set transfer address & page bits for specific DMA channel.
* Assumes dma flipflop is clear.
*/
static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
{
unsigned int io_base = (dmanr<=3)? IO_DMA1_BASE : IO_DMA2_BASE;
set_dma_page(dmanr, a>>16);
outb(a & 0xff, ((dmanr&3)<<1) + io_base);
outb((a>>8) & 0xff, ((dmanr&3)<<1) + io_base);
}
/* Set transfer size (max 64k) for a specific DMA channel.
* You must ensure the parameters are valid.
* NOTE: from a manual: "the number of transfers is one more
* than the initial word count"! This is taken into account.
* Assumes dma flip-flop is clear.
*/
static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
{
unsigned int dc = count - 1;
unsigned int io_base = (dmanr<=3)? IO_DMA1_BASE : IO_DMA2_BASE;
outb(dc & 0xff, ((dmanr&3)<<1) + 1 + io_base);
outb((dc>>8) & 0xff, ((dmanr&3)<<1) + 1 + io_base);
}
/* Get DMA residue count. After a DMA transfer, this
* should return zero. Reading this while a DMA transfer is
* still in progress will return unpredictable results.
* If called before the channel has been used, it may return 1.
* Otherwise, it returns the number of bytes left to transfer,
* minus 1, modulo 64k.
* Assumes DMA flip-flop is clear.
*/
static __inline__ short int get_dma_residue(unsigned int dmanr)
{
unsigned int io_base = (dmanr<=3)? IO_DMA1_BASE : IO_DMA2_BASE;
return 1 + inb( ((dmanr&3)<<1) + 1 + io_base ) +
( inb( ((dmanr&3)<<1) + 1 + io_base ) << 8 );
}
/* These are in kernel/dma.c: */
extern int request_dma(unsigned int dmanr); /* reserve a DMA channel */
extern void free_dma(unsigned int dmanr); /* release it again */
#endif /* _ASM_DMA_H */

View File

@@ -0,0 +1,57 @@
#ifndef _ASM_IO_H
#define _ASM_IO_H
/*
* Thanks to James van Artsdalen for a better timing-fix than
* the two short jumps: using outb's to a nonexistent port seems
* to guarantee better timings even on fast machines.
*
* On the other hand, I'd like to be sure of a non-existent port:
* I feel a bit unsafe abou using 0x80.
*
* Linus
*/
#ifdef SLOW_IO_BY_JUMPING
#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:")
#else
#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80")
#endif
#ifdef REALLY_SLOW_IO
#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; }
#else
#define SLOW_DOWN_IO __SLOW_DOWN_IO
#endif
extern void inline outb(char value, unsigned short port)
{
__asm__ __volatile__ ("outb %%al,%%dx"
::"a" ((char) value),"d" ((unsigned short) port));
}
extern unsigned int inline inb(unsigned short port)
{
unsigned int _v;
__asm__ __volatile__ ("inb %%dx,%%al"
:"=a" (_v):"d" ((unsigned short) port),"0" (0));
return _v;
}
extern void inline outb_p(char value, unsigned short port)
{
__asm__ __volatile__ ("outb %%al,%%dx"
::"a" ((char) value),"d" ((unsigned short) port));
SLOW_DOWN_IO;
}
extern unsigned int inline inb_p(unsigned short port)
{
unsigned int _v;
__asm__ __volatile__ ("inb %%dx,%%al"
:"=a" (_v):"d" ((unsigned short) port),"0" (0));
SLOW_DOWN_IO;
return _v;
}
#endif

View File

@@ -0,0 +1,147 @@
#ifndef _ASM_IRQ_H
#define _ASM_IRQ_H
/*
* linux/include/asm/irq.h
*
* (C) 1992 Linus Torvalds
*/
#define SAVE_ALL \
"cld\n\t" \
"push %gs\n\t" \
"push %fs\n\t" \
"push %es\n\t" \
"push %ds\n\t" \
"pushl %eax\n\t" \
"pushl %ebp\n\t" \
"pushl %edi\n\t" \
"pushl %esi\n\t" \
"pushl %edx\n\t" \
"pushl %ecx\n\t" \
"pushl %ebx\n\t" \
"movl $0x10,%edx\n\t" \
"mov %dx,%ds\n\t" \
"mov %dx,%es\n\t" \
"movl $0x17,%edx\n\t" \
"mov %dx,%fs\n\t"
/*
* SAVE_MOST/RESTORE_MOST is used for the faster version of IRQ handlers,
* installed by using the SA_INTERRUPT flag. These kinds of IRQ's don't
* call the routines that do signal handling etc on return, and can have
* more relaxed register-saving etc. They are also atomic, and are thus
* suited for small, fast interrupts like the serial lines or the harddisk
* drivers, which don't actually need signal handling etc.
*
* Also note that we actually save only those registers that are used in
* C subroutines (%eax, %edx and %ecx), so if you do something weird,
* you're on your own. The only segments that are saved (not counting the
* automatic stack and code segment handling) are %ds and %es, and they
* point to kernel space. No messing around with %fs here.
*/
#define SAVE_MOST \
"cld\n\t" \
"push %es\n\t" \
"push %ds\n\t" \
"pushl %eax\n\t" \
"pushl %edx\n\t" \
"pushl %ecx\n\t" \
"movl $0x10,%edx\n\t" \
"mov %dx,%ds\n\t" \
"mov %dx,%es\n\t"
#define RESTORE_MOST \
"popl %ecx\n\t" \
"popl %edx\n\t" \
"popl %eax\n\t" \
"pop %ds\n\t" \
"pop %es\n\t" \
"iret"
#define ACK_FIRST(mask) \
"inb $0x21,%al\n\t" \
"jmp 1f\n" \
"1:\tjmp 1f\n" \
"1:\torb $" #mask ",%al\n\t" \
"outb %al,$0x21\n\t" \
"jmp 1f\n" \
"1:\tjmp 1f\n" \
"1:\tmovb $0x20,%al\n\t" \
"outb %al,$0x20\n\t"
#define ACK_SECOND(mask) \
"inb $0xA1,%al\n\t" \
"jmp 1f\n" \
"1:\tjmp 1f\n" \
"1:\torb $" #mask ",%al\n\t" \
"outb %al,$0xA1\n\t" \
"jmp 1f\n" \
"1:\tjmp 1f\n" \
"1:\tmovb $0x20,%al\n\t" \
"outb %al,$0xA0\n\t" \
"jmp 1f\n" \
"1:\tjmp 1f\n" \
"1:\toutb %al,$0x20\n\t"
#define UNBLK_FIRST(mask) \
"inb $0x21,%al\n\t" \
"jmp 1f\n" \
"1:\tjmp 1f\n" \
"1:\tandb $~(" #mask "),%al\n\t" \
"outb %al,$0x21\n\t"
#define UNBLK_SECOND(mask) \
"inb $0xA1,%al\n\t" \
"jmp 1f\n" \
"1:\tjmp 1f\n" \
"1:\tandb $~(" #mask "),%al\n\t" \
"outb %al,$0xA1\n\t"
#define IRQ_NAME2(nr) nr##_interrupt()
#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
#define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr)
#define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr)
#define BUILD_IRQ(chip,nr,mask) \
void IRQ_NAME(nr); \
void FAST_IRQ_NAME(nr); \
void BAD_IRQ_NAME(nr); \
__asm__( \
"\n.align 2\n" \
"_IRQ" #nr "_interrupt:\n\t" \
"pushl $-"#nr"-2\n\t" \
SAVE_ALL \
ACK_##chip(mask) \
"sti\n\t" \
"movl %esp,%ebx\n\t" \
"pushl %ebx\n\t" \
"pushl $" #nr "\n\t" \
"call _do_IRQ\n\t" \
"addl $8,%esp\n\t" \
"testl %eax,%eax\n\t" \
"jne ret_from_sys_call\n\t" \
"cli\n\t" \
UNBLK_##chip(mask) \
"jmp ret_from_sys_call\n" \
"\n.align 2\n" \
"_fast_IRQ" #nr "_interrupt:\n\t" \
SAVE_MOST \
ACK_##chip(mask) \
"pushl $" #nr "\n\t" \
"call _do_fast_IRQ\n\t" \
"addl $4,%esp\n\t" \
"testl %eax,%eax\n\t" \
"jne 2f\n\t" \
"cli\n\t" \
UNBLK_##chip(mask) \
"\n2:\t" \
RESTORE_MOST \
"\n\n.align 2\n" \
"_bad_IRQ" #nr "_interrupt:\n\t" \
"pushl %eax\n\t" \
ACK_##chip(mask) \
"popl %eax\n\t" \
"iret");
#endif

View File

@@ -0,0 +1,39 @@
/*
* NOTE!!! memcpy(dest,src,n) assumes ds=es=normal data segment. This
* goes for all kernel functions (ds=es=kernel space, fs=local data,
* gs=null), as well as for all well-behaving user programs (ds=es=
* user data space). This is NOT a bug, as any user program that changes
* es deserves to die if it isn't careful.
*/
#if 0
#define memcpy(dest,src,n) ({ \
void * _res = dest; \
__asm__ __volatile__ ("cld;rep;movsb" \
::"D" ((long)(_res)),"S" ((long)(src)),"c" ((long) (n)) \
:"di","si","cx"); \
_res; \
})
#else
/* this is basically memcpy_tofs. It should be faster.
I've reorder it. This should be a little faster. -RAB */
#define memcpy(dest, src, n) f_memcpy(dest, src, n)
extern inline void * f_memcpy(void * to, void * from, unsigned long n)
{
__asm__("cld\n\t"
"movl %%edx, %%ecx\n\t"
"shrl $2,%%ecx\n\t"
"rep ; movsl\n\t"
"testb $1,%%dl\n\t"
"je 1f\n\t"
"movsb\n"
"1:\ttestb $2,%%dl\n\t"
"je 2f\n\t"
"movsw\n"
"2:\n"
::"d" (n),"D" ((long) to),"S" ((long) from)
: "cx","di","si");
return (to);
}
#endif

View File

@@ -0,0 +1,99 @@
extern inline unsigned char get_fs_byte(const char * addr)
{
unsigned register char _v;
__asm__ ("movb %%fs:%1,%0":"=q" (_v):"m" (*addr));
return _v;
}
extern inline unsigned short get_fs_word(const unsigned short *addr)
{
unsigned short _v;
__asm__ ("movw %%fs:%1,%0":"=r" (_v):"m" (*addr));
return _v;
}
extern inline unsigned long get_fs_long(const unsigned long *addr)
{
unsigned long _v;
__asm__ ("movl %%fs:%1,%0":"=r" (_v):"m" (*addr)); \
return _v;
}
extern inline void put_fs_byte(char val,char *addr)
{
__asm__ ("movb %0,%%fs:%1"::"q" (val),"m" (*addr));
}
extern inline void put_fs_word(short val,short * addr)
{
__asm__ ("movw %0,%%fs:%1"::"r" (val),"m" (*addr));
}
extern inline void put_fs_long(unsigned long val,unsigned long * addr)
{
__asm__ ("movl %0,%%fs:%1"::"r" (val),"m" (*addr));
}
extern inline void memcpy_tofs(void * to, const void * from, unsigned long n)
{
__asm__("cld\n\t"
"push %%es\n\t"
"push %%fs\n\t"
"pop %%es\n\t"
"testb $1,%%cl\n\t"
"je 1f\n\t"
"movsb\n"
"1:\ttestb $2,%%cl\n\t"
"je 2f\n\t"
"movsw\n"
"2:\tshrl $2,%%ecx\n\t"
"rep ; movsl\n\t"
"pop %%es"
::"c" (n),"D" ((long) to),"S" ((long) from)
:"cx","di","si");
}
extern inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
{
__asm__("cld\n\t"
"testb $1,%%cl\n\t"
"je 1f\n\t"
"fs ; movsb\n"
"1:\ttestb $2,%%cl\n\t"
"je 2f\n\t"
"fs ; movsw\n"
"2:\tshrl $2,%%ecx\n\t"
"rep ; fs ; movsl"
::"c" (n),"D" ((long) to),"S" ((long) from)
:"cx","di","si");
}
/*
* Someone who knows GNU asm better than I should double check the followig.
* It seems to work, but I don't know if I'm doing something subtly wrong.
* --- TYT, 11/24/91
* [ nothing wrong here, Linus: I just changed the ax to be any reg ]
*/
extern inline unsigned long get_fs()
{
unsigned short _v;
__asm__("mov %%fs,%0":"=r" (_v):);
return _v;
}
extern inline unsigned long get_ds()
{
unsigned short _v;
__asm__("mov %%ds,%0":"=r" (_v):);
return _v;
}
extern inline void set_fs(unsigned long val)
{
__asm__ __volatile__("mov %0,%%fs"::"r" ((unsigned short) val));
}

View File

@@ -0,0 +1,72 @@
#define move_to_user_mode() \
__asm__ __volatile__ ("movl %%esp,%%eax\n\t" \
"pushl $0x17\n\t" \
"pushl %%eax\n\t" \
"pushfl\n\t" \
"pushl $0x0f\n\t" \
"pushl $1f\n\t" \
"iret\n" \
"1:\tmovl $0x17,%%eax\n\t" \
"mov %%ax,%%ds\n\t" \
"mov %%ax,%%es\n\t" \
"mov %%ax,%%fs\n\t" \
"mov %%ax,%%gs" \
:::"ax")
#define sti() __asm__ __volatile__ ("sti"::)
#define cli() __asm__ __volatile__ ("cli"::)
#define nop() __asm__ __volatile__ ("nop"::)
#define save_flags(x) \
__asm__ __volatile__("pushfl ; popl %0":"=r" (x))
#define restore_flags(x) \
__asm__ __volatile__("pushl %0 ; popfl"::"r" (x))
#define iret() __asm__ __volatile__ ("iret"::)
#define _set_gate(gate_addr,type,dpl,addr) \
__asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
"movw %0,%%dx\n\t" \
"movl %%eax,%1\n\t" \
"movl %%edx,%2" \
:: "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
"m" (*((char *) (gate_addr))), \
"m" (*(4+(char *) (gate_addr))), \
"d" ((char *) (addr)),"a" (0x00080000) \
:"ax","dx")
#define set_intr_gate(n,addr) \
_set_gate(&idt[n],14,0,addr)
#define set_trap_gate(n,addr) \
_set_gate(&idt[n],15,0,addr)
#define set_system_gate(n,addr) \
_set_gate(&idt[n],15,3,addr)
#define _set_seg_desc(gate_addr,type,dpl,base,limit) {\
*(gate_addr) = ((base) & 0xff000000) | \
(((base) & 0x00ff0000)>>16) | \
((limit) & 0xf0000) | \
((dpl)<<13) | \
(0x00408000) | \
((type)<<8); \
*((gate_addr)+1) = (((base) & 0x0000ffff)<<16) | \
((limit) & 0x0ffff); }
#define _set_tssldt_desc(n,addr,limit,type) \
__asm__ __volatile__ ("movw $" #limit ",%1\n\t" \
"movw %%ax,%2\n\t" \
"rorl $16,%%eax\n\t" \
"movb %%al,%3\n\t" \
"movb $" type ",%4\n\t" \
"movb $0x00,%5\n\t" \
"movb %%ah,%6\n\t" \
"rorl $16,%%eax" \
::"a" (addr+0xc0000000), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
"m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \
)
#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),231,"0x89")
#define set_ldt_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),23,"0x82")