ia64/xen-unstable

changeset 16454:d5c396128897

x86_emulate: Support most common segment load/save instructions.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Sat Nov 24 21:40:19 2007 +0000 (2007-11-24)
parents 2e7fcea74cb1
children 51082cf273d4
files xen/arch/x86/x86_emulate.c xen/include/asm-x86/hvm/hvm.h xen/include/asm-x86/hvm/svm/vmcb.h xen/include/asm-x86/x86_emulate.h
line diff
     1.1 --- a/xen/arch/x86/x86_emulate.c	Sat Nov 24 16:16:57 2007 +0000
     1.2 +++ b/xen/arch/x86/x86_emulate.c	Sat Nov 24 21:40:19 2007 +0000
     1.3 @@ -60,19 +60,19 @@ static uint8_t opcode_table[256] = {
     1.4      /* 0x00 - 0x07 */
     1.5      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
     1.6      ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
     1.7 -    ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
     1.8 +    ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, ImplicitOps,
     1.9      /* 0x08 - 0x0F */
    1.10      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
    1.11      ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
    1.12 -    ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
    1.13 +    ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, 0,
    1.14      /* 0x10 - 0x17 */
    1.15      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
    1.16      ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
    1.17 -    ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
    1.18 +    ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, ImplicitOps,
    1.19      /* 0x18 - 0x1F */
    1.20      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
    1.21      ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
    1.22 -    ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
    1.23 +    ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, ImplicitOps,
    1.24      /* 0x20 - 0x27 */
    1.25      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
    1.26      ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
    1.27 @@ -120,7 +120,8 @@ static uint8_t opcode_table[256] = {
    1.28      /* 0x88 - 0x8F */
    1.29      ByteOp|DstMem|SrcReg|ModRM|Mov, DstMem|SrcReg|ModRM|Mov,
    1.30      ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
    1.31 -    0, DstReg|SrcNone|ModRM, 0, DstMem|SrcNone|ModRM|Mov,
    1.32 +    DstMem|SrcReg|ModRM|Mov, DstReg|SrcNone|ModRM,
    1.33 +    DstReg|SrcMem|ModRM|Mov, DstMem|SrcNone|ModRM|Mov,
    1.34      /* 0x90 - 0x97 */
    1.35      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    1.36      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    1.37 @@ -158,7 +159,7 @@ static uint8_t opcode_table[256] = {
    1.38      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    1.39      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    1.40      /* 0xE8 - 0xEF */
    1.41 -    ImplicitOps, ImplicitOps, 0, ImplicitOps,
    1.42 +    ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    1.43      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    1.44      /* 0xF0 - 0xF7 */
    1.45      0, 0, 0, 0,
    1.46 @@ -170,7 +171,7 @@ static uint8_t opcode_table[256] = {
    1.47  
    1.48  static uint8_t twobyte_table[256] = {
    1.49      /* 0x00 - 0x07 */
    1.50 -    0, 0, 0, 0, 0, ImplicitOps, 0, 0,
    1.51 +    0, ImplicitOps|ModRM, 0, 0, 0, ImplicitOps, 0, 0,
    1.52      /* 0x08 - 0x0F */
    1.53      ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps|ModRM, 0, 0,
    1.54      /* 0x10 - 0x17 */
    1.55 @@ -220,9 +221,10 @@ static uint8_t twobyte_table[256] = {
    1.56      ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
    1.57      ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
    1.58      /* 0xA0 - 0xA7 */
    1.59 -    0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0, 
    1.60 +    ImplicitOps, ImplicitOps, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0, 
    1.61      /* 0xA8 - 0xAF */
    1.62 -    0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, DstReg|SrcMem|ModRM,
    1.63 +    ImplicitOps, ImplicitOps, 0, DstBitBase|SrcReg|ModRM,
    1.64 +    0, 0, 0, DstReg|SrcMem|ModRM,
    1.65      /* 0xB0 - 0xB7 */
    1.66      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
    1.67      0, DstBitBase|SrcReg|ModRM,
    1.68 @@ -677,6 +679,45 @@ test_cc(
    1.69      return (!!rc ^ (condition & 1));
    1.70  }
    1.71  
    1.72 +static int
    1.73 +in_realmode(
    1.74 +    struct x86_emulate_ctxt *ctxt,
    1.75 +    struct x86_emulate_ops  *ops)
    1.76 +{
    1.77 +    unsigned long cr0;
    1.78 +    int rc;
    1.79 +
    1.80 +    if ( ops->read_cr == NULL )
    1.81 +        return 0;
    1.82 +
    1.83 +    rc = ops->read_cr(0, &cr0, ctxt);
    1.84 +    return (!rc && !(cr0 & 1));
    1.85 +}
    1.86 +
    1.87 +static int
    1.88 +load_seg(
    1.89 +    enum x86_segment seg,
    1.90 +    uint16_t sel,
    1.91 +    struct x86_emulate_ctxt *ctxt,
    1.92 +    struct x86_emulate_ops *ops)
    1.93 +{
    1.94 +    struct segment_register reg;
    1.95 +    int rc;
    1.96 +
    1.97 +    if ( !in_realmode(ctxt, ops) ||
    1.98 +         (ops->read_segment == NULL) ||
    1.99 +         (ops->write_segment == NULL) )
   1.100 +        return X86EMUL_UNHANDLEABLE;
   1.101 +
   1.102 +    if ( (rc = ops->read_segment(seg, &reg, ctxt)) != 0 )
   1.103 +        return rc;
   1.104 +
   1.105 +    reg.sel  = sel;
   1.106 +    reg.base = (uint32_t)sel << 4;
   1.107 +
   1.108 +    return ops->write_segment(seg, &reg, ctxt);
   1.109 +}
   1.110 +
   1.111  void *
   1.112  decode_register(
   1.113      uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs)
   1.114 @@ -717,6 +758,24 @@ decode_register(
   1.115      return p;
   1.116  }
   1.117  
   1.118 +#define decode_segment_failed x86_seg_tr
   1.119 +enum x86_segment
   1.120 +decode_segment(
   1.121 +    uint8_t modrm_reg)
   1.122 +{
   1.123 +    switch ( modrm_reg )
   1.124 +    {
   1.125 +    case 0: return x86_seg_es;
   1.126 +    case 1: return x86_seg_cs;
   1.127 +    case 2: return x86_seg_ss;
   1.128 +    case 3: return x86_seg_ds;
   1.129 +    case 4: return x86_seg_fs;
   1.130 +    case 5: return x86_seg_gs;
   1.131 +    default: break;
   1.132 +    }
   1.133 +    return decode_segment_failed;
   1.134 +}
   1.135 +
   1.136  int
   1.137  x86_emulate(
   1.138      struct x86_emulate_ctxt *ctxt,
   1.139 @@ -1205,6 +1264,7 @@ x86_emulate(
   1.140                  dst.val  = (dst.val & ~3) | (src_val & 3);
   1.141              else
   1.142                  dst.type = OP_NONE;
   1.143 +            generate_exception_if(in_realmode(ctxt, ops), EXC_UD);
   1.144          }
   1.145          break;
   1.146  
   1.147 @@ -1284,6 +1344,28 @@ x86_emulate(
   1.148          dst.val = src.val;
   1.149          break;
   1.150  
   1.151 +    case 0x8c: /* mov Sreg,r/m */ {
   1.152 +        struct segment_register reg;
   1.153 +        enum x86_segment seg = decode_segment(modrm_reg);
   1.154 +        generate_exception_if(seg == decode_segment_failed, EXC_UD);
   1.155 +        fail_if(ops->read_segment == NULL);
   1.156 +        if ( (rc = ops->read_segment(seg, &reg, ctxt)) != 0 )
   1.157 +            goto done;
   1.158 +        dst.val = reg.sel;
   1.159 +        if ( dst.type == OP_MEM )
   1.160 +            dst.bytes = 2;
   1.161 +        break;
   1.162 +    }
   1.163 +
   1.164 +    case 0x8e: /* mov r/m,Sreg */ {
   1.165 +        enum x86_segment seg = decode_segment(modrm_reg);
   1.166 +        generate_exception_if(seg == decode_segment_failed, EXC_UD);
   1.167 +        if ( (rc = load_seg(seg, (uint16_t)src.val, ctxt, ops)) != 0 )
   1.168 +            goto done;
   1.169 +        dst.type = OP_NONE;
   1.170 +        break;
   1.171 +    }
   1.172 +
   1.173      case 0x8d: /* lea */
   1.174          dst.val = ea.mem.off;
   1.175          break;
   1.176 @@ -1657,6 +1739,56 @@ x86_emulate(
   1.177  
   1.178      switch ( b )
   1.179      {
   1.180 +    case 0x06: /* push %%es */ {
   1.181 +        struct segment_register reg;
   1.182 +        src.val = x86_seg_es;
   1.183 +    push_seg:
   1.184 +        fail_if(ops->read_segment == NULL);
   1.185 +        if ( (rc = ops->read_segment(src.val, &reg, ctxt)) != 0 )
   1.186 +            return rc;
   1.187 +        /* 64-bit mode: PUSH defaults to a 64-bit operand. */
   1.188 +        if ( mode_64bit() && (op_bytes == 4) )
   1.189 +            op_bytes = 8;
   1.190 +        if ( (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes),
   1.191 +                              reg.sel, op_bytes, ctxt)) != 0 )
   1.192 +            goto done;
   1.193 +        break;
   1.194 +    }
   1.195 +
   1.196 +    case 0x07: /* pop %%es */
   1.197 +        src.val = x86_seg_es;
   1.198 +    pop_seg:
   1.199 +        fail_if(ops->write_segment == NULL);
   1.200 +        /* 64-bit mode: PUSH defaults to a 64-bit operand. */
   1.201 +        if ( mode_64bit() && (op_bytes == 4) )
   1.202 +            op_bytes = 8;
   1.203 +        if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
   1.204 +                             &dst.val, op_bytes, ctxt)) != 0 )
   1.205 +            goto done;
   1.206 +        if ( (rc = load_seg(src.val, (uint16_t)dst.val, ctxt, ops)) != 0 )
   1.207 +            return rc;
   1.208 +        break;
   1.209 +
   1.210 +    case 0x0e: /* push %%cs */
   1.211 +        src.val = x86_seg_cs;
   1.212 +        goto push_seg;
   1.213 +
   1.214 +    case 0x16: /* push %%ss */
   1.215 +        src.val = x86_seg_ss;
   1.216 +        goto push_seg;
   1.217 +
   1.218 +    case 0x17: /* pop %%ss */
   1.219 +        src.val = x86_seg_ss;
   1.220 +        goto pop_seg;
   1.221 +
   1.222 +    case 0x1e: /* push %%ds */
   1.223 +        src.val = x86_seg_ds;
   1.224 +        goto push_seg;
   1.225 +
   1.226 +    case 0x1f: /* pop %%ds */
   1.227 +        src.val = x86_seg_ds;
   1.228 +        goto pop_seg;
   1.229 +
   1.230      case 0x27: /* daa */ {
   1.231          uint8_t al = _regs.eax;
   1.232          unsigned long eflags = _regs.eflags;
   1.233 @@ -2066,6 +2198,18 @@ x86_emulate(
   1.234          break;
   1.235      }
   1.236  
   1.237 +    case 0xea: /* jmp (far, absolute) */ {
   1.238 +        uint16_t sel;
   1.239 +        uint32_t eip;
   1.240 +        generate_exception_if(mode_64bit(), EXC_UD);
   1.241 +        eip = insn_fetch_bytes(op_bytes);
   1.242 +        sel = insn_fetch_type(uint16_t);
   1.243 +        if ( (rc = load_seg(x86_seg_cs, sel, ctxt, ops)) != 0 )
   1.244 +            goto done;
   1.245 +        _regs.eip = eip;
   1.246 +        break;
   1.247 +    }
   1.248 +
   1.249      case 0xeb: /* jmp (short) */
   1.250          jmp_rel(insn_fetch_type(int8_t));
   1.251          break;
   1.252 @@ -2252,6 +2396,51 @@ x86_emulate(
   1.253   twobyte_special_insn:
   1.254      switch ( b )
   1.255      {
   1.256 +    case 0x01: /* Grp7 */ {
   1.257 +        struct segment_register reg;
   1.258 +
   1.259 +        switch ( modrm_reg & 7 )
   1.260 +        {
   1.261 +        case 0: /* sgdt */
   1.262 +        case 1: /* sidt */
   1.263 +            generate_exception_if(ea.type != OP_MEM, EXC_UD);
   1.264 +            fail_if(ops->read_segment == NULL);
   1.265 +            if ( (rc = ops->read_segment((modrm_reg & 1) ?
   1.266 +                                         x86_seg_idtr : x86_seg_gdtr,
   1.267 +                                         &reg, ctxt)) )
   1.268 +                goto done;
   1.269 +            if ( op_bytes == 2 )
   1.270 +                reg.base &= 0xffffff;
   1.271 +            if ( (rc = ops->write(ea.mem.seg, ea.mem.off+0,
   1.272 +                                  reg.limit, 2, ctxt)) ||
   1.273 +                 (rc = ops->write(ea.mem.seg, ea.mem.off+2,
   1.274 +                                  reg.base, mode_64bit() ? 8 : 4, ctxt)) )
   1.275 +                goto done;
   1.276 +            break;
   1.277 +        case 2: /* lgdt */
   1.278 +        case 3: /* lidt */
   1.279 +            generate_exception_if(ea.type != OP_MEM, EXC_UD);
   1.280 +            fail_if(ops->write_segment == NULL);
   1.281 +            memset(&reg, 0, sizeof(reg));
   1.282 +            if ( (rc = ops->read(ea.mem.seg, ea.mem.off+0,
   1.283 +                                 (unsigned long *)&reg.limit, 2, ctxt)) ||
   1.284 +                 (rc = ops->read(ea.mem.seg, ea.mem.off+2,
   1.285 +                                 (unsigned long *)&reg.base,
   1.286 +                                 mode_64bit() ? 8 : 4, ctxt)) )
   1.287 +                goto done;
   1.288 +            if ( op_bytes == 2 )
   1.289 +                reg.base &= 0xffffff;
   1.290 +            if ( (rc = ops->write_segment((modrm_reg & 1) ?
   1.291 +                                          x86_seg_idtr : x86_seg_gdtr,
   1.292 +                                          &reg, ctxt)) )
   1.293 +                goto done;
   1.294 +            break;
   1.295 +        default:
   1.296 +            goto cannot_emulate;
   1.297 +        }
   1.298 +        break;
   1.299 +    }
   1.300 +
   1.301      case 0x06: /* clts */
   1.302          generate_exception_if(!mode_ring0(), EXC_GP);
   1.303          fail_if((ops->read_cr == NULL) || (ops->write_cr == NULL));
   1.304 @@ -2341,6 +2530,22 @@ x86_emulate(
   1.305          break;
   1.306      }
   1.307  
   1.308 +    case 0xa0: /* push %%fs */
   1.309 +        src.val = x86_seg_fs;
   1.310 +        goto push_seg;
   1.311 +
   1.312 +    case 0xa1: /* pop %%fs */
   1.313 +        src.val = x86_seg_fs;
   1.314 +        goto pop_seg;
   1.315 +
   1.316 +    case 0xa8: /* push %%gs */
   1.317 +        src.val = x86_seg_gs;
   1.318 +        goto push_seg;
   1.319 +
   1.320 +    case 0xa9: /* pop %%gs */
   1.321 +        src.val = x86_seg_gs;
   1.322 +        goto pop_seg;
   1.323 +
   1.324      case 0xc7: /* Grp9 (cmpxchg8b) */
   1.325  #if defined(__i386__)
   1.326      {
     2.1 --- a/xen/include/asm-x86/hvm/hvm.h	Sat Nov 24 16:16:57 2007 +0000
     2.2 +++ b/xen/include/asm-x86/hvm/hvm.h	Sat Nov 24 21:40:19 2007 +0000
     2.3 @@ -26,36 +26,6 @@
     2.4  #include <public/domctl.h>
     2.5  #include <public/hvm/save.h>
     2.6  
     2.7 -/* 
     2.8 - * Attribute for segment selector. This is a copy of bit 40:47 & 52:55 of the
     2.9 - * segment descriptor. It happens to match the format of an AMD SVM VMCB.
    2.10 - */
    2.11 -typedef union segment_attributes {
    2.12 -    u16 bytes;
    2.13 -    struct
    2.14 -    {
    2.15 -        u16 type:4;    /* 0;  Bit 40-43 */
    2.16 -        u16 s:   1;    /* 4;  Bit 44 */
    2.17 -        u16 dpl: 2;    /* 5;  Bit 45-46 */
    2.18 -        u16 p:   1;    /* 7;  Bit 47 */
    2.19 -        u16 avl: 1;    /* 8;  Bit 52 */
    2.20 -        u16 l:   1;    /* 9;  Bit 53 */
    2.21 -        u16 db:  1;    /* 10; Bit 54 */
    2.22 -        u16 g:   1;    /* 11; Bit 55 */
    2.23 -    } fields;
    2.24 -} __attribute__ ((packed)) segment_attributes_t;
    2.25 -
    2.26 -/*
    2.27 - * Full state of a segment register (visible and hidden portions).
    2.28 - * Again, this happens to match the format of an AMD SVM VMCB.
    2.29 - */
    2.30 -typedef struct segment_register {
    2.31 -    u16        sel;
    2.32 -    segment_attributes_t attr;
    2.33 -    u32        limit;
    2.34 -    u64        base;
    2.35 -} __attribute__ ((packed)) segment_register_t;
    2.36 -
    2.37  /* Interrupt acknowledgement sources. */
    2.38  enum hvm_intsrc {
    2.39      hvm_intsrc_none,
     3.1 --- a/xen/include/asm-x86/hvm/svm/vmcb.h	Sat Nov 24 16:16:57 2007 +0000
     3.2 +++ b/xen/include/asm-x86/hvm/svm/vmcb.h	Sat Nov 24 21:40:19 2007 +0000
     3.3 @@ -304,7 +304,7 @@ enum VMEXIT_EXITCODE
     3.4  };
     3.5  
     3.6  /* Definition of segment state is borrowed by the generic HVM code. */
     3.7 -typedef segment_register_t svm_segment_register_t;
     3.8 +typedef struct segment_register svm_segment_register_t;
     3.9  
    3.10  typedef union 
    3.11  {
     4.1 --- a/xen/include/asm-x86/x86_emulate.h	Sat Nov 24 16:16:57 2007 +0000
     4.2 +++ b/xen/include/asm-x86/x86_emulate.h	Sat Nov 24 21:40:19 2007 +0000
     4.3 @@ -26,10 +26,7 @@
     4.4  
     4.5  struct x86_emulate_ctxt;
     4.6  
     4.7 -/*
     4.8 - * Comprehensive enumeration of x86 segment registers. Note that the system
     4.9 - * registers (TR, LDTR, GDTR, IDTR) are never referenced by the emulator.
    4.10 - */
    4.11 +/* Comprehensive enumeration of x86 segment registers. */
    4.12  enum x86_segment {
    4.13      /* General purpose. */
    4.14      x86_seg_cs,
    4.15 @@ -45,6 +42,36 @@ enum x86_segment {
    4.16      x86_seg_idtr
    4.17  };
    4.18  
    4.19 +/* 
    4.20 + * Attribute for segment selector. This is a copy of bit 40:47 & 52:55 of the
    4.21 + * segment descriptor. It happens to match the format of an AMD SVM VMCB.
    4.22 + */
    4.23 +typedef union segment_attributes {
    4.24 +    u16 bytes;
    4.25 +    struct
    4.26 +    {
    4.27 +        u16 type:4;    /* 0;  Bit 40-43 */
    4.28 +        u16 s:   1;    /* 4;  Bit 44 */
    4.29 +        u16 dpl: 2;    /* 5;  Bit 45-46 */
    4.30 +        u16 p:   1;    /* 7;  Bit 47 */
    4.31 +        u16 avl: 1;    /* 8;  Bit 52 */
    4.32 +        u16 l:   1;    /* 9;  Bit 53 */
    4.33 +        u16 db:  1;    /* 10; Bit 54 */
    4.34 +        u16 g:   1;    /* 11; Bit 55 */
    4.35 +    } fields;
    4.36 +} __attribute__ ((packed)) segment_attributes_t;
    4.37 +
    4.38 +/*
    4.39 + * Full state of a segment register (visible and hidden portions).
    4.40 + * Again, this happens to match the format of an AMD SVM VMCB.
    4.41 + */
    4.42 +struct segment_register {
    4.43 +    u16        sel;
    4.44 +    segment_attributes_t attr;
    4.45 +    u32        limit;
    4.46 +    u64        base;
    4.47 +} __attribute__ ((packed));
    4.48 +
    4.49  /*
    4.50   * Return codes from state-accessor functions and from x86_emulate().
    4.51   */
    4.52 @@ -148,6 +175,24 @@ struct x86_emulate_ops
    4.53          struct x86_emulate_ctxt *ctxt);
    4.54  
    4.55      /*
    4.56 +     * read_segment: Emulate a read of full context of a segment register.
    4.57 +     *  @reg:   [OUT] Contents of segment register (visible and hidden state).
    4.58 +     */
    4.59 +    int (*read_segment)(
    4.60 +        enum x86_segment seg,
    4.61 +        struct segment_register *reg,
    4.62 +        struct x86_emulate_ctxt *ctxt);
    4.63 +
    4.64 +    /*
    4.65 +     * write_segment: Emulate a read of full context of a segment register.
    4.66 +     *  @reg:   [OUT] Contents of segment register (visible and hidden state).
    4.67 +     */
    4.68 +    int (*write_segment)(
    4.69 +        enum x86_segment seg,
    4.70 +        struct segment_register *reg,
    4.71 +        struct x86_emulate_ctxt *ctxt);
    4.72 +
    4.73 +    /*
    4.74       * read_io: Read from I/O port(s).
    4.75       *  @port:  [IN ] Base port for access.
    4.76       */