more wip
This commit is contained in:
8
Makefile
8
Makefile
@@ -24,8 +24,9 @@ LD := $(CONTAINER_CMD) i686-elf-ld
|
|||||||
AS := $(CONTAINER_CMD) i686-elf-as
|
AS := $(CONTAINER_CMD) i686-elf-as
|
||||||
AR := $(CONTAINER_CMD) i686-elf-ar
|
AR := $(CONTAINER_CMD) i686-elf-ar
|
||||||
|
|
||||||
C_SOURCES := $(shell find $(SOURCE_DIR) ! -name '*_test*' -name '*.c')
|
C_SOURCES := $(shell set -x; find $(SOURCE_DIR) -path $(SOURCE_DIR)/userspace -prune -o -type f -name '*.c' ! -name '*_test*' -print)
|
||||||
ASM_SOURCES := $(shell find $(SOURCE_DIR) -name '*.S')
|
$(info C_SOURCES=$(C_SOURCES))
|
||||||
|
ASM_SOURCES := $(shell find $(SOURCE_DIR) -name '*.S' ! -name '*userspace*')
|
||||||
OBJECTS := $(patsubst $(SOURCE_DIR)/%, $(BUILD_DIR)/%, $(C_SOURCES:.c=.o) $(ASM_SOURCES:.S=.o))
|
OBJECTS := $(patsubst $(SOURCE_DIR)/%, $(BUILD_DIR)/%, $(C_SOURCES:.c=.o) $(ASM_SOURCES:.S=.o))
|
||||||
DEPENDS := $(patsubst $(SOURCE_DIR)/%, $(BUILD_DIR)/%, $(C_SOURCES:.c=.d))
|
DEPENDS := $(patsubst $(SOURCE_DIR)/%, $(BUILD_DIR)/%, $(C_SOURCES:.c=.d))
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ myos.iso: $(BUILD_DIR)/myos.bin
|
|||||||
|
|
||||||
$(BUILD_DIR)/myos.bin: $(OBJECTS)
|
$(BUILD_DIR)/myos.bin: $(OBJECTS)
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
$(CC) -T linker.ld -o $@ $(CFLAGS) -nostdlib $^ -lgcc
|
$(CC) -T linker.ld -o $@ $(CFLAGS) -nostdlib $(OBJECTS) -lgcc
|
||||||
|
|
||||||
-include $(DEPENDS)
|
-include $(DEPENDS)
|
||||||
|
|
||||||
@@ -75,7 +76,6 @@ $(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.S Makefile
|
|||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
$(AS) $(ASFLAGS) $< -o $@
|
$(AS) $(ASFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
###################
|
###################
|
||||||
# TESTS #
|
# TESTS #
|
||||||
###################
|
###################
|
||||||
|
|||||||
13
linker.ld
13
linker.ld
@@ -58,11 +58,20 @@ SECTIONS
|
|||||||
{
|
{
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
|
|
||||||
kernel_memory_end = .;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kernel_memory_end = 0x400000;
|
||||||
|
. = 0x400000;
|
||||||
|
|
||||||
/* The compiler may produce other sections, by default it will put them in
|
/* The compiler may produce other sections, by default it will put them in
|
||||||
a segment with the same name. Simply add stuff here as needed. */
|
a segment with the same name. Simply add stuff here as needed. */
|
||||||
|
|
||||||
|
.userland-text ALIGN(16) : {
|
||||||
|
*(.userland-text)
|
||||||
|
}
|
||||||
|
|
||||||
|
.userland-rodata ALIGN(16) : {
|
||||||
|
*(.userland-rodata)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
291
src/kernel/file_system.c
Normal file
291
src/kernel/file_system.c
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
|
||||||
|
#include "file_system.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "malloc.h"
|
||||||
|
#include "libc.h"
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
#define MIN(a, b) ((a) > (b) ? (b) : (a))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File node implementation
|
||||||
|
* ========================
|
||||||
|
* */
|
||||||
|
static void node_init(struct file_node* n, uint32_t block_offset)
|
||||||
|
{
|
||||||
|
n->block_offset = block_offset;
|
||||||
|
n->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [path -> file] mapping
|
||||||
|
* ========
|
||||||
|
*/
|
||||||
|
static uint32_t djb2_hash(struct str key)
|
||||||
|
{
|
||||||
|
/* credits: Daniel J. Bernstein */
|
||||||
|
uint32_t hash = 5381;
|
||||||
|
for (size_t i = 0; i < key.len; i++) {
|
||||||
|
hash <<= 5;
|
||||||
|
hash += (uint32_t)key.data[i];
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct file_path* file_map_at(struct file_path_map* file_map, struct str path)
|
||||||
|
{
|
||||||
|
const uint32_t hash = djb2_hash(path) % FILE_MAP_SIZE;
|
||||||
|
return &(file_map->entries[hash]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct file_path* collision_alternative(struct file_path_map* file_map, struct file_path* f)
|
||||||
|
{
|
||||||
|
/* i = (i + 1) % FILE_MAP_SIZE */
|
||||||
|
return ((f - file_map->entries + 1) % FILE_MAP_SIZE) + file_map->entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct file_path* file_map_get(struct file_path_map* file_map, struct str path)
|
||||||
|
{
|
||||||
|
struct file_path* f = file_map_at(file_map, path);
|
||||||
|
|
||||||
|
for (int i = 0; i < FILE_MAP_SIZE; i++) {
|
||||||
|
if ((f->attr & FILE_PRESENT) == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
uint32_t min = MIN(path.len, f->name_len);
|
||||||
|
if (memcmp(path.data, f->name, min) == 0) {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
f = collision_alternative(file_map, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct file_path* file_map_insert(struct file_path_map* map, struct str path)
|
||||||
|
{
|
||||||
|
if (map->count == FILE_MAP_SIZE) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
struct file_path* f = file_map_at(map, path);
|
||||||
|
|
||||||
|
for (int i = 0; i < FILE_MAP_SIZE; i++) {
|
||||||
|
uint32_t min = MIN(path.len, f->name_len);
|
||||||
|
if (memcmp(path.data, f->name, min) == 0) {
|
||||||
|
return NULL /* file with name already exists */;
|
||||||
|
}
|
||||||
|
f = collision_alternative(map, f);
|
||||||
|
if ((f->attr & FILE_PRESENT) == 0) {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ramdisk implementation
|
||||||
|
* ===========
|
||||||
|
*/
|
||||||
|
constexpr int RAMDISK_BLOCK_SIZE = 4096;
|
||||||
|
constexpr int RAMDISK_BLOCK_COUNT = 128;
|
||||||
|
|
||||||
|
uint8_t ramdisk_data[RAMDISK_BLOCK_SIZE * RAMDISK_BLOCK_COUNT];
|
||||||
|
uint32_t ramdisk_free_bitmap[RAMDISK_BLOCK_COUNT / (sizeof(uint32_t) * CHAR_BIT)];
|
||||||
|
|
||||||
|
/* returns block offset */
|
||||||
|
int ramdisk_allocate_block(struct file_system* fs)
|
||||||
|
{
|
||||||
|
int free_pos = bitmap_find(&fs->free_blocks_bitmap, 0);
|
||||||
|
if (free_pos == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (bitmap_set(&fs->free_blocks_bitmap, free_pos)) {
|
||||||
|
/* this means there's an error in the bitmap implementation */
|
||||||
|
panic(str_attach("failed to set bitmap when allocating block"));
|
||||||
|
}
|
||||||
|
return free_pos * RAMDISK_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ramdisk_write_block(struct file_system*, uint32_t block_offset, const uint8_t* buf)
|
||||||
|
{
|
||||||
|
/* for now just use the memory as a file system */
|
||||||
|
for (size_t i = 0; i < RAMDISK_BLOCK_SIZE; i++) {
|
||||||
|
ramdisk_data[block_offset + i] = buf[i];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ramdisk_read_block(struct file_system*, uint32_t block_offset, uint8_t* output)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < RAMDISK_BLOCK_SIZE; i++) {
|
||||||
|
output[i] = ramdisk_data[block_offset + i];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct file_system g_ramdisk = {
|
||||||
|
.free_blocks_bitmap = BITMAP_ATTACH(ramdisk_free_bitmap,
|
||||||
|
sizeof(ramdisk_free_bitmap)),
|
||||||
|
|
||||||
|
.block_size = RAMDISK_BLOCK_SIZE,
|
||||||
|
.block_count = RAMDISK_BLOCK_COUNT,
|
||||||
|
|
||||||
|
.file_write_block = ramdisk_write_block,
|
||||||
|
.file_read_block = ramdisk_read_block,
|
||||||
|
.file_allocate_block = ramdisk_allocate_block,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Higher level interfaces
|
||||||
|
* =======================
|
||||||
|
*/
|
||||||
|
struct file_path* file_create(struct file_system* fs, struct str path)
|
||||||
|
{
|
||||||
|
struct file_path* f = file_map_insert(&fs->file_map, path);
|
||||||
|
|
||||||
|
memset(f, 0, sizeof *f);
|
||||||
|
f->attr |= FILE_PRESENT;
|
||||||
|
memcpy(f->name, path.data, MIN(path.len, FILE_NAME_MAX));
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct file_path* file_open(struct file_system* fs, struct str path)
|
||||||
|
{
|
||||||
|
return file_map_get(&fs->file_map, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool file_write(struct file_system* fs, struct file_path* f, const uint8_t* data, size_t n)
|
||||||
|
{
|
||||||
|
struct file_node** node = &f->node;
|
||||||
|
size_t written = 0;
|
||||||
|
|
||||||
|
while (written < n) {
|
||||||
|
if (*node == NULL) {
|
||||||
|
struct file_node* new_node = kalloc(sizeof *new_node);
|
||||||
|
if (new_node == NULL) {
|
||||||
|
panic(str_attach("failed to allocate new node for file"));
|
||||||
|
}
|
||||||
|
int offset = fs->file_allocate_block(fs);
|
||||||
|
if (offset == -1) {
|
||||||
|
panic(str_attach("failed to allocate new block in disk"));
|
||||||
|
}
|
||||||
|
node_init(new_node, offset);
|
||||||
|
*node = new_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = fs->file_write_block(fs, (*node)->block_offset, &data[written]);
|
||||||
|
if (!ok) {
|
||||||
|
panic(str_attach("file_write_byte failed"));
|
||||||
|
}
|
||||||
|
written += fs->block_size;
|
||||||
|
|
||||||
|
node = &((*node)->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool file_read(struct file_system* fs, struct file_path* f, uint8_t* out, int n)
|
||||||
|
{
|
||||||
|
uint8_t buf[MAX_FILE_BLOCK_SIZE];
|
||||||
|
static int32_t last_read_block = -1;
|
||||||
|
|
||||||
|
struct file_node dummy = {.next = f->node};
|
||||||
|
struct file_node* node = &dummy;
|
||||||
|
int read = 0;
|
||||||
|
|
||||||
|
while (read < n) {
|
||||||
|
if (!node->next) {
|
||||||
|
panic(str_attach("no next block found when reading"));
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
int remaining = n - read;
|
||||||
|
if (remaining > fs->block_size) {
|
||||||
|
ok = fs->file_read_block(fs, node->block_offset, &out[read]);
|
||||||
|
if (!ok) {
|
||||||
|
panic(str_attach("file_read_block failed"));
|
||||||
|
}
|
||||||
|
read += fs->block_size;
|
||||||
|
} else {
|
||||||
|
ok = fs->file_read_block(fs, node->block_offset, buf);
|
||||||
|
if (!ok) {
|
||||||
|
panic(str_attach("file_read_block failed"));
|
||||||
|
}
|
||||||
|
memcpy(&out[read], buf, remaining);
|
||||||
|
read += n - read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: remove this hacky test technique! */
|
||||||
|
|
||||||
|
int test_file_system()
|
||||||
|
{
|
||||||
|
struct file_path* f = file_create(&g_ramdisk, str_attach("test_file"));
|
||||||
|
|
||||||
|
const uint8_t data[] = "hello world!!!!\n";
|
||||||
|
printf(str_attach("trying to write to file {cstr}"), f->name);
|
||||||
|
bool ok = file_write(&g_ramdisk, f, data, sizeof data);
|
||||||
|
if (!ok) {
|
||||||
|
printf(str_attach("\nfailed to write to file {cstr}\n"), f->name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf(str_attach(" - OK!\n"));
|
||||||
|
|
||||||
|
printf(str_attach("trying to read from file {cstr}"), f->name);
|
||||||
|
uint8_t read_buf[sizeof data + 1];
|
||||||
|
read_buf[sizeof data] = '\0';
|
||||||
|
ok = file_read(&g_ramdisk, f, read_buf, sizeof data);
|
||||||
|
if (!ok) {
|
||||||
|
printf(str_attach("\nfailed to read from file {cstr}\n"), f->name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(read_buf, data, sizeof data) != 0) {
|
||||||
|
printf(str_attach("data mismatch between write and read\n"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf(str_attach(" - OK!, output was:\n{cstr}\n"), read_buf);
|
||||||
|
|
||||||
|
printf(str_attach("attempting to get a file that doesn't exist"));
|
||||||
|
{
|
||||||
|
struct file_path* f = file_map_get(&g_ramdisk.file_map, str_attach("asd"));
|
||||||
|
if (f) {
|
||||||
|
printf(str_attach("\ngot file when no such file should exist\n"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf(str_attach(" - OK!\n"));
|
||||||
|
|
||||||
|
uint8_t big_data[MAX_FILE_BLOCK_SIZE * 2 + 3] = {0};
|
||||||
|
memset(big_data, 0xAB, sizeof big_data);
|
||||||
|
f = file_create(&g_ramdisk, str_attach("test_big_file"));
|
||||||
|
printf(str_attach("attempting to write more than a block to {cstr}"), f->name);
|
||||||
|
ok = file_write(&g_ramdisk, f, big_data, sizeof big_data);
|
||||||
|
if (!ok) {
|
||||||
|
printf(str_attach("\nfailed to write data larger than a block\n"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf(str_attach(" - OK!\n"));
|
||||||
|
|
||||||
|
printf(str_attach("trying to read from file {cstr}"), f->name);
|
||||||
|
uint8_t big_read_buf[sizeof big_data];
|
||||||
|
ok = file_read(&g_ramdisk, f, big_read_buf, sizeof big_read_buf);
|
||||||
|
if (!ok) {
|
||||||
|
printf(str_attach("\nfailed to read from file {cstr}\n"), f->name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf(str_attach(" - OK!\n"));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
60
src/kernel/file_system.h
Normal file
60
src/kernel/file_system.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "bitmap.h"
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
constexpr int FILE_NAME_MAX = 31;
|
||||||
|
constexpr int FILE_MAP_SIZE = 128;
|
||||||
|
constexpr int MAX_FILE_BLOCK_SIZE = 4096;
|
||||||
|
|
||||||
|
enum file_attr : uint32_t {
|
||||||
|
FILE_PRESENT = 1<<0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct file_node {
|
||||||
|
struct file_node* next;
|
||||||
|
uint32_t block_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct file_path {
|
||||||
|
uint32_t attr;
|
||||||
|
uint32_t size;
|
||||||
|
|
||||||
|
uint32_t name_len;
|
||||||
|
char name[FILE_NAME_MAX+1];
|
||||||
|
|
||||||
|
struct file_node* node;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* TODO: clean up this mess:*/
|
||||||
|
struct file_system {
|
||||||
|
/* map of paths */
|
||||||
|
struct file_path_map {
|
||||||
|
struct file_path entries[FILE_MAP_SIZE];
|
||||||
|
uint32_t count;
|
||||||
|
} file_map;
|
||||||
|
|
||||||
|
/* map of free blocks */
|
||||||
|
struct bitmap free_blocks_bitmap;
|
||||||
|
|
||||||
|
int block_size;
|
||||||
|
int block_count;
|
||||||
|
|
||||||
|
/* virtual methods */
|
||||||
|
int (*file_allocate_block)(struct file_system*);
|
||||||
|
bool (*file_write_block)(struct file_system*, uint32_t, const uint8_t *data);
|
||||||
|
bool (*file_read_block)(struct file_system*, uint32_t, uint8_t *output);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int test_file_system();
|
||||||
|
|
||||||
|
struct file_path* file_open(struct file_system* fs, struct str path);
|
||||||
|
|
||||||
|
bool file_write(struct file_system* fs, struct file_path* f, const uint8_t* data, size_t n);
|
||||||
|
|
||||||
|
bool file_read(struct file_system* fs, struct file_path* f, uint8_t* out, int n);
|
||||||
|
|
||||||
|
|
||||||
|
extern struct file_system g_ramdisk;
|
||||||
@@ -128,7 +128,7 @@ void exception_handler_page_fault(struct interrupt_frame* frame, int err)
|
|||||||
static const struct str error_flag_str[page_fault_error_count] = {
|
static const struct str error_flag_str[page_fault_error_count] = {
|
||||||
[present] = str_attach("Caused by a page-protection violation"),
|
[present] = str_attach("Caused by a page-protection violation"),
|
||||||
[write] = str_attach("Caused by a write access"),
|
[write] = str_attach("Caused by a write access"),
|
||||||
[user] = str_attach("Caused while CPL == 3 (not neccessarily a privilige escalation)"),
|
[user] = str_attach("Caused by userspace (not neccessarily a privilige escalation)"),
|
||||||
[reserved_write] = str_attach("One or more page directory entries contain reserved bits which are set to 1"),
|
[reserved_write] = str_attach("One or more page directory entries contain reserved bits which are set to 1"),
|
||||||
[instruction_fetch] = str_attach("Caused by an instruction fetch"),
|
[instruction_fetch] = str_attach("Caused by an instruction fetch"),
|
||||||
[protection_key] = str_attach("Caused by a protection-key violation"),
|
[protection_key] = str_attach("Caused by a protection-key violation"),
|
||||||
@@ -139,7 +139,7 @@ void exception_handler_page_fault(struct interrupt_frame* frame, int err)
|
|||||||
static const struct str error_flag_zero_str[page_fault_error_count] = {
|
static const struct str error_flag_zero_str[page_fault_error_count] = {
|
||||||
[present] = str_attach("Caused by a non-present page"),
|
[present] = str_attach("Caused by a non-present page"),
|
||||||
[write] = str_attach("Caused by a read access"),
|
[write] = str_attach("Caused by a read access"),
|
||||||
[user] = str_attach("Caused while CPL != 3"),
|
[user] = str_attach("Caused by ring 0"),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (size_t i = 0; i < page_fault_error_count; i++) {
|
for (size_t i = 0; i < page_fault_error_count; i++) {
|
||||||
@@ -151,6 +151,8 @@ void exception_handler_page_fault(struct interrupt_frame* frame, int err)
|
|||||||
}
|
}
|
||||||
printf(str_attach("\n"));
|
printf(str_attach("\n"));
|
||||||
|
|
||||||
|
printf(str_attach("Instruction(s) that caused violation: {x32}\n"), *(uint32_t*)frame->ip);
|
||||||
|
|
||||||
print_interrupt_frame(frame);
|
print_interrupt_frame(frame);
|
||||||
|
|
||||||
__asm__ volatile("cli; hlt");
|
__asm__ volatile("cli; hlt");
|
||||||
|
|||||||
@@ -20,23 +20,13 @@
|
|||||||
#include "bitmap.h"
|
#include "bitmap.h"
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
|
|
||||||
#define syscall(number, b, c, d) \
|
__attribute__((section(".userland-text")))
|
||||||
__asm__ volatile( \
|
void user_mode_code(void*)
|
||||||
"int $0x80\n" \
|
|
||||||
: \
|
|
||||||
: "a"(number), \
|
|
||||||
"b"(b), \
|
|
||||||
"c"(c), \
|
|
||||||
"d"(d) \
|
|
||||||
: "memory" \
|
|
||||||
);
|
|
||||||
|
|
||||||
static void user_mode_code(void*)
|
|
||||||
{
|
{
|
||||||
//printf(str_attach("hello from user-space before interrupt :)\n"));
|
const char msg[] = "hello from ring 3\n";
|
||||||
//__asm__ volatile ("int $0x80");
|
syscall(SYSCALL_PRINT, &str_attach(msg), 0, 0);
|
||||||
int output;
|
|
||||||
syscall(SYSCALL_PRINT, &str_attach("hello from ring 3\n"), 0, 0);
|
volatile uint32_t a = *(uint32_t*)0;
|
||||||
#if 0
|
#if 0
|
||||||
syscall(SYSCALL_PRINT, &str_attach("trying to divide by zero :)\n"), 0, 0);
|
syscall(SYSCALL_PRINT, &str_attach("trying to divide by zero :)\n"), 0, 0);
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
@@ -51,10 +41,30 @@ static void user_mode_code(void*)
|
|||||||
|
|
||||||
syscall(SYSCALL_EXIT, 0, 0, 0);
|
syscall(SYSCALL_EXIT, 0, 0, 0);
|
||||||
|
|
||||||
while (1)
|
//#pragma GCC diagnostic push
|
||||||
;
|
//#pragma GCC diagnostic ignored "-Wunused-value"
|
||||||
|
//*(uint32_t*)0;
|
||||||
|
//#pragma GCC diagnostic pop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef uint32_t pde_t;
|
||||||
|
|
||||||
|
struct proc {
|
||||||
|
uint32_t (*page_directory)[1024];
|
||||||
|
uint8_t* kernel_stack;
|
||||||
|
char name[16];
|
||||||
|
uint32_t mem_size;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
//struct trapframe *tf;
|
||||||
|
//struct context *context; // swtch() here to run process
|
||||||
|
//void *chan; // If non-zero, sleeping on chan
|
||||||
|
//int killed; // If non-zero, have been killed
|
||||||
|
//struct file *ofile[NOFILE]; // Open files
|
||||||
|
//struct inode *cwd; // Current directory
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static void ring3_mode(segment_t udata_segment, segment_t ucode_segment, func_t callback)
|
static void ring3_mode(segment_t udata_segment, segment_t ucode_segment, func_t callback)
|
||||||
{
|
{
|
||||||
__asm__ volatile (
|
__asm__ volatile (
|
||||||
@@ -164,6 +174,7 @@ void kernel_main(void)
|
|||||||
* Setup the TSS
|
* Setup the TSS
|
||||||
* ============= */
|
* ============= */
|
||||||
static uint8_t kernel_stack[KERNEL_STACK_SIZE];
|
static uint8_t kernel_stack[KERNEL_STACK_SIZE];
|
||||||
|
memset(&kernel.tss, 0, sizeof kernel.tss);
|
||||||
kernel.tss.ss0 = segment(SEGMENT_KERNEL_DATA, SEGMENT_GDT, 0);
|
kernel.tss.ss0 = segment(SEGMENT_KERNEL_DATA, SEGMENT_GDT, 0);
|
||||||
kernel.tss.esp0 = (uint32_t)kernel_stack;
|
kernel.tss.esp0 = (uint32_t)kernel_stack;
|
||||||
tss_load(segment(SEGMENT_TASK_STATE, SEGMENT_GDT, 0));
|
tss_load(segment(SEGMENT_TASK_STATE, SEGMENT_GDT, 0));
|
||||||
@@ -242,30 +253,36 @@ void kernel_main(void)
|
|||||||
/**
|
/**
|
||||||
* Paging setup
|
* Paging setup
|
||||||
* ============
|
* ============
|
||||||
* We align by 1<<12 because page directory and page table entries store
|
* We align by (1<<12) == 4096 because page directory and page table
|
||||||
* addresses from bit 12-31
|
* entries store addresses from bit 12-31
|
||||||
*
|
*
|
||||||
* For now give user access to pages to avoid a page fault, since it's not
|
* For now give user access to pages to avoid a page fault, since it's not
|
||||||
* implemented properly
|
* implemented properly
|
||||||
*/
|
*/
|
||||||
printf(str_attach("setting up paging...\n"));
|
printf(str_attach("setting up paging...\n"));
|
||||||
|
printf(str_attach("kernel end: {bin}\n"), kernel_memory_end);
|
||||||
|
|
||||||
static uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
static uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
||||||
static uint32_t page_table_0[1024] __attribute__((aligned(4096)));
|
static uint32_t page_table_kernel[1024] __attribute__((aligned(4096)));
|
||||||
_Static_assert(((uint32_t)page_directory & 0xfff) == 0);
|
static uint32_t page_table_user[1024] __attribute__((aligned(4096)));
|
||||||
_Static_assert(((uint32_t)page_table_0 & 0xfff) == 0);
|
_Static_assert(((uint32_t)page_directory & 0xfff) == 0);
|
||||||
|
_Static_assert(((uint32_t)page_table_kernel & 0xfff) == 0);
|
||||||
|
_Static_assert(((uint32_t)page_table_user & 0xfff) == 0);
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof page_directory / sizeof *page_directory; i++) {
|
for (size_t i = 0; i < sizeof page_directory / sizeof *page_directory; i++) {
|
||||||
page_directory[i] = PDE_WRITE; /* no present bit */
|
page_directory[i] = PDE_WRITE; /* no present bit */
|
||||||
}
|
}
|
||||||
page_directory[1023] = (uint32_t)page_directory;
|
page_directory[sizeof page_directory / sizeof *page_directory - 1] = (uint32_t)page_directory | PDE_WRITE | PDE_PRESENT;
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof page_table_0 / sizeof *page_table_0; i++) {
|
for (size_t i = 0; i < sizeof page_table_kernel / sizeof *page_table_kernel; i++) {
|
||||||
// for now this page table allows user-space code to access
|
page_table_kernel[i] = (i<<12) | PTE_WRITE | PTE_PRESENT;
|
||||||
// kernel-space memory (PTE_USER)
|
|
||||||
page_table_0[i] = PTE_ADDRESS(i) | PTE_WRITE | PTE_PRESENT | PTE_USER;
|
|
||||||
}
|
}
|
||||||
page_directory[0] = ((uint32_t)page_table_0) | PDE_WRITE | PDE_PRESENT | PDE_USER_ACCESS;
|
page_directory[0] = ((uint32_t)page_table_kernel) | PDE_WRITE | PDE_PRESENT | PDE_USER_ACCESS;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sizeof page_table_user / sizeof *page_table_user; i++) {
|
||||||
|
page_table_user[i] = ((uint32_t)kernel_memory_end + (i<<12)) | PTE_WRITE | PTE_PRESENT | PTE_USER;
|
||||||
|
}
|
||||||
|
page_directory[1] = ((uint32_t)page_table_user) | PDE_WRITE | PDE_PRESENT | PDE_USER_ACCESS;
|
||||||
|
|
||||||
cr3_set((uint32_t)page_directory);
|
cr3_set((uint32_t)page_directory);
|
||||||
cr0_flags_set(CR0_PAGING | CR0_PROTECTED_MODE);
|
cr0_flags_set(CR0_PAGING | CR0_PROTECTED_MODE);
|
||||||
@@ -274,6 +291,14 @@ void kernel_main(void)
|
|||||||
|
|
||||||
printf(str_attach("starting code in ring 3...\n"));
|
printf(str_attach("starting code in ring 3...\n"));
|
||||||
|
|
||||||
|
/* Load userspace binary to memory */
|
||||||
|
|
||||||
|
printf(str_attach("address of userspace code: {x32} = {addr}\n"), user_mode_code, user_mode_code);
|
||||||
|
|
||||||
|
printf(str_attach("im going ring 3 mode\n"));
|
||||||
|
|
||||||
|
//new_proc();
|
||||||
|
|
||||||
/* Finally go to ring 3 */
|
/* Finally go to ring 3 */
|
||||||
ring3_mode(segment(SEGMENT_USER_DATA, SEGMENT_GDT, 3),
|
ring3_mode(segment(SEGMENT_USER_DATA, SEGMENT_GDT, 3),
|
||||||
segment(SEGMENT_USER_CODE, SEGMENT_GDT, 3),
|
segment(SEGMENT_USER_CODE, SEGMENT_GDT, 3),
|
||||||
@@ -283,4 +308,3 @@ void kernel_main(void)
|
|||||||
|
|
||||||
__asm__ volatile ("hlt");
|
__asm__ volatile ("hlt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
9
src/kernel/malloc.h
Normal file
9
src/kernel/malloc.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void* kalloc(size_t size);
|
||||||
|
|
||||||
|
void kfree(void* ptr);
|
||||||
|
|
||||||
|
void* krealloc(void* ptr, size_t size);
|
||||||
192
src/kernel/serial.h
Normal file
192
src/kernel/serial.h
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: consolidate memory mapped addresses into one header file, maybe per
|
||||||
|
* architecture
|
||||||
|
* */
|
||||||
|
|
||||||
|
//static uint8_t* SERIAL_COM1 = (uint8_t*)0x03F8;
|
||||||
|
//static uint8_t* SERIAL_COM2 = (uint8_t*)0x02F8;
|
||||||
|
|
||||||
|
enum serial_port : uint16_t {
|
||||||
|
SERIAL_COM1 = 0x03F8,
|
||||||
|
SERIAL_COM2 = 0x02F8,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum serial_port_offsets : uint8_t {
|
||||||
|
SERIAL_DATA_REGISTER = 0,
|
||||||
|
SERIAL_INTERRUPT = 1,
|
||||||
|
|
||||||
|
SERIAL_DLAB_LSB = 0, /* when dlab is set this is the least
|
||||||
|
significant byte for the divisor*/
|
||||||
|
SERIAL_DLAB_MSB = 1, /* ... and this is the most significant byte*/
|
||||||
|
|
||||||
|
SERIAL_INTERRUPT_IDENTIFICATION = 2,
|
||||||
|
SERIAL_FIFO_CONTROL = 2,
|
||||||
|
SERIAL_LINE_CONTROL = 3,
|
||||||
|
SERIAL_MODEM_CONTROL = 4,
|
||||||
|
SERIAL_LINE_STATUS = 5,
|
||||||
|
SERIAL_MODEM_STATUS = 6,
|
||||||
|
SERIAL_SCRATCH_REGISTER = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum serial_line_control : uint8_t {
|
||||||
|
SERIAL_LINE_DATA_5_BIT = 0b00<<0,
|
||||||
|
SERIAL_LINE_DATA_6_BIT = 0b01<<0,
|
||||||
|
SERIAL_LINE_DATA_7_BIT = 0b10<<0,
|
||||||
|
SERIAL_LINE_DATA_8_BIT = 0b11<<0,
|
||||||
|
|
||||||
|
SERIAL_LINE_STOP_1 = 0<<2,
|
||||||
|
SERIAL_LINE_STOP_2 = 1<<2,
|
||||||
|
|
||||||
|
SERIAL_LINE_PARITY_NONE = 0b000<<3,
|
||||||
|
SERIAL_LINE_PARITY_ODD = 0b001<<3,
|
||||||
|
SERIAL_LINE_PARITY_EVEN = 0b011<<3,
|
||||||
|
SERIAL_LINE_PARITY_MARK = 0b101<<3,
|
||||||
|
SERIAL_LINE_PARITY_SPACE = 0b111<<3,
|
||||||
|
|
||||||
|
SERIAL_LINE_BREAK_ENABLE = 1<<6,
|
||||||
|
|
||||||
|
SERIAL_LINE_DLAB = 1<<7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum serial_interrupt_control : uint8_t {
|
||||||
|
SERIAL_INTERRUPT_RECEIVED_DATA_AVAILABLE = 1<<0,
|
||||||
|
SERIAL_INTERRUPT_TRANSMITTER_HOLDING_REGISTER_EMPTY = 1<<1,
|
||||||
|
SERIAL_INTERRUPT_RECEIVER_LINE_STATUS = 1<<2,
|
||||||
|
SERIAL_INTERRUPT_MODEM_STATUS = 1<<3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum serial_fifo_control : uint8_t {
|
||||||
|
SERIAL_FIFO_ENABLE = 1<<0,
|
||||||
|
SERIAL_FIFO_CLEAR_RECEIVE = 1<<1,
|
||||||
|
SERIAL_FIFO_CLEAR_TRANSMIT = 1<<2,
|
||||||
|
SERIAL_FIFO_DMA_MODE = 1<<3,
|
||||||
|
SERIAL_FIFO_INTERRUPT_1_BYTE = 0<<6,
|
||||||
|
SERIAL_FIFO_INTERRUPT_4_BYTE = 1<<6,
|
||||||
|
SERIAL_FIFO_INTERRUPT_8_BYTE = 2<<6,
|
||||||
|
SERIAL_FIFO_INTERRUPT_14_BYTE = 3<<6,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum serial_modem_control : uint8_t {
|
||||||
|
SERIAL_MODEM_DATA_READY = 1<<0,
|
||||||
|
SERIAL_MODEM_REQUEST_TO_SEND = 1<<1,
|
||||||
|
SERIAL_MODEM_OUT_1 = 1<<2,
|
||||||
|
SERIAL_MODEM_OUT_2 = 1<<3,
|
||||||
|
SERIAL_MODEM_ENABLE_IRQ = 1<<3, /* alias for out_2 */
|
||||||
|
SERIAL_MODEM_LOOP = 1<<4,
|
||||||
|
SERIAL_MODEM_UNUSED_0 = 1<<5,
|
||||||
|
SERIAL_MODEM_UNUSED_1 = 1<<6,
|
||||||
|
SERIAL_MODEM_UNUSED_3 = 1<<7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum serial_line_status: uint8_t {
|
||||||
|
SERIAL_LINE_STATUS_DATA_READY = 1<<0,
|
||||||
|
SERIAL_LINE_STATUS_OVERRUN_ERROR = 1<<1,
|
||||||
|
SERIAL_LINE_STATUS_PARITY_ERROR = 1<<2,
|
||||||
|
SERIAL_LINE_STATUS_FRAMING_ERROR = 1<<3,
|
||||||
|
SERIAL_LINE_STATUS_BREAK_INDICATOR = 1<<4,
|
||||||
|
SERIAL_LINE_STATUS_TRANSMISSION_BUF_EMPTY = 1<<5,
|
||||||
|
SERIAL_LINE_STATUS_TRANSMITTER_EMPTY = 1<<6,
|
||||||
|
SERIAL_LINE_STATUS_IMPENDING_ERROR = 1<<7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum serial_modem_status : uint8_t {
|
||||||
|
SERIAL_MODEM_STATUS_DCTS = 1<<0,
|
||||||
|
SERIAL_MODEM_STATUS_DDSR = 1<<1,
|
||||||
|
SERIAL_MODEM_STATUS_TERI = 1<<2,
|
||||||
|
SERIAL_MODEM_STATUS_DDCD = 1<<3,
|
||||||
|
SERIAL_MODEM_STATUS_CTS = 1<<4,
|
||||||
|
SERIAL_MODEM_STATUS_DSR = 1<<5,
|
||||||
|
SERIAL_MODEM_STATUS_RI = 1<<6,
|
||||||
|
SERIAL_MODEM_STATUS_DCD = 1<<7,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void outb(uint16_t port, uint8_t signal)
|
||||||
|
{
|
||||||
|
__asm__ volatile ("outb %[signal], %[port]"
|
||||||
|
:
|
||||||
|
: [signal] "a" (signal),
|
||||||
|
[port] "Nd" (port)
|
||||||
|
: "memory");
|
||||||
|
#ifdef ADD_IO_WAIT
|
||||||
|
/* do an I/O operation on an unused port to wait 1-4 microseconds */
|
||||||
|
outb(0x80, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t inb(uint16_t port)
|
||||||
|
{
|
||||||
|
uint8_t ret;
|
||||||
|
__asm__ volatile ( "inb %[port], %[ret]"
|
||||||
|
: [ret] "=a"(ret)
|
||||||
|
: [port] "Nd"(port)
|
||||||
|
: "memory");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serial_init(enum serial_port serial, uint16_t baud_divisor)
|
||||||
|
{
|
||||||
|
outb(serial + SERIAL_INTERRUPT, SERIAL_LINE_DLAB);
|
||||||
|
outb(serial + SERIAL_LINE_CONTROL, SERIAL_LINE_DLAB);
|
||||||
|
outb(serial + SERIAL_DLAB_LSB, baud_divisor & 0x0F);
|
||||||
|
outb(serial + SERIAL_DLAB_MSB, (baud_divisor & 0xF0) >> 8);
|
||||||
|
outb(serial + SERIAL_LINE_CONTROL, SERIAL_LINE_DATA_8_BIT);
|
||||||
|
|
||||||
|
outb(serial + SERIAL_FIFO_CONTROL, 0
|
||||||
|
| SERIAL_FIFO_ENABLE
|
||||||
|
| SERIAL_FIFO_INTERRUPT_14_BYTE
|
||||||
|
| SERIAL_FIFO_CLEAR_RECEIVE);
|
||||||
|
|
||||||
|
outb(serial + SERIAL_MODEM_CONTROL, 0
|
||||||
|
| SERIAL_MODEM_DATA_READY
|
||||||
|
| SERIAL_MODEM_REQUEST_TO_SEND
|
||||||
|
| SERIAL_MODEM_ENABLE_IRQ);
|
||||||
|
|
||||||
|
outb(serial + SERIAL_MODEM_CONTROL, 0
|
||||||
|
| SERIAL_MODEM_REQUEST_TO_SEND
|
||||||
|
| SERIAL_MODEM_OUT_1
|
||||||
|
| SERIAL_MODEM_OUT_2
|
||||||
|
| SERIAL_MODEM_LOOP);
|
||||||
|
|
||||||
|
constexpr uint8_t ping = 0xAE;
|
||||||
|
|
||||||
|
outb(serial + SERIAL_DATA_REGISTER, ping);
|
||||||
|
|
||||||
|
if (inb(serial + SERIAL_DATA_REGISTER) != ping) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
outb(serial + SERIAL_MODEM_CONTROL, 0
|
||||||
|
| SERIAL_MODEM_REQUEST_TO_SEND
|
||||||
|
| SERIAL_MODEM_DATA_READY
|
||||||
|
| SERIAL_MODEM_OUT_1
|
||||||
|
| SERIAL_MODEM_OUT_2
|
||||||
|
);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serial_is_transmit_empty(enum serial_port port) {
|
||||||
|
return inb(port + SERIAL_LINE_STATUS)
|
||||||
|
& SERIAL_LINE_STATUS_TRANSMISSION_BUF_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void serial_putchar(enum serial_port port, char ch)
|
||||||
|
{
|
||||||
|
while (serial_is_transmit_empty(port) == 0)
|
||||||
|
/* spin lock */;
|
||||||
|
|
||||||
|
outb(port, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void serial_write(enum serial_port port, struct str s)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < s.len; i++) {
|
||||||
|
serial_putchar(port, s.data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
60
src/kernel/syscall.c
Normal file
60
src/kernel/syscall.c
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
|
#include "libc.h"
|
||||||
|
#include "tty.h"
|
||||||
|
#include "interrupts.h"
|
||||||
|
#include "kernel_state.h"
|
||||||
|
#include "file_system.h"
|
||||||
|
|
||||||
|
#define EXCEPTION_DEPTH_MAX 3
|
||||||
|
|
||||||
|
int syscall_main(int syscall_no, int a, int b, int c)
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
switch (syscall_no) {
|
||||||
|
|
||||||
|
case SYSCALL_PRINT:
|
||||||
|
{
|
||||||
|
terminal_write(*(struct str*)a);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case SYSCALL_OPEN:
|
||||||
|
{
|
||||||
|
struct str path = *(struct str*)a;
|
||||||
|
struct file_path* f = file_open(&g_ramdisk, path);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case SYSCALL_WRITE:
|
||||||
|
{
|
||||||
|
//bool file_write(struct file_system* fs, struct file_path* f, const uint8_t* data, size_t n);
|
||||||
|
struct file_path* filepath = (struct file_path*)a;
|
||||||
|
const uint8_t* data = (const uint8_t*)b;
|
||||||
|
const uint8_t n = (const uint8_t)c;
|
||||||
|
file_write(&g_ramdisk, filepath, data, n);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case SYSCALL_READ:
|
||||||
|
{
|
||||||
|
//bool file_read(struct file_system* fs, struct file_path* f, uint8_t* out, int n);
|
||||||
|
struct file_path* filepath = (struct file_path*)a;
|
||||||
|
uint8_t* out = (uint8_t*)b;
|
||||||
|
const uint8_t n = (const uint8_t)c;
|
||||||
|
file_read(&g_ramdisk, filepath, out, n);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case SYSCALL_EXIT:
|
||||||
|
{
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
printf(str_attach("unknown syscall {i32}: a:{i32}, b:{i32}, c:{i32}\n"), syscall_no, a, b, c);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
20
src/kernel/syscall.h
Normal file
20
src/kernel/syscall.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SYSCALL_PRINT,
|
||||||
|
SYSCALL_OPEN,
|
||||||
|
SYSCALL_READ,
|
||||||
|
SYSCALL_WRITE,
|
||||||
|
SYSCALL_EXIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define syscall(number, b, c, d) \
|
||||||
|
__asm__ volatile( \
|
||||||
|
"int $0x80\n" \
|
||||||
|
: \
|
||||||
|
: "a"(number), \
|
||||||
|
"b"(b), \
|
||||||
|
"c"(c), \
|
||||||
|
"d"(d) \
|
||||||
|
: "memory" \
|
||||||
|
);
|
||||||
30
src/kernel/syscall_handler.S
Normal file
30
src/kernel/syscall_handler.S
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
.global interrupt_handler_syscall
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
interrupt_handler_syscall:
|
||||||
|
|
||||||
|
pushal // push all general purpose registers
|
||||||
|
cld // clear direction flag
|
||||||
|
|
||||||
|
// Passing Parameters
|
||||||
|
// (https://gitlab.com/x86-psABIs/i386-ABI/-/wikis/uploads/14c05f1b1e156e0e46b61bfa7c1df1e2/intel386-psABI-2020-08-07.pdf)
|
||||||
|
// ---------
|
||||||
|
// Most parameters are passed on the stack. Parameters are pushed onto the
|
||||||
|
// stack in reverse order - the last argument in the parameter list has the
|
||||||
|
// highest address, that is, it is stored farthest away from the stack pointer
|
||||||
|
// at the time of the call.
|
||||||
|
|
||||||
|
|
||||||
|
push %edx
|
||||||
|
push %ecx
|
||||||
|
push %ebx
|
||||||
|
push %eax
|
||||||
|
call syscall_main
|
||||||
|
pop %eax
|
||||||
|
pop %ebx
|
||||||
|
pop %ecx
|
||||||
|
pop %edx
|
||||||
|
|
||||||
|
popal // pop all general purpose registers
|
||||||
|
|
||||||
|
iret
|
||||||
493
src/lib/dump_asm.c
Normal file
493
src/lib/dump_asm.c
Normal file
@@ -0,0 +1,493 @@
|
|||||||
|
|
||||||
|
/* Encoding scheme:
|
||||||
|
X(map, opcode, ext, attrs, mnemonic, argc, a1, a2, a3, desc)
|
||||||
|
|
||||||
|
map: MAP_PRIMARY, MAP_0F
|
||||||
|
opcode: 1-byte primary opcode (numeric literal)
|
||||||
|
ext: -1 if none, else digit (0..7)
|
||||||
|
attrs bitmask: see * below
|
||||||
|
|
||||||
|
Operand shorthands: r8/16/32/64, rm8/16/32/64, m8/16/32/64, imm8/16/32, rel8/32, moffs8/16/32/64, AL/AX/EAX/RAX, rFLAGS. */
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* --- enums and flags --- */
|
||||||
|
enum opcode_map {
|
||||||
|
MAP_PRIMARY = 0,
|
||||||
|
MAP_0F = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum arg_kind {
|
||||||
|
AK_NONE=0,
|
||||||
|
|
||||||
|
// fixed regs
|
||||||
|
AK_AL,
|
||||||
|
AK_AX_EAX_RAX, // accumulator by operand size
|
||||||
|
|
||||||
|
// gp regs
|
||||||
|
AK_R8, AK_R16, AK_R32, AK_R64,
|
||||||
|
AK_R16_32_64, // size-selected GPR
|
||||||
|
AK_R32_64, // 32 or 64 reg
|
||||||
|
|
||||||
|
// reg/mem
|
||||||
|
AK_RM8, AK_RM16, AK_RM32, AK_RM64,
|
||||||
|
AK_RM16_32_64,
|
||||||
|
AK_RM8_16_32_64,
|
||||||
|
|
||||||
|
// memory
|
||||||
|
AK_M, // memory, size from opcode/REX.W
|
||||||
|
AK_MOFFS8,
|
||||||
|
AK_MOFFS16_32_64,
|
||||||
|
|
||||||
|
// immediates and rels
|
||||||
|
AK_IMM8, AK_IMM16, AK_IMM32,
|
||||||
|
AK_IMM_OPSIZE, // 16 or 32 by operand size
|
||||||
|
AK_REL8, AK_REL32,
|
||||||
|
|
||||||
|
// special implicit operands
|
||||||
|
AK_CL,
|
||||||
|
AK_ONE
|
||||||
|
};
|
||||||
|
|
||||||
|
int arg_kind_bytes[] = {
|
||||||
|
[AK_NONE] = -9999,
|
||||||
|
[AK_AL] = 0,
|
||||||
|
[AK_AX_EAX_RAX] = 0, // accumulator by operand size
|
||||||
|
|
||||||
|
// gp regs
|
||||||
|
[AK_R8] = 1,
|
||||||
|
[AK_R16] = 2,
|
||||||
|
[AK_R32] = 4,
|
||||||
|
[AK_R64] = 8,
|
||||||
|
[AK_R16_32_64] = -9999, // size-selected GPR
|
||||||
|
[AK_R32_64] = -9999, // 32 or 64 reg
|
||||||
|
|
||||||
|
// reg/mem
|
||||||
|
[AK_RM8] = 1,
|
||||||
|
[AK_RM16] = 2,
|
||||||
|
[AK_RM32] = 4,
|
||||||
|
[AK_RM64] = 8,
|
||||||
|
[AK_RM16_32_64] = -9999,
|
||||||
|
[AK_RM8_16_32_64] = -9999,
|
||||||
|
|
||||||
|
// memory
|
||||||
|
[AK_M] = -9999, // memory, size from opcode/REX.W
|
||||||
|
[AK_MOFFS8] = -9999,
|
||||||
|
[AK_MOFFS16_32_64] = -9999,
|
||||||
|
|
||||||
|
// immediates and rels
|
||||||
|
[AK_IMM8] = 1,
|
||||||
|
[AK_IMM16] = 2,
|
||||||
|
[AK_IMM32] = 4,
|
||||||
|
[AK_IMM_OPSIZE] = -9999, // 16 or 32 by operand size
|
||||||
|
[AK_REL8] = 1,
|
||||||
|
[AK_REL32] = 4,
|
||||||
|
|
||||||
|
// special implicit operands
|
||||||
|
[AK_CL] = 0,
|
||||||
|
[AK_ONE] = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* arg_kind_str[] = {
|
||||||
|
[AK_NONE] = "NONE",
|
||||||
|
[AK_AL] = "AL",
|
||||||
|
[AK_AX_EAX_RAX] = "AX_EAX_RAX",
|
||||||
|
[AK_R8] = "R8",
|
||||||
|
[AK_R16] = "R16",
|
||||||
|
[AK_R32] = "R32",
|
||||||
|
[AK_R64] = "R64",
|
||||||
|
[AK_R16_32_64] = "R16_32_64",
|
||||||
|
[AK_R32_64] = "R32_64",
|
||||||
|
[AK_RM8] = "RM8",
|
||||||
|
[AK_RM16] = "RM16",
|
||||||
|
[AK_RM32] = "RM32",
|
||||||
|
[AK_RM64] = "RM64",
|
||||||
|
[AK_RM16_32_64] = "RM16_32_64",
|
||||||
|
[AK_RM8_16_32_64] = "RM8_16_32_64",
|
||||||
|
[AK_M] = "M",
|
||||||
|
[AK_MOFFS8] = "MOFFS8",
|
||||||
|
[AK_MOFFS16_32_64] = "MOFFS16_32_64",
|
||||||
|
[AK_IMM8] = "IMM8",
|
||||||
|
[AK_IMM16] = "IMM16",
|
||||||
|
[AK_IMM32] = "IMM32",
|
||||||
|
[AK_IMM_OPSIZE] = "IMM_OPSIZE",
|
||||||
|
[AK_REL8] = "REL8",
|
||||||
|
[AK_REL32] = "REL32",
|
||||||
|
[AK_CL] = "CL",
|
||||||
|
[AK_ONE] = "ONE",
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
AA_NONE = 0,
|
||||||
|
AA_SEXT = 1<<0, // sign-extended when used (e.g., 83 /? imm8)
|
||||||
|
AA_ZEXT = 1<<1 // zero-extended use
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* arg_attr_str[] = {
|
||||||
|
[AA_NONE] = "NONE",
|
||||||
|
[AA_SEXT] = "SEXT",
|
||||||
|
[AA_ZEXT] = "ZEXT",
|
||||||
|
[AA_SEXT | AA_ZEXT] = "SEXT + ZEXT",
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ARG(kind, attrs) ( ((uint32_t)(kind) << 16) | (uint32_t)(attrs) )
|
||||||
|
#define ARG_KIND(a) (((a) >> 16) & ((1<<16)-1))
|
||||||
|
#define ARG_ATTRS(a) ((a) & ((1<<16)-1))
|
||||||
|
#define A(kind) ARG((kind), AA_NONE)
|
||||||
|
#define A0 ARG(AK_NONE, AA_NONE)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MODRM = 1<<( 0 + 8), /* instruction uses ModRM */
|
||||||
|
IMM8 = 1<<( 1 + 8),
|
||||||
|
IMM16 = 1<<( 2 + 8),
|
||||||
|
IMM32 = 1<<( 3 + 8),
|
||||||
|
REL8 = 1<<( 4 + 8),
|
||||||
|
REL32 = 1<<( 5 + 8),
|
||||||
|
MOFFS = 1<<( 6 + 8), /* moffs form (A0..A3) */
|
||||||
|
PLUS_R = 1<<( 7 + 8), /* opcode is base + reg */
|
||||||
|
ACCUM = 1<<( 8 + 8), /* accumulator special encoding */
|
||||||
|
LOCK_OK = 1<<( 9 + 8), /* LOCK prefix allowed */
|
||||||
|
REP_F3 = 1<<(10 + 8), /* REP/REPE F3 meaningful */
|
||||||
|
REP_F2 = 1<<(11 + 8), /* REPNE F2 meaningful */
|
||||||
|
REXW_OK = 1<<(12 + 8), /* 64-bit operand via REX.W */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
X(opcode, map, ext, attrs, mnemonic, argc, a1, a2, a3, desc)
|
||||||
|
*/
|
||||||
|
#define INSTRUCTION_LIST \
|
||||||
|
X(0x00, MAP_PRIMARY, -1, MODRM|LOCK_OK, ADD, 2, A(AK_RM8), A(AK_R8), A0, "Add r8 to r/m8") \
|
||||||
|
X(0x01, MAP_PRIMARY, -1, MODRM|LOCK_OK|REXW_OK, ADD, 2, A(AK_RM16_32_64), A(AK_R16_32_64), A0, "Add r to r/m") \
|
||||||
|
X(0x02, MAP_PRIMARY, -1, MODRM, ADD, 2, A(AK_R8), A(AK_RM8), A0, "Add r/m8 to r8") \
|
||||||
|
X(0x03, MAP_PRIMARY, -1, MODRM|REXW_OK, ADD, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Add r/m to r") \
|
||||||
|
X(0x04, MAP_PRIMARY, -1, IMM8|ACCUM, ADD, 2, A(AK_AL), A(AK_IMM8), A0, "Add imm8 to AL") \
|
||||||
|
X(0x05, MAP_PRIMARY, -1, IMM32|ACCUM|REXW_OK, ADD, 2, A(AK_AX_EAX_RAX), A(AK_IMM_OPSIZE), A0, "Add imm to accumulator") \
|
||||||
|
X(0x08, MAP_PRIMARY, -1, MODRM|LOCK_OK, OR, 2, A(AK_RM8), A(AK_R8), A0, "OR r8 to r/m8") \
|
||||||
|
X(0x09, MAP_PRIMARY, -1, MODRM|LOCK_OK|REXW_OK, OR, 2, A(AK_RM16_32_64), A(AK_R16_32_64), A0, "OR r to r/m") \
|
||||||
|
X(0x0A, MAP_PRIMARY, -1, MODRM, OR, 2, A(AK_R8), A(AK_RM8), A0, "OR r/m8 to r8") \
|
||||||
|
X(0x0B, MAP_PRIMARY, -1, MODRM|REXW_OK, OR, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "OR r/m to r") \
|
||||||
|
X(0x0C, MAP_PRIMARY, -1, IMM8|ACCUM, OR, 2, A(AK_AL), A(AK_IMM8), A0, "OR imm8 to AL") \
|
||||||
|
X(0x0D, MAP_PRIMARY, -1, IMM32|ACCUM|REXW_OK, OR, 2, A(AK_AX_EAX_RAX), A(AK_IMM_OPSIZE), A0, "OR imm to accumulator") \
|
||||||
|
X(0x0F, MAP_PRIMARY, -1, 0, NOP_MULTI, 0, A0, A0, A0, "Multi-byte NOPs via 0F 1F */r") \
|
||||||
|
X(0x0F, MAP_PRIMARY, -1, 0, TWO_BYTE_ESC, 0, A0, A0, A0, "Opcode map escape (placeholder)") \
|
||||||
|
X(0x10, MAP_PRIMARY, -1, MODRM|LOCK_OK, ADC, 2, A(AK_RM8), A(AK_R8), A0, "Add with carry") \
|
||||||
|
X(0x11, MAP_PRIMARY, -1, MODRM|LOCK_OK|REXW_OK, ADC, 2, A(AK_RM16_32_64), A(AK_R16_32_64), A0, "Add with carry") \
|
||||||
|
X(0x12, MAP_PRIMARY, -1, MODRM, ADC, 2, A(AK_R8), A(AK_RM8), A0, "Add with carry") \
|
||||||
|
X(0x13, MAP_PRIMARY, -1, MODRM|REXW_OK, ADC, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Add with carry") \
|
||||||
|
X(0x14, MAP_PRIMARY, -1, IMM8|ACCUM, ADC, 2, A(AK_AL), A(AK_IMM8), A0, "ADC imm8 to AL") \
|
||||||
|
X(0x15, MAP_PRIMARY, -1, IMM32|ACCUM|REXW_OK, ADC, 2, A(AK_AX_EAX_RAX), A(AK_IMM_OPSIZE), A0, "ADC imm to accumulator") \
|
||||||
|
X(0x18, MAP_PRIMARY, -1, MODRM|LOCK_OK, SBB, 2, A(AK_RM8), A(AK_R8), A0, "Subtract with borrow") \
|
||||||
|
X(0x19, MAP_PRIMARY, -1, MODRM|LOCK_OK|REXW_OK, SBB, 2, A(AK_RM16_32_64), A(AK_R16_32_64), A0, "Subtract with borrow") \
|
||||||
|
X(0x1A, MAP_PRIMARY, -1, MODRM, SBB, 2, A(AK_R8), A(AK_RM8), A0, "Subtract with borrow") \
|
||||||
|
X(0x1B, MAP_PRIMARY, -1, MODRM|REXW_OK, SBB, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Subtract with borrow") \
|
||||||
|
X(0x1C, MAP_PRIMARY, -1, IMM8|ACCUM, SBB, 2, A(AK_AL), A(AK_IMM8), A0, "SBB imm8 to AL") \
|
||||||
|
X(0x1D, MAP_PRIMARY, -1, IMM32|ACCUM|REXW_OK, SBB, 2, A(AK_AX_EAX_RAX), A(AK_IMM_OPSIZE), A0, "SBB imm to accumulator") \
|
||||||
|
X(0x20, MAP_PRIMARY, -1, MODRM|LOCK_OK, AND, 2, A(AK_RM8), A(AK_R8), A0, "AND r8 to r/m8") \
|
||||||
|
X(0x21, MAP_PRIMARY, -1, MODRM|LOCK_OK|REXW_OK, AND, 2, A(AK_RM16_32_64), A(AK_R16_32_64), A0, "AND r to r/m") \
|
||||||
|
X(0x22, MAP_PRIMARY, -1, MODRM, AND, 2, A(AK_R8), A(AK_RM8), A0, "AND r/m8 to r8") \
|
||||||
|
X(0x23, MAP_PRIMARY, -1, MODRM|REXW_OK, AND, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "AND r/m to r") \
|
||||||
|
X(0x24, MAP_PRIMARY, -1, IMM8|ACCUM, AND, 2, A(AK_AL), A(AK_IMM8), A0, "AND imm8 to AL") \
|
||||||
|
X(0x25, MAP_PRIMARY, -1, IMM32|ACCUM|REXW_OK, AND, 2, A(AK_AX_EAX_RAX), A(AK_IMM_OPSIZE), A0, "AND imm to accumulator") \
|
||||||
|
X(0x27, MAP_PRIMARY, -1, 0, DAA, 0, A0, A0, A0, "Decimal adjust after add") \
|
||||||
|
X(0x28, MAP_PRIMARY, -1, MODRM|LOCK_OK, SUB, 2, A(AK_RM8), A(AK_R8), A0, "Subtract r8 from r/m8") \
|
||||||
|
X(0x29, MAP_PRIMARY, -1, MODRM|LOCK_OK|REXW_OK, SUB, 2, A(AK_RM16_32_64), A(AK_R16_32_64), A0, "Subtract r from r/m") \
|
||||||
|
X(0x2A, MAP_PRIMARY, -1, MODRM, SUB, 2, A(AK_R8), A(AK_RM8), A0, "Subtract r/m8 from r8") \
|
||||||
|
X(0x2B, MAP_PRIMARY, -1, MODRM|REXW_OK, SUB, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Subtract r/m from r") \
|
||||||
|
X(0x2C, MAP_PRIMARY, -1, IMM8|ACCUM, SUB, 2, A(AK_AL), A(AK_IMM8), A0, "SUB imm8 from AL") \
|
||||||
|
X(0x2D, MAP_PRIMARY, -1, IMM32|ACCUM|REXW_OK, SUB, 2, A(AK_AX_EAX_RAX), A(AK_IMM_OPSIZE), A0, "SUB imm from accumulator") \
|
||||||
|
X(0x2F, MAP_PRIMARY, -1, 0, DAS, 0, A0, A0, A0, "Decimal adjust after sub") \
|
||||||
|
X(0x30, MAP_PRIMARY, -1, MODRM|LOCK_OK, XOR, 2, A(AK_RM8), A(AK_R8), A0, "XOR r8 to r/m8") \
|
||||||
|
X(0x31, MAP_0F, -1, 0, RDTSC, 0, A0, A0, A0, "Read time-stamp counter") \
|
||||||
|
X(0x31, MAP_PRIMARY, -1, MODRM|LOCK_OK|REXW_OK, XOR, 2, A(AK_RM16_32_64), A(AK_R16_32_64), A0, "XOR r to r/m") \
|
||||||
|
X(0x32, MAP_PRIMARY, -1, MODRM, XOR, 2, A(AK_R8), A(AK_RM8), A0, "XOR r/m8 to r8") \
|
||||||
|
X(0x33, MAP_PRIMARY, -1, MODRM|REXW_OK, XOR, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "XOR r/m to r") \
|
||||||
|
X(0x34, MAP_PRIMARY, -1, IMM8|ACCUM, XOR, 2, A(AK_AL), A(AK_IMM8), A0, "XOR imm8 to AL") \
|
||||||
|
X(0x35, MAP_PRIMARY, -1, IMM32|ACCUM|REXW_OK, XOR, 2, A(AK_AX_EAX_RAX), A(AK_IMM_OPSIZE), A0, "XOR imm to accumulator") \
|
||||||
|
X(0x37, MAP_PRIMARY, -1, 0, AAA, 0, A0, A0, A0, "ASCII adjust after add") \
|
||||||
|
X(0x38, MAP_PRIMARY, -1, MODRM, CMP, 2, A(AK_RM8), A(AK_R8), A0, "Compare r/m8, r8") \
|
||||||
|
X(0x39, MAP_PRIMARY, -1, MODRM|REXW_OK, CMP, 2, A(AK_RM16_32_64), A(AK_R16_32_64), A0, "Compare r/m, r") \
|
||||||
|
X(0x3A, MAP_PRIMARY, -1, MODRM, CMP, 2, A(AK_R8), A(AK_RM8), A0, "Compare r8, r/m8") \
|
||||||
|
X(0x3B, MAP_PRIMARY, -1, MODRM|REXW_OK, CMP, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Compare r, r/m") \
|
||||||
|
X(0x3C, MAP_PRIMARY, -1, IMM8|ACCUM, CMP, 2, A(AK_AL), A(AK_IMM8), A0, "Compare AL, imm8") \
|
||||||
|
X(0x3D, MAP_PRIMARY, -1, IMM32|ACCUM|REXW_OK, CMP, 2, A(AK_AX_EAX_RAX), A(AK_IMM_OPSIZE), A0, "Compare accumulator, imm") \
|
||||||
|
X(0x3F, MAP_PRIMARY, -1, 0, AAS, 0, A0, A0, A0, "ASCII adjust after sub") \
|
||||||
|
X(0x40, MAP_0F, -1, MODRM|REXW_OK, CMOVO, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move O") \
|
||||||
|
X(0x41, MAP_0F, -1, MODRM|REXW_OK, CMOVNO, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move NO") \
|
||||||
|
X(0x42, MAP_0F, -1, MODRM|REXW_OK, CMOVB, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move B") \
|
||||||
|
X(0x43, MAP_0F, -1, MODRM|REXW_OK, CMOVAE, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move AE") \
|
||||||
|
X(0x44, MAP_0F, -1, MODRM|REXW_OK, CMOVE, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move E") \
|
||||||
|
X(0x45, MAP_0F, -1, MODRM|REXW_OK, CMOVNE, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move NE") \
|
||||||
|
X(0x46, MAP_0F, -1, MODRM|REXW_OK, CMOVBE, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move BE") \
|
||||||
|
X(0x47, MAP_0F, -1, MODRM|REXW_OK, CMOVA, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move A") \
|
||||||
|
X(0x48, MAP_0F, -1, MODRM|REXW_OK, CMOVS, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move S") \
|
||||||
|
X(0x49, MAP_0F, -1, MODRM|REXW_OK, CMOVNS, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move NS") \
|
||||||
|
X(0x4A, MAP_0F, -1, MODRM|REXW_OK, CMOVP, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move P") \
|
||||||
|
X(0x4B, MAP_0F, -1, MODRM|REXW_OK, CMOVNP, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move NP") \
|
||||||
|
X(0x4C, MAP_0F, -1, MODRM|REXW_OK, CMOVL, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move L") \
|
||||||
|
X(0x4D, MAP_0F, -1, MODRM|REXW_OK, CMOVGE, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move GE") \
|
||||||
|
X(0x4E, MAP_0F, -1, MODRM|REXW_OK, CMOVLE, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move LE") \
|
||||||
|
X(0x4F, MAP_0F, -1, MODRM|REXW_OK, CMOVG, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Conditional move G") \
|
||||||
|
X(0x50, MAP_PRIMARY, -1, PLUS_R, PUSH, 1, A(AK_R64), A0, A0, "Push r64") \
|
||||||
|
X(0x58, MAP_PRIMARY, -1, PLUS_R, POP, 1, A(AK_R64), A0, A0, "Pop into r64") \
|
||||||
|
X(0x63, MAP_PRIMARY, -1, MODRM, MOVSXD, 2, A(AK_R64), A(AK_RM32), A0, "Sign-extend dword -> qword") \
|
||||||
|
X(0x68, MAP_PRIMARY, -1, IMM32, PUSH, 1, ARG(AK_IMM32, AA_SEXT), A0, A0, "Push sign-extended imm32") \
|
||||||
|
X(0x70, MAP_PRIMARY, -1, REL8, JO, 1, A(AK_REL8), A0, A0, "Jump if overflow") \
|
||||||
|
X(0x71, MAP_PRIMARY, -1, REL8, JNO, 1, A(AK_REL8), A0, A0, "Jump if not overflow") \
|
||||||
|
X(0x72, MAP_PRIMARY, -1, REL8, JB, 1, A(AK_REL8), A0, A0, "Jump if below") \
|
||||||
|
X(0x73, MAP_PRIMARY, -1, REL8, JAE, 1, A(AK_REL8), A0, A0, "Jump if above or equal") \
|
||||||
|
X(0x74, MAP_PRIMARY, -1, REL8, JE, 1, A(AK_REL8), A0, A0, "Jump if equal") \
|
||||||
|
X(0x75, MAP_PRIMARY, -1, REL8, JNE, 1, A(AK_REL8), A0, A0, "Jump if not equal") \
|
||||||
|
X(0x76, MAP_PRIMARY, -1, REL8, JBE, 1, A(AK_REL8), A0, A0, "Jump if below or equal") \
|
||||||
|
X(0x77, MAP_PRIMARY, -1, REL8, JA, 1, A(AK_REL8), A0, A0, "Jump if above") \
|
||||||
|
X(0x78, MAP_PRIMARY, -1, REL8, JS, 1, A(AK_REL8), A0, A0, "Jump if sign") \
|
||||||
|
X(0x79, MAP_PRIMARY, -1, REL8, JNS, 1, A(AK_REL8), A0, A0, "Jump if not sign") \
|
||||||
|
X(0x7A, MAP_PRIMARY, -1, REL8, JP, 1, A(AK_REL8), A0, A0, "Jump if parity") \
|
||||||
|
X(0x7B, MAP_PRIMARY, -1, REL8, JNP, 1, A(AK_REL8), A0, A0, "Jump if not parity") \
|
||||||
|
X(0x7C, MAP_PRIMARY, -1, REL8, JL, 1, A(AK_REL8), A0, A0, "Jump if less") \
|
||||||
|
X(0x7D, MAP_PRIMARY, -1, REL8, JGE, 1, A(AK_REL8), A0, A0, "Jump if greater or equal") \
|
||||||
|
X(0x7E, MAP_PRIMARY, -1, REL8, JLE, 1, A(AK_REL8), A0, A0, "Jump if less or equal") \
|
||||||
|
X(0x7F, MAP_PRIMARY, -1, REL8, JG, 1, A(AK_REL8), A0, A0, "Jump if greater") \
|
||||||
|
X(0x80, MAP_0F, -1, REL32, JO, 1, A(AK_REL32), A0, A0, "Near JO") \
|
||||||
|
X(0x80, MAP_PRIMARY, 0, MODRM|IMM8|LOCK_OK, ADD, 2, A(AK_RM8), A(AK_IMM8), A0, "Add imm8") \
|
||||||
|
X(0x80, MAP_PRIMARY, 1, MODRM|IMM8|LOCK_OK, OR, 2, A(AK_RM8), A(AK_IMM8), A0, "OR imm8") \
|
||||||
|
X(0x80, MAP_PRIMARY, 2, MODRM|IMM8|LOCK_OK, ADC, 2, A(AK_RM8), A(AK_IMM8), A0, "ADC imm8") \
|
||||||
|
X(0x80, MAP_PRIMARY, 3, MODRM|IMM8|LOCK_OK, SBB, 2, A(AK_RM8), A(AK_IMM8), A0, "SBB imm8") \
|
||||||
|
X(0x80, MAP_PRIMARY, 4, MODRM|IMM8|LOCK_OK, AND, 2, A(AK_RM8), A(AK_IMM8), A0, "AND imm8") \
|
||||||
|
X(0x80, MAP_PRIMARY, 5, MODRM|IMM8|LOCK_OK, SUB, 2, A(AK_RM8), A(AK_IMM8), A0, "SUB imm8") \
|
||||||
|
X(0x80, MAP_PRIMARY, 6, MODRM|IMM8|LOCK_OK, XOR, 2, A(AK_RM8), A(AK_IMM8), A0, "XOR imm8") \
|
||||||
|
X(0x80, MAP_PRIMARY, 7, MODRM|IMM8, CMP, 2, A(AK_RM8), A(AK_IMM8), A0, "Compare r/m8, imm8") \
|
||||||
|
X(0x81, MAP_0F, -1, REL32, JNO, 1, A(AK_REL32), A0, A0, "Near JNO") \
|
||||||
|
X(0x81, MAP_PRIMARY, 0, MODRM|IMM32|LOCK_OK|REXW_OK, ADD, 2, A(AK_RM16_32_64), A(AK_IMM_OPSIZE), A0, "Add imm") \
|
||||||
|
X(0x81, MAP_PRIMARY, 1, MODRM|IMM32|LOCK_OK|REXW_OK, OR, 2, A(AK_RM16_32_64), A(AK_IMM_OPSIZE), A0, "OR imm") \
|
||||||
|
X(0x81, MAP_PRIMARY, 2, MODRM|IMM32|LOCK_OK|REXW_OK, ADC, 2, A(AK_RM16_32_64), A(AK_IMM_OPSIZE), A0, "ADC imm") \
|
||||||
|
X(0x81, MAP_PRIMARY, 3, MODRM|IMM32|LOCK_OK|REXW_OK, SBB, 2, A(AK_RM16_32_64), A(AK_IMM_OPSIZE), A0, "SBB imm") \
|
||||||
|
X(0x81, MAP_PRIMARY, 4, MODRM|IMM32|LOCK_OK|REXW_OK, AND, 2, A(AK_RM16_32_64), A(AK_IMM_OPSIZE), A0, "AND imm") \
|
||||||
|
X(0x81, MAP_PRIMARY, 5, MODRM|IMM32|LOCK_OK|REXW_OK, SUB, 2, A(AK_RM16_32_64), A(AK_IMM_OPSIZE), A0, "SUB imm") \
|
||||||
|
X(0x81, MAP_PRIMARY, 6, MODRM|IMM32|LOCK_OK|REXW_OK, XOR, 2, A(AK_RM16_32_64), A(AK_IMM_OPSIZE), A0, "XOR imm") \
|
||||||
|
X(0x81, MAP_PRIMARY, 7, MODRM|IMM32|REXW_OK, CMP, 2, A(AK_RM16_32_64), A(AK_IMM_OPSIZE), A0, "Compare r/m, imm") \
|
||||||
|
X(0x83, MAP_PRIMARY, 0, MODRM|IMM8|LOCK_OK|REXW_OK, ADD, 2, A(AK_RM16_32_64), ARG(AK_IMM8, AA_SEXT), A0, "Add sign-imm8") \
|
||||||
|
X(0x83, MAP_PRIMARY, 1, MODRM|IMM8|LOCK_OK|REXW_OK, OR, 2, A(AK_RM16_32_64), ARG(AK_IMM8, AA_SEXT), A0, "OR sign-imm8") \
|
||||||
|
X(0x83, MAP_PRIMARY, 2, MODRM|IMM8|LOCK_OK|REXW_OK, ADC, 2, A(AK_RM16_32_64), ARG(AK_IMM8, AA_SEXT), A0, "ADC sign-imm8") \
|
||||||
|
X(0x83, MAP_PRIMARY, 3, MODRM|IMM8|LOCK_OK|REXW_OK, SBB, 2, A(AK_RM16_32_64), ARG(AK_IMM8, AA_SEXT), A0, "SBB sign-imm8") \
|
||||||
|
X(0x83, MAP_PRIMARY, 4, MODRM|IMM8|LOCK_OK|REXW_OK, AND, 2, A(AK_RM16_32_64), ARG(AK_IMM8, AA_SEXT), A0, "AND sign-imm8") \
|
||||||
|
X(0x83, MAP_PRIMARY, 5, MODRM|IMM8|LOCK_OK|REXW_OK, SUB, 2, A(AK_RM16_32_64), ARG(AK_IMM8, AA_SEXT), A0, "SUB sign-imm8") \
|
||||||
|
X(0x83, MAP_PRIMARY, 6, MODRM|IMM8|LOCK_OK|REXW_OK, XOR, 2, A(AK_RM16_32_64), ARG(AK_IMM8, AA_SEXT), A0, "XOR sign-imm8") \
|
||||||
|
X(0x83, MAP_PRIMARY, 7, MODRM|IMM8|REXW_OK, CMP, 2, A(AK_RM16_32_64), ARG(AK_IMM8, AA_SEXT), A0, "Compare r/m, sign-imm8") \
|
||||||
|
X(0x84, MAP_PRIMARY, -1, MODRM, TEST, 2, A(AK_RM8), A(AK_R8), A0, "TEST r/m8, r8") \
|
||||||
|
X(0x85, MAP_PRIMARY, -1, MODRM|REXW_OK, TEST, 2, A(AK_RM16_32_64), A(AK_R16_32_64), A0, "TEST r/m, r") \
|
||||||
|
X(0x87, MAP_PRIMARY, -1, MODRM|REXW_OK|LOCK_OK, XCHG, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Exchange") \
|
||||||
|
X(0x88, MAP_PRIMARY, -1, MODRM|LOCK_OK, MOV, 2, A(AK_RM8), A(AK_R8), A0, "Move r8 -> r/m8") \
|
||||||
|
X(0x89, MAP_PRIMARY, -1, MODRM|LOCK_OK|REXW_OK, MOV, 2, A(AK_RM16_32_64), A(AK_R16_32_64), A0, "Move r -> r/m") \
|
||||||
|
X(0x8A, MAP_PRIMARY, -1, MODRM, MOV, 2, A(AK_R8), A(AK_RM8), A0, "Move r/m8 -> r8") \
|
||||||
|
X(0x8B, MAP_PRIMARY, -1, MODRM|REXW_OK, MOV, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Move r/m -> r") \
|
||||||
|
X(0x8D, MAP_PRIMARY, -1, MODRM|REXW_OK, LEA, 2, A(AK_R16_32_64), A(AK_M), A0, "Load effective address") \
|
||||||
|
X(0x8F, MAP_PRIMARY, -1, 0, NOP_ALIAS, 0, A0, A0, A0, "Used as POP r/m64; no pure LEA alias here") \
|
||||||
|
X(0x8F, MAP_PRIMARY, 0, MODRM, POP, 1, A(AK_RM64), A0, A0, "Pop into r/m64") \
|
||||||
|
X(0x90, MAP_0F, -1, MODRM, SETO, 1, A(AK_RM8), A0, A0, "Set on overflow") \
|
||||||
|
X(0x90, MAP_PRIMARY, -1, 0, NOP, 0, A0, A0, A0, "No operation") \
|
||||||
|
X(0x90, MAP_PRIMARY, -1, 0, PAUSE, 0, A0, A0, A0, "PAUSE uses F3 90 prefix") \
|
||||||
|
X(0x90, MAP_PRIMARY, -1, PLUS_R|ACCUM, XCHG, 2, A(AK_AX_EAX_RAX), A(AK_R16_32_64), A0, "Exchange with accumulator") \
|
||||||
|
X(0x91, MAP_0F, -1, MODRM, SETNO, 1, A(AK_RM8), A0, A0, "Set on not overflow") \
|
||||||
|
X(0x92, MAP_0F, -1, MODRM, SETB, 1, A(AK_RM8), A0, A0, "Set on below/CF=1") \
|
||||||
|
X(0x93, MAP_0F, -1, MODRM, SETAE, 1, A(AK_RM8), A0, A0, "Set on above or equal") \
|
||||||
|
X(0x94, MAP_0F, -1, MODRM, SETE, 1, A(AK_RM8), A0, A0, "Set on equal") \
|
||||||
|
X(0x95, MAP_0F, -1, MODRM, SETNE, 1, A(AK_RM8), A0, A0, "Set on not equal") \
|
||||||
|
X(0x96, MAP_0F, -1, MODRM, SETBE, 1, A(AK_RM8), A0, A0, "Set on below or equal") \
|
||||||
|
X(0x97, MAP_0F, -1, MODRM, SETA, 1, A(AK_RM8), A0, A0, "Set on above") \
|
||||||
|
X(0x98, MAP_0F, -1, MODRM, SETS, 1, A(AK_RM8), A0, A0, "Set on sign") \
|
||||||
|
X(0x98, MAP_PRIMARY, -1, 0, CBW, 0, A0, A0, A0, "AL->AX (size-propagates)") \
|
||||||
|
X(0x99, MAP_0F, -1, MODRM, SETNS, 1, A(AK_RM8), A0, A0, "Set on not sign") \
|
||||||
|
X(0x99, MAP_PRIMARY, -1, 0, CWD, 0, A0, A0, A0, "AX->DX:AX (CDQ/CQO by size)") \
|
||||||
|
X(0x9A, MAP_0F, -1, MODRM, SETP, 1, A(AK_RM8), A0, A0, "Set on parity") \
|
||||||
|
X(0x9A, MAP_PRIMARY, -1, 0, FARCALL, 0, A0, A0, A0, "Far call (not common in 64-bit)") \
|
||||||
|
X(0x9B, MAP_0F, -1, MODRM, SETNP, 1, A(AK_RM8), A0, A0, "Set on not parity") \
|
||||||
|
X(0x9B, MAP_PRIMARY, -1, 0, FWAIT, 0, A0, A0, A0, "Wait (legacy alias WAIT)") \
|
||||||
|
X(0x9C, MAP_0F, -1, MODRM, SETL, 1, A(AK_RM8), A0, A0, "Set on less") \
|
||||||
|
X(0x9C, MAP_PRIMARY, -1, 0, PUSHF, 0, A0, A0, A0, "Push rFLAGS (alias)") \
|
||||||
|
X(0x9C, MAP_PRIMARY, -1, 0, PUSHFQ, 0, A0, A0, A0, "Push RFLAGS") \
|
||||||
|
X(0x9D, MAP_0F, -1, MODRM, SETGE, 1, A(AK_RM8), A0, A0, "Set on greater or equal") \
|
||||||
|
X(0x9D, MAP_PRIMARY, -1, 0, POPF, 0, A0, A0, A0, "Pop rFLAGS (alias)") \
|
||||||
|
X(0x9D, MAP_PRIMARY, -1, 0, POPFQ, 0, A0, A0, A0, "Pop RFLAGS") \
|
||||||
|
X(0x9E, MAP_0F, -1, MODRM, SETLE, 1, A(AK_RM8), A0, A0, "Set on less or equal") \
|
||||||
|
X(0x9E, MAP_PRIMARY, -1, 0, SAHF, 0, A0, A0, A0, "Store AH into RFLAGS") \
|
||||||
|
X(0x9F, MAP_0F, -1, MODRM, SETG, 1, A(AK_RM8), A0, A0, "Set on greater") \
|
||||||
|
X(0x9F, MAP_PRIMARY, -1, 0, LAHF, 0, A0, A0, A0, "Load AH with RFLAGS") \
|
||||||
|
X(0xA0, MAP_PRIMARY, -1, MOFFS|ACCUM, MOV, 2, A(AK_AL), A(AK_MOFFS8), A0, "Load moffs8 -> AL") \
|
||||||
|
X(0xA1, MAP_PRIMARY, -1, MOFFS|ACCUM|REXW_OK, MOV, 2, A(AK_AX_EAX_RAX), A(AK_MOFFS16_32_64), A0, "Load moffs -> RAX") \
|
||||||
|
X(0xA2, MAP_0F, -1, 0, CPUID, 0, A0, A0, A0, "Query CPU ID") \
|
||||||
|
X(0xA2, MAP_PRIMARY, -1, MOFFS|ACCUM, MOV, 2, A(AK_MOFFS8), A(AK_AL), A0, "Store AL -> moffs8") \
|
||||||
|
X(0xA3, MAP_0F, -1, MODRM|REXW_OK, BT, 2, A(AK_RM16_32_64), A(AK_R16_32_64), A0, "Bit test") \
|
||||||
|
X(0xA3, MAP_PRIMARY, -1, MOFFS|ACCUM|REXW_OK, MOV, 2, A(AK_MOFFS16_32_64), A(AK_AX_EAX_RAX), A0, "Store RAX -> moffs") \
|
||||||
|
X(0xA4, MAP_PRIMARY, -1, REP_F3|REP_F2, MOVSB, 0, A0, A0, A0, "Move byte string") \
|
||||||
|
X(0xA5, MAP_PRIMARY, -1, REP_F3|REP_F2|REXW_OK, MOVSWD, 0, A0, A0, A0, "Move string (word/dword/qword by size)") \
|
||||||
|
X(0xA6, MAP_PRIMARY, -1, REP_F3|REP_F2, CMPSB, 0, A0, A0, A0, "Compare byte string") \
|
||||||
|
X(0xA7, MAP_PRIMARY, -1, REP_F3|REP_F2|REXW_OK, CMPSWD, 0, A0, A0, A0, "Compare string") \
|
||||||
|
X(0xA8, MAP_PRIMARY, -1, IMM8|ACCUM, TEST, 2, A(AK_AL), A(AK_IMM8), A0, "TEST AL, imm8") \
|
||||||
|
X(0xA9, MAP_PRIMARY, -1, IMM32|ACCUM|REXW_OK, TEST, 2, A(AK_AX_EAX_RAX), A(AK_IMM_OPSIZE), A0, "TEST accumulator, imm") \
|
||||||
|
X(0xAA, MAP_PRIMARY, -1, REP_F3|REP_F2, STOSB, 0, A0, A0, A0, "Store byte string") \
|
||||||
|
X(0xAB, MAP_0F, -1, MODRM|LOCK_OK|REXW_OK, BTS, 2, A(AK_RM16_32_64), A(AK_R16_32_64), A0, "Bit test and set") \
|
||||||
|
X(0xAB, MAP_PRIMARY, -1, REP_F3|REP_F2|REXW_OK, STOSWD, 0, A0, A0, A0, "Store string") \
|
||||||
|
X(0xAC, MAP_PRIMARY, -1, REP_F3|REP_F2, LODSB, 0, A0, A0, A0, "Load byte string") \
|
||||||
|
X(0xAD, MAP_PRIMARY, -1, REP_F3|REP_F2|REXW_OK, LODSWD, 0, A0, A0, A0, "Load string") \
|
||||||
|
X(0xAE, MAP_PRIMARY, -1, REP_F3|REP_F2, SCASB, 0, A0, A0, A0, "Scan byte string") \
|
||||||
|
X(0xAF, MAP_PRIMARY, -1, REP_F3|REP_F2|REXW_OK, SCASWD, 0, A0, A0, A0, "Scan string") \
|
||||||
|
X(0xB3, MAP_0F, -1, MODRM|LOCK_OK|REXW_OK, BTR, 2, A(AK_RM16_32_64), A(AK_R16_32_64), A0, "Bit test and reset") \
|
||||||
|
X(0xB6, MAP_0F, -1, MODRM|REXW_OK, MOVZX, 2, A(AK_R16_32_64), A(AK_RM8), A0, "Zero-extend byte") \
|
||||||
|
X(0xB7, MAP_0F, -1, MODRM|REXW_OK, MOVZX, 2, A(AK_R16_32_64), A(AK_RM16), A0, "Zero-extend word") \
|
||||||
|
X(0xBA, MAP_0F, 4, MODRM|IMM8|REXW_OK, BT, 2, A(AK_RM16_32_64), A(AK_IMM8), A0, "Bit test imm") \
|
||||||
|
X(0xBA, MAP_0F, 5, MODRM|IMM8|LOCK_OK|REXW_OK, BTS, 2, A(AK_RM16_32_64), A(AK_IMM8), A0, "Bit test and set imm") \
|
||||||
|
X(0xBA, MAP_0F, 6, MODRM|IMM8|LOCK_OK|REXW_OK, BTR, 2, A(AK_RM16_32_64), A(AK_IMM8), A0, "Bit test and reset imm") \
|
||||||
|
X(0xBA, MAP_0F, 7, MODRM|IMM8|LOCK_OK|REXW_OK, BTC, 2, A(AK_RM16_32_64), A(AK_IMM8), A0, "Bit test and complement imm")\
|
||||||
|
X(0xBB, MAP_0F, -1, MODRM|LOCK_OK|REXW_OK, BTC, 2, A(AK_RM16_32_64), A(AK_R16_32_64), A0, "Bit test and complement") \
|
||||||
|
X(0xBC, MAP_0F, -1, MODRM|REXW_OK, BSF, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Bit scan forward") \
|
||||||
|
X(0xBD, MAP_0F, -1, MODRM|REXW_OK, BSR, 2, A(AK_R16_32_64), A(AK_RM16_32_64), A0, "Bit scan reverse") \
|
||||||
|
X(0xBE, MAP_0F, -1, MODRM|REXW_OK, MOVSX, 2, A(AK_R16_32_64), A(AK_RM8), A0, "Sign-extend byte") \
|
||||||
|
X(0xBF, MAP_0F, -1, MODRM|REXW_OK, MOVSX, 2, A(AK_R16_32_64), A(AK_RM16), A0, "Sign-extend word") \
|
||||||
|
X(0xC0, MAP_0F, -1, MODRM|REXW_OK|LOCK_OK, XADD, 2, A(AK_RM8_16_32_64), A(AK_R16_32_64), A0, "Exchange and add") \
|
||||||
|
X(0xC0, MAP_PRIMARY, 0, MODRM|IMM8, ROL, 2, A(AK_RM8), A(AK_IMM8), A0, "Rotate left by imm8") \
|
||||||
|
X(0xC0, MAP_PRIMARY, 1, MODRM|IMM8, ROR, 2, A(AK_RM8), A(AK_IMM8), A0, "Rotate right by imm8") \
|
||||||
|
X(0xC0, MAP_PRIMARY, 4, MODRM|IMM8, SHL, 2, A(AK_RM8), A(AK_IMM8), A0, "Shift left by imm8") \
|
||||||
|
X(0xC0, MAP_PRIMARY, 5, MODRM|IMM8, SHR, 2, A(AK_RM8), A(AK_IMM8), A0, "Logical shift right by imm8")\
|
||||||
|
X(0xC0, MAP_PRIMARY, 7, MODRM|IMM8, SAR, 2, A(AK_RM8), A(AK_IMM8), A0, "Arithmetic shift right by imm8")\
|
||||||
|
X(0xC1, MAP_PRIMARY, 0, MODRM|IMM8|REXW_OK, ROL, 2, A(AK_RM16_32_64), A(AK_IMM8), A0, "Rotate left by imm8") \
|
||||||
|
X(0xC1, MAP_PRIMARY, 1, MODRM|IMM8|REXW_OK, ROR, 2, A(AK_RM16_32_64), A(AK_IMM8), A0, "Rotate right by imm8") \
|
||||||
|
X(0xC1, MAP_PRIMARY, 4, MODRM|IMM8|REXW_OK, SHL, 2, A(AK_RM16_32_64), A(AK_IMM8), A0, "Shift left by imm8") \
|
||||||
|
X(0xC1, MAP_PRIMARY, 5, MODRM|IMM8|REXW_OK, SHR, 2, A(AK_RM16_32_64), A(AK_IMM8), A0, "Logical shift right by imm8")\
|
||||||
|
X(0xC1, MAP_PRIMARY, 7, MODRM|IMM8|REXW_OK, SAR, 2, A(AK_RM16_32_64), A(AK_IMM8), A0, "Arithmetic shift right by imm8")\
|
||||||
|
X(0xC2, MAP_PRIMARY, -1, IMM16, RET, 1, A(AK_IMM16), A0, A0, "Return and pop imm16") \
|
||||||
|
X(0xC3, MAP_PRIMARY, -1, 0, RET, 0, A0, A0, A0, "Return") \
|
||||||
|
X(0xC6, MAP_PRIMARY, 0, MODRM|IMM8|LOCK_OK, MOV, 2, A(AK_RM8), A(AK_IMM8), A0, "Move imm8 -> r/m8") \
|
||||||
|
X(0xC7, MAP_PRIMARY, 0, MODRM|IMM32|LOCK_OK|REXW_OK, MOV, 2, A(AK_RM16_32_64), A(AK_IMM_OPSIZE), A0, "Move imm -> r/m") \
|
||||||
|
X(0xC8, MAP_0F, -1, PLUS_R|REXW_OK, BSWAP, 1, A(AK_R32_64), A0, A0, "Byte swap r32/r64") \
|
||||||
|
X(0xD0, MAP_PRIMARY, 0, MODRM, ROL, 2, A(AK_RM8), A(AK_ONE), A0, "Rotate left by 1") \
|
||||||
|
X(0xD0, MAP_PRIMARY, 1, MODRM, ROR, 2, A(AK_RM8), A(AK_ONE), A0, "Rotate right by 1") \
|
||||||
|
X(0xD0, MAP_PRIMARY, 2, MODRM, RCL, 2, A(AK_RM8), A(AK_ONE), A0, "Rotate through CF left by 1")\
|
||||||
|
X(0xD0, MAP_PRIMARY, 3, MODRM, RCR, 2, A(AK_RM8), A(AK_ONE), A0, "Rotate through CF right by 1")\
|
||||||
|
X(0xD0, MAP_PRIMARY, 4, MODRM, SHL, 2, A(AK_RM8), A(AK_ONE), A0, "Shift left by 1") \
|
||||||
|
X(0xD0, MAP_PRIMARY, 5, MODRM, SHR, 2, A(AK_RM8), A(AK_ONE), A0, "Logical shift right by 1") \
|
||||||
|
X(0xD0, MAP_PRIMARY, 7, MODRM, SAR, 2, A(AK_RM8), A(AK_ONE), A0, "Arithmetic shift right by 1")\
|
||||||
|
X(0xD1, MAP_PRIMARY, 0, MODRM|REXW_OK, ROL, 2, A(AK_RM16_32_64), A(AK_ONE), A0, "Rotate left by 1") \
|
||||||
|
X(0xD1, MAP_PRIMARY, 1, MODRM|REXW_OK, ROR, 2, A(AK_RM16_32_64), A(AK_ONE), A0, "Rotate right by 1") \
|
||||||
|
X(0xD1, MAP_PRIMARY, 2, MODRM|REXW_OK, RCL, 2, A(AK_RM16_32_64), A(AK_ONE), A0, "Rotate through CF left by 1")\
|
||||||
|
X(0xD1, MAP_PRIMARY, 3, MODRM|REXW_OK, RCR, 2, A(AK_RM16_32_64), A(AK_ONE), A0, "Rotate through CF right by 1")\
|
||||||
|
X(0xD1, MAP_PRIMARY, 4, MODRM|REXW_OK, SHL, 2, A(AK_RM16_32_64), A(AK_ONE), A0, "Shift left by 1") \
|
||||||
|
X(0xD1, MAP_PRIMARY, 5, MODRM|REXW_OK, SHR, 2, A(AK_RM16_32_64), A(AK_ONE), A0, "Logical shift right by 1") \
|
||||||
|
X(0xD1, MAP_PRIMARY, 7, MODRM|REXW_OK, SAR, 2, A(AK_RM16_32_64), A(AK_ONE), A0, "Arithmetic shift right by 1")\
|
||||||
|
X(0xD2, MAP_PRIMARY, 0, MODRM, ROL, 2, A(AK_RM8), A(AK_CL), A0, "Rotate left by CL") \
|
||||||
|
X(0xD2, MAP_PRIMARY, 1, MODRM, ROR, 2, A(AK_RM8), A(AK_CL), A0, "Rotate right by CL") \
|
||||||
|
X(0xD2, MAP_PRIMARY, 2, MODRM, RCL, 2, A(AK_RM8), A(AK_CL), A0, "Rotate through CF left by CL")\
|
||||||
|
X(0xD2, MAP_PRIMARY, 3, MODRM, RCR, 2, A(AK_RM8), A(AK_CL), A0, "Rotate through CF right by CL")\
|
||||||
|
X(0xD2, MAP_PRIMARY, 4, MODRM, SHL, 2, A(AK_RM8), A(AK_CL), A0, "Shift left by CL") \
|
||||||
|
X(0xD2, MAP_PRIMARY, 5, MODRM, SHR, 2, A(AK_RM8), A(AK_CL), A0, "Logical shift right by CL") \
|
||||||
|
X(0xD2, MAP_PRIMARY, 7, MODRM, SAR, 2, A(AK_RM8), A(AK_CL), A0, "Arithmetic shift right by CL")\
|
||||||
|
X(0xD3, MAP_PRIMARY, 0, MODRM|REXW_OK, ROL, 2, A(AK_RM16_32_64), A(AK_CL), A0, "Rotate left by CL") \
|
||||||
|
X(0xD3, MAP_PRIMARY, 1, MODRM|REXW_OK, ROR, 2, A(AK_RM16_32_64), A(AK_CL), A0, "Rotate right by CL") \
|
||||||
|
X(0xD3, MAP_PRIMARY, 2, MODRM|REXW_OK, RCL, 2, A(AK_RM16_32_64), A(AK_CL), A0, "Rotate through CF left by CL")\
|
||||||
|
X(0xD3, MAP_PRIMARY, 3, MODRM|REXW_OK, RCR, 2, A(AK_RM16_32_64), A(AK_CL), A0, "Rotate through CF right by CL")\
|
||||||
|
X(0xD3, MAP_PRIMARY, 4, MODRM|REXW_OK, SHL, 2, A(AK_RM16_32_64), A(AK_CL), A0, "Shift left by CL") \
|
||||||
|
X(0xD3, MAP_PRIMARY, 5, MODRM|REXW_OK, SHR, 2, A(AK_RM16_32_64), A(AK_CL), A0, "Logical shift right by CL") \
|
||||||
|
X(0xD3, MAP_PRIMARY, 7, MODRM|REXW_OK, SAR, 2, A(AK_RM16_32_64), A(AK_CL), A0, "Arithmetic shift right by CL")\
|
||||||
|
X(0xD7, MAP_PRIMARY, -1, 0, XLAT, 0, A0, A0, A0, "Table look-up translation") \
|
||||||
|
X(0xE8, MAP_PRIMARY, -1, REL32, CALL, 1, A(AK_REL32), A0, A0, "Near call rel32") \
|
||||||
|
X(0xE9, MAP_PRIMARY, -1, REL32, JMP, 1, A(AK_REL32), A0, A0, "Near jump rel32") \
|
||||||
|
X(0xEA, MAP_PRIMARY, -1, 0, FARJMP, 0, A0, A0, A0, "Far jump (not common in 64-bit)") \
|
||||||
|
X(0xEB, MAP_PRIMARY, -1, REL8, JMP, 1, A(AK_REL8), A0, A0, "Short jump rel8") \
|
||||||
|
X(0xF4, MAP_PRIMARY, -1, 0, HLT, 0, A0, A0, A0, "Halt") \
|
||||||
|
X(0xF5, MAP_PRIMARY, -1, 0, CMC, 0, A0, A0, A0, "Complement CF") \
|
||||||
|
X(0xF6, MAP_PRIMARY, 0, MODRM|IMM8, TEST, 2, A(AK_RM8), A(AK_IMM8), A0, "TEST r/m8, imm8") \
|
||||||
|
X(0xF6, MAP_PRIMARY, 2, MODRM, NOT, 1, A(AK_RM8), A0, A0, "Invert r/m8") \
|
||||||
|
X(0xF6, MAP_PRIMARY, 3, MODRM, NEG, 1, A(AK_RM8), A0, A0, "Two's-complement r/m8") \
|
||||||
|
X(0xF6, MAP_PRIMARY, 4, MODRM, MUL, 1, A(AK_RM8), A0, A0, "Unsigned mul AL * r/m8 -> AX") \
|
||||||
|
X(0xF6, MAP_PRIMARY, 5, MODRM, IMUL, 1, A(AK_RM8), A0, A0, "Signed mul AL * r/m8 -> AX") \
|
||||||
|
X(0xF6, MAP_PRIMARY, 6, MODRM, DIV, 1, A(AK_RM8), A0, A0, "Unsigned div AX / r/m8") \
|
||||||
|
X(0xF6, MAP_PRIMARY, 7, MODRM, IDIV, 1, A(AK_RM8), A0, A0, "Signed div AX / r/m8") \
|
||||||
|
X(0xF7, MAP_PRIMARY, 0, MODRM|IMM32|REXW_OK, TEST, 2, A(AK_RM16_32_64), A(AK_IMM_OPSIZE), A0, "TEST r/m, imm") \
|
||||||
|
X(0xF7, MAP_PRIMARY, 2, MODRM|REXW_OK, NOT, 1, A(AK_RM16_32_64), A0, A0, "Invert r/m") \
|
||||||
|
X(0xF7, MAP_PRIMARY, 3, MODRM|REXW_OK, NEG, 1, A(AK_RM16_32_64), A0, A0, "Two's-complement r/m") \
|
||||||
|
X(0xF7, MAP_PRIMARY, 4, MODRM|REXW_OK, MUL, 1, A(AK_RM16_32_64), A0, A0, "Unsigned mul accumulator") \
|
||||||
|
X(0xF7, MAP_PRIMARY, 5, MODRM|REXW_OK, IMUL, 1, A(AK_RM16_32_64), A0, A0, "Signed mul accumulator") \
|
||||||
|
X(0xF7, MAP_PRIMARY, 6, MODRM|REXW_OK, DIV, 1, A(AK_RM16_32_64), A0, A0, "Unsigned division") \
|
||||||
|
X(0xF7, MAP_PRIMARY, 7, MODRM|REXW_OK, IDIV, 1, A(AK_RM16_32_64), A0, A0, "Signed division") \
|
||||||
|
X(0xF8, MAP_PRIMARY, -1, 0, CLC, 0, A0, A0, A0, "Clear CF") \
|
||||||
|
X(0xF9, MAP_PRIMARY, -1, 0, STC, 0, A0, A0, A0, "Set CF") \
|
||||||
|
X(0xFA, MAP_PRIMARY, -1, 0, CLI, 0, A0, A0, A0, "Clear IF") \
|
||||||
|
X(0xFB, MAP_PRIMARY, -1, 0, STI, 0, A0, A0, A0, "Set IF") \
|
||||||
|
X(0xFC, MAP_PRIMARY, -1, 0, CLD, 0, A0, A0, A0, "Clear DF") \
|
||||||
|
X(0xFD, MAP_PRIMARY, -1, 0, STD, 0, A0, A0, A0, "Set DF") \
|
||||||
|
X(0xFE, MAP_PRIMARY, 0, MODRM|LOCK_OK, INC, 1, A(AK_RM8), A0, A0, "Increment r/m8") \
|
||||||
|
X(0xFE, MAP_PRIMARY, 1, MODRM|LOCK_OK, DEC, 1, A(AK_RM8), A0, A0, "Decrement r/m8") \
|
||||||
|
X(0xFF, MAP_PRIMARY, 0, MODRM|LOCK_OK|REXW_OK, INC, 1, A(AK_RM16_32_64), A0, A0, "Increment r/m") \
|
||||||
|
X(0xFF, MAP_PRIMARY, 1, MODRM|LOCK_OK|REXW_OK, DEC, 1, A(AK_RM16_32_64), A0, A0, "Decrement r/m") \
|
||||||
|
X(0xFF, MAP_PRIMARY, 2, MODRM|REXW_OK, CALL, 1, A(AK_RM16_32_64), A0, A0, "Indirect call") \
|
||||||
|
X(0xFF, MAP_PRIMARY, 4, MODRM|REXW_OK, JMP, 1, A(AK_RM16_32_64), A0, A0, "Indirect jump") \
|
||||||
|
X(0xFF, MAP_PRIMARY, 6, MODRM, PUSH, 1, A(AK_RM64), A0, A0, "Push r/m64") \
|
||||||
|
|
||||||
|
struct instruction {
|
||||||
|
uint8_t opcode;
|
||||||
|
int32_t ext;
|
||||||
|
uint32_t attrs;
|
||||||
|
uint32_t argc;
|
||||||
|
const char* mnemonic;
|
||||||
|
uint32_t args[3];
|
||||||
|
const char* desc;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define XSTR(x) #x
|
||||||
|
#define STR(x) XSTR(x)
|
||||||
|
|
||||||
|
static const struct instruction byte_to_instruction[] = {
|
||||||
|
#define X(_opcode, _map, _ext, _attrs, _mnemonic, _argc, _a1, _a2, _a3, _desc) \
|
||||||
|
[_opcode] = {.opcode = _opcode, .ext = _ext, .attrs = _attrs, .mnemonic = STR(_mnemonic), .argc = _argc, .args = {_a1, _a2, _a3}, .desc = _desc},
|
||||||
|
INSTRUCTION_LIST
|
||||||
|
#undef X
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
while ((c = fgetc(stdin)) != EOF) {
|
||||||
|
if (c < 0 || c > sizeof byte_to_instruction / sizeof *byte_to_instruction) {
|
||||||
|
fprintf(stderr, "unsupported byte 0x%02x, aborting\n", c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
struct instruction ins = byte_to_instruction[c];
|
||||||
|
if (ins.opcode == 0) {
|
||||||
|
fprintf(stderr, "unsupported byte 0x%02x, aborting\n", c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("OP: %s (0x%02x)\n", ins.mnemonic, ins.opcode);
|
||||||
|
|
||||||
|
for (int i = 0; i < ins.argc; i++) {
|
||||||
|
uint32_t arg = ins.args[i];
|
||||||
|
enum arg_kind kind = ARG_KIND(arg);
|
||||||
|
int attr = ARG_ATTRS(arg);
|
||||||
|
|
||||||
|
union {
|
||||||
|
unsigned char bytes[4];
|
||||||
|
int32_t i32;
|
||||||
|
int32_t u32;
|
||||||
|
} val = {0};
|
||||||
|
|
||||||
|
//for (int i = 3; i > 0; i--) {
|
||||||
|
for (int i = 0; i < arg_kind_bytes[kind]; i++) {
|
||||||
|
c = fgetc(stdin);
|
||||||
|
if (c == EOF) goto end;
|
||||||
|
val.bytes[i] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (kind) {
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
printf("ARG: kind: %s, attrs: %s, val: 0x%02x\n", arg_kind_str[kind], arg_attr_str[attr], val.u32);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
0
src/lib/dump_asm.h
Normal file
0
src/lib/dump_asm.h
Normal file
@@ -109,6 +109,26 @@ static int print_b32(struct printf_state* s, int padding, char pad_char)
|
|||||||
return print_long(n, alphabet, false, padding, pad_char);
|
return print_long(n, alphabet, false, padding, pad_char);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int print_linear_address(struct printf_state* s)
|
||||||
|
{
|
||||||
|
int padding = 0;
|
||||||
|
char pad_char = '\0';
|
||||||
|
uint32_t addr = va_arg(s->ap, uint32_t);
|
||||||
|
|
||||||
|
uint32_t dir = addr >> 22;
|
||||||
|
uint32_t page = (addr & ((1<<22)-1)) >> 12;
|
||||||
|
uint32_t offset = (addr & ((1<<12)-1));
|
||||||
|
|
||||||
|
struct str alphabet = str_attach("01");
|
||||||
|
int n = 0;
|
||||||
|
n += print_long(dir, alphabet, false, padding, pad_char);
|
||||||
|
terminal_putchar(' ');
|
||||||
|
n += print_long(page, alphabet, false, padding, pad_char);
|
||||||
|
terminal_putchar(' ');
|
||||||
|
n += print_long(offset, alphabet, false, padding, pad_char);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
static int print_str(struct printf_state* s, int padding, char pad_char)
|
static int print_str(struct printf_state* s, int padding, char pad_char)
|
||||||
{
|
{
|
||||||
// TODO: implement padding
|
// TODO: implement padding
|
||||||
@@ -246,6 +266,12 @@ static int parse_format_cmd(struct printf_state* s)
|
|||||||
case 'str':
|
case 'str':
|
||||||
return print_str(s, pad, pad_char);
|
return print_str(s, pad, pad_char);
|
||||||
|
|
||||||
|
case 'bin':
|
||||||
|
return print_b32(s, pad, pad_char);
|
||||||
|
|
||||||
|
case 'addr':
|
||||||
|
return print_linear_address(s);
|
||||||
|
|
||||||
case 'char':
|
case 'char':
|
||||||
return print_char(s);
|
return print_char(s);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user