Support for etherboot.

This commit is contained in:
Ronald G. Minnich 2001-06-23 21:04:48 +00:00
commit 9ea31ee45a
21 changed files with 4102 additions and 4 deletions

3
src/etherboot/Config Normal file
View file

@ -0,0 +1,3 @@
object netboot.o
object rarp.o
object sis900.o

173
src/etherboot/cards.h Normal file
View file

@ -0,0 +1,173 @@
#ifndef CARDS_H
#define CARDS_H
/*
* 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, or (at
* your option) any later version.
*/
#include "nic.h"
/* OK, this is how the PCI support hack works: if pci.h is included before
* this file is included, assume that the driver supports PCI. This means that
* this file is usually included last. */
#ifdef PCI_H
#define PCI_ARG(x) ,x
#else
#define PCI_ARG(x)
#endif
#ifdef INCLUDE_WD
extern struct nic *wd_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_3C503
extern struct nic *t503_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_VIA_RHINE
extern struct nic *rhine_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_NE
extern struct nic *ne_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_NS8390
extern struct nic *nepci_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_3C509
extern struct nic *t509_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_3C529
extern struct nic *t529_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_3C595
extern struct nic *t595_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_3C90X
extern struct nic *a3c90x_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_EEPRO
extern struct nic *eepro_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_EEPRO100
extern struct nic *eepro100_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_EPIC100
extern struct nic *epic100_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_OTULIP
extern struct nic *otulip_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_TULIP
extern struct nic *tulip_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_DAVICOM
extern struct nic *davicom_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_CS89X0
extern struct nic *cs89x0_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_LANCE
extern struct nic *lancepci_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_NE2100
extern struct nic *ne2100_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_NI6510
extern struct nic *ni6510_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_SK_G16
extern struct nic *SK_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_3C507
extern struct nic *t507_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_NI5010
extern struct nic *ni5010_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_NI5210
extern struct nic *ni5210_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_EXOS205
extern struct nic *exos205_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_SMC9000
extern struct nic *smc9000_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_TIARA
extern struct nic *tiara_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_DEPCA
extern struct nic *depca_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_RTL8139
extern struct nic *rtl8139_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_W89C840
extern struct nic *w89c840_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_SIS900
extern struct nic *sis900_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#endif /* CARDS_H */

598
src/etherboot/etherboot.h Normal file
View file

@ -0,0 +1,598 @@
/**************************************************************************
Etherboot - BOOTP/TFTP Bootstrap Program
Author: Martin Renters
Date: Dec/93
**************************************************************************/
#include "osdep.h"
/* These could be customised for different languages perhaps */
#define ASK_PROMPT "Boot from (N)etwork or from (L)ocal? "
#define ANS_NETWORK 'N'
#define ANS_LOCAL 'L'
#ifndef ANS_DEFAULT /* in case left out in Makefile */
#define ANS_DEFAULT ANS_NETWORK
#endif
#if !defined(TAGGED_IMAGE) && !defined(AOUT_IMAGE) && !defined(ELF_IMAGE)
#define TAGGED_IMAGE /* choose at least one */
#endif
#define ESC '\033'
/* Edit this to change the path to hostspecific kernel image
kernel.<client_ip_address> in RARP boot */
#ifndef DEFAULT_KERNELPATH
#define DEFAULT_KERNELPATH "/tftpboot/kernel.%I"
#endif
/* Edit this to change the default fallback kernel image.
This is used if bootp/dhcp-server doesn't provide the kernel path */
#ifndef DEFAULT_BOOTFILE
#define DEFAULT_BOOTFILE "/tftpboot/kernel"
#endif
/* Clean up console settings... mainly CONSOLE_CRT and CONSOLE_SERIAL are used
* in the sources (except start.S and serial.S which cannot include
* etherboot.h). At least one of the CONSOLE_xxx has to be set, and
* CONSOLE_DUAL sets both CONSOLE_CRT and CONSOLE_SERIAL. If none is set,
* CONSOLE_CRT is assumed. */
#ifdef CONSOLE_DUAL
#undef CONSOLE_CRT
#define CONSOLE_CRT
#undef CONSOLE_SERIAL
#define CONSOLE_SERIAL
#endif
#if defined(CONSOLE_CRT) && defined(CONSOLE_SERIAL)
#undef CONSOLE_DUAL
#define CONSOLE_DUAL
#endif
#if !defined(CONSOLE_CRT) && !defined(CONSOLE_SERIAL)
#define CONSOLE_CRT
#endif
#ifndef DOWNLOAD_PROTO_NFS
#undef DOWNLOAD_PROTO_TFTP
#define DOWNLOAD_PROTO_TFTP /* default booting protocol */
#endif
#ifdef DOWNLOAD_PROTO_TFTP
#define download(fname,loader) tftp((fname),(loader))
#endif
#ifdef DOWNLOAD_PROTO_NFS
#define download(fname,loader) nfs((fname),(loader))
#endif
#ifndef MAX_TFTP_RETRIES
#define MAX_TFTP_RETRIES 20
#endif
#ifndef MAX_BOOTP_RETRIES
#define MAX_BOOTP_RETRIES 20
#endif
#ifdef BOOTP_DATA_AT_0x93C00
#define MAX_BOOTP_EXTLEN (1024-sizeof(struct bootp_t))
#else
#define MAX_BOOTP_EXTLEN (ETH_FRAME_LEN-ETH_HLEN-sizeof(struct bootp_t))
#endif
#ifndef MAX_ARP_RETRIES
#define MAX_ARP_RETRIES 20
#endif
#ifndef MAX_RPC_RETRIES
#define MAX_RPC_RETRIES 20
#endif
#define TICKS_PER_SEC 18
/* Inter-packet retry in ticks */
#define TIMEOUT (10*TICKS_PER_SEC)
/* These settings have sense only if compiled with -DCONGESTED */
/* total retransmission timeout in ticks */
#define TFTP_TIMEOUT (30*TICKS_PER_SEC)
/* packet retransmission timeout in ticks */
#define TFTP_REXMT (3*TICKS_PER_SEC)
#ifndef NULL
#define NULL ((void *)0)
#endif
/*
I'm moving towards the defined names in linux/if_ether.h for clarity.
The confusion between 60/64 and 1514/1518 arose because the NS8390
counts the 4 byte frame checksum in the incoming packet, but not
in the outgoing packet. 60/1514 are the correct numbers for most
if not all of the other NIC controllers. I will be retiring the
64/1518 defines in the lead-up to 5.0.
*/
#define ETH_ALEN 6 /* Size of Ethernet address */
#define ETH_HLEN 14 /* Size of ethernet header */
#define ETH_ZLEN 60 /* Minimum packet */
/*#define ETH_MIN_PACKET 64*/
#define ETH_FRAME_LEN 1514 /* Maximum packet */
/*#define ETH_MAX_PACKET 1518*/
#define ARP_CLIENT 0
#define ARP_SERVER 1
#define ARP_GATEWAY 2
#define ARP_ROOTSERVER 3
#define ARP_SWAPSERVER 4
#define MAX_ARP ARP_SWAPSERVER+1
#define RARP_REQUEST 3
#define RARP_REPLY 4
#define IP 0x0800
#define ARP 0x0806
#define RARP 0x8035
#define BOOTP_SERVER 67
#define BOOTP_CLIENT 68
#define TFTP_PORT 69
#define SUNRPC_PORT 111
#define IP_UDP 17
/* Same after going through htonl */
#define IP_BROADCAST 0xFFFFFFFF
#define ARP_REQUEST 1
#define ARP_REPLY 2
#define BOOTP_REQUEST 1
#define BOOTP_REPLY 2
#define TAG_LEN(p) (*((p)+1))
#define RFC1533_COOKIE 99, 130, 83, 99
#define RFC1533_PAD 0
#define RFC1533_NETMASK 1
#define RFC1533_TIMEOFFSET 2
#define RFC1533_GATEWAY 3
#define RFC1533_TIMESERVER 4
#define RFC1533_IEN116NS 5
#define RFC1533_DNS 6
#define RFC1533_LOGSERVER 7
#define RFC1533_COOKIESERVER 8
#define RFC1533_LPRSERVER 9
#define RFC1533_IMPRESSSERVER 10
#define RFC1533_RESOURCESERVER 11
#define RFC1533_HOSTNAME 12
#define RFC1533_BOOTFILESIZE 13
#define RFC1533_MERITDUMPFILE 14
#define RFC1533_DOMAINNAME 15
#define RFC1533_SWAPSERVER 16
#define RFC1533_ROOTPATH 17
#define RFC1533_EXTENSIONPATH 18
#define RFC1533_IPFORWARDING 19
#define RFC1533_IPSOURCEROUTING 20
#define RFC1533_IPPOLICYFILTER 21
#define RFC1533_IPMAXREASSEMBLY 22
#define RFC1533_IPTTL 23
#define RFC1533_IPMTU 24
#define RFC1533_IPMTUPLATEAU 25
#define RFC1533_INTMTU 26
#define RFC1533_INTLOCALSUBNETS 27
#define RFC1533_INTBROADCAST 28
#define RFC1533_INTICMPDISCOVER 29
#define RFC1533_INTICMPRESPOND 30
#define RFC1533_INTROUTEDISCOVER 31
#define RFC1533_INTROUTESOLICIT 32
#define RFC1533_INTSTATICROUTES 33
#define RFC1533_LLTRAILERENCAP 34
#define RFC1533_LLARPCACHETMO 35
#define RFC1533_LLETHERNETENCAP 36
#define RFC1533_TCPTTL 37
#define RFC1533_TCPKEEPALIVETMO 38
#define RFC1533_TCPKEEPALIVEGB 39
#define RFC1533_NISDOMAIN 40
#define RFC1533_NISSERVER 41
#define RFC1533_NTPSERVER 42
#define RFC1533_VENDOR 43
#define RFC1533_NBNS 44
#define RFC1533_NBDD 45
#define RFC1533_NBNT 46
#define RFC1533_NBSCOPE 47
#define RFC1533_XFS 48
#define RFC1533_XDM 49
#ifndef NO_DHCP_SUPPORT
#define RFC2132_REQ_ADDR 50
#define RFC2132_MSG_TYPE 53
#define RFC2132_SRV_ID 54
#define RFC2132_PARAM_LIST 55
#define RFC2132_MAX_SIZE 57
#define RFC2132_VENDOR_CLASS_ID 60
#define DHCPDISCOVER 1
#define DHCPOFFER 2
#define DHCPREQUEST 3
#define DHCPACK 5
#endif /* NO_DHCP_SUPPORT */
#define RFC1533_VENDOR_MAJOR 0
#define RFC1533_VENDOR_MINOR 0
#define RFC1533_VENDOR_MAGIC 128
#define RFC1533_VENDOR_ADDPARM 129
#define RFC1533_VENDOR_ETHDEV 130
#ifdef IMAGE_FREEBSD
#define RFC1533_VENDOR_HOWTO 132
#endif
#define RFC1533_VENDOR_MNUOPTS 160
#define RFC1533_VENDOR_SELECTION 176
#define RFC1533_VENDOR_MOTD 184
#define RFC1533_VENDOR_NUMOFMOTD 8
#define RFC1533_VENDOR_IMG 192
#define RFC1533_VENDOR_NUMOFIMG 16
#define RFC1533_END 255
#define BOOTP_VENDOR_LEN 64
#ifndef NO_DHCP_SUPPORT
#define DHCP_OPT_LEN 312
#endif /* NO_DHCP_SUPPORT */
#define TFTP_DEFAULTSIZE_PACKET 512
#define TFTP_MAX_PACKET 1432 /* 512 */
#define TFTP_RRQ 1
#define TFTP_WRQ 2
#define TFTP_DATA 3
#define TFTP_ACK 4
#define TFTP_ERROR 5
#define TFTP_OACK 6
#define TFTP_CODE_EOF 1
#define TFTP_CODE_MORE 2
#define TFTP_CODE_ERROR 3
#define TFTP_CODE_BOOT 4
#define TFTP_CODE_CFG 5
#define AWAIT_ARP 0
#define AWAIT_BOOTP 1
#define AWAIT_TFTP 2
#define AWAIT_RARP 3
#define AWAIT_RPC 4
#define AWAIT_QDRAIN 5 /* drain queue, process ARP requests */
typedef struct {
unsigned long s_addr;
} in_addr;
struct arptable_t {
in_addr ipaddr;
unsigned char node[6];
};
/*
* A pity sipaddr and tipaddr are not longword aligned or we could use
* in_addr. No, I don't want to use #pragma packed.
*/
struct arprequest {
unsigned short hwtype;
unsigned short protocol;
char hwlen;
char protolen;
unsigned short opcode;
char shwaddr[6];
char sipaddr[4];
char thwaddr[6];
char tipaddr[4];
};
struct iphdr {
char verhdrlen;
char service;
unsigned short len;
unsigned short ident;
unsigned short frags;
char ttl;
char protocol;
unsigned short chksum;
in_addr src;
in_addr dest;
};
struct udphdr {
unsigned short src;
unsigned short dest;
unsigned short len;
unsigned short chksum;
};
/* Format of a bootp packet */
struct bootp_t {
char bp_op;
char bp_htype;
char bp_hlen;
char bp_hops;
unsigned long bp_xid;
unsigned short bp_secs;
unsigned short unused;
in_addr bp_ciaddr;
in_addr bp_yiaddr;
in_addr bp_siaddr;
in_addr bp_giaddr;
char bp_hwaddr[16];
char bp_sname[64];
char bp_file[128];
#ifdef NO_DHCP_SUPPORT
char bp_vend[BOOTP_VENDOR_LEN];
#else
char bp_vend[DHCP_OPT_LEN];
#endif /* NO_DHCP_SUPPORT */
};
/* Format of a bootp IP packet */
struct bootpip_t
{
struct iphdr ip;
struct udphdr udp;
struct bootp_t bp;
};
/* Format of bootp packet with extensions */
struct bootpd_t {
struct bootp_t bootp_reply;
unsigned char bootp_extension[MAX_BOOTP_EXTLEN];
};
#define KERNEL_BUF (BOOTP_DATA_ADDR->bootp_reply.bp_file)
struct tftp_t {
struct iphdr ip;
struct udphdr udp;
unsigned short opcode;
union {
char rrq[TFTP_DEFAULTSIZE_PACKET];
struct {
unsigned short block;
char download[TFTP_MAX_PACKET];
} data;
struct {
unsigned short block;
} ack;
struct {
unsigned short errcode;
char errmsg[TFTP_DEFAULTSIZE_PACKET];
} err;
struct {
char data[TFTP_DEFAULTSIZE_PACKET+2];
} oack;
} u;
};
/* define a smaller tftp packet solely for making requests to conserve stack
512 bytes should be enough */
struct tftpreq_t {
struct iphdr ip;
struct udphdr udp;
unsigned short opcode;
union {
char rrq[512];
struct {
unsigned short block;
} ack;
struct {
unsigned short errcode;
char errmsg[512-2];
} err;
} u;
};
#define TFTP_MIN_PACKET (sizeof(struct iphdr) + sizeof(struct udphdr) + 4)
struct rpc_t {
struct iphdr ip;
struct udphdr udp;
union {
char data[300]; /* longest RPC call must fit!!!! */
struct {
long id;
long type;
long rpcvers;
long prog;
long vers;
long proc;
long data[1];
} call;
struct {
long id;
long type;
long rstatus;
long verifier;
long v2;
long astatus;
long data[1];
} reply;
} u;
};
#define PROG_PORTMAP 100000
#define PROG_NFS 100003
#define PROG_MOUNT 100005
#define MSG_CALL 0
#define MSG_REPLY 1
#define PORTMAP_GETPORT 3
#define MOUNT_ADDENTRY 1
#define MOUNT_UMOUNTALL 4
#define NFS_LOOKUP 4
#define NFS_READ 6
#define NFS_FHSIZE 32
#define NFSERR_PERM 1
#define NFSERR_NOENT 2
#define NFSERR_ACCES 13
/* Block size used for NFS read accesses. A RPC reply packet (including all
* headers) must fit within a single Ethernet frame to avoid fragmentation.
* Chosen to be a power of two, as most NFS servers are optimized for this. */
#define NFS_READ_SIZE 1024
#define FLOPPY_BOOT_LOCATION 0x7c00
#define ROM_INFO_LOCATION 0x7dfa
/* at end of floppy boot block */
struct rom_info {
unsigned short rom_segment;
unsigned short rom_length;
};
extern inline int rom_address_ok(struct rom_info *rom, int assigned_rom_segment)
{
return (assigned_rom_segment < 0xC000
|| assigned_rom_segment == rom->rom_segment);
}
/* Define a type for use by setjmp and longjmp */
typedef struct {
unsigned long buf[7];
} jmpbuf[1];
/* Define a type for passing info to a loaded program */
struct ebinfo {
unsigned char major, minor; /* Version */
unsigned short flags; /* Bit flags */
};
/***************************************************************************
External prototypes
***************************************************************************/
/* main.c */
extern int tftp P((const char *name, int (*)(unsigned char *, int, int, int)));
extern int udp_transmit P((unsigned long destip, unsigned int srcsock,
unsigned int destsock, int len, const void *buf));
extern int await_reply P((int type, int ival, void *ptr, int timeout));
extern int decode_rfc1533 P((unsigned char *, int, int, int));
extern void rfc951_sleep P((int));
extern void cleanup P((void));
/* nfs.c */
extern void rpc_init(void);
extern int nfs P((const char *name, int (*)(unsigned char *, int, int, int)));
extern void nfs_umountall P((int));
/* config.c */
extern void print_config(void);
extern void eth_reset(void);
extern int eth_probe(void);
extern int eth_poll(void);
extern void eth_transmit(const char *d, unsigned int t, unsigned int s, const void *p);
extern void eth_disable(void);
/* bootmenu.c */
extern void bootmenu P((int));
extern void show_motd P((void));
extern void parse_menuopts P((char *,int));
extern void selectImage P((char **));
/* osloader.c */
#if defined(AOUT_IMAGE) || defined(ELF_IMAGE)
extern int howto;
#endif
extern int os_download P((unsigned int, unsigned char *,unsigned int));
/* misc.c */
extern void twiddle P((void));
extern void sleep P((int secs));
extern int strcasecmp P((char *a, char *b));
extern char *substr P((char *a, char *b));
extern int getdec P((char **));
extern void printf P((const char *, ...));
extern int sprintf P((char *, const char *, ...));
extern int inet_aton P((char *p, in_addr *i));
extern void gateA20_set P((void));
extern void gateA20_unset P((void));
extern void putchar P((int));
extern int getchar P((void));
extern int iskey P((void));
/* start*.S */
extern int console_getc P((void));
extern void console_putc P((int));
extern int console_ischar P((void));
extern int getshift P((void));
extern unsigned int memsize P((void));
extern unsigned short basememsize P((void));
extern void disk_init P((void));
extern unsigned int disk_read P((int drv,int c,int h,int s,char *buf));
extern void xstart P((unsigned long, unsigned long, char *));
#ifdef IMAGE_MULTIBOOT
extern void xend P((void));
#endif
extern unsigned long currticks P((void));
extern int setjmp P((jmpbuf env));
extern void longjmp P((jmpbuf env, int val));
extern void exit P((int status));
/* serial.S */
extern int serial_getc P((void));
extern void serial_putc P((int));
extern int serial_ischar P((void));
extern int serial_init P((void));
/* ansiesc.c */
extern void ansi_reset P((void));
extern void enable_cursor P((int));
extern void ansi_putc P((unsigned int));
/* md5.c */
extern void md5_put P((unsigned int ch));
extern void md5_done P((unsigned char *buf));
/* floppy.c */
extern int bootdisk P((int dev,int part));
/***************************************************************************
External variables
***************************************************************************/
/* main.c */
extern struct rom_info rom;
extern char *hostname;
extern int hostnamelen;
extern jmpbuf jmp_bootmenu;
extern struct arptable_t arptable[MAX_ARP];
#ifdef IMAGE_MENU
extern int menutmo,menudefault;
extern unsigned char *defparams;
extern int defparams_max;
#endif
#ifdef MOTD
extern char *motd[RFC1533_VENDOR_NUMOFMOTD];
#endif
#ifdef BOOTP_DATA_AT_0x93C00
#define BOOTP_DATA_ADDR ((struct bootpd_t *)0x93C00)
#else
extern struct bootpd_t bootp_data;
#define BOOTP_DATA_ADDR (&bootp_data)
#endif
extern unsigned char *end_of_rfc1533;
#ifdef IMAGE_FREEBSD
extern int freebsd_howto;
#endif
/* config.c */
extern struct nic nic;
/* bootmenu.c */
/* osloader.c */
/* created by linker */
extern char _start[], edata[], end[];
/*
* Local variables:
* c-basic-offset: 8
* End:
*/

View file

@ -0,0 +1,187 @@
#ifndef _ASM_IO_H
#define _ASM_IO_H
/*
* This file contains the definitions for the x86 IO instructions
* inb/inw/inl/outb/outw/outl and the "string versions" of the same
* (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
* versions of the single-IO instructions (inb_p/inw_p/..).
*
* This file is not meant to be obfuscating: it's just complicated
* to (a) handle it all in a way that makes gcc able to optimize it
* as well as possible and (b) trying to avoid writing the same thing
* over and over again with slight variations and possibly making a
* mistake somewhere.
*/
/*
* 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 about using 0x80 (should be safe, though)
*
* 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
/*
* readX/writeX() are used to access memory mapped devices. On some
* architectures the memory mapped IO stuff needs to be accessed
* differently. On the x86 architecture, we just read/write the
* memory location directly.
*/
#define readb(addr) (*(volatile unsigned char *) (addr))
#define readw(addr) (*(volatile unsigned short *) (addr))
#define readl(addr) (*(volatile unsigned int *) (addr))
#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
#define memset_io(a,b,c) memset((void *)(a),(b),(c))
#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
/*
* Again, i386 does not require mem IO specific function.
*/
#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d))
/*
* Talk about misusing macros..
*/
#define __OUT1(s,x) \
extern void __out##s(unsigned x value, unsigned short port); \
extern inline void __out##s(unsigned x value, unsigned short port) {
#define __OUT2(s,s1,s2) \
__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
#define __OUT(s,s1,x) \
__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \
__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \
__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \
__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; }
#define __IN1(s,x) \
extern unsigned x __in##s(unsigned short port); \
extern inline unsigned x __in##s(unsigned short port) { unsigned x _v;
#define __IN2(s,s1,s2) \
__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
#define __IN(s,s1,x,i...) \
__IN1(s,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \
__IN1(s##c,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \
__IN1(s##_p,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \
__IN1(s##c_p,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; }
#define __INS(s) \
extern void ins##s(unsigned short port, void * addr, unsigned long count); \
extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
{ __asm__ __volatile__ ("cld ; rep ; ins" #s \
: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
#define __OUTS(s) \
extern void outs##s(unsigned short port, const void * addr, unsigned long count); \
extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
{ __asm__ __volatile__ ("cld ; rep ; outs" #s \
: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
__IN(b,"", char)
__IN(w,"",short)
__IN(l,"", long)
__OUT(b,"b",char)
__OUT(w,"w",short)
__OUT(l,,int)
__INS(b)
__INS(w)
__INS(l)
__OUTS(b)
__OUTS(w)
__OUTS(l)
/*
* Note that due to the way __builtin_constant_p() works, you
* - can't use it inside a inline function (it will never be true)
* - you don't have to worry about side effects within the __builtin..
*/
#define outb(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outbc((val),(port)) : \
__outb((val),(port)))
#define inb(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inbc(port) : \
__inb(port))
#define outb_p(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outbc_p((val),(port)) : \
__outb_p((val),(port)))
#define inb_p(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inbc_p(port) : \
__inb_p(port))
#define outw(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outwc((val),(port)) : \
__outw((val),(port)))
#define inw(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inwc(port) : \
__inw(port))
#define outw_p(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outwc_p((val),(port)) : \
__outw_p((val),(port)))
#define inw_p(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inwc_p(port) : \
__inw_p(port))
#define outl(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outlc((val),(port)) : \
__outl((val),(port)))
#define inl(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inlc(port) : \
__inl(port))
#define outl_p(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outlc_p((val),(port)) : \
__outl_p((val),(port)))
#define inl_p(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inlc_p(port) : \
__inl_p(port))
#endif

