int arch_vcpu_deinit(struct vmm_vcpu *vcpu)
{
	virtual_addr_t sp_exec =
			riscv_regs(vcpu)->sp_exec - CONFIG_IRQ_STACK_SIZE;

	/* TODO: For Normal VCPUs */

	/* For both Orphan & Normal VCPUs */

	/* Free-up excepiton stack */
	vmm_pagepool_free(VMM_PAGEPOOL_NORMAL, sp_exec,
			  VMM_SIZE_TO_PAGE(CONFIG_IRQ_STACK_SIZE));

	/* Clear arch registers */
	memset(riscv_regs(vcpu), 0, sizeof(arch_regs_t));

	return VMM_OK;
}
int arch_vcpu_init(struct vmm_vcpu *vcpu)
{
	int rc = VMM_OK;
	const char *attr;
	virtual_addr_t sp_exec;

	/* First time allocate exception stack */
	if (!vcpu->reset_count) {
		sp_exec = vmm_pagepool_alloc(VMM_PAGEPOOL_NORMAL,
				VMM_SIZE_TO_PAGE(CONFIG_IRQ_STACK_SIZE));
		if (!sp_exec) {
			return VMM_ENOMEM;
		}
		sp_exec += CONFIG_IRQ_STACK_SIZE;
	} else {
		sp_exec = riscv_regs(vcpu)->sp_exec;
	}

	/* For both Orphan & Normal VCPUs */
	memset(riscv_regs(vcpu), 0, sizeof(arch_regs_t));
	riscv_regs(vcpu)->sepc = vcpu->start_pc;
	riscv_regs(vcpu)->sstatus = SSTATUS_SPP | SSTATUS_SPIE; /* TODO: */
	riscv_regs(vcpu)->sp = vcpu->stack_va +
			     (vcpu->stack_sz - ARCH_CACHE_LINE_SIZE);
	riscv_regs(vcpu)->sp = riscv_regs(vcpu)->sp & ~0x7;
	riscv_regs(vcpu)->sp_exec = sp_exec;
	riscv_regs(vcpu)->hstatus = 0;

	/* For Orphan VCPUs we are done */
	if (!vcpu->is_normal) {
		return VMM_OK;
	}

	/* Following initialization for normal VCPUs only */
	rc = vmm_devtree_read_string(vcpu->node,
			VMM_DEVTREE_COMPATIBLE_ATTR_NAME, &attr);
	if (rc) {
		goto done;
	}
#if __riscv_xlen == 64
	if (strcmp(attr, "riscv64,generic") != 0) {
#elif __riscv_xlen == 32
	if (strcmp(attr, "riscv32,generic") != 0) {
#else
#error "Unexpected __riscv_xlen"
#endif
		rc = VMM_EINVALID;
		goto done;
	}

	/* Update HSTATUS */
	riscv_regs(vcpu)->hstatus |= HSTATUS_SP2V;
	riscv_regs(vcpu)->hstatus |= HSTATUS_SP2P;
	riscv_regs(vcpu)->hstatus |= HSTATUS_SPV;

	/* First time initialization of private context */
	if (!vcpu->reset_count) {
		/* Alloc private context */
		vcpu->arch_priv = vmm_zalloc(sizeof(struct riscv_priv));
		if (!vcpu->arch_priv) {
			rc = VMM_ENOMEM;
			goto done;
		}
	}

	/* Update BS<xyz> */
	riscv_priv(vcpu)->bsstatus = 0; /* TODO: ??? */
	riscv_priv(vcpu)->bsie = 0;
	riscv_priv(vcpu)->bstvec = 0;
	riscv_priv(vcpu)->bsscratch = 0;
	riscv_priv(vcpu)->bsepc = 0;
	riscv_priv(vcpu)->bscause = 0;
	riscv_priv(vcpu)->bstval = 0;
	riscv_priv(vcpu)->bsip = 0;
	riscv_priv(vcpu)->bsatp = 0;

	/* Update HIDELEG */
	riscv_priv(vcpu)->hideleg = 0;
	riscv_priv(vcpu)->hideleg |= SIP_SSIP;
	riscv_priv(vcpu)->hideleg |= SIP_STIP;
	riscv_priv(vcpu)->hideleg |= SIP_SEIP;

	/* Update HEDELEG */
	riscv_priv(vcpu)->hedeleg = 0;
	riscv_priv(vcpu)->hedeleg |= (1U << CAUSE_MISALIGNED_FETCH);
	riscv_priv(vcpu)->hedeleg |= (1U << CAUSE_BREAKPOINT);
	riscv_priv(vcpu)->hedeleg |= (1U << CAUSE_USER_ECALL);
	riscv_priv(vcpu)->hedeleg |= (1U << CAUSE_FETCH_PAGE_FAULT);
	riscv_priv(vcpu)->hedeleg |= (1U << CAUSE_LOAD_PAGE_FAULT);
	riscv_priv(vcpu)->hedeleg |= (1U << CAUSE_STORE_PAGE_FAULT);

done:
	return rc;
}

int arch_vcpu_deinit(struct vmm_vcpu *vcpu)
{
	virtual_addr_t sp_exec =
			riscv_regs(vcpu)->sp_exec - CONFIG_IRQ_STACK_SIZE;

	/* For both Orphan & Normal VCPUs */

	/* Free-up excepiton stack */
	vmm_pagepool_free(VMM_PAGEPOOL_NORMAL, sp_exec,
			  VMM_SIZE_TO_PAGE(CONFIG_IRQ_STACK_SIZE));

	/* Clear arch registers */
	memset(riscv_regs(vcpu), 0, sizeof(arch_regs_t));

	/* For Orphan VCPUs do nothing else */
	if (!vcpu->is_normal) {
		return VMM_OK;
	}

	/* Free private context */
	vmm_free(vcpu->arch_priv);
	vcpu->arch_priv = NULL;

	return VMM_OK;
}