import pyopencl as cl
import numpy as np

# ----------------------------
# 1️⃣ HDGL lattice setup
# ----------------------------
ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)

LATTICE_SIZE = 64 * 1024 * 1024  # 64 MB
lattice_mem = np.zeros(LATTICE_SIZE, dtype=np.uint8)
lattice_buf = cl.Buffer(ctx, cl.mem_flags.READ_WRITE | cl.mem_flags.COPY_HOST_PTR, hostbuf=lattice_mem)
print("[HDGL] Lattice initialized.")

# ----------------------------
# 2️⃣ Load Debian kernel + initramfs
# ----------------------------
KERNEL_OFFSET = 0x100000  # 1 MB
INITRAMFS_OFFSET = 0x800000  # 8 MB

with open("bzImage", "rb") as f:
    kernel_bytes = np.frombuffer(f.read(), dtype=np.uint8)

with open("initramfs.cpio.gz", "rb") as f:
    initramfs_bytes = np.frombuffer(f.read(), dtype=np.uint8)

cl.enqueue_copy(queue, lattice_buf, kernel_bytes, device_offset=KERNEL_OFFSET)
cl.enqueue_copy(queue, lattice_buf, initramfs_bytes, device_offset=INITRAMFS_OFFSET)
print(f"[HDGL] Debian kernel loaded at 0x{KERNEL_OFFSET:X}")
print(f"[HDGL] initramfs loaded at 0x{INITRAMFS_OFFSET:X}")

# ----------------------------
# 3️⃣ CPU / Registers / Memory
# ----------------------------
cpu_ip = KERNEL_OFFSET
cpu_cs = 0x0000
cpu_regs = {"ax":0,"bx":0,"cx":0,"dx":0,"sp":0x7C00,"bp":0,"si":0,"di":0}
cpu_flags = 0x0002  # reserved
gdt = []
memory_map = {}

# ----------------------------
# 4️⃣ Minimal instruction emulation
# ----------------------------
def fetch_byte(addr):
    return lattice_mem[addr]

def fetch_word(addr):
    return lattice_mem[addr] | (lattice_mem[addr+1]<<8)

def far_jump(addr):
    offset = fetch_word(addr+1)
    segment = fetch_word(addr+3)
    new_ip = (segment << 4) + offset
    print(f"[HDGL] Far JMP to 0x{new_ip:X}")
    return new_ip

def emulate_instruction(opcode):
    global cpu_ip, cpu_regs
    # minimal set needed to reach kernel entry
    if opcode == 0xB8:  # MOV AX, imm16
        cpu_regs["ax"] = fetch_word(cpu_ip+1)
        cpu_ip += 3
    elif opcode == 0xEA:  # Far JMP
        cpu_ip = far_jump(cpu_ip)
        enable_protected_mode()
    elif opcode == 0xF4:  # HLT
        return False
    else:
        cpu_ip += 1  # skip unknowns
    return True

# ----------------------------
# 5️⃣ Protected mode + minimal MMU
# ----------------------------
def enable_protected_mode():
    global cpu_flags
    gdt.append({"base":0x0,"limit":0xFFFFF,"type":"code"})
    gdt.append({"base":0x0,"limit":0xFFFFF,"type":"data"})
    cpu_flags |= 0x20000  # CR0.PE simulation
    print("[HDGL] Protected mode enabled (stub). Kernel ready to execute.")

def map_memory(addr, size):
    memory_map[addr] = bytearray(size)
    print(f"[HDGL] Memory mapped: 0x{addr:X} - 0x{addr+size:X}")

# map kernel + initramfs
map_memory(KERNEL_OFFSET, len(kernel_bytes))
map_memory(INITRAMFS_OFFSET, len(initramfs_bytes))

# ----------------------------
# 6️⃣ Bootstrap execution loop
# ----------------------------
ticks = 0
MAX_TICKS = 1_000_000
while ticks < MAX_TICKS:
    opcode = fetch_byte(cpu_ip)
    running = emulate_instruction(opcode)
    if not running:
        break
    ticks += 1
    if ticks % 50_000 == 0:
        print(f"[Tick {ticks}] IP: 0x{cpu_ip:X}")

print("[HDGL] Minimal Debian kernel + initramfs ready in HDGL lattice.")
