waterbox: add guard pages to libco stacks
This commit is contained in:
parent
8a24960cce
commit
626de2d7c8
|
@ -42,6 +42,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
|
||||
private class Bin
|
||||
{
|
||||
public const MemoryBlock.Protection _FreeProt = (MemoryBlock.Protection)255;
|
||||
|
||||
/// <summary>
|
||||
/// first page# in this bin, inclusive
|
||||
/// </summary>
|
||||
|
@ -62,11 +64,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
{
|
||||
get
|
||||
{
|
||||
return (byte)Protection == 255;
|
||||
return Protection == _FreeProt;
|
||||
}
|
||||
set
|
||||
{
|
||||
Protection = value ? (MemoryBlock.Protection)255 : MemoryBlock.Protection.None;
|
||||
Protection = value ? _FreeProt : MemoryBlock.Protection.None;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,7 +265,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
var ds = Memory.GetStream(ret, oldSize, true);
|
||||
ss.CopyTo(ds);
|
||||
Memory.Protect(ret, oldSize, oldStartBin.Protection);
|
||||
UnmapPagesInternal(oldStartPage, oldNumPages, oldStartBin);
|
||||
ProtectPagesInternal(oldStartPage, oldNumPages, oldStartBin, Bin._FreeProt);
|
||||
//EnsureUsedInternal();
|
||||
return ret;
|
||||
}
|
||||
|
@ -276,7 +278,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
{
|
||||
// shrink in place
|
||||
var s = GetBinForStartPage(newEndPage);
|
||||
UnmapPagesInternal(newEndPage, oldEndPage - newEndPage, s);
|
||||
ProtectPagesInternal(newEndPage, oldEndPage - newEndPage, s, Bin._FreeProt);
|
||||
//EnsureUsedInternal();
|
||||
return start;
|
||||
}
|
||||
|
@ -302,14 +304,34 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
if (GetBinForEndPageEnsureAllocated(endPage, startBin) == null)
|
||||
return false;
|
||||
|
||||
UnmapPagesInternal(startPage, numPages, startBin);
|
||||
ProtectPagesInternal(startPage, numPages, startBin, Bin._FreeProt);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Protect(ulong start, ulong size, MemoryBlock.Protection prot)
|
||||
{
|
||||
// TODO: lots of copy paste here
|
||||
if (start < Memory.Start || start + size > Memory.End)
|
||||
return false;
|
||||
if (size == 0)
|
||||
return true;
|
||||
|
||||
var startPage = GetPage(start);
|
||||
var numPages = WaterboxUtils.PagesNeeded(size);
|
||||
var endPage = startPage + numPages;
|
||||
// to change protection, the entire area must currently be mapped
|
||||
var startBin = GetBinForStartPage(startPage);
|
||||
if (GetBinForEndPageEnsureAllocated(endPage, startBin) == null)
|
||||
return false;
|
||||
|
||||
ProtectPagesInternal(startPage, numPages, startBin, prot);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// frees some pages. assumes they are all allocated
|
||||
/// frees or changes the protection on some pages. assumes they are all allocated
|
||||
/// </summary>
|
||||
private void UnmapPagesInternal(int startPage, int numPages, Bin startBin)
|
||||
private void ProtectPagesInternal(int startPage, int numPages, Bin startBin, MemoryBlock.Protection prot)
|
||||
{
|
||||
// from the various paths we took to get here, we must be unmapping at least one page
|
||||
|
||||
|
@ -318,10 +340,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
if (freeBin.StartPage != startPage)
|
||||
{
|
||||
freeBin.Cleave(startPage - freeBin.StartPage);
|
||||
freeBin.Next.Protection = freeBin.Protection;
|
||||
freeBin = freeBin.Next;
|
||||
}
|
||||
freeBin.Free = true;
|
||||
MemoryBlock.Protection lastEaten = MemoryBlock.Protection.None;
|
||||
MemoryBlock.Protection lastEaten = freeBin.Protection;
|
||||
while (freeBin.EndPage < endPage)
|
||||
{
|
||||
freeBin.PageCount += freeBin.Next.PageCount;
|
||||
|
@ -332,11 +354,19 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
{
|
||||
freeBin.Next.Protection = lastEaten;
|
||||
}
|
||||
freeBin.Protection = prot;
|
||||
freeBin.ApplyProtection(Memory);
|
||||
|
||||
var totalSize = ((ulong)numPages) << WaterboxUtils.PageShift;
|
||||
Used -= totalSize;
|
||||
Console.WriteLine($"Freed {totalSize} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
|
||||
if (prot == Bin._FreeProt)
|
||||
{
|
||||
Used -= totalSize;
|
||||
Console.WriteLine($"Freed {totalSize} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Set protection for {totalSize} bytes on {Name} to {prot}");
|
||||
}
|
||||
//EnsureUsedInternal();
|
||||
}
|
||||
|
||||
|
|
|
@ -456,6 +456,25 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
{
|
||||
return _parent._mmapheap.Unmap((ulong)address, (ulong)size) ? 0 : -1;
|
||||
}
|
||||
|
||||
[BizExport(CallingConvention.Cdecl, EntryPoint = "n10")]
|
||||
public int MProtect(UIntPtr address, UIntPtr size, int prot)
|
||||
{
|
||||
MemoryBlock.Protection mprot;
|
||||
switch (prot)
|
||||
{
|
||||
case 0: mprot = MemoryBlock.Protection.None; break;
|
||||
default:
|
||||
case 6: // W^X
|
||||
case 7: // W^X
|
||||
case 4: // exec only????
|
||||
case 2: return -1; // write only????
|
||||
case 3: mprot = MemoryBlock.Protection.RW; break;
|
||||
case 1: mprot = MemoryBlock.Protection.R; break;
|
||||
case 5: mprot = MemoryBlock.Protection.RX; break;
|
||||
}
|
||||
return _parent._mmapheap.Protect((ulong)address, (ulong)size, mprot) ? 0 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,6 @@
|
|||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
"editor.insertSpaces": false,
|
||||
"editor.detectIndentation": false,
|
||||
"editor.tabSize": 4
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
CC = x86_64-nt64-midipix-gcc
|
||||
AS = nasm
|
||||
|
||||
CCFLAGS:= -Wall -O3
|
||||
CCFLAGS:= -Wall -O3 -std=c99
|
||||
ASFLAGS:= -f elf64
|
||||
|
||||
TARGET = libco.so
|
||||
|
@ -21,25 +21,25 @@ AOBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_AOBJS))
|
|||
|
||||
$(OBJ_DIR)/%.c.o: %.c
|
||||
@mkdir -p $(@D)
|
||||
$(CC) -c -o $@ $< $(CCFLAGS)
|
||||
@$(CC) -c -o $@ $< $(CCFLAGS)
|
||||
|
||||
$(OBJ_DIR)/%.s.o: %.s
|
||||
@mkdir -p $(@D)
|
||||
$(AS) $(ASFLAGS) -o $@ $<
|
||||
@$(AS) $(ASFLAGS) -o $@ $<
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
.PHONY: clean all
|
||||
|
||||
$(TARGET): $(OBJS) $(AOBJS)
|
||||
$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) $(AOBJS)
|
||||
mv $(TARGET) $(TARGET).in
|
||||
strip $(TARGET).in -o $(TARGET) -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104
|
||||
@$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) $(AOBJS)
|
||||
@mv $(TARGET) $(TARGET).in
|
||||
@strip $(TARGET).in -o $(TARGET) -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJ_DIR)
|
||||
rm -f $(TARGET).in
|
||||
rm -f $(TARGET)
|
||||
@rm -rf $(OBJ_DIR)
|
||||
@rm -f $(TARGET).in
|
||||
@rm -f $(TARGET)
|
||||
|
||||
#install:
|
||||
# $(CP) $(TARGET) $(DEST_$(ARCH))
|
||||
|
|
|
@ -7,76 +7,94 @@
|
|||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <sys/mman.h>
|
||||
|
||||
static long long co_active_buffer[64];
|
||||
static cothread_t co_active_handle = 0;
|
||||
|
||||
static void* smalloc(size_t size)
|
||||
// allocations are 16k larger than asked for,
|
||||
// and include guard space between the stack and the storage
|
||||
|
||||
static void* alloc_thread(size_t* size)
|
||||
{
|
||||
char* ret = malloc(size + 16);
|
||||
if (ret)
|
||||
{
|
||||
*(size_t*)ret = size;
|
||||
return ret + 16;
|
||||
}
|
||||
return NULL;
|
||||
// align up to 4k
|
||||
*size = (*size + 16384 + 4095) & ~4095;
|
||||
|
||||
uint64_t* ptr = mmap(NULL, *size,
|
||||
PROT_READ | PROT_WRITE, MAP_ANONYMOUS, -1, 0);
|
||||
if (ptr == (uint64_t*)(-1))
|
||||
return NULL;
|
||||
|
||||
ptr[512] = *size;
|
||||
for (int i = 513; i < 2048; i++)
|
||||
ptr[i] = 0xdeadbeefdeadbeef;
|
||||
|
||||
if (mprotect(ptr + 512, 512 * 3 * sizeof(uint64_t), PROT_NONE) != 0)
|
||||
abort();
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void sfree(void* ptr)
|
||||
static void free_thread(void* p)
|
||||
{
|
||||
char* original = (char*)ptr - 16;
|
||||
size_t size = *(size_t*)original + 16;
|
||||
memset(original, 0, size);
|
||||
free(original);
|
||||
uint64_t* ptr = (uint64_t*)p;
|
||||
if (mprotect(ptr + 512, 512 * 3 * sizeof(uint64_t), PROT_READ | PROT_WRITE) != 0)
|
||||
abort();
|
||||
uint64_t size = ptr[512];
|
||||
memset(p, 0, size);
|
||||
if (munmap(ptr, size) != 0)
|
||||
abort();
|
||||
}
|
||||
|
||||
extern void co_swap(cothread_t, cothread_t);
|
||||
|
||||
static void crash() {
|
||||
assert(0); /* called only if cothread_t entrypoint returns */
|
||||
static void crash()
|
||||
{
|
||||
assert(0); /* called only if cothread_t entrypoint returns */
|
||||
}
|
||||
|
||||
void co_clean() {
|
||||
memset(co_active_buffer, 0, sizeof(co_active_buffer));
|
||||
void co_clean()
|
||||
{
|
||||
memset(co_active_buffer, 0, sizeof(co_active_buffer));
|
||||
}
|
||||
|
||||
cothread_t co_active() {
|
||||
if(!co_active_handle) co_active_handle = &co_active_buffer;
|
||||
return co_active_handle;
|
||||
cothread_t co_active()
|
||||
{
|
||||
if (!co_active_handle)
|
||||
co_active_handle = &co_active_buffer;
|
||||
return co_active_handle;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
|
||||
cothread_t handle;
|
||||
if(!co_active_handle) co_active_handle = &co_active_buffer;
|
||||
size += 512; /* allocate additional space for storage */
|
||||
size &= ~15; /* align stack to 16-byte boundary */
|
||||
cothread_t co_create(unsigned int sz, void (*entrypoint)(void))
|
||||
{
|
||||
cothread_t handle;
|
||||
if (!co_active_handle)
|
||||
co_active_handle = &co_active_buffer;
|
||||
|
||||
if(handle = (cothread_t)smalloc(size)) {
|
||||
long long *p = (long long*)((char*)handle + size); /* seek to top of stack */
|
||||
*--p = (long long)crash; /* crash if entrypoint returns */
|
||||
*--p = (long long)entrypoint; /* start of function */
|
||||
*(long long*)handle = (long long)p; /* stack pointer */
|
||||
}
|
||||
uint64_t size = sz;
|
||||
|
||||
return handle;
|
||||
if (handle = (cothread_t)alloc_thread(&size))
|
||||
{
|
||||
uint64_t* p = (uint64_t*)((char*)handle + size); // seek to top of stack
|
||||
*--p = (uint64_t)crash; /* crash if entrypoint returns */
|
||||
*--p = (uint64_t)entrypoint; /* start of function */
|
||||
*(uint64_t*)handle = (uint64_t)p; /* stack pointer */
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t handle) {
|
||||
sfree(handle);
|
||||
void co_delete(cothread_t handle)
|
||||
{
|
||||
free_thread(handle);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t handle) {
|
||||
register cothread_t co_previous_handle = co_active_handle;
|
||||
co_swap(co_active_handle = handle, co_previous_handle);
|
||||
void co_switch(cothread_t handle)
|
||||
{
|
||||
register cothread_t co_previous_handle = co_active_handle;
|
||||
co_swap(co_active_handle = handle, co_previous_handle);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue