Vystem 0.2
This commit is contained in:
175
shelter/lib/src/devs/apic/ioapic.c
Normal file
175
shelter/lib/src/devs/apic/ioapic.c
Normal file
@@ -0,0 +1,175 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
#include "devs/apic/ioapic.h"
|
||||
#include "memory/memory.h"
|
||||
#include "kernel/log.h"
|
||||
typedef struct {
|
||||
sh_ioapic_DEVICE **by_ioapic_id;
|
||||
sh_uint64 max_ioapic_id;
|
||||
sh_uint64 ioapic_count;
|
||||
} ioapic_devs_template;
|
||||
ioapic_devs_template ioapic_devs={0};
|
||||
static inline sh_uint32 sh_ioapic_read(sh_ioapic_DEVICE *ioapic,sh_uint32 reg) {
|
||||
*(volatile sh_uint32*)((sh_uint8*)ioapic->base+SH_IOAPIC_OFFSET_IOREGSEL)=reg;
|
||||
return *(volatile sh_uint32*)((sh_uint8*)ioapic->base+SH_IOAPIC_OFFSET_IOWIN);
|
||||
}
|
||||
static inline void sh_ioapic_write(sh_ioapic_DEVICE *ioapic,sh_uint32 reg,sh_uint32 value) {
|
||||
*(volatile sh_uint32*)((sh_uint8*)ioapic->base+SH_IOAPIC_OFFSET_IOREGSEL)=reg;
|
||||
*(volatile sh_uint32*)((sh_uint8*)ioapic->base+SH_IOAPIC_OFFSET_IOWIN)=value;
|
||||
}
|
||||
SH_STATUS sh_ioapic_init(sh_uint32 base,sh_uint8 ioapic_id,sh_uint32 gsi_base,sh_ioapic_DEVICE *ioapic) {
|
||||
if (ioapic==SH_NULLPTR || base==0) return SH_STATUS_INVALID_PARAMETER;
|
||||
sh_uint64 page=base& ~0xfffull;
|
||||
SH_STATUS status=sh_memory_identity_map(page,1,SH_PAGE_RW | SH_PAGE_PRESENT | SH_PAGE_NX | SH_PAGE_PCD);
|
||||
if (sh_status_error(status) && status!=SH_STATUS_ERROR_VA_FULLY_MAPPED) return status;
|
||||
ioapic->base=(volatile sh_uint32*)(sh_uint64)base;
|
||||
ioapic->ioapic_id=ioapic_id;
|
||||
ioapic->gsi_base=gsi_base;
|
||||
ioapic->gsi_count=0;
|
||||
ioapic->lock=SH_LOCK_LOCAL();
|
||||
sh_uint32 ver=sh_ioapic_read(ioapic,SH_IOAPIC_REGISTER_IOAPICVER);
|
||||
sh_uint32 max_redir=(ver>>16)&0xFF;
|
||||
ioapic->gsi_count=max_redir+1;
|
||||
sh_log_fdebug(SH_LOG_SOURCE_ACPI,"IOAPIC with id %1u: [%4u - %4u]\n",ioapic->ioapic_id,ioapic->gsi_base,ioapic->gsi_base+ioapic->gsi_count-1);
|
||||
sh_uint32 id_reg=sh_ioapic_read(ioapic,SH_IOAPIC_REGISTER_IOAPICID);
|
||||
sh_uint8 hw_id=(id_reg>>24)&0x0F;
|
||||
if (hw_id!=ioapic_id) {
|
||||
sh_log_fwarning(SH_LOG_SOURCE_ACPI,"IOAPIC of IOAPIC id %1u doesn't provide the same id in his hardware register: %4u.\n",ioapic_id,hw_id);
|
||||
}
|
||||
return SH_STATUS_SUCCESS;
|
||||
}
|
||||
SH_STATUS sh_ioapic_init_devs(sh_uint8 max_ioapic_id) {
|
||||
sh_ioapic_DEVICE **ioapic_ptr_by_ioapic_id=sh_malloc((max_ioapic_id+1)*sizeof(sh_ioapic_DEVICE*));
|
||||
if (!ioapic_ptr_by_ioapic_id) return SH_STATUS_ERROR_NULLPTR_RETURNED;
|
||||
sh_mem_set_8((sh_uint8*)ioapic_ptr_by_ioapic_id,0x0,(max_ioapic_id+1)*sizeof(sh_ioapic_DEVICE*));
|
||||
ioapic_devs.by_ioapic_id=ioapic_ptr_by_ioapic_id;
|
||||
ioapic_devs.max_ioapic_id=max_ioapic_id;
|
||||
return SH_STATUS_SUCCESS;
|
||||
}
|
||||
SH_STATUS sh_ioapic_bind(sh_ioapic_DEVICE *ioapic_dev) {
|
||||
if (ioapic_dev==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
|
||||
if (ioapic_devs.by_ioapic_id==SH_NULLPTR) return SH_STATUS_DEVS_NOT_INITIALIZED;
|
||||
ioapic_devs.by_ioapic_id[ioapic_dev->ioapic_id]=ioapic_dev;
|
||||
ioapic_devs.ioapic_count++;
|
||||
return SH_STATUS_SUCCESS;
|
||||
}
|
||||
sh_ioapic_DEVICE *sh_ioapic_get_dev_ioapic_id(sh_uint64 ioapic_id) {
|
||||
if (ioapic_id>ioapic_devs.max_ioapic_id) return SH_NULLPTR;
|
||||
return ioapic_devs.by_ioapic_id[ioapic_id];
|
||||
}
|
||||
SH_STATUS sh_ioapic_read_ioredtbl_entry(sh_ioapic_DEVICE *ioapic_dev,sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry) {
|
||||
if (!ioapic_dev || !entry) return SH_STATUS_INVALID_PARAMETER;
|
||||
if (gsi<ioapic_dev->gsi_base) return SH_STATUS_INVALID_PARAMETER;
|
||||
sh_uint32 index=gsi-ioapic_dev->gsi_base;
|
||||
if (index>=ioapic_dev->gsi_count) return SH_STATUS_INVALID_PARAMETER;
|
||||
sh_uint32 low_reg=SH_IOAPIC_REGISTER_IOREDTBL_BASE+(index*2);
|
||||
sh_uint32 high_reg=low_reg+1;
|
||||
sh_spin_lock(&ioapic_dev->lock);
|
||||
entry->low=sh_ioapic_read(ioapic_dev,low_reg);
|
||||
entry->high=sh_ioapic_read(ioapic_dev,high_reg);
|
||||
sh_spin_unlock(&ioapic_dev->lock);
|
||||
return SH_STATUS_SUCCESS;
|
||||
}
|
||||
SH_STATUS sh_ioapic_mask_gsi(sh_ioapic_DEVICE *dev,sh_uint32 gsi) {
|
||||
if (!dev) return SH_STATUS_INVALID_PARAMETER;
|
||||
sh_ioapic_IOREDTBL_ENTRY e;
|
||||
SH_STATUS status=sh_ioapic_read_ioredtbl_entry(dev,gsi,&e);
|
||||
if (status!=SH_STATUS_SUCCESS) return status;
|
||||
e.low|=(1<<16);
|
||||
return sh_ioapic_write_ioredtbl_entry(dev,gsi,&e);
|
||||
}
|
||||
SH_STATUS sh_ioapic_unmask_gsi(sh_ioapic_DEVICE *dev,sh_uint32 gsi) {
|
||||
if (!dev) return SH_STATUS_INVALID_PARAMETER;
|
||||
sh_ioapic_IOREDTBL_ENTRY e;
|
||||
SH_STATUS status=sh_ioapic_read_ioredtbl_entry(dev,gsi,&e);
|
||||
if (status!=SH_STATUS_SUCCESS) return status;
|
||||
e.low&= ~(1U<<16);
|
||||
return sh_ioapic_write_ioredtbl_entry(dev,gsi,&e);
|
||||
}
|
||||
SH_STATUS sh_ioapic_write_ioredtbl_entry(sh_ioapic_DEVICE *ioapic_dev,sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry) {
|
||||
if (!ioapic_dev || !entry) return SH_STATUS_INVALID_PARAMETER;
|
||||
if (gsi<ioapic_dev->gsi_base) return SH_STATUS_INVALID_PARAMETER;
|
||||
sh_uint32 index=gsi-ioapic_dev->gsi_base;
|
||||
if (index>=ioapic_dev->gsi_count) return SH_STATUS_INVALID_PARAMETER;
|
||||
sh_uint32 low_reg=SH_IOAPIC_REGISTER_IOREDTBL_BASE+(index*2);
|
||||
sh_uint32 high_reg=low_reg+1;
|
||||
sh_spin_lock(&ioapic_dev->lock);
|
||||
sh_ioapic_write(ioapic_dev,high_reg,entry->high);
|
||||
sh_ioapic_write(ioapic_dev,low_reg,entry->low);
|
||||
sh_spin_unlock(&ioapic_dev->lock);
|
||||
return SH_STATUS_SUCCESS;
|
||||
}
|
||||
sh_ioapic_DEVICE *sh_ioapic_get_dev_by_gsi(sh_uint32 gsi) {
|
||||
if (ioapic_devs.by_ioapic_id==SH_NULLPTR) return SH_NULLPTR;
|
||||
for (sh_uint64 i=0;i<=ioapic_devs.max_ioapic_id;i++) {
|
||||
sh_ioapic_DEVICE *dev=ioapic_devs.by_ioapic_id[i];
|
||||
if (!dev) continue;
|
||||
if (gsi>=dev->gsi_base && gsi<(dev->gsi_base+dev->gsi_count)) {
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
return SH_NULLPTR;
|
||||
}
|
||||
SH_STATUS sh_ioapic_mask_all() {
|
||||
if (ioapic_devs.by_ioapic_id==SH_NULLPTR) return SH_STATUS_DEVS_NOT_INITIALIZED;
|
||||
for (sh_uint64 i=0;i<=ioapic_devs.max_ioapic_id;i++) {
|
||||
sh_ioapic_DEVICE *dev=ioapic_devs.by_ioapic_id[i];
|
||||
if (!dev) continue;
|
||||
for (sh_uint32 j=0;j<dev->gsi_count;j++) {
|
||||
sh_uint32 gsi=dev->gsi_base+j;
|
||||
SH_STATUS status=sh_ioapic_mask_gsi(dev,gsi);
|
||||
if (sh_status_error(status)) return status;
|
||||
}
|
||||
}
|
||||
return SH_STATUS_SUCCESS;
|
||||
}
|
||||
SH_STATUS sh_ioapic_devs_query(char *sub_path,sh_devs_RESULT *result) {
|
||||
if (sub_path==SH_NULLPTR || result==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
|
||||
sh_uint64 path_len=sh_string_len(sub_path);
|
||||
if (path_len==0 || path_len>256) return SH_STATUS_INVALID_PARAMETER;
|
||||
if (ioapic_devs.by_ioapic_id==SH_NULLPTR) return SH_STATUS_DEVS_NOT_INITIALIZED;
|
||||
if (sh_string_compare(sub_path,"/count",6)) {
|
||||
if (path_len==6) {
|
||||
result->type=SH_DEVS_VALUE;
|
||||
result->value=ioapic_devs.ioapic_count;
|
||||
return SH_STATUS_SUCCESS;
|
||||
} else {
|
||||
return SH_STATUS_NOT_FOUND;
|
||||
}
|
||||
} else if (sh_string_compare(sub_path,"/max-ioapic-id",14)) {
|
||||
if (path_len==14) {
|
||||
result->type=SH_DEVS_VALUE;
|
||||
result->value=ioapic_devs.max_ioapic_id;
|
||||
return SH_STATUS_SUCCESS;
|
||||
} else {
|
||||
return SH_STATUS_NOT_FOUND;
|
||||
}
|
||||
} else if (sh_string_compare(sub_path,"/by-ioapic-id/",14)) {
|
||||
if (path_len>14 && path_len<=34) {
|
||||
sh_uint64 remaining_text=sh_string_len(sub_path)-sh_string_len("/by-ioapic-id/");
|
||||
char ioapic_id_str[22];
|
||||
sh_string_substring(sub_path,sh_string_len("/by-ioapic-id/"),remaining_text,ioapic_id_str);
|
||||
sh_uint64 ioapic_id=sh_string_to_uint64(ioapic_id_str);
|
||||
if (ioapic_id>ioapic_devs.max_ioapic_id) return SH_STATUS_NOT_FOUND;
|
||||
result->type=SH_DEVS_IOAPIC;
|
||||
result->value=(sh_uint64)ioapic_devs.by_ioapic_id[ioapic_id];
|
||||
return SH_STATUS_SUCCESS;
|
||||
} else {
|
||||
return SH_STATUS_NOT_FOUND;
|
||||
}
|
||||
} else if (sh_string_compare(sub_path,"/by-gsi/",8)) {
|
||||
if (path_len>8 && path_len<=28) {
|
||||
sh_uint64 remaining_text=sh_string_len(sub_path)-sh_string_len("/by-gsi/");
|
||||
char gsi_str[22];
|
||||
sh_string_substring(sub_path,sh_string_len("/by-gsi/"),remaining_text,gsi_str);
|
||||
sh_uint64 gsi=sh_string_to_uint64(gsi_str);
|
||||
result->type=SH_DEVS_IOAPIC;
|
||||
result->value=(sh_uint64)sh_ioapic_get_dev_by_gsi((sh_uint32)gsi);
|
||||
return SH_STATUS_SUCCESS;
|
||||
} else {
|
||||
return SH_STATUS_NOT_FOUND;
|
||||
}
|
||||
} else {
|
||||
return SH_STATUS_NOT_FOUND;
|
||||
}
|
||||
return SH_STATUS_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user