15ae6f34bSAugustin Cavalier /*
25ae6f34bSAugustin Cavalier * Copyright 2005, Oscar Lesta. All rights reserved.
3*0bb43cbfSX512 * Copyright 2018-2023, Haiku, Inc. All rights reserved.
45ae6f34bSAugustin Cavalier * Distributed under the terms of the MIT License.
55ae6f34bSAugustin Cavalier */
6*0bb43cbfSX512 #include "poke.h"
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*0bb43cbfSX512 #include <team.h>
14*0bb43cbfSX512 #include <vm/vm.h>
15*0bb43cbfSX512
1608d7c6e8SFrançois Revol #if defined(__i386__) || defined(__x86_64__)
1708d7c6e8SFrançois Revol #include <thread.h>
1808d7c6e8SFrançois Revol #endif
1908d7c6e8SFrançois Revol
205ae6f34bSAugustin Cavalier
215ae6f34bSAugustin Cavalier static status_t poke_open(const char*, uint32, void**);
225ae6f34bSAugustin Cavalier static status_t poke_close(void*);
235ae6f34bSAugustin Cavalier static status_t poke_free(void*);
245ae6f34bSAugustin Cavalier static status_t poke_control(void*, uint32, void*, size_t);
255ae6f34bSAugustin Cavalier static status_t poke_read(void*, off_t, void*, size_t*);
265ae6f34bSAugustin Cavalier static status_t poke_write(void*, off_t, const void*, size_t*);
275ae6f34bSAugustin Cavalier
285ae6f34bSAugustin Cavalier
295ae6f34bSAugustin Cavalier static const char* poke_name[] = {
305ae6f34bSAugustin Cavalier "misc/" POKE_DEVICE_NAME,
315ae6f34bSAugustin Cavalier NULL
325ae6f34bSAugustin Cavalier };
335ae6f34bSAugustin Cavalier
345ae6f34bSAugustin Cavalier
355ae6f34bSAugustin Cavalier device_hooks poke_hooks = {
365ae6f34bSAugustin Cavalier poke_open,
375ae6f34bSAugustin Cavalier poke_close,
385ae6f34bSAugustin Cavalier poke_free,
395ae6f34bSAugustin Cavalier poke_control,
405ae6f34bSAugustin Cavalier poke_read,
415ae6f34bSAugustin Cavalier poke_write,
425ae6f34bSAugustin Cavalier };
435ae6f34bSAugustin Cavalier
445ae6f34bSAugustin Cavalier int32 api_version = B_CUR_DRIVER_API_VERSION;
455ae6f34bSAugustin Cavalier
465ae6f34bSAugustin Cavalier isa_module_info* isa;
475ae6f34bSAugustin Cavalier pci_module_info* pci;
485ae6f34bSAugustin Cavalier
495ae6f34bSAugustin Cavalier
505ae6f34bSAugustin Cavalier status_t
init_hardware(void)515ae6f34bSAugustin Cavalier init_hardware(void)
525ae6f34bSAugustin Cavalier {
535ae6f34bSAugustin Cavalier return B_OK;
545ae6f34bSAugustin Cavalier }
555ae6f34bSAugustin Cavalier
565ae6f34bSAugustin Cavalier
575ae6f34bSAugustin Cavalier status_t
init_driver(void)585ae6f34bSAugustin Cavalier init_driver(void)
595ae6f34bSAugustin Cavalier {
605ae6f34bSAugustin Cavalier if (get_module(B_ISA_MODULE_NAME, (module_info**)&isa) < B_OK)
615ae6f34bSAugustin Cavalier return ENOSYS;
625ae6f34bSAugustin Cavalier
635ae6f34bSAugustin Cavalier if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci) < B_OK) {
645ae6f34bSAugustin Cavalier put_module(B_ISA_MODULE_NAME);
655ae6f34bSAugustin Cavalier return ENOSYS;
665ae6f34bSAugustin Cavalier }
675ae6f34bSAugustin Cavalier
685ae6f34bSAugustin Cavalier return B_OK;
695ae6f34bSAugustin Cavalier }
705ae6f34bSAugustin Cavalier
715ae6f34bSAugustin Cavalier
725ae6f34bSAugustin Cavalier void
uninit_driver(void)735ae6f34bSAugustin Cavalier uninit_driver(void)
745ae6f34bSAugustin Cavalier {
755ae6f34bSAugustin Cavalier put_module(B_ISA_MODULE_NAME);
765ae6f34bSAugustin Cavalier put_module(B_PCI_MODULE_NAME);
775ae6f34bSAugustin Cavalier }
785ae6f34bSAugustin Cavalier
795ae6f34bSAugustin Cavalier
805ae6f34bSAugustin Cavalier const char**
publish_devices(void)815ae6f34bSAugustin Cavalier publish_devices(void)
825ae6f34bSAugustin Cavalier {
835ae6f34bSAugustin Cavalier return poke_name;
845ae6f34bSAugustin Cavalier }
855ae6f34bSAugustin Cavalier
865ae6f34bSAugustin Cavalier
875ae6f34bSAugustin Cavalier device_hooks*
find_device(const char * name)885ae6f34bSAugustin Cavalier find_device(const char* name)
895ae6f34bSAugustin Cavalier {
905ae6f34bSAugustin Cavalier return &poke_hooks;
915ae6f34bSAugustin Cavalier }
925ae6f34bSAugustin Cavalier
935ae6f34bSAugustin Cavalier
945ae6f34bSAugustin Cavalier // #pragma mark -
955ae6f34bSAugustin Cavalier
965ae6f34bSAugustin Cavalier
975ae6f34bSAugustin Cavalier status_t
poke_open(const char * name,uint32 flags,void ** cookie)985ae6f34bSAugustin Cavalier poke_open(const char* name, uint32 flags, void** cookie)
995ae6f34bSAugustin Cavalier {
1005ae6f34bSAugustin Cavalier *cookie = NULL;
1015ae6f34bSAugustin Cavalier
1021e3f0626SAugustin Cavalier if (getuid() != 0 && geteuid() != 0)
1031e3f0626SAugustin Cavalier return EPERM;
1041e3f0626SAugustin Cavalier
10508d7c6e8SFrançois Revol #if defined(__i386__) || defined(__x86_64__)
10608d7c6e8SFrançois Revol /* on x86, raise the IOPL so that outb/inb will work */
10708d7c6e8SFrançois Revol iframe* frame = x86_get_user_iframe();
10808d7c6e8SFrançois Revol int iopl = 3;
10908d7c6e8SFrançois Revol frame->flags &= ~X86_EFLAGS_IO_PRIVILEG_LEVEL;
11008d7c6e8SFrançois Revol frame->flags |= (iopl << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT)
11108d7c6e8SFrançois Revol & X86_EFLAGS_IO_PRIVILEG_LEVEL;
11208d7c6e8SFrançois Revol #endif
11308d7c6e8SFrançois Revol
1145ae6f34bSAugustin Cavalier return B_OK;
1155ae6f34bSAugustin Cavalier }
1165ae6f34bSAugustin Cavalier
1175ae6f34bSAugustin Cavalier
1185ae6f34bSAugustin Cavalier status_t
poke_close(void * cookie)1195ae6f34bSAugustin Cavalier poke_close(void* cookie)
1205ae6f34bSAugustin Cavalier {
1215ae6f34bSAugustin Cavalier return B_OK;
1225ae6f34bSAugustin Cavalier }
1235ae6f34bSAugustin Cavalier
1245ae6f34bSAugustin Cavalier
1255ae6f34bSAugustin Cavalier status_t
poke_free(void * cookie)1265ae6f34bSAugustin Cavalier poke_free(void* cookie)
1275ae6f34bSAugustin Cavalier {
12808d7c6e8SFrançois Revol #if defined(__i386__) || defined(__x86_64__)
12908d7c6e8SFrançois Revol iframe* frame = x86_get_user_iframe();
13008d7c6e8SFrançois Revol int iopl = 0;
13108d7c6e8SFrançois Revol frame->flags &= ~X86_EFLAGS_IO_PRIVILEG_LEVEL;
13208d7c6e8SFrançois Revol frame->flags |= (iopl << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT)
13308d7c6e8SFrançois Revol & X86_EFLAGS_IO_PRIVILEG_LEVEL;
13408d7c6e8SFrançois Revol #endif
13508d7c6e8SFrançois Revol
1365ae6f34bSAugustin Cavalier return B_OK;
1375ae6f34bSAugustin Cavalier }
1385ae6f34bSAugustin Cavalier
1395ae6f34bSAugustin Cavalier
1405ae6f34bSAugustin Cavalier status_t
poke_control(void * cookie,uint32 op,void * arg,size_t length)1415ae6f34bSAugustin Cavalier poke_control(void* cookie, uint32 op, void* arg, size_t length)
1425ae6f34bSAugustin Cavalier {
1435ae6f34bSAugustin Cavalier switch (op) {
1445ae6f34bSAugustin Cavalier case POKE_PORT_READ:
1455ae6f34bSAugustin Cavalier {
1468d13e725SAugustin Cavalier status_t result = B_OK;
1478d13e725SAugustin Cavalier port_io_args ioctl;
1488d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(port_io_args)) != B_OK)
1498d13e725SAugustin Cavalier return B_BAD_ADDRESS;
1508d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE)
1515ae6f34bSAugustin Cavalier return B_BAD_VALUE;
1525ae6f34bSAugustin Cavalier
1538d13e725SAugustin Cavalier switch (ioctl.size) {
1545ae6f34bSAugustin Cavalier case 1:
1558d13e725SAugustin Cavalier ioctl.value = isa->read_io_8(ioctl.port);
1565ae6f34bSAugustin Cavalier break;
1575ae6f34bSAugustin Cavalier case 2:
1588d13e725SAugustin Cavalier ioctl.value = isa->read_io_16(ioctl.port);
1595ae6f34bSAugustin Cavalier break;
1605ae6f34bSAugustin Cavalier case 4:
1618d13e725SAugustin Cavalier ioctl.value = isa->read_io_32(ioctl.port);
1625ae6f34bSAugustin Cavalier break;
1635ae6f34bSAugustin Cavalier default:
1645ae6f34bSAugustin Cavalier result = B_BAD_VALUE;
1655ae6f34bSAugustin Cavalier }
1665ae6f34bSAugustin Cavalier
1678d13e725SAugustin Cavalier if (user_memcpy(arg, &ioctl, sizeof(port_io_args)) != B_OK)
1688d13e725SAugustin Cavalier return B_BAD_ADDRESS;
1695ae6f34bSAugustin Cavalier return result;
1705ae6f34bSAugustin Cavalier }
1715ae6f34bSAugustin Cavalier
1725ae6f34bSAugustin Cavalier case POKE_PORT_WRITE:
1735ae6f34bSAugustin Cavalier {
1748d13e725SAugustin Cavalier status_t result = B_OK;
1758d13e725SAugustin Cavalier port_io_args ioctl;
1768d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(port_io_args)) != B_OK)
1778d13e725SAugustin Cavalier return B_BAD_ADDRESS;
1788d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE)
1795ae6f34bSAugustin Cavalier return B_BAD_VALUE;
1805ae6f34bSAugustin Cavalier
1818d13e725SAugustin Cavalier switch (ioctl.size) {
1825ae6f34bSAugustin Cavalier case 1:
1838d13e725SAugustin Cavalier isa->write_io_8(ioctl.port, ioctl.value);
1845ae6f34bSAugustin Cavalier break;
1855ae6f34bSAugustin Cavalier case 2:
1868d13e725SAugustin Cavalier isa->write_io_16(ioctl.port, ioctl.value);
1875ae6f34bSAugustin Cavalier break;
1885ae6f34bSAugustin Cavalier case 4:
1898d13e725SAugustin Cavalier isa->write_io_32(ioctl.port, ioctl.value);
1905ae6f34bSAugustin Cavalier break;
1915ae6f34bSAugustin Cavalier default:
1925ae6f34bSAugustin Cavalier result = B_BAD_VALUE;
1935ae6f34bSAugustin Cavalier }
1945ae6f34bSAugustin Cavalier
1955ae6f34bSAugustin Cavalier return result;
1965ae6f34bSAugustin Cavalier }
1975ae6f34bSAugustin Cavalier
1985ae6f34bSAugustin Cavalier case POKE_PORT_INDEXED_READ:
1995ae6f34bSAugustin Cavalier {
2008d13e725SAugustin Cavalier port_io_args ioctl;
2018d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(port_io_args)) != B_OK)
2028d13e725SAugustin Cavalier return B_BAD_ADDRESS;
2038d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE)
2045ae6f34bSAugustin Cavalier return B_BAD_VALUE;
2055ae6f34bSAugustin Cavalier
2068d13e725SAugustin Cavalier isa->write_io_8(ioctl.port, ioctl.size);
2078d13e725SAugustin Cavalier ioctl.value = isa->read_io_8(ioctl.port + 1);
2088d13e725SAugustin Cavalier
2098d13e725SAugustin Cavalier if (user_memcpy(arg, &ioctl, sizeof(port_io_args)) != B_OK)
2108d13e725SAugustin Cavalier return B_BAD_ADDRESS;
2115ae6f34bSAugustin Cavalier return B_OK;
2125ae6f34bSAugustin Cavalier }
2135ae6f34bSAugustin Cavalier
2145ae6f34bSAugustin Cavalier case POKE_PORT_INDEXED_WRITE:
2155ae6f34bSAugustin Cavalier {
2168d13e725SAugustin Cavalier port_io_args ioctl;
2178d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(port_io_args)) != B_OK)
2188d13e725SAugustin Cavalier return B_BAD_ADDRESS;
2198d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE)
2205ae6f34bSAugustin Cavalier return B_BAD_VALUE;
2215ae6f34bSAugustin Cavalier
2228d13e725SAugustin Cavalier isa->write_io_8(ioctl.port, ioctl.size);
2238d13e725SAugustin Cavalier isa->write_io_8(ioctl.port + 1, ioctl.value);
2245ae6f34bSAugustin Cavalier return B_OK;
2255ae6f34bSAugustin Cavalier }
2265ae6f34bSAugustin Cavalier
2275ae6f34bSAugustin Cavalier case POKE_PCI_READ_CONFIG:
2285ae6f34bSAugustin Cavalier {
2298d13e725SAugustin Cavalier pci_io_args ioctl;
2308d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(pci_io_args)) != B_OK)
2318d13e725SAugustin Cavalier return B_BAD_ADDRESS;
2328d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE)
2335ae6f34bSAugustin Cavalier return B_BAD_VALUE;
2345ae6f34bSAugustin Cavalier
2358d13e725SAugustin Cavalier ioctl.value = pci->read_pci_config(ioctl.bus, ioctl.device,
2368d13e725SAugustin Cavalier ioctl.function, ioctl.offset, ioctl.size);
2378d13e725SAugustin Cavalier if (user_memcpy(arg, &ioctl, sizeof(pci_io_args)) != B_OK)
2388d13e725SAugustin Cavalier return B_BAD_ADDRESS;
2395ae6f34bSAugustin Cavalier return B_OK;
2405ae6f34bSAugustin Cavalier }
2415ae6f34bSAugustin Cavalier
2425ae6f34bSAugustin Cavalier case POKE_PCI_WRITE_CONFIG:
2435ae6f34bSAugustin Cavalier {
2448d13e725SAugustin Cavalier pci_io_args ioctl;
2458d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(pci_io_args)) != B_OK)
2468d13e725SAugustin Cavalier return B_BAD_ADDRESS;
2478d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE)
2485ae6f34bSAugustin Cavalier return B_BAD_VALUE;
2495ae6f34bSAugustin Cavalier
2508d13e725SAugustin Cavalier pci->write_pci_config(ioctl.bus, ioctl.device, ioctl.function,
2518d13e725SAugustin Cavalier ioctl.offset, ioctl.size, ioctl.value);
2525ae6f34bSAugustin Cavalier return B_OK;
2535ae6f34bSAugustin Cavalier }
2545ae6f34bSAugustin Cavalier
2555ae6f34bSAugustin Cavalier case POKE_GET_NTH_PCI_INFO:
2565ae6f34bSAugustin Cavalier {
2578d13e725SAugustin Cavalier pci_info_args ioctl;
2588d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(pci_info_args)) != B_OK)
2598d13e725SAugustin Cavalier return B_BAD_ADDRESS;
2608d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE)
2615ae6f34bSAugustin Cavalier return B_BAD_VALUE;
2625ae6f34bSAugustin Cavalier
2638d13e725SAugustin Cavalier pci_info info;
2648d13e725SAugustin Cavalier ioctl.status = pci->get_nth_pci_info(ioctl.index, &info);
2658d13e725SAugustin Cavalier
2668d13e725SAugustin Cavalier if (user_memcpy(ioctl.info, &info, sizeof(pci_info)) != B_OK)
2678d13e725SAugustin Cavalier return B_BAD_ADDRESS;
2688d13e725SAugustin Cavalier if (user_memcpy(arg, &ioctl, sizeof(pci_info_args)) != B_OK)
2698d13e725SAugustin Cavalier return B_BAD_ADDRESS;
2705ae6f34bSAugustin Cavalier return B_OK;
2715ae6f34bSAugustin Cavalier }
2725ae6f34bSAugustin Cavalier
2735ae6f34bSAugustin Cavalier case POKE_GET_PHYSICAL_ADDRESS:
2745ae6f34bSAugustin Cavalier {
2758d13e725SAugustin Cavalier mem_map_args ioctl;
2768d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(mem_map_args)) != B_OK)
2778d13e725SAugustin Cavalier return B_BAD_ADDRESS;
2785ae6f34bSAugustin Cavalier physical_entry table;
2795ae6f34bSAugustin Cavalier status_t result;
2805ae6f34bSAugustin Cavalier
2818d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE)
2825ae6f34bSAugustin Cavalier return B_BAD_VALUE;
2835ae6f34bSAugustin Cavalier
2848d13e725SAugustin Cavalier result = get_memory_map(ioctl.address, ioctl.size, &table, 1);
28559b54f38SOscar Lesta ioctl.physical_address = table.address;
2868d13e725SAugustin Cavalier ioctl.size = table.size;
2878d13e725SAugustin Cavalier if (user_memcpy(arg, &ioctl, sizeof(mem_map_args)) != B_OK)
2888d13e725SAugustin Cavalier return B_BAD_ADDRESS;
2895ae6f34bSAugustin Cavalier return result;
2905ae6f34bSAugustin Cavalier }
2915ae6f34bSAugustin Cavalier
2925ae6f34bSAugustin Cavalier case POKE_MAP_MEMORY:
2935ae6f34bSAugustin Cavalier {
2948d13e725SAugustin Cavalier mem_map_args ioctl;
2958d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(mem_map_args)) != B_OK)
2968d13e725SAugustin Cavalier return B_BAD_ADDRESS;
2978d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE)
2985ae6f34bSAugustin Cavalier return B_BAD_VALUE;
2995ae6f34bSAugustin Cavalier
3008d13e725SAugustin Cavalier char name[B_OS_NAME_LENGTH];
301f866c782SX512 if (user_strlcpy(name, ioctl.name, B_OS_NAME_LENGTH) < B_OK)
3028d13e725SAugustin Cavalier return B_BAD_ADDRESS;
3038d13e725SAugustin Cavalier
304*0bb43cbfSX512 ioctl.area = vm_map_physical_memory(team_get_current_team_id(), name,
305*0bb43cbfSX512 (void**)&ioctl.address, ioctl.flags, ioctl.size, ioctl.protection,
306*0bb43cbfSX512 ioctl.physical_address, false);
3078d13e725SAugustin Cavalier
3088d13e725SAugustin Cavalier if (user_memcpy(arg, &ioctl, sizeof(mem_map_args)) != B_OK)
3098d13e725SAugustin Cavalier return B_BAD_ADDRESS;
3108d13e725SAugustin Cavalier return ioctl.area;
3115ae6f34bSAugustin Cavalier }
3125ae6f34bSAugustin Cavalier
3135ae6f34bSAugustin Cavalier case POKE_UNMAP_MEMORY:
3145ae6f34bSAugustin Cavalier {
3158d13e725SAugustin Cavalier mem_map_args ioctl;
3168d13e725SAugustin Cavalier if (user_memcpy(&ioctl, arg, sizeof(mem_map_args)) != B_OK)
3178d13e725SAugustin Cavalier return B_BAD_ADDRESS;
3188d13e725SAugustin Cavalier if (ioctl.signature != POKE_SIGNATURE)
3195ae6f34bSAugustin Cavalier return B_BAD_VALUE;
3205ae6f34bSAugustin Cavalier
321*0bb43cbfSX512 return _user_delete_area(ioctl.area);
3225ae6f34bSAugustin Cavalier }
3235ae6f34bSAugustin Cavalier }
3245ae6f34bSAugustin Cavalier
3255ae6f34bSAugustin Cavalier return B_BAD_VALUE;
3265ae6f34bSAugustin Cavalier }
3275ae6f34bSAugustin Cavalier
3285ae6f34bSAugustin Cavalier
3295ae6f34bSAugustin Cavalier status_t
poke_read(void * cookie,off_t position,void * buffer,size_t * numBytes)3305ae6f34bSAugustin Cavalier poke_read(void* cookie, off_t position, void* buffer, size_t* numBytes)
3315ae6f34bSAugustin Cavalier {
3325ae6f34bSAugustin Cavalier *numBytes = 0;
3335ae6f34bSAugustin Cavalier return B_NOT_ALLOWED;
3345ae6f34bSAugustin Cavalier }
3355ae6f34bSAugustin Cavalier
3365ae6f34bSAugustin Cavalier
3375ae6f34bSAugustin Cavalier status_t
poke_write(void * cookie,off_t position,const void * buffer,size_t * numBytes)3385ae6f34bSAugustin Cavalier poke_write(void* cookie, off_t position, const void* buffer, size_t* numBytes)
3395ae6f34bSAugustin Cavalier {
3405ae6f34bSAugustin Cavalier *numBytes = 0;
3415ae6f34bSAugustin Cavalier return B_NOT_ALLOWED;
3425ae6f34bSAugustin Cavalier }
343