+++ /dev/null
-##############################################################################
-##############################################################################
-#
-# IMPORTANT!
-#
-# The use of this file to set options that affect only single object
-# files is deprecated, because changing anything in this file results
-# in a complete rebuild, which is slow. All options are gradually
-# being migrated to config.h, which does not suffer from this problem.
-#
-# Only options that affect the entire build (e.g. overriding the $(CC)
-# Makefile variable) should be placed in here.
-#
-##############################################################################
-##############################################################################
-
-
-#
-# Config for Etherboot/32
-#
-#
-# Do not delete the tag OptionDescription and /OptionDescription
-# It is used to automatically generate the documentation.
-#
-# @OptionDescription@
-# User interaction options:
-#
-# -DASK_BOOT=n
-# Ask "Boot from (N)etwork ... or (Q)uit? "
-# at startup, timeout after n seconds (0 = no timeout).
-# If unset or negative, don't ask and boot immediately
-# using the default.
-# -DBOOT_FIRST
-# -DBOOT_SECOND
-# -DBOOT_THIRD
-# On timeout or Return key from previous
-# question, selects the order to try to boot from
-# various devices.
-# (alternatives: BOOT_NIC, BOOT_DISK,
-# BOOT_FLOPPY, BOOT_NOTHING)
-# See etherboot.h for prompt and answer strings.
-# BOOT_DISK and BOOT_FLOPPY work only where a driver
-# exists, e.g. in LinuxBIOS.
-# They have no effect on PCBIOS.
-# -DBOOT_INDEX The device to boot from 0 == any device.
-# 1 == The first nic found.
-# 2 == The second nic found
-# ...
-# BOOT_INDEX only applies to the BOOT_FIRST. BOOT_SECOND
-# and BOOT_THIRD search through all of the boot devices.
-# -DBAR_PROGRESS
-# Use rotating bar instead of sequential dots
-# to indicate an IP packet transmitted.
-#
-# Boot order options:
-#
-# -DBOOT_CLASS_FIRST
-# -DBOOT_CLASS_SECOND
-# -DBOOT_CLASS_THIRD
-# Select the priority of the boot classes
-# Valid values are:
-# BOOT_NIC
-# BOOT_DISK
-# BOOT_FLOPPY
-# BOOT_DISK and BOOT_FLOPPY work only where a driver exists,
-# e.g. in LinuxBIOS. They have no effect on PCBIOS.
-#
-# Boot autoconfiguration protocol options:
-#
-# -DALTERNATE_DHCP_PORTS_1067_1068
-# Use ports 1067 and 1068 for DHCP instead of 67 and 68.
-# As these ports are non-standard, you need to configure
-# your DHCP server to use them. This option gets around
-# existing DHCP servers which cannot be touched, for
-# one reason or another, at the cost of non-standard
-# boot images.
-# -DNO_DHCP_SUPPORT
-# Use BOOTP instead of DHCP.
-# -DRARP_NOT_BOOTP
-# Use RARP instead of BOOTP/DHCP.
-# -DREQUIRE_VCI_ETHERBOOT
-# Require an encapsulated Vendor Class Identifier
-# of "Etherboot" in the DHCP reply
-# Requires DHCP support.
-# -DDHCP_CLIENT_ID=\"Identifier\"
-# -DDHCP_CLIENT_ID_LEN=<Client ID length in octets>
-# -DDHCP_CLIENT_ID_TYPE=<Client ID type>
-# Specify a RFC2132 Client Identifier option, length and type.
-# Requires DHCP support.
-# -DDHCP_USER_CLASS=\"UserClass\"
-# -DDHCP_USER_CLASS_LEN=<User Class length in octets>
-# Specify a RFC3004 User Class option and length. Use this
-# option to set a UC (or multiple UCs) rather than munge the
-# client Vendor Class ID.
-# Requires DHCP support.
-# -DALLOW_ONLY_ENCAPSULATED
-# Ignore Etherboot-specific options that are not within
-# the Etherboot encapsulated options field. This option
-# should be enabled unless you have a legacy DHCP server
-# configuration from the bad old days before the use of
-# encapsulated Etherboot options.
-# -DDEFAULT_BOOTFILE=\"default_bootfile_name\"
-# Define a default bootfile for the case where your DHCP
-# server does not provide the information. Example:
-# -DDEFAULT_BOOTFILE="tftp:///tftpboot/kernel"
-# If you do not specify this option, then DHCP offers that
-# do not specify bootfiles will be ignored.
-#
-# NIC tuning parameters:
-#
-# -DALLMULTI
-# Turns on multicast reception in the NICs.
-#
-# Boot tuning parameters:
-#
-# -DCONGESTED
-# Turns on packet retransmission. Use it on a
-# congested network, where the normal operation
-# can't boot the image.
-# -DBACKOFF_LIMIT
-# Sets the maximum RFC951 backoff exponent to n.
-# Do not set this unreasonably low, because on networks
-# with many machines they can saturate the link
-# (the delay corresponding to the exponent is a random
-# time in the range 0..3.5*2^n seconds). Use 5 for a
-# VERY small network (max. 2 minutes delay), 7 for a
-# medium sized network (max. 7.5 minutes delay) or 10
-# for a really huge network with many clients, frequent
-# congestions (max. 1 hour delay). On average the
-# delay time will be half the maximum value. If in
-# doubt about the consequences, use a larger value.
-# Also keep in mind that the number of retransmissions
-# is not changed by this setting, so the default of 20
-# may no longer be appropriate. You might need to set
-# MAX_ARP_RETRIES, MAX_BOOTP_RETRIES, MAX_TFTP_RETRIES
-# and MAX_RPC_RETRIES to a larger value.
-# -DTIMEOUT=n
-# Use with care!! See above.
-# Sets the base of RFC2131 sleep interval to n.
-# This can be used with -DBACKOFF_LIMIT=0 to get a small
-# and constant (predictable) retry interval for embedded
-# devices. This is to achieve short boot delays if both
-# the DHCP Server and the embedded device will be powered
-# on the same time. Otherwise if the DHCP server is ready
-# the client could sleep the next exponentially timeout,
-# e.g. 70 seconds or more. This is not what you want.
-# n should be a multiple of TICKS_PER_SEC (18).
-#
-# Boot device options:
-#
-# -DTRY_FLOPPY_FIRST
-# If > 0, tries that many times to read the boot
-# sector from a floppy drive before booting from
-# ROM. If successful, does a local boot.
-# It assumes the floppy is bootable.
-# -DEXIT_IF_NO_OFFER
-# If no IP offer is obtained, exit and
-# let the BIOS continue.
-# The accessibility of the TFTP server has no effect,
-# so configure your DHCP/BOOTP server properly.
-# You should probably reduce MAX_BOOTP_RETRIES
-# to a small number like 3.
-#
-# Boot image options:
-#
-# -DFREEBSD_KERNEL_ENV
-# Pass in FreeBSD kernel environment
-# -DAOUT_LYNX_KDI
-# Add Lynx a.out KDI support
-# -DMULTICAST_LEVEL1
-# Support for sending multicast packets
-# -DMULTICAST_LEVEL2
-# Support for receiving multicast packets
-#
-# Interface export options:
-#
-# -DPXE_EXPORT
-# Export a PXE API interface. This is work in
-# progress. Note that you won't be able to load
-# PXE NBPs unless you also use -DPXE_IMAGE.
-# -DPXE_STRICT
-# Strict(er) compliance with the PXE
-# specification as published by Intel. This may
-# or may not be a good thing depending on your
-# view of the spec...
-# -DPXE_DHCP_STRICT
-# Strict compliance of the DHCP request packets
-# with the PXE specification as published by
-# Intel. This may or may not be a good thing
-# depending on your view of whether requesting
-# vendor options which don't actually exist is
-# pointless or not. You probably want this
-# option if you intend to use Windows RIS or
-# similar.
-#
-# Obscure options you probably don't need to touch:
-#
-# -DZPXE_SUFFIX_STRIP
-# If the last 5 characters of the filename passed to Etherboot is
-# ".zpxe" then strip it off. This is useful in cases where a DHCP server
-# is not able to be configured to support conditionals. The way it works
-# is that the DHCP server is configured with a filename like
-# "foo.nbi.zpxe" so that when PXE asks for a filename it gets that, and
-# loads Etherboot from that file. Etherboot then starts up and once
-# again asks the DHCP server for a filename and once again gets
-# foo.nbi.zpxe, but with this option turned on loads "foo.nbi" instead.
-# This allows people to use Etherboot who might not otherwise be able to
-# because their DHCP servers won't let them.
-#
-# -DPOWERSAVE
-# Halt the processor when waiting for keyboard input
-# which saves power while waiting for user interaction.
-# Good for compute clusters and VMware emulation.
-# But may not work for all CPUs.
-#
-# @/OptionDescription@
-
-# These default settings compile Etherboot with a small number of options.
-# You may wish to enable more of the features if the size of your ROM allows.
-
-
-# For prompting and default on timeout
-# CFLAGS+= -DASK_BOOT=3 -DBOOT_FIRST=BOOT_NIC
-# If you would like to attempt to boot from other devices as well as the network.
-# CFLAGS+= -DBOOT_SECOND=BOOT_FLOPPY
-# CFLAGS+= -DBOOT_THIRD=BOOT_DISK
-# CFLAGS+= -DBOOT_INDEX=0
-
-# If you prefer the old style rotating bar progress display
-# CFLAGS+= -DBAR_PROGRESS
-
-# Show size indicator
-# CFLAGS+= -DSIZEINDICATOR
-
-# Enabling this creates non-standard images which use ports 1067 and 1068
-# for DHCP/BOOTP
-# CFLAGS+= -DALTERNATE_DHCP_PORTS_1067_1068
-
-# Enabling this makes the boot ROM require a Vendor Class Identifier
-# of "Etherboot" in the Vendor Encapsulated Options
-# This can be used to reject replies from servers other than the one
-# we want to give out addresses to us, but it will prevent Etherboot
-# from getting an IP lease until you have configured DHCPD correctly
-# CFLAGS+= -DREQUIRE_VCI_ETHERBOOT
-
-# EXPERIMENTAL! Set DHCP_CLIENT_ID to create a Client Identifier (DHCP
-# option 61, see RFC2132 section 9.14) when Etherboot sends the DHCP
-# DISCOVER and REQUEST packets. This ID must UNIQUELY identify each
-# client on your local network. Set DHCP_CLIENT_ID_TYPE to the
-# appropriate hardware type as described in RFC2132 / RFC1700; this
-# almost certainly means using '1' if the Client ID is an Ethernet MAC
-# address and '0' otherwise. Set DHCP_CLIENT_ID_LEN to the length of
-# the Client ID in octets (this is not a null terminated C string, do
-# NOT add 1 for a terminator and do NOT add an extra 1 for the
-# hardware type octet). Note that to identify your client using the
-# normal default MAC address of your NIC, you do NOT need to set this
-# option, as the MAC address is automatically used in the
-# hwtype/chaddr field; note also that this field only sets the DHCP
-# option: it does NOT change the MAC address used by the client.
-
-# CFLAGS+= -DDHCP_CLIENT_ID="'C','L','I','E','N','T','0','0','1'" \
-# -DDHCP_CLIENT_ID_LEN=9 -DDHCP_CLIENT_ID_TYPE=0
-
-# CFLAGS+= -DDHCP_CLIENT_ID="0xDE,0xAD,0xBE,0xEF,0xDE,0xAD" \
-# -DDHCP_CLIENT_ID_LEN=6 -DDHCP_CLIENT_ID_TYPE=1
-
-# EXPERIMENTAL! Set DHCP_USER_CLASS to create a User Class option (see
-# RFC3004) when Etherboot sends the DHCP DISCOVER and REQUEST packets.
-# This can be used for classification of clients, typically so that a
-# DHCP server can send an appropriately tailored reply. Normally, a
-# string identifies a class of to which this client instance belongs
-# which is useful in your network, such as a department ('FINANCE' or
-# 'MARKETING') or hardware type ('THINCLIENT' or 'KIOSK'). Set
-# DHCP_USER_CLASS_LEN to the length of DHCP_USER_CLASS in octets.
-# This is NOT a null terminated C string, do NOT add 1 for a
-# terminator. RFC3004 advises how to lay out multiple User Class
-# options by using an octet for the length of each string, as in this
-# example. It is, of course, up to the server to parse this.
-
-# CFLAGS+= -DDHCP_USER_CLASS="'T','E','S','T','C','L','A','S','S'" \
-# -DDHCP_USER_CLASS_LEN=9
-
-# CFLAGS+= -DDHCP_USER_CLASS="5,'A','L','P','H','A',4,'B','E','T','A'" \
-# -DDHCP_USER_CLASS_LEN=11
-
-# Enabling this causes Etherboot to ignore Etherboot-specific options
-# that are not within an Etherboot encapsulated options field.
-# This option should be enabled unless you have a legacy DHCP server
-# configuration from the bad old days before the use of
-# encapsulated Etherboot options.
-# CFLAGS+= -DALLOW_ONLY_ENCAPSULATED
-
-# Disable DHCP support
-# CFLAGS+= -DNO_DHCP_SUPPORT
-
-# Specify a default bootfile to be used if the DHCP server does not
-# provide the information. If you do not specify this option, then
-# DHCP offers that do not contain bootfiles will be ignored.
-# CFLAGS+= -DDEFAULT_BOOTFILE=\"tftp:///tftpboot/kernel\"
-
-# Limit the delay on packet loss/congestion to a more bearable value. See
-# description above. If unset, do not limit the delay between resend.
-# CFLAGS+= -DBACKOFF_LIMIT=5 -DCONGESTED
-
-# More optional features
-# CFLAGS+= -DTRY_FLOPPY_FIRST=4
-# CFLAGS+= -DEXIT_IF_NO_OFFER
-
-
-# Multicast Support
-# CFLAGS+= -DALLMULTI -DMULTICAST_LEVEL1 -DMULTICAST_LEVEL2
-
-# Etherboot as a PXE network protocol ROM
-# CFLAGS+= -DPXE_IMAGE -DPXE_EXPORT
-# Etherboot stricter as a PXE network protocol ROM
-# CFLAGS+= -DPXE_DHCP_STRICT
-
-# Support for PXE emulation. Works only with FreeBSD to load the kernel
-# via pxeboot, use only with DOWNLOAD_PROTO_NFS
-# CFLAGS+= -DFREEBSD_PXEEMU
-
-
-
-# Garbage from Makefile.main temporarily placed here until a home can
-# be found for it.
-
-# NS8390 options:
-# -DINCLUDE_NE - Include NE1000/NE2000 support
-# -DNE_SCAN=list - Probe for NE base address using list of
-# comma separated hex addresses
-# -DINCLUDE_3C503 - Include 3c503 support
-# -DT503_SHMEM - Use 3c503 shared memory mode (off by default)
-# -DINCLUDE_WD - Include Western Digital/SMC support
-# -DWD_DEFAULT_MEM- Default memory location for WD/SMC cards
-# -DWD_790_PIO - Read/write to WD/SMC 790 cards in PIO mode (default
-# is to use shared memory) Try this if you get "Bogus
-# packet, ignoring" messages, common on ISA/PCI hybrid
-# systems.
-# -DCOMPEX_RL2000_FIX
-#
-# If you have a Compex RL2000 PCI 32-bit (11F6:1401),
-# and the bootrom hangs in "Probing...[NE*000/PCI]",
-# try enabling this fix... it worked for me :).
-# In the first packet write somehow it somehow doesn't
-# get back the expected data so it is stuck in a loop.
-# I didn't bother to investigate what or why because it works
-# when I interrupt the loop if it takes more then COMPEX_RL2000_TRIES.
-# The code will notify if it does a abort.
-# SomniOne - somnione@gmx.net
-#
-# 3C90X options:
-# Warning Warning Warning
-# If you use any of the XCVR options below, please do not complain about
-# the behaviour with Linux drivers to the kernel developers. You are
-# on your own if you do this. Please read 3c90x.txt to understand
-# what they do. If you don't understand them, ask for help on the
-# Etherboot mailing list. And please document what you did to the NIC
-# on the NIC so that people after you won't get nasty surprises.
-#
-# -DCFG_3C90X_PRESERVE_XCVR - Reset the transceiver type to the value it
-# had initially just before the loaded code is started.
-# -DCFG_3C90X_XCVR - Hardcode the tranceiver type Etherboot uses.
-# -DCFG_3C90X_BOOTROM_FIX - If you have a 3c905B with buggy ROM
-# interface, setting this option might "fix" it. Use
-# with caution and read the docs in 3c90x.txt!
-#
-# See the documentation file 3c90x.txt for more details.
-#
-# CS89X0 (optional) options:
-# -DISA_PROBE_ADDRS=list
-# Probe for CS89x0 base address using list of
-# comma separated hex addresses; increasing the
-# address by one (0x300 -> 0x301) will force a
-# more aggressive probing algorithm. This might
-# be neccessary after a soft-reset of the NIC.
-
-
-CFLAGS_3c503 = -DINCLUDE_3C503 # -DT503_SHMEM
-CFLAGS_ne = -DINCLUDE_NE -DNE_SCAN=0x300,0x280,0x320,0x340,0x380
-CFLAGS_ns8390 = -DINCLUDE_NS8390 # NE2000/PCI!
-CFLAGS_wd = -DINCLUDE_WD -DWD_DEFAULT_MEM=0xCC000
@$(ECHO)
@$(ECHO) '==========================================================='
-# Grab the central Config file.
-#
-MAKEDEPS += Config
-include Config
-
# If no architecture is specified in Config or on the command-line,
# use that of the build machine.
#
# Check for tools that can cause failed builds
#
-.toolcheck : Makefile Config
+.toolcheck : Makefile
@if $(CC) -v 2>&1 | grep -is 'gcc version 2\.96' > /dev/null; then \
$(ECHO) 'gcc 2.96 is unsuitable for compiling Etherboot'; \
$(ECHO) 'Use gcc 2.95 or gcc 3.x instead'; \
#define IH_OFFSET_FLUX_END ( IH_OFFSET_END - 20 )
do_interrupt:
/* Store CPU state in GDB register snapshot */
- pushl %gs
- pushl %fs
- pushl %es
- pushl %ds
- pushl %ss
- pushl IH_OFFSET_FLUX_OLD_CS(%esp)
+ pushw $0
+ pushw %gs
+ pushw $0
+ pushw %fs
+ pushw $0
+ pushw %es
+ pushw $0
+ pushw %ds
+ pushw $0
+ pushw %ss
+ pushw $0
+ pushw IH_OFFSET_FLUX_OLD_CS + 2(%esp)
pushl IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
pushl IH_OFFSET_FLUX_OLD_EIP(%esp)
pushl %edi
/* Call GDB stub exception handler */
pushl %esp
pushl (IH_OFFSET_SIGNO + 4)(%esp)
- call gdbstub_handler
+ call gdbmach_handler
addl $8, %esp
/* Restore CPU state from GDB register snapshot */
}
/* Calculate load address and size of real-mode portion */
- load_ctx->rm_kernel_seg = 0x1000; /* place RM kernel at 1000:0000 */
+ load_ctx->rm_kernel_seg = ( ( bzhdr->loadflags & BZI_LOAD_HIGH ) ?
+ 0x1000 : /* 1000:0000 (bzImage) */
+ 0x9000 ); /* 9000:0000 (zImage) */
load_ctx->rm_kernel = real_to_user ( load_ctx->rm_kernel_seg, 0 );
load_ctx->rm_filesz =
( ( bzhdr->setup_sects ? bzhdr->setup_sects : 4 ) + 1 ) << 9;
*
*/
+#include <stdint.h>
+
typedef uint32_t gdbreg_t;
/* The register snapshot, this must be in sync with interrupt handler and the
GDBMACH_SIZEOF_REGS = GDBMACH_NREGS * sizeof ( gdbreg_t )
};
+/* Breakpoint types */
+enum {
+ GDBMACH_BPMEM,
+ GDBMACH_BPHW,
+ GDBMACH_WATCH,
+ GDBMACH_RWATCH,
+ GDBMACH_AWATCH,
+};
+
static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
regs [ GDBMACH_EIP ] = pc;
}
__asm__ __volatile__ ( "int $3\n" );
}
+extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable );
+
#endif /* GDBMACH_H */
Description:
This is just a little bit of code and data that can get prepended
- to an Etherboot ROM image in order to allow LILO to load the
- result as if it were a Linux kernel image.
+ to a ROM image in order to allow bootloaders to load the result
+ as if it were a Linux kernel image.
A real Linux kernel image consists of a one-sector boot loader
(to load the image from a floppy disk), followed a few sectors
contains some other parameters that aren't interesting in this
case.
- When LILO loads the sectors that comprise a kernel image, it doesn't
- execute the code in the first sector (since that code would try to
- load the image from a floppy disk.) The code in the first sector
- below doesn't expect to get executed (and prints an error message
- if it ever -is- executed.) LILO's only interested in knowing the
- number of setup sectors advertised in the table (at offset 497 in
- the first sector.)
+ When a bootloader loads the sectors that comprise a kernel image,
+ it doesn't execute the code in the first sector (since that code
+ would try to load the image from a floppy disk.) The code in the
+ first sector below doesn't expect to get executed (and prints an
+ error message if it ever -is- executed.)
- Etherboot doesn't require much in the way of setup code.
- Historically, the Linux kernel required at least 4 sectors of
- setup code. Current versions of LILO look at the byte at
- offset 497 in the first sector to indicate how many sectors
- of setup code are contained in the image.
+ We don't require much in the way of setup code. Historically, the
+ Linux kernel required at least 4 sectors of setup code.
+ Therefore, at least 4 sectors must be present even though we don't
+ use them.
*/
why_end:
+/*
+ The following header is documented in the Linux source code at
+ Documentation/i386/boot.txt
+*/
.org 497
setup_sects:
.byte SETUPSECS
root_flags:
.word 0
syssize:
- .word _load_size_pgh - PREFIXPGH
-swap_dev:
- .word 0
+ .long _load_size_pgh - PREFIXPGH
+
+ .section ".zinfo.fixup", "a" /* Compressor fixup information */
+ .ascii "SUBL"
+ .long syssize
+ .long 16
+ .long 0
+ .previous
+
ram_size:
.word 0
vid_mode:
.word 0
boot_flag:
.word 0xAA55
-
-
- .org 512
-
- .section ".zinfo.fixup", "a" /* Compressor fixup information */
- .ascii "SUBW"
- .long syssize
- .long 16
+jump:
+ jmp setup_code
+header:
+ .byte 'H', 'd', 'r', 'S'
+version:
+ .word 0x0207 /* 2.07 */
+realmode_swtch:
.long 0
- .previous
-
-/*
- We're now at the beginning of the second sector of the image -
- where the setup code goes.
+start_sys:
+ .word 0
+kernel_version:
+ .word 0
+type_of_loader:
+ .byte 0
+loadflags:
+ .byte 0
+setup_move_size:
+ .word 0
+code32_start:
+ .long 0
+ramdisk_image:
+ .long 0
+ramdisk_size:
+ .long 0
+bootsect_kludge:
+ .long 0
+heap_end_ptr:
+ .word 0
+pad1:
+ .word 0
+cmd_line_ptr:
+ .long 0
+initrd_addr_max:
+ .long 0
+kernel_alignment:
+ .long 0
+relocatable_kernel:
+ .byte 0
+pad2:
+ .byte 0, 0, 0
+cmdline_size:
+ .long 0
+hardware_subarch:
+ .long 0
+hardware_subarch_data:
+ .byte 0, 0, 0, 0, 0, 0, 0, 0
- We don't need to do too much setup for Etherboot.
+/*
+ We don't need to do too much setup.
This code gets loaded at SETUPSEG:0. It wants to start
- executing the Etherboot image that's loaded at SYSSEG:0 and
+ executing the image that's loaded at SYSSEG:0 and
whose entry point is SYSSEG:0.
*/
setup_code:
- /* Etherboot expects to be contiguous in memory once loaded.
- * LILO doesn't do this, but since we don't need any
- * information that's left in the prefix, it doesn't matter:
- * we just have to ensure that %cs:0000 is where the start of
- * the Etherboot image *would* be.
+ /* We expect to be contiguous in memory once loaded. The Linux image
+ * boot process requires that setup code is loaded separately from
+ * "non-real code". Since we don't need any information that's left
+ * in the prefix, it doesn't matter: we just have to ensure that
+ * %cs:0000 is where the start of the image *would* be.
*/
- ljmp $(SYSSEG-(PREFIXSIZE/16)), $run_etherboot
+ ljmp $(SYSSEG-(PREFIXSIZE/16)), $run_gpxe
.org PREFIXSIZE
/*
We're now at the beginning of the kernel proper.
*/
-run_etherboot:
+run_gpxe:
+ /* Set up stack just below 0x7c00 */
+ xorw %ax, %ax
+ movw %ax, %ss
+ movw $0x7c00, %sp
+
call install
+ /* Set up real-mode stack */
+ movw %bx, %ss
+ movw $_estack16, %sp
+
/* Jump to .text16 segment */
pushw %ax
pushw $1f
popl %es:( 0x19 * 4 )
hook_bbs:
/* Check for PMM */
- movw $( 0xe00 - 1 ), %bx
+ movw $( 0xe000 - 1 ), %bx
pmm_scan:
incw %bx
jz no_pmm
#undef BUILD_ID /* Include a custom build ID string,
* e.g "test-foo" */
#undef NULL_TRAP /* Attempt to catch NULL function calls */
-#undef GDBSTUB /* Remote GDB debugging */
+#undef GDBSERIAL /* Remote GDB debugging over serial */
+#undef GDBUDP /* Remote GDB debugging over UDP
+ * (both may be set) */
/* @END general.h */
#ifdef NULL_TRAP
REQUIRE_OBJECT ( nulltrap );
#endif
-#ifdef GDBSTUB
+#ifdef GDBSERIAL
REQUIRE_OBJECT ( gdbidt );
+REQUIRE_OBJECT ( gdbserial );
+REQUIRE_OBJECT ( gdbstub_cmd );
+#endif
+#ifdef GDBUDP
+REQUIRE_OBJECT ( gdbidt );
+REQUIRE_OBJECT ( gdbudp );
+REQUIRE_OBJECT ( gdbstub_cmd );
#endif
*/
#include <stdlib.h>
-#include <stddef.h>
#include <stdio.h>
+#include <string.h>
#include <ctype.h>
-#include <assert.h>
-#include <gpxe/process.h>
-#include <gpxe/serial.h>
+#include <byteswap.h>
+#include <gpxe/gdbstub.h>
#include "gdbmach.h"
enum {
- POSIX_EINVAL = 0x1c /* used to report bad arguments to GDB */
+ POSIX_EINVAL = 0x1c, /* used to report bad arguments to GDB */
+ SIZEOF_PAYLOAD = 256, /* buffer size of GDB payload data */
};
struct gdbstub {
+ struct gdb_transport *trans;
+ int exit_handler; /* leave interrupt handler */
+
int signo;
gdbreg_t *regs;
- int exit_handler; /* leave interrupt handler */
void ( * parse ) ( struct gdbstub *stub, char ch );
uint8_t cksum1;
/* Buffer for payload data when parsing a packet. Once the
* packet has been received, this buffer is used to hold
* the reply payload. */
- char payload [ 256 ];
- int len;
+ char buf [ SIZEOF_PAYLOAD + 4 ]; /* $...PAYLOAD...#XX */
+ char *payload; /* start of payload */
+ int len; /* length of payload */
};
+/* Transports */
+static struct gdb_transport gdb_transport_start[0] __table_start ( struct gdb_transport, gdb_transports );
+static struct gdb_transport gdb_transport_end[0] __table_end ( struct gdb_transport, gdb_transports );
+
/* Packet parser states */
static void gdbstub_state_new ( struct gdbstub *stub, char ch );
static void gdbstub_state_data ( struct gdbstub *stub, char ch );
return ( b < 0xa ? '0' : 'a' - 0xa ) + b;
}
-static void gdbstub_from_hex_buf ( char *dst, char *src, int len ) {
- while ( len-- > 0 ) {
- *dst = gdbstub_from_hex_digit ( *src++ );
- if ( len-- > 0 ) {
- *dst = (*dst << 4) | gdbstub_from_hex_digit ( *src++ );
+/*
+ * To make reading/writing device memory atomic, we check for
+ * 2- or 4-byte aligned operations and handle them specially.
+ */
+
+static void gdbstub_from_hex_buf ( char *dst, char *src, int lenbytes ) {
+ if ( lenbytes == 2 && ( ( unsigned long ) dst & 0x1 ) == 0 ) {
+ uint16_t i = gdbstub_from_hex_digit ( src [ 2 ] ) << 12 |
+ gdbstub_from_hex_digit ( src [ 3 ] ) << 8 |
+ gdbstub_from_hex_digit ( src [ 0 ] ) << 4 |
+ gdbstub_from_hex_digit ( src [ 1 ] );
+ * ( uint16_t * ) dst = cpu_to_le16 ( i );
+ } else if ( lenbytes == 4 && ( ( unsigned long ) dst & 0x3 ) == 0 ) {
+ uint32_t i = gdbstub_from_hex_digit ( src [ 6 ] ) << 28 |
+ gdbstub_from_hex_digit ( src [ 7 ] ) << 24 |
+ gdbstub_from_hex_digit ( src [ 4 ] ) << 20 |
+ gdbstub_from_hex_digit ( src [ 5 ] ) << 16 |
+ gdbstub_from_hex_digit ( src [ 2 ] ) << 12 |
+ gdbstub_from_hex_digit ( src [ 3 ] ) << 8 |
+ gdbstub_from_hex_digit ( src [ 0 ] ) << 4 |
+ gdbstub_from_hex_digit ( src [ 1 ] );
+ * ( uint32_t * ) dst = cpu_to_le32 ( i );
+ } else {
+ while ( lenbytes-- > 0 ) {
+ *dst++ = gdbstub_from_hex_digit ( src [ 0 ] ) << 4 |
+ gdbstub_from_hex_digit ( src [ 1 ] );
+ src += 2;
}
- dst++;
}
}
-static void gdbstub_to_hex_buf ( char *dst, char *src, int len ) {
- while ( len-- > 0 ) {
- *dst++ = gdbstub_to_hex_digit ( *src >> 4 );
- *dst++ = gdbstub_to_hex_digit ( *src++ );
+static void gdbstub_to_hex_buf ( char *dst, char *src, int lenbytes ) {
+ if ( lenbytes == 2 && ( ( unsigned long ) src & 0x1 ) == 0 ) {
+ uint16_t i = cpu_to_le16 ( * ( uint16_t * ) src );
+ dst [ 0 ] = gdbstub_to_hex_digit ( i >> 4 );
+ dst [ 1 ] = gdbstub_to_hex_digit ( i );
+ dst [ 2 ] = gdbstub_to_hex_digit ( i >> 12 );
+ dst [ 3 ] = gdbstub_to_hex_digit ( i >> 8 );
+ } else if ( lenbytes == 4 && ( ( unsigned long ) src & 0x3 ) == 0 ) {
+ uint32_t i = cpu_to_le32 ( * ( uint32_t * ) src );
+ dst [ 0 ] = gdbstub_to_hex_digit ( i >> 4 );
+ dst [ 1 ] = gdbstub_to_hex_digit ( i );
+ dst [ 2 ] = gdbstub_to_hex_digit ( i >> 12 );
+ dst [ 3 ] = gdbstub_to_hex_digit ( i >> 8 );
+ dst [ 4 ] = gdbstub_to_hex_digit ( i >> 20 );
+ dst [ 5 ] = gdbstub_to_hex_digit ( i >> 16);
+ dst [ 6 ] = gdbstub_to_hex_digit ( i >> 28 );
+ dst [ 7 ] = gdbstub_to_hex_digit ( i >> 24 );
+ } else {
+ while ( lenbytes-- > 0 ) {
+ *dst++ = gdbstub_to_hex_digit ( *src >> 4 );
+ *dst++ = gdbstub_to_hex_digit ( *src );
+ src++;
+ }
}
}
return cksum;
}
-static int gdbstub_getchar ( struct gdbstub *stub ) {
- if ( stub->exit_handler ) {
- return -1;
- }
- return serial_getc();
-}
-
-static void gdbstub_putchar ( struct gdbstub * stub __unused, char ch ) {
- serial_putc ( ch );
-}
-
static void gdbstub_tx_packet ( struct gdbstub *stub ) {
uint8_t cksum = gdbstub_cksum ( stub->payload, stub->len );
- int i;
-
- gdbstub_putchar ( stub, '$' );
- for ( i = 0; i < stub->len; i++ ) {
- gdbstub_putchar ( stub, stub->payload [ i ] );
- }
- gdbstub_putchar ( stub, '#' );
- gdbstub_putchar ( stub, gdbstub_to_hex_digit ( cksum >> 4 ) );
- gdbstub_putchar ( stub, gdbstub_to_hex_digit ( cksum ) );
-
+ stub->buf [ 0 ] = '$';
+ stub->buf [ stub->len + 1 ] = '#';
+ stub->buf [ stub->len + 2 ] = gdbstub_to_hex_digit ( cksum >> 4 );
+ stub->buf [ stub->len + 3 ] = gdbstub_to_hex_digit ( cksum );
+ stub->trans->send ( stub->buf, stub->len + 4 );
stub->parse = gdbstub_state_wait_ack;
}
gdbstub_send_errno ( stub, POSIX_EINVAL );
return;
}
- gdbstub_from_hex_buf ( ( char * ) stub->regs, &stub->payload [ 1 ], stub->len );
+ gdbstub_from_hex_buf ( ( char * ) stub->regs, &stub->payload [ 1 ], GDBMACH_SIZEOF_REGS );
gdbstub_send_ok ( stub );
}
gdbstub_send_errno ( stub, POSIX_EINVAL );
return;
}
- args [ 1 ] = ( args [ 1 ] < sizeof stub->payload / 2 ) ? args [ 1 ] : sizeof stub->payload / 2;
+ args [ 1 ] = ( args [ 1 ] < SIZEOF_PAYLOAD / 2 ) ? args [ 1 ] : SIZEOF_PAYLOAD / 2;
gdbstub_to_hex_buf ( stub->payload, ( char * ) args [ 0 ], args [ 1 ] );
stub->len = args [ 1 ] * 2;
gdbstub_tx_packet ( stub );
gdbstub_send_errno ( stub, POSIX_EINVAL );
return;
}
- gdbstub_from_hex_buf ( ( char * ) args [ 0 ], &stub->payload [ colon + 1 ], stub->len - colon - 1 );
+ gdbstub_from_hex_buf ( ( char * ) args [ 0 ], &stub->payload [ colon + 1 ], ( stub->len - colon - 1 ) / 2 );
gdbstub_send_ok ( stub );
}
/* Reply will be sent when we hit the next breakpoint or interrupt */
}
+static void gdbstub_breakpoint ( struct gdbstub *stub ) {
+ unsigned long args [ 3 ];
+ int enable = stub->payload [ 0 ] == 'Z' ? 1 : 0;
+ if ( !gdbstub_get_packet_args ( stub, args, sizeof args / sizeof args [ 0 ], NULL ) ) {
+ gdbstub_send_errno ( stub, POSIX_EINVAL );
+ return;
+ }
+ if ( gdbmach_set_breakpoint ( args [ 0 ], args [ 1 ], args [ 2 ], enable ) ) {
+ gdbstub_send_ok ( stub );
+ } else {
+ /* Not supported */
+ stub->len = 0;
+ gdbstub_tx_packet ( stub );
+ }
+}
+
static void gdbstub_rx_packet ( struct gdbstub *stub ) {
switch ( stub->payload [ 0 ] ) {
case '?':
case 'M':
gdbstub_write_mem ( stub );
break;
- case 'c':
- gdbstub_continue ( stub, 0 );
+ case 'c': /* Continue */
+ case 'k': /* Kill */
+ case 's': /* Step */
+ case 'D': /* Detach */
+ gdbstub_continue ( stub, stub->payload [ 0 ] == 's' );
+ if ( stub->payload [ 0 ] == 'D' ) {
+ gdbstub_send_ok ( stub );
+ }
break;
- case 's':
- gdbstub_continue ( stub, 1 );
+ case 'Z': /* Insert breakpoint */
+ case 'z': /* Remove breakpoint */
+ gdbstub_breakpoint ( stub );
break;
default:
stub->len = 0;
stub->len = 0; /* retry new packet */
} else {
/* If the length exceeds our buffer, let the checksum fail */
- if ( stub->len < ( int ) sizeof stub->payload ) {
+ if ( stub->len < SIZEOF_PAYLOAD ) {
stub->payload [ stub->len++ ] = ch;
}
}
their_cksum = stub->cksum1 + gdbstub_from_hex_digit ( ch );
our_cksum = gdbstub_cksum ( stub->payload, stub->len );
if ( their_cksum == our_cksum ) {
- gdbstub_putchar ( stub, '+' );
+ stub->trans->send ( "+", 1 );
if ( stub->len > 0 ) {
gdbstub_rx_packet ( stub );
}
} else {
- gdbstub_putchar ( stub, '-' );
+ stub->trans->send ( "-", 1 );
}
}
stub->parse = gdbstub_state_new;
} else if ( ch == '-' ) {
gdbstub_tx_packet ( stub ); /* retransmit */
+ } else if ( ch == '$' ) {
+ /* GDB is reconnecting, drop our packet and listen to GDB */
+ stub->trans->send ( "-", 1 );
+ stub->parse = gdbstub_state_new;
}
}
.parse = gdbstub_state_new
};
-__cdecl void gdbstub_handler ( int signo, gdbreg_t *regs ) {
- int ch;
+void gdbstub_handler ( int signo, gdbreg_t *regs ) {
+ char packet [ SIZEOF_PAYLOAD + 4 ];
+ size_t len, i;
+
+ /* A transport must be set up */
+ if ( !stub.trans ) {
+ return;
+ }
+
stub.signo = signo;
stub.regs = regs;
stub.exit_handler = 0;
gdbstub_report_signal ( &stub );
- while ( ( ch = gdbstub_getchar( &stub ) ) != -1 ) {
- gdbstub_parse ( &stub, ch );
+ while ( !stub.exit_handler && ( len = stub.trans->recv ( packet, sizeof ( packet ) ) ) > 0 ) {
+ for ( i = 0; i < len; i++ ) {
+ gdbstub_parse ( &stub, packet [ i ] );
+ }
}
}
-/* Activity monitor to detect packets from GDB when we are not active */
-static void gdbstub_activity_step ( struct process *process __unused ) {
- if ( serial_ischar() ) {
- gdbmach_breakpoint();
+struct gdb_transport *find_gdb_transport ( const char *name ) {
+ struct gdb_transport *trans;
+ for ( trans = gdb_transport_start; trans < gdb_transport_end; trans++ ) {
+ if ( strcmp ( trans->name, name ) == 0 ) {
+ return trans;
+ }
}
+ return NULL;
}
-struct process gdbstub_activity_process __permanent_process = {
- .step = gdbstub_activity_step,
-};
+void gdbstub_start ( struct gdb_transport *trans ) {
+ stub.trans = trans;
+ stub.payload = &stub.buf [ 1 ];
+ gdbmach_breakpoint();
+}
#if 1
+#if !defined(INCLUDE_NS8390) && !defined(INCLUDE_WD) && \
+ !defined(INCLUDE_NE) && !defined(INCLUDE_3C503)
+ /* The driver named ns8390 is the PCI driver, often called
+ "PCI ne2000 clones". */
+# define INCLUDE_NS8390 1
+#endif
#include "etherboot.h"
#include "nic.h"
.arch i386
+
+ .section ".data"
+watch_me:
+ .long 0xfeedbeef
+
.section ".text"
.code32
gdbstub_test:
int $3
addl $8, %esp
+ /* 5. Step test */
+ int $3
+ nop
+
+ /* 6. Access watch test */
+ movl $0x600d0000, %ecx
+ movl watch_me, %eax
+ movl $0xbad00000, %ecx
+ int $3
+ movl $0x600d0001, %ecx
+ movl %eax, watch_me
+ movl $0xbad00001, %ecx
+ int $3
+
+ /* 7. Write watch test */
+ movl $0x600d0002, %ecx
+ movl %eax, watch_me
+ movl $0xbad00002, %ecx
+ int $3
+
1:
jmp 1b
# Run:
# make bin/gpxe.hd.tmp
# make
-# tests/gdbstub_test.gdb
+# gdb
+# (gdb) target remote :TCPPORT
+# OR
+# (gdb) target remote udp:IP:UDPPORT
+# (gdb) source tests/gdbstub_test.gdb
define gpxe_load_symbols
file bin/gpxe.hd.tmp
end
-define gpxe_connect
- target remote localhost:4444
-end
-
define gpxe_assert
if $arg0 != $arg1
echo FAIL $arg2\n
gpxe_assert ({char}($esp)) (char)0x99 "gpxe_test_mem_write char"
end
+define gpxe_test_step
+ c
+ si
+ gpxe_assert ({char}($eip-1)) (char)0x90 "gpxe_test_step" # nop = 0x90
+end
+
+define gpxe_test_awatch
+ awatch watch_me
+
+ c
+ gpxe_assert $ecx 0x600d0000 "gpxe_test_awatch read"
+ if $ecx == 0x600d0000
+ c
+ end
+
+ c
+ gpxe_assert $ecx 0x600d0001 "gpxe_test_awatch write"
+ if $ecx == 0x600d0001
+ c
+ end
+
+ delete
+end
+
+define gpxe_test_watch
+ watch watch_me
+ c
+ gpxe_assert $ecx 0x600d0002 "gpxe_test_watch"
+ if $ecx == 0x600d0002
+ c
+ end
+ delete
+end
+
gpxe_load_symbols
-gpxe_connect
gpxe_start_tests
gpxe_test_regs_read
gpxe_test_regs_write
gpxe_test_mem_read
gpxe_test_mem_write
+gpxe_test_step
+gpxe_test_awatch
+gpxe_test_watch