Index: projects/collation/kerberos5/lib/Makefile =================================================================== --- projects/collation/kerberos5/lib/Makefile (revision 289266) +++ projects/collation/kerberos5/lib/Makefile (revision 289267) @@ -1,12 +1,11 @@ # $FreeBSD$ SUBDIR= libasn1 libgssapi_krb5 libgssapi_ntlm libgssapi_spnego libhdb \ libheimntlm libhx509 libkadm5clnt libkadm5srv libkrb5 \ libroken libsl libvers libkdc libwind libheimbase libheimipcc libheimipcs SUBDIR+= libkafs5 # requires krb_err.h from libkrb5 SUBDIR_DEPEND_libkafs5= libkrb5 -SUBDIR_PARALLEL= .include Index: projects/collation/share/mk/bsd.subdir.mk =================================================================== --- projects/collation/share/mk/bsd.subdir.mk (revision 289266) +++ projects/collation/share/mk/bsd.subdir.mk (revision 289267) @@ -1,152 +1,153 @@ # from: @(#)bsd.subdir.mk 5.9 (Berkeley) 2/1/91 # $FreeBSD$ # # The include file contains the default targets # for building subdirectories. # # For all of the directories listed in the variable SUBDIRS, the # specified directory will be visited and the target made. There is # also a default target which allows the command "make subdir" where # subdir is any directory listed in the variable SUBDIRS. # # # +++ variables +++ # # DISTRIBUTION Name of distribution. [base] # # SUBDIR A list of subdirectories that should be built as well. # Each of the targets will execute the same target in the # subdirectories. SUBDIR.yes is automatically appeneded # to this list. # # +++ targets +++ # # distribute: # This is a variant of install, which will # put the stuff into the right "distribution". # -# afterinstall, all, all-man, beforeinstall, checkdpadd, clean, -# cleandepend, cleandir, cleanilinks depend, install, lint, -# maninstall, manlint, obj, objlink, realinstall, regress, tags +# See ALL_SUBDIR_TARGETS for list of targets that will recurse. +# Custom targets can be added to SUBDIR_TARGETS in src.conf. # .if !target(____) ____: +ALL_SUBDIR_TARGETS= all all-man checkdpadd clean cleandepend cleandir \ + cleanilinks cleanobj depend distribute lint maninstall manlint obj \ + objlink realinstall regress tags ${SUBDIR_TARGETS} + .include .if !defined(NEED_SUBDIR) .if ${.MAKE.LEVEL} == 0 && ${MK_META_MODE} == "yes" && !empty(SUBDIR) && !(make(clean*) || make(destroy*)) .include # ignore this _SUBDIR: .endif .endif .if !target(_SUBDIR) .if defined(SUBDIR) SUBDIR:=${SUBDIR} ${SUBDIR.yes} SUBDIR:=${SUBDIR:u} .endif DISTRIBUTION?= base .if !target(distribute) distribute: .MAKE .for dist in ${DISTRIBUTION} ${_+_}cd ${.CURDIR}; \ ${MAKE} install -DNO_SUBDIR DESTDIR=${DISTDIR}/${dist} SHARED=copies .endfor .endif _SUBDIR: .USE .MAKE .if defined(SUBDIR) && !empty(SUBDIR) && !defined(NO_SUBDIR) @${_+_}for entry in ${SUBDIR:N.WAIT}; do \ if test -d ${.CURDIR}/$${entry}.${MACHINE_ARCH}; then \ ${ECHODIR} "===> ${DIRPRFX}$${entry}.${MACHINE_ARCH} (${.TARGET:S,realinstall,install,:S,^_sub.,,})"; \ edir=$${entry}.${MACHINE_ARCH}; \ cd ${.CURDIR}/$${edir}; \ else \ ${ECHODIR} "===> ${DIRPRFX}$$entry (${.TARGET:S,realinstall,install,:S,^_sub.,,})"; \ edir=$${entry}; \ cd ${.CURDIR}/$${edir}; \ fi; \ ${MAKE} ${.TARGET:S,realinstall,install,:S,^_sub.,,} \ DIRPRFX=${DIRPRFX}$$edir/; \ done .endif ${SUBDIR:N.WAIT}: .PHONY .MAKE ${_+_}@if test -d ${.TARGET}.${MACHINE_ARCH}; then \ cd ${.CURDIR}/${.TARGET}.${MACHINE_ARCH}; \ else \ cd ${.CURDIR}/${.TARGET}; \ fi; \ ${MAKE} all # Work around parsing of .if nested in .for by putting .WAIT string into a var. __wait= .WAIT -.for __target in all all-man checkdpadd clean cleandepend cleandir \ - cleanilinks depend distribute lint maninstall manlint obj objlink \ - realinstall regress tags ${SUBDIR_TARGETS} +.for __target in ${ALL_SUBDIR_TARGETS} .ifdef SUBDIR_PARALLEL __subdir_targets= .for __dir in ${SUBDIR} .if ${__wait} == ${__dir} __subdir_targets+= .WAIT .else __subdir_targets+= ${__target}_subdir_${__dir} __deps= .for __dep in ${SUBDIR_DEPEND_${__dir}} __deps+= ${__target}_subdir_${__dep} .endfor ${__target}_subdir_${__dir}: .MAKE ${__deps} .if !defined(NO_SUBDIR) @${_+_}if test -d ${.CURDIR}/${__dir}.${MACHINE_ARCH}; then \ ${ECHODIR} "===> ${DIRPRFX}${__dir}.${MACHINE_ARCH} (${__target:realinstall=install})"; \ edir=${__dir}.${MACHINE_ARCH}; \ cd ${.CURDIR}/$${edir}; \ else \ ${ECHODIR} "===> ${DIRPRFX}${__dir} (${__target:realinstall=install})"; \ edir=${__dir}; \ cd ${.CURDIR}/$${edir}; \ fi; \ ${MAKE} ${__target:realinstall=install} \ DIRPRFX=${DIRPRFX}$$edir/ .endif .endif .endfor ${__target}: ${__subdir_targets} .else ${__target}: _sub.${__target} _sub.${__target}: _SUBDIR .endif .endfor .for __target in files includes config .for __stage in build install ${__stage}${__target}: .if make(${__stage}${__target}) ${__stage}${__target}: _sub.${__stage}${__target} _sub.${__stage}${__target}: _SUBDIR .endif .endfor .if !target(${__target}) ${__target}: .MAKE ${_+_}cd ${.CURDIR}; ${MAKE} build${__target}; ${MAKE} install${__target} .endif .endfor .endif .if !target(install) .if !target(beforeinstall) beforeinstall: .endif .if !target(afterinstall) afterinstall: .endif install: beforeinstall realinstall afterinstall .ORDER: beforeinstall realinstall afterinstall .endif .endif Index: projects/collation/share =================================================================== --- projects/collation/share (revision 289266) +++ projects/collation/share (revision 289267) Property changes on: projects/collation/share ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/share:r289239-289266 Index: projects/collation/sys/dev/ioat/ioat_internal.h =================================================================== --- projects/collation/sys/dev/ioat/ioat_internal.h (revision 289266) +++ projects/collation/sys/dev/ioat/ioat_internal.h (revision 289267) @@ -1,447 +1,447 @@ /*- * Copyright (C) 2012 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ __FBSDID("$FreeBSD$"); #ifndef __IOAT_INTERNAL_H__ #define __IOAT_INTERNAL_H__ #define DEVICE2SOFTC(dev) ((struct ioat_softc *) device_get_softc(dev)) #define ioat_read_chancnt(ioat) \ ioat_read_1((ioat), IOAT_CHANCNT_OFFSET) #define ioat_read_xfercap(ioat) \ ioat_read_1((ioat), IOAT_XFERCAP_OFFSET) #define ioat_write_intrctrl(ioat, value) \ ioat_write_1((ioat), IOAT_INTRCTRL_OFFSET, (value)) #define ioat_read_cbver(ioat) \ (ioat_read_1((ioat), IOAT_CBVER_OFFSET) & 0xFF) #define ioat_read_dmacapability(ioat) \ ioat_read_4((ioat), IOAT_DMACAPABILITY_OFFSET) #define ioat_write_chanctrl(ioat, value) \ ioat_write_2((ioat), IOAT_CHANCTRL_OFFSET, (value)) static __inline uint64_t ioat_bus_space_read_8_lower_first(bus_space_tag_t tag, bus_space_handle_t handle, bus_size_t offset) { return (bus_space_read_4(tag, handle, offset) | ((uint64_t)bus_space_read_4(tag, handle, offset + 4)) << 32); } static __inline void ioat_bus_space_write_8_lower_first(bus_space_tag_t tag, bus_space_handle_t handle, bus_size_t offset, uint64_t val) { bus_space_write_4(tag, handle, offset, val); bus_space_write_4(tag, handle, offset + 4, val >> 32); } -#ifdef i386 +#ifdef __i386__ #define ioat_bus_space_read_8 ioat_bus_space_read_8_lower_first #define ioat_bus_space_write_8 ioat_bus_space_write_8_lower_first #else #define ioat_bus_space_read_8(tag, handle, offset) \ bus_space_read_8((tag), (handle), (offset)) #define ioat_bus_space_write_8(tag, handle, offset, val) \ bus_space_write_8((tag), (handle), (offset), (val)) #endif #define ioat_read_1(ioat, offset) \ bus_space_read_1((ioat)->pci_bus_tag, (ioat)->pci_bus_handle, \ (offset)) #define ioat_read_2(ioat, offset) \ bus_space_read_2((ioat)->pci_bus_tag, (ioat)->pci_bus_handle, \ (offset)) #define ioat_read_4(ioat, offset) \ bus_space_read_4((ioat)->pci_bus_tag, (ioat)->pci_bus_handle, \ (offset)) #define ioat_read_8(ioat, offset) \ ioat_bus_space_read_8((ioat)->pci_bus_tag, (ioat)->pci_bus_handle, \ (offset)) #define ioat_read_double_4(ioat, offset) \ ioat_bus_space_read_8_lower_first((ioat)->pci_bus_tag, \ (ioat)->pci_bus_handle, (offset)) #define ioat_write_1(ioat, offset, value) \ bus_space_write_1((ioat)->pci_bus_tag, (ioat)->pci_bus_handle, \ (offset), (value)) #define ioat_write_2(ioat, offset, value) \ bus_space_write_2((ioat)->pci_bus_tag, (ioat)->pci_bus_handle, \ (offset), (value)) #define ioat_write_4(ioat, offset, value) \ bus_space_write_4((ioat)->pci_bus_tag, (ioat)->pci_bus_handle, \ (offset), (value)) #define ioat_write_8(ioat, offset, value) \ ioat_bus_space_write_8((ioat)->pci_bus_tag, (ioat)->pci_bus_handle, \ (offset), (value)) #define ioat_write_double_4(ioat, offset, value) \ ioat_bus_space_write_8_lower_first((ioat)->pci_bus_tag, \ (ioat)->pci_bus_handle, (offset), (value)) MALLOC_DECLARE(M_IOAT); SYSCTL_DECL(_hw_ioat); void ioat_log_message(int verbosity, char *fmt, ...); struct ioat_dma_hw_descriptor { uint32_t size; union { uint32_t control_raw; struct { uint32_t int_enable:1; uint32_t src_snoop_disable:1; uint32_t dest_snoop_disable:1; uint32_t completion_update:1; uint32_t fence:1; uint32_t null:1; uint32_t src_page_break:1; uint32_t dest_page_break:1; uint32_t bundle:1; uint32_t dest_dca:1; uint32_t hint:1; uint32_t reserved:13; #define IOAT_OP_COPY 0x00 uint32_t op:8; } control; } u; uint64_t src_addr; uint64_t dest_addr; uint64_t next; uint64_t reserved; uint64_t reserved2; uint64_t user1; uint64_t user2; }; struct ioat_fill_hw_descriptor { uint32_t size; union { uint32_t control_raw; struct { uint32_t int_enable:1; uint32_t reserved:1; uint32_t dest_snoop_disable:1; uint32_t completion_update:1; uint32_t fence:1; uint32_t reserved2:2; uint32_t dest_page_break:1; uint32_t bundle:1; uint32_t reserved3:15; #define IOAT_OP_FILL 0x01 uint32_t op:8; } control; } u; uint64_t src_data; uint64_t dest_addr; uint64_t next; uint64_t reserved; uint64_t next_dest_addr; uint64_t user1; uint64_t user2; }; struct ioat_xor_hw_descriptor { uint32_t size; union { uint32_t control_raw; struct { uint32_t int_enable:1; uint32_t src_snoop_disable:1; uint32_t dest_snoop_disable:1; uint32_t completion_update:1; uint32_t fence:1; uint32_t src_count:3; uint32_t bundle:1; uint32_t dest_dca:1; uint32_t hint:1; uint32_t reserved:13; #define IOAT_OP_XOR 0x87 #define IOAT_OP_XOR_VAL 0x88 uint32_t op:8; } control; } u; uint64_t src_addr; uint64_t dest_addr; uint64_t next; uint64_t src_addr2; uint64_t src_addr3; uint64_t src_addr4; uint64_t src_addr5; }; struct ioat_xor_ext_hw_descriptor { uint64_t src_addr6; uint64_t src_addr7; uint64_t src_addr8; uint64_t next; uint64_t reserved[4]; }; struct ioat_pq_hw_descriptor { uint32_t size; union { uint32_t control_raw; struct { uint32_t int_enable:1; uint32_t src_snoop_disable:1; uint32_t dest_snoop_disable:1; uint32_t completion_update:1; uint32_t fence:1; uint32_t src_count:3; uint32_t bundle:1; uint32_t dest_dca:1; uint32_t hint:1; uint32_t p_disable:1; uint32_t q_disable:1; uint32_t reserved:11; #define IOAT_OP_PQ 0x89 #define IOAT_OP_PQ_VAL 0x8a uint32_t op:8; } control; } u; uint64_t src_addr; uint64_t p_addr; uint64_t next; uint64_t src_addr2; uint64_t src_addr3; uint8_t coef[8]; uint64_t q_addr; }; struct ioat_pq_ext_hw_descriptor { uint64_t src_addr4; uint64_t src_addr5; uint64_t src_addr6; uint64_t next; uint64_t src_addr7; uint64_t src_addr8; uint64_t reserved[2]; }; struct ioat_pq_update_hw_descriptor { uint32_t size; union { uint32_t control_raw; struct { uint32_t int_enable:1; uint32_t src_snoop_disable:1; uint32_t dest_snoop_disable:1; uint32_t completion_update:1; uint32_t fence:1; uint32_t src_cnt:3; uint32_t bundle:1; uint32_t dest_dca:1; uint32_t hint:1; uint32_t p_disable:1; uint32_t q_disable:1; uint32_t reserved:3; uint32_t coef:8; #define IOAT_OP_PQ_UP 0x8b uint32_t op:8; } control; } u; uint64_t src_addr; uint64_t p_addr; uint64_t next; uint64_t src_addr2; uint64_t p_src; uint64_t q_src; uint64_t q_addr; }; struct ioat_raw_hw_descriptor { uint64_t field[8]; }; struct bus_dmadesc { bus_dmaengine_callback_t callback_fn; void *callback_arg; }; struct ioat_descriptor { struct bus_dmadesc bus_dmadesc; union { struct ioat_dma_hw_descriptor *dma; struct ioat_fill_hw_descriptor *fill; struct ioat_xor_hw_descriptor *xor; struct ioat_xor_ext_hw_descriptor *xor_ext; struct ioat_pq_hw_descriptor *pq; struct ioat_pq_ext_hw_descriptor *pq_ext; struct ioat_raw_hw_descriptor *raw; } u; uint32_t id; uint32_t length; enum validate_flags *validate_result; bus_addr_t hw_desc_bus_addr; }; /* One of these per allocated PCI device. */ struct ioat_softc { bus_dmaengine_t dmaengine; #define to_ioat_softc(_dmaeng) \ ({ \ bus_dmaengine_t *_p = (_dmaeng); \ (struct ioat_softc *)((char *)_p - \ offsetof(struct ioat_softc, dmaengine)); \ }) int version; struct mtx submit_lock; int num_interrupts; device_t device; bus_space_tag_t pci_bus_tag; bus_space_handle_t pci_bus_handle; int pci_resource_id; struct resource *pci_resource; uint32_t max_xfer_size; struct resource *res; int rid; void *tag; bus_dma_tag_t hw_desc_tag; bus_dmamap_t hw_desc_map; bus_dma_tag_t comp_update_tag; bus_dmamap_t comp_update_map; uint64_t *comp_update; bus_addr_t comp_update_bus_addr; struct callout timer; boolean_t is_resize_pending; boolean_t is_completion_pending; boolean_t is_reset_pending; boolean_t is_channel_running; boolean_t is_waiting_for_ack; uint32_t xfercap_log; uint32_t head; uint32_t tail; uint16_t reserved; uint32_t ring_size_order; bus_addr_t last_seen; struct ioat_descriptor **ring; struct mtx cleanup_lock; }; static inline uint64_t ioat_get_chansts(struct ioat_softc *ioat) { uint64_t status; if (ioat->version >= IOAT_VER_3_3) status = ioat_read_8(ioat, IOAT_CHANSTS_OFFSET); else /* Must read lower 4 bytes before upper 4 bytes. */ status = ioat_read_double_4(ioat, IOAT_CHANSTS_OFFSET); return (status); } static inline void ioat_write_chancmp(struct ioat_softc *ioat, uint64_t addr) { if (ioat->version >= IOAT_VER_3_3) ioat_write_8(ioat, IOAT_CHANCMP_OFFSET_LOW, addr); else ioat_write_double_4(ioat, IOAT_CHANCMP_OFFSET_LOW, addr); } static inline void ioat_write_chainaddr(struct ioat_softc *ioat, uint64_t addr) { if (ioat->version >= IOAT_VER_3_3) ioat_write_8(ioat, IOAT_CHAINADDR_OFFSET_LOW, addr); else ioat_write_double_4(ioat, IOAT_CHAINADDR_OFFSET_LOW, addr); } static inline boolean_t is_ioat_active(uint64_t status) { return ((status & IOAT_CHANSTS_STATUS) == IOAT_CHANSTS_ACTIVE); } static inline boolean_t is_ioat_idle(uint64_t status) { return ((status & IOAT_CHANSTS_STATUS) == IOAT_CHANSTS_IDLE); } static inline boolean_t is_ioat_halted(uint64_t status) { return ((status & IOAT_CHANSTS_STATUS) == IOAT_CHANSTS_HALTED); } static inline boolean_t is_ioat_suspended(uint64_t status) { return ((status & IOAT_CHANSTS_STATUS) == IOAT_CHANSTS_SUSPENDED); } static inline void ioat_suspend(struct ioat_softc *ioat) { ioat_write_1(ioat, IOAT_CHANCMD_OFFSET, IOAT_CHANCMD_SUSPEND); } static inline void ioat_reset(struct ioat_softc *ioat) { ioat_write_1(ioat, IOAT_CHANCMD_OFFSET, IOAT_CHANCMD_RESET); } static inline boolean_t ioat_reset_pending(struct ioat_softc *ioat) { uint8_t cmd; cmd = ioat_read_1(ioat, IOAT_CHANCMD_OFFSET); return ((cmd & IOAT_CHANCMD_RESET) != 0); } #endif /* __IOAT_INTERNAL_H__ */ Index: projects/collation/sys/dev/ntb/if_ntb/if_ntb.c =================================================================== --- projects/collation/sys/dev/ntb/if_ntb/if_ntb.c (revision 289266) +++ projects/collation/sys/dev/ntb/if_ntb/if_ntb.c (revision 289267) @@ -1,1435 +1,1435 @@ /*- * Copyright (C) 2013 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../ntb_hw/ntb_hw.h" /* * The Non-Transparent Bridge (NTB) is a device on some Intel processors that * allows you to connect two systems using a PCI-e link. * * This module contains a protocol for sending and receiving messages, and * exposes that protocol through a simulated ethernet device called ntb. * * NOTE: Much of the code in this module is shared with Linux. Any patches may * be picked up and redistributed in Linux with a dual GPL/BSD license. */ /* TODO: These functions should really be part of the kernel */ #define test_bit(pos, bitmap_addr) (*(bitmap_addr) & 1UL << (pos)) #define set_bit(pos, bitmap_addr) *(bitmap_addr) |= 1UL << (pos) #define clear_bit(pos, bitmap_addr) *(bitmap_addr) &= ~(1UL << (pos)) #define KTR_NTB KTR_SPARE3 #define NTB_TRANSPORT_VERSION 3 #define NTB_RX_MAX_PKTS 64 #define NTB_RXQ_SIZE 300 static unsigned int transport_mtu = 0x4000 + ETHER_HDR_LEN + ETHER_CRC_LEN; /* * This is an oversimplification to work around Xeon Errata. The second client * may be usable for unidirectional traffic. */ static unsigned int max_num_clients = 1; STAILQ_HEAD(ntb_queue_list, ntb_queue_entry); struct ntb_queue_entry { /* ntb_queue list reference */ STAILQ_ENTRY(ntb_queue_entry) entry; /* info on data to be transfered */ void *cb_data; void *buf; uint64_t len; uint64_t flags; }; struct ntb_rx_info { unsigned int entry; }; struct ntb_transport_qp { struct ntb_netdev *transport; struct ntb_softc *ntb; void *cb_data; bool client_ready; bool qp_link; uint8_t qp_num; /* Only 64 QPs are allowed. 0-63 */ struct ntb_rx_info *rx_info; struct ntb_rx_info *remote_rx_info; void (*tx_handler) (struct ntb_transport_qp *qp, void *qp_data, void *data, int len); struct ntb_queue_list tx_free_q; struct mtx ntb_tx_free_q_lock; void *tx_mw; uint64_t tx_index; uint64_t tx_max_entry; uint64_t tx_max_frame; void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data, void *data, int len); struct ntb_queue_list rx_pend_q; struct ntb_queue_list rx_free_q; struct mtx ntb_rx_pend_q_lock; struct mtx ntb_rx_free_q_lock; struct task rx_completion_task; void *rx_buff; uint64_t rx_index; uint64_t rx_max_entry; uint64_t rx_max_frame; void (*event_handler) (void *data, int status); struct callout link_work; struct callout queue_full; struct callout rx_full; uint64_t last_rx_no_buf; /* Stats */ uint64_t rx_bytes; uint64_t rx_pkts; uint64_t rx_ring_empty; uint64_t rx_err_no_buf; uint64_t rx_err_oflow; uint64_t rx_err_ver; uint64_t tx_bytes; uint64_t tx_pkts; uint64_t tx_ring_full; }; struct ntb_queue_handlers { void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data, void *data, int len); void (*tx_handler) (struct ntb_transport_qp *qp, void *qp_data, void *data, int len); void (*event_handler) (void *data, int status); }; struct ntb_transport_mw { size_t size; void *virt_addr; vm_paddr_t dma_addr; }; struct ntb_netdev { struct ntb_softc *ntb; struct ifnet *ifp; struct ntb_transport_mw mw[NTB_NUM_MW]; struct ntb_transport_qp *qps; uint64_t max_qps; uint64_t qp_bitmap; bool transport_link; struct callout link_work; struct ntb_transport_qp *qp; uint64_t bufsize; u_char eaddr[ETHER_ADDR_LEN]; struct mtx tx_lock; struct mtx rx_lock; }; static struct ntb_netdev net_softc; enum { IF_NTB_DESC_DONE_FLAG = 1 << 0, IF_NTB_LINK_DOWN_FLAG = 1 << 1, }; struct ntb_payload_header { uint64_t ver; uint64_t len; uint64_t flags; }; enum { /* * The order of this enum is part of the if_ntb remote protocol. Do * not reorder without bumping protocol version (and it's probably best * to keep the protocol in lock-step with the Linux NTB driver. */ IF_NTB_VERSION = 0, IF_NTB_QP_LINKS, IF_NTB_NUM_QPS, IF_NTB_NUM_MWS, /* * N.B.: transport_link_work assumes MW1 enums = MW0 + 2. */ IF_NTB_MW0_SZ_HIGH, IF_NTB_MW0_SZ_LOW, IF_NTB_MW1_SZ_HIGH, IF_NTB_MW1_SZ_LOW, IF_NTB_MAX_SPAD, }; #define QP_TO_MW(qp) ((qp) % NTB_NUM_MW) #define NTB_QP_DEF_NUM_ENTRIES 100 #define NTB_LINK_DOWN_TIMEOUT 10 static int ntb_handle_module_events(struct module *m, int what, void *arg); static int ntb_setup_interface(void); static int ntb_teardown_interface(void); static void ntb_net_init(void *arg); static int ntb_ioctl(struct ifnet *ifp, u_long command, caddr_t data); static void ntb_start(struct ifnet *ifp); static void ntb_net_tx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data, int len); static void ntb_net_rx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data, int len); static void ntb_net_event_handler(void *data, int status); static int ntb_transport_init(struct ntb_softc *ntb); static void ntb_transport_free(void *transport); static void ntb_transport_init_queue(struct ntb_netdev *nt, unsigned int qp_num); static void ntb_transport_free_queue(struct ntb_transport_qp *qp); static struct ntb_transport_qp * ntb_transport_create_queue(void *data, struct ntb_softc *pdev, const struct ntb_queue_handlers *handlers); static void ntb_transport_link_up(struct ntb_transport_qp *qp); static int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, unsigned int len); static int ntb_process_tx(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry); static void ntb_tx_copy_task(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry, void *offset); static void ntb_qp_full(void *arg); static void ntb_transport_rxc_db(void *data, int db_num); static void ntb_rx_pendq_full(void *arg); static void ntb_transport_rx(struct ntb_transport_qp *qp); static int ntb_process_rxc(struct ntb_transport_qp *qp); static void ntb_rx_copy_task(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry, void *offset); static void ntb_rx_completion_task(void *arg, int pending); static void ntb_transport_event_callback(void *data, enum ntb_hw_event event); static void ntb_transport_link_work(void *arg); static int ntb_set_mw(struct ntb_netdev *nt, int num_mw, unsigned int size); static void ntb_free_mw(struct ntb_netdev *nt, int num_mw); static void ntb_transport_setup_qp_mw(struct ntb_netdev *nt, unsigned int qp_num); static void ntb_qp_link_work(void *arg); static void ntb_transport_link_cleanup(struct ntb_netdev *nt); static void ntb_qp_link_down(struct ntb_transport_qp *qp); static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp); static void ntb_transport_link_down(struct ntb_transport_qp *qp); static void ntb_send_link_down(struct ntb_transport_qp *qp); static void ntb_list_add(struct mtx *lock, struct ntb_queue_entry *entry, struct ntb_queue_list *list); static struct ntb_queue_entry *ntb_list_rm(struct mtx *lock, struct ntb_queue_list *list); static void create_random_local_eui48(u_char *eaddr); static unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp); MALLOC_DEFINE(M_NTB_IF, "if_ntb", "ntb network driver"); /* Module setup and teardown */ static int ntb_handle_module_events(struct module *m, int what, void *arg) { int err = 0; switch (what) { case MOD_LOAD: err = ntb_setup_interface(); break; case MOD_UNLOAD: err = ntb_teardown_interface(); break; default: err = EOPNOTSUPP; break; } return (err); } static moduledata_t if_ntb_mod = { "if_ntb", ntb_handle_module_events, NULL }; DECLARE_MODULE(if_ntb, if_ntb_mod, SI_SUB_KLD, SI_ORDER_ANY); MODULE_DEPEND(if_ntb, ntb_hw, 1, 1, 1); static int ntb_setup_interface(void) { struct ifnet *ifp; struct ntb_queue_handlers handlers = { ntb_net_rx_handler, ntb_net_tx_handler, ntb_net_event_handler }; net_softc.ntb = devclass_get_softc(devclass_find("ntb_hw"), 0); if (net_softc.ntb == NULL) { printf("ntb: Cannot find devclass\n"); return (ENXIO); } ntb_transport_init(net_softc.ntb); ifp = net_softc.ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { printf("ntb: cannot allocate ifnet structure\n"); return (ENOMEM); } net_softc.qp = ntb_transport_create_queue(ifp, net_softc.ntb, &handlers); if_initname(ifp, "ntb", 0); ifp->if_init = ntb_net_init; ifp->if_softc = &net_softc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; ifp->if_ioctl = ntb_ioctl; ifp->if_start = ntb_start; IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; IFQ_SET_READY(&ifp->if_snd); create_random_local_eui48(net_softc.eaddr); ether_ifattach(ifp, net_softc.eaddr); ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_JUMBO_MTU; ifp->if_capenable = ifp->if_capabilities; ntb_transport_link_up(net_softc.qp); net_softc.bufsize = ntb_transport_max_size(net_softc.qp) + sizeof(struct ether_header); return (0); } static int ntb_teardown_interface(void) { if (net_softc.qp != NULL) ntb_transport_link_down(net_softc.qp); if (net_softc.ifp != NULL) { ether_ifdetach(net_softc.ifp); if_free(net_softc.ifp); } if (net_softc.qp != NULL) { ntb_transport_free_queue(net_softc.qp); ntb_transport_free(&net_softc); } return (0); } /* Network device interface */ static void ntb_net_init(void *arg) { struct ntb_netdev *ntb_softc = arg; struct ifnet *ifp = ntb_softc->ifp; ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_flags |= IFF_UP; if_link_state_change(ifp, LINK_STATE_UP); } static int ntb_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { struct ntb_netdev *nt = ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; int error = 0; switch (command) { case SIOCSIFMTU: { if (ifr->ifr_mtu > ntb_transport_max_size(nt->qp) - ETHER_HDR_LEN - ETHER_CRC_LEN) { error = EINVAL; break; } ifp->if_mtu = ifr->ifr_mtu; break; } default: error = ether_ioctl(ifp, command, data); break; } return (error); } static void ntb_start(struct ifnet *ifp) { struct mbuf *m_head; struct ntb_netdev *nt = ifp->if_softc; int rc; mtx_lock(&nt->tx_lock); ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; CTR0(KTR_NTB, "TX: ntb_start"); while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); CTR1(KTR_NTB, "TX: start mbuf %p", m_head); rc = ntb_transport_tx_enqueue(nt->qp, m_head, m_head, m_length(m_head, NULL)); if (rc != 0) { CTR1(KTR_NTB, "TX: could not tx mbuf %p. Returning to snd q", m_head); if (rc == EAGAIN) { ifp->if_drv_flags |= IFF_DRV_OACTIVE; IFQ_DRV_PREPEND(&ifp->if_snd, m_head); callout_reset(&nt->qp->queue_full, hz / 1000, ntb_qp_full, ifp); } break; } } mtx_unlock(&nt->tx_lock); } /* Network Device Callbacks */ static void ntb_net_tx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data, int len) { m_freem(data); CTR1(KTR_NTB, "TX: tx_handler freeing mbuf %p", data); } static void ntb_net_rx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data, int len) { struct mbuf *m = data; struct ifnet *ifp = qp_data; CTR0(KTR_NTB, "RX: rx handler"); (*ifp->if_input)(ifp, m); } static void ntb_net_event_handler(void *data, int status) { } /* Transport Init and teardown */ static int ntb_transport_init(struct ntb_softc *ntb) { struct ntb_netdev *nt = &net_softc; int rc, i; nt->max_qps = max_num_clients; ntb_register_transport(ntb, nt); mtx_init(&nt->tx_lock, "ntb transport tx", NULL, MTX_DEF); mtx_init(&nt->rx_lock, "ntb transport rx", NULL, MTX_DEF); nt->qps = malloc(nt->max_qps * sizeof(struct ntb_transport_qp), M_NTB_IF, M_WAITOK|M_ZERO); nt->qp_bitmap = ((uint64_t) 1 << nt->max_qps) - 1; for (i = 0; i < nt->max_qps; i++) ntb_transport_init_queue(nt, i); callout_init(&nt->link_work, 0); rc = ntb_register_event_callback(ntb, ntb_transport_event_callback); if (rc != 0) goto err; if (ntb_query_link_status(ntb)) { if (bootverbose) device_printf(ntb_get_device(ntb), "link up\n"); callout_reset(&nt->link_work, 0, ntb_transport_link_work, nt); } return (0); err: free(nt->qps, M_NTB_IF); ntb_unregister_transport(ntb); return (rc); } static void ntb_transport_free(void *transport) { struct ntb_netdev *nt = transport; struct ntb_softc *ntb = nt->ntb; int i; nt->transport_link = NTB_LINK_DOWN; callout_drain(&nt->link_work); /* verify that all the qps are freed */ for (i = 0; i < nt->max_qps; i++) if (!test_bit(i, &nt->qp_bitmap)) ntb_transport_free_queue(&nt->qps[i]); ntb_unregister_event_callback(ntb); for (i = 0; i < NTB_NUM_MW; i++) ntb_free_mw(nt, i); free(nt->qps, M_NTB_IF); ntb_unregister_transport(ntb); } static void ntb_transport_init_queue(struct ntb_netdev *nt, unsigned int qp_num) { struct ntb_transport_qp *qp; unsigned int num_qps_mw, tx_size; uint8_t mw_num = QP_TO_MW(qp_num); qp = &nt->qps[qp_num]; qp->qp_num = qp_num; qp->transport = nt; qp->ntb = nt->ntb; qp->qp_link = NTB_LINK_DOWN; qp->client_ready = NTB_LINK_DOWN; qp->event_handler = NULL; if (nt->max_qps % NTB_NUM_MW && mw_num < nt->max_qps % NTB_NUM_MW) num_qps_mw = nt->max_qps / NTB_NUM_MW + 1; else num_qps_mw = nt->max_qps / NTB_NUM_MW; tx_size = (unsigned int) ntb_get_mw_size(qp->ntb, mw_num) / num_qps_mw; qp->rx_info = (struct ntb_rx_info *) ((char *)ntb_get_mw_vbase(qp->ntb, mw_num) + (qp_num / NTB_NUM_MW * tx_size)); tx_size -= sizeof(struct ntb_rx_info); qp->tx_mw = qp->rx_info + 1; /* Due to house-keeping, there must be at least 2 buffs */ qp->tx_max_frame = min(transport_mtu + sizeof(struct ntb_payload_header), tx_size / 2); qp->tx_max_entry = tx_size / qp->tx_max_frame; callout_init(&qp->link_work, 0); callout_init(&qp->queue_full, 1); callout_init(&qp->rx_full, 1); mtx_init(&qp->ntb_rx_pend_q_lock, "ntb rx pend q", NULL, MTX_SPIN); mtx_init(&qp->ntb_rx_free_q_lock, "ntb rx free q", NULL, MTX_SPIN); mtx_init(&qp->ntb_tx_free_q_lock, "ntb tx free q", NULL, MTX_SPIN); TASK_INIT(&qp->rx_completion_task, 0, ntb_rx_completion_task, qp); STAILQ_INIT(&qp->rx_pend_q); STAILQ_INIT(&qp->rx_free_q); STAILQ_INIT(&qp->tx_free_q); } static void ntb_transport_free_queue(struct ntb_transport_qp *qp) { struct ntb_queue_entry *entry; if (qp == NULL) return; callout_drain(&qp->link_work); ntb_unregister_db_callback(qp->ntb, qp->qp_num); while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q))) free(entry, M_NTB_IF); while ((entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q))) free(entry, M_NTB_IF); while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q))) free(entry, M_NTB_IF); set_bit(qp->qp_num, &qp->transport->qp_bitmap); } /** * ntb_transport_create_queue - Create a new NTB transport layer queue * @rx_handler: receive callback function * @tx_handler: transmit callback function * @event_handler: event callback function * * Create a new NTB transport layer queue and provide the queue with a callback * routine for both transmit and receive. The receive callback routine will be * used to pass up data when the transport has received it on the queue. The * transmit callback routine will be called when the transport has completed the * transmission of the data on the queue and the data is ready to be freed. * * RETURNS: pointer to newly created ntb_queue, NULL on error. */ static struct ntb_transport_qp * ntb_transport_create_queue(void *data, struct ntb_softc *pdev, const struct ntb_queue_handlers *handlers) { struct ntb_queue_entry *entry; struct ntb_transport_qp *qp; struct ntb_netdev *nt; unsigned int free_queue; int rc, i; nt = ntb_find_transport(pdev); if (nt == NULL) goto err; free_queue = ffs(nt->qp_bitmap); if (free_queue == 0) goto err; /* decrement free_queue to make it zero based */ free_queue--; clear_bit(free_queue, &nt->qp_bitmap); qp = &nt->qps[free_queue]; qp->cb_data = data; qp->rx_handler = handlers->rx_handler; qp->tx_handler = handlers->tx_handler; qp->event_handler = handlers->event_handler; for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) { entry = malloc(sizeof(struct ntb_queue_entry), M_NTB_IF, M_WAITOK|M_ZERO); entry->cb_data = nt->ifp; entry->buf = NULL; entry->len = transport_mtu; ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q); } for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) { entry = malloc(sizeof(struct ntb_queue_entry), M_NTB_IF, M_WAITOK|M_ZERO); ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q); } rc = ntb_register_db_callback(qp->ntb, free_queue, qp, ntb_transport_rxc_db); if (rc != 0) goto err1; return (qp); err1: while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q))) free(entry, M_NTB_IF); while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q))) free(entry, M_NTB_IF); set_bit(free_queue, &nt->qp_bitmap); err: return (NULL); } /** * ntb_transport_link_up - Notify NTB transport of client readiness to use queue * @qp: NTB transport layer queue to be enabled * * Notify NTB transport layer of client readiness to use queue */ static void ntb_transport_link_up(struct ntb_transport_qp *qp) { if (qp == NULL) return; qp->client_ready = NTB_LINK_UP; if (bootverbose) device_printf(ntb_get_device(qp->ntb), "qp client ready\n"); if (qp->transport->transport_link == NTB_LINK_UP) callout_reset(&qp->link_work, 0, ntb_qp_link_work, qp); } /* Transport Tx */ /** * ntb_transport_tx_enqueue - Enqueue a new NTB queue entry * @qp: NTB transport layer queue the entry is to be enqueued on * @cb: per buffer pointer for callback function to use * @data: pointer to data buffer that will be sent * @len: length of the data buffer * * Enqueue a new transmit buffer onto the transport queue from which a NTB - * payload will be transmitted. This assumes that a lock is behing held to + * payload will be transmitted. This assumes that a lock is being held to * serialize access to the qp. * * RETURNS: An appropriate ERRNO error value on error, or zero for success. */ static int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, unsigned int len) { struct ntb_queue_entry *entry; int rc; if (qp == NULL || qp->qp_link != NTB_LINK_UP || len == 0) { CTR0(KTR_NTB, "TX: link not up"); return (EINVAL); } entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q); if (entry == NULL) { CTR0(KTR_NTB, "TX: could not get entry from tx_free_q"); return (ENOMEM); } CTR1(KTR_NTB, "TX: got entry %p from tx_free_q", entry); entry->cb_data = cb; entry->buf = data; entry->len = len; entry->flags = 0; rc = ntb_process_tx(qp, entry); if (rc != 0) { ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q); CTR1(KTR_NTB, "TX: process_tx failed. Returning entry %p to tx_free_q", entry); } return (rc); } static int ntb_process_tx(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry) { void *offset; offset = (char *)qp->tx_mw + qp->tx_max_frame * qp->tx_index; CTR3(KTR_NTB, "TX: process_tx: tx_pkts=%u, tx_index=%u, remote entry=%u", qp->tx_pkts, qp->tx_index, qp->remote_rx_info->entry); if (qp->tx_index == qp->remote_rx_info->entry) { CTR0(KTR_NTB, "TX: ring full"); qp->tx_ring_full++; return (EAGAIN); } if (entry->len > qp->tx_max_frame - sizeof(struct ntb_payload_header)) { if (qp->tx_handler != NULL) qp->tx_handler(qp, qp->cb_data, entry->buf, EIO); ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q); CTR1(KTR_NTB, "TX: frame too big. returning entry %p to tx_free_q", entry); return (0); } CTR2(KTR_NTB, "TX: copying entry %p to offset %p", entry, offset); ntb_tx_copy_task(qp, entry, offset); qp->tx_index++; qp->tx_index %= qp->tx_max_entry; qp->tx_pkts++; return (0); } static void ntb_tx_copy_task(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry, void *offset) { struct ntb_payload_header *hdr; CTR2(KTR_NTB, "TX: copying %d bytes to offset %p", entry->len, offset); if (entry->buf != NULL) m_copydata((struct mbuf *)entry->buf, 0, entry->len, offset); hdr = (struct ntb_payload_header *)((char *)offset + qp->tx_max_frame - sizeof(struct ntb_payload_header)); hdr->len = entry->len; /* TODO: replace with bus_space_write */ hdr->ver = qp->tx_pkts; /* TODO: replace with bus_space_write */ wmb(); /* TODO: replace with bus_space_write */ hdr->flags = entry->flags | IF_NTB_DESC_DONE_FLAG; - ntb_ring_sdb(qp->ntb, qp->qp_num); + ntb_ring_doorbell(qp->ntb, qp->qp_num); /* * The entry length can only be zero if the packet is intended to be a * "link down" or similar. Since no payload is being sent in these * cases, there is nothing to add to the completion queue. */ if (entry->len > 0) { qp->tx_bytes += entry->len; if (qp->tx_handler) qp->tx_handler(qp, qp->cb_data, entry->cb_data, entry->len); } CTR2(KTR_NTB, "TX: entry %p sent. hdr->ver = %d, Returning to tx_free_q", entry, hdr->ver); ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q); } static void ntb_qp_full(void *arg) { CTR0(KTR_NTB, "TX: qp_full callout"); ntb_start(arg); } /* Transport Rx */ static void ntb_transport_rxc_db(void *data, int db_num) { struct ntb_transport_qp *qp = data; ntb_transport_rx(qp); } static void ntb_rx_pendq_full(void *arg) { CTR0(KTR_NTB, "RX: ntb_rx_pendq_full callout"); ntb_transport_rx(arg); } static void ntb_transport_rx(struct ntb_transport_qp *qp) { uint64_t i; int rc; /* * Limit the number of packets processed in a single interrupt to * provide fairness to others */ mtx_lock(&qp->transport->rx_lock); CTR0(KTR_NTB, "RX: transport_rx"); for (i = 0; i < qp->rx_max_entry; i++) { rc = ntb_process_rxc(qp); if (rc != 0) { CTR0(KTR_NTB, "RX: process_rxc failed"); break; } } mtx_unlock(&qp->transport->rx_lock); } static int ntb_process_rxc(struct ntb_transport_qp *qp) { struct ntb_payload_header *hdr; struct ntb_queue_entry *entry; void *offset; offset = (void *) ((char *)qp->rx_buff + qp->rx_max_frame * qp->rx_index); hdr = (void *) ((char *)offset + qp->rx_max_frame - sizeof(struct ntb_payload_header)); CTR1(KTR_NTB, "RX: process_rxc rx_index = %u", qp->rx_index); entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q); if (entry == NULL) { qp->rx_err_no_buf++; CTR0(KTR_NTB, "RX: No entries in rx_pend_q"); return (ENOMEM); } callout_stop(&qp->rx_full); CTR1(KTR_NTB, "RX: rx entry %p from rx_pend_q", entry); if ((hdr->flags & IF_NTB_DESC_DONE_FLAG) == 0) { CTR1(KTR_NTB, "RX: hdr not done. Returning entry %p to rx_pend_q", entry); ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q); qp->rx_ring_empty++; return (EAGAIN); } if (hdr->ver != (uint32_t) qp->rx_pkts) { CTR3(KTR_NTB,"RX: ver != rx_pkts (%x != %lx). " "Returning entry %p to rx_pend_q", hdr->ver, qp->rx_pkts, entry); ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q); qp->rx_err_ver++; return (EIO); } if ((hdr->flags & IF_NTB_LINK_DOWN_FLAG) != 0) { ntb_qp_link_down(qp); CTR1(KTR_NTB, "RX: link down. adding entry %p back to rx_pend_q", entry); ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q); goto out; } if (hdr->len <= entry->len) { entry->len = hdr->len; ntb_rx_copy_task(qp, entry, offset); } else { CTR1(KTR_NTB, "RX: len too long. Returning entry %p to rx_pend_q", entry); ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q); qp->rx_err_oflow++; } qp->rx_bytes += hdr->len; qp->rx_pkts++; CTR1(KTR_NTB, "RX: received %ld rx_pkts", qp->rx_pkts); out: /* Ensure that the data is globally visible before clearing the flag */ wmb(); hdr->flags = 0; /* TODO: replace with bus_space_write */ qp->rx_info->entry = qp->rx_index; qp->rx_index++; qp->rx_index %= qp->rx_max_entry; return (0); } static void ntb_rx_copy_task(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry, void *offset) { struct ifnet *ifp = entry->cb_data; unsigned int len = entry->len; struct mbuf *m; CTR2(KTR_NTB, "RX: copying %d bytes from offset %p", len, offset); m = m_devget(offset, len, 0, ifp, NULL); m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID; entry->buf = (void *)m; CTR2(KTR_NTB, "RX: copied entry %p to mbuf %p. Adding entry to rx_free_q", entry, m); ntb_list_add(&qp->ntb_rx_free_q_lock, entry, &qp->rx_free_q); taskqueue_enqueue(taskqueue_swi, &qp->rx_completion_task); } static void ntb_rx_completion_task(void *arg, int pending) { struct ntb_transport_qp *qp = arg; struct mbuf *m; struct ntb_queue_entry *entry; CTR0(KTR_NTB, "RX: rx_completion_task"); while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q))) { m = entry->buf; CTR2(KTR_NTB, "RX: completing entry %p, mbuf %p", entry, m); if (qp->rx_handler && qp->client_ready == NTB_LINK_UP) qp->rx_handler(qp, qp->cb_data, m, entry->len); entry->buf = NULL; entry->len = qp->transport->bufsize; CTR1(KTR_NTB,"RX: entry %p removed from rx_free_q " "and added to rx_pend_q", entry); ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q); if (qp->rx_err_no_buf > qp->last_rx_no_buf) { qp->last_rx_no_buf = qp->rx_err_no_buf; CTR0(KTR_NTB, "RX: could spawn rx task"); callout_reset(&qp->rx_full, hz / 1000, ntb_rx_pendq_full, qp); } } } /* Link Event handler */ static void ntb_transport_event_callback(void *data, enum ntb_hw_event event) { struct ntb_netdev *nt = data; switch (event) { case NTB_EVENT_HW_LINK_UP: if (bootverbose) device_printf(ntb_get_device(nt->ntb), "HW link up\n"); callout_reset(&nt->link_work, 0, ntb_transport_link_work, nt); break; case NTB_EVENT_HW_LINK_DOWN: if (bootverbose) device_printf(ntb_get_device(nt->ntb), "HW link down\n"); ntb_transport_link_cleanup(nt); break; default: panic("ntb: Unknown NTB event"); } } /* Link bring up */ static void ntb_transport_link_work(void *arg) { struct ntb_netdev *nt = arg; struct ntb_softc *ntb = nt->ntb; struct ntb_transport_qp *qp; uint64_t val64; uint32_t val, i, num_mw; int rc; if (ntb_has_feature(ntb, NTB_REGS_THRU_MW)) num_mw = NTB_NUM_MW - 1; else num_mw = NTB_NUM_MW; /* send the local info, in the opposite order of the way we read it */ for (i = 0; i < num_mw; i++) { rc = ntb_write_remote_spad(ntb, IF_NTB_MW0_SZ_HIGH + (i * 2), - ntb_get_mw_size(ntb, i) >> 32); + (uint64_t)ntb_get_mw_size(ntb, i) >> 32); if (rc != 0) goto out; rc = ntb_write_remote_spad(ntb, IF_NTB_MW0_SZ_LOW + (i * 2), (uint32_t)ntb_get_mw_size(ntb, i)); if (rc != 0) goto out; } rc = ntb_write_remote_spad(ntb, IF_NTB_NUM_MWS, num_mw); if (rc != 0) goto out; rc = ntb_write_remote_spad(ntb, IF_NTB_NUM_QPS, nt->max_qps); if (rc != 0) goto out; rc = ntb_write_remote_spad(ntb, IF_NTB_VERSION, NTB_TRANSPORT_VERSION); if (rc != 0) goto out; /* Query the remote side for its info */ rc = ntb_read_local_spad(ntb, IF_NTB_VERSION, &val); if (rc != 0) goto out; if (val != NTB_TRANSPORT_VERSION) goto out; rc = ntb_read_local_spad(ntb, IF_NTB_NUM_QPS, &val); if (rc != 0) goto out; if (val != nt->max_qps) goto out; rc = ntb_read_local_spad(ntb, IF_NTB_NUM_MWS, &val); if (rc != 0) goto out; if (val != num_mw) goto out; for (i = 0; i < num_mw; i++) { rc = ntb_read_local_spad(ntb, IF_NTB_MW0_SZ_HIGH + (i * 2), &val); if (rc != 0) goto free_mws; val64 = (uint64_t)val << 32; rc = ntb_read_local_spad(ntb, IF_NTB_MW0_SZ_LOW + (i * 2), &val); if (rc != 0) goto free_mws; val64 |= val; rc = ntb_set_mw(nt, i, val64); if (rc != 0) goto free_mws; } nt->transport_link = NTB_LINK_UP; if (bootverbose) device_printf(ntb_get_device(ntb), "transport link up\n"); for (i = 0; i < nt->max_qps; i++) { qp = &nt->qps[i]; ntb_transport_setup_qp_mw(nt, i); if (qp->client_ready == NTB_LINK_UP) callout_reset(&qp->link_work, 0, ntb_qp_link_work, qp); } return; free_mws: for (i = 0; i < NTB_NUM_MW; i++) ntb_free_mw(nt, i); out: if (ntb_query_link_status(ntb)) callout_reset(&nt->link_work, NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_transport_link_work, nt); } static int ntb_set_mw(struct ntb_netdev *nt, int num_mw, unsigned int size) { struct ntb_transport_mw *mw = &nt->mw[num_mw]; /* No need to re-setup */ if (mw->size == size) return (0); if (mw->size != 0) ntb_free_mw(nt, num_mw); /* Alloc memory for receiving data. Must be 4k aligned */ mw->size = size; mw->virt_addr = contigmalloc(mw->size, M_NTB_IF, M_ZERO, 0, BUS_SPACE_MAXADDR, mw->size, 0); if (mw->virt_addr == NULL) { mw->size = 0; printf("ntb: Unable to allocate MW buffer of size %d\n", (int)mw->size); return (ENOMEM); } /* TODO: replace with bus_space_* functions */ mw->dma_addr = vtophys(mw->virt_addr); /* Notify HW the memory location of the receive buffer */ ntb_set_mw_addr(nt->ntb, num_mw, mw->dma_addr); return (0); } static void ntb_free_mw(struct ntb_netdev *nt, int num_mw) { struct ntb_transport_mw *mw = &nt->mw[num_mw]; if (mw->virt_addr == NULL) return; contigfree(mw->virt_addr, mw->size, M_NTB_IF); mw->virt_addr = NULL; } static void ntb_transport_setup_qp_mw(struct ntb_netdev *nt, unsigned int qp_num) { struct ntb_transport_qp *qp = &nt->qps[qp_num]; void *offset; unsigned int rx_size, num_qps_mw; uint8_t mw_num = QP_TO_MW(qp_num); unsigned int i; if (nt->max_qps % NTB_NUM_MW && mw_num < nt->max_qps % NTB_NUM_MW) num_qps_mw = nt->max_qps / NTB_NUM_MW + 1; else num_qps_mw = nt->max_qps / NTB_NUM_MW; rx_size = (unsigned int) nt->mw[mw_num].size / num_qps_mw; qp->remote_rx_info = (void *)((uint8_t *)nt->mw[mw_num].virt_addr + (qp_num / NTB_NUM_MW * rx_size)); rx_size -= sizeof(struct ntb_rx_info); qp->rx_buff = qp->remote_rx_info + 1; /* Due to house-keeping, there must be at least 2 buffs */ qp->rx_max_frame = min(transport_mtu + sizeof(struct ntb_payload_header), rx_size / 2); qp->rx_max_entry = rx_size / qp->rx_max_frame; qp->rx_index = 0; qp->remote_rx_info->entry = qp->rx_max_entry - 1; /* setup the hdr offsets with 0's */ for (i = 0; i < qp->rx_max_entry; i++) { offset = (void *)((uint8_t *)qp->rx_buff + qp->rx_max_frame * (i + 1) - sizeof(struct ntb_payload_header)); memset(offset, 0, sizeof(struct ntb_payload_header)); } qp->rx_pkts = 0; qp->tx_pkts = 0; qp->tx_index = 0; } static void ntb_qp_link_work(void *arg) { struct ntb_transport_qp *qp = arg; struct ntb_softc *ntb = qp->ntb; struct ntb_netdev *nt = qp->transport; int rc, val; rc = ntb_read_remote_spad(ntb, IF_NTB_QP_LINKS, &val); if (rc != 0) return; rc = ntb_write_remote_spad(ntb, IF_NTB_QP_LINKS, val | 1 << qp->qp_num); /* query remote spad for qp ready bits */ rc = ntb_read_local_spad(ntb, IF_NTB_QP_LINKS, &val); /* See if the remote side is up */ if ((1 << qp->qp_num & val) != 0) { qp->qp_link = NTB_LINK_UP; if (qp->event_handler != NULL) qp->event_handler(qp->cb_data, NTB_LINK_UP); if (bootverbose) device_printf(ntb_get_device(ntb), "qp link up\n"); } else if (nt->transport_link == NTB_LINK_UP) { callout_reset(&qp->link_work, NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_qp_link_work, qp); } } /* Link down event*/ static void ntb_transport_link_cleanup(struct ntb_netdev *nt) { int i; if (nt->transport_link == NTB_LINK_DOWN) callout_drain(&nt->link_work); else nt->transport_link = NTB_LINK_DOWN; /* Pass along the info to any clients */ for (i = 0; i < nt->max_qps; i++) if (!test_bit(i, &nt->qp_bitmap)) ntb_qp_link_down(&nt->qps[i]); /* * The scratchpad registers keep the values if the remote side * goes down, blast them now to give them a sane value the next * time they are accessed */ for (i = 0; i < IF_NTB_MAX_SPAD; i++) ntb_write_local_spad(nt->ntb, i, 0); } static void ntb_qp_link_down(struct ntb_transport_qp *qp) { ntb_qp_link_cleanup(qp); } static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp) { struct ntb_netdev *nt = qp->transport; if (qp->qp_link == NTB_LINK_DOWN) { callout_drain(&qp->link_work); return; } if (qp->event_handler != NULL) qp->event_handler(qp->cb_data, NTB_LINK_DOWN); qp->qp_link = NTB_LINK_DOWN; if (nt->transport_link == NTB_LINK_UP) callout_reset(&qp->link_work, NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_qp_link_work, qp); } /* Link commanded down */ /** * ntb_transport_link_down - Notify NTB transport to no longer enqueue data * @qp: NTB transport layer queue to be disabled * * Notify NTB transport layer of client's desire to no longer receive data on * transport queue specified. It is the client's responsibility to ensure all - * entries on queue are purged or otherwise handled appropraitely. + * entries on queue are purged or otherwise handled appropriately. */ static void ntb_transport_link_down(struct ntb_transport_qp *qp) { int rc, val; if (qp == NULL) return; qp->client_ready = NTB_LINK_DOWN; rc = ntb_read_remote_spad(qp->ntb, IF_NTB_QP_LINKS, &val); if (rc != 0) return; rc = ntb_write_remote_spad(qp->ntb, IF_NTB_QP_LINKS, val & ~(1 << qp->qp_num)); if (qp->qp_link == NTB_LINK_UP) ntb_send_link_down(qp); else callout_drain(&qp->link_work); } static void ntb_send_link_down(struct ntb_transport_qp *qp) { struct ntb_queue_entry *entry; int i, rc; if (qp->qp_link == NTB_LINK_DOWN) return; qp->qp_link = NTB_LINK_DOWN; for (i = 0; i < NTB_LINK_DOWN_TIMEOUT; i++) { entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q); if (entry != NULL) break; pause("NTB Wait for link down", hz / 10); } if (entry == NULL) return; entry->cb_data = NULL; entry->buf = NULL; entry->len = 0; entry->flags = IF_NTB_LINK_DOWN_FLAG; mtx_lock(&qp->transport->tx_lock); rc = ntb_process_tx(qp, entry); if (rc != 0) printf("ntb: Failed to send link down\n"); mtx_unlock(&qp->transport->tx_lock); } /* List Management */ static void ntb_list_add(struct mtx *lock, struct ntb_queue_entry *entry, struct ntb_queue_list *list) { mtx_lock_spin(lock); STAILQ_INSERT_TAIL(list, entry, entry); mtx_unlock_spin(lock); } static struct ntb_queue_entry * ntb_list_rm(struct mtx *lock, struct ntb_queue_list *list) { struct ntb_queue_entry *entry; mtx_lock_spin(lock); if (STAILQ_EMPTY(list)) { entry = NULL; goto out; } entry = STAILQ_FIRST(list); STAILQ_REMOVE_HEAD(list, entry); out: mtx_unlock_spin(lock); return (entry); } /* Helper functions */ /* TODO: This too should really be part of the kernel */ #define EUI48_MULTICAST 1 << 0 #define EUI48_LOCALLY_ADMINISTERED 1 << 1 static void create_random_local_eui48(u_char *eaddr) { static uint8_t counter = 0; uint32_t seed = ticks; eaddr[0] = EUI48_LOCALLY_ADMINISTERED; memcpy(&eaddr[1], &seed, sizeof(uint32_t)); eaddr[5] = counter++; } /** * ntb_transport_max_size - Query the max payload size of a qp * @qp: NTB transport layer queue to be queried * * Query the maximum payload size permissible on the given qp * * RETURNS: the max payload size of a qp */ static unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp) { if (qp == NULL) return (0); return (qp->tx_max_frame - sizeof(struct ntb_payload_header)); } Index: projects/collation/sys/dev/ntb/ntb_hw/ntb_hw.c =================================================================== --- projects/collation/sys/dev/ntb/ntb_hw/ntb_hw.c (revision 289266) +++ projects/collation/sys/dev/ntb/ntb_hw/ntb_hw.c (revision 289267) @@ -1,1508 +1,1516 @@ /*- * Copyright (C) 2013 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ntb_regs.h" #include "ntb_hw.h" /* * The Non-Transparent Bridge (NTB) is a device on some Intel processors that * allows you to connect two systems using a PCI-e link. * * This module contains the hardware abstraction layer for the NTB. It allows * you to send and recieve interrupts, map the memory windows and send and * receive messages in the scratch-pad registers. * * NOTE: Much of the code in this module is shared with Linux. Any patches may * be picked up and redistributed in Linux with a dual GPL/BSD license. */ #define NTB_CONFIG_BAR 0 #define NTB_B2B_BAR_1 1 #define NTB_B2B_BAR_2 2 #define NTB_MAX_BARS 3 #define NTB_MW_TO_BAR(mw) ((mw) + 1) #define MAX_MSIX_INTERRUPTS MAX(XEON_MAX_DB_BITS, SOC_MAX_DB_BITS) #define NTB_HB_TIMEOUT 1 /* second */ #define SOC_LINK_RECOVERY_TIME 500 #define DEVICE2SOFTC(dev) ((struct ntb_softc *) device_get_softc(dev)) enum ntb_device_type { NTB_XEON, NTB_SOC }; /* Device features and workarounds */ #define HAS_FEATURE(feature) \ ((ntb->features & (feature)) != 0) struct ntb_hw_info { uint32_t device_id; const char *desc; enum ntb_device_type type; uint64_t features; }; struct ntb_pci_bar_info { bus_space_tag_t pci_bus_tag; bus_space_handle_t pci_bus_handle; int pci_resource_id; struct resource *pci_resource; vm_paddr_t pbase; void *vbase; u_long size; }; struct ntb_int_info { struct resource *res; int rid; void *tag; }; struct ntb_db_cb { ntb_db_callback callback; unsigned int db_num; void *data; struct ntb_softc *ntb; }; struct ntb_softc { device_t device; enum ntb_device_type type; uint64_t features; struct ntb_pci_bar_info bar_info[NTB_MAX_BARS]; struct ntb_int_info int_info[MAX_MSIX_INTERRUPTS]; uint32_t allocated_interrupts; struct callout heartbeat_timer; struct callout lr_timer; void *ntb_transport; ntb_event_callback event_cb; struct ntb_db_cb *db_cb; struct { uint8_t max_spads; uint8_t max_db_bits; uint8_t msix_cnt; } limits; struct { - uint32_t pdb; - uint32_t pdb_mask; - uint32_t sdb; - uint32_t sbar2_xlat; - uint32_t sbar4_xlat; + uint32_t ldb; + uint32_t ldb_mask; + uint32_t rdb; + uint32_t bar2_xlat; + uint32_t bar4_xlat; uint32_t spad_remote; uint32_t spad_local; uint32_t lnk_cntl; uint32_t lnk_stat; uint32_t spci_cmd; } reg_ofs; uint8_t conn_type; uint8_t dev_type; uint8_t bits_per_vector; uint8_t link_status; uint8_t link_width; uint8_t link_speed; }; #ifdef __i386__ static __inline uint64_t bus_space_read_8(bus_space_tag_t tag, bus_space_handle_t handle, bus_size_t offset) { return (bus_space_read_4(tag, handle, offset) | ((uint64_t)bus_space_read_4(tag, handle, offset + 4)) << 32); } static __inline void bus_space_write_8(bus_space_tag_t tag, bus_space_handle_t handle, bus_size_t offset, uint64_t val) { bus_space_write_4(tag, handle, offset, val); bus_space_write_4(tag, handle, offset + 4, val >> 32); } #endif #define ntb_bar_read(SIZE, bar, offset) \ bus_space_read_ ## SIZE (ntb->bar_info[(bar)].pci_bus_tag, \ ntb->bar_info[(bar)].pci_bus_handle, (offset)) #define ntb_bar_write(SIZE, bar, offset, val) \ bus_space_write_ ## SIZE (ntb->bar_info[(bar)].pci_bus_tag, \ ntb->bar_info[(bar)].pci_bus_handle, (offset), (val)) #define ntb_reg_read(SIZE, offset) ntb_bar_read(SIZE, NTB_CONFIG_BAR, offset) #define ntb_reg_write(SIZE, offset, val) \ ntb_bar_write(SIZE, NTB_CONFIG_BAR, offset, val) #define ntb_mw_read(SIZE, offset) ntb_bar_read(SIZE, NTB_B2B_BAR_2, offset) #define ntb_mw_write(SIZE, offset, val) \ ntb_bar_write(SIZE, NTB_B2B_BAR_2, offset, val) typedef int (*bar_map_strategy)(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar); static int ntb_probe(device_t device); static int ntb_attach(device_t device); static int ntb_detach(device_t device); static int ntb_map_pci_bars(struct ntb_softc *ntb); static int map_pci_bar(struct ntb_softc *ntb, bar_map_strategy strategy, struct ntb_pci_bar_info *bar); static int map_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar); static int map_memory_window_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar); static void ntb_unmap_pci_bar(struct ntb_softc *ntb); static int ntb_setup_interrupts(struct ntb_softc *ntb); static void ntb_teardown_interrupts(struct ntb_softc *ntb); static void handle_soc_irq(void *arg); static void handle_xeon_irq(void *arg); static void handle_xeon_event_irq(void *arg); static void ntb_handle_legacy_interrupt(void *arg); static int ntb_create_callbacks(struct ntb_softc *ntb, int num_vectors); static void ntb_free_callbacks(struct ntb_softc *ntb); static struct ntb_hw_info *ntb_get_device_info(uint32_t device_id); static int ntb_initialize_hw(struct ntb_softc *ntb); static int ntb_setup_xeon(struct ntb_softc *ntb); static int ntb_setup_soc(struct ntb_softc *ntb); static void configure_soc_secondary_side_bars(struct ntb_softc *ntb); static void configure_xeon_secondary_side_bars(struct ntb_softc *ntb); static void ntb_handle_heartbeat(void *arg); static void ntb_handle_link_event(struct ntb_softc *ntb, int link_state); static void recover_soc_link(void *arg); static int ntb_check_link_status(struct ntb_softc *ntb); static void save_bar_parameters(struct ntb_pci_bar_info *bar); static struct ntb_hw_info pci_ids[] = { { 0x0C4E8086, "Atom Processor S1200 NTB Primary B2B", NTB_SOC, 0 }, /* XXX: PS/SS IDs left out until they are supported. */ { 0x37258086, "JSF Xeon C35xx/C55xx Non-Transparent Bridge B2B", NTB_XEON, NTB_REGS_THRU_MW | NTB_B2BDOORBELL_BIT14 }, { 0x3C0D8086, "SNB Xeon E5/Core i7 Non-Transparent Bridge B2B", NTB_XEON, NTB_REGS_THRU_MW | NTB_B2BDOORBELL_BIT14 }, { 0x0E0D8086, "IVT Xeon E5 V2 Non-Transparent Bridge B2B", NTB_XEON, NTB_REGS_THRU_MW | NTB_B2BDOORBELL_BIT14 | NTB_SB01BASE_LOCKUP | NTB_BAR_SIZE_4K }, { 0x2F0D8086, "HSX Xeon E5 V3 Non-Transparent Bridge B2B", NTB_XEON, NTB_REGS_THRU_MW | NTB_B2BDOORBELL_BIT14 | NTB_SB01BASE_LOCKUP }, { 0x6F0D8086, "BDX Xeon E5 V4 Non-Transparent Bridge B2B", NTB_XEON, NTB_REGS_THRU_MW | NTB_B2BDOORBELL_BIT14 | NTB_SB01BASE_LOCKUP }, { 0x00000000, NULL, NTB_SOC, 0 } }; /* * OS <-> Driver interface structures */ MALLOC_DEFINE(M_NTB, "ntb_hw", "ntb_hw driver memory allocations"); static device_method_t ntb_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ntb_probe), DEVMETHOD(device_attach, ntb_attach), DEVMETHOD(device_detach, ntb_detach), DEVMETHOD_END }; static driver_t ntb_pci_driver = { "ntb_hw", ntb_pci_methods, sizeof(struct ntb_softc), }; static devclass_t ntb_devclass; DRIVER_MODULE(ntb_hw, pci, ntb_pci_driver, ntb_devclass, NULL, NULL); MODULE_VERSION(ntb_hw, 1); SYSCTL_NODE(_hw, OID_AUTO, ntb, CTLFLAG_RW, 0, "NTB sysctls"); /* * OS <-> Driver linkage functions */ static int ntb_probe(device_t device) { struct ntb_hw_info *p; p = ntb_get_device_info(pci_get_devid(device)); if (p == NULL) return (ENXIO); device_set_desc(device, p->desc); return (0); } static int ntb_attach(device_t device) { struct ntb_softc *ntb; struct ntb_hw_info *p; int error; ntb = DEVICE2SOFTC(device); p = ntb_get_device_info(pci_get_devid(device)); ntb->device = device; ntb->type = p->type; ntb->features = p->features; /* Heartbeat timer for NTB_SOC since there is no link interrupt */ callout_init(&ntb->heartbeat_timer, 1); callout_init(&ntb->lr_timer, 1); error = ntb_map_pci_bars(ntb); if (error) goto out; error = ntb_initialize_hw(ntb); if (error) goto out; error = ntb_setup_interrupts(ntb); if (error) goto out; pci_enable_busmaster(ntb->device); out: if (error != 0) ntb_detach(device); return (error); } static int ntb_detach(device_t device) { struct ntb_softc *ntb; ntb = DEVICE2SOFTC(device); callout_drain(&ntb->heartbeat_timer); callout_drain(&ntb->lr_timer); ntb_teardown_interrupts(ntb); ntb_unmap_pci_bar(ntb); return (0); } static int ntb_map_pci_bars(struct ntb_softc *ntb) { int rc; ntb->bar_info[NTB_CONFIG_BAR].pci_resource_id = PCIR_BAR(0); rc = map_pci_bar(ntb, map_mmr_bar, &ntb->bar_info[NTB_CONFIG_BAR]); if (rc != 0) return (rc); ntb->bar_info[NTB_B2B_BAR_1].pci_resource_id = PCIR_BAR(2); rc = map_pci_bar(ntb, map_memory_window_bar, &ntb->bar_info[NTB_B2B_BAR_1]); if (rc != 0) return (rc); ntb->bar_info[NTB_B2B_BAR_2].pci_resource_id = PCIR_BAR(4); if (HAS_FEATURE(NTB_REGS_THRU_MW)) rc = map_pci_bar(ntb, map_mmr_bar, &ntb->bar_info[NTB_B2B_BAR_2]); else rc = map_pci_bar(ntb, map_memory_window_bar, &ntb->bar_info[NTB_B2B_BAR_2]); return (rc); } static int map_pci_bar(struct ntb_softc *ntb, bar_map_strategy strategy, struct ntb_pci_bar_info *bar) { int rc; rc = strategy(ntb, bar); if (rc != 0) device_printf(ntb->device, "unable to allocate pci resource\n"); else device_printf(ntb->device, "Bar size = %lx, v %p, p %p\n", bar->size, bar->vbase, (void *)(bar->pbase)); return (rc); } static int map_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar) { bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY, &bar->pci_resource_id, RF_ACTIVE); if (bar->pci_resource == NULL) return (ENXIO); save_bar_parameters(bar); return (0); } static int map_memory_window_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar) { int rc; uint8_t bar_size_bits = 0; bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY, &bar->pci_resource_id, RF_ACTIVE); if (bar->pci_resource == NULL) return (ENXIO); save_bar_parameters(bar); /* * Ivytown NTB BAR sizes are misreported by the hardware due to a * hardware issue. To work around this, query the size it should be * configured to by the device and modify the resource to correspond to * this new size. The BIOS on systems with this problem is required to * provide enough address space to allow the driver to make this change * safely. * * Ideally I could have just specified the size when I allocated the * resource like: * bus_alloc_resource(ntb->device, * SYS_RES_MEMORY, &bar->pci_resource_id, 0ul, ~0ul, * 1ul << bar_size_bits, RF_ACTIVE); * but the PCI driver does not honor the size in this call, so we have * to modify it after the fact. */ if (HAS_FEATURE(NTB_BAR_SIZE_4K)) { if (bar->pci_resource_id == PCIR_BAR(2)) bar_size_bits = pci_read_config(ntb->device, XEON_PBAR23SZ_OFFSET, 1); else bar_size_bits = pci_read_config(ntb->device, XEON_PBAR45SZ_OFFSET, 1); rc = bus_adjust_resource(ntb->device, SYS_RES_MEMORY, bar->pci_resource, bar->pbase, bar->pbase + (1ul << bar_size_bits) - 1); if (rc != 0) { device_printf(ntb->device, "unable to resize bar\n"); return (rc); } save_bar_parameters(bar); } /* Mark bar region as write combining to improve performance. */ rc = pmap_change_attr((vm_offset_t)bar->vbase, bar->size, VM_MEMATTR_WRITE_COMBINING); if (rc != 0) { device_printf(ntb->device, "unable to mark bar as WRITE_COMBINING\n"); return (rc); } return (0); } static void ntb_unmap_pci_bar(struct ntb_softc *ntb) { struct ntb_pci_bar_info *current_bar; int i; for (i = 0; i< NTB_MAX_BARS; i++) { current_bar = &ntb->bar_info[i]; if (current_bar->pci_resource != NULL) bus_release_resource(ntb->device, SYS_RES_MEMORY, current_bar->pci_resource_id, current_bar->pci_resource); } } static int ntb_setup_interrupts(struct ntb_softc *ntb) { void (*interrupt_handler)(void *); void *int_arg; bool use_msix = false; uint32_t num_vectors; int i; ntb->allocated_interrupts = 0; /* * On SOC, disable all interrupts. On XEON, disable all but Link * Interrupt. The rest will be unmasked as callbacks are registered. */ if (ntb->type == NTB_SOC) - ntb_reg_write(8, ntb->reg_ofs.pdb_mask, ~0); + ntb_reg_write(8, ntb->reg_ofs.ldb_mask, ~0); else - ntb_reg_write(2, ntb->reg_ofs.pdb_mask, + ntb_reg_write(2, ntb->reg_ofs.ldb_mask, ~(1 << ntb->limits.max_db_bits)); num_vectors = MIN(pci_msix_count(ntb->device), ntb->limits.max_db_bits); if (num_vectors >= 1) { pci_alloc_msix(ntb->device, &num_vectors); if (num_vectors >= 4) use_msix = true; } ntb_create_callbacks(ntb, num_vectors); if (use_msix == true) { for (i = 0; i < num_vectors; i++) { ntb->int_info[i].rid = i + 1; ntb->int_info[i].res = bus_alloc_resource_any( ntb->device, SYS_RES_IRQ, &ntb->int_info[i].rid, RF_ACTIVE); if (ntb->int_info[i].res == NULL) { device_printf(ntb->device, "bus_alloc_resource failed\n"); return (ENOMEM); } ntb->int_info[i].tag = NULL; ntb->allocated_interrupts++; if (ntb->type == NTB_SOC) { interrupt_handler = handle_soc_irq; int_arg = &ntb->db_cb[i]; } else { if (i == num_vectors - 1) { interrupt_handler = handle_xeon_event_irq; int_arg = ntb; } else { interrupt_handler = handle_xeon_irq; int_arg = &ntb->db_cb[i]; } } if (bus_setup_intr(ntb->device, ntb->int_info[i].res, INTR_MPSAFE | INTR_TYPE_MISC, NULL, interrupt_handler, int_arg, &ntb->int_info[i].tag) != 0) { device_printf(ntb->device, "bus_setup_intr failed\n"); return (ENXIO); } } } else { ntb->int_info[0].rid = 0; ntb->int_info[0].res = bus_alloc_resource_any(ntb->device, SYS_RES_IRQ, &ntb->int_info[0].rid, RF_SHAREABLE|RF_ACTIVE); interrupt_handler = ntb_handle_legacy_interrupt; if (ntb->int_info[0].res == NULL) { device_printf(ntb->device, "bus_alloc_resource failed\n"); return (ENOMEM); } ntb->int_info[0].tag = NULL; ntb->allocated_interrupts = 1; if (bus_setup_intr(ntb->device, ntb->int_info[0].res, INTR_MPSAFE | INTR_TYPE_MISC, NULL, interrupt_handler, ntb, &ntb->int_info[0].tag) != 0) { device_printf(ntb->device, "bus_setup_intr failed\n"); return (ENXIO); } } return (0); } static void ntb_teardown_interrupts(struct ntb_softc *ntb) { struct ntb_int_info *current_int; int i; for (i = 0; i < ntb->allocated_interrupts; i++) { current_int = &ntb->int_info[i]; if (current_int->tag != NULL) bus_teardown_intr(ntb->device, current_int->res, current_int->tag); if (current_int->res != NULL) bus_release_resource(ntb->device, SYS_RES_IRQ, rman_get_rid(current_int->res), current_int->res); } ntb_free_callbacks(ntb); pci_release_msi(ntb->device); } static void handle_soc_irq(void *arg) { struct ntb_db_cb *db_cb = arg; struct ntb_softc *ntb = db_cb->ntb; - ntb_reg_write(8, ntb->reg_ofs.pdb, (uint64_t) 1 << db_cb->db_num); + ntb_reg_write(8, ntb->reg_ofs.ldb, (uint64_t) 1 << db_cb->db_num); if (db_cb->callback != NULL) db_cb->callback(db_cb->data, db_cb->db_num); } static void handle_xeon_irq(void *arg) { struct ntb_db_cb *db_cb = arg; struct ntb_softc *ntb = db_cb->ntb; /* * On Xeon, there are 16 bits in the interrupt register * but only 4 vectors. So, 5 bits are assigned to the first 3 * vectors, with the 4th having a single bit for link * interrupts. */ - ntb_reg_write(2, ntb->reg_ofs.pdb, + ntb_reg_write(2, ntb->reg_ofs.ldb, ((1 << ntb->bits_per_vector) - 1) << (db_cb->db_num * ntb->bits_per_vector)); if (db_cb->callback != NULL) db_cb->callback(db_cb->data, db_cb->db_num); } /* Since we do not have a HW doorbell in SOC, this is only used in JF/JT */ static void handle_xeon_event_irq(void *arg) { struct ntb_softc *ntb = arg; int rc; rc = ntb_check_link_status(ntb); if (rc != 0) device_printf(ntb->device, "Error determining link status\n"); /* bit 15 is always the link bit */ - ntb_reg_write(2, ntb->reg_ofs.pdb, 1 << ntb->limits.max_db_bits); + ntb_reg_write(2, ntb->reg_ofs.ldb, 1 << ntb->limits.max_db_bits); } static void ntb_handle_legacy_interrupt(void *arg) { struct ntb_softc *ntb = arg; unsigned int i = 0; - uint64_t pdb64; - uint16_t pdb16; + uint64_t ldb64; + uint16_t ldb16; if (ntb->type == NTB_SOC) { - pdb64 = ntb_reg_read(8, ntb->reg_ofs.pdb); + ldb64 = ntb_reg_read(8, ntb->reg_ofs.ldb); - while (pdb64) { - i = ffs(pdb64); - pdb64 &= pdb64 - 1; + while (ldb64) { + i = ffs(ldb64); + ldb64 &= ldb64 - 1; handle_soc_irq(&ntb->db_cb[i]); } } else { - pdb16 = ntb_reg_read(2, ntb->reg_ofs.pdb); + ldb16 = ntb_reg_read(2, ntb->reg_ofs.ldb); - if ((pdb16 & XEON_DB_HW_LINK) != 0) { + if ((ldb16 & XEON_DB_HW_LINK) != 0) { handle_xeon_event_irq(ntb); - pdb16 &= ~XEON_DB_HW_LINK; + ldb16 &= ~XEON_DB_HW_LINK; } - while (pdb16 != 0) { - i = ffs(pdb16); - pdb16 &= pdb16 - 1; + while (ldb16 != 0) { + i = ffs(ldb16); + ldb16 &= ldb16 - 1; handle_xeon_irq(&ntb->db_cb[i]); } } } static int ntb_create_callbacks(struct ntb_softc *ntb, int num_vectors) { int i; ntb->db_cb = malloc(num_vectors * sizeof(*ntb->db_cb), M_NTB, M_ZERO | M_WAITOK); for (i = 0; i < num_vectors; i++) { ntb->db_cb[i].db_num = i; ntb->db_cb[i].ntb = ntb; } return (0); } static void ntb_free_callbacks(struct ntb_softc *ntb) { int i; for (i = 0; i < ntb->limits.max_db_bits; i++) ntb_unregister_db_callback(ntb, i); free(ntb->db_cb, M_NTB); } static struct ntb_hw_info * ntb_get_device_info(uint32_t device_id) { struct ntb_hw_info *ep = pci_ids; while (ep->device_id) { if (ep->device_id == device_id) return (ep); ++ep; } return (NULL); } static int ntb_initialize_hw(struct ntb_softc *ntb) { if (ntb->type == NTB_SOC) return (ntb_setup_soc(ntb)); else return (ntb_setup_xeon(ntb)); } static int ntb_setup_xeon(struct ntb_softc *ntb) { uint8_t val, connection_type; val = pci_read_config(ntb->device, NTB_PPD_OFFSET, 1); connection_type = val & XEON_PPD_CONN_TYPE; + + if ((val & XEON_PPD_DEV_TYPE) != 0) + ntb->dev_type = NTB_DEV_USD; + else + ntb->dev_type = NTB_DEV_DSD; + + ntb->reg_ofs.ldb = XEON_PDOORBELL_OFFSET; + ntb->reg_ofs.ldb_mask = XEON_PDBMSK_OFFSET; + ntb->reg_ofs.spad_local = XEON_SPAD_OFFSET; + ntb->reg_ofs.bar2_xlat = XEON_SBAR2XLAT_OFFSET; + ntb->reg_ofs.bar4_xlat = XEON_SBAR4XLAT_OFFSET; + switch (connection_type) { case NTB_CONN_B2B: ntb->conn_type = NTB_CONN_B2B; + + /* + * reg_ofs.rdb and reg_ofs.spad_remote are effectively ignored + * with the NTB_REGS_THRU_MW errata mode enabled. (See + * ntb_ring_doorbell() and ntb_read/write_remote_spad().) + */ + ntb->reg_ofs.rdb = XEON_B2B_DOORBELL_OFFSET; + ntb->reg_ofs.spad_remote = XEON_B2B_SPAD_OFFSET; + + ntb->limits.max_spads = XEON_MAX_SPADS; break; - case NTB_CONN_CLASSIC: + case NTB_CONN_RP: + /* + * Every Xeon today needs NTB_REGS_THRU_MW, so punt on RP for + * now. + */ + KASSERT(HAS_FEATURE(NTB_REGS_THRU_MW), + ("Xeon without MW errata unimplemented")); + device_printf(ntb->device, + "NTB-RP disabled to due hardware errata.\n"); + return (ENXIO); + + case NTB_CONN_TRANSPARENT: default: device_printf(ntb->device, "Connection type %d not supported\n", connection_type); return (ENXIO); } - if ((val & XEON_PPD_DEV_TYPE) != 0) - ntb->dev_type = NTB_DEV_USD; - else - ntb->dev_type = NTB_DEV_DSD; - - ntb->reg_ofs.pdb = XEON_PDOORBELL_OFFSET; - ntb->reg_ofs.pdb_mask = XEON_PDBMSK_OFFSET; - ntb->reg_ofs.sbar2_xlat = XEON_SBAR2XLAT_OFFSET; - ntb->reg_ofs.sbar4_xlat = XEON_SBAR4XLAT_OFFSET; - ntb->reg_ofs.lnk_cntl = XEON_NTBCNTL_OFFSET; - ntb->reg_ofs.lnk_stat = XEON_LINK_STATUS_OFFSET; - ntb->reg_ofs.spad_local = XEON_SPAD_OFFSET; - ntb->reg_ofs.spci_cmd = XEON_PCICMD_OFFSET; - /* * There is a Xeon hardware errata related to writes to SDOORBELL or * B2BDOORBELL in conjunction with inbound access to NTB MMIO space, * which may hang the system. To workaround this use the second memory * window to access the interrupt and scratch pad registers on the * remote system. */ if (HAS_FEATURE(NTB_REGS_THRU_MW)) /* * Set the Limit register to 4k, the minimum size, to prevent * an illegal access. */ ntb_reg_write(8, XEON_PBAR4LMT_OFFSET, ntb_get_mw_size(ntb, 1) + 0x1000); else /* * Disable the limit register, just in case it is set to * something silly. */ ntb_reg_write(8, XEON_PBAR4LMT_OFFSET, 0); - if (ntb->conn_type == NTB_CONN_B2B) { - ntb->reg_ofs.sdb = XEON_B2B_DOORBELL_OFFSET; - ntb->reg_ofs.spad_remote = XEON_B2B_SPAD_OFFSET; - ntb->limits.max_spads = XEON_MAX_SPADS; - } else { - ntb->reg_ofs.sdb = XEON_SDOORBELL_OFFSET; - ntb->reg_ofs.spad_remote = XEON_SPAD_OFFSET; - ntb->limits.max_spads = XEON_MAX_COMPAT_SPADS; - } + ntb->reg_ofs.lnk_cntl = XEON_NTBCNTL_OFFSET; + ntb->reg_ofs.lnk_stat = XEON_LINK_STATUS_OFFSET; + ntb->reg_ofs.spci_cmd = XEON_PCICMD_OFFSET; - ntb->limits.max_db_bits = XEON_MAX_DB_BITS; + ntb->limits.max_db_bits = XEON_MAX_DB_BITS; ntb->limits.msix_cnt = XEON_MSIX_CNT; ntb->bits_per_vector = XEON_DB_BITS_PER_VEC; configure_xeon_secondary_side_bars(ntb); /* Enable Bus Master and Memory Space on the secondary side */ - ntb_reg_write(2, ntb->reg_ofs.spci_cmd, - PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); + if (ntb->conn_type == NTB_CONN_B2B) + ntb_reg_write(2, ntb->reg_ofs.spci_cmd, + PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); /* Enable link training */ ntb_reg_write(4, ntb->reg_ofs.lnk_cntl, NTB_CNTL_BAR23_SNOOP | NTB_CNTL_BAR45_SNOOP); return (0); } static int ntb_setup_soc(struct ntb_softc *ntb) { uint32_t val, connection_type; val = pci_read_config(ntb->device, NTB_PPD_OFFSET, 4); connection_type = (val & SOC_PPD_CONN_TYPE) >> 8; switch (connection_type) { case NTB_CONN_B2B: ntb->conn_type = NTB_CONN_B2B; break; - case NTB_CONN_RP: default: - device_printf(ntb->device, "Connection type %d not supported\n", - connection_type); + device_printf(ntb->device, + "Unsupported NTB configuration (%d)\n", connection_type); return (ENXIO); } if ((val & SOC_PPD_DEV_TYPE) != 0) ntb->dev_type = NTB_DEV_DSD; else ntb->dev_type = NTB_DEV_USD; /* Initiate PCI-E link training */ pci_write_config(ntb->device, NTB_PPD_OFFSET, val | SOC_PPD_INIT_LINK, 4); - ntb->reg_ofs.pdb = SOC_PDOORBELL_OFFSET; - ntb->reg_ofs.pdb_mask = SOC_PDBMSK_OFFSET; - ntb->reg_ofs.sbar2_xlat = SOC_SBAR2XLAT_OFFSET; - ntb->reg_ofs.sbar4_xlat = SOC_SBAR4XLAT_OFFSET; + ntb->reg_ofs.ldb = SOC_PDOORBELL_OFFSET; + ntb->reg_ofs.ldb_mask = SOC_PDBMSK_OFFSET; + ntb->reg_ofs.rdb = SOC_B2B_DOORBELL_OFFSET; + ntb->reg_ofs.bar2_xlat = SOC_SBAR2XLAT_OFFSET; + ntb->reg_ofs.bar4_xlat = SOC_SBAR4XLAT_OFFSET; ntb->reg_ofs.lnk_cntl = SOC_NTBCNTL_OFFSET; ntb->reg_ofs.lnk_stat = SOC_LINK_STATUS_OFFSET; ntb->reg_ofs.spad_local = SOC_SPAD_OFFSET; + ntb->reg_ofs.spad_remote = SOC_B2B_SPAD_OFFSET; ntb->reg_ofs.spci_cmd = SOC_PCICMD_OFFSET; - if (ntb->conn_type == NTB_CONN_B2B) { - ntb->reg_ofs.sdb = SOC_B2B_DOORBELL_OFFSET; - ntb->reg_ofs.spad_remote = SOC_B2B_SPAD_OFFSET; - ntb->limits.max_spads = SOC_MAX_SPADS; - } else { - ntb->reg_ofs.sdb = SOC_PDOORBELL_OFFSET; - ntb->reg_ofs.spad_remote = SOC_SPAD_OFFSET; - ntb->limits.max_spads = SOC_MAX_COMPAT_SPADS; - } - - ntb->limits.max_db_bits = SOC_MAX_DB_BITS; + ntb->limits.max_spads = SOC_MAX_SPADS; + ntb->limits.max_db_bits = SOC_MAX_DB_BITS; ntb->limits.msix_cnt = SOC_MSIX_CNT; ntb->bits_per_vector = SOC_DB_BITS_PER_VEC; /* * FIXME - MSI-X bug on early SOC HW, remove once internal issue is * resolved. Mask transaction layer internal parity errors. */ pci_write_config(ntb->device, 0xFC, 0x4, 4); configure_soc_secondary_side_bars(ntb); /* Enable Bus Master and Memory Space on the secondary side */ ntb_reg_write(2, ntb->reg_ofs.spci_cmd, PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); callout_reset(&ntb->heartbeat_timer, 0, ntb_handle_heartbeat, ntb); return (0); } static void configure_soc_secondary_side_bars(struct ntb_softc *ntb) { if (ntb->dev_type == NTB_DEV_USD) { ntb_reg_write(8, SOC_PBAR2XLAT_OFFSET, PBAR2XLAT_USD_ADDR); ntb_reg_write(8, SOC_PBAR4XLAT_OFFSET, PBAR4XLAT_USD_ADDR); ntb_reg_write(8, SOC_MBAR23_OFFSET, MBAR23_USD_ADDR); ntb_reg_write(8, SOC_MBAR45_OFFSET, MBAR45_USD_ADDR); } else { ntb_reg_write(8, SOC_PBAR2XLAT_OFFSET, PBAR2XLAT_DSD_ADDR); ntb_reg_write(8, SOC_PBAR4XLAT_OFFSET, PBAR4XLAT_DSD_ADDR); ntb_reg_write(8, SOC_MBAR23_OFFSET, MBAR23_DSD_ADDR); ntb_reg_write(8, SOC_MBAR45_OFFSET, MBAR45_DSD_ADDR); } } static void configure_xeon_secondary_side_bars(struct ntb_softc *ntb) { if (ntb->dev_type == NTB_DEV_USD) { ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET, PBAR2XLAT_USD_ADDR); if (HAS_FEATURE(NTB_REGS_THRU_MW)) ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, MBAR01_DSD_ADDR); else { ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, PBAR4XLAT_USD_ADDR); /* * B2B_XLAT_OFFSET is a 64-bit register but can only be * written 32 bits at a time. */ ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL, MBAR01_DSD_ADDR & 0xffffffff); ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU, MBAR01_DSD_ADDR >> 32); } ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, MBAR01_USD_ADDR); ntb_reg_write(8, XEON_SBAR2BASE_OFFSET, MBAR23_USD_ADDR); ntb_reg_write(8, XEON_SBAR4BASE_OFFSET, MBAR45_USD_ADDR); } else { ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET, PBAR2XLAT_DSD_ADDR); if (HAS_FEATURE(NTB_REGS_THRU_MW)) ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, MBAR01_USD_ADDR); else { ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET, PBAR4XLAT_DSD_ADDR); /* * B2B_XLAT_OFFSET is a 64-bit register but can only be * written 32 bits at a time. */ ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL, MBAR01_USD_ADDR & 0xffffffff); ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU, MBAR01_USD_ADDR >> 32); } ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, MBAR01_DSD_ADDR); ntb_reg_write(8, XEON_SBAR2BASE_OFFSET, MBAR23_DSD_ADDR); ntb_reg_write(8, XEON_SBAR4BASE_OFFSET, MBAR45_DSD_ADDR); } } /* SOC does not have link status interrupt, poll on that platform */ static void ntb_handle_heartbeat(void *arg) { struct ntb_softc *ntb = arg; uint32_t status32; int rc; rc = ntb_check_link_status(ntb); if (rc != 0) device_printf(ntb->device, "Error determining link status\n"); /* Check to see if a link error is the cause of the link down */ if (ntb->link_status == NTB_LINK_DOWN) { status32 = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET); if ((status32 & SOC_LTSSMSTATEJMP_FORCEDETECT) != 0) { callout_reset(&ntb->lr_timer, 0, recover_soc_link, ntb); return; } } callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, ntb_handle_heartbeat, ntb); } static void soc_perform_link_restart(struct ntb_softc *ntb) { uint32_t status; /* Driver resets the NTB ModPhy lanes - magic! */ ntb_reg_write(1, SOC_MODPHY_PCSREG6, 0xe0); ntb_reg_write(1, SOC_MODPHY_PCSREG4, 0x40); ntb_reg_write(1, SOC_MODPHY_PCSREG4, 0x60); ntb_reg_write(1, SOC_MODPHY_PCSREG6, 0x60); /* Driver waits 100ms to allow the NTB ModPhy to settle */ pause("ModPhy", hz / 10); /* Clear AER Errors, write to clear */ status = ntb_reg_read(4, SOC_ERRCORSTS_OFFSET); status &= PCIM_AER_COR_REPLAY_ROLLOVER; ntb_reg_write(4, SOC_ERRCORSTS_OFFSET, status); /* Clear unexpected electrical idle event in LTSSM, write to clear */ status = ntb_reg_read(4, SOC_LTSSMERRSTS0_OFFSET); status |= SOC_LTSSMERRSTS0_UNEXPECTEDEI; ntb_reg_write(4, SOC_LTSSMERRSTS0_OFFSET, status); /* Clear DeSkew Buffer error, write to clear */ status = ntb_reg_read(4, SOC_DESKEWSTS_OFFSET); status |= SOC_DESKEWSTS_DBERR; ntb_reg_write(4, SOC_DESKEWSTS_OFFSET, status); status = ntb_reg_read(4, SOC_IBSTERRRCRVSTS0_OFFSET); status &= SOC_IBIST_ERR_OFLOW; ntb_reg_write(4, SOC_IBSTERRRCRVSTS0_OFFSET, status); /* Releases the NTB state machine to allow the link to retrain */ status = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET); status &= ~SOC_LTSSMSTATEJMP_FORCEDETECT; ntb_reg_write(4, SOC_LTSSMSTATEJMP_OFFSET, status); } static void ntb_handle_link_event(struct ntb_softc *ntb, int link_state) { enum ntb_hw_event event; uint16_t status; if (ntb->link_status == link_state) return; if (link_state == NTB_LINK_UP) { device_printf(ntb->device, "Link Up\n"); ntb->link_status = NTB_LINK_UP; event = NTB_EVENT_HW_LINK_UP; - if (ntb->type == NTB_SOC) + if (ntb->type == NTB_SOC || + ntb->conn_type == NTB_CONN_TRANSPARENT) status = ntb_reg_read(2, ntb->reg_ofs.lnk_stat); else status = pci_read_config(ntb->device, XEON_LINK_STATUS_OFFSET, 2); ntb->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4; ntb->link_speed = (status & NTB_LINK_SPEED_MASK); device_printf(ntb->device, "Link Width %d, Link Speed %d\n", ntb->link_width, ntb->link_speed); callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, ntb_handle_heartbeat, ntb); } else { device_printf(ntb->device, "Link Down\n"); ntb->link_status = NTB_LINK_DOWN; event = NTB_EVENT_HW_LINK_DOWN; /* Do not modify link width/speed, we need it in link recovery */ } /* notify the upper layer if we have an event change */ if (ntb->event_cb != NULL) ntb->event_cb(ntb->ntb_transport, event); } static void recover_soc_link(void *arg) { struct ntb_softc *ntb = arg; uint8_t speed, width; uint32_t status32; uint16_t status16; soc_perform_link_restart(ntb); /* * There is a potential race between the 2 NTB devices recovering at * the same time. If the times are the same, the link will not recover * and the driver will be stuck in this loop forever. Add a random * interval to the recovery time to prevent this race. */ status32 = arc4random() % SOC_LINK_RECOVERY_TIME; pause("Link", (SOC_LINK_RECOVERY_TIME + status32) * hz / 1000); status32 = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET); if ((status32 & SOC_LTSSMSTATEJMP_FORCEDETECT) != 0) goto retry; status32 = ntb_reg_read(4, SOC_IBSTERRRCRVSTS0_OFFSET); if ((status32 & SOC_IBIST_ERR_OFLOW) != 0) goto retry; status32 = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl); if ((status32 & SOC_CNTL_LINK_DOWN) != 0) goto out; status16 = ntb_reg_read(2, ntb->reg_ofs.lnk_stat); width = (status16 & NTB_LINK_WIDTH_MASK) >> 4; speed = (status16 & NTB_LINK_SPEED_MASK); if (ntb->link_width != width || ntb->link_speed != speed) goto retry; out: callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, ntb_handle_heartbeat, ntb); return; retry: callout_reset(&ntb->lr_timer, NTB_HB_TIMEOUT * hz, recover_soc_link, ntb); } static int ntb_check_link_status(struct ntb_softc *ntb) { int link_state; uint32_t ntb_cntl; uint16_t status; if (ntb->type == NTB_SOC) { ntb_cntl = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl); if ((ntb_cntl & SOC_CNTL_LINK_DOWN) != 0) link_state = NTB_LINK_DOWN; else link_state = NTB_LINK_UP; } else { status = pci_read_config(ntb->device, XEON_LINK_STATUS_OFFSET, 2); if ((status & NTB_LINK_STATUS_ACTIVE) != 0) link_state = NTB_LINK_UP; else link_state = NTB_LINK_DOWN; } ntb_handle_link_event(ntb, link_state); return (0); } /** * ntb_register_event_callback() - register event callback * @ntb: pointer to ntb_softc instance * @func: callback function to register * * This function registers a callback for any HW driver events such as link * up/down, power management notices and etc. * * RETURNS: An appropriate ERRNO error value on error, or zero for success. */ int ntb_register_event_callback(struct ntb_softc *ntb, ntb_event_callback func) { if (ntb->event_cb != NULL) return (EINVAL); ntb->event_cb = func; return (0); } /** * ntb_unregister_event_callback() - unregisters the event callback * @ntb: pointer to ntb_softc instance * * This function unregisters the existing callback from transport */ void ntb_unregister_event_callback(struct ntb_softc *ntb) { ntb->event_cb = NULL; } /** * ntb_register_db_callback() - register a callback for doorbell interrupt * @ntb: pointer to ntb_softc instance * @idx: doorbell index to register callback, zero based + * @data: pointer to be returned to caller with every callback * @func: callback function to register * * This function registers a callback function for the doorbell interrupt * on the primary side. The function will unmask the doorbell as well to * allow interrupt. * * RETURNS: An appropriate ERRNO error value on error, or zero for success. */ int ntb_register_db_callback(struct ntb_softc *ntb, unsigned int idx, void *data, ntb_db_callback func) { uint16_t mask; if (idx >= ntb->allocated_interrupts || ntb->db_cb[idx].callback) { device_printf(ntb->device, "Invalid Index.\n"); return (EINVAL); } ntb->db_cb[idx].callback = func; ntb->db_cb[idx].data = data; /* unmask interrupt */ - mask = ntb_reg_read(2, ntb->reg_ofs.pdb_mask); + mask = ntb_reg_read(2, ntb->reg_ofs.ldb_mask); mask &= ~(1 << (idx * ntb->bits_per_vector)); - ntb_reg_write(2, ntb->reg_ofs.pdb_mask, mask); + ntb_reg_write(2, ntb->reg_ofs.ldb_mask, mask); return (0); } /** * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt * @ntb: pointer to ntb_softc instance * @idx: doorbell index to register callback, zero based * * This function unregisters a callback function for the doorbell interrupt * on the primary side. The function will also mask the said doorbell. */ void ntb_unregister_db_callback(struct ntb_softc *ntb, unsigned int idx) { unsigned long mask; if (idx >= ntb->allocated_interrupts || !ntb->db_cb[idx].callback) return; - mask = ntb_reg_read(2, ntb->reg_ofs.pdb_mask); + mask = ntb_reg_read(2, ntb->reg_ofs.ldb_mask); mask |= 1 << (idx * ntb->bits_per_vector); - ntb_reg_write(2, ntb->reg_ofs.pdb_mask, mask); + ntb_reg_write(2, ntb->reg_ofs.ldb_mask, mask); ntb->db_cb[idx].callback = NULL; } /** * ntb_find_transport() - find the transport pointer * @transport: pointer to pci device * * Given the pci device pointer, return the transport pointer passed in when * the transport attached when it was inited. * * RETURNS: pointer to transport. */ void * ntb_find_transport(struct ntb_softc *ntb) { return (ntb->ntb_transport); } /** * ntb_register_transport() - Register NTB transport with NTB HW driver * @transport: transport identifier * * This function allows a transport to reserve the hardware driver for * NTB usage. * * RETURNS: pointer to ntb_softc, NULL on error. */ struct ntb_softc * ntb_register_transport(struct ntb_softc *ntb, void *transport) { /* * TODO: when we have more than one transport, we will need to rewrite * this to prevent race conditions */ if (ntb->ntb_transport != NULL) return (NULL); ntb->ntb_transport = transport; return (ntb); } /** * ntb_unregister_transport() - Unregister the transport with the NTB HW driver * @ntb - ntb_softc of the transport to be freed * * This function unregisters the transport from the HW driver and performs any * necessary cleanups. */ void ntb_unregister_transport(struct ntb_softc *ntb) { int i; if (ntb->ntb_transport == NULL) return; for (i = 0; i < ntb->allocated_interrupts; i++) ntb_unregister_db_callback(ntb, i); ntb_unregister_event_callback(ntb); ntb->ntb_transport = NULL; } /** * ntb_get_max_spads() - get the total scratch regs usable * @ntb: pointer to ntb_softc instance * * This function returns the max 32bit scratchpad registers usable by the * upper layer. * * RETURNS: total number of scratch pad registers available */ uint8_t ntb_get_max_spads(struct ntb_softc *ntb) { return (ntb->limits.max_spads); } /** * ntb_write_local_spad() - write to the secondary scratchpad register * @ntb: pointer to ntb_softc instance * @idx: index to the scratchpad register, 0 based * @val: the data value to put into the register * * This function allows writing of a 32bit value to the indexed scratchpad * register. The register resides on the secondary (external) side. * * RETURNS: An appropriate ERRNO error value on error, or zero for success. */ int ntb_write_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val) { if (idx >= ntb->limits.max_spads) return (EINVAL); ntb_reg_write(4, ntb->reg_ofs.spad_local + idx * 4, val); return (0); } /** * ntb_read_local_spad() - read from the primary scratchpad register * @ntb: pointer to ntb_softc instance * @idx: index to scratchpad register, 0 based * @val: pointer to 32bit integer for storing the register value * * This function allows reading of the 32bit scratchpad register on * the primary (internal) side. * * RETURNS: An appropriate ERRNO error value on error, or zero for success. */ int ntb_read_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val) { if (idx >= ntb->limits.max_spads) return (EINVAL); *val = ntb_reg_read(4, ntb->reg_ofs.spad_local + idx * 4); return (0); } /** * ntb_write_remote_spad() - write to the secondary scratchpad register * @ntb: pointer to ntb_softc instance * @idx: index to the scratchpad register, 0 based * @val: the data value to put into the register * * This function allows writing of a 32bit value to the indexed scratchpad * register. The register resides on the secondary (external) side. * * RETURNS: An appropriate ERRNO error value on error, or zero for success. */ int ntb_write_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val) { if (idx >= ntb->limits.max_spads) return (EINVAL); if (HAS_FEATURE(NTB_REGS_THRU_MW)) ntb_mw_write(4, XEON_SHADOW_SPAD_OFFSET + idx * 4, val); else ntb_reg_write(4, ntb->reg_ofs.spad_remote + idx * 4, val); return (0); } /** * ntb_read_remote_spad() - read from the primary scratchpad register * @ntb: pointer to ntb_softc instance * @idx: index to scratchpad register, 0 based * @val: pointer to 32bit integer for storing the register value * * This function allows reading of the 32bit scratchpad register on * the primary (internal) side. * * RETURNS: An appropriate ERRNO error value on error, or zero for success. */ int ntb_read_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val) { if (idx >= ntb->limits.max_spads) return (EINVAL); if (HAS_FEATURE(NTB_REGS_THRU_MW)) *val = ntb_mw_read(4, XEON_SHADOW_SPAD_OFFSET + idx * 4); else *val = ntb_reg_read(4, ntb->reg_ofs.spad_remote + idx * 4); return (0); } /** * ntb_get_mw_vbase() - get virtual addr for the NTB memory window * @ntb: pointer to ntb_softc instance * @mw: memory window number * * This function provides the base virtual address of the memory window * specified. * * RETURNS: pointer to virtual address, or NULL on error. */ void * ntb_get_mw_vbase(struct ntb_softc *ntb, unsigned int mw) { if (mw >= NTB_NUM_MW) return (NULL); return (ntb->bar_info[NTB_MW_TO_BAR(mw)].vbase); } vm_paddr_t ntb_get_mw_pbase(struct ntb_softc *ntb, unsigned int mw) { if (mw >= NTB_NUM_MW) return (0); return (ntb->bar_info[NTB_MW_TO_BAR(mw)].pbase); } /** * ntb_get_mw_size() - return size of NTB memory window * @ntb: pointer to ntb_softc instance * @mw: memory window number * * This function provides the physical size of the memory window specified * * RETURNS: the size of the memory window or zero on error */ u_long ntb_get_mw_size(struct ntb_softc *ntb, unsigned int mw) { if (mw >= NTB_NUM_MW) return (0); return (ntb->bar_info[NTB_MW_TO_BAR(mw)].size); } /** * ntb_set_mw_addr - set the memory window address * @ntb: pointer to ntb_softc instance * @mw: memory window number * @addr: base address for data * * This function sets the base physical address of the memory window. This * memory address is where data from the remote system will be transfered into * or out of depending on how the transport is configured. */ void ntb_set_mw_addr(struct ntb_softc *ntb, unsigned int mw, uint64_t addr) { if (mw >= NTB_NUM_MW) return; switch (NTB_MW_TO_BAR(mw)) { case NTB_B2B_BAR_1: - ntb_reg_write(8, ntb->reg_ofs.sbar2_xlat, addr); + ntb_reg_write(8, ntb->reg_ofs.bar2_xlat, addr); break; case NTB_B2B_BAR_2: - ntb_reg_write(8, ntb->reg_ofs.sbar4_xlat, addr); + ntb_reg_write(8, ntb->reg_ofs.bar4_xlat, addr); break; } } /** - * ntb_ring_sdb() - Set the doorbell on the secondary/external side + * ntb_ring_doorbell() - Set the doorbell on the secondary/external side * @ntb: pointer to ntb_softc instance * @db: doorbell to ring * * This function allows triggering of a doorbell on the secondary/external * side that will initiate an interrupt on the remote host * * RETURNS: An appropriate ERRNO error value on error, or zero for success. */ void -ntb_ring_sdb(struct ntb_softc *ntb, unsigned int db) +ntb_ring_doorbell(struct ntb_softc *ntb, unsigned int db) { if (ntb->type == NTB_SOC) - ntb_reg_write(8, ntb->reg_ofs.sdb, (uint64_t) 1 << db); + ntb_reg_write(8, ntb->reg_ofs.rdb, (uint64_t) 1 << db); else { if (HAS_FEATURE(NTB_REGS_THRU_MW)) ntb_mw_write(2, XEON_SHADOW_PDOORBELL_OFFSET, ((1 << ntb->bits_per_vector) - 1) << (db * ntb->bits_per_vector)); else - ntb_reg_write(2, ntb->reg_ofs.sdb, + ntb_reg_write(2, ntb->reg_ofs.rdb, ((1 << ntb->bits_per_vector) - 1) << (db * ntb->bits_per_vector)); } } /** * ntb_query_link_status() - return the hardware link status * @ndev: pointer to ntb_device instance * * Returns true if the hardware is connected to the remote system * * RETURNS: true or false based on the hardware link state */ bool ntb_query_link_status(struct ntb_softc *ntb) { return (ntb->link_status == NTB_LINK_UP); } static void save_bar_parameters(struct ntb_pci_bar_info *bar) { bar->pci_bus_tag = rman_get_bustag(bar->pci_resource); bar->pci_bus_handle = rman_get_bushandle(bar->pci_resource); bar->pbase = rman_get_start(bar->pci_resource); bar->size = rman_get_size(bar->pci_resource); bar->vbase = rman_get_virtual(bar->pci_resource); } device_t ntb_get_device(struct ntb_softc *ntb) { return (ntb->device); } /* Export HW-specific errata information. */ bool ntb_has_feature(struct ntb_softc *ntb, uint64_t feature) { return (HAS_FEATURE(feature)); } Index: projects/collation/sys/dev/ntb/ntb_hw/ntb_hw.h =================================================================== --- projects/collation/sys/dev/ntb/ntb_hw/ntb_hw.h (revision 289266) +++ projects/collation/sys/dev/ntb/ntb_hw/ntb_hw.h (revision 289267) @@ -1,83 +1,83 @@ /*- * Copyright (C) 2013 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _NTB_HW_H_ #define _NTB_HW_H_ struct ntb_softc; #define NTB_NUM_MW 2 #define NTB_LINK_DOWN 0 #define NTB_LINK_UP 1 enum ntb_hw_event { NTB_EVENT_SW_EVENT0 = 0, NTB_EVENT_SW_EVENT1, NTB_EVENT_SW_EVENT2, NTB_EVENT_HW_ERROR, NTB_EVENT_HW_LINK_UP, NTB_EVENT_HW_LINK_DOWN, }; SYSCTL_DECL(_hw_ntb); typedef void (*ntb_db_callback)(void *data, int db_num); typedef void (*ntb_event_callback)(void *data, enum ntb_hw_event event); int ntb_register_event_callback(struct ntb_softc *ntb, ntb_event_callback func); void ntb_unregister_event_callback(struct ntb_softc *ntb); int ntb_register_db_callback(struct ntb_softc *ntb, unsigned int idx, void *data, ntb_db_callback func); void ntb_unregister_db_callback(struct ntb_softc *ntb, unsigned int idx); void *ntb_find_transport(struct ntb_softc *ntb); struct ntb_softc *ntb_register_transport(struct ntb_softc *ntb, void *transport); void ntb_unregister_transport(struct ntb_softc *ntb); uint8_t ntb_get_max_spads(struct ntb_softc *ntb); int ntb_write_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val); int ntb_read_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val); int ntb_write_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val); int ntb_read_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val); void *ntb_get_mw_vbase(struct ntb_softc *ntb, unsigned int mw); vm_paddr_t ntb_get_mw_pbase(struct ntb_softc *ntb, unsigned int mw); u_long ntb_get_mw_size(struct ntb_softc *ntb, unsigned int mw); void ntb_set_mw_addr(struct ntb_softc *ntb, unsigned int mw, uint64_t addr); -void ntb_ring_sdb(struct ntb_softc *ntb, unsigned int db); +void ntb_ring_doorbell(struct ntb_softc *ntb, unsigned int db); bool ntb_query_link_status(struct ntb_softc *ntb); device_t ntb_get_device(struct ntb_softc *ntb); #define NTB_BAR_SIZE_4K (1 << 0) /* REGS_THRU_MW is the equivalent of Linux's NTB_HWERR_SDOORBELL_LOCKUP */ #define NTB_REGS_THRU_MW (1 << 1) #define NTB_SB01BASE_LOCKUP (1 << 2) #define NTB_B2BDOORBELL_BIT14 (1 << 3) bool ntb_has_feature(struct ntb_softc *, uint64_t); #endif /* _NTB_HW_H_ */ Index: projects/collation/sys/dev/ntb/ntb_hw/ntb_regs.h =================================================================== --- projects/collation/sys/dev/ntb/ntb_hw/ntb_regs.h (revision 289266) +++ projects/collation/sys/dev/ntb/ntb_hw/ntb_regs.h (revision 289267) @@ -1,155 +1,155 @@ /*- * Copyright (C) 2013 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _NTB_REGS_H_ #define _NTB_REGS_H_ -#define NTB_LINK_ENABLE 0x0000 -#define NTB_LINK_DISABLE 0x0002 #define NTB_LINK_STATUS_ACTIVE 0x2000 #define NTB_LINK_SPEED_MASK 0x000f #define NTB_LINK_WIDTH_MASK 0x03f0 #define XEON_MSIX_CNT 4 #define XEON_MAX_SPADS 16 #define XEON_MAX_COMPAT_SPADS 16 /* Reserve the uppermost bit for link interrupt */ #define XEON_MAX_DB_BITS 15 #define XEON_DB_BITS_PER_VEC 5 #define XEON_DB_HW_LINK 0x8000 #define XEON_PCICMD_OFFSET 0x0504 #define XEON_DEVCTRL_OFFSET 0x0598 #define XEON_LINK_STATUS_OFFSET 0x01a2 +#define XEON_SLINK_STATUS_OFFSET 0x05a2 #define XEON_PBAR2LMT_OFFSET 0x0000 #define XEON_PBAR4LMT_OFFSET 0x0008 #define XEON_PBAR2XLAT_OFFSET 0x0010 #define XEON_PBAR4XLAT_OFFSET 0x0018 #define XEON_SBAR2LMT_OFFSET 0x0020 #define XEON_SBAR4LMT_OFFSET 0x0028 #define XEON_SBAR2XLAT_OFFSET 0x0030 #define XEON_SBAR4XLAT_OFFSET 0x0038 #define XEON_SBAR0BASE_OFFSET 0x0040 #define XEON_SBAR2BASE_OFFSET 0x0048 #define XEON_SBAR4BASE_OFFSET 0x0050 #define XEON_NTBCNTL_OFFSET 0x0058 #define XEON_SBDF_OFFSET 0x005c #define XEON_PDOORBELL_OFFSET 0x0060 #define XEON_PDBMSK_OFFSET 0x0062 #define XEON_SDOORBELL_OFFSET 0x0064 #define XEON_SDBMSK_OFFSET 0x0066 #define XEON_USMEMMISS 0x0070 #define XEON_SPAD_OFFSET 0x0080 #define XEON_SPADSEMA4_OFFSET 0x00c0 #define XEON_WCCNTRL_OFFSET 0x00e0 #define XEON_B2B_SPAD_OFFSET 0x0100 #define XEON_B2B_DOORBELL_OFFSET 0x0140 #define XEON_B2B_XLAT_OFFSETL 0x0144 #define XEON_B2B_XLAT_OFFSETU 0x0148 #define SOC_MSIX_CNT 34 #define SOC_MAX_SPADS 16 -#define SOC_MAX_COMPAT_SPADS 16 #define SOC_MAX_DB_BITS 34 #define SOC_DB_BITS_PER_VEC 1 #define SOC_PCICMD_OFFSET 0xb004 #define SOC_MBAR23_OFFSET 0xb018 #define SOC_MBAR45_OFFSET 0xb020 #define SOC_DEVCTRL_OFFSET 0xb048 #define SOC_LINK_STATUS_OFFSET 0xb052 #define SOC_ERRCORSTS_OFFSET 0xb110 #define SOC_SBAR2XLAT_OFFSET 0x0008 #define SOC_SBAR4XLAT_OFFSET 0x0010 #define SOC_PDOORBELL_OFFSET 0x0020 #define SOC_PDBMSK_OFFSET 0x0028 #define SOC_NTBCNTL_OFFSET 0x0060 #define SOC_EBDF_OFFSET 0x0064 #define SOC_SPAD_OFFSET 0x0080 #define SOC_SPADSEMA_OFFSET 0x00c0 #define SOC_STKYSPAD_OFFSET 0x00c4 #define SOC_PBAR2XLAT_OFFSET 0x8008 #define SOC_PBAR4XLAT_OFFSET 0x8010 #define SOC_B2B_DOORBELL_OFFSET 0x8020 #define SOC_B2B_SPAD_OFFSET 0x8080 #define SOC_B2B_SPADSEMA_OFFSET 0x80c0 #define SOC_B2B_STKYSPAD_OFFSET 0x80c4 #define SOC_MODPHY_PCSREG4 0x1c004 #define SOC_MODPHY_PCSREG6 0x1c006 #define SOC_IP_BASE 0xc000 #define SOC_DESKEWSTS_OFFSET (SOC_IP_BASE + 0x3024) #define SOC_LTSSMERRSTS0_OFFSET (SOC_IP_BASE + 0x3180) #define SOC_LTSSMSTATEJMP_OFFSET (SOC_IP_BASE + 0x3040) #define SOC_IBSTERRRCRVSTS0_OFFSET (SOC_IP_BASE + 0x3324) #define SOC_DESKEWSTS_DBERR (1 << 15) #define SOC_LTSSMERRSTS0_UNEXPECTEDEI (1 << 20) #define SOC_LTSSMSTATEJMP_FORCEDETECT (1 << 2) #define SOC_IBIST_ERR_OFLOW 0x7fff7fff +#define NTB_CNTL_CFG_LOCK (1 << 0) +#define NTB_CNTL_LINK_DISABLE (1 << 1) #define NTB_CNTL_BAR23_SNOOP (1 << 2) #define NTB_CNTL_BAR45_SNOOP (1 << 6) #define SOC_CNTL_LINK_DOWN (1 << 16) #define XEON_PBAR23SZ_OFFSET 0x00d0 #define XEON_PBAR45SZ_OFFSET 0x00d1 #define NTB_PPD_OFFSET 0x00d4 #define XEON_PPD_CONN_TYPE 0x0003 #define XEON_PPD_DEV_TYPE 0x0010 #define SOC_PPD_INIT_LINK 0x0008 #define SOC_PPD_CONN_TYPE 0x0300 #define SOC_PPD_DEV_TYPE 0x1000 -#define NTB_CONN_CLASSIC 0 +#define NTB_CONN_TRANSPARENT 0 #define NTB_CONN_B2B 1 #define NTB_CONN_RP 2 #define NTB_DEV_DSD 1 #define NTB_DEV_USD 0 #define PBAR2XLAT_USD_ADDR 0x0000004000000000ull #define PBAR4XLAT_USD_ADDR 0x0000008000000000ull #define MBAR01_USD_ADDR 0x000000210000000cull #define MBAR23_USD_ADDR 0x000000410000000cull #define MBAR45_USD_ADDR 0x000000810000000cull #define PBAR2XLAT_DSD_ADDR 0x0000004100000000ull #define PBAR4XLAT_DSD_ADDR 0x0000008100000000ull #define MBAR01_DSD_ADDR 0x000000200000000cull #define MBAR23_DSD_ADDR 0x000000400000000cull #define MBAR45_DSD_ADDR 0x000000800000000cull /* XEON Shadowed MMIO Space */ #define XEON_SHADOW_PDOORBELL_OFFSET 0x60 #define XEON_SHADOW_SPAD_OFFSET 0x80 #endif /* _NTB_REGS_H_ */ Index: projects/collation/sys/netinet/sctp_timer.c =================================================================== --- projects/collation/sys/netinet/sctp_timer.c (revision 289266) +++ projects/collation/sys/netinet/sctp_timer.c (revision 289267) @@ -1,1585 +1,1589 @@ /*- * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * a) Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * b) Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the distribution. * * c) Neither the name of Cisco Systems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #define _IP_VHL #include #include #ifdef INET6 #endif #include #include #include #include #include #include #include #include #include #include #include #if defined(INET) || defined(INET6) #include #endif void sctp_audit_retranmission_queue(struct sctp_association *asoc) { struct sctp_tmit_chunk *chk; SCTPDBG(SCTP_DEBUG_TIMER4, "Audit invoked on send queue cnt:%d onqueue:%d\n", asoc->sent_queue_retran_cnt, asoc->sent_queue_cnt); asoc->sent_queue_retran_cnt = 0; asoc->sent_queue_cnt = 0; TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { if (chk->sent == SCTP_DATAGRAM_RESEND) { sctp_ucount_incr(asoc->sent_queue_retran_cnt); } asoc->sent_queue_cnt++; } TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { if (chk->sent == SCTP_DATAGRAM_RESEND) { sctp_ucount_incr(asoc->sent_queue_retran_cnt); } } TAILQ_FOREACH(chk, &asoc->asconf_send_queue, sctp_next) { if (chk->sent == SCTP_DATAGRAM_RESEND) { sctp_ucount_incr(asoc->sent_queue_retran_cnt); } } SCTPDBG(SCTP_DEBUG_TIMER4, "Audit completes retran:%d onqueue:%d\n", asoc->sent_queue_retran_cnt, asoc->sent_queue_cnt); } int sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net, uint16_t threshold) { if (net) { net->error_count++; SCTPDBG(SCTP_DEBUG_TIMER4, "Error count for %p now %d thresh:%d\n", (void *)net, net->error_count, net->failure_threshold); if (net->error_count > net->failure_threshold) { /* We had a threshold failure */ if (net->dest_state & SCTP_ADDR_REACHABLE) { net->dest_state &= ~SCTP_ADDR_REACHABLE; net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY; net->dest_state &= ~SCTP_ADDR_PF; sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, (void *)net, SCTP_SO_NOT_LOCKED); } } else if ((net->pf_threshold < net->failure_threshold) && (net->error_count > net->pf_threshold)) { if (!(net->dest_state & SCTP_ADDR_PF)) { net->dest_state |= SCTP_ADDR_PF; net->last_active = sctp_get_tick_count(); sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_1); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); } } } if (stcb == NULL) return (0); if (net) { if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { sctp_misc_ints(SCTP_THRESHOLD_INCR, stcb->asoc.overall_error_count, (stcb->asoc.overall_error_count + 1), SCTP_FROM_SCTP_TIMER, __LINE__); } stcb->asoc.overall_error_count++; } } else { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { sctp_misc_ints(SCTP_THRESHOLD_INCR, stcb->asoc.overall_error_count, (stcb->asoc.overall_error_count + 1), SCTP_FROM_SCTP_TIMER, __LINE__); } stcb->asoc.overall_error_count++; } SCTPDBG(SCTP_DEBUG_TIMER4, "Overall error count for %p now %d thresh:%u state:%x\n", (void *)&stcb->asoc, stcb->asoc.overall_error_count, (uint32_t) threshold, ((net == NULL) ? (uint32_t) 0 : (uint32_t) net->dest_state)); /* * We specifically do not do >= to give the assoc one more change * before we fail it. */ if (stcb->asoc.overall_error_count > threshold) { /* Abort notification sends a ULP notify */ struct mbuf *op_err; op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), "Association error counter exceeded"); inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_2; sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); return (1); } return (0); } /* * sctp_find_alternate_net() returns a non-NULL pointer as long * the argument net is non-NULL. */ struct sctp_nets * sctp_find_alternate_net(struct sctp_tcb *stcb, struct sctp_nets *net, int mode) { /* Find and return an alternate network if possible */ struct sctp_nets *alt, *mnet, *min_errors_net = NULL, *max_cwnd_net = NULL; int once; /* JRS 5/14/07 - Initialize min_errors to an impossible value. */ int min_errors = -1; uint32_t max_cwnd = 0; if (stcb->asoc.numnets == 1) { /* No others but net */ return (TAILQ_FIRST(&stcb->asoc.nets)); } /* * JRS 5/14/07 - If mode is set to 2, use the CMT PF find alternate * net algorithm. This algorithm chooses the active destination (not * in PF state) with the largest cwnd value. If all destinations are * in PF state, unreachable, or unconfirmed, choose the desination * that is in PF state with the lowest error count. In case of a * tie, choose the destination that was most recently active. */ if (mode == 2) { TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) { /* * JRS 5/14/07 - If the destination is unreachable * or unconfirmed, skip it. */ if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) || (mnet->dest_state & SCTP_ADDR_UNCONFIRMED)) { continue; } /* * JRS 5/14/07 - If the destination is reachable * but in PF state, compare the error count of the * destination to the minimum error count seen thus * far. Store the destination with the lower error * count. If the error counts are equal, store the * destination that was most recently active. */ if (mnet->dest_state & SCTP_ADDR_PF) { /* * JRS 5/14/07 - If the destination under * consideration is the current destination, * work as if the error count is one higher. * The actual error count will not be * incremented until later in the t3 * handler. */ if (mnet == net) { if (min_errors == -1) { min_errors = mnet->error_count + 1; min_errors_net = mnet; } else if (mnet->error_count + 1 < min_errors) { min_errors = mnet->error_count + 1; min_errors_net = mnet; } else if (mnet->error_count + 1 == min_errors && mnet->last_active > min_errors_net->last_active) { min_errors_net = mnet; min_errors = mnet->error_count + 1; } continue; } else { if (min_errors == -1) { min_errors = mnet->error_count; min_errors_net = mnet; } else if (mnet->error_count < min_errors) { min_errors = mnet->error_count; min_errors_net = mnet; } else if (mnet->error_count == min_errors && mnet->last_active > min_errors_net->last_active) { min_errors_net = mnet; min_errors = mnet->error_count; } continue; } } /* * JRS 5/14/07 - If the destination is reachable and * not in PF state, compare the cwnd of the * destination to the highest cwnd seen thus far. * Store the destination with the higher cwnd value. * If the cwnd values are equal, randomly choose one * of the two destinations. */ if (max_cwnd < mnet->cwnd) { max_cwnd_net = mnet; max_cwnd = mnet->cwnd; } else if (max_cwnd == mnet->cwnd) { uint32_t rndval; uint8_t this_random; if (stcb->asoc.hb_random_idx > 3) { rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); memcpy(stcb->asoc.hb_random_values, &rndval, sizeof(stcb->asoc.hb_random_values)); this_random = stcb->asoc.hb_random_values[0]; stcb->asoc.hb_random_idx++; stcb->asoc.hb_ect_randombit = 0; } else { this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx]; stcb->asoc.hb_random_idx++; stcb->asoc.hb_ect_randombit = 0; } if (this_random % 2 == 1) { max_cwnd_net = mnet; max_cwnd = mnet->cwnd; /* Useless? */ } } } if (max_cwnd_net == NULL) { if (min_errors_net == NULL) { return (net); } return (min_errors_net); } else { return (max_cwnd_net); } } /* * JRS 5/14/07 - If mode is set to 1, use the CMT policy for * choosing an alternate net. */ else if (mode == 1) { TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) { if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) || (mnet->dest_state & SCTP_ADDR_UNCONFIRMED)) { /* * will skip ones that are not-reachable or * unconfirmed */ continue; } if (max_cwnd < mnet->cwnd) { max_cwnd_net = mnet; max_cwnd = mnet->cwnd; } else if (max_cwnd == mnet->cwnd) { uint32_t rndval; uint8_t this_random; if (stcb->asoc.hb_random_idx > 3) { rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); memcpy(stcb->asoc.hb_random_values, &rndval, sizeof(stcb->asoc.hb_random_values)); this_random = stcb->asoc.hb_random_values[0]; stcb->asoc.hb_random_idx = 0; stcb->asoc.hb_ect_randombit = 0; } else { this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx]; stcb->asoc.hb_random_idx++; stcb->asoc.hb_ect_randombit = 0; } if (this_random % 2) { max_cwnd_net = mnet; max_cwnd = mnet->cwnd; } } } if (max_cwnd_net) { return (max_cwnd_net); } } mnet = net; once = 0; if (mnet == NULL) { mnet = TAILQ_FIRST(&stcb->asoc.nets); if (mnet == NULL) { return (NULL); } } for (;;) { alt = TAILQ_NEXT(mnet, sctp_next); if (alt == NULL) { once++; if (once > 1) { break; } alt = TAILQ_FIRST(&stcb->asoc.nets); if (alt == NULL) { return (NULL); } } if (alt->ro.ro_rt == NULL) { if (alt->ro._s_addr) { sctp_free_ifa(alt->ro._s_addr); alt->ro._s_addr = NULL; } alt->src_addr_selected = 0; } if (((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) && (alt->ro.ro_rt != NULL) && (!(alt->dest_state & SCTP_ADDR_UNCONFIRMED))) { /* Found a reachable address */ break; } mnet = alt; } if (alt == NULL) { /* Case where NO insv network exists (dormant state) */ /* we rotate destinations */ once = 0; mnet = net; for (;;) { if (mnet == NULL) { return (TAILQ_FIRST(&stcb->asoc.nets)); } alt = TAILQ_NEXT(mnet, sctp_next); if (alt == NULL) { once++; if (once > 1) { break; } alt = TAILQ_FIRST(&stcb->asoc.nets); if (alt == NULL) { break; } } if ((!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) && (alt != net)) { /* Found an alternate address */ break; } mnet = alt; } } if (alt == NULL) { return (net); } return (alt); } static void sctp_backoff_on_timeout(struct sctp_tcb *stcb, struct sctp_nets *net, int win_probe, int num_marked, int num_abandoned) { if (net->RTO == 0) { - net->RTO = stcb->asoc.minrto; + if (net->RTO_measured) { + net->RTO = stcb->asoc.minrto; + } else { + net->RTO = stcb->asoc.initial_rto; + } } net->RTO <<= 1; if (net->RTO > stcb->asoc.maxrto) { net->RTO = stcb->asoc.maxrto; } if ((win_probe == 0) && (num_marked || num_abandoned)) { /* We don't apply penalty to window probe scenarios */ /* JRS - Use the congestion control given in the CC module */ stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout(stcb, net); } } #ifndef INVARIANTS static void sctp_recover_sent_list(struct sctp_tcb *stcb) { struct sctp_tmit_chunk *chk, *nchk; struct sctp_association *asoc; asoc = &stcb->asoc; TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) { if (SCTP_TSN_GE(asoc->last_acked_seq, chk->rec.data.TSN_seq)) { SCTP_PRINTF("Found chk:%p tsn:%x <= last_acked_seq:%x\n", (void *)chk, chk->rec.data.TSN_seq, asoc->last_acked_seq); if (chk->sent != SCTP_DATAGRAM_NR_ACKED) { if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) { asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--; } } TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next); if (PR_SCTP_ENABLED(chk->flags)) { if (asoc->pr_sctp_cnt != 0) asoc->pr_sctp_cnt--; } if (chk->data) { /* sa_ignore NO_NULL_CHK */ sctp_free_bufspace(stcb, asoc, chk, 1); sctp_m_freem(chk->data); chk->data = NULL; if (asoc->prsctp_supported && PR_SCTP_BUF_ENABLED(chk->flags)) { asoc->sent_queue_cnt_removeable--; } } asoc->sent_queue_cnt--; sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); } } SCTP_PRINTF("after recover order is as follows\n"); TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { SCTP_PRINTF("chk:%p TSN:%x\n", (void *)chk, chk->rec.data.TSN_seq); } } #endif static int sctp_mark_all_for_resend(struct sctp_tcb *stcb, struct sctp_nets *net, struct sctp_nets *alt, int window_probe, int *num_marked, int *num_abandoned) { /* * Mark all chunks (well not all) that were sent to *net for * retransmission. Move them to alt for there destination as well... * We only mark chunks that have been outstanding long enough to * have received feed-back. */ struct sctp_tmit_chunk *chk, *nchk; struct sctp_nets *lnets; struct timeval now, min_wait, tv; int cur_rto; int cnt_abandoned; int audit_tf, num_mk, fir; unsigned int cnt_mk; uint32_t orig_flight, orig_tf; uint32_t tsnlast, tsnfirst; int recovery_cnt = 0; /* none in flight now */ audit_tf = 0; fir = 0; /* * figure out how long a data chunk must be pending before we can * mark it .. */ (void)SCTP_GETTIME_TIMEVAL(&now); /* get cur rto in micro-seconds */ cur_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; cur_rto *= 1000; if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(cur_rto, stcb->asoc.peers_rwnd, window_probe, SCTP_FR_T3_MARK_TIME); sctp_log_fr(net->flight_size, 0, 0, SCTP_FR_CWND_REPORT); sctp_log_fr(net->flight_size, net->cwnd, stcb->asoc.total_flight, SCTP_FR_CWND_REPORT); } tv.tv_sec = cur_rto / 1000000; tv.tv_usec = cur_rto % 1000000; min_wait = now; timevalsub(&min_wait, &tv); if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) { /* * if we hit here, we don't have enough seconds on the clock * to account for the RTO. We just let the lower seconds be * the bounds and don't worry about it. This may mean we * will mark a lot more than we should. */ min_wait.tv_sec = min_wait.tv_usec = 0; } if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(cur_rto, now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME); sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME); } /* * Our rwnd will be incorrect here since we are not adding back the * cnt * mbuf but we will fix that down below. */ orig_flight = net->flight_size; orig_tf = stcb->asoc.total_flight; net->fast_retran_ip = 0; /* Now on to each chunk */ cnt_abandoned = 0; num_mk = cnt_mk = 0; tsnfirst = tsnlast = 0; #ifndef INVARIANTS start_again: #endif TAILQ_FOREACH_SAFE(chk, &stcb->asoc.sent_queue, sctp_next, nchk) { if (SCTP_TSN_GE(stcb->asoc.last_acked_seq, chk->rec.data.TSN_seq)) { /* Strange case our list got out of order? */ SCTP_PRINTF("Our list is out of order? last_acked:%x chk:%x\n", (unsigned int)stcb->asoc.last_acked_seq, (unsigned int)chk->rec.data.TSN_seq); recovery_cnt++; #ifdef INVARIANTS panic("last acked >= chk on sent-Q"); #else SCTP_PRINTF("Recover attempts a restart cnt:%d\n", recovery_cnt); sctp_recover_sent_list(stcb); if (recovery_cnt < 10) { goto start_again; } else { SCTP_PRINTF("Recovery fails %d times??\n", recovery_cnt); } #endif } if ((chk->whoTo == net) && (chk->sent < SCTP_DATAGRAM_ACKED)) { /* * found one to mark: If it is less than * DATAGRAM_ACKED it MUST not be a skipped or marked * TSN but instead one that is either already set * for retransmission OR one that needs * retransmission. */ /* validate its been outstanding long enough */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(chk->rec.data.TSN_seq, chk->sent_rcv_time.tv_sec, chk->sent_rcv_time.tv_usec, SCTP_FR_T3_MARK_TIME); } if ((chk->sent_rcv_time.tv_sec > min_wait.tv_sec) && (window_probe == 0)) { /* * we have reached a chunk that was sent * some seconds past our min.. forget it we * will find no more to send. */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(0, chk->sent_rcv_time.tv_sec, chk->sent_rcv_time.tv_usec, SCTP_FR_T3_STOPPED); } continue; } else if ((chk->sent_rcv_time.tv_sec == min_wait.tv_sec) && (window_probe == 0)) { /* * we must look at the micro seconds to * know. */ if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) { /* * ok it was sent after our boundary * time. */ continue; } } if (stcb->asoc.prsctp_supported && PR_SCTP_TTL_ENABLED(chk->flags)) { /* Is it expired? */ if (timevalcmp(&now, &chk->rec.data.timetodrop, >)) { /* Yes so drop it */ if (chk->data) { (void)sctp_release_pr_sctp_chunk(stcb, chk, 1, SCTP_SO_NOT_LOCKED); cnt_abandoned++; } continue; } } if (stcb->asoc.prsctp_supported && PR_SCTP_RTX_ENABLED(chk->flags)) { /* Has it been retransmitted tv_sec times? */ if (chk->snd_count > chk->rec.data.timetodrop.tv_sec) { if (chk->data) { (void)sctp_release_pr_sctp_chunk(stcb, chk, 1, SCTP_SO_NOT_LOCKED); cnt_abandoned++; } continue; } } if (chk->sent < SCTP_DATAGRAM_RESEND) { sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); num_mk++; if (fir == 0) { fir = 1; tsnfirst = chk->rec.data.TSN_seq; } tsnlast = chk->rec.data.TSN_seq; if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count, 0, SCTP_FR_T3_MARKED); } if (chk->rec.data.chunk_was_revoked) { /* deflate the cwnd */ chk->whoTo->cwnd -= chk->book_size; chk->rec.data.chunk_was_revoked = 0; } net->marked_retrans++; stcb->asoc.marked_retrans++; if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND_TO, chk->whoTo->flight_size, chk->book_size, (uintptr_t) chk->whoTo, chk->rec.data.TSN_seq); } sctp_flight_size_decrease(chk); sctp_total_flight_decrease(stcb, chk); stcb->asoc.peers_rwnd += chk->send_size; stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh); } chk->sent = SCTP_DATAGRAM_RESEND; SCTP_STAT_INCR(sctps_markedretrans); /* reset the TSN for striking and other FR stuff */ chk->rec.data.doing_fast_retransmit = 0; /* Clear any time so NO RTT is being done */ if (chk->do_rtt) { if (chk->whoTo->rto_needed == 0) { chk->whoTo->rto_needed = 1; } } chk->do_rtt = 0; if (alt != net) { sctp_free_remote_addr(chk->whoTo); chk->no_fr_allowed = 1; chk->whoTo = alt; atomic_add_int(&alt->ref_count, 1); } else { chk->no_fr_allowed = 0; if (TAILQ_EMPTY(&stcb->asoc.send_queue)) { chk->rec.data.fast_retran_tsn = stcb->asoc.sending_seq; } else { chk->rec.data.fast_retran_tsn = (TAILQ_FIRST(&stcb->asoc.send_queue))->rec.data.TSN_seq; } } /* * CMT: Do not allow FRs on retransmitted TSNs. */ if (stcb->asoc.sctp_cmt_on_off > 0) { chk->no_fr_allowed = 1; } #ifdef THIS_SHOULD_NOT_BE_DONE } else if (chk->sent == SCTP_DATAGRAM_ACKED) { /* remember highest acked one */ could_be_sent = chk; #endif } if (chk->sent == SCTP_DATAGRAM_RESEND) { cnt_mk++; } } if ((orig_flight - net->flight_size) != (orig_tf - stcb->asoc.total_flight)) { /* we did not subtract the same things? */ audit_tf = 1; } if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT); } #ifdef SCTP_DEBUG if (num_mk) { SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n", tsnlast); SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%ld\n", num_mk, (u_long)stcb->asoc.peers_rwnd); SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n", tsnlast); SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%d\n", num_mk, (int)stcb->asoc.peers_rwnd); } #endif *num_marked = num_mk; *num_abandoned = cnt_abandoned; /* * Now check for a ECN Echo that may be stranded And include the * cnt_mk'd to have all resends in the control queue. */ TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { if (chk->sent == SCTP_DATAGRAM_RESEND) { cnt_mk++; } if ((chk->whoTo == net) && (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { sctp_free_remote_addr(chk->whoTo); chk->whoTo = alt; if (chk->sent != SCTP_DATAGRAM_RESEND) { chk->sent = SCTP_DATAGRAM_RESEND; sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); cnt_mk++; } atomic_add_int(&alt->ref_count, 1); } } #ifdef THIS_SHOULD_NOT_BE_DONE if ((stcb->asoc.sent_queue_retran_cnt == 0) && (could_be_sent)) { /* fix it so we retransmit the highest acked anyway */ sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); cnt_mk++; could_be_sent->sent = SCTP_DATAGRAM_RESEND; } #endif if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) { #ifdef INVARIANTS SCTP_PRINTF("Local Audit says there are %d for retran asoc cnt:%d we marked:%d this time\n", cnt_mk, stcb->asoc.sent_queue_retran_cnt, num_mk); #endif #ifndef SCTP_AUDITING_ENABLED stcb->asoc.sent_queue_retran_cnt = cnt_mk; #endif } if (audit_tf) { SCTPDBG(SCTP_DEBUG_TIMER4, "Audit total flight due to negative value net:%p\n", (void *)net); stcb->asoc.total_flight = 0; stcb->asoc.total_flight_count = 0; /* Clear all networks flight size */ TAILQ_FOREACH(lnets, &stcb->asoc.nets, sctp_next) { lnets->flight_size = 0; SCTPDBG(SCTP_DEBUG_TIMER4, "Net:%p c-f cwnd:%d ssthresh:%d\n", (void *)lnets, lnets->cwnd, lnets->ssthresh); } TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { if (chk->sent < SCTP_DATAGRAM_RESEND) { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { sctp_misc_ints(SCTP_FLIGHT_LOG_UP, chk->whoTo->flight_size, chk->book_size, (uintptr_t) chk->whoTo, chk->rec.data.TSN_seq); } sctp_flight_size_increase(chk); sctp_total_flight_increase(stcb, chk); } } } /* We return 1 if we only have a window probe outstanding */ return (0); } int sctp_t3rxt_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net) { struct sctp_nets *alt; int win_probe, num_mk, num_abandoned; if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(0, 0, 0, SCTP_FR_T3_TIMEOUT); } if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { struct sctp_nets *lnet; TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { if (net == lnet) { sctp_log_cwnd(stcb, lnet, 1, SCTP_CWND_LOG_FROM_T3); } else { sctp_log_cwnd(stcb, lnet, 0, SCTP_CWND_LOG_FROM_T3); } } } /* Find an alternate and mark those for retransmission */ if ((stcb->asoc.peers_rwnd == 0) && (stcb->asoc.total_flight < net->mtu)) { SCTP_STAT_INCR(sctps_timowindowprobe); win_probe = 1; } else { win_probe = 0; } if (win_probe == 0) { /* We don't do normal threshold management on window probes */ if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { /* Association was destroyed */ return (1); } else { if (net != stcb->asoc.primary_destination) { /* send a immediate HB if our RTO is stale */ struct timeval now; unsigned int ms_goneby; (void)SCTP_GETTIME_TIMEVAL(&now); if (net->last_sent_time.tv_sec) { ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000; } else { ms_goneby = 0; } if ((net->dest_state & SCTP_ADDR_PF) == 0) { if ((ms_goneby > net->RTO) || (net->RTO == 0)) { /* * no recent feed back in an * RTO or more, request a * RTT update */ sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); } } } } } else { /* * For a window probe we don't penalize the net's but only * the association. This may fail it if SACKs are not coming * back. If sack's are coming with rwnd locked at 0, we will * continue to hold things waiting for rwnd to raise */ if (sctp_threshold_management(inp, stcb, NULL, stcb->asoc.max_send_times)) { /* Association was destroyed */ return (1); } } if (stcb->asoc.sctp_cmt_on_off > 0) { if (net->pf_threshold < net->failure_threshold) { alt = sctp_find_alternate_net(stcb, net, 2); } else { /* * CMT: Using RTX_SSTHRESH policy for CMT. If CMT is * being used, then pick dest with largest ssthresh * for any retransmission. */ alt = sctp_find_alternate_net(stcb, net, 1); /* * CUCv2: If a different dest is picked for the * retransmission, then new (rtx-)pseudo_cumack * needs to be tracked for orig dest. Let CUCv2 * track new (rtx-) pseudo-cumack always. */ net->find_pseudo_cumack = 1; net->find_rtx_pseudo_cumack = 1; } } else { alt = sctp_find_alternate_net(stcb, net, 0); } num_mk = 0; num_abandoned = 0; (void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, &num_mk, &num_abandoned); /* FR Loss recovery just ended with the T3. */ stcb->asoc.fast_retran_loss_recovery = 0; /* CMT FR loss recovery ended with the T3 */ net->fast_retran_loss_recovery = 0; if ((stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) && (net->flight_size == 0)) { (*stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) (stcb, net); } /* * setup the sat loss recovery that prevents satellite cwnd advance. */ stcb->asoc.sat_t3_loss_recovery = 1; stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq; /* Backoff the timer and cwnd */ sctp_backoff_on_timeout(stcb, net, win_probe, num_mk, num_abandoned); if ((!(net->dest_state & SCTP_ADDR_REACHABLE)) || (net->dest_state & SCTP_ADDR_PF)) { /* Move all pending over too */ sctp_move_chunks_from_net(stcb, net); /* * Get the address that failed, to force a new src address * selecton and a route allocation. */ if (net->ro._s_addr) { sctp_free_ifa(net->ro._s_addr); net->ro._s_addr = NULL; } net->src_addr_selected = 0; /* Force a route allocation too */ if (net->ro.ro_rt) { RTFREE(net->ro.ro_rt); net->ro.ro_rt = NULL; } /* Was it our primary? */ if ((stcb->asoc.primary_destination == net) && (alt != net)) { /* * Yes, note it as such and find an alternate note: * this means HB code must use this to resent the * primary if it goes active AND if someone does a * change-primary then this flag must be cleared * from any net structures. */ if (stcb->asoc.alternate) { sctp_free_remote_addr(stcb->asoc.alternate); } stcb->asoc.alternate = alt; atomic_add_int(&stcb->asoc.alternate->ref_count, 1); } } /* * Special case for cookie-echo'ed case, we don't do output but must * await the COOKIE-ACK before retransmission */ if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) { /* * Here we just reset the timer and start again since we * have not established the asoc */ sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); return (0); } if (stcb->asoc.prsctp_supported) { struct sctp_tmit_chunk *lchk; lchk = sctp_try_advance_peer_ack_point(stcb, &stcb->asoc); /* C3. See if we need to send a Fwd-TSN */ if (SCTP_TSN_GT(stcb->asoc.advanced_peer_ack_point, stcb->asoc.last_acked_seq)) { send_forward_tsn(stcb, &stcb->asoc); if (lchk) { /* Assure a timer is up */ sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, lchk->whoTo); } } } if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { sctp_log_cwnd(stcb, net, net->cwnd, SCTP_CWND_LOG_FROM_RTX); } return (0); } int sctp_t1init_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net) { /* bump the thresholds */ if (stcb->asoc.delayed_connection) { /* * special hook for delayed connection. The library did NOT * complete the rest of its sends. */ stcb->asoc.delayed_connection = 0; sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED); return (0); } if (SCTP_GET_STATE((&stcb->asoc)) != SCTP_STATE_COOKIE_WAIT) { return (0); } if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_init_times)) { /* Association was destroyed */ return (1); } stcb->asoc.dropped_special_cnt = 0; sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0, 0); if (stcb->asoc.initial_init_rto_max < net->RTO) { net->RTO = stcb->asoc.initial_init_rto_max; } if (stcb->asoc.numnets > 1) { /* If we have more than one addr use it */ struct sctp_nets *alt; alt = sctp_find_alternate_net(stcb, stcb->asoc.primary_destination, 0); if (alt != stcb->asoc.primary_destination) { sctp_move_chunks_from_net(stcb, stcb->asoc.primary_destination); stcb->asoc.primary_destination = alt; } } /* Send out a new init */ sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED); return (0); } /* * For cookie and asconf we actually need to find and mark for resend, then * increment the resend counter (after all the threshold management stuff of * course). */ int sctp_cookie_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED) { struct sctp_nets *alt; struct sctp_tmit_chunk *cookie; /* first before all else we must find the cookie */ TAILQ_FOREACH(cookie, &stcb->asoc.control_send_queue, sctp_next) { if (cookie->rec.chunk_id.id == SCTP_COOKIE_ECHO) { break; } } if (cookie == NULL) { if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) { /* FOOBAR! */ struct mbuf *op_err; op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), "Cookie timer expired, but no cookie"); inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_3; sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); } else { #ifdef INVARIANTS panic("Cookie timer expires in wrong state?"); #else SCTP_PRINTF("Strange in state %d not cookie-echoed yet c-e timer expires?\n", SCTP_GET_STATE(&stcb->asoc)); return (0); #endif } return (0); } /* Ok we found the cookie, threshold management next */ if (sctp_threshold_management(inp, stcb, cookie->whoTo, stcb->asoc.max_init_times)) { /* Assoc is over */ return (1); } /* * cleared theshold management now lets backoff the address & select * an alternate */ stcb->asoc.dropped_special_cnt = 0; sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0, 0); alt = sctp_find_alternate_net(stcb, cookie->whoTo, 0); if (alt != cookie->whoTo) { sctp_free_remote_addr(cookie->whoTo); cookie->whoTo = alt; atomic_add_int(&alt->ref_count, 1); } /* Now mark the retran info */ if (cookie->sent != SCTP_DATAGRAM_RESEND) { sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); } cookie->sent = SCTP_DATAGRAM_RESEND; /* * Now call the output routine to kick out the cookie again, Note we * don't mark any chunks for retran so that FR will need to kick in * to move these (or a send timer). */ return (0); } int sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net) { struct sctp_nets *alt; struct sctp_tmit_chunk *strrst = NULL, *chk = NULL; if (stcb->asoc.stream_reset_outstanding == 0) { return (0); } /* find the existing STRRESET, we use the seq number we sent out on */ (void)sctp_find_stream_reset(stcb, stcb->asoc.str_reset_seq_out, &strrst); if (strrst == NULL) { return (0); } /* do threshold management */ if (sctp_threshold_management(inp, stcb, strrst->whoTo, stcb->asoc.max_send_times)) { /* Assoc is over */ return (1); } /* * cleared theshold management now lets backoff the address & select * an alternate */ sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0, 0); alt = sctp_find_alternate_net(stcb, strrst->whoTo, 0); sctp_free_remote_addr(strrst->whoTo); strrst->whoTo = alt; atomic_add_int(&alt->ref_count, 1); /* See if a ECN Echo is also stranded */ TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { if ((chk->whoTo == net) && (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { sctp_free_remote_addr(chk->whoTo); if (chk->sent != SCTP_DATAGRAM_RESEND) { chk->sent = SCTP_DATAGRAM_RESEND; sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); } chk->whoTo = alt; atomic_add_int(&alt->ref_count, 1); } } if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { /* * If the address went un-reachable, we need to move to * alternates for ALL chk's in queue */ sctp_move_chunks_from_net(stcb, net); } /* mark the retran info */ if (strrst->sent != SCTP_DATAGRAM_RESEND) sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); strrst->sent = SCTP_DATAGRAM_RESEND; /* restart the timer */ sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, inp, stcb, strrst->whoTo); return (0); } int sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net) { struct sctp_nets *alt; struct sctp_tmit_chunk *asconf, *chk; /* is this a first send, or a retransmission? */ if (TAILQ_EMPTY(&stcb->asoc.asconf_send_queue)) { /* compose a new ASCONF chunk and send it */ sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED); } else { /* * Retransmission of the existing ASCONF is needed */ /* find the existing ASCONF */ asconf = TAILQ_FIRST(&stcb->asoc.asconf_send_queue); if (asconf == NULL) { return (0); } /* do threshold management */ if (sctp_threshold_management(inp, stcb, asconf->whoTo, stcb->asoc.max_send_times)) { /* Assoc is over */ return (1); } if (asconf->snd_count > stcb->asoc.max_send_times) { /* * Something is rotten: our peer is not responding * to ASCONFs but apparently is to other chunks. * i.e. it is not properly handling the chunk type * upper bits. Mark this peer as ASCONF incapable * and cleanup. */ SCTPDBG(SCTP_DEBUG_TIMER1, "asconf_timer: Peer has not responded to our repeated ASCONFs\n"); sctp_asconf_cleanup(stcb, net); return (0); } /* * cleared threshold management, so now backoff the net and * select an alternate */ sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0, 0); alt = sctp_find_alternate_net(stcb, asconf->whoTo, 0); if (asconf->whoTo != alt) { sctp_free_remote_addr(asconf->whoTo); asconf->whoTo = alt; atomic_add_int(&alt->ref_count, 1); } /* See if an ECN Echo is also stranded */ TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { if ((chk->whoTo == net) && (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { sctp_free_remote_addr(chk->whoTo); chk->whoTo = alt; if (chk->sent != SCTP_DATAGRAM_RESEND) { chk->sent = SCTP_DATAGRAM_RESEND; sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); } atomic_add_int(&alt->ref_count, 1); } } TAILQ_FOREACH(chk, &stcb->asoc.asconf_send_queue, sctp_next) { if (chk->whoTo != alt) { sctp_free_remote_addr(chk->whoTo); chk->whoTo = alt; atomic_add_int(&alt->ref_count, 1); } if (asconf->sent != SCTP_DATAGRAM_RESEND && chk->sent != SCTP_DATAGRAM_UNSENT) sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); chk->sent = SCTP_DATAGRAM_RESEND; } if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { /* * If the address went un-reachable, we need to move * to the alternate for ALL chunks in queue */ sctp_move_chunks_from_net(stcb, net); } /* mark the retran info */ if (asconf->sent != SCTP_DATAGRAM_RESEND) sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); asconf->sent = SCTP_DATAGRAM_RESEND; /* send another ASCONF if any and we can do */ sctp_send_asconf(stcb, alt, SCTP_ADDR_NOT_LOCKED); } return (0); } /* Mobility adaptation */ void sctp_delete_prim_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED) { if (stcb->asoc.deleted_primary == NULL) { SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: deleted_primary is not stored...\n"); sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); return; } SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: finished to keep deleted primary "); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa); sctp_free_remote_addr(stcb->asoc.deleted_primary); stcb->asoc.deleted_primary = NULL; sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); return; } /* * For the shutdown and shutdown-ack, we do not keep one around on the * control queue. This means we must generate a new one and call the general * chunk output routine, AFTER having done threshold management. * It is assumed that net is non-NULL. */ int sctp_shutdown_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net) { struct sctp_nets *alt; /* first threshold managment */ if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { /* Assoc is over */ return (1); } sctp_backoff_on_timeout(stcb, net, 1, 0, 0); /* second select an alternative */ alt = sctp_find_alternate_net(stcb, net, 0); /* third generate a shutdown into the queue for out net */ sctp_send_shutdown(stcb, alt); /* fourth restart timer */ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, alt); return (0); } int sctp_shutdownack_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net) { struct sctp_nets *alt; /* first threshold managment */ if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { /* Assoc is over */ return (1); } sctp_backoff_on_timeout(stcb, net, 1, 0, 0); /* second select an alternative */ alt = sctp_find_alternate_net(stcb, net, 0); /* third generate a shutdown into the queue for out net */ sctp_send_shutdown_ack(stcb, alt); /* fourth restart timer */ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, alt); return (0); } static void sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp, struct sctp_tcb *stcb) { struct sctp_stream_queue_pending *sp; unsigned int i, chks_in_queue = 0; int being_filled = 0; /* * This function is ONLY called when the send/sent queues are empty. */ if ((stcb == NULL) || (inp == NULL)) return; if (stcb->asoc.sent_queue_retran_cnt) { SCTP_PRINTF("Hmm, sent_queue_retran_cnt is non-zero %d\n", stcb->asoc.sent_queue_retran_cnt); stcb->asoc.sent_queue_retran_cnt = 0; } if (stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, &stcb->asoc)) { /* No stream scheduler information, initialize scheduler */ stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 0); if (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, &stcb->asoc)) { /* yep, we lost a stream or two */ SCTP_PRINTF("Found additional streams NOT managed by scheduler, corrected\n"); } else { /* no streams lost */ stcb->asoc.total_output_queue_size = 0; } } /* Check to see if some data queued, if so report it */ for (i = 0; i < stcb->asoc.streamoutcnt; i++) { if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { TAILQ_FOREACH(sp, &stcb->asoc.strmout[i].outqueue, next) { if (sp->msg_is_complete) being_filled++; chks_in_queue++; } } } if (chks_in_queue != stcb->asoc.stream_queue_cnt) { SCTP_PRINTF("Hmm, stream queue cnt at %d I counted %d in stream out wheel\n", stcb->asoc.stream_queue_cnt, chks_in_queue); } if (chks_in_queue) { /* call the output queue function */ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); if ((TAILQ_EMPTY(&stcb->asoc.send_queue)) && (TAILQ_EMPTY(&stcb->asoc.sent_queue))) { /* * Probably should go in and make it go back through * and add fragments allowed */ if (being_filled == 0) { SCTP_PRINTF("Still nothing moved %d chunks are stuck\n", chks_in_queue); } } } else { SCTP_PRINTF("Found no chunks on any queue tot:%lu\n", (u_long)stcb->asoc.total_output_queue_size); stcb->asoc.total_output_queue_size = 0; } } int sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net) { uint8_t net_was_pf; if (net->dest_state & SCTP_ADDR_PF) { net_was_pf = 1; } else { net_was_pf = 0; } if (net->hb_responded == 0) { if (net->ro._s_addr) { /* * Invalidate the src address if we did not get a * response last time. */ sctp_free_ifa(net->ro._s_addr); net->ro._s_addr = NULL; net->src_addr_selected = 0; } sctp_backoff_on_timeout(stcb, net, 1, 0, 0); if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { /* Assoc is over */ return (1); } } /* Zero PBA, if it needs it */ if (net->partial_bytes_acked) { net->partial_bytes_acked = 0; } if ((stcb->asoc.total_output_queue_size > 0) && (TAILQ_EMPTY(&stcb->asoc.send_queue)) && (TAILQ_EMPTY(&stcb->asoc.sent_queue))) { sctp_audit_stream_queues_for_size(inp, stcb); } if (!(net->dest_state & SCTP_ADDR_NOHB) && !((net_was_pf == 0) && (net->dest_state & SCTP_ADDR_PF))) { /* * when move to PF during threshold mangement, a HB has been * queued in that routine */ uint32_t ms_gone_by; if ((net->last_sent_time.tv_sec > 0) || (net->last_sent_time.tv_usec > 0)) { struct timeval diff; SCTP_GETTIME_TIMEVAL(&diff); timevalsub(&diff, &net->last_sent_time); ms_gone_by = (uint32_t) (diff.tv_sec * 1000) + (uint32_t) (diff.tv_usec / 1000); } else { ms_gone_by = 0xffffffff; } if ((ms_gone_by >= net->heart_beat_delay) || (net->dest_state & SCTP_ADDR_PF)) { sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); } } return (0); } void sctp_pathmtu_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net) { uint32_t next_mtu, mtu; next_mtu = sctp_get_next_mtu(net->mtu); if ((next_mtu > net->mtu) && (net->port == 0)) { if ((net->src_addr_selected == 0) || (net->ro._s_addr == NULL) || (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) { if ((net->ro._s_addr != NULL) && (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) { sctp_free_ifa(net->ro._s_addr); net->ro._s_addr = NULL; net->src_addr_selected = 0; } else if (net->ro._s_addr == NULL) { #if defined(INET6) && defined(SCTP_EMBEDDED_V6_SCOPE) if (net->ro._l_addr.sa.sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; /* KAME hack: embed scopeid */ (void)sa6_embedscope(sin6, MODULE_GLOBAL(ip6_use_defzone)); } #endif net->ro._s_addr = sctp_source_address_selection(inp, stcb, (sctp_route_t *) & net->ro, net, 0, stcb->asoc.vrf_id); #if defined(INET6) && defined(SCTP_EMBEDDED_V6_SCOPE) if (net->ro._l_addr.sa.sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; (void)sa6_recoverscope(sin6); } #endif /* INET6 */ } if (net->ro._s_addr) net->src_addr_selected = 1; } if (net->ro._s_addr) { mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._s_addr.sa, net->ro.ro_rt); #if defined(INET) || defined(INET6) if (net->port) { mtu -= sizeof(struct udphdr); } #endif if (mtu > next_mtu) { net->mtu = next_mtu; } else { net->mtu = mtu; } } } /* restart the timer */ sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); } void sctp_autoclose_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net) { struct timeval tn, *tim_touse; struct sctp_association *asoc; int ticks_gone_by; (void)SCTP_GETTIME_TIMEVAL(&tn); if (stcb->asoc.sctp_autoclose_ticks && sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) { /* Auto close is on */ asoc = &stcb->asoc; /* pick the time to use */ if (asoc->time_last_rcvd.tv_sec > asoc->time_last_sent.tv_sec) { tim_touse = &asoc->time_last_rcvd; } else { tim_touse = &asoc->time_last_sent; } /* Now has long enough transpired to autoclose? */ ticks_gone_by = SEC_TO_TICKS(tn.tv_sec - tim_touse->tv_sec); if ((ticks_gone_by > 0) && (ticks_gone_by >= (int)asoc->sctp_autoclose_ticks)) { /* * autoclose time has hit, call the output routine, * which should do nothing just to be SURE we don't * have hanging data. We can then safely check the * queues and know that we are clear to send * shutdown */ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED); /* Are we clean? */ if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue)) { /* * there is nothing queued to send, so I'm * done... */ if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { /* only send SHUTDOWN 1st time thru */ struct sctp_nets *netp; if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); sctp_stop_timers_for_shutdown(stcb); if (stcb->asoc.alternate) { netp = stcb->asoc.alternate; } else { netp = stcb->asoc.primary_destination; } sctp_send_shutdown(stcb, netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, netp); } } } else { /* * No auto close at this time, reset t-o to check * later */ int tmp; /* fool the timer startup to use the time left */ tmp = asoc->sctp_autoclose_ticks; asoc->sctp_autoclose_ticks -= ticks_gone_by; sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, net); /* restore the real tick value */ asoc->sctp_autoclose_ticks = tmp; } } } Index: projects/collation/sys =================================================================== --- projects/collation/sys (revision 289266) +++ projects/collation/sys (revision 289267) Property changes on: projects/collation/sys ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys:r289239-289266 Index: projects/collation/usr.bin/truss/amd64-fbsd.c =================================================================== --- projects/collation/usr.bin/truss/amd64-fbsd.c (revision 289266) +++ projects/collation/usr.bin/truss/amd64-fbsd.c (nonexistent) @@ -1,131 +0,0 @@ -/* - * Copyright 1997 Sean Eric Fagan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Sean Eric Fagan - * 4. Neither the name of the author may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* FreeBSD/amd64-specific system call handling. */ - -#include -#include - -#include -#include - -#include - -#include "truss.h" - -#include "syscalls.h" - -static int -amd64_fetch_args(struct trussinfo *trussinfo, u_int narg) -{ - struct ptrace_io_desc iorequest; - struct reg regs; - struct current_syscall *cs; - lwpid_t tid; - u_int i, reg; - - tid = trussinfo->curthread->tid; - cs = &trussinfo->curthread->cs; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - /* - * FreeBSD has two special kinds of system call redirections -- - * SYS_syscall, and SYS___syscall. The former is the old syscall() - * routine, basically; the latter is for quad-aligned arguments. - * - * The system call argument count and code from ptrace() already - * account for these, but we need to skip over %rax if it contains - * either of these values. - */ - reg = 0; - switch (regs.r_rax) { - case SYS_syscall: - case SYS___syscall: - reg++; - break; - } - - for (i = 0; i < narg && reg < 6; i++, reg++) { - switch (reg) { - case 0: cs->args[i] = regs.r_rdi; break; - case 1: cs->args[i] = regs.r_rsi; break; - case 2: cs->args[i] = regs.r_rdx; break; - case 3: cs->args[i] = regs.r_rcx; break; - case 4: cs->args[i] = regs.r_r8; break; - case 5: cs->args[i] = regs.r_r9; break; - } - } - if (narg > i) { - iorequest.piod_op = PIOD_READ_D; - iorequest.piod_offs = (void *)(regs.r_rsp + sizeof(register_t)); - iorequest.piod_addr = &cs->args[i]; - iorequest.piod_len = (narg - i) * sizeof(register_t); - ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); - if (iorequest.piod_len == 0) - return (-1); - } - - return (0); -} - -static int -amd64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) -{ - struct reg regs; - lwpid_t tid; - - tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - retval[0] = regs.r_rax; - retval[1] = regs.r_rdx; - *errorp = !!(regs.r_rflags & PSL_C); - return (0); -} - -static struct procabi amd64_fbsd = { - "FreeBSD ELF64", - syscallnames, - nitems(syscallnames), - amd64_fetch_args, - amd64_fetch_retval -}; - -PROCABI(amd64_fbsd); Property changes on: projects/collation/usr.bin/truss/amd64-fbsd.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/i386linux.conf =================================================================== --- projects/collation/usr.bin/truss/i386linux.conf (revision 289266) +++ projects/collation/usr.bin/truss/i386linux.conf (nonexistent) @@ -1,13 +0,0 @@ -# $FreeBSD$ - -sysnames="linux_syscalls.h" -sysproto="/dev/null" -sysproto_h="/dev/null" -syshdr="/dev/null" -sysmk="/dev/null" -syssw="/dev/null" -syshide="/dev/null" -syscallprefix="SYS_" -switchname="sysent" -namesname="linux_syscallnames" -systrace="/dev/null" Property changes on: projects/collation/usr.bin/truss/i386linux.conf ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/arm-fbsd.c =================================================================== --- projects/collation/usr.bin/truss/arm-fbsd.c (revision 289266) +++ projects/collation/usr.bin/truss/arm-fbsd.c (nonexistent) @@ -1,138 +0,0 @@ -/* - * Copyright 1997 Sean Eric Fagan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Sean Eric Fagan - * 4. Neither the name of the author may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* FreeBSD/arm-specific system call handling. */ - -#include -#include - -#include -#include -#include - -#include - -#include "truss.h" - -#include "syscalls.h" - -static int -arm_fetch_args(struct trussinfo *trussinfo, u_int narg) -{ - struct ptrace_io_desc iorequest; - struct reg regs; - struct current_syscall *cs; - lwpid_t tid; - u_int i, reg, syscall_num; - - tid = trussinfo->curthread->tid; - cs = &trussinfo->curthread->cs; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - /* - * FreeBSD has two special kinds of system call redirections -- - * SYS_syscall, and SYS___syscall. The former is the old syscall() - * routine, basically; the latter is for quad-aligned arguments. - * - * The system call argument count and code from ptrace() already - * account for these, but we need to skip over the first argument. - */ -#ifdef __ARM_EABI__ - syscall_num = regs.r[7]; -#else - if ((syscall_num = ptrace(PT_READ_I, tid, - (caddr_t)(regs.r[_REG_PC] - INSN_SIZE), 0)) == -1) { - fprintf(trussinfo->outfile, "-- CANNOT READ PC --\n"); - return (-1); - } - syscall_num = syscall_num & 0x000fffff; -#endif - - reg = 0; - switch (syscall_num) { - case SYS_syscall: - reg = 1; - break; - case SYS___syscall: - reg = 2; - break; - } - - for (i = 0; i < narg && reg < 4; i++, reg++) - cs->args[i] = regs.r[reg]; - if (narg > i) { - iorequest.piod_op = PIOD_READ_D; - iorequest.piod_offs = (void *)(regs.r_sp + - 4 * sizeof(uint32_t)); - iorequest.piod_addr = &cs->args[i]; - iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); - ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); - if (iorequest.piod_len == 0) - return (-1); - } - - return (0); -} - -static int -arm_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) -{ - struct reg regs; - lwpid_t tid; - - tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - /* XXX: Does not have the __ARMEB__ handling for __syscall(). */ - retval[0] = regs.r[0]; - retval[1] = regs.r[1]; - *errorp = !!(regs.r_cpsr & PSR_C); - return (0); -} - -static struct procabi arm_fbsd = { - "FreeBSD ELF32", - syscallnames, - nitems(syscallnames), - arm_fetch_args, - arm_fetch_retval -}; - -PROCABI(arm_fbsd); Property changes on: projects/collation/usr.bin/truss/arm-fbsd.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/collation/usr.bin/truss/fbsd32.conf =================================================================== --- projects/collation/usr.bin/truss/fbsd32.conf (revision 289266) +++ projects/collation/usr.bin/truss/fbsd32.conf (nonexistent) @@ -1,13 +0,0 @@ -# $FreeBSD$ - -sysnames="freebsd32_syscalls.h" -sysproto="/dev/null" -sysproto_h="/dev/null" -syshdr="/dev/null" -sysmk="/dev/null" -syssw="/dev/null" -syshide="/dev/null" -syscallprefix="SYS_" -switchname="sysent" -namesname="freebsd32_syscallnames" -systrace="/dev/null" Property changes on: projects/collation/usr.bin/truss/fbsd32.conf ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/aarch64-fbsd.c =================================================================== --- projects/collation/usr.bin/truss/aarch64-fbsd.c (revision 289266) +++ projects/collation/usr.bin/truss/aarch64-fbsd.c (nonexistent) @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2015 The FreeBSD Foundation - * - * Portions of this software were developed by Konstantin Belousov - * under sponsorship from the FreeBSD Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* FreeBSD/arm64-specific system call handling. */ - -#include -#include - -#include -#include -#include - -#include - -#include "truss.h" - -extern const char *syscallnames[]; /* silence compiler */ -#include "syscalls.h" - -static int -aarch64_fetch_args(struct trussinfo *trussinfo, u_int narg) -{ - struct reg regs; - struct current_syscall *cs; - lwpid_t tid; - u_int i, reg, syscall_num; - - tid = trussinfo->curthread->tid; - cs = &trussinfo->curthread->cs; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - /* - * FreeBSD has two special kinds of system call redirections -- - * SYS_syscall, and SYS___syscall. The former is the old syscall() - * routine, basically; the latter is for quad-aligned arguments. - * - * The system call argument count and code from ptrace() already - * account for these, but we need to skip over the first argument. - */ - syscall_num = regs.x[8]; - if (syscall_num == SYS_syscall || syscall_num == SYS___syscall) { - reg = 1; - syscall_num = regs.x[0]; - } else { - reg = 0; - } - - for (i = 0; i < narg && reg < 8; i++, reg++) - cs->args[i] = regs.x[reg]; - return (0); -} - -static int -aarch64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) -{ - struct reg regs; - lwpid_t tid; - - tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - retval[0] = regs.x[0]; - retval[1] = regs.x[1]; - *errorp = !!(regs.spsr & PSR_C); - return (0); -} - -static struct procabi aarch64_fbsd = { - "FreeBSD ELF64", - syscallnames, - nitems(syscallnames), - aarch64_fetch_args, - aarch64_fetch_retval -}; - -PROCABI(aarch64_fbsd); Property changes on: projects/collation/usr.bin/truss/aarch64-fbsd.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/collation/usr.bin/truss/i386.conf =================================================================== --- projects/collation/usr.bin/truss/i386.conf (revision 289266) +++ projects/collation/usr.bin/truss/i386.conf (nonexistent) @@ -1,13 +0,0 @@ -# $FreeBSD$ - -sysnames="syscalls.h" -sysproto="/dev/null" -sysproto_h="/dev/null" -syshdr="/dev/null" -sysmk="/dev/null" -syssw="/dev/null" -syshide="/dev/null" -syscallprefix="SYS_" -switchname="sysent" -namesname="syscallnames" -systrace="/dev/null" Property changes on: projects/collation/usr.bin/truss/i386.conf ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/sparc64-fbsd.c =================================================================== --- projects/collation/usr.bin/truss/sparc64-fbsd.c (revision 289266) +++ projects/collation/usr.bin/truss/sparc64-fbsd.c (nonexistent) @@ -1,125 +0,0 @@ -/* - * Copyright 1998 Sean Eric Fagan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Sean Eric Fagan - * 4. Neither the name of the author may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* FreeBSD/sparc64-specific system call handling. */ - -#include -#include - -#include -#include -#include - -#include -#include - -#include "truss.h" - -#include "syscalls.h" - -static int -sparc64_fetch_args(struct trussinfo *trussinfo, u_int narg) -{ - struct ptrace_io_desc iorequest; - struct reg regs; - struct current_syscall *cs; - lwpid_t tid; - u_int i, reg; - - tid = trussinfo->curthread->tid; - cs = &trussinfo->curthread->cs; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - /* - * FreeBSD has two special kinds of system call redirections -- - * SYS_syscall, and SYS___syscall. The former is the old syscall() - * routine, basically; the latter is for quad-aligned arguments. - * - * The system call argument count and code from ptrace() already - * account for these, but we need to skip over the first argument. - */ - reg = 0; - switch (regs.r_global[1]) { - case SYS_syscall: - case SYS___syscall: - reg = 1; - break; - } - - for (i = 0; i < narg && reg < 6; i++, reg++) - cs->args[i] = regs.r_out[reg]; - if (narg > i) { - iorequest.piod_op = PIOD_READ_D; - iorequest.piod_offs = (void *)(regs.r_out[6] + SPOFF + - offsetof(struct frame, fr_pad[6])); - iorequest.piod_addr = &cs->args[i]; - iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); - ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); - if (iorequest.piod_len == 0) - return (-1); - } - - return (0); -} - -static int -sparc64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) -{ - struct reg regs; - lwpid_t tid; - - tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - retval[0] = regs.r_out[0]; - retval[1] = regs.r_out[1]; - *errorp = !!(regs.r_tstate & TSTATE_XCC_C); - return (0); -} - -static struct procabi sparc64_fbsd = { - "FreeBSD ELF64", - syscallnames, - nitems(syscallnames), - sparc64_fetch_args, - sparc64_fetch_retval -}; - -PROCABI(sparc64_fbsd); Property changes on: projects/collation/usr.bin/truss/sparc64-fbsd.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/amd64linux32.conf =================================================================== --- projects/collation/usr.bin/truss/amd64linux32.conf (revision 289266) +++ projects/collation/usr.bin/truss/amd64linux32.conf (nonexistent) @@ -1,13 +0,0 @@ -# $FreeBSD$ - -sysnames="linux32_syscalls.h" -sysproto="/dev/null" -sysproto_h="/dev/null" -syshdr="/dev/null" -sysmk="/dev/null" -syssw="/dev/null" -syshide="/dev/null" -syscallprefix="SYS_" -switchname="sysent" -namesname="linux32_syscallnames" -systrace="/dev/null" Property changes on: projects/collation/usr.bin/truss/amd64linux32.conf ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/amd64-fbsd32.c =================================================================== --- projects/collation/usr.bin/truss/amd64-fbsd32.c (revision 289266) +++ projects/collation/usr.bin/truss/amd64-fbsd32.c (nonexistent) @@ -1,137 +0,0 @@ -/* - * Copyright 1997 Sean Eric Fagan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Sean Eric Fagan - * 4. Neither the name of the author may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* FreeBSD/i386-specific system call handling. */ - -#include -#include - -#include -#include - -#include -#include - -#include "truss.h" - -#include "freebsd32_syscalls.h" - -static int -amd64_fbsd32_fetch_args(struct trussinfo *trussinfo, u_int narg) -{ - struct ptrace_io_desc iorequest; - struct reg regs; - struct current_syscall *cs; - unsigned int args32[narg]; - unsigned long parm_offset; - lwpid_t tid; - u_int i; - - tid = trussinfo->curthread->tid; - cs = &trussinfo->curthread->cs; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - parm_offset = regs.r_rsp + sizeof(int); - - /* - * FreeBSD has two special kinds of system call redirections -- - * SYS_syscall, and SYS___syscall. The former is the old syscall() - * routine, basically; the latter is for quad-aligned arguments. - * - * The system call argument count and code from ptrace() already - * account for these, but we need to skip over the first argument. - */ - switch (regs.r_rax) { - case SYS_syscall: - parm_offset += sizeof(int); - break; - case SYS___syscall: - parm_offset += sizeof(quad_t); - break; - } - - iorequest.piod_op = PIOD_READ_D; - iorequest.piod_offs = (void *)parm_offset; - iorequest.piod_addr = args32; - iorequest.piod_len = sizeof(args32); - ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); - if (iorequest.piod_len == 0) { - return (-1); - } - - for (i = 0; i < narg; i++) - cs->args[i] = args32[i]; - return (0); -} - -static int -amd64_fbsd32_fetch_retval(struct trussinfo *trussinfo, long *retval, - int *errorp) -{ - struct reg regs; - lwpid_t tid; - - tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - retval[0] = regs.r_rax & 0xffffffff; - retval[1] = regs.r_rdx & 0xffffffff; - *errorp = !!(regs.r_rflags & PSL_C); - return (0); -} - -static struct procabi amd64_fbsd32 = { - "FreeBSD ELF32", - freebsd32_syscallnames, - nitems(freebsd32_syscallnames), - amd64_fbsd32_fetch_args, - amd64_fbsd32_fetch_retval -}; - -PROCABI(amd64_fbsd32); - -static struct procabi amd64_fbsd32_aout = { - "FreeBSD a.out", - freebsd32_syscallnames, - nitems(freebsd32_syscallnames), - amd64_fbsd32_fetch_args, - amd64_fbsd32_fetch_retval -}; - -PROCABI(amd64_fbsd32_aout); Property changes on: projects/collation/usr.bin/truss/amd64-fbsd32.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/i386-fbsd.c =================================================================== --- projects/collation/usr.bin/truss/i386-fbsd.c (revision 289266) +++ projects/collation/usr.bin/truss/i386-fbsd.c (nonexistent) @@ -1,131 +0,0 @@ -/* - * Copyright 1997 Sean Eric Fagan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Sean Eric Fagan - * 4. Neither the name of the author may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* FreeBSD/i386-specific system call handling. */ - -#include -#include - -#include -#include - -#include - -#include "truss.h" - -#include "syscalls.h" - -static int -i386_fetch_args(struct trussinfo *trussinfo, u_int narg) -{ - struct ptrace_io_desc iorequest; - struct reg regs; - struct current_syscall *cs; - lwpid_t tid; - unsigned int parm_offset; - - tid = trussinfo->curthread->tid; - cs = &trussinfo->curthread->cs; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - parm_offset = regs.r_esp + sizeof(int); - - /* - * FreeBSD has two special kinds of system call redirections -- - * SYS_syscall, and SYS___syscall. The former is the old syscall() - * routine, basically; the latter is for quad-aligned arguments. - * - * The system call argument count and code from ptrace() already - * account for these, but we need to skip over the first argument. - */ - switch (regs.r_eax) { - case SYS_syscall: - parm_offset += sizeof(int); - break; - case SYS___syscall: - parm_offset += sizeof(quad_t); - break; - } - - iorequest.piod_op = PIOD_READ_D; - iorequest.piod_offs = (void *)parm_offset; - iorequest.piod_addr = cs->args; - iorequest.piod_len = narg * sizeof(unsigned long); - ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); - if (iorequest.piod_len == 0) - return (-1); - - return (0); -} - -static int -i386_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) -{ - struct reg regs; - lwpid_t tid; - - tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - retval[0] = regs.r_eax; - retval[1] = regs.r_edx; - *errorp = !!(regs.r_eflags & PSL_C); - return (0); -} - -static struct procabi i386_fbsd = { - "FreeBSD ELF32", - syscallnames, - nitems(syscallnames), - i386_fetch_args, - i386_fetch_retval -}; - -PROCABI(i386_fbsd); - -static struct procabi i386_fbsd_aout = { - "FreeBSD a.out", - syscallnames, - nitems(syscallnames), - i386_fetch_args, - i386_fetch_retval -}; - -PROCABI(i386_fbsd_aout); - Property changes on: projects/collation/usr.bin/truss/i386-fbsd.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/mips-fbsd.c =================================================================== --- projects/collation/usr.bin/truss/mips-fbsd.c (revision 289266) +++ projects/collation/usr.bin/truss/mips-fbsd.c (nonexistent) @@ -1,141 +0,0 @@ -/* - * Copyright 1998 Sean Eric Fagan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Sean Eric Fagan - * 4. Neither the name of the author may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* FreeBSD/mips-specific system call handling. */ - -#include -#include - -#include -#include - -#include - -#include "truss.h" - -#include "syscalls.h" - -static int -mips_fetch_args(struct trussinfo *trussinfo, u_int narg) -{ - struct ptrace_io_desc iorequest; - struct reg regs; - struct current_syscall *cs; - lwpid_t tid; - u_int i, reg; - - tid = trussinfo->curthread->tid; - cs = &trussinfo->curthread->cs; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - /* - * FreeBSD has two special kinds of system call redirections -- - * SYS_syscall, and SYS___syscall. The former is the old syscall() - * routine, basically; the latter is for quad-aligned arguments. - * - * The system call argument count and code from ptrace() already - * account for these, but we need to skip over the first argument. - */ - reg = A0; - switch (regs.r_regs[V0]) { - case SYS_syscall: - reg = A1; - break; - case SYS___syscall: -#if defined(__mips_n32) || defined(__mips_n64) - reg = A1; -#else - reg = A2; -#endif - break; - } - -#if defined(__mips_n32) || defined(__mips_n64) -#define MAXREG A7 -#else -#define MAXREG A3 -#endif - - for (i = 0; i < narg && reg <= MAXREG; i++, reg++) - cs->args[i] = regs.r_regs[reg]; - if (narg > i) { - iorequest.piod_op = PIOD_READ_D; - iorequest.piod_offs = (void *)((uintptr_t)regs.r_regs[SP] + - 4 * sizeof(cs->args[0])); - iorequest.piod_addr = &cs->args[i]; - iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); - ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); - if (iorequest.piod_len == 0) - return (-1); - } - - return (0); -} - -static int -mips_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) -{ - struct reg regs; - lwpid_t tid; - - tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - /* XXX: Does not have special handling for __syscall(). */ - retval[0] = regs.r_regs[V0]; - retval[1] = regs.r_regs[V1]; - *errorp = !!regs.r_regs[A3]; - return (0); -} - - -static struct procabi mips_fbsd = { -#ifdef __mips_n64 - "FreeBSD ELF64", -#else - "FreeBSD ELF32", -#endif - syscallnames, - nitems(syscallnames), - mips_fetch_args, - mips_fetch_retval -}; - -PROCABI(mips_fbsd); Property changes on: projects/collation/usr.bin/truss/mips-fbsd.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/collation/usr.bin/truss/powerpc-fbsd.c =================================================================== --- projects/collation/usr.bin/truss/powerpc-fbsd.c (revision 289266) +++ projects/collation/usr.bin/truss/powerpc-fbsd.c (nonexistent) @@ -1,150 +0,0 @@ -/* - * Copyright 2006 Peter Grehan - * Copyright 2005 Orlando Bassotto - * Copyright 1998 Sean Eric Fagan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* FreeBSD/powerpc-specific system call handling. */ - -#include -#include - -#include -#include - -#include - -#include "truss.h" - -#ifdef __powerpc64__ /* 32-bit compatibility */ -#include "freebsd32_syscalls.h" -#define syscallnames freebsd32_syscallnames -#else /* native 32-bit */ -#include "syscalls.h" -#endif - -static int -powerpc_fetch_args(struct trussinfo *trussinfo, u_int narg) -{ - struct ptrace_io_desc iorequest; - struct reg regs; - struct current_syscall *cs; - lwpid_t tid; - u_int i, reg; - - tid = trussinfo->curthread->tid; - cs = &trussinfo->curthread->cs; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - /* - * FreeBSD has two special kinds of system call redirections -- - * SYS_syscall, and SYS___syscall. The former is the old syscall() - * routine, basically; the latter is for quad-aligned arguments. - * - * The system call argument count and code from ptrace() already - * account for these, but we need to skip over the first argument. - */ - reg = 0; - switch (regs.fixreg[0]) { - case SYS_syscall: - reg += 1; - break; - case SYS___syscall: - reg += 2; - break; - } - - for (i = 0; i < narg && reg < NARGREG; i++, reg++) { -#ifdef __powerpc64__ - cs->args[i] = regs.fixreg[FIRSTARG + reg] & 0xffffffff; -#else - cs->args[i] = regs.fixreg[FIRSTARG + reg]; -#endif - } - if (narg > i) { -#ifdef __powerpc64__ - uint32_t args32[narg - i]; - u_int j; - -#endif - iorequest.piod_op = PIOD_READ_D; - iorequest.piod_offs = (void *)(regs.fixreg[1] + 8); -#ifdef __powerpc64__ - iorequest.piod_addr = args32; - iorequest.piod_len = sizeof(args32); -#else - iorequest.piod_addr = &cs->args[i]; - iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); -#endif - ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); - if (iorequest.piod_len == 0) - return (-1); -#ifdef __powerpc64__ - for (j = 0; j < narg - i; j++) - cs->args[i + j] = args32[j]; -#endif - } - - return (0); -} - -static int -powerpc_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) -{ - struct reg regs; - lwpid_t tid; - - tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - /* XXX: Does not have fixup for __syscall(). */ -#ifdef __powerpc64__ - retval[0] = regs.fixreg[3] & 0xffffffff; - retval[1] = regs.fixreg[4] & 0xffffffff; -#else - retval[0] = regs.fixreg[3]; - retval[1] = regs.fixreg[4]; -#endif - *errorp = !!(regs.cr & 0x10000000); - return (0); -} - -static struct procabi powerpc_fbsd = { - "FreeBSD ELF32", - syscallnames, - nitems(syscallnames), - powerpc_fetch_args, - powerpc_fetch_retval -}; - -PROCABI(powerpc_fbsd); Property changes on: projects/collation/usr.bin/truss/powerpc-fbsd.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/amd64cloudabi64.conf =================================================================== --- projects/collation/usr.bin/truss/amd64cloudabi64.conf (revision 289266) +++ projects/collation/usr.bin/truss/amd64cloudabi64.conf (nonexistent) @@ -1,13 +0,0 @@ -# $FreeBSD$ - -sysnames="cloudabi64_syscalls.h" -sysproto="/dev/null" -sysproto_h="/dev/null" -syshdr="/dev/null" -sysmk="/dev/null" -syssw="/dev/null" -syshide="/dev/null" -syscallprefix="SYS_" -switchname="sysent" -namesname="cloudabi64_syscallnames" -systrace="/dev/null" Property changes on: projects/collation/usr.bin/truss/amd64cloudabi64.conf ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/collation/usr.bin/truss/powerpc64-fbsd.c =================================================================== --- projects/collation/usr.bin/truss/powerpc64-fbsd.c (revision 289266) +++ projects/collation/usr.bin/truss/powerpc64-fbsd.c (nonexistent) @@ -1,118 +0,0 @@ -/* - * Copyright 2006 Peter Grehan - * Copyright 2005 Orlando Bassotto - * Copyright 1998 Sean Eric Fagan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* FreeBSD/powerpc64-specific system call handling. */ - -#include -#include - -#include -#include - -#include - -#include "truss.h" - -#include "syscalls.h" - -static int -powerpc64_fetch_args(struct trussinfo *trussinfo, u_int narg) -{ - struct ptrace_io_desc iorequest; - struct reg regs; - struct current_syscall *cs; - lwpid_t tid; - u_int i, reg; - - tid = trussinfo->curthread->tid; - cs = &trussinfo->curthread->cs; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - /* - * FreeBSD has two special kinds of system call redirections -- - * SYS_syscall, and SYS___syscall. The former is the old syscall() - * routine, basically; the latter is for quad-aligned arguments. - * - * The system call argument count and code from ptrace() already - * account for these, but we need to skip over the first argument. - */ - reg = 0; - switch (regs.fixreg[0]) { - case SYS_syscall: - case SYS___syscall: - reg += 1; - break; - } - - for (i = 0; i < narg && reg < NARGREG; i++, reg++) - cs->args[i] = regs.fixreg[FIRSTARG + reg]; - if (narg > i) { - iorequest.piod_op = PIOD_READ_D; - iorequest.piod_offs = (void *)(regs.fixreg[1] + 48); - iorequest.piod_addr = &cs->args[i]; - iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); - ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); - if (iorequest.piod_len == 0) - return (-1); - } - - return (0); -} - -static int -powerpc64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) -{ - struct reg regs; - lwpid_t tid; - - tid = trussinfo->curthread->tid; - if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { - fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); - return (-1); - } - - retval[0] = regs.fixreg[3]; - retval[1] = regs.fixreg[4]; - *errorp = !!(regs.cr & 0x10000000); - return (0); -} - -static struct procabi powerpc64_fbsd = { - "FreeBSD ELF64", - syscallnames, - nitems(syscallnames), - powerpc64_fetch_args, - powerpc64_fetch_retval -}; - -PROCABI(powerpc64_fbsd); Property changes on: projects/collation/usr.bin/truss/powerpc64-fbsd.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/Makefile =================================================================== --- projects/collation/usr.bin/truss/Makefile (revision 289266) +++ projects/collation/usr.bin/truss/Makefile (revision 289267) @@ -1,88 +1,65 @@ # $FreeBSD$ NO_WERROR= PROG= truss -SRCS= main.c setup.c syscalls.c syscalls.h ioctl.c +SRCS= main.c setup.c syscalls.c ioctl.c -.if exists(${.CURDIR}/${MACHINE_ARCH}-fbsd.c) -SRCS+= ${MACHINE_ARCH}-fbsd.c -.else -SRCS+= ${MACHINE_CPUARCH}-fbsd.c -.endif - .PATH: ${.CURDIR:H}/kdump SRCS+= utrace.c CFLAGS+= -I${.CURDIR} -I. -I${.CURDIR}/../../sys -CLEANFILES= syscalls.master syscalls.h ioctl.c +CLEANFILES= ioctl.c -.SUFFIXES: .master - -syscalls.master: ${.CURDIR}/../../sys/kern/syscalls.master - cat ${.ALLSRC} > syscalls.master - -syscalls.h: syscalls.master - /bin/sh ${.CURDIR}/../../sys/kern/makesyscalls.sh syscalls.master \ - ${.CURDIR}/i386.conf - ioctl.c: ${.CURDIR}/../kdump/mkioctls env MACHINE=${MACHINE} CPP="${CPP}" \ /bin/sh ${.CURDIR}/../kdump/mkioctls return ${DESTDIR}${INCLUDEDIR} > ${.TARGET} -.if ${MACHINE_CPUARCH} == "i386" -SRCS+= i386-linux.c linux_syscalls.h -CLEANFILES+=i386l-syscalls.master linux_syscalls.h +# Define where to generate syscalls for each ABI. +ABI_SYSPATH.freebsd= sys/kern +ABI_SYSPATH.freebsd32= sys/compat/freebsd32 +ABI_SYSPATH.cloudabi64= sys/compat/cloudabi64 +ABI_SYSPATH.i386-linux= sys/i386/linux +ABI_SYSPATH.amd64-linux32= sys/amd64/linux32 -i386l-syscalls.master: ${.CURDIR}/../../sys/i386/linux/syscalls.master - cat ${.ALLSRC} > ${.TARGET} - -linux_syscalls.h: i386l-syscalls.master - /bin/sh ${.CURDIR}/../../sys/kern/makesyscalls.sh ${.ALLSRC} \ - ${.CURDIR}/i386linux.conf +ABIS+= freebsd +# Each ABI is expected to have an ABI.c, MACHINE_ARCH-ABI.c or +# MACHINE_CPUARCH-ABI.c file that will be used to map the syscall arguments. +.if ${MACHINE_CPUARCH} == "i386" +ABIS+= i386-linux .endif - .if ${MACHINE_CPUARCH} == "amd64" -SRCS+= amd64-linux32.c linux32_syscalls.h -CLEANFILES+=amd64l32-syscalls.master linux32_syscalls.h - -amd64l32-syscalls.master: ${.CURDIR}/../../sys/amd64/linux32/syscalls.master - cat ${.ALLSRC} > ${.TARGET} - -linux32_syscalls.h: amd64l32-syscalls.master - /bin/sh ${.CURDIR}/../../sys/kern/makesyscalls.sh ${.ALLSRC} \ - ${.CURDIR}/amd64linux32.conf - -SRCS+= amd64-fbsd32.c freebsd32_syscalls.h -CLEANFILES+=fbsd32-syscalls.master freebsd32_syscalls.h - -fbsd32-syscalls.master: ${.CURDIR}/../../sys/compat/freebsd32/syscalls.master - cat ${.ALLSRC} > ${.TARGET} - -freebsd32_syscalls.h: fbsd32-syscalls.master - /bin/sh ${.CURDIR}/../../sys/kern/makesyscalls.sh ${.ALLSRC} \ - ${.CURDIR}/fbsd32.conf - -SRCS+= amd64-cloudabi64.c cloudabi64_syscalls.h -CLEANFILES+=amd64cloudabi64-syscalls.master cloudabi64_syscalls.h - -amd64cloudabi64-syscalls.master: ${.CURDIR}/../../sys/compat/cloudabi64/syscalls.master - cat ${.ALLSRC} > ${.TARGET} - -cloudabi64_syscalls.h: amd64cloudabi64-syscalls.master - /bin/sh ${.CURDIR}/../../sys/kern/makesyscalls.sh ${.ALLSRC} \ - ${.CURDIR}/amd64cloudabi64.conf +ABIS+= amd64-linux32 +ABIS+= freebsd32 +ABIS+= cloudabi64 .endif - .if ${MACHINE_ARCH} == "powerpc64" -SRCS+= powerpc-fbsd.c freebsd32_syscalls.h -CLEANFILES+=fbsd32-syscalls.master freebsd32_syscalls.h +ABIS+= freebsd32 +.endif -fbsd32-syscalls.master: ${.CURDIR}/../../sys/compat/freebsd32/syscalls.master - cat ${.ALLSRC} > ${.TARGET} - -freebsd32_syscalls.h: fbsd32-syscalls.master - /bin/sh ${.CURDIR}/../../sys/kern/makesyscalls.sh ${.ALLSRC} \ - ${.CURDIR}/fbsd32.conf +.for abi in ${ABIS} +# Find the right file to handle this ABI. +abi_src= +ABI_SRCS= ${abi}.c ${MACHINE_ARCH}-${abi}.c ${MACHINE_CPUARCH}-${abi}.c +.for f in ${ABI_SRCS} +.if exists(${.CURDIR}/${f}) && empty(abi_src) +abi_src= ${f} .endif +.endfor +SRCS:= ${SRCS} ${abi_src} ${abi}_syscalls.h +CLEANFILES+= ${abi}_syscalls.conf ${abi}_syscalls.master ${abi}_syscalls.h +${abi}_syscalls.conf: ${.CURDIR}/makesyscallsconf.sh + /bin/sh ${.CURDIR}/makesyscallsconf.sh ${abi} ${.TARGET} + +${abi}_syscalls.master: ${.CURDIR:H:H}/${ABI_SYSPATH.${abi}}/syscalls.master + cp -f ${.ALLSRC} ${.TARGET} + +${abi}_syscalls.h: ${abi}_syscalls.master ${abi}_syscalls.conf \ + ${.CURDIR:H:H}/sys/kern/makesyscalls.sh + /bin/sh ${.CURDIR:H:H}/sys/kern/makesyscalls.sh \ + ${abi}_syscalls.master ${abi}_syscalls.conf +# Eliminate compiler warning about non-static global. + sed -i '' '/^const char \*/s/^/static /' ${.TARGET}.tmp + mv ${.TARGET}.tmp ${.TARGET} +.endfor .include Index: projects/collation/usr.bin/truss/Makefile.depend.amd64 =================================================================== --- projects/collation/usr.bin/truss/Makefile.depend.amd64 (revision 289266) +++ projects/collation/usr.bin/truss/Makefile.depend.amd64 (revision 289267) @@ -1,30 +1,30 @@ # $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ gnu/lib/csu \ gnu/lib/libgcc \ include \ include/arpa \ include/rpc \ include/xlocale \ lib/${CSU_DIR} \ lib/libc \ lib/libcompiler_rt \ .include .if ${DEP_RELDIR} == ${_DEP_RELDIR} # local dependencies - needed for -jN in clean tree amd64-cloudabi64.o: cloudabi64_syscalls.h amd64-cloudabi64.po: cloudabi64_syscalls.h -amd64-fbsd.o: syscalls.h -amd64-fbsd.po: syscalls.h -amd64-fbsd32.o: freebsd32_syscalls.h -amd64-fbsd32.po: freebsd32_syscalls.h -amd64-linux32.o: linux32_syscalls.h -amd64-linux32.po: linux32_syscalls.h +amd64-freebsd.o: freebsd_syscalls.h +amd64-freebsd.po: freebsd_syscalls.h +amd64-freebsd32.o: freebsd32_syscalls.h +amd64-freebsd32.po: freebsd32_syscalls.h +amd64-linux32.o: amd64-linux32_syscalls.h +amd64-linux32.po: amd64-linux32_syscalls.h ioctl.o: ioctl.c ioctl.po: ioctl.c .endif Index: projects/collation/usr.bin/truss/aarch64-freebsd.c =================================================================== --- projects/collation/usr.bin/truss/aarch64-freebsd.c (nonexistent) +++ projects/collation/usr.bin/truss/aarch64-freebsd.c (revision 289267) @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015 The FreeBSD Foundation + * + * Portions of this software were developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* FreeBSD/arm64-specific system call handling. */ + +#include +#include + +#include +#include +#include + +#include + +#include "truss.h" + +#include "freebsd_syscalls.h" + +static int +aarch64_fetch_args(struct trussinfo *trussinfo, u_int narg) +{ + struct reg regs; + struct current_syscall *cs; + lwpid_t tid; + u_int i, reg, syscall_num; + + tid = trussinfo->curthread->tid; + cs = &trussinfo->curthread->cs; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + /* + * FreeBSD has two special kinds of system call redirections -- + * SYS_syscall, and SYS___syscall. The former is the old syscall() + * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. + */ + syscall_num = regs.x[8]; + if (syscall_num == SYS_syscall || syscall_num == SYS___syscall) { + reg = 1; + syscall_num = regs.x[0]; + } else { + reg = 0; + } + + for (i = 0; i < narg && reg < 8; i++, reg++) + cs->args[i] = regs.x[reg]; + return (0); +} + +static int +aarch64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) +{ + struct reg regs; + lwpid_t tid; + + tid = trussinfo->curthread->tid; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + retval[0] = regs.x[0]; + retval[1] = regs.x[1]; + *errorp = !!(regs.spsr & PSR_C); + return (0); +} + +static struct procabi aarch64_freebsd = { + "FreeBSD ELF64", + syscallnames, + nitems(syscallnames), + aarch64_fetch_args, + aarch64_fetch_retval +}; + +PROCABI(aarch64_freebsd); Property changes on: projects/collation/usr.bin/truss/aarch64-freebsd.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/collation/usr.bin/truss/amd64-cloudabi64.c =================================================================== --- projects/collation/usr.bin/truss/amd64-cloudabi64.c (revision 289266) +++ projects/collation/usr.bin/truss/amd64-cloudabi64.c (revision 289267) @@ -1,180 +1,180 @@ /*- * Copyright (c) 2015 Nuxi, https://nuxi.nl/ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "cloudabi64_syscalls.h" #include "truss.h" static int amd64_cloudabi64_fetch_args(struct trussinfo *trussinfo, unsigned int narg) { struct current_syscall *cs; struct reg regs; lwpid_t tid; tid = trussinfo->curthread->tid; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) == -1) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } cs = &trussinfo->curthread->cs; if (narg >= 1) cs->args[0] = regs.r_rdi; if (narg >= 2) cs->args[1] = regs.r_rsi; if (narg >= 3) cs->args[2] = regs.r_rdx; if (narg >= 4) cs->args[3] = regs.r_rcx; if (narg >= 5) cs->args[4] = regs.r_r8; if (narg >= 6) cs->args[5] = regs.r_r9; return (0); } static const int cloudabi_errno_table[] = { [CLOUDABI_E2BIG] = E2BIG, [CLOUDABI_EACCES] = EACCES, [CLOUDABI_EADDRINUSE] = EADDRINUSE, [CLOUDABI_EADDRNOTAVAIL] = EADDRNOTAVAIL, [CLOUDABI_EAFNOSUPPORT] = EAFNOSUPPORT, [CLOUDABI_EAGAIN] = EAGAIN, [CLOUDABI_EALREADY] = EALREADY, [CLOUDABI_EBADF] = EBADF, [CLOUDABI_EBADMSG] = EBADMSG, [CLOUDABI_EBUSY] = EBUSY, [CLOUDABI_ECANCELED] = ECANCELED, [CLOUDABI_ECHILD] = ECHILD, [CLOUDABI_ECONNABORTED] = ECONNABORTED, [CLOUDABI_ECONNREFUSED] = ECONNREFUSED, [CLOUDABI_ECONNRESET] = ECONNRESET, [CLOUDABI_EDEADLK] = EDEADLK, [CLOUDABI_EDESTADDRREQ] = EDESTADDRREQ, [CLOUDABI_EDOM] = EDOM, [CLOUDABI_EDQUOT] = EDQUOT, [CLOUDABI_EEXIST] = EEXIST, [CLOUDABI_EFAULT] = EFAULT, [CLOUDABI_EFBIG] = EFBIG, [CLOUDABI_EHOSTUNREACH] = EHOSTUNREACH, [CLOUDABI_EIDRM] = EIDRM, [CLOUDABI_EILSEQ] = EILSEQ, [CLOUDABI_EINPROGRESS] = EINPROGRESS, [CLOUDABI_EINTR] = EINTR, [CLOUDABI_EINVAL] = EINVAL, [CLOUDABI_EIO] = EIO, [CLOUDABI_EISCONN] = EISCONN, [CLOUDABI_EISDIR] = EISDIR, [CLOUDABI_ELOOP] = ELOOP, [CLOUDABI_EMFILE] = EMFILE, [CLOUDABI_EMLINK] = EMLINK, [CLOUDABI_EMSGSIZE] = EMSGSIZE, [CLOUDABI_EMULTIHOP] = EMULTIHOP, [CLOUDABI_ENAMETOOLONG] = ENAMETOOLONG, [CLOUDABI_ENETDOWN] = ENETDOWN, [CLOUDABI_ENETRESET] = ENETRESET, [CLOUDABI_ENETUNREACH] = ENETUNREACH, [CLOUDABI_ENFILE] = ENFILE, [CLOUDABI_ENOBUFS] = ENOBUFS, [CLOUDABI_ENODEV] = ENODEV, [CLOUDABI_ENOENT] = ENOENT, [CLOUDABI_ENOEXEC] = ENOEXEC, [CLOUDABI_ENOLCK] = ENOLCK, [CLOUDABI_ENOLINK] = ENOLINK, [CLOUDABI_ENOMEM] = ENOMEM, [CLOUDABI_ENOMSG] = ENOMSG, [CLOUDABI_ENOPROTOOPT] = ENOPROTOOPT, [CLOUDABI_ENOSPC] = ENOSPC, [CLOUDABI_ENOSYS] = ENOSYS, [CLOUDABI_ENOTCONN] = ENOTCONN, [CLOUDABI_ENOTDIR] = ENOTDIR, [CLOUDABI_ENOTEMPTY] = ENOTEMPTY, [CLOUDABI_ENOTRECOVERABLE] = ENOTRECOVERABLE, [CLOUDABI_ENOTSOCK] = ENOTSOCK, [CLOUDABI_ENOTSUP] = ENOTSUP, [CLOUDABI_ENOTTY] = ENOTTY, [CLOUDABI_ENXIO] = ENXIO, [CLOUDABI_EOVERFLOW] = EOVERFLOW, [CLOUDABI_EOWNERDEAD] = EOWNERDEAD, [CLOUDABI_EPERM] = EPERM, [CLOUDABI_EPIPE] = EPIPE, [CLOUDABI_EPROTO] = EPROTO, [CLOUDABI_EPROTONOSUPPORT] = EPROTONOSUPPORT, [CLOUDABI_EPROTOTYPE] = EPROTOTYPE, [CLOUDABI_ERANGE] = ERANGE, [CLOUDABI_EROFS] = EROFS, [CLOUDABI_ESPIPE] = ESPIPE, [CLOUDABI_ESRCH] = ESRCH, [CLOUDABI_ESTALE] = ESTALE, [CLOUDABI_ETIMEDOUT] = ETIMEDOUT, [CLOUDABI_ETXTBSY] = ETXTBSY, [CLOUDABI_EXDEV] = EXDEV, [CLOUDABI_ENOTCAPABLE] = ENOTCAPABLE, }; static int amd64_cloudabi64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) { struct reg regs; lwpid_t tid; tid = trussinfo->curthread->tid; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) == -1) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } retval[0] = regs.r_rax; retval[1] = regs.r_rdx; *errorp = (regs.r_rflags & PSL_C) != 0; if (*errorp && *retval >= 0 && *retval < nitems(cloudabi_errno_table) && cloudabi_errno_table[*retval] != 0) *retval = cloudabi_errno_table[*retval]; return (0); } static struct procabi amd64_cloudabi64 = { "CloudABI ELF64", - cloudabi64_syscallnames, - nitems(cloudabi64_syscallnames), + syscallnames, + nitems(syscallnames), amd64_cloudabi64_fetch_args, amd64_cloudabi64_fetch_retval }; PROCABI(amd64_cloudabi64); Index: projects/collation/usr.bin/truss/amd64-freebsd.c =================================================================== --- projects/collation/usr.bin/truss/amd64-freebsd.c (nonexistent) +++ projects/collation/usr.bin/truss/amd64-freebsd.c (revision 289267) @@ -0,0 +1,131 @@ +/* + * Copyright 1997 Sean Eric Fagan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Sean Eric Fagan + * 4. Neither the name of the author may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* FreeBSD/amd64-specific system call handling. */ + +#include +#include + +#include +#include + +#include + +#include "truss.h" + +#include "freebsd_syscalls.h" + +static int +amd64_fetch_args(struct trussinfo *trussinfo, u_int narg) +{ + struct ptrace_io_desc iorequest; + struct reg regs; + struct current_syscall *cs; + lwpid_t tid; + u_int i, reg; + + tid = trussinfo->curthread->tid; + cs = &trussinfo->curthread->cs; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + /* + * FreeBSD has two special kinds of system call redirections -- + * SYS_syscall, and SYS___syscall. The former is the old syscall() + * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over %rax if it contains + * either of these values. + */ + reg = 0; + switch (regs.r_rax) { + case SYS_syscall: + case SYS___syscall: + reg++; + break; + } + + for (i = 0; i < narg && reg < 6; i++, reg++) { + switch (reg) { + case 0: cs->args[i] = regs.r_rdi; break; + case 1: cs->args[i] = regs.r_rsi; break; + case 2: cs->args[i] = regs.r_rdx; break; + case 3: cs->args[i] = regs.r_rcx; break; + case 4: cs->args[i] = regs.r_r8; break; + case 5: cs->args[i] = regs.r_r9; break; + } + } + if (narg > i) { + iorequest.piod_op = PIOD_READ_D; + iorequest.piod_offs = (void *)(regs.r_rsp + sizeof(register_t)); + iorequest.piod_addr = &cs->args[i]; + iorequest.piod_len = (narg - i) * sizeof(register_t); + ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); + if (iorequest.piod_len == 0) + return (-1); + } + + return (0); +} + +static int +amd64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) +{ + struct reg regs; + lwpid_t tid; + + tid = trussinfo->curthread->tid; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + retval[0] = regs.r_rax; + retval[1] = regs.r_rdx; + *errorp = !!(regs.r_rflags & PSL_C); + return (0); +} + +static struct procabi amd64_freebsd = { + "FreeBSD ELF64", + syscallnames, + nitems(syscallnames), + amd64_fetch_args, + amd64_fetch_retval +}; + +PROCABI(amd64_freebsd); Property changes on: projects/collation/usr.bin/truss/amd64-freebsd.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/amd64-freebsd32.c =================================================================== --- projects/collation/usr.bin/truss/amd64-freebsd32.c (nonexistent) +++ projects/collation/usr.bin/truss/amd64-freebsd32.c (revision 289267) @@ -0,0 +1,137 @@ +/* + * Copyright 1997 Sean Eric Fagan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Sean Eric Fagan + * 4. Neither the name of the author may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* FreeBSD/amd64-freebsd32-specific system call handling. */ + +#include +#include + +#include +#include + +#include +#include + +#include "truss.h" + +#include "freebsd32_syscalls.h" + +static int +amd64_freebsd32_fetch_args(struct trussinfo *trussinfo, u_int narg) +{ + struct ptrace_io_desc iorequest; + struct reg regs; + struct current_syscall *cs; + unsigned int args32[narg]; + unsigned long parm_offset; + lwpid_t tid; + u_int i; + + tid = trussinfo->curthread->tid; + cs = &trussinfo->curthread->cs; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + parm_offset = regs.r_rsp + sizeof(int); + + /* + * FreeBSD has two special kinds of system call redirections -- + * SYS_syscall, and SYS___syscall. The former is the old syscall() + * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. + */ + switch (regs.r_rax) { + case SYS_syscall: + parm_offset += sizeof(int); + break; + case SYS___syscall: + parm_offset += sizeof(quad_t); + break; + } + + iorequest.piod_op = PIOD_READ_D; + iorequest.piod_offs = (void *)parm_offset; + iorequest.piod_addr = args32; + iorequest.piod_len = sizeof(args32); + ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); + if (iorequest.piod_len == 0) { + return (-1); + } + + for (i = 0; i < narg; i++) + cs->args[i] = args32[i]; + return (0); +} + +static int +amd64_freebsd32_fetch_retval(struct trussinfo *trussinfo, long *retval, + int *errorp) +{ + struct reg regs; + lwpid_t tid; + + tid = trussinfo->curthread->tid; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + retval[0] = regs.r_rax & 0xffffffff; + retval[1] = regs.r_rdx & 0xffffffff; + *errorp = !!(regs.r_rflags & PSL_C); + return (0); +} + +static struct procabi amd64_freebsd32 = { + "FreeBSD ELF32", + syscallnames, + nitems(syscallnames), + amd64_freebsd32_fetch_args, + amd64_freebsd32_fetch_retval +}; + +PROCABI(amd64_freebsd32); + +static struct procabi amd64_freebsd32_aout = { + "FreeBSD a.out", + syscallnames, + nitems(syscallnames), + amd64_freebsd32_fetch_args, + amd64_freebsd32_fetch_retval +}; + +PROCABI(amd64_freebsd32_aout); Property changes on: projects/collation/usr.bin/truss/amd64-freebsd32.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/amd64-linux32.c =================================================================== --- projects/collation/usr.bin/truss/amd64-linux32.c (revision 289266) +++ projects/collation/usr.bin/truss/amd64-linux32.c (revision 289267) @@ -1,141 +1,141 @@ /* * Copyright 1997 Sean Eric Fagan * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Sean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* Linux/i386-specific system call handling. */ #include #include #include #include #include "truss.h" -#include "linux32_syscalls.h" +#include "amd64-linux32_syscalls.h" static int amd64_linux32_fetch_args(struct trussinfo *trussinfo, u_int narg) { struct reg regs; struct current_syscall *cs; lwpid_t tid; tid = trussinfo->curthread->tid; cs = &trussinfo->curthread->cs; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } /* * Linux passes syscall arguments in registers, not * on the stack. Fortunately, we've got access to the * register set. Note that we don't bother checking the * number of arguments. And what does linux do for syscalls * that have more than five arguments? */ switch (narg) { default: cs->args[5] = regs.r_rbp; /* Unconfirmed */ case 5: cs->args[4] = regs.r_rdi; case 4: cs->args[3] = regs.r_rsi; case 3: cs->args[2] = regs.r_rdx; case 2: cs->args[1] = regs.r_rcx; case 1: cs->args[0] = regs.r_rbx; } return (0); } /* * Linux syscalls return negative errno's, we do positive and map them */ static const int bsd_to_linux_errno[] = { -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, -6, }; static int amd64_linux32_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) { struct reg regs; lwpid_t tid; size_t i; tid = trussinfo->curthread->tid; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } retval[0] = regs.r_rax & 0xffffffff; retval[1] = regs.r_rdx & 0xffffffff; *errorp = !!(regs.r_rflags & PSL_C); if (*errorp) { for (i = 0; i < nitems(bsd_to_linux_errno); i++) { if (retval[0] == bsd_to_linux_errno[i]) { retval[0] = i; return (0); } } /* XXX: How to handle unknown errors? */ } return (0); } static struct procabi amd64_linux32 = { "Linux ELF32", - linux32_syscallnames, - nitems(linux32_syscallnames), + syscallnames, + nitems(syscallnames), amd64_linux32_fetch_args, amd64_linux32_fetch_retval }; PROCABI(amd64_linux32); Index: projects/collation/usr.bin/truss/arm-freebsd.c =================================================================== --- projects/collation/usr.bin/truss/arm-freebsd.c (nonexistent) +++ projects/collation/usr.bin/truss/arm-freebsd.c (revision 289267) @@ -0,0 +1,138 @@ +/* + * Copyright 1997 Sean Eric Fagan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Sean Eric Fagan + * 4. Neither the name of the author may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* FreeBSD/arm-specific system call handling. */ + +#include +#include + +#include +#include +#include + +#include + +#include "truss.h" + +#include "freebsd_syscalls.h" + +static int +arm_fetch_args(struct trussinfo *trussinfo, u_int narg) +{ + struct ptrace_io_desc iorequest; + struct reg regs; + struct current_syscall *cs; + lwpid_t tid; + u_int i, reg, syscall_num; + + tid = trussinfo->curthread->tid; + cs = &trussinfo->curthread->cs; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + /* + * FreeBSD has two special kinds of system call redirections -- + * SYS_syscall, and SYS___syscall. The former is the old syscall() + * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. + */ +#ifdef __ARM_EABI__ + syscall_num = regs.r[7]; +#else + if ((syscall_num = ptrace(PT_READ_I, tid, + (caddr_t)(regs.r[_REG_PC] - INSN_SIZE), 0)) == -1) { + fprintf(trussinfo->outfile, "-- CANNOT READ PC --\n"); + return (-1); + } + syscall_num = syscall_num & 0x000fffff; +#endif + + reg = 0; + switch (syscall_num) { + case SYS_syscall: + reg = 1; + break; + case SYS___syscall: + reg = 2; + break; + } + + for (i = 0; i < narg && reg < 4; i++, reg++) + cs->args[i] = regs.r[reg]; + if (narg > i) { + iorequest.piod_op = PIOD_READ_D; + iorequest.piod_offs = (void *)(regs.r_sp + + 4 * sizeof(uint32_t)); + iorequest.piod_addr = &cs->args[i]; + iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); + ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); + if (iorequest.piod_len == 0) + return (-1); + } + + return (0); +} + +static int +arm_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) +{ + struct reg regs; + lwpid_t tid; + + tid = trussinfo->curthread->tid; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + /* XXX: Does not have the __ARMEB__ handling for __syscall(). */ + retval[0] = regs.r[0]; + retval[1] = regs.r[1]; + *errorp = !!(regs.r_cpsr & PSR_C); + return (0); +} + +static struct procabi arm_freebsd = { + "FreeBSD ELF32", + syscallnames, + nitems(syscallnames), + arm_fetch_args, + arm_fetch_retval +}; + +PROCABI(arm_freebsd); Property changes on: projects/collation/usr.bin/truss/arm-freebsd.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/collation/usr.bin/truss/i386-freebsd.c =================================================================== --- projects/collation/usr.bin/truss/i386-freebsd.c (nonexistent) +++ projects/collation/usr.bin/truss/i386-freebsd.c (revision 289267) @@ -0,0 +1,131 @@ +/* + * Copyright 1997 Sean Eric Fagan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Sean Eric Fagan + * 4. Neither the name of the author may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* FreeBSD/i386-specific system call handling. */ + +#include +#include + +#include +#include + +#include + +#include "truss.h" + +#include "freebsd_syscalls.h" + +static int +i386_fetch_args(struct trussinfo *trussinfo, u_int narg) +{ + struct ptrace_io_desc iorequest; + struct reg regs; + struct current_syscall *cs; + lwpid_t tid; + unsigned int parm_offset; + + tid = trussinfo->curthread->tid; + cs = &trussinfo->curthread->cs; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + parm_offset = regs.r_esp + sizeof(int); + + /* + * FreeBSD has two special kinds of system call redirections -- + * SYS_syscall, and SYS___syscall. The former is the old syscall() + * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. + */ + switch (regs.r_eax) { + case SYS_syscall: + parm_offset += sizeof(int); + break; + case SYS___syscall: + parm_offset += sizeof(quad_t); + break; + } + + iorequest.piod_op = PIOD_READ_D; + iorequest.piod_offs = (void *)parm_offset; + iorequest.piod_addr = cs->args; + iorequest.piod_len = narg * sizeof(unsigned long); + ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); + if (iorequest.piod_len == 0) + return (-1); + + return (0); +} + +static int +i386_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) +{ + struct reg regs; + lwpid_t tid; + + tid = trussinfo->curthread->tid; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + retval[0] = regs.r_eax; + retval[1] = regs.r_edx; + *errorp = !!(regs.r_eflags & PSL_C); + return (0); +} + +static struct procabi i386_freebsd = { + "FreeBSD ELF32", + syscallnames, + nitems(syscallnames), + i386_fetch_args, + i386_fetch_retval +}; + +PROCABI(i386_freebsd); + +static struct procabi i386_freebsd_aout = { + "FreeBSD a.out", + syscallnames, + nitems(syscallnames), + i386_fetch_args, + i386_fetch_retval +}; + +PROCABI(i386_freebsd_aout); + Property changes on: projects/collation/usr.bin/truss/i386-freebsd.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/i386-linux.c =================================================================== --- projects/collation/usr.bin/truss/i386-linux.c (revision 289266) +++ projects/collation/usr.bin/truss/i386-linux.c (revision 289267) @@ -1,140 +1,140 @@ /* * Copyright 1997 Sean Eric Fagan * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Sean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* Linux/i386-specific system call handling. */ #include #include #include #include #include "truss.h" -#include "linux_syscalls.h" +#include "i386-linux_syscalls.h" static int i386_linux_fetch_args(struct trussinfo *trussinfo, u_int narg) { struct reg regs; struct current_syscall *cs; lwpid_t tid; tid = trussinfo->curthread->tid; cs = &trussinfo->curthread->cs; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } /* * Linux passes syscall arguments in registers, not * on the stack. Fortunately, we've got access to the * register set. Note that we don't bother checking the * number of arguments. And what does linux do for syscalls * that have more than five arguments? */ switch (narg) { default: cs->args[5] = regs.r_ebp; /* Unconfirmed */ case 5: cs->args[4] = regs.r_edi; case 4: cs->args[3] = regs.r_esi; case 3: cs->args[2] = regs.r_edx; case 2: cs->args[1] = regs.r_ecx; case 1: cs->args[0] = regs.r_ebx; } return (0); } /* * Linux syscalls return negative errno's, we do positive and map them */ static const int bsd_to_linux_errno[] = { -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, -6, }; static int i386_linux_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) { struct reg regs; lwpid_t tid; size_t i; tid = trussinfo->curthread->tid; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } retval[0] = regs.r_eax; retval[1] = regs.r_edx; *errorp = !!(regs.r_eflags & PSL_C); if (*errorp) { for (i = 0; i < nitems(bsd_to_linux_errno); i++) { if (retval[0] == bsd_to_linux_errno[i]) { retval[0] = i; return (0); } } /* XXX: How to handle unknown errors? */ } return (0); } static struct procabi i386_linux = { "Linux ELF32", - linux_syscallnames, - nitems(linux_syscallnames), + syscallnames, + nitems(syscallnames), i386_linux_fetch_args, i386_linux_fetch_retval }; PROCABI(i386_linux); Index: projects/collation/usr.bin/truss/makesyscallsconf.sh =================================================================== --- projects/collation/usr.bin/truss/makesyscallsconf.sh (nonexistent) +++ projects/collation/usr.bin/truss/makesyscallsconf.sh (revision 289267) @@ -0,0 +1,21 @@ +#! /bin/sh +# $FreeBSD$ + +ABI="$1" +CONF="$2" + +header="${ABI}_syscalls.h" + +cat > "${CONF}" << EOF +sysnames="${header}.tmp" +sysproto="/dev/null" +sysproto_h="/dev/null" +syshdr="/dev/null" +sysmk="/dev/null" +syssw="/dev/null" +syshide="/dev/null" +syscallprefix="SYS_" +switchname="sysent" +namesname="syscallnames" +systrace="/dev/null" +EOF Property changes on: projects/collation/usr.bin/truss/makesyscallsconf.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/collation/usr.bin/truss/mips-freebsd.c =================================================================== --- projects/collation/usr.bin/truss/mips-freebsd.c (nonexistent) +++ projects/collation/usr.bin/truss/mips-freebsd.c (revision 289267) @@ -0,0 +1,141 @@ +/* + * Copyright 1998 Sean Eric Fagan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Sean Eric Fagan + * 4. Neither the name of the author may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* FreeBSD/mips-specific system call handling. */ + +#include +#include + +#include +#include + +#include + +#include "truss.h" + +#include "freebsd_syscalls.h" + +static int +mips_fetch_args(struct trussinfo *trussinfo, u_int narg) +{ + struct ptrace_io_desc iorequest; + struct reg regs; + struct current_syscall *cs; + lwpid_t tid; + u_int i, reg; + + tid = trussinfo->curthread->tid; + cs = &trussinfo->curthread->cs; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + /* + * FreeBSD has two special kinds of system call redirections -- + * SYS_syscall, and SYS___syscall. The former is the old syscall() + * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. + */ + reg = A0; + switch (regs.r_regs[V0]) { + case SYS_syscall: + reg = A1; + break; + case SYS___syscall: +#if defined(__mips_n32) || defined(__mips_n64) + reg = A1; +#else + reg = A2; +#endif + break; + } + +#if defined(__mips_n32) || defined(__mips_n64) +#define MAXREG A7 +#else +#define MAXREG A3 +#endif + + for (i = 0; i < narg && reg <= MAXREG; i++, reg++) + cs->args[i] = regs.r_regs[reg]; + if (narg > i) { + iorequest.piod_op = PIOD_READ_D; + iorequest.piod_offs = (void *)((uintptr_t)regs.r_regs[SP] + + 4 * sizeof(cs->args[0])); + iorequest.piod_addr = &cs->args[i]; + iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); + ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); + if (iorequest.piod_len == 0) + return (-1); + } + + return (0); +} + +static int +mips_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) +{ + struct reg regs; + lwpid_t tid; + + tid = trussinfo->curthread->tid; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + /* XXX: Does not have special handling for __syscall(). */ + retval[0] = regs.r_regs[V0]; + retval[1] = regs.r_regs[V1]; + *errorp = !!regs.r_regs[A3]; + return (0); +} + + +static struct procabi mips_freebsd = { +#ifdef __mips_n64 + "FreeBSD ELF64", +#else + "FreeBSD ELF32", +#endif + syscallnames, + nitems(syscallnames), + mips_fetch_args, + mips_fetch_retval +}; + +PROCABI(mips_freebsd); Property changes on: projects/collation/usr.bin/truss/mips-freebsd.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/collation/usr.bin/truss/powerpc-freebsd.c =================================================================== --- projects/collation/usr.bin/truss/powerpc-freebsd.c (nonexistent) +++ projects/collation/usr.bin/truss/powerpc-freebsd.c (revision 289267) @@ -0,0 +1,122 @@ +/* + * Copyright 2006 Peter Grehan + * Copyright 2005 Orlando Bassotto + * Copyright 1998 Sean Eric Fagan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* FreeBSD/powerpc-specific system call handling. */ + +#include +#include + +#include +#include + +#include + +#include "truss.h" + +#include "freebsd_syscalls.h" + +static int +powerpc_fetch_args(struct trussinfo *trussinfo, u_int narg) +{ + struct ptrace_io_desc iorequest; + struct reg regs; + struct current_syscall *cs; + lwpid_t tid; + u_int i, reg; + + tid = trussinfo->curthread->tid; + cs = &trussinfo->curthread->cs; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + /* + * FreeBSD has two special kinds of system call redirections -- + * SYS_syscall, and SYS___syscall. The former is the old syscall() + * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. + */ + reg = 0; + switch (regs.fixreg[0]) { + case SYS_syscall: + reg += 1; + break; + case SYS___syscall: + reg += 2; + break; + } + + for (i = 0; i < narg && reg < NARGREG; i++, reg++) { + cs->args[i] = regs.fixreg[FIRSTARG + reg]; + } + if (narg > i) { + iorequest.piod_op = PIOD_READ_D; + iorequest.piod_offs = (void *)(regs.fixreg[1] + 8); + iorequest.piod_addr = &cs->args[i]; + iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); + ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); + if (iorequest.piod_len == 0) + return (-1); + } + + return (0); +} + +static int +powerpc_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) +{ + struct reg regs; + lwpid_t tid; + + tid = trussinfo->curthread->tid; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + /* XXX: Does not have fixup for __syscall(). */ + retval[0] = regs.fixreg[3]; + retval[1] = regs.fixreg[4]; + *errorp = !!(regs.cr & 0x10000000); + return (0); +} + +static struct procabi powerpc_freebsd = { + "FreeBSD ELF32", + syscallnames, + nitems(syscallnames), + powerpc_fetch_args, + powerpc_fetch_retval +}; + +PROCABI(powerpc_freebsd); Property changes on: projects/collation/usr.bin/truss/powerpc-freebsd.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/powerpc64-freebsd.c =================================================================== --- projects/collation/usr.bin/truss/powerpc64-freebsd.c (nonexistent) +++ projects/collation/usr.bin/truss/powerpc64-freebsd.c (revision 289267) @@ -0,0 +1,118 @@ +/* + * Copyright 2006 Peter Grehan + * Copyright 2005 Orlando Bassotto + * Copyright 1998 Sean Eric Fagan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* FreeBSD/powerpc64-specific system call handling. */ + +#include +#include + +#include +#include + +#include + +#include "truss.h" + +#include "freebsd_syscalls.h" + +static int +powerpc64_fetch_args(struct trussinfo *trussinfo, u_int narg) +{ + struct ptrace_io_desc iorequest; + struct reg regs; + struct current_syscall *cs; + lwpid_t tid; + u_int i, reg; + + tid = trussinfo->curthread->tid; + cs = &trussinfo->curthread->cs; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + /* + * FreeBSD has two special kinds of system call redirections -- + * SYS_syscall, and SYS___syscall. The former is the old syscall() + * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. + */ + reg = 0; + switch (regs.fixreg[0]) { + case SYS_syscall: + case SYS___syscall: + reg += 1; + break; + } + + for (i = 0; i < narg && reg < NARGREG; i++, reg++) + cs->args[i] = regs.fixreg[FIRSTARG + reg]; + if (narg > i) { + iorequest.piod_op = PIOD_READ_D; + iorequest.piod_offs = (void *)(regs.fixreg[1] + 48); + iorequest.piod_addr = &cs->args[i]; + iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); + ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); + if (iorequest.piod_len == 0) + return (-1); + } + + return (0); +} + +static int +powerpc64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) +{ + struct reg regs; + lwpid_t tid; + + tid = trussinfo->curthread->tid; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + retval[0] = regs.fixreg[3]; + retval[1] = regs.fixreg[4]; + *errorp = !!(regs.cr & 0x10000000); + return (0); +} + +static struct procabi powerpc64_freebsd = { + "FreeBSD ELF64", + syscallnames, + nitems(syscallnames), + powerpc64_fetch_args, + powerpc64_fetch_retval +}; + +PROCABI(powerpc64_freebsd); Property changes on: projects/collation/usr.bin/truss/powerpc64-freebsd.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/powerpc64-freebsd32.c =================================================================== --- projects/collation/usr.bin/truss/powerpc64-freebsd32.c (nonexistent) +++ projects/collation/usr.bin/truss/powerpc64-freebsd32.c (revision 289267) @@ -0,0 +1,127 @@ +/* + * Copyright 2006 Peter Grehan + * Copyright 2005 Orlando Bassotto + * Copyright 1998 Sean Eric Fagan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* FreeBSD/powerpc64-freebsd32-specific system call handling. */ + +#include +#include + +#include +#include + +#include + +#include "truss.h" + +#include "freebsd32_syscalls.h" + +static int +powerpc64_freebsd32_fetch_args(struct trussinfo *trussinfo, u_int narg) +{ + struct ptrace_io_desc iorequest; + struct reg regs; + struct current_syscall *cs; + lwpid_t tid; + u_int i, reg; + + tid = trussinfo->curthread->tid; + cs = &trussinfo->curthread->cs; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + /* + * FreeBSD has two special kinds of system call redirections -- + * SYS_syscall, and SYS___syscall. The former is the old syscall() + * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. + */ + reg = 0; + switch (regs.fixreg[0]) { + case SYS_syscall: + reg += 1; + break; + case SYS___syscall: + reg += 2; + break; + } + + for (i = 0; i < narg && reg < NARGREG; i++, reg++) { + cs->args[i] = regs.fixreg[FIRSTARG + reg] & 0xffffffff; + } + if (narg > i) { + uint32_t args32[narg - i]; + u_int j; + + iorequest.piod_op = PIOD_READ_D; + iorequest.piod_offs = (void *)(regs.fixreg[1] + 8); + iorequest.piod_addr = args32; + iorequest.piod_len = sizeof(args32); + ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); + if (iorequest.piod_len == 0) + return (-1); + for (j = 0; j < narg - i; j++) + cs->args[i + j] = args32[j]; + } + + return (0); +} + +static int +powerpc64_freebsd32_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) +{ + struct reg regs; + lwpid_t tid; + + tid = trussinfo->curthread->tid; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + /* XXX: Does not have fixup for __syscall(). */ + retval[0] = regs.fixreg[3] & 0xffffffff; + retval[1] = regs.fixreg[4] & 0xffffffff; + *errorp = !!(regs.cr & 0x10000000); + return (0); +} + +static struct procabi powerpc64_freebsd32 = { + "FreeBSD ELF32", + syscallnames, + nitems(syscallnames), + powerpc64_freebsd32_fetch_args, + powerpc64_freebsd32_fetch_retval +}; + +PROCABI(powerpc64_freebsd32); Property changes on: projects/collation/usr.bin/truss/powerpc64-freebsd32.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.bin/truss/sparc64-freebsd.c =================================================================== --- projects/collation/usr.bin/truss/sparc64-freebsd.c (nonexistent) +++ projects/collation/usr.bin/truss/sparc64-freebsd.c (revision 289267) @@ -0,0 +1,125 @@ +/* + * Copyright 1998 Sean Eric Fagan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Sean Eric Fagan + * 4. Neither the name of the author may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* FreeBSD/sparc64-specific system call handling. */ + +#include +#include + +#include +#include +#include + +#include +#include + +#include "truss.h" + +#include "freebsd_syscalls.h" + +static int +sparc64_fetch_args(struct trussinfo *trussinfo, u_int narg) +{ + struct ptrace_io_desc iorequest; + struct reg regs; + struct current_syscall *cs; + lwpid_t tid; + u_int i, reg; + + tid = trussinfo->curthread->tid; + cs = &trussinfo->curthread->cs; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + /* + * FreeBSD has two special kinds of system call redirections -- + * SYS_syscall, and SYS___syscall. The former is the old syscall() + * routine, basically; the latter is for quad-aligned arguments. + * + * The system call argument count and code from ptrace() already + * account for these, but we need to skip over the first argument. + */ + reg = 0; + switch (regs.r_global[1]) { + case SYS_syscall: + case SYS___syscall: + reg = 1; + break; + } + + for (i = 0; i < narg && reg < 6; i++, reg++) + cs->args[i] = regs.r_out[reg]; + if (narg > i) { + iorequest.piod_op = PIOD_READ_D; + iorequest.piod_offs = (void *)(regs.r_out[6] + SPOFF + + offsetof(struct frame, fr_pad[6])); + iorequest.piod_addr = &cs->args[i]; + iorequest.piod_len = (narg - i) * sizeof(cs->args[0]); + ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); + if (iorequest.piod_len == 0) + return (-1); + } + + return (0); +} + +static int +sparc64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp) +{ + struct reg regs; + lwpid_t tid; + + tid = trussinfo->curthread->tid; + if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); + return (-1); + } + + retval[0] = regs.r_out[0]; + retval[1] = regs.r_out[1]; + *errorp = !!(regs.r_tstate & TSTATE_XCC_C); + return (0); +} + +static struct procabi sparc64_freebsd = { + "FreeBSD ELF64", + syscallnames, + nitems(syscallnames), + sparc64_fetch_args, + sparc64_fetch_retval +}; + +PROCABI(sparc64_freebsd); Property changes on: projects/collation/usr.bin/truss/sparc64-freebsd.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: projects/collation/usr.sbin/config/mkmakefile.c =================================================================== --- projects/collation/usr.sbin/config/mkmakefile.c (revision 289266) +++ projects/collation/usr.sbin/config/mkmakefile.c (revision 289267) @@ -1,777 +1,779 @@ /* * Copyright (c) 1980, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)mkmakefile.c 8.1 (Berkeley) 6/6/93"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* * Build the makefile for the system, from * the information in the files files and the * additional files for the machine being compiled to. */ #include #include #include #include #include #include #include "y.tab.h" #include "config.h" #include "configvers.h" static char *tail(char *); static void do_clean(FILE *); static void do_rules(FILE *); static void do_xxfiles(char *, FILE *); static void do_objs(FILE *); static void do_before_depend(FILE *); static int opteq(const char *, const char *); static void read_files(void); static void errout(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); exit(1); } /* * Lookup a file, by name. */ static struct file_list * fl_lookup(char *file) { struct file_list *fp; STAILQ_FOREACH(fp, &ftab, f_next) { if (eq(fp->f_fn, file)) return (fp); } return (0); } /* * Make a new file list entry */ static struct file_list * new_fent(void) { struct file_list *fp; fp = (struct file_list *) calloc(1, sizeof *fp); if (fp == NULL) err(EXIT_FAILURE, "calloc"); STAILQ_INSERT_TAIL(&ftab, fp, f_next); return (fp); } /* * Open the correct Makefile and return it, or error out. */ FILE * open_makefile_template(void) { FILE *ifp; char line[BUFSIZ]; snprintf(line, sizeof(line), "../../conf/Makefile.%s", machinename); ifp = fopen(line, "r"); if (ifp == 0) { snprintf(line, sizeof(line), "Makefile.%s", machinename); ifp = fopen(line, "r"); } if (ifp == 0) err(1, "%s", line); return (ifp); } /* * Build the makefile from the skeleton */ void makefile(void) { FILE *ifp, *ofp; char line[BUFSIZ]; struct opt *op, *t; read_files(); ifp = open_makefile_template(); ofp = fopen(path("Makefile.new"), "w"); if (ofp == 0) err(1, "%s", path("Makefile.new")); fprintf(ofp, "KERN_IDENT=%s\n", ident); fprintf(ofp, "MACHINE=%s\n", machinename); fprintf(ofp, "MACHINE_ARCH=%s\n", machinearch); SLIST_FOREACH_SAFE(op, &mkopt, op_next, t) { fprintf(ofp, "%s=%s", op->op_name, op->op_value); while ((op = SLIST_NEXT(op, op_append)) != NULL) fprintf(ofp, " %s", op->op_value); fprintf(ofp, "\n"); } if (debugging) fprintf(ofp, "DEBUG=-g\n"); if (profiling) fprintf(ofp, "PROFLEVEL=%d\n", profiling); if (*srcdir != '\0') fprintf(ofp,"S=%s\n", srcdir); while (fgets(line, BUFSIZ, ifp) != NULL) { if (*line != '%') { fprintf(ofp, "%s", line); continue; } if (eq(line, "%BEFORE_DEPEND\n")) do_before_depend(ofp); else if (eq(line, "%OBJS\n")) do_objs(ofp); else if (strncmp(line, "%FILES.", 7) == 0) do_xxfiles(line, ofp); else if (eq(line, "%RULES\n")) do_rules(ofp); else if (eq(line, "%CLEAN\n")) do_clean(ofp); else if (strncmp(line, "%VERSREQ=", 9) == 0) line[0] = '\0'; /* handled elsewhere */ else fprintf(stderr, "Unknown %% construct in generic makefile: %s", line); } (void) fclose(ifp); (void) fclose(ofp); moveifchanged(path("Makefile.new"), path("Makefile")); } /* * Build hints.c from the skeleton */ void makehints(void) { FILE *ifp, *ofp; char line[BUFSIZ]; char *s; struct hint *hint; ofp = fopen(path("hints.c.new"), "w"); if (ofp == NULL) err(1, "%s", path("hints.c.new")); fprintf(ofp, "#include \n"); fprintf(ofp, "#include \n"); fprintf(ofp, "\n"); fprintf(ofp, "int hintmode = %d;\n", hintmode); fprintf(ofp, "char static_hints[] = {\n"); STAILQ_FOREACH(hint, &hints, hint_next) { ifp = fopen(hint->hint_name, "r"); if (ifp == NULL) err(1, "%s", hint->hint_name); while (fgets(line, BUFSIZ, ifp) != NULL) { /* zap trailing CR and/or LF */ while ((s = strrchr(line, '\n')) != NULL) *s = '\0'; while ((s = strrchr(line, '\r')) != NULL) *s = '\0'; /* remove # comments */ s = strchr(line, '#'); if (s) *s = '\0'; /* remove any whitespace and " characters */ s = line; while (*s) { if (*s == ' ' || *s == '\t' || *s == '"') { while (*s) { s[0] = s[1]; s++; } /* start over */ s = line; continue; } s++; } /* anything left? */ if (*line == '\0') continue; fprintf(ofp, "\"%s\\0\"\n", line); } fclose(ifp); } fprintf(ofp, "\"\\0\"\n};\n"); fclose(ofp); moveifchanged(path("hints.c.new"), path("hints.c")); } /* * Build env.c from the skeleton */ void makeenv(void) { FILE *ifp, *ofp; char line[BUFSIZ]; char *s; if (env) { ifp = fopen(env, "r"); if (ifp == NULL) err(1, "%s", env); } else { ifp = NULL; } ofp = fopen(path("env.c.new"), "w"); if (ofp == NULL) err(1, "%s", path("env.c.new")); fprintf(ofp, "#include \n"); fprintf(ofp, "#include \n"); fprintf(ofp, "\n"); fprintf(ofp, "int envmode = %d;\n", envmode); fprintf(ofp, "char static_env[] = {\n"); if (ifp) { while (fgets(line, BUFSIZ, ifp) != NULL) { /* zap trailing CR and/or LF */ while ((s = strrchr(line, '\n')) != NULL) *s = '\0'; while ((s = strrchr(line, '\r')) != NULL) *s = '\0'; /* remove # comments */ s = strchr(line, '#'); if (s) *s = '\0'; /* remove any whitespace and " characters */ s = line; while (*s) { if (*s == ' ' || *s == '\t' || *s == '"') { while (*s) { s[0] = s[1]; s++; } /* start over */ s = line; continue; } s++; } /* anything left? */ if (*line == '\0') continue; fprintf(ofp, "\"%s\\0\"\n", line); } } fprintf(ofp, "\"\\0\"\n};\n"); if (ifp) fclose(ifp); fclose(ofp); moveifchanged(path("env.c.new"), path("env.c")); } static void read_file(char *fname) { char ifname[MAXPATHLEN]; FILE *fp; struct file_list *tp; struct device *dp; struct opt *op; char *wd, *this, *compilewith, *depends, *clean, *warning; const char *objprefix; int compile, match, nreqs, std, filetype, not, imp_rule, no_obj, before_depend, nowerror; fp = fopen(fname, "r"); if (fp == 0) err(1, "%s", fname); next: /* * include "filename" * filename [ standard | optional ] * [ dev* [ | dev* ... ] | profiling-routine ] [ no-obj ] * [ compile-with "compile rule" [no-implicit-rule] ] * [ dependency "dependency-list"] [ before-depend ] * [ clean "file-list"] [ warning "text warning" ] * [ obj-prefix "file prefix"] */ wd = get_word(fp); if (wd == (char *)EOF) { (void) fclose(fp); return; } if (wd == 0) goto next; if (wd[0] == '#') { while (((wd = get_word(fp)) != (char *)EOF) && wd) ; goto next; } if (eq(wd, "include")) { wd = get_quoted_word(fp); if (wd == (char *)EOF || wd == 0) errout("%s: missing include filename.\n", fname); (void) snprintf(ifname, sizeof(ifname), "../../%s", wd); read_file(ifname); while (((wd = get_word(fp)) != (char *)EOF) && wd) ; goto next; } this = ns(wd); wd = get_word(fp); if (wd == (char *)EOF) return; if (wd == 0) errout("%s: No type for %s.\n", fname, this); tp = fl_lookup(this); compile = 0; match = 1; nreqs = 0; compilewith = 0; depends = 0; clean = 0; warning = 0; std = 0; imp_rule = 0; no_obj = 0; before_depend = 0; nowerror = 0; not = 0; filetype = NORMAL; objprefix = ""; if (eq(wd, "standard")) std = 1; else if (!eq(wd, "optional")) errout("%s: \"%s\" %s must be optional or standard\n", fname, wd, this); for (wd = get_word(fp); wd; wd = get_word(fp)) { if (wd == (char *)EOF) return; if (eq(wd, "!")) { not = 1; continue; } if (eq(wd, "|")) { if (nreqs == 0) errout("%s: syntax error describing %s\n", fname, this); compile += match; match = 1; nreqs = 0; continue; } if (eq(wd, "no-obj")) { no_obj++; continue; } if (eq(wd, "no-implicit-rule")) { if (compilewith == 0) errout("%s: alternate rule required when " "\"no-implicit-rule\" is specified for" " %s.\n", fname, this); imp_rule++; continue; } if (eq(wd, "before-depend")) { before_depend++; continue; } if (eq(wd, "dependency")) { wd = get_quoted_word(fp); if (wd == (char *)EOF || wd == 0) errout("%s: %s missing dependency string.\n", fname, this); depends = ns(wd); continue; } if (eq(wd, "clean")) { wd = get_quoted_word(fp); if (wd == (char *)EOF || wd == 0) errout("%s: %s missing clean file list.\n", fname, this); clean = ns(wd); continue; } if (eq(wd, "compile-with")) { wd = get_quoted_word(fp); if (wd == (char *)EOF || wd == 0) errout("%s: %s missing compile command string.\n", fname, this); compilewith = ns(wd); continue; } if (eq(wd, "warning")) { wd = get_quoted_word(fp); if (wd == (char *)EOF || wd == 0) errout("%s: %s missing warning text string.\n", fname, this); warning = ns(wd); continue; } if (eq(wd, "obj-prefix")) { wd = get_quoted_word(fp); if (wd == (char *)EOF || wd == 0) errout("%s: %s missing object prefix string.\n", fname, this); objprefix = ns(wd); continue; } if (eq(wd, "nowerror")) { nowerror = 1; continue; } if (eq(wd, "local")) { filetype = LOCAL; continue; } if (eq(wd, "no-depend")) { filetype = NODEPEND; continue; } nreqs++; if (eq(wd, "profiling-routine")) { filetype = PROFILING; continue; } if (std) errout("standard entry %s has optional inclusion specifier %s!\n", this, wd); STAILQ_FOREACH(dp, &dtab, d_next) if (eq(dp->d_name, wd)) { if (not) match = 0; else dp->d_done |= DEVDONE; goto nextparam; } SLIST_FOREACH(op, &opt, op_next) if (op->op_value == 0 && opteq(op->op_name, wd)) { if (not) match = 0; goto nextparam; } match &= not; nextparam:; not = 0; } compile += match; if (compile && tp == NULL) { if (std == 0 && nreqs == 0) errout("%s: what is %s optional on?\n", fname, this); if (filetype == PROFILING && profiling == 0) goto next; tp = new_fent(); tp->f_fn = this; tp->f_type = filetype; if (imp_rule) tp->f_flags |= NO_IMPLCT_RULE; if (no_obj) tp->f_flags |= NO_OBJ; if (before_depend) tp->f_flags |= BEFORE_DEPEND; if (nowerror) tp->f_flags |= NOWERROR; tp->f_compilewith = compilewith; tp->f_depends = depends; tp->f_clean = clean; tp->f_warn = warning; tp->f_objprefix = objprefix; } goto next; } /* * Read in the information about files used in making the system. * Store it in the ftab linked list. */ static void read_files(void) { char fname[MAXPATHLEN]; struct files_name *nl, *tnl; (void) snprintf(fname, sizeof(fname), "../../conf/files"); read_file(fname); (void) snprintf(fname, sizeof(fname), "../../conf/files.%s", machinename); read_file(fname); for (nl = STAILQ_FIRST(&fntab); nl != NULL; nl = tnl) { read_file(nl->f_name); tnl = STAILQ_NEXT(nl, f_next); free(nl->f_name); free(nl); } } static int opteq(const char *cp, const char *dp) { char c, d; for (; ; cp++, dp++) { if (*cp != *dp) { c = isupper(*cp) ? tolower(*cp) : *cp; d = isupper(*dp) ? tolower(*dp) : *dp; if (c != d) return (0); } if (*cp == 0) return (1); } } static void do_before_depend(FILE *fp) { struct file_list *tp; int lpos, len; fputs("BEFORE_DEPEND=", fp); lpos = 15; STAILQ_FOREACH(tp, &ftab, f_next) if (tp->f_flags & BEFORE_DEPEND) { len = strlen(tp->f_fn); if ((len = 3 + len) + lpos > 72) { lpos = 8; fputs("\\\n\t", fp); } if (tp->f_flags & NO_IMPLCT_RULE) fprintf(fp, "%s ", tp->f_fn); else fprintf(fp, "$S/%s ", tp->f_fn); lpos += len + 1; } if (lpos != 8) putc('\n', fp); } static void do_objs(FILE *fp) { struct file_list *tp; int lpos, len; char *cp, och, *sp; fprintf(fp, "OBJS="); lpos = 6; STAILQ_FOREACH(tp, &ftab, f_next) { if (tp->f_flags & NO_OBJ) continue; sp = tail(tp->f_fn); cp = sp + (len = strlen(sp)) - 1; och = *cp; *cp = 'o'; len += strlen(tp->f_objprefix); if (len + lpos > 72) { lpos = 8; fprintf(fp, "\\\n\t"); } fprintf(fp, "%s%s ", tp->f_objprefix, sp); lpos += len + 1; *cp = och; } if (lpos != 8) putc('\n', fp); } static void do_xxfiles(char *tag, FILE *fp) { struct file_list *tp; int lpos, len, slen; char *suff, *SUFF; if (tag[strlen(tag) - 1] == '\n') tag[strlen(tag) - 1] = '\0'; suff = ns(tag + 7); SUFF = ns(suff); raisestr(SUFF); slen = strlen(suff); fprintf(fp, "%sFILES=", SUFF); + free(SUFF); lpos = 8; STAILQ_FOREACH(tp, &ftab, f_next) if (tp->f_type != NODEPEND) { len = strlen(tp->f_fn); if (tp->f_fn[len - slen - 1] != '.') continue; if (strcasecmp(&tp->f_fn[len - slen], suff) != 0) continue; if ((len = 3 + len) + lpos > 72) { lpos = 8; fputs("\\\n\t", fp); } if (tp->f_type != LOCAL) fprintf(fp, "$S/%s ", tp->f_fn); else fprintf(fp, "%s ", tp->f_fn); lpos += len + 1; } + free(suff); if (lpos != 8) putc('\n', fp); } static char * tail(char *fn) { char *cp; cp = strrchr(fn, '/'); if (cp == 0) return (fn); return (cp+1); } /* * Create the makerules for each file * which is part of the system. */ static void do_rules(FILE *f) { char *cp, *np, och; struct file_list *ftp; char *compilewith; char cmd[128]; STAILQ_FOREACH(ftp, &ftab, f_next) { if (ftp->f_warn) fprintf(stderr, "WARNING: %s\n", ftp->f_warn); cp = (np = ftp->f_fn) + strlen(ftp->f_fn) - 1; och = *cp; if (ftp->f_flags & NO_IMPLCT_RULE) { if (ftp->f_depends) fprintf(f, "%s%s: %s\n", ftp->f_objprefix, np, ftp->f_depends); else fprintf(f, "%s%s: \n", ftp->f_objprefix, np); } else { *cp = '\0'; if (och == 'o') { fprintf(f, "%s%so:\n\t-cp $S/%so .\n\n", ftp->f_objprefix, tail(np), np); continue; } if (ftp->f_depends) { fprintf(f, "%s%sln: $S/%s%c %s\n", ftp->f_objprefix, tail(np), np, och, ftp->f_depends); fprintf(f, "\t${NORMAL_LINT}\n\n"); fprintf(f, "%s%so: $S/%s%c %s\n", ftp->f_objprefix, tail(np), np, och, ftp->f_depends); } else { fprintf(f, "%s%sln: $S/%s%c\n", ftp->f_objprefix, tail(np), np, och); fprintf(f, "\t${NORMAL_LINT}\n\n"); fprintf(f, "%s%so: $S/%s%c\n", ftp->f_objprefix, tail(np), np, och); } } compilewith = ftp->f_compilewith; if (compilewith == 0) { const char *ftype = NULL; switch (ftp->f_type) { case NORMAL: ftype = "NORMAL"; break; case PROFILING: if (!profiling) continue; ftype = "PROFILE"; break; default: fprintf(stderr, "config: don't know rules for %s\n", np); break; } snprintf(cmd, sizeof(cmd), "${%s_%c%s}", ftype, toupper(och), ftp->f_flags & NOWERROR ? "_NOWERROR" : ""); compilewith = cmd; } *cp = och; if (strlen(ftp->f_objprefix)) fprintf(f, "\t%s $S/%s\n", compilewith, np); else fprintf(f, "\t%s\n", compilewith); if (!(ftp->f_flags & NO_OBJ)) fprintf(f, "\t${NORMAL_CTFCONVERT}\n\n"); else fprintf(f, "\n"); } } static void do_clean(FILE *fp) { struct file_list *tp; int lpos, len; fputs("CLEAN=", fp); lpos = 7; STAILQ_FOREACH(tp, &ftab, f_next) if (tp->f_clean) { len = strlen(tp->f_clean); if (len + lpos > 72) { lpos = 8; fputs("\\\n\t", fp); } fprintf(fp, "%s ", tp->f_clean); lpos += len + 1; } if (lpos != 8) putc('\n', fp); } char * raisestr(char *str) { char *cp = str; while (*str) { if (islower(*str)) *str = toupper(*str); str++; } return (cp); } Index: projects/collation =================================================================== --- projects/collation (revision 289266) +++ projects/collation (revision 289267) Property changes on: projects/collation ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r289239-289266