View file

@ -0,0 +1,253 @@
/*
* Taken from Linux /usr/include/asm/string.h
* All except memcpy, memmove, memset and memcmp removed.
*/
#ifndef _I386_STRING_H_
#define _I386_STRING_H_
#include <types.h>
/*
* This string-include defines all string functions as inline
* functions. Use gcc. It also assumes ds=es=data space, this should be
* normal. Most of the string-functions are rather heavily hand-optimized,
* see especially strtok,strstr,str[c]spn. They should work, but are not
* very easy to understand. Everything is done entirely within the register
* set, making the functions fast and clean. String instructions have been
* used through-out, making for "slightly" unclear code :-)
*
* NO Copyright (C) 1991, 1992 Linus Torvalds,
* consider these trivial functions to be PD.
*/
extern void *__memcpy(void * to, const void * from, size_t n);
extern void *__constant_memcpy(void * to, const void * from, size_t n);
extern void *memmove(void * dest,const void * src, size_t n);
extern void *__memset_generic(void * s, char c,size_t count);
extern void *__constant_c_memset(void * s, unsigned long c, size_t count);
extern void *__constant_c_and_count_memset(void * s, unsigned long pattern, size_t count);
extern inline void * __memcpy(void * to, const void * from, size_t n)
{
int d0, d1, d2;
__asm__ __volatile__(
"cld\n\t"
"rep ; movsl\n\t"
"testb $2,%b4\n\t"
"je 1f\n\t"
"movsw\n"
"1:\ttestb $1,%b4\n\t"
"je 2f\n\t"
"movsb\n"
"2:"
: "=&c" (d0), "=&D" (d1), "=&S" (d2)
:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
: "memory");
return (to);
}
/*
* This looks horribly ugly, but the compiler can optimize it totally,
* as the count is constant.
*/
extern inline void * __constant_memcpy(void * to, const void * from, size_t n)
{
switch (n) {
case 0:
return to;
case 1:
*(unsigned char *)to = *(const unsigned char *)from;
return to;
case 2:
*(unsigned short *)to = *(const unsigned short *)from;
return to;
case 3:
*(unsigned short *)to = *(const unsigned short *)from;
*(2+(unsigned char *)to) = *(2+(const unsigned char *)from);
return to;
case 4:
*(unsigned long *)to = *(const unsigned long *)from;
return to;
case 6: /* for Ethernet addresses */
*(unsigned long *)to = *(const unsigned long *)from;
*(2+(unsigned short *)to) = *(2+(const unsigned short *)from);
return to;
case 8:
*(unsigned long *)to = *(const unsigned long *)from;
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
return to;
case 12:
*(unsigned long *)to = *(const unsigned long *)from;
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
return to;
case 16:
*(unsigned long *)to = *(const unsigned long *)from;
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
*(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
return to;
case 20:
*(unsigned long *)to = *(const unsigned long *)from;
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
*(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
*(4+(unsigned long *)to) = *(4+(const unsigned long *)from);
return to;
}
#define COMMON(x) \
__asm__ __volatile__( \
"cld\n\t" \
"rep ; movsl" \
x \
: "=&c" (d0), "=&D" (d1), "=&S" (d2) \
: "0" (n/4),"1" ((long) to),"2" ((long) from) \
: "memory");
{
int d0, d1, d2;
switch (n % 4) {
case 0: COMMON(""); return to;
case 1: COMMON("\n\tmovsb"); return to;
case 2: COMMON("\n\tmovsw"); return to;
default: COMMON("\n\tmovsw\n\tmovsb"); return to;
}
}
#undef COMMON
}
#define __HAVE_ARCH_MEMCPY
#define memcpy(t, f, n) \
(__builtin_constant_p(n) ? \
__constant_memcpy((t),(f),(n)) : \
__memcpy((t),(f),(n)))
#define __HAVE_ARCH_MEMMOVE
extern inline void * memmove(void * dest,const void * src, size_t n)
{
int d0, d1, d2;
if (dest<src)
__asm__ __volatile__(
"cld\n\t"
"rep\n\t"
"movsb"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
:"0" (n),"1" (src),"2" (dest)
: "memory");
else
__asm__ __volatile__(
"std\n\t"
"rep\n\t"
"movsb\n\t"
"cld"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
:"0" (n),
"1" (n-1+(const char *)src),
"2" (n-1+(char *)dest)
:"memory");
return dest;
}
#define memcmp __builtin_memcmp
extern inline void * __memset_generic(void * s, char c,size_t count)
{
int d0, d1;
__asm__ __volatile__(
"cld\n\t"
"rep\n\t"
"stosb"
: "=&c" (d0), "=&D" (d1)
:"a" (c),"1" (s),"0" (count)
:"memory");
return s;
}
/* we might want to write optimized versions of these later */
#define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
/*
* memset(x,0,y) is a reasonably common thing to do, so we want to fill
* things 32 bits at a time even when we don't know the size of the
* area at compile-time..
*/
extern inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
{
int d0, d1;
__asm__ __volatile__(
"cld\n\t"
"rep ; stosl\n\t"
"testb $2,%b3\n\t"
"je 1f\n\t"
"stosw\n"
"1:\ttestb $1,%b3\n\t"
"je 2f\n\t"
"stosb\n"
"2:"
: "=&c" (d0), "=&D" (d1)
:"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
:"memory");
return (s);
}
/*
* This looks horribly ugly, but the compiler can optimize it totally,
* as we by now know that both pattern and count is constant..
*/
extern inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
{
switch (count) {
case 0:
return s;
case 1:
*(unsigned char *)s = pattern;
return s;
case 2:
*(unsigned short *)s = pattern;
return s;
case 3:
*(unsigned short *)s = pattern;
*(2+(unsigned char *)s) = pattern;
return s;
case 4:
*(unsigned long *)s = pattern;
return s;
}
#define COMMON(x) \
__asm__ __volatile__("cld\n\t" \
"rep ; stosl" \
x \
: "=&c" (d0), "=&D" (d1) \
: "a" (pattern),"0" (count/4),"1" ((long) s) \
: "memory")
{
int d0, d1;
switch (count % 4) {
case 0: COMMON(""); return s;
case 1: COMMON("\n\tstosb"); return s;
case 2: COMMON("\n\tstosw"); return s;
default: COMMON("\n\tstosw\n\tstosb"); return s;
}
}
#undef COMMON
}
#define __constant_c_x_memset(s, c, count) \
(__builtin_constant_p(count) ? \
__constant_c_and_count_memset((s),(c),(count)) : \
__constant_c_memset((s),(c),(count)))
#define __memset(s, c, count) \
(__builtin_constant_p(count) ? \
__constant_count_memset((s),(c),(count)) : \
__memset_generic((s),(c),(count)))
#define __HAVE_ARCH_MEMSET
#define memset(s, c, count) \
(__builtin_constant_p(c) ? \
__constant_c_x_memset((s),(c),(count)) : \
__memset((s),(c),(count)))
#endif

112
src/etherboot/netboot.c Normal file
View file

@ -0,0 +1,112 @@
#include <printk.h>
#include <pciconf.h>
#include <subr.h>
#include <pci.h>
#include <pci_ids.h>
#include <cpu/p5/io.h>
#include "nic.h"
#include "sis900.h"
#include "etherboot.h"
struct nic nic;
unsigned char eth_addr[6];
int acpi_base;
void init_HR_TIMER(void)
{
int j;
outl(0x80000840, 0x0cf8);
acpi_base = inb(0x0cfc) | 0x80;
outb(acpi_base, 0x0cfc);
outl(0x80000874, 0x0cf8);
acpi_base = inw(0x0cfc);
printk("init_HR_TIMER: acpi_base = %04x\n", acpi_base);
j = inw(acpi_base + 0x56) | 0x02; // HR_TMR control
outw(j, acpi_base + 0x56); // activate HR_TMR
}
inline unsigned long currticks(void)
{
unsigned long int j=0;
j = inl(acpi_base + 0x4c);
j /= 55555; // HR_TMR runs at 1MHz, etherboot drivers expect 18.2Hz, but this will be close enough.
return(j);
}
int test_display_tftp_callback(char *data, int block, int length, int eof)
{
int i;
#ifdef DEBUG
printk("RECD block %u, length = %u:\n",block, length);
#endif
for(i=0; i<length; i++)
if(!data[i])
printk("|");
else
printk("%c",data[i]);
#ifdef DEBUG
if(eof)
printk("\nEND OF FILE\n");
printk("====================\n");
#endif
return(-1);
}
char buffer[1024];
void netboot_init()
{
struct pci_dev *pcidev;
struct nic *result;
unsigned short iobase = 0x0b001; // address = 0x0b00, I/O port space
int rc=512;
int i;
nic.node_addr = eth_addr;
/* first, init the sis900 ethernet! */
pcidev = pci_find_device(PCI_VENDOR_ID_SI, 0x0900, (void *)NULL);
pci_write_config_byte(pcidev, PCI_BASE_ADDRESS_0, iobase);
printk("\ncalling init_HR_TIMER\n");
init_HR_TIMER();
result = sis900_probe(&nic, &iobase, pcidev);
printk("netboot_init : sis900_probe = %04x\n", (unsigned int) result);
memcpy(arptable[ARP_CLIENT].node, eth_addr, ETH_ALEN);
printk("doing rarp:\n");
rarp();
printk("My IP address is: %04x\n",arptable[ARP_CLIENT].ipaddr.s_addr);
printk("My server's IP address is: %04x\n",arptable[ARP_SERVER].ipaddr.s_addr);
#ifdef DEBUG
printk("Now testing tftp, transferring cmdline\n");
// tftp("cmdline", test_display_tftp_callback);
tftp_init("cmdline");
while(rc == 512) {
rc = tftp_fetchone(buffer);
for(i=0; i<rc; i++)
if(!buffer[i])
printk("|");
else
printk("%c",buffer[i]);
}
#endif
}

31
src/etherboot/nic.h Normal file
View file

@ -0,0 +1,31 @@
/*
* 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, or (at
* your option) any later version.
*/
#ifndef NIC_H
#define NIC_H
/*
* Structure returned from eth_probe and passed to other driver
* functions.
*/
struct nic
{
void (*reset)(struct nic *);
int (*poll)(struct nic *);
void (*transmit)(struct nic *, const char *d,
unsigned int t, unsigned int s, const char *p);
void (*disable)(struct nic *);
int flags; /* driver specific flags */
struct rom_info *rom_info; /* -> rom_info from main */
unsigned char *node_addr;
char *packet;
unsigned int packetlen;
void *priv_data; /* driver can hang private data here */
};
#endif /* NIC_H */

121
src/etherboot/osdep.h Normal file
View file

@ -0,0 +1,121 @@
#ifndef __OSDEP_H__
#define __OSDEP_H__
/*
* 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, or (at
* your option) any later version.
*/
#define __LITTLE_ENDIAN /* x86 */
/* Taken from /usr/include/linux/hfs_sysdep.h */
#if defined(__BIG_ENDIAN)
# if !defined(__constant_htonl)
# define __constant_htonl(x) (x)
# endif
# if !defined(__constant_htons)
# define __constant_htons(x) (x)
# endif
#elif defined(__LITTLE_ENDIAN)
# if !defined(__constant_htonl)
# define __constant_htonl(x) \
((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
(((unsigned long int)(x) & 0x0000ff00U) << 8) | \
(((unsigned long int)(x) & 0x00ff0000U) >> 8) | \
(((unsigned long int)(x) & 0xff000000U) >> 24)))
# endif
# if !defined(__constant_htons)
# define __constant_htons(x) \
((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
(((unsigned short int)(x) & 0xff00) >> 8)))
# endif
#else
# error "Don't know if bytes are big- or little-endian!"
#endif
#define ntohl(x) \
(__builtin_constant_p(x) ? \
__constant_htonl((x)) : \
__swap32(x))
#define htonl(x) \
(__builtin_constant_p(x) ? \
__constant_htonl((x)) : \
__swap32(x))
#define ntohs(x) \
(__builtin_constant_p(x) ? \
__constant_htons((x)) : \
__swap16(x))
#define htons(x) \
(__builtin_constant_p(x) ? \
__constant_htons((x)) : \
__swap16(x))
static inline unsigned long int __swap32(unsigned long int x)
{
__asm__("xchgb %b0,%h0\n\t"
"rorl $16,%0\n\t"
"xchgb %b0,%h0"
: "=q" (x)
: "0" (x));
return x;
}
static inline unsigned short int __swap16(unsigned short int x)
{
__asm__("xchgb %b0,%h0"
: "=q" (x)
: "0" (x));
return x;
}
/* Make routines available to all */
#define swap32(x) __swap32(x)
#define swap16(x) __swap16(x)
/* Taken from asm/string-486.h */
#define __HAVE_ARCH_STRNCMP
extern inline int strncmp(const char * cs,const char * ct,int count)
{
register int __res;
__asm__ __volatile__(
"\n1:\tdecl %3\n\t"
"js 2f\n\t"
"movb (%1),%b0\n\t"
"incl %1\n\t"
"cmpb %b0,(%2)\n\t"
"jne 3f\n\t"
"incl %2\n\t"
"testb %b0,%b0\n\t"
"jne 1b\n"
"2:\txorl %0,%0\n\t"
"jmp 4f\n"
"3:\tmovl $1,%0\n\t"
"jb 4f\n\t"
"negl %0\n"
"4:"
:"=q" (__res), "=r" (cs), "=r" (ct), "=r" (count)
:"1" (cs), "2" (ct), "3" (count));
return __res;
}
#include "linux-asm-string.h"
#include "linux-asm-io.h"
typedef unsigned long Address;
/* ANSI prototyping macro */
#ifdef __STDC__
#define P(x) x
#else
#define P(x) ()
#endif
#endif
/*
* Local variables:
* c-basic-offset: 8
* End:
*/

178
src/etherboot/pci.h Normal file
View file

@ -0,0 +1,178 @@
#ifndef PCI_H
#define PCI_H
/*
** Support for NE2000 PCI clones added David Monro June 1997
** Generalised for other PCI NICs by Ken Yap July 1997
**
** Most of this is taken from:
**
** /usr/src/linux/drivers/pci/pci.c
** /usr/src/linux/include/linux/pci.h
** /usr/src/linux/arch/i386/bios32.c
** /usr/src/linux/include/linux/bios32.h
** /usr/src/linux/drivers/net/ne.c
*/
/*
* 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, or (at
* your option) any later version.
*/
#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */
#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
#define PCIBIOS_PCI_FUNCTION_ID 0xb1XX
#define PCIBIOS_PCI_BIOS_PRESENT 0xb101
#define PCIBIOS_FIND_PCI_DEVICE 0xb102
#define PCIBIOS_FIND_PCI_CLASS_CODE 0xb103
#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106
#define PCIBIOS_READ_CONFIG_BYTE 0xb108
#define PCIBIOS_READ_CONFIG_WORD 0xb109
#define PCIBIOS_READ_CONFIG_DWORD 0xb10a
#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b
#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c
#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d
#define PCI_VENDOR_ID 0x00 /* 16 bits */
#define PCI_DEVICE_ID 0x02 /* 16 bits */
#define PCI_COMMAND 0x04 /* 16 bits */
#define PCI_REVISION 0x08 /* 8 bits */
#define PCI_CLASS_CODE 0x0b /* 8 bits */
#define PCI_SUBCLASS_CODE 0x0a /* 8 bits */
#define PCI_HEADER_TYPE 0x0e /* 8 bits */
#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits */
#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits */
#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
#ifndef PCI_BASE_ADDRESS_IO_MASK
#define PCI_BASE_ADDRESS_IO_MASK (~0x03)
#endif
#define PCI_BASE_ADDRESS_SPACE_IO 0x01
#define PCI_ROM_ADDRESS 0x30 /* 32 bits */
#define PCI_ROM_ADDRESS_ENABLE 0x01 /* Write 1 to enable ROM,
bits 31..11 are address,
10..2 are reserved */
#define PCI_FUNC(devfn) ((devfn) & 0x07)
#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
/* PCI signature: "PCI " */
#define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
/* PCI service signature: "$PCI" */
#define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
union bios32 {
struct {
unsigned long signature; /* _32_ */
unsigned long entry; /* 32 bit physical address */
unsigned char revision; /* Revision level, 0 */
unsigned char length; /* Length in paragraphs should be 01 */
unsigned char checksum; /* All bytes must add up to zero */
unsigned char reserved[5]; /* Must be zero */
} fields;
char chars[16];
};
#define KERN_CODE_SEG 0x8 /* This _MUST_ match start.S */
/* Stuff for asm */
#define save_flags(x) \
__asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory")
#define cli() __asm__ __volatile__ ("cli": : :"memory")
#define restore_flags(x) \
__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
#define PCI_VENDOR_ID_ADMTEK 0x1317
#define PCI_DEVICE_ID_ADMTEK_0985 0x0985
#define PCI_VENDOR_ID_REALTEK 0x10ec
#define PCI_DEVICE_ID_REALTEK_8029 0x8029
#define PCI_DEVICE_ID_REALTEK_8139 0x8139
#define PCI_VENDOR_ID_WINBOND2 0x1050
#define PCI_DEVICE_ID_WINBOND2_89C940 0x0940
#define PCI_DEVICE_ID_WINBOND2_89C840 0x0840
#define PCI_VENDOR_ID_COMPEX 0x11f6
#define PCI_DEVICE_ID_COMPEX_RL2000 0x1401
#define PCI_DEVICE_ID_COMPEX_RL100ATX 0x2011
#define PCI_VENDOR_ID_KTI 0x8e2e
#define PCI_DEVICE_ID_KTI_ET32P2 0x3000
#define PCI_VENDOR_ID_NETVIN 0x4a14
#define PCI_DEVICE_ID_NETVIN_NV5000SC 0x5000
#define PCI_VENDOR_ID_3COM 0x10b7
#define PCI_DEVICE_ID_3COM_3C590 0x5900
#define PCI_DEVICE_ID_3COM_3C595 0x5950
#define PCI_DEVICE_ID_3COM_3C595_1 0x5951
#define PCI_DEVICE_ID_3COM_3C595_2 0x5952
#define PCI_DEVICE_ID_3COM_3C900TPO 0x9000
#define PCI_DEVICE_ID_3COM_3C900COMBO 0x9001
#define PCI_DEVICE_ID_3COM_3C905TX 0x9050
#define PCI_DEVICE_ID_3COM_3C905T4 0x9051
#define PCI_DEVICE_ID_3COM_3C905B_TX 0x9055
#define PCI_DEVICE_ID_3COM_3C905C_TXM 0x9200
#define PCI_VENDOR_ID_INTEL 0x8086
#define PCI_DEVICE_ID_INTEL_82557 0x1229
#define PCI_DEVICE_ID_INTEL_82559ER 0x1209
#define PCI_DEVICE_ID_INTEL_ID1029 0x1029
#define PCI_DEVICE_ID_INTEL_ID1030 0x1030
#define PCI_DEVICE_ID_INTEL_82562 0x2449
#define PCI_VENDOR_ID_AMD 0x1022
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
#define PCI_VENDOR_ID_AMD_HOMEPNA 0x1022
#define PCI_DEVICE_ID_AMD_HOMEPNA 0x2001
#define PCI_VENDOR_ID_SMC_1211 0x1113
#define PCI_DEVICE_ID_SMC_1211 0x1211
#define PCI_VENDOR_ID_DEC 0x1011
#define PCI_DEVICE_ID_DEC_TULIP 0x0002
#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014
#define PCI_DEVICE_ID_DEC_21142 0x0019
#define PCI_VENDOR_ID_SMC 0x10B8
#ifndef PCI_DEVICE_ID_SMC_EPIC100
# define PCI_DEVICE_ID_SMC_EPIC100 0x0005
#endif
#define PCI_VENDOR_ID_MACRONIX 0x10d9
#define PCI_DEVICE_ID_MX987x5 0x0531
#define PCI_VENDOR_ID_LINKSYS 0x11AD
#define PCI_DEVICE_ID_LC82C115 0xC115
#define PCI_VENDOR_ID_VIATEC 0x1106
#define PCI_DEVICE_ID_VIA_RHINE_I 0x3043
#define PCI_DEVICE_ID_VIA_VT6102 0x3065
#define PCI_DEVICE_ID_VIA_86C100A 0x6100
#define PCI_VENDOR_ID_DAVICOM 0x1282
#define PCI_DEVICE_ID_DM9009 0x9009
#define PCI_DEVICE_ID_DM9102 0x9102
#define PCI_VENDOR_ID_SIS 0x1039
#define PCI_DEVICE_ID_SIS900 0x0900
#define PCI_DEVICE_ID_SIS7016 0x7016
#define PCI_VENDOR_ID_DLINK 0x1186
#define PCI_DEVICE_ID_DFE530TXP 0x1300
struct pci_device {
unsigned short vendor, dev_id;
const char *name;
unsigned int membase;
unsigned short ioaddr;
unsigned char devfn;
unsigned char bus;
};
extern void eth_pci_init(struct pci_device *);
extern int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned char *value);
extern int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned char value);
extern int pcibios_read_config_word(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned short *value);
extern int pcibios_write_config_word (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned short value);
extern int pcibios_write_config_dword(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int value);
#endif /* PCI_H */

