* Unaligned load/store emulation */
| 1522 | * Unaligned load/store emulation |
| 1523 | */ |
| 1524 | static int |
| 1525 | mips_unaligned_load_store(struct trapframe *frame, int mode, register_t addr, register_t pc) |
| 1526 | { |
| 1527 | register_t *reg = (register_t *) frame; |
| 1528 | u_int32_t inst = *((u_int32_t *)(intptr_t)pc); |
| 1529 | register_t value_msb = 0, value = 0; |
| 1530 | unsigned size; |
| 1531 | |
| 1532 | /* |
| 1533 | * ADDR_ERR faults have higher priority than TLB |
| 1534 | * Miss faults. Therefore, it is necessary to |
| 1535 | * verify that the faulting address is a valid |
| 1536 | * virtual address within the process' address space |
| 1537 | * before trying to emulate the unaligned access. |
| 1538 | */ |
| 1539 | switch (MIPS_INST_OPCODE(inst)) { |
| 1540 | case OP_LHU: case OP_LH: |
| 1541 | case OP_SH: |
| 1542 | size = 2; |
| 1543 | break; |
| 1544 | case OP_LWU: case OP_LW: |
| 1545 | case OP_SW: |
| 1546 | size = 4; |
| 1547 | break; |
| 1548 | case OP_LD: |
| 1549 | case OP_SD: |
| 1550 | size = 8; |
| 1551 | break; |
| 1552 | default: |
| 1553 | printf("%s: unhandled opcode in address error: %#x\n", __func__, MIPS_INST_OPCODE(inst)); |
| 1554 | return (0); |
| 1555 | } |
| 1556 | |
| 1557 | if (!useracc((void *)rounddown2((vm_offset_t)addr, size), size * 2, mode)) |
| 1558 | return (0); |
| 1559 | |
| 1560 | /* |
| 1561 | * XXX |
| 1562 | * Handle LL/SC LLD/SCD. |
| 1563 | */ |
| 1564 | switch (MIPS_INST_OPCODE(inst)) { |
| 1565 | case OP_LHU: |
| 1566 | KASSERT(mode == VM_PROT_READ, ("access mode must be read for load instruction.")); |
| 1567 | lbu_macro(value_msb, addr); |
| 1568 | addr += 1; |
| 1569 | lbu_macro(value, addr); |
| 1570 | value |= value_msb << 8; |
| 1571 | reg[MIPS_INST_RT(inst)] = value; |
| 1572 | return (MIPS_LHU_ACCESS); |
| 1573 | |
| 1574 | case OP_LH: |
| 1575 | KASSERT(mode == VM_PROT_READ, ("access mode must be read for load instruction.")); |
| 1576 | lb_macro(value_msb, addr); |
| 1577 | addr += 1; |
| 1578 | lbu_macro(value, addr); |
| 1579 | value |= value_msb << 8; |
| 1580 | reg[MIPS_INST_RT(inst)] = value; |
| 1581 | return (MIPS_LH_ACCESS); |
no test coverage detected