15ae6f34bSAugustin Cavalier /* 25ae6f34bSAugustin Cavalier * Copyright 2005, Oscar Lesta. All rights reserved. 38d13e725SAugustin Cavalier * Copyright 2018, Haiku, Inc. All rights reserved. 45ae6f34bSAugustin Cavalier * Distributed under the terms of the MIT License. 55ae6f34bSAugustin Cavalier */ 65ae6f34bSAugustin Cavalier 75ae6f34bSAugustin Cavalier 85ae6f34bSAugustin Cavalier #include <Drivers.h> 95ae6f34bSAugustin Cavalier #include <KernelExport.h> 105ae6f34bSAugustin Cavalier #include <ISA.h> 115ae6f34bSAugustin Cavalier #include <PCI.h> 125ae6f34bSAugustin Cavalier 13*08d7c6e8SFrançois Revol #if defined(__i386__) || defined(__x86_64__) 14*08d7c6e8SFrançois Revol #include <thread.h> 15*08d7c6e8SFrançois Revol #endif 16*08d7c6e8SFrançois Revol 175ae6f34bSAugustin Cavalier #include "poke.h" 185ae6f34bSAugustin Cavalier 19*08d7c6e8SFrançois Revol /* 20*08d7c6e8SFrançois Revol TODO: maintain a list of mapped areas in the cookie 21*08d7c6e8SFrançois Revol and only allow unmapping them, and clean them up on free. 22*08d7c6e8SFrançois Revol */ 235ae6f34bSAugustin Cavalier 245ae6f34bSAugustin Cavalier static status_t poke_open(const char*, uint32, void**); 255ae6f34bSAugustin Cavalier static status_t poke_close(void*); 265ae6f34bSAugustin Cavalier static status_t poke_free(void*); 275ae6f34bSAugustin Cavalier static status_t poke_control(void*, uint32, void*, size_t); 285ae6f34bSAugustin Cavalier static status_t poke_read(void*, off_t, void*, size_t*); 295ae6f34bSAugustin Cavalier static status_t poke_write(void*, off_t, const void*, size_t*); 305ae6f34bSAugustin Cavalier 315ae6f34bSAugustin Cavalier 325ae6f34bSAugustin Cavalier static const char* poke_name[] = { 335ae6f34bSAugustin Cavalier "misc/" POKE_DEVICE_NAME, 345ae6f34bSAugustin Cavalier NULL 355ae6f34bSAugustin Cavalier }; 365ae6f34bSAugustin Cavalier 375ae6f34bSAugustin Cavalier 385ae6f34bSAugustin Cavalier device_hooks poke_hooks = { 395ae6f34bSAugustin Cavalier poke_open, 405ae6f34bSAugustin Cavalier poke_close, 415ae6f34bSAugustin Cavalier poke_free, 425ae6f34bSAugustin Cavalier poke_control, 435ae6f34bSAugustin Cavalier poke_read, 445ae6f34bSAugustin Cavalier poke_write, 455ae6f34bSAugustin Cavalier }; 465ae6f34bSAugustin Cavalier 475ae6f34bSAugustin Cavalier int32 api_version = B_CUR_DRIVER_API_VERSION; 485ae6f34bSAugustin Cavalier 495ae6f34bSAugustin Cavalier isa_module_info* isa; 505ae6f34bSAugustin Cavalier pci_module_info* pci; 515ae6f34bSAugustin Cavalier 525ae6f34bSAugustin Cavalier 535ae6f34bSAugustin Cavalier status_t 545ae6f34bSAugustin Cavalier init_hardware(void) 555ae6f34bSAugustin Cavalier { 565ae6f34bSAugustin Cavalier return B_OK; 575ae6f34bSAugustin Cavalier } 585ae6f34bSAugustin Cavalier 595ae6f34bSAugustin Cavalier 605ae6f34bSAugustin Cavalier status_t 615ae6f34bSAugustin Cavalier init_driver(void) 625ae6f34bSAugustin Cavalier { 635ae6f34bSAugustin Cavalier if (get_module(B_ISA_MODULE_NAME, (module_info**)&isa) < B_OK) 645ae6f34bSAugustin Cavalier return ENOSYS; 655ae6f34bSAugustin Cavalier 665ae6f34bSAugustin Cavalier if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci) < B_OK) { 675ae6f34bSAugustin Cavalier put_module(B_ISA_MODULE_NAME); 685ae6f34bSAugustin Cavalier return ENOSYS; 695ae6f34bSAugustin Cavalier } 705ae6f34bSAugustin Cavalier 715ae6f34bSAugustin Cavalier return B_OK; 725ae6f34bSAugustin Cavalier } 735ae6f34bSAugustin Cavalier 745ae6f34bSAugustin Cavalier 755ae6f34bSAugustin Cavalier void 765ae6f34bSAugustin Cavalier uninit_driver(void) 775ae6f34bSAugustin Cavalier { 785ae6f34bSAugustin Cavalier put_module(B_ISA_MODULE_NAME); 795ae6f34bSAugustin Cavalier put_module(B_PCI_MODULE_NAME); 805ae6f34bSAugustin Cavalier } 815ae6f34bSAugustin Cavalier 825ae6f34bSAugustin Cavalier 835ae6f34bSAugustin Cavalier const char** 845ae6f34bSAugustin Cavalier publish_devices(void) 855ae6f34bSAugustin Cavalier { 865ae6f34bSAugustin Cavalier return poke_name; 875ae6f34bSAugustin Cavalier } 885ae6f34bSAugustin Cavalier 895ae6f34bSAugustin Cavalier 905ae6f34bSAugustin Cavalier device_hooks* 915ae6f34bSAugustin Cavalier find_device(const char* name) 925ae6f34bSAugustin Cavalier { 935ae6f34bSAugustin Cavalier return &poke_hooks; 945ae6f34bSAugustin Cavalier } 955ae6f34bSAugustin Cavalier 965ae6f34bSAugustin Cavalier 975ae6f34bSAugustin Cavalier // #pragma mark - 985ae6f34bSAugustin Cavalier 995ae6f34bSAugustin Cavalier 1005ae6f34bSAugustin Cavalier status_t 1015ae6f34bSAugustin Cavalier poke_open(const char* name, uint32 flags, void** cookie) 1025ae6f34bSAugustin Cavalier { 1035ae6f34bSAugustin Cavalier *cookie = NULL; 1045ae6f34bSAugustin Cavalier 1051e3f0626SAugustin Cavalier if (getuid() != 0 && geteuid() != 0) 1061e3f0626SAugustin Cavalier return EPERM; 1071e3f0626SAugustin Cavalier 108*08d7c6e8SFrançois Revol #if defined(__i386__) || defined(__x86_64__) 109*08d7c6e8SFrançois Revol /* on x86, raise the IOPL so that outb/inb will work */ 110*08d7c6e8SFrançois Revol iframe* frame = x86_get_user_iframe(); 111*08d7c6e8SFrançois Revol int iopl = 3; 112*08d7c6e8SFrançois Revol frame->flags &= ~X86_EFLAGS_IO_PRIVILEG_LEVEL; 113*08d7c6e8SFrançois Revol frame->flags |= (iopl << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT) 114*08d7c6e8SFrançois Revol & X86_EFLAGS_IO_PRIVILEG_LEVEL; 115*08d7c6e8SFrançois Revol #endif 116*08d7c6e8SFrançois Revol 1175ae6f34bSAugustin Cavalier return B_OK; 1185ae6f34bSAugustin Cavalier } 1195ae6f34bSAugustin Cavalier 1205ae6f34bSAugustin Cavalier 1215ae6f34bSAugustin Cavalier status_t 1225ae6f34bSAugustin Cavalier poke_close(void* cookie) 1235ae6f34bSAugustin Cavalier { 1245ae6f34bSAugustin Cavalier return B_OK; 1255ae6f34bSAugustin Cavalier } 1265ae6f34bSAugustin Cavalier 1275ae6f34bSAugustin Cavalier 1285ae6f34bSAugustin Cavalier status_t 1295ae6f34bSAugustin Cavalier poke_free(void* cookie) 1305ae6f34bSAugustin Cavalier { 131*08d7c6e8SFrançois Revol #if defined(__i386__) || defined(__x86_64__) 132*08d7c6e8SFrançois Revol iframe* frame = x86_get_user_iframe(); 133*08d7c6e8SFrançois Revol int iopl = 0; 134*08d7c6e8SFrançois Revol frame->flags &= ~X86_EFLAGS_IO_PRIVILEG_LEVEL; 135*08d7c6e8SFrançois Revol frame->flags |= (iopl << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT) 136*08d7c6e8SFrançois Revol & X86_EFLAGS_IO_PRIVILEG_LEVEL; 137*08d7c6e8SFrançois Revol #endif 138*08d7c6e8SFrançois Revol 1395ae6f34bSAugustin Cavalier return B_OK; 1405ae6f34bSAugustin Cavalier } 1415ae6f34bSAugustin Cavalier 1425ae6f34bSAugustin Cavalier 1435ae6f34bSAugustin Cavalier status_t 1445ae6f34bSAugustin Cavalier poke_control(void* cookie, uint32 op, void* arg, size_t length) 1455ae6f34bSAugustin Cavalier { 1465ae6f34bSAugustin Cavalier switch (op) { 1475ae6f34bSAugustin Cavalier case POKE_PORT_READ: 1485ae6f34bSAugustin Cavalier { 1498d13e725SAugustin Cavalier status_t result = B_OK; 1508d13e725SAugustin Cavalier port_io_args ioctl; 1518d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(port_io_args)) != B_OK) 1528d13e725SAugustin Cavalier return B_BAD_ADDRESS; 1538d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE) 1545ae6f34bSAugustin Cavalier return B_BAD_VALUE; 1555ae6f34bSAugustin Cavalier 1568d13e725SAugustin Cavalier switch (ioctl.size) { 1575ae6f34bSAugustin Cavalier case 1: 1588d13e725SAugustin Cavalier ioctl.value = isa->read_io_8(ioctl.port); 1595ae6f34bSAugustin Cavalier break; 1605ae6f34bSAugustin Cavalier case 2: 1618d13e725SAugustin Cavalier ioctl.value = isa->read_io_16(ioctl.port); 1625ae6f34bSAugustin Cavalier break; 1635ae6f34bSAugustin Cavalier case 4: 1648d13e725SAugustin Cavalier ioctl.value = isa->read_io_32(ioctl.port); 1655ae6f34bSAugustin Cavalier break; 1665ae6f34bSAugustin Cavalier default: 1675ae6f34bSAugustin Cavalier result = B_BAD_VALUE; 1685ae6f34bSAugustin Cavalier } 1695ae6f34bSAugustin Cavalier 1708d13e725SAugustin Cavalier if (user_memcpy(arg, &ioctl, sizeof(port_io_args)) != B_OK) 1718d13e725SAugustin Cavalier return B_BAD_ADDRESS; 1725ae6f34bSAugustin Cavalier return result; 1735ae6f34bSAugustin Cavalier } 1745ae6f34bSAugustin Cavalier 1755ae6f34bSAugustin Cavalier case POKE_PORT_WRITE: 1765ae6f34bSAugustin Cavalier { 1778d13e725SAugustin Cavalier status_t result = B_OK; 1788d13e725SAugustin Cavalier port_io_args ioctl; 1798d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(port_io_args)) != B_OK) 1808d13e725SAugustin Cavalier return B_BAD_ADDRESS; 1818d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE) 1825ae6f34bSAugustin Cavalier return B_BAD_VALUE; 1835ae6f34bSAugustin Cavalier 1848d13e725SAugustin Cavalier switch (ioctl.size) { 1855ae6f34bSAugustin Cavalier case 1: 1868d13e725SAugustin Cavalier isa->write_io_8(ioctl.port, ioctl.value); 1875ae6f34bSAugustin Cavalier break; 1885ae6f34bSAugustin Cavalier case 2: 1898d13e725SAugustin Cavalier isa->write_io_16(ioctl.port, ioctl.value); 1905ae6f34bSAugustin Cavalier break; 1915ae6f34bSAugustin Cavalier case 4: 1928d13e725SAugustin Cavalier isa->write_io_32(ioctl.port, ioctl.value); 1935ae6f34bSAugustin Cavalier break; 1945ae6f34bSAugustin Cavalier default: 1955ae6f34bSAugustin Cavalier result = B_BAD_VALUE; 1965ae6f34bSAugustin Cavalier } 1975ae6f34bSAugustin Cavalier 1985ae6f34bSAugustin Cavalier return result; 1995ae6f34bSAugustin Cavalier } 2005ae6f34bSAugustin Cavalier 2015ae6f34bSAugustin Cavalier case POKE_PORT_INDEXED_READ: 2025ae6f34bSAugustin Cavalier { 2038d13e725SAugustin Cavalier port_io_args ioctl; 2048d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(port_io_args)) != B_OK) 2058d13e725SAugustin Cavalier return B_BAD_ADDRESS; 2068d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE) 2075ae6f34bSAugustin Cavalier return B_BAD_VALUE; 2085ae6f34bSAugustin Cavalier 2098d13e725SAugustin Cavalier isa->write_io_8(ioctl.port, ioctl.size); 2108d13e725SAugustin Cavalier ioctl.value = isa->read_io_8(ioctl.port + 1); 2118d13e725SAugustin Cavalier 2128d13e725SAugustin Cavalier if (user_memcpy(arg, &ioctl, sizeof(port_io_args)) != B_OK) 2138d13e725SAugustin Cavalier return B_BAD_ADDRESS; 2145ae6f34bSAugustin Cavalier return B_OK; 2155ae6f34bSAugustin Cavalier } 2165ae6f34bSAugustin Cavalier 2175ae6f34bSAugustin Cavalier case POKE_PORT_INDEXED_WRITE: 2185ae6f34bSAugustin Cavalier { 2198d13e725SAugustin Cavalier port_io_args ioctl; 2208d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(port_io_args)) != B_OK) 2218d13e725SAugustin Cavalier return B_BAD_ADDRESS; 2228d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE) 2235ae6f34bSAugustin Cavalier return B_BAD_VALUE; 2245ae6f34bSAugustin Cavalier 2258d13e725SAugustin Cavalier isa->write_io_8(ioctl.port, ioctl.size); 2268d13e725SAugustin Cavalier isa->write_io_8(ioctl.port + 1, ioctl.value); 2275ae6f34bSAugustin Cavalier return B_OK; 2285ae6f34bSAugustin Cavalier } 2295ae6f34bSAugustin Cavalier 2305ae6f34bSAugustin Cavalier case POKE_PCI_READ_CONFIG: 2315ae6f34bSAugustin Cavalier { 2328d13e725SAugustin Cavalier pci_io_args ioctl; 2338d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(pci_io_args)) != B_OK) 2348d13e725SAugustin Cavalier return B_BAD_ADDRESS; 2358d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE) 2365ae6f34bSAugustin Cavalier return B_BAD_VALUE; 2375ae6f34bSAugustin Cavalier 2388d13e725SAugustin Cavalier ioctl.value = pci->read_pci_config(ioctl.bus, ioctl.device, 2398d13e725SAugustin Cavalier ioctl.function, ioctl.offset, ioctl.size); 2408d13e725SAugustin Cavalier if (user_memcpy(arg, &ioctl, sizeof(pci_io_args)) != B_OK) 2418d13e725SAugustin Cavalier return B_BAD_ADDRESS; 2425ae6f34bSAugustin Cavalier return B_OK; 2435ae6f34bSAugustin Cavalier } 2445ae6f34bSAugustin Cavalier 2455ae6f34bSAugustin Cavalier case POKE_PCI_WRITE_CONFIG: 2465ae6f34bSAugustin Cavalier { 2478d13e725SAugustin Cavalier pci_io_args ioctl; 2488d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(pci_io_args)) != B_OK) 2498d13e725SAugustin Cavalier return B_BAD_ADDRESS; 2508d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE) 2515ae6f34bSAugustin Cavalier return B_BAD_VALUE; 2525ae6f34bSAugustin Cavalier 2538d13e725SAugustin Cavalier pci->write_pci_config(ioctl.bus, ioctl.device, ioctl.function, 2548d13e725SAugustin Cavalier ioctl.offset, ioctl.size, ioctl.value); 2555ae6f34bSAugustin Cavalier return B_OK; 2565ae6f34bSAugustin Cavalier } 2575ae6f34bSAugustin Cavalier 2585ae6f34bSAugustin Cavalier case POKE_GET_NTH_PCI_INFO: 2595ae6f34bSAugustin Cavalier { 2608d13e725SAugustin Cavalier pci_info_args ioctl; 2618d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(pci_info_args)) != B_OK) 2628d13e725SAugustin Cavalier return B_BAD_ADDRESS; 2638d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE) 2645ae6f34bSAugustin Cavalier return B_BAD_VALUE; 2655ae6f34bSAugustin Cavalier 2668d13e725SAugustin Cavalier pci_info info; 2678d13e725SAugustin Cavalier ioctl.status = pci->get_nth_pci_info(ioctl.index, &info); 2688d13e725SAugustin Cavalier 2698d13e725SAugustin Cavalier if (user_memcpy(ioctl.info, &info, sizeof(pci_info)) != B_OK) 2708d13e725SAugustin Cavalier return B_BAD_ADDRESS; 2718d13e725SAugustin Cavalier if (user_memcpy(arg, &ioctl, sizeof(pci_info_args)) != B_OK) 2728d13e725SAugustin Cavalier return B_BAD_ADDRESS; 2735ae6f34bSAugustin Cavalier return B_OK; 2745ae6f34bSAugustin Cavalier } 2755ae6f34bSAugustin Cavalier 2765ae6f34bSAugustin Cavalier case POKE_GET_PHYSICAL_ADDRESS: 2775ae6f34bSAugustin Cavalier { 2788d13e725SAugustin Cavalier mem_map_args ioctl; 2798d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(mem_map_args)) != B_OK) 2808d13e725SAugustin Cavalier return B_BAD_ADDRESS; 2815ae6f34bSAugustin Cavalier physical_entry table; 2825ae6f34bSAugustin Cavalier status_t result; 2835ae6f34bSAugustin Cavalier 2848d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE) 2855ae6f34bSAugustin Cavalier return B_BAD_VALUE; 2865ae6f34bSAugustin Cavalier 2878d13e725SAugustin Cavalier result = get_memory_map(ioctl.address, ioctl.size, &table, 1); 2888d13e725SAugustin Cavalier ioctl.physical_address = (void*)(addr_t)table.address; 2895ae6f34bSAugustin Cavalier // TODO: mem_map_args::physical_address should be phys_addr_t! 2908d13e725SAugustin Cavalier ioctl.size = table.size; 2918d13e725SAugustin Cavalier if (user_memcpy(arg, &ioctl, sizeof(mem_map_args)) != B_OK) 2928d13e725SAugustin Cavalier return B_BAD_ADDRESS; 2935ae6f34bSAugustin Cavalier return result; 2945ae6f34bSAugustin Cavalier } 2955ae6f34bSAugustin Cavalier 2965ae6f34bSAugustin Cavalier case POKE_MAP_MEMORY: 2975ae6f34bSAugustin Cavalier { 2988d13e725SAugustin Cavalier mem_map_args ioctl; 2998d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(mem_map_args)) != B_OK) 3008d13e725SAugustin Cavalier return B_BAD_ADDRESS; 3018d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE) 3025ae6f34bSAugustin Cavalier return B_BAD_VALUE; 3035ae6f34bSAugustin Cavalier 3048d13e725SAugustin Cavalier char name[B_OS_NAME_LENGTH]; 3058d13e725SAugustin Cavalier if (user_strlcpy(name, ioctl.name, B_OS_NAME_LENGTH) != B_OK) 3068d13e725SAugustin Cavalier return B_BAD_ADDRESS; 3078d13e725SAugustin Cavalier 3088d13e725SAugustin Cavalier ioctl.area = map_physical_memory(name, 3098d13e725SAugustin Cavalier (addr_t)ioctl.physical_address, ioctl.size, ioctl.flags, 3108d13e725SAugustin Cavalier ioctl.protection, (void**)&ioctl.address); 3118d13e725SAugustin Cavalier 3128d13e725SAugustin Cavalier if (user_memcpy(arg, &ioctl, sizeof(mem_map_args)) != B_OK) 3138d13e725SAugustin Cavalier return B_BAD_ADDRESS; 3148d13e725SAugustin Cavalier return ioctl.area; 3155ae6f34bSAugustin Cavalier } 3165ae6f34bSAugustin Cavalier 3175ae6f34bSAugustin Cavalier case POKE_UNMAP_MEMORY: 3185ae6f34bSAugustin Cavalier { 3198d13e725SAugustin Cavalier mem_map_args ioctl; 3208d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(mem_map_args)) != B_OK) 3218d13e725SAugustin Cavalier return B_BAD_ADDRESS; 3228d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE) 3235ae6f34bSAugustin Cavalier return B_BAD_VALUE; 3245ae6f34bSAugustin Cavalier 3258d13e725SAugustin Cavalier return delete_area(ioctl.area); 3265ae6f34bSAugustin Cavalier } 3275ae6f34bSAugustin Cavalier } 3285ae6f34bSAugustin Cavalier 3295ae6f34bSAugustin Cavalier return B_BAD_VALUE; 3305ae6f34bSAugustin Cavalier } 3315ae6f34bSAugustin Cavalier 3325ae6f34bSAugustin Cavalier 3335ae6f34bSAugustin Cavalier status_t 3345ae6f34bSAugustin Cavalier poke_read(void* cookie, off_t position, void* buffer, size_t* numBytes) 3355ae6f34bSAugustin Cavalier { 3365ae6f34bSAugustin Cavalier *numBytes = 0; 3375ae6f34bSAugustin Cavalier return B_NOT_ALLOWED; 3385ae6f34bSAugustin Cavalier } 3395ae6f34bSAugustin Cavalier 3405ae6f34bSAugustin Cavalier 3415ae6f34bSAugustin Cavalier status_t 3425ae6f34bSAugustin Cavalier poke_write(void* cookie, off_t position, const void* buffer, size_t* numBytes) 3435ae6f34bSAugustin Cavalier { 3445ae6f34bSAugustin Cavalier *numBytes = 0; 3455ae6f34bSAugustin Cavalier return B_NOT_ALLOWED; 3465ae6f34bSAugustin Cavalier } 347