734
src/etherboot/rarp.c Normal file
View file

@ -0,0 +1,734 @@
#include "etherboot.h"
#include "nic.h"
static unsigned long xid;
#define eth_poll() nic.poll(&nic)
#define eth_transmit(a,b,c,d) nic.transmit(&nic,a,b,c, (char *) d)
int decode_rfc1533(unsigned char *p, int block, int len, int eof)
{
return(-1); // don't support it yet, just define it!
}
#define NO_DHCP_SUPPORT
#define EMERGENCYDISKBOOT
#define getchar() ttys0_rx_char()
static const unsigned char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
static unsigned long netmask;
struct arptable_t arptable[MAX_ARP];
struct bootpd_t bootp_data;
/***************************************************************************
getdec, a simple sort of atoi
***************************************************************************/
int getdec(char **ptr)
{
char *p = *ptr;
int ret=0;
if ((*p < '0') || (*p > '9')) return(-1);
while ((*p >= '0') && (*p <= '9')) {
ret = ret*10 + (*p - '0');
p++;
}
*ptr = p;
return(ret);
}
/**************************************************************************
STRCASECMP (not entirely correct, but this will do for our purposes)
**************************************************************************/
int strcasecmp(char *a, char *b)
{
while (*a && *b && (*a & ~0x20) == (*b & ~0x20)) {a++; b++; }
return((*a & ~0x20) - (*b & ~0x20));
}
/**************************************************************************
DEFAULT_NETMASK - Return default netmask for IP address
**************************************************************************/
static inline unsigned long default_netmask(void)
{
int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24;
if (net <= 127)
return(htonl(0xff000000));
else if (net < 192)
return(htonl(0xffff0000));
else
return(htonl(0xffffff00));
}
/**************************************************************************
IPCHKSUM - Checksum IP Header
**************************************************************************/
static unsigned short ipchksum(unsigned short *ip, int len)
{
unsigned long sum = 0;
len >>= 1;
while (len--) {
sum += *(ip++);
if (sum > 0xFFFF)
sum -= 0xFFFF;
}
return((~sum) & 0x0000FFFF);
}
/**************************************************************************
RFC951_SLEEP - sleep for expotentially longer times
**************************************************************************/
void rfc951_sleep(int exp)
{
static long seed = 0;
long q;
unsigned long tmo;
#ifdef BACKOFF_LIMIT
if (exp > BACKOFF_LIMIT)
exp = BACKOFF_LIMIT;
#endif
if (!seed) /* Initialize linear congruential generator */
seed = currticks() + *(long *)&arptable[ARP_CLIENT].node
+ ((short *)arptable[ARP_CLIENT].node)[2];
/* simplified version of the LCG given in Bruce Scheier's
"Applied Cryptography" */
q = seed/53668;
if ((seed = 40014*(seed-53668*q) - 12211*q) < 0) seed += 2147483563l;
/* compute mask */
for (tmo = 63; tmo <= 60*TICKS_PER_SEC && --exp > 0; tmo = 2*tmo+1);
/* sleep */
printk("<sleep>\n");
for (tmo = (tmo&seed)+currticks(); currticks() < tmo; )
return;
}
/**************************************************************************
AWAIT_REPLY - Wait until we get a response for our request
**************************************************************************/
int await_reply(int type, int ival, void *ptr, int timeout)
{
unsigned long time;
struct iphdr *ip;
struct udphdr *udp;
struct arprequest *arpreply;
struct bootp_t *bootpreply;
struct rpc_t *rpc;
unsigned short ptype;
unsigned int protohdrlen = ETH_HLEN + sizeof(struct iphdr) +
sizeof(struct udphdr);
time = timeout + currticks();
/* The timeout check is done below. The timeout is only checked if
* there is no packet in the Rx queue. This assumes that eth_poll()
* needs a negligible amount of time. */
for (;;) {
if (eth_poll()) { /* We have something! */
/* Check for ARP - No IP hdr */
if (nic.packetlen >= ETH_HLEN) {
ptype = ((unsigned short) nic.packet[12]) << 8
| ((unsigned short) nic.packet[13]);
} else continue; /* what else could we do with it? */
if ((nic.packetlen >= ETH_HLEN +
sizeof(struct arprequest)) &&
(ptype == ARP) ) {
unsigned long tmp;
arpreply = (struct arprequest *)
&nic.packet[ETH_HLEN];
if ((arpreply->opcode == htons(ARP_REPLY)) &&
!memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) &&
(type == AWAIT_ARP)) {
memcpy(arptable[ival].node, arpreply->shwaddr, ETH_ALEN);
return(1);
}
memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
if ((arpreply->opcode == htons(ARP_REQUEST)) &&
(tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
arpreply->opcode = htons(ARP_REPLY);
memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr));
memcpy(arpreply->thwaddr, arpreply->shwaddr, ETH_ALEN);
memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
eth_transmit(arpreply->thwaddr, ARP,
sizeof(struct arprequest),
(char *) arpreply);
#ifdef MDEBUG
memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
printf("Sent ARP reply to: %I\n",tmp);
#endif /* MDEBUG */
}
continue;
}
if (type == AWAIT_QDRAIN) {
continue;
}
/* Check for RARP - No IP hdr */
if ((type == AWAIT_RARP) &&
(nic.packetlen >= ETH_HLEN +
sizeof(struct arprequest)) &&
(ptype == RARP)) {
arpreply = (struct arprequest *)
&nic.packet[ETH_HLEN];
if ((arpreply->opcode == htons(RARP_REPLY)) &&
!memcmp(arpreply->thwaddr, ptr, ETH_ALEN)) {
memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETH_ALEN);
memcpy(& arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr));
memcpy(& arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr));
return(1);
}
continue;
}
/* Anything else has IP header */
if ((nic.packetlen < protohdrlen) ||
(ptype != IP) ) continue;
ip = (struct iphdr *)&nic.packet[ETH_HLEN];
if ((ip->verhdrlen != 0x45) ||
ipchksum((unsigned short *)ip, sizeof(struct iphdr)) ||
(ip->protocol != IP_UDP)) continue;
udp = (struct udphdr *)&nic.packet[ETH_HLEN +
sizeof(struct iphdr)];
/* BOOTP ? */
bootpreply = (struct bootp_t *)&nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
if ((type == AWAIT_BOOTP) &&
(nic.packetlen >= (ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr) +
#ifdef NO_DHCP_SUPPORT
sizeof(struct bootp_t))) &&
#else
sizeof(struct bootp_t))-DHCP_OPT_LEN) &&
#endif /* NO_DHCP_SUPPORT */
(udp->dest == htons(BOOTP_CLIENT)) &&
(bootpreply->bp_op == BOOTP_REPLY) &&
(bootpreply->bp_xid == xid) &&
(memcmp(broadcast, bootpreply->bp_hwaddr, ETH_ALEN) ==0 ||
memcmp(arptable[ARP_CLIENT].node, bootpreply->bp_hwaddr, ETH_ALEN) == 0)) {
arptable[ARP_CLIENT].ipaddr.s_addr =
bootpreply->bp_yiaddr.s_addr;
#ifndef NO_DHCP_SUPPORT
dhcp_addr.s_addr = bootpreply->bp_yiaddr.s_addr;
#endif /* NO_DHCP_SUPPORT */
netmask = default_netmask();
arptable[ARP_SERVER].ipaddr.s_addr =
bootpreply->bp_siaddr.s_addr;
memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */
arptable[ARP_GATEWAY].ipaddr.s_addr =
bootpreply->bp_giaddr.s_addr;
memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */
/* bootpreply->bp_file will be copied to KERNEL_BUF in the memcpy */
memcpy((char *)BOOTP_DATA_ADDR, (char *)bootpreply, sizeof(struct bootpd_t));
decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend,
#ifdef NO_DHCP_SUPPORT
0, BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN, 1);
#else
0, DHCP_OPT_LEN + MAX_BOOTP_EXTLEN, 1);
#endif /* NO_DHCP_SUPPORT */
#ifdef REQUIRE_VCI_ETHERBOOT
if (!vci_etherboot)
return (0);
#endif
return(1);
}
#ifdef DOWNLOAD_PROTO_TFTP
/* TFTP ? */
if ((type == AWAIT_TFTP) &&
(ntohs(udp->dest) == ival)) return(1);
#endif /* DOWNLOAD_PROTO_TFTP */
#ifdef DOWNLOAD_PROTO_NFS
/* RPC ? */
rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];
if ((type == AWAIT_RPC) &&
(ntohs(udp->dest) == ival) &&
(*(unsigned long *)ptr == ntohl(rpc->u.reply.id)) &&
(ntohl(rpc->u.reply.type) == MSG_REPLY)) {
return (1);
}
#endif /* DOWNLOAD_PROTO_NFS */
} else {
/* Check for abort key only if the Rx queue is empty -
* as long as we have something to process, don't
* assume that something failed. It is unlikely that
* we have no processing time left between packets. */
if (iskey() && (getchar() == ESC))
#ifdef EMERGENCYDISKBOOT
return(-1);
#else
longjmp(jmp_bootmenu, -1);
#endif
/* Do the timeout after at least a full queue walk. */
if ((timeout == 0) || (currticks() > time)) {
break;
}
}
}
return(0);
}
/**************************************************************************
RARP - Get my IP address and load information
**************************************************************************/
int rarp(void)
{
int retry;
/* arp and rarp requests share the same packet structure. */
struct arprequest rarpreq;
memset(&rarpreq, 0, sizeof(rarpreq));
rarpreq.hwtype = htons(1);
rarpreq.protocol = htons(IP);
rarpreq.hwlen = ETH_ALEN;
rarpreq.protolen = 4;
rarpreq.opcode = htons(RARP_REQUEST);
memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
/* sipaddr is already zeroed out */
memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
/* tipaddr is already zeroed out */
for (retry = 0; retry < MAX_ARP_RETRIES; rfc951_sleep(++retry)) {
eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq);
if (await_reply(AWAIT_RARP, 0, rarpreq.shwaddr, TIMEOUT))
break;
}
if (retry < MAX_ARP_RETRIES) {
(void)sprintf(KERNEL_BUF, DEFAULT_KERNELPATH, arptable[ARP_CLIENT].ipaddr);
return (1);
}
return (0);
}
/**************************************************************************
UDP_TRANSMIT - Send a UDP datagram
**************************************************************************/
int udp_transmit(unsigned long destip, unsigned int srcsock,
unsigned int destsock, int len, const void *buf)
{
struct iphdr *ip;
struct udphdr *udp;
struct arprequest arpreq;
int arpentry, i;
int retry;
ip = (struct iphdr *)buf;
udp = (struct udphdr *)((char *)buf + sizeof(struct iphdr));
ip->verhdrlen = 0x45;
ip->service = 0;
ip->len = htons(len);
ip->ident = 0;
ip->frags = 0;
ip->ttl = 60;
ip->protocol = IP_UDP;
ip->chksum = 0;
ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
ip->dest.s_addr = destip;
ip->chksum = ipchksum((unsigned short *)buf, sizeof(struct iphdr));
udp->src = htons(srcsock);
udp->dest = htons(destsock);
udp->len = htons(len - sizeof(struct iphdr));
udp->chksum = 0;
if (destip == IP_BROADCAST) {
eth_transmit(broadcast, IP, len, buf);
} else {
if (((destip & netmask) !=
(arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) &&
arptable[ARP_GATEWAY].ipaddr.s_addr)
destip = arptable[ARP_GATEWAY].ipaddr.s_addr;
for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
if (arptable[arpentry].ipaddr.s_addr == destip) break;
if (arpentry == MAX_ARP) {
printk("%I is not in my arp table!\n", destip);
return(0);
}
for (i = 0; i < ETH_ALEN; i++)
if (arptable[arpentry].node[i])
break;
if (i == ETH_ALEN) { /* Need to do arp request */
arpreq.hwtype = htons(1);
arpreq.protocol = htons(IP);
arpreq.hwlen = ETH_ALEN;
arpreq.protolen = 4;
arpreq.opcode = htons(ARP_REQUEST);
memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
memset(arpreq.thwaddr, 0, ETH_ALEN);
memcpy(arpreq.tipaddr, &destip, sizeof(in_addr));
for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) {
eth_transmit(broadcast, ARP, sizeof(arpreq),
&arpreq);
if (await_reply(AWAIT_ARP, arpentry,
arpreq.tipaddr, TIMEOUT)) goto xmit;
rfc951_sleep(retry);
/* We have slept for a while - the packet may
* have arrived by now. If not, we have at
* least some room in the Rx buffer for the
* next reply. */
if (await_reply(AWAIT_ARP, arpentry,
arpreq.tipaddr, 0)) goto xmit;
}
return(0);
}
xmit:
eth_transmit(arptable[arpentry].node, IP, len, buf);
}
return(1);
}
/**************************************************************************
TFTP - Download extended BOOTP data, or kernel image
**************************************************************************/
int tftp(const char *name, int (*fnc)(unsigned char *, int, int, int))
{
int retry = 0;
static unsigned short iport = 2000;
unsigned short oport;
unsigned short len, block = 0, prevblock = 0;
int bcounter = 0;
struct tftp_t *tr;
struct tftpreq_t tp;
int rc;
int packetsize = TFTP_DEFAULTSIZE_PACKET;
/* Clear out the Rx queue first. It contains nothing of interest,
* except possibly ARP requests from the DHCP/TFTP server. We use
* polling throughout Etherboot, so some time may have passed since we
* last polled the receive queue, which may now be filled with
* broadcast packets. This will cause the reply to the packets we are
* about to send to be lost immediately. Not very clever. */
await_reply(AWAIT_QDRAIN, 0, NULL, 0);
tp.opcode = htons(TFTP_RRQ);
/* Warning: the following assumes the layout of bootp_t.
But that's fixed by the IP, UDP and BOOTP specs. */
len = sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) +
sprintf((char *)tp.u.rrq, "%s%coctet%cblksize%c%d",
name, 0, 0, 0, TFTP_MAX_PACKET) + 1;
if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
TFTP_PORT, len, &tp))
return (0);
for (;;)
{
#ifdef CONGESTED
if (!await_reply(AWAIT_TFTP, iport, NULL, (block ? TFTP_REXMT : TIMEOUT)))
#else
if (!await_reply(AWAIT_TFTP, iport, NULL, TIMEOUT))
#endif
{
if (!block && retry++ < MAX_TFTP_RETRIES)
{ /* maybe initial request was lost */
rfc951_sleep(retry);
if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
++iport, TFTP_PORT, len, &tp))
return (0);
continue;
}
#ifdef CONGESTED
if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
{ /* we resend our last ack */
#ifdef MDEBUG
printk("<REXMT>\n");
#endif
udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
iport, oport,
TFTP_MIN_PACKET, &tp);
continue;
}
#endif
break; /* timeout */
}
tr = (struct tftp_t *)&nic.packet[ETH_HLEN];
if (tr->opcode == ntohs(TFTP_ERROR))
{
printk("TFTP error %d (%s)\n",
ntohs(tr->u.err.errcode),
tr->u.err.errmsg);
break;
}
if (tr->opcode == ntohs(TFTP_OACK)) {
char *p = tr->u.oack.data, *e;
if (prevblock) /* shouldn't happen */
continue; /* ignore it */
len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 2;
if (len > TFTP_MAX_PACKET)
goto noak;
e = p + len;
while (*p != '\000' && p < e) {
if (!strcasecmp("blksize", p)) {
p += 8;
if ((packetsize = getdec(&p)) <
TFTP_DEFAULTSIZE_PACKET)
goto noak;
while (p < e && *p) p++;
if (p < e)
p++;
}
else {
noak:
tp.opcode = htons(TFTP_ERROR);
tp.u.err.errcode = 8;
/*
* Warning: the following assumes the layout of bootp_t.
* But that's fixed by the IP, UDP and BOOTP specs.
*/
len = sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) + sizeof(tp.u.err.errcode) +
sprintf((char *)tp.u.err.errmsg,
"RFC1782 error") + 1;
udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
iport, ntohs(tr->udp.src),
len, &tp);
return (0);
}
}
if (p > e)
goto noak;
block = tp.u.ack.block = 0; /* this ensures, that */
/* the packet does not get */
/* processed as data! */
}
else if (tr->opcode == htons(TFTP_DATA)) {
len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4;
if (len > packetsize) /* shouldn't happen */
continue; /* ignore it */
block = ntohs(tp.u.ack.block = tr->u.data.block); }
else /* neither TFTP_OACK nor TFTP_DATA */
break;
if ((block || bcounter) && (block != prevblock+1)) {
/* Block order should be continuous */
tp.u.ack.block = htons(block = prevblock);
}
tp.opcode = htons(TFTP_ACK);
oport = ntohs(tr->udp.src);
udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport,
oport, TFTP_MIN_PACKET, &tp); /* ack */
if ((unsigned short)(block-prevblock) != 1) {
/* Retransmission or OACK, don't process via callback
* and don't change the value of prevblock. */
continue;
}
prevblock = block;
retry = 0; /* It's the right place to zero the timer? */
if ((rc = fnc(tr->u.data.download,
++bcounter, len, len < packetsize)) >= 0)
return(rc);
if (len < packetsize) /* End of data */
return (1);
}
return (0);
}
int retry = 0;
static unsigned short iport = 2000;
unsigned short oport;
unsigned short len, block = 0, prevblock = 0;
int bcounter = 0;
struct tftp_t *tr;
struct tftpreq_t tp;
int rc;
int packetsize = TFTP_DEFAULTSIZE_PACKET;
int tftp_init(const char *name)
{
retry = 0;
iport = 2000;
block = 0;
prevblock = 0;
bcounter = 0;
packetsize = TFTP_DEFAULTSIZE_PACKET;
/* Clear out the Rx queue first. It contains nothing of interest,
* except possibly ARP requests from the DHCP/TFTP server. We use
* polling throughout Etherboot, so some time may have passed since we
* last polled the receive queue, which may now be filled with
* broadcast packets. This will cause the reply to the packets we are
* about to send to be lost immediately. Not very clever. */
await_reply(AWAIT_QDRAIN, 0, NULL, 0);
tp.opcode = htons(TFTP_RRQ);
/* Warning: the following assumes the layout of bootp_t.
But that's fixed by the IP, UDP and BOOTP specs. */
len = sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) +
sprintf((char *)tp.u.rrq, "%s%coctet%cblksize%c%d",
name, 0, 0, 0, TFTP_MAX_PACKET) + 1;
if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
TFTP_PORT, len, &tp))
return (-1);
#ifdef CONGESTED
while (!await_reply(AWAIT_TFTP, iport, NULL, (block ? TFTP_REXMT : TIMEOUT)))
#else
while (!await_reply(AWAIT_TFTP, iport, NULL, TIMEOUT))
#endif
{
if (!block && retry++ < MAX_TFTP_RETRIES)
{ /* maybe initial request was lost */
rfc951_sleep(retry);
if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
++iport, TFTP_PORT, len, &tp))
return (-1);
continue;
}
#ifdef CONGESTED
if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
{ /* we resend our last ack */
#ifdef MDEBUG
printk("<REXMT>\n");
#endif
udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
iport, oport,
TFTP_MIN_PACKET, &tp);
continue;
}
#endif
break; /* timeout */
}
// we have recieved reply. see if it's any good.
tr = (struct tftp_t *)&nic.packet[ETH_HLEN];
if (tr->opcode == ntohs(TFTP_ERROR)) {
printk("TFTP error %d (%s)\n",
ntohs(tr->u.err.errcode),
tr->u.err.errmsg);
return(-ntohs(tr->u.err.errcode));
}
if (tr->opcode == ntohs(TFTP_OACK)) {
char *p = tr->u.oack.data, *e;
if (prevblock) /* shouldn't happen */
return(-1); /* ignore it */
len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 2;
if (len > TFTP_MAX_PACKET)
goto noak;
e = p + len;
while (*p != '\000' && p < e) {
if (!strcasecmp("blksize", p)) {
p += 8;
if ((packetsize = getdec(&p)) <
TFTP_DEFAULTSIZE_PACKET)
goto noak;
while (p < e && *p) p++;
if (p < e)
p++;
}
else {
noak:
tp.opcode = htons(TFTP_ERROR);
tp.u.err.errcode = 8;
/*
* Warning: the following assumes the layout of bootp_t.
* But that's fixed by the IP, UDP and BOOTP specs.
*/
len = sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) + sizeof(tp.u.err.errcode) +
sprintf((char *)tp.u.err.errmsg,
"RFC1782 error") + 1;
udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
iport, ntohs(tr->udp.src),
len, &tp);
return (-1);
}
}
if (p > e)
goto noak;
block = tp.u.ack.block = 0; /* this ensures, that */
/* the packet does not get */
/* processed as data! */
}
return(0);
}
int tftp_fetchone(char *buffer)
{
/* Clear out the Rx queue first. It contains nothing of interest,
* except possibly ARP requests from the DHCP/TFTP server. We use
* polling throughout Etherboot, so some time may have passed since we
* last polled the receive queue, which may now be filled with
* broadcast packets. This will cause the reply to the packets we are
* about to send to be lost immediately. Not very clever. */
retry:
await_reply(AWAIT_QDRAIN, 0, NULL, 0);
tp.opcode = htons(TFTP_ACK);
oport = ntohs(tr->udp.src);
udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport,
oport, TFTP_MIN_PACKET, &tp); /* ack */
#ifdef CONGESTED
while (!await_reply(AWAIT_TFTP, iport, NULL, (block ? TFTP_REXMT : TIMEOUT)))
#else
while (!await_reply(AWAIT_TFTP, iport, NULL, TIMEOUT))
#endif
{
if (!block && retry++ < MAX_TFTP_RETRIES)
{ /* maybe initial request was lost */
rfc951_sleep(retry);
if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
++iport, TFTP_PORT, len, &tp))
return (-1);
continue;
}
#ifdef CONGESTED
if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
{ /* we resend our last ack */
#ifdef MDEBUG
printk("<REXMT>\n");
#endif
udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
iport, oport,
TFTP_MIN_PACKET, &tp);
continue;
}
#endif
break; /* timeout */
}
tr = (struct tftp_t *)&nic.packet[ETH_HLEN];
if (tr->opcode == ntohs(TFTP_ERROR))
{
printk("TFTP error %d (%s)\n",
ntohs(tr->u.err.errcode),
tr->u.err.errmsg);
return(-tr->u.err.errcode);
}
if (tr->opcode == ntohs(TFTP_OACK))
goto retry; // session is already started! try again.
else if (tr->opcode == htons(TFTP_DATA)) {
len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4;
if (len > packetsize) /* shouldn't happen */
goto retry; /* bad thing, skip it and try again! */
block = ntohs(tp.u.ack.block = tr->u.data.block);
} else /* neither TFTP_OACK nor TFTP_DATA */
goto retry; // whatever it is, it's invalid! try again.
if ((block || bcounter) && (block != prevblock+1)) {
/* Block order should be continuous */
tp.u.ack.block = htons(block = prevblock);
goto retry;
}
prevblock = block;
retry = 0; /* It's the right place to zero the timer? */
memcpy(buffer,tr->u.data.download, len);
return(len);
}

