Make improvements

- Emulator can now test the αcτµαlly pδrταblε εxεcµταblε bootloader

- Whipped up a webserver named redbean. It services 150k requests per
  second on a single core. Bundling assets inside zip enables extremely
  fast serving for two reasons. The first is that zip central directory
  lookups go faster than stat() system calls. The second is that both
  zip and gzip content-encoding use DEFLATE, therefore, compressed
  responses can be served via the sendfile() system call which does an
  in-kernel copy directly from the zip executable structure. Also note
  that red bean zip executables can be deployed easily to all platforms,
  since these native executables work on Linux, Mac, BSD, and Windows.

- Address sanitizer now works very well
This commit is contained in:
Justine Tunney 2020-09-06 21:39:00 -07:00
parent 7327c345f9
commit 416fd86676
230 changed files with 9835 additions and 5682 deletions

522
tool/build/lib/ssemov.c Normal file
View file

@ -0,0 +1,522 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/str/str.h"
#include "tool/build/lib/address.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/modrm.h"
#include "tool/build/lib/ssemov.h"
#include "tool/build/lib/throw.h"
static void MovdquVdqWdq(struct Machine *m, uint32_t rde) {
memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(m, rde), 16);
}
static void MovdquWdqVdq(struct Machine *m, uint32_t rde) {
memcpy(GetModrmRegisterXmmPointerWrite16(m, rde), XmmRexrReg(m, rde), 16);
}
static void MovupsVpsWps(struct Machine *m, uint32_t rde) {
MovdquVdqWdq(m, rde);
}
static void MovupsWpsVps(struct Machine *m, uint32_t rde) {
MovdquWdqVdq(m, rde);
}
static void MovupdVpsWps(struct Machine *m, uint32_t rde) {
MovdquVdqWdq(m, rde);
}
static void MovupdWpsVps(struct Machine *m, uint32_t rde) {
MovdquWdqVdq(m, rde);
}
void OpLddquVdqMdq(struct Machine *m, uint32_t rde) {
MovdquVdqWdq(m, rde);
}
void OpMovntiMdqpGdqp(struct Machine *m, uint32_t rde) {
if (Rexw(rde)) {
memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8);
} else {
memcpy(ComputeReserveAddressWrite4(m, rde), XmmRexrReg(m, rde), 4);
}
}
static void MovdqaVdqMdq(struct Machine *m, uint32_t rde) {
int64_t v;
uint8_t *p;
v = ComputeAddress(m, rde);
SetReadAddr(m, v, 16);
if ((v & 15) || !(p = FindReal(m, v))) ThrowSegmentationFault(m, v);
memcpy(XmmRexrReg(m, rde), Abp16(p), 16);
}
static void MovdqaMdqVdq(struct Machine *m, uint32_t rde) {
int64_t v;
uint8_t *p;
v = ComputeAddress(m, rde);
SetWriteAddr(m, v, 16);
if ((v & 15) || !(p = FindReal(m, v))) ThrowSegmentationFault(m, v);
memcpy(Abp16(p), XmmRexrReg(m, rde), 16);
}
static void MovdqaVdqWdq(struct Machine *m, uint32_t rde) {
if (IsModrmRegister(rde)) {
memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde), 16);
} else {
MovdqaVdqMdq(m, rde);
}
}
static void MovdqaWdqVdq(struct Machine *m, uint32_t rde) {
if (IsModrmRegister(rde)) {
memcpy(XmmRexbRm(m, rde), XmmRexrReg(m, rde), 16);
} else {
MovdqaMdqVdq(m, rde);
}
}
static void MovntdqMdqVdq(struct Machine *m, uint32_t rde) {
MovdqaMdqVdq(m, rde);
}
static void MovntpsMpsVps(struct Machine *m, uint32_t rde) {
MovdqaMdqVdq(m, rde);
}
static void MovntpdMpdVpd(struct Machine *m, uint32_t rde) {
MovdqaMdqVdq(m, rde);
}
void OpMovntdqaVdqMdq(struct Machine *m, uint32_t rde) {
MovdqaVdqMdq(m, rde);
}
static void MovqPqQq(struct Machine *m, uint32_t rde) {
memcpy(MmReg(m, rde), GetModrmRegisterMmPointerRead8(m, rde), 8);
}
static void MovqQqPq(struct Machine *m, uint32_t rde) {
memcpy(GetModrmRegisterMmPointerWrite8(m, rde), MmReg(m, rde), 8);
}
static void MovqVdqEqp(struct Machine *m, uint32_t rde) {
memcpy(XmmRexrReg(m, rde), GetModrmRegisterWordPointerRead8(m, rde), 8);
memset(XmmRexrReg(m, rde) + 8, 0, 8);
}
static void MovdVdqEd(struct Machine *m, uint32_t rde) {
memset(XmmRexrReg(m, rde), 0, 16);
memcpy(XmmRexrReg(m, rde), GetModrmRegisterWordPointerRead4(m, rde), 4);
}
static void MovqPqEqp(struct Machine *m, uint32_t rde) {
memcpy(MmReg(m, rde), GetModrmRegisterWordPointerRead8(m, rde), 8);
}
static void MovdPqEd(struct Machine *m, uint32_t rde) {
memcpy(MmReg(m, rde), GetModrmRegisterWordPointerRead4(m, rde), 4);
memset(MmReg(m, rde) + 4, 0, 4);
}
static void MovdEdVdq(struct Machine *m, uint32_t rde) {
if (IsModrmRegister(rde)) {
Write64(RegRexbRm(m, rde), Read32(XmmRexrReg(m, rde)));
} else {
memcpy(ComputeReserveAddressWrite4(m, rde), XmmRexrReg(m, rde), 4);
}
}
static void MovqEqpVdq(struct Machine *m, uint32_t rde) {
memcpy(GetModrmRegisterWordPointerWrite8(m, rde), XmmRexrReg(m, rde), 8);
}
static void MovdEdPq(struct Machine *m, uint32_t rde) {
if (IsModrmRegister(rde)) {
Write64(RegRexbRm(m, rde), Read32(MmReg(m, rde)));
} else {
memcpy(ComputeReserveAddressWrite4(m, rde), MmReg(m, rde), 4);
}
}
static void MovqEqpPq(struct Machine *m, uint32_t rde) {
memcpy(GetModrmRegisterWordPointerWrite(m, rde, 8), MmReg(m, rde), 8);
}
static void MovntqMqPq(struct Machine *m, uint32_t rde) {
memcpy(ComputeReserveAddressWrite8(m, rde), MmReg(m, rde), 8);
}
static void MovqVqWq(struct Machine *m, uint32_t rde) {
memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead8(m, rde), 8);
memset(XmmRexrReg(m, rde) + 8, 0, 8);
}
static void MovssVpsWps(struct Machine *m, uint32_t rde) {
memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead4(m, rde), 4);
}
static void MovssWpsVps(struct Machine *m, uint32_t rde) {
memcpy(GetModrmRegisterXmmPointerWrite4(m, rde), XmmRexrReg(m, rde), 4);
}
static void MovsdVpsWps(struct Machine *m, uint32_t rde) {
memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(m, rde), 8);
}
static void MovsdWpsVps(struct Machine *m, uint32_t rde) {
memcpy(GetModrmRegisterXmmPointerWrite16(m, rde), XmmRexrReg(m, rde), 8);
}
static void MovhlpsVqUq(struct Machine *m, uint32_t rde) {
memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde) + 8, 8);
}
static void MovlpsVqMq(struct Machine *m, uint32_t rde) {
memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(m, rde), 8);
}
static void MovlpdVqMq(struct Machine *m, uint32_t rde) {
memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(m, rde), 8);
}
static void MovddupVqWq(struct Machine *m, uint32_t rde) {
uint8_t *src;
src = GetModrmRegisterXmmPointerRead8(m, rde);
memcpy(XmmRexrReg(m, rde) + 0, src, 8);
memcpy(XmmRexrReg(m, rde) + 8, src, 8);
}
static void MovsldupVqWq(struct Machine *m, uint32_t rde) {
uint8_t *dst, *src;
dst = XmmRexrReg(m, rde);
src = GetModrmRegisterXmmPointerRead16(m, rde);
memcpy(dst + 0 + 0, src + 0, 4);
memcpy(dst + 0 + 4, src + 0, 4);
memcpy(dst + 8 + 0, src + 8, 4);
memcpy(dst + 8 + 4, src + 8, 4);
}
static void MovlpsMqVq(struct Machine *m, uint32_t rde) {
memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8);
}
static void MovlpdMqVq(struct Machine *m, uint32_t rde) {
memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8);
}
static void MovlhpsVqUq(struct Machine *m, uint32_t rde) {
memcpy(XmmRexrReg(m, rde) + 8, XmmRexbRm(m, rde), 8);
}
static void MovhpsVqMq(struct Machine *m, uint32_t rde) {
memcpy(XmmRexrReg(m, rde) + 8, ComputeReserveAddressRead8(m, rde), 8);
}
static void MovhpdVqMq(struct Machine *m, uint32_t rde) {
memcpy(XmmRexrReg(m, rde) + 8, ComputeReserveAddressRead8(m, rde), 8);
}
static void MovshdupVqWq(struct Machine *m, uint32_t rde) {
uint8_t *dst, *src;
dst = XmmRexrReg(m, rde);
src = GetModrmRegisterXmmPointerRead16(m, rde);
memcpy(dst + 0 + 0, src + 04, 4);
memcpy(dst + 0 + 4, src + 04, 4);
memcpy(dst + 8 + 0, src + 12, 4);
memcpy(dst + 8 + 4, src + 12, 4);
}
static void MovhpsMqVq(struct Machine *m, uint32_t rde) {
memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde) + 8, 8);
}
static void MovhpdMqVq(struct Machine *m, uint32_t rde) {
memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde) + 8, 8);
}
static void MovqWqVq(struct Machine *m, uint32_t rde) {
if (IsModrmRegister(rde)) {
memcpy(XmmRexbRm(m, rde), XmmRexrReg(m, rde), 8);
memset(XmmRexbRm(m, rde) + 8, 0, 8);
} else {
memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8);
}
}
static void Movq2dqVdqNq(struct Machine *m, uint32_t rde) {
memcpy(XmmRexrReg(m, rde), MmRm(m, rde), 8);
memset(XmmRexrReg(m, rde) + 8, 0, 8);
}
static void Movdq2qPqUq(struct Machine *m, uint32_t rde) {
memcpy(MmReg(m, rde), XmmRexbRm(m, rde), 8);
}
static void MovapsVpsWps(struct Machine *m, uint32_t rde) {
MovdqaVdqWdq(m, rde);
}
static void MovapdVpdWpd(struct Machine *m, uint32_t rde) {
MovdqaVdqWdq(m, rde);
}
static void MovapsWpsVps(struct Machine *m, uint32_t rde) {
MovdqaWdqVdq(m, rde);
}
static void MovapdWpdVpd(struct Machine *m, uint32_t rde) {
MovdqaWdqVdq(m, rde);
}
void OpMovWpsVps(struct Machine *m, uint32_t rde) {
uint8_t *p, *r;
switch (Rep(rde) | Osz(rde)) {
case 0:
MovupsWpsVps(m, rde);
break;
case 1:
MovupdWpsVps(m, rde);
break;
case 2:
MovsdWpsVps(m, rde);
break;
case 3:
MovssWpsVps(m, rde);
break;
default:
unreachable;
}
}
void OpMov0f28(struct Machine *m, uint32_t rde) {
if (!Osz(rde)) {
MovapsVpsWps(m, rde);
} else {
MovapdVpdWpd(m, rde);
}
}
void OpMov0f6e(struct Machine *m, uint32_t rde) {
if (Osz(rde)) {
if (Rexw(rde)) {
MovqVdqEqp(m, rde);
} else {
MovdVdqEd(m, rde);
}
} else {
if (Rexw(rde)) {
MovqPqEqp(m, rde);
} else {
MovdPqEd(m, rde);
}
}
}
void OpMov0f6f(struct Machine *m, uint32_t rde) {
if (Osz(rde)) {
MovdqaVdqWdq(m, rde);
} else if (Rep(rde) == 3) {
MovdquVdqWdq(m, rde);
} else {
MovqPqQq(m, rde);
}
}
void OpMov0fE7(struct Machine *m, uint32_t rde) {
if (!Osz(rde)) {
MovntqMqPq(m, rde);
} else {
MovntdqMdqVdq(m, rde);
}
}
void OpMov0f7e(struct Machine *m, uint32_t rde) {
if (Rep(rde) == 3) {
MovqVqWq(m, rde);
} else if (Osz(rde)) {
if (Rexw(rde)) {
MovqEqpVdq(m, rde);
} else {
MovdEdVdq(m, rde);
}
} else {
if (Rexw(rde)) {
MovqEqpPq(m, rde);
} else {
MovdEdPq(m, rde);
}
}
}
void OpMov0f7f(struct Machine *m, uint32_t rde) {
if (Rep(rde) == 3) {
MovdquWdqVdq(m, rde);
} else if (Osz(rde)) {
MovdqaWdqVdq(m, rde);
} else {
MovqQqPq(m, rde);
}
}
void OpMov0f10(struct Machine *m, uint32_t rde) {
uint8_t *p, *r;
switch (Rep(rde) | Osz(rde)) {
case 0:
MovupsVpsWps(m, rde);
break;
case 1:
MovupdVpsWps(m, rde);
break;
case 2:
MovsdVpsWps(m, rde);
break;
case 3:
MovssVpsWps(m, rde);
break;
default:
unreachable;
}
}
void OpMov0f29(struct Machine *m, uint32_t rde) {
if (!Osz(rde)) {
MovapsWpsVps(m, rde);
} else {
MovapdWpdVpd(m, rde);
}
}
void OpMov0f2b(struct Machine *m, uint32_t rde) {
if (!Osz(rde)) {
MovntpsMpsVps(m, rde);
} else {
MovntpdMpdVpd(m, rde);
}
}
void OpMov0f12(struct Machine *m, uint32_t rde) {
switch (Rep(rde) | Osz(rde)) {
case 0:
if (IsModrmRegister(rde)) {
MovhlpsVqUq(m, rde);
} else {
MovlpsVqMq(m, rde);
}
break;
case 1:
MovlpdVqMq(m, rde);
break;
case 2:
MovddupVqWq(m, rde);
break;
case 3:
MovsldupVqWq(m, rde);
break;
default:
unreachable;
}
}
void OpMov0f13(struct Machine *m, uint32_t rde) {
if (Osz(rde)) {
MovlpdMqVq(m, rde);
} else {
MovlpsMqVq(m, rde);
}
}
void OpMov0f16(struct Machine *m, uint32_t rde) {
switch (Rep(rde) | Osz(rde)) {
case 0:
if (IsModrmRegister(rde)) {
MovlhpsVqUq(m, rde);
} else {
MovhpsVqMq(m, rde);
}
break;
case 1:
MovhpdVqMq(m, rde);
break;
case 3:
MovshdupVqWq(m, rde);
break;
default:
OpUd(m, rde);
break;
}
}
void OpMov0f17(struct Machine *m, uint32_t rde) {
if (Osz(rde)) {
MovhpdMqVq(m, rde);
} else {
MovhpsMqVq(m, rde);
}
}
void OpMov0fD6(struct Machine *m, uint32_t rde) {
if (Rep(rde) == 3) {
Movq2dqVdqNq(m, rde);
} else if (Rep(rde) == 2) {
Movdq2qPqUq(m, rde);
} else if (Osz(rde)) {
MovqWqVq(m, rde);
} else {
OpUd(m, rde);
}
}
static uint8_t pmovmskb(uint64_t x) {
return (x & 0x0000000000000080) >> 007 | (x & 0x0000000000008000) >> 016 |
(x & 0x0000000000800000) >> 025 | (x & 0x0000000080000000) >> 034 |
(x & 0x0000008000000000) >> 043 | (x & 0x0000800000000000) >> 052 |
(x & 0x0080000000000000) >> 061 | (x & 0x8000000000000000) >> 070;
}
void OpPmovmskbGdqpNqUdq(struct Machine *m, uint32_t rde) {
uint64_t bitmask;
if (Osz(rde)) {
bitmask = pmovmskb(Read64(XmmRexbRm(m, rde) + 8)) << 8 |
pmovmskb(Read64(XmmRexbRm(m, rde)));
} else {
bitmask = pmovmskb(Read64(MmRm(m, rde) + 8)) << 8 |
pmovmskb(Read64(MmRm(m, rde)));
}
Write64(RegRexrReg(m, rde), bitmask);
}
void OpMaskMovDiXmmRegXmmRm(struct Machine *m, uint32_t rde) {
void *p[2];
uint64_t v;
unsigned i, n;
uint8_t *mem, b[16];
v = AddressDi(m, rde);
n = Osz(rde) ? 16 : 8;
mem = BeginStore(m, v, n, p, b);
for (i = 0; i < n; ++i) {
if (XmmRexbRm(m, rde)[i] & 0x80) {
mem[i] = XmmRexrReg(m, rde)[i];
}
}
EndStore(m, v, n, p, b);
}