2021-01-29 14:03:25 +02:00
/*
* Copyright ( c ) 2021 , Liav A . < liavalb @ hotmail . co . il >
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2021-01-29 14:03:25 +02:00
*/
# include <AK/Memory.h>
# include <AK/StdLibExtras.h>
2021-09-11 09:19:20 +03:00
# include <Kernel/Devices/DeviceManagement.h>
2021-07-11 12:02:15 -07:00
# include <Kernel/Devices/MemoryDevice.h>
2021-09-11 10:39:47 +03:00
# include <Kernel/Firmware/BIOS.h>
2021-08-06 10:45:34 +02:00
# include <Kernel/Memory/AnonymousVMObject.h>
2021-12-23 21:49:31 +02:00
# include <Kernel/Memory/TypedMapping.h>
2021-06-22 17:40:16 +02:00
# include <Kernel/Sections.h>
2021-01-29 14:03:25 +02:00
namespace Kernel {
2021-06-18 11:37:26 +03:00
UNMAP_AFTER_INIT NonnullRefPtr < MemoryDevice > MemoryDevice : : must_create ( )
{
2021-09-11 09:19:20 +03:00
auto memory_device_or_error = DeviceManagement : : try_create_device < MemoryDevice > ( ) ;
2021-09-10 14:44:46 +03:00
// FIXME: Find a way to propagate errors
VERIFY ( ! memory_device_or_error . is_error ( ) ) ;
return memory_device_or_error . release_value ( ) ;
2021-06-18 11:37:26 +03:00
}
2021-02-19 21:29:46 +01:00
UNMAP_AFTER_INIT MemoryDevice : : MemoryDevice ( )
2021-01-29 14:03:25 +02:00
: CharacterDevice ( 1 , 1 )
{
}
2022-03-16 13:15:15 -06:00
UNMAP_AFTER_INIT MemoryDevice : : ~ MemoryDevice ( ) = default ;
2021-01-29 14:03:25 +02:00
2021-12-23 21:49:31 +02:00
ErrorOr < size_t > MemoryDevice : : read ( OpenFileDescription & , u64 offset , UserOrKernelBuffer & buffer , size_t length )
2021-01-29 14:03:25 +02:00
{
2021-12-23 21:49:31 +02:00
if ( ! MM . is_allowed_to_read_physical_memory_for_userspace ( PhysicalAddress ( offset ) , length ) ) {
dbgln ( " MemoryDevice: Trying to read physical memory at {} for range of {} bytes failed due to violation of access " , PhysicalAddress ( offset ) , length ) ;
return EINVAL ;
}
2022-01-13 18:20:22 +02:00
auto mapping = TRY ( Memory : : map_typed < u8 > ( PhysicalAddress ( offset ) , length ) ) ;
2021-12-23 21:49:31 +02:00
auto bytes = ReadonlyBytes { mapping . ptr ( ) , length } ;
TRY ( buffer . write ( bytes ) ) ;
return length ;
2021-01-29 14:03:25 +02:00
}
2021-11-08 00:51:39 +01:00
ErrorOr < Memory : : Region * > MemoryDevice : : mmap ( Process & process , OpenFileDescription & , Memory : : VirtualRange const & range , u64 offset , int prot , bool shared )
2021-01-29 14:03:25 +02:00
{
auto viewed_address = PhysicalAddress ( offset ) ;
2021-12-23 22:09:19 +02:00
// Note: This check happens to guard against possible memory leak.
// For example, if we try to mmap physical memory from 0x1000 to 0x2000 and you
// can actually mmap only from 0x1001, then we would fail as usual.
// However, in such case if we mmap from 0x1002, we are technically not violating
// any rules, besides the fact that we mapped an entire page with two bytes which we
// were not supposed to see. To prevent that, if we use mmap(2) syscall, we should
// always consider the start page to be aligned on PAGE_SIZE, or to be more precise
// is to be set to the page base of that start address.
VERIFY ( viewed_address = = viewed_address . page_base ( ) ) ;
2021-12-23 21:49:31 +02:00
if ( ! MM . is_allowed_to_read_physical_memory_for_userspace ( viewed_address , range . size ( ) ) ) {
2022-04-01 19:52:22 +03:00
dbgln_if ( MEMORY_DEVICE_DEBUG , " MemoryDevice: Trying to mmap physical memory at {} for range of {} bytes failed due to violation of access " , viewed_address , range . size ( ) ) ;
2021-01-29 14:03:25 +02:00
return EINVAL ;
}
2021-09-06 20:33:45 +02:00
auto vmobject = TRY ( Memory : : AnonymousVMObject : : try_create_for_physical_range ( viewed_address , range . size ( ) ) ) ;
2021-08-15 09:07:59 +00:00
2021-08-06 13:59:22 +02:00
return process . address_space ( ) . allocate_region_with_vmobject (
2021-01-29 14:03:25 +02:00
range ,
2021-09-06 20:33:45 +02:00
move ( vmobject ) ,
2021-01-29 14:03:25 +02:00
0 ,
" Mapped Physical Memory " ,
prot ,
shared ) ;
}
}