1073
src/etherboot/sis900.c Normal file

File diff suppressed because it is too large Load diff

365
src/etherboot/sis900.h Normal file
View file

@ -0,0 +1,365 @@
/* -*- Mode:C; c-basic-offset:4; -*- */
/* Definitions for SiS ethernet controllers including 7014/7016 and 900
* References:
* SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
* preliminary Rev. 1.0 Jan. 14, 1998
* SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
* preliminary Rev. 1.0 Nov. 10, 1998
* SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
* preliminary Rev. 1.0 Jan. 18, 1998
* http://www.sis.com.tw/support/databook.htm
*/
/* MAC operationl registers of SiS 7016 and SiS 900 ethernet controller */
/* The I/O extent, SiS 900 needs 256 bytes of io address */
#define SIS900_TOTAL_SIZE 0x100
/* Symbolic offsets to registers. */
enum sis900_registers {
cr=0x0, /* Command Register */
cfg=0x4, /* Configuration Register */
mear=0x8, /* EEPROM Access Register */
ptscr=0xc, /* PCI Test Control Register */
isr=0x10, /* Interrupt Status Register */
imr=0x14, /* Interrupt Mask Register */
ier=0x18, /* Interrupt Enable Register */
epar=0x18, /* Enhanced PHY Access Register */
txdp=0x20, /* Transmit Descriptor Pointer Register */
txcfg=0x24, /* Transmit Configuration Register */
rxdp=0x30, /* Receive Descriptor Pointer Register */
rxcfg=0x34, /* Receive Configuration Register */
flctrl=0x38, /* Flow Control Register */
rxlen=0x3c, /* Receive Packet Length Register */
rfcr=0x48, /* Receive Filter Control Register */
rfdr=0x4C, /* Receive Filter Data Register */
pmctrl=0xB0, /* Power Management Control Register */
pmer=0xB4 /* Power Management Wake-up Event Register */
};
/* Symbolic names for bits in various registers */
enum sis900_command_register_bits {
RESET = 0x00000100,
SWI = 0x00000080,
RxRESET = 0x00000020,
TxRESET = 0x00000010,
RxDIS = 0x00000008,
RxENA = 0x00000004,
TxDIS = 0x00000002,
TxENA = 0x00000001
};
enum sis900_configuration_register_bits {
DESCRFMT = 0x00000100, /* 7016 specific */
REQALG = 0x00000080,
SB = 0x00000040,
POW = 0x00000020,
EXD = 0x00000010,
PESEL = 0x00000008,
LPM = 0x00000004,
BEM = 0x00000001
};
enum sis900_eeprom_access_reigster_bits {
MDC = 0x00000040,
MDDIR = 0x00000020,
MDIO = 0x00000010, /* 7016 specific */
EECS = 0x00000008,
EECLK = 0x00000004,
EEDO = 0x00000002,
EEDI = 0x00000001
};
enum sis900_interrupt_register_bits {
WKEVT = 0x10000000,
TxPAUSEEND = 0x08000000,
TxPAUSE = 0x04000000,
TxRCMP = 0x02000000,
RxRCMP = 0x01000000,
DPERR = 0x00800000,
SSERR = 0x00400000,
RMABT = 0x00200000,
RTABT = 0x00100000,
RxSOVR = 0x00010000,
HIBERR = 0x00008000,
SWINT = 0x00001000,
MIBINT = 0x00000800,
TxURN = 0x00000400,
TxIDLE = 0x00000200,
TxERR = 0x00000100,
TxDESC = 0x00000080,
TxOK = 0x00000040,
RxORN = 0x00000020,
RxIDLE = 0x00000010,
RxEARLY = 0x00000008,
RxERR = 0x00000004,
RxDESC = 0x00000002,
RxOK = 0x00000001
};
enum sis900_interrupt_enable_reigster_bits {
IE = 0x00000001
};
/* maximum dma burst fro transmission and receive*/
#define MAX_DMA_RANGE 7 /* actually 0 means MAXIMUM !! */
#define TxMXDMA_shift 20
#define RxMXDMA_shift 20
#define TX_DMA_BURST 0
#define RX_DMA_BURST 0
/* transmit FIFO threshholds */
#define TX_FILL_THRESH 16 /* 1/4 FIFO size */
#define TxFILLT_shift 8
#define TxDRNT_shift 0
#define TxDRNT_100 48 /* 3/4 FIFO size */
#define TxDRNT_10 16 /* 1/2 FIFO size */
enum sis900_transmit_config_register_bits {
TxCSI = 0x80000000,
TxHBI = 0x40000000,
TxMLB = 0x20000000,
TxATP = 0x10000000,
TxIFG = 0x0C000000,
TxFILLT = 0x00003F00,
TxDRNT = 0x0000003F
};
/* recevie FIFO thresholds */
#define RxDRNT_shift 1
#define RxDRNT_100 16 /* 1/2 FIFO size */
#define RxDRNT_10 24 /* 3/4 FIFO size */
enum sis900_reveive_config_register_bits {
RxAEP = 0x80000000,
RxARP = 0x40000000,
RxATX = 0x10000000,
RxAJAB = 0x08000000,
RxDRNT = 0x0000007F
};
#define RFAA_shift 28
#define RFADDR_shift 16
enum sis900_receive_filter_control_register_bits {
RFEN = 0x80000000,
RFAAB = 0x40000000,
RFAAM = 0x20000000,
RFAAP = 0x10000000,
RFPromiscuous = (RFAAB|RFAAM|RFAAP)
};
enum sis900_reveive_filter_data_mask {
RFDAT = 0x0000FFFF
};
/* EEPROM Addresses */
enum sis900_eeprom_address {
EEPROMSignature = 0x00,
EEPROMVendorID = 0x02,
EEPROMDeviceID = 0x03,
EEPROMMACAddr = 0x08,
EEPROMChecksum = 0x0b
};
/* The EEPROM commands include the alway-set leading bit. Refer to NM93Cxx datasheet */
enum sis900_eeprom_command {
EEread = 0x0180,
EEwrite = 0x0140,
EEerase = 0x01C0,
EEwriteEnable = 0x0130,
EEwriteDisable = 0x0100,
EEeraseAll = 0x0120,
EEwriteAll = 0x0110,
EEaddrMask = 0x013F,
};
/* Manamgement Data I/O (mdio) frame */
#define MIIread 0x6000
#define MIIwrite 0x5002
#define MIIpmdShift 7
#define MIIregShift 2
#define MIIcmdLen 16
#define MIIcmdShift 16
/* Buffer Descriptor Status*/
enum sis900_buffer_status {
OWN = 0x80000000,
MORE = 0x40000000,
INTR = 0x20000000,
SUPCRC = 0x10000000,
INCCRC = 0x10000000,
OK = 0x08000000,
DSIZE = 0x00000FFF
};
/* Status for TX Buffers */
enum sis900_tx_buffer_status {
ABORT = 0x04000000,
UNDERRUN = 0x02000000,
NOCARRIER = 0x01000000,
DEFERD = 0x00800000,
EXCDEFER = 0x00400000,
OWCOLL = 0x00200000,
EXCCOLL = 0x00100000,
COLCNT = 0x000F0000
};
enum sis900_rx_bufer_status {
OVERRUN = 0x02000000,
DEST = 0x00800000,
BCAST = 0x01800000,
MCAST = 0x01000000,
UNIMATCH = 0x00800000,
TOOLONG = 0x00400000,
RUNT = 0x00200000,
RXISERR = 0x00100000,
CRCERR = 0x00080000,
FAERR = 0x00040000,
LOOPBK = 0x00020000,
RXCOL = 0x00010000
};
/* MII register offsets */
enum mii_registers {
MII_CONTROL = 0x0000,
MII_STATUS = 0x0001,
MII_PHY_ID0 = 0x0002,
MII_PHY_ID1 = 0x0003,
MII_ANADV = 0x0004,
MII_ANLPAR = 0x0005,
MII_ANEXT = 0x0006
};
/* mii registers specific to SiS 900 */
enum sis_mii_registers {
MII_CONFIG1 = 0x0010,
MII_CONFIG2 = 0x0011,
MII_STSOUT = 0x0012,
MII_MASK = 0x0013
};
/* mii registers specific to AMD 79C901 */
enum amd_mii_registers {
MII_STATUS_SUMMARY = 0x0018
};
/* mii registers specific to ICS 1893 */
enum ics_mii_registers {
MII_EXTCTRL = 0x0010, MII_QPDSTS = 0x0011, MII_10BTOP = 0x0012,
MII_EXTCTRL2 = 0x0013
};
/* MII Control register bit definitions. */
enum mii_control_register_bits {
MII_CNTL_FDX = 0x0100,
MII_CNTL_RST_AUTO = 0x0200,
MII_CNTL_ISOLATE = 0x0400,
MII_CNTL_PWRDWN = 0x0800,
MII_CNTL_AUTO = 0x1000,
MII_CNTL_SPEED = 0x2000,
MII_CNTL_LPBK = 0x4000,
MII_CNTL_RESET = 0x8000
};
/* MII Status register bit */
enum mii_status_register_bits {
MII_STAT_EXT = 0x0001,
MII_STAT_JAB = 0x0002,
MII_STAT_LINK = 0x0004,
MII_STAT_CAN_AUTO = 0x0008,
MII_STAT_FAULT = 0x0010,
MII_STAT_AUTO_DONE = 0x0020,
MII_STAT_CAN_T = 0x0800,
MII_STAT_CAN_T_FDX = 0x1000,
MII_STAT_CAN_TX = 0x2000,
MII_STAT_CAN_TX_FDX = 0x4000,
MII_STAT_CAN_T4 = 0x8000
};
#define MII_ID1_OUI_LO 0xFC00 /* low bits of OUI mask */
#define MII_ID1_MODEL 0x03F0 /* model number */
#define MII_ID1_REV 0x000F /* model number */
/* MII NWAY Register Bits ...
valid for the ANAR (Auto-Negotiation Advertisement) and
ANLPAR (Auto-Negotiation Link Partner) registers */
enum mii_nway_register_bits {
MII_NWAY_NODE_SEL = 0x001f,
MII_NWAY_CSMA_CD = 0x0001,
MII_NWAY_T = 0x0020,
MII_NWAY_T_FDX = 0x0040,
MII_NWAY_TX = 0x0080,
MII_NWAY_TX_FDX = 0x0100,
MII_NWAY_T4 = 0x0200,
MII_NWAY_PAUSE = 0x0400,
MII_NWAY_RF = 0x2000,
MII_NWAY_ACK = 0x4000,
MII_NWAY_NP = 0x8000
};
enum mii_stsout_register_bits {
MII_STSOUT_LINK_FAIL = 0x4000,
MII_STSOUT_SPD = 0x0080,
MII_STSOUT_DPLX = 0x0040
};
enum mii_stsics_register_bits {
MII_STSICS_SPD = 0x8000, MII_STSICS_DPLX = 0x4000,
MII_STSICS_LINKSTS = 0x0001
};
enum mii_stssum_register_bits {
MII_STSSUM_LINK = 0x0008,
MII_STSSUM_DPLX = 0x0004,
MII_STSSUM_AUTO = 0x0002,
MII_STSSUM_SPD = 0x0001
};
enum sis900_revision_id {
SIS630A_900_REV = 0x80, SIS630E_900_REV = 0x81,
SIS630S_900_REV = 0x82, SIS630EA1_900_REV = 0x83
};
enum sis630_revision_id {
SIS630A0 = 0x00, SIS630A1 = 0x01,
SIS630B0 = 0x10, SIS630B1 = 0x11
};
#define FDX_CAPABLE_DUPLEX_UNKNOWN 0
#define FDX_CAPABLE_HALF_SELECTED 1
#define FDX_CAPABLE_FULL_SELECTED 2
#define HW_SPEED_UNCONFIG 0
#define HW_SPEED_HOME 1
#define HW_SPEED_10_MBPS 10
#define HW_SPEED_100_MBPS 100
#define HW_SPEED_DEFAULT (HW_SPEED_100_MBPS)
#define CRC_SIZE 4
#define MAC_HEADER_SIZE 14
#define TX_BUF_SIZE 1536
#define RX_BUF_SIZE 1536
#define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */
/* etherboot needs these defined. LinuxBIOS does it for us
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
*/
/* Time in ticks before concluding the transmitter is hung. */
#define TX_TIMEOUT (4*TICKS_PER_SEC)
typedef struct _BufferDesc {
u32 link;
volatile u32 cmdsts;
u32 bufptr;
} BufferDesc;

91
src/etherboot/sis900.txt Normal file
View file

@ -0,0 +1,91 @@
How I added the SIS900 card to Etherboot
Author: Marty Connor (mdc@thinguin.org)
Date: 25 Febrary 2001
Description:
This file is intended to help people who want to write an Etherboot
driver or port another driver to Etherboot. It is a starting point.
Perhaps someday I may write a more detailed description of writing an
Etherboot driver. This text should help get people started, and
studying sis900.[ch] should help show the basic structure and
techniques involved in writing and Etherboot driver.
***********************************************************************
0. Back up all the files I need to modify:
cd etherboot-4.7.20/src
cp Makefile Makefile.orig
cp config.c config.c.orig
cp pci.h pci.h.orig
cp NIC NIC.orig
cp cards.h cards.h.orig
1. Edit src/Makefile to add SIS900FLAGS to defines
SIS900FLAGS= -DINCLUDE_SIS900
2. edit src/pci.h to add PCI signatures for card
#define PCI_VENDOR_ID_SIS 0x1039
#define PCI_DEVICE_ID_SIS900 0x0900
#define PCI_DEVICE_ID_SIS7016 0x7016
3. Edit src/config.c to add the card to the card probe list
#if defined(INCLUDE_NS8390) || defined(INCLUDE_EEPRO100) ||
defined(INCLUDE_LANCE) || defined(INCLUDE_EPIC100) ||
defined(INCLUDE_TULIP) || defined(INCLUDE_OTULIP) ||
defined(INCLUDE_3C90X) || defined(INCLUDE_3C595) ||
defined(INCLUDE_RTL8139) || defined(INCLUDE_VIA_RHINE) ||
defined(INCLUDE_SIS900) || defined(INCLUDE_W89C840)
... and ...
#ifdef INCLUDE_SIS900
{ PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS900,
"SIS900", 0, 0, 0, 0},
{ PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS7016,
"SIS7016", 0, 0, 0, 0},
#endif
... and ...
#ifdef INCLUDE_SIS900
{ "SIS900", sis900_probe, pci_ioaddrs },
#endif
4. Edit NIC to add sis900 and sis7016 to NIC list
# SIS 900 and SIS 7016
sis900 sis900 0x1039,0x0900
sis7016 sis900 0x1039,0x7016
5. Edit cards.h to add sis900 probe routine declaration
#ifdef INCLUDE_SIS900
extern struct nic *sis900_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
***********************************************************************
At this point, you can begin creating your driver source file. See
the "Writing and Etherboot Driver" section of the Etherboot
documentation for some hints. See the skel.c file for a starting
point. If there is a Linux driver for the card, you may be able to
use that. Copy and learn from existing Etherboot drivers (this is GPL
/ Open Source software!).
Join the etherboot-developers and etherboot-users mailing lists
(information is on etherboot.sourceforge.net) for information and
assistance. We invite more developers to help improve Etherboot.
Visit the http://etherboot.sourceforge.net, http://thinguin.org,
http://rom-o-matic.net, and http://ltsp.org sites for information and
assistance.
Enjoy.

64
src/etherboot/timer.h Normal file
View file

@ -0,0 +1,64 @@
/* Defines for routines to implement a low-overhead timer for drivers */
/*
* 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, or (at
* your option) any later version.
*/
#ifndef TIMER_H
#define TIMER_H
/* Ports for the 8254 timer chip */
#define TIMER2_PORT 0x42
#define TIMER_MODE_PORT 0x43
/* Meaning of the mode bits */
#define TIMER0_SEL 0x00
#define TIMER1_SEL 0x40
#define TIMER2_SEL 0x80
#define READBACK_SEL 0xC0
#define LATCH_COUNT 0x00
#define LOBYTE_ACCESS 0x10
#define HIBYTE_ACCESS 0x20
#define WORD_ACCESS 0x30
#define MODE0 0x00
#define MODE1 0x02
#define MODE2 0x04
#define MODE3 0x06
#define MODE4 0x08
#define MODE5 0x0A
#define BINARY_COUNT 0x00
#define BCD_COUNT 0x01
/* Timers tick over at this rate */
#define TICKS_PER_MS 1193
/* Parallel Peripheral Controller Port B */
#define PPC_PORTB 0x61
/* Meaning of the port bits */
#define PPCB_T2OUT 0x20 /* Bit 5 */
#define PPCB_SPKR 0x02 /* Bit 1 */
#define PPCB_T2GATE 0x01 /* Bit 0 */
/* Ticks must be between 0 and 65535 (0 == 65536)
because it is a 16 bit counter */
extern void load_timer2(unsigned int ticks);
extern inline int timer2_running(void)
{
return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0);
}
extern inline void waiton_timer2(unsigned int ticks)
{
load_timer2(ticks);
while ((inb(PPC_PORTB) & PPCB_T2OUT) == 0)
;
}
#endif /* TIMER_H */

View file

@ -28,7 +28,11 @@
#endif
#include "do_inflate.h"
#ifdef USE_TFTP
extern void netboot_init(void);
extern int tftp_init(const char *name);
extern int tftp_fetchone(char *buffer);
#endif
int linuxbiosmain(unsigned long base, unsigned long totalram)
{
@ -37,6 +41,11 @@ int linuxbiosmain(unsigned long base, unsigned long totalram)
unsigned char *cmd_line;
unsigned long initrd_start, initrd_size;
#ifdef USE_TFTP
char buffer[256];
char *bufptr;
int buflen;
#endif
#if USE_ELF_BOOT
return elfboot(totalram);
@ -72,6 +81,16 @@ int linuxbiosmain(unsigned long base, unsigned long totalram)
post_code(0xf1);
#ifdef PYRO_TEST1
printk(KERN_NOTICE "LiLa loader, press a key to test netboot_init:");
buflen = sizeof(buffer);
ttys0_rx_line(buffer, &buflen);
#endif
#ifdef USE_TFTP
netboot_init();
printk(KERN_NOTICE "\nnetboot_init test complete, all is well (I hope!)\n");
#endif
DBG("Gunzip setup\n");
gunzip_setup();
@ -83,6 +102,35 @@ int linuxbiosmain(unsigned long base, unsigned long totalram)
}
post_code(0xf8);
#ifdef TFTP_INITRD
printk("Loading initrd now\n");
buflen = tftp_init("initrd");
printk("TFTP init complete (%d)\n",buflen);
buflen = 512; // I know, not it's purpose,
// but it isn't being used at this point.
bufptr = initrd_start = 0x0400000;
while(buflen == 512) {
buflen = tftp_fetchone(bufptr);
#ifdef DEBUG_TFTP
printk("Got block, bufptr = %lu, size= %u\n",bufptr, buflen);
#endif
bufptr += buflen;
}
initrd_size = bufptr - initrd_start;
printk("Initrd loaded\n");
if(tftp_init("cmdline") >=0) {
tftp_fetchone(buffer);
cmd_line=buffer;
}
printk("Booting with command line: %s\n",cmd_line);
#endif
/* parameter passing to linux. You have to get the pointer to the
* empty_zero_page, then fill it in.
*/

View file

@ -36,6 +36,38 @@ static char rcsid[] = "$Id$";
#define TTYS0_DIV (115200/TTYS0_BAUD)
#ifdef PYRO_SERIAL
/* experimental serial read stuffs */
int iskey(void) {
if( inb(TTYS0_LSR) & 0x01)
return(1);
return(0);
}
char ttys0_rx_char(void) {
char result;
while(!(inb(TTYS0_LSR) & 0x01));
result = inb(TTYS0_RBR);
return(result);
}
void ttys0_rx_line(char *buffer, int *len) {
int pos=0;
char chargot=0;
while(chargot != '\r' && chargot != '\n' && pos< *len) {
chargot = ttys0_rx_char();
buffer[pos++] = chargot;
}
*len = pos-1;
}
#endif
void ttys0_init(void)
{
/* disable interrupts */

View file

@ -1,5 +1,5 @@
option SIS630
option USE_DOC_MIL
# option USE_DOC_MIL
option SMA_SIZE=0xA0
docipl northsouthbridge/sis/630/ipl.S
raminit northsouthbridge/sis/630/raminit.inc

View file

@ -1,5 +1,5 @@
option SIS730
option USE_DOC_MIL
# option USE_DOC_MIL
option SMA_SIZE=0xA0
docipl northsouthbridge/sis/730/ipl.S
raminit northsouthbridge/sis/730/raminit.inc

View file

@ -32,6 +32,9 @@
#include "ipl.h"
.code16
#ifdef STD_FLASH
.org 0xfe00
#endif
#define SIZE_ALL
#define REALLY_COMPACT
@ -210,7 +213,20 @@ sis730ipl_start:
movw %ax, %ss
movw $SPL_RAM_SEG, %ax
movw %ax, %es
#ifdef STD_FLASH
movw $0xf000, %ax
movw %ax, %ds
xorw %sp, %sp # clear %sp
xorw %si, %si
xorw %di, %di
movw $0xffff, %cx
rep
movsb
movw $DOC_WIN_SEG, %ax
movw %ax, %ds
#else
movw $sis950_init_table, %si # unlock SiS 950 LPC
movw $0x05, %cx # select Clock Selection
movw $0x2e, %dx # and Flash ROM I/F
@ -278,6 +294,7 @@ doc_delay:
incw %bp # increse current page number
cmpw $128, %bp # moved 63 KB ??
jl read_next_page # no, read next page
#endif /*else STD_FLASH */
sis730ipl_end:
jmp spl_vector # jump to SPL vector
@ -395,10 +412,18 @@ pci_init_table:
.word 0x0000 /* Null, End of table */
.org 0x01f0
#ifdef STD_FLASH
.org 0xfff0
reset_vector:
.byte 0xea # jmp to fe00:0000, where IPL
.word 0xfe00, 0xf000 # starts in DoC
#else
.org 0x1f0
reset_vector:
.byte 0xea # jmp to fe00:0000, where IPL
.word 0x0000, DOC_WIN_SEG # starts in DoC
#endif
spl_vector:
.byte 0xea # jmp to 8000:0000, where SPL

View file

@ -2,3 +2,4 @@ object fill_inbuf.o
object rom_fill_inbuf.o
object docmil_fill_inbuf.o
object tsunami_tigbus_rom_fill_inbuf.o
object tftp_fill_inbuf.o

View file

@ -128,6 +128,14 @@ def dir(base_dir, name):
def mainboard(dir, mainboard_name):
common_command_action(dir, 'mainboard', mainboard_name)
def etherboot(dir, net_name):
common_command_action(dir, 'etherboot', '')
option(dir,'OLD_KERNEL_HACK')
option(dir,'USE_TFTP')
option(dir,'TFTP_INITRD')
option(dir,'PYRO_SERIAL')
# old legacy PC junk, which will be dying soon.
def keyboard(dir, keyboard_name):
if (debug):
@ -363,6 +371,7 @@ command_actions = {
'dir' : dir,
'keyboard' : keyboard,
'docipl' : docipl,
'etherboot' : etherboot,
'makedefine' : makedefine,
'makerule' : makerule,
'addaction' : addaction,