zakhar_azg

Untitled

Nov 27th, 2024
38
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 37.03 KB | None | 0 0
  1. use alloc::vec::Vec;
  2. use core::{arch::asm, ops::Deref, str};
  3.  
  4. use x86_64::registers::model_specific::{Efer, EferFlags, LStar, SFMask, Star};
  5.  
  6. use ku::{
  7. allocator::BigAllocator, log::{self, event, level_into_symbol, Level}, memory::mmu::PageTable, process::{ExitCode, MiniContext, RFlags, ResultCode, State, Syscall}, sync::spinlock::SpinlockGuard
  8. };
  9.  
  10. use crate::{
  11. allocator::MemoryAllocator,
  12. error::{
  13. Error::{InvalidArgument, NoPage, Overflow, PermissionDenied, WrongAlignment},
  14. Result,
  15. },
  16. gdt::Gdt,
  17. log::{debug, error, info, trace, warn},
  18. memory::{
  19. self,
  20. mmu::{PageTableEntry, PageTableFlags},
  21. Block,
  22. Page,
  23. Virt,
  24. FRAME_ALLOCATOR,
  25. KERNEL_RW,
  26. USER,
  27. USER_READ,
  28. },
  29. smp::{Cpu, KERNEL_RSP_OFFSET_IN_CPU},
  30. };
  31.  
  32. use super::{process::TrapContext, Pid, Process, Scheduler, Table};
  33.  
  34. use lock_set::{lock_dst, lock_src_dst};
  35.  
  36. // Used in docs.
  37. #[allow(unused)]
  38. use crate::error::Error;
  39.  
  40.  
  41. /// Инициализация системных вызовов.
  42. /// Подготавливает процессор к выполнению инструкций
  43. /// [syscall](https://www.felixcloutier.com/x86/syscall) и
  44. /// [sysret](https://www.felixcloutier.com/x86/sysret).
  45. pub(crate) fn init() {
  46. let syscall_virt = Virt::from_ptr(syscall_trampoline as *const ());
  47.  
  48. let mut efer = Efer::read();
  49. efer.insert(EferFlags::SYSTEM_CALL_EXTENSIONS);
  50. unsafe { Efer::write(efer) };
  51.  
  52. Star::write(
  53. Gdt::user_code(),
  54. Gdt::user_data(),
  55. Gdt::kernel_code(),
  56. Gdt::kernel_data()
  57. ).unwrap();
  58.  
  59. LStar::write(Virt::from_ptr(syscall_trampoline as *const ()).into());
  60.  
  61. SFMask::write(RFlags::ALL.into());
  62. }
  63.  
  64.  
  65. /// Получает управление при выполнении инструкции
  66. /// [syscall](https://www.felixcloutier.com/x86/syscall).
  67. ///
  68. /// Переключает стек на стек ядра, разрешает прерывания и
  69. /// передаёт управление в функцию [`syscall()`].
  70. #[naked]
  71. extern "C" fn syscall_trampoline() -> ! {
  72. unsafe {
  73. asm!(
  74. "
  75. mov rbx, rsp
  76.  
  77. mov rsp, gs:[{kernel_rsp_offset}]
  78.  
  79. sti
  80.  
  81. push rbx
  82. push rcx
  83. push rax
  84. mov rcx, r10
  85.  
  86. call {syscall}
  87. ",
  88.  
  89. syscall = sym syscall,
  90. kernel_rsp_offset = const KERNEL_RSP_OFFSET_IN_CPU,
  91. options(noreturn),
  92. );
  93. }
  94. }
  95.  
  96.  
  97. // ANCHOR: syscall
  98. /// Выполняет диспетчеризацию системных вызовов по аргументу `number` --- номеру системного вызова.
  99. ///
  100. /// Передаёт в функции, реализующие конкретные системные вызовы,
  101. /// нужную часть аргументов `arg0`--`arg4`.
  102. /// После выполнения функции конкретного системного вызова,
  103. /// с помощью функции [`sysret()`] возвращает управление в контекст пользователя,
  104. /// задаваемый `rip` и `rsp`.
  105. extern "C" fn syscall(
  106. // https://wiki.osdev.org/System_V_ABI#x86-64:
  107. // Parameters to functions are passed in the registers
  108. // rdi, rsi, rdx, rcx, r8, r9,
  109. // and further values are passed on the stack in reverse order.
  110. arg0: usize, // rdi
  111. arg1: usize, // rsi
  112. arg2: usize, // rdx
  113. arg3: usize, // rcx
  114. arg4: usize, // r8
  115. _arg5: usize, // r9
  116. // Stack, push in reverse order.
  117. number: usize,
  118. rip: Virt,
  119. rsp: Virt,
  120. ) -> ! {
  121. // ANCHOR_END: syscall
  122. assert!(
  123. RFlags::read().contains(RFlags::INTERRUPT_FLAG),
  124. "enable the interrupts during the system calls",
  125. );
  126.  
  127. let context = MiniContext::new(rip, rsp);
  128. let process = Table::get(Cpu::current_process().unwrap()).unwrap();
  129.  
  130. let syscall_number = Syscall::try_from(number);
  131.  
  132. if syscall_number.is_ok() {
  133. match syscall_number {
  134. Ok(Syscall::Exit) => {
  135. exit(process, arg0);
  136. },
  137. Ok(Syscall::LogValue) => {
  138. let log_result = log_value(process, arg0, arg1, arg2, arg3);
  139. if log_result.is_err() {
  140. sysret(context, log_result);
  141. }
  142.  
  143. sysret(context, Ok(0));
  144. },
  145. Ok(Syscall::SchedYield) => {
  146. sched_yield(process, context);
  147. },
  148. Ok(Syscall::Unmap) => {
  149. let sysval = unmap(process, arg0, arg1, arg2);
  150. sysret(context, sysval)
  151. },
  152. Ok(Syscall::Map) => {
  153. let sysval = map(process, arg0, arg1, arg2, arg3);
  154. sysret(context, sysval)
  155. },
  156. Ok(Syscall::CopyMapping) => {
  157. let sysval = copy_mapping(process, arg0, arg1, arg2, arg3, arg4);
  158. sysret(context, sysval);
  159. },
  160. _ => {}
  161. }
  162. }
  163.  
  164. sysret(context, Err(Error::InvalidArgument));
  165. }
  166.  
  167.  
  168. // ANCHOR: sysret
  169. /// С помощью инструкции [sysret](https://www.felixcloutier.com/x86/sysret)
  170. /// возвращает управление в контекст пользователя `context`.
  171. ///
  172. /// Передаёт пользователю результат системного вызова в виде кода успеха или ошибки и
  173. /// полезной нагрузки из `result`.
  174. fn sysret(context: MiniContext, result: Result<usize>) -> ! {
  175. // ANCHOR_END: sysret
  176. trace!(%context, ?result, "sysret");
  177.  
  178. let rflags = RFlags::default();
  179. let rdi = match result.clone() {
  180. Ok(value) => value,
  181. Err(_) => 0,
  182. };
  183.  
  184. unsafe {
  185. asm!(
  186. "
  187. mov rsp, r8
  188.  
  189. xor r8, r8
  190. xor r9, r9
  191. xor r10, r10
  192. xor r12, r12
  193. xor r13, r13
  194. xor r14, r14
  195. xor r15, r15
  196.  
  197. xor rbp, rbp
  198. xor rbx, rbx
  199. xor rdx, rdx
  200. xor rsi, rsi
  201.  
  202. sysretq
  203. ",
  204.  
  205. in("r11") rflags.into_usize(),
  206. in("rax") usize::from(ResultCode::from(result.clone())),
  207. in("rdi") rdi,
  208. in("rcx") context.rip().into_usize(),
  209. in("r8") context.rsp().into_usize(),
  210.  
  211. options(noreturn)
  212. );
  213. }
  214. }
  215.  
  216.  
  217. // ANCHOR: exit
  218. /// Выполняет системный вызов
  219. /// [`lib::syscall::exit(code)`](https://sergey-v-galtsev.gitlab.io/labs-description/doc/lib/syscall/fn.exit.html).
  220. ///
  221. /// Освобождает слот таблицы процессов и возвращается в контекст ядра,
  222. /// из которого пользовательский процесс был запущен.
  223. fn exit(process: SpinlockGuard<Process>, code: usize) -> ! {
  224. // ANCHOR_END: exit
  225. log::info!("Exit with code: {}", code);
  226. Table::free(process.pid()).unwrap();
  227. Process::sched_yield();
  228. }
  229.  
  230.  
  231. // ANCHOR: log_value
  232. /// Выполняет системный вызов
  233. /// [`lib::syscall::log_value(message, value)`](https://sergey-v-galtsev.gitlab.io/labs-description/doc/lib/syscall/fn.log_value.html).
  234. ///
  235. /// Логирует строку `message` типа `&str`, заданную началом `start` и длиной `len`,
  236. /// а также число `value`.
  237. #[allow(unused_mut)] // TODO: remove before flight.
  238. fn log_value(
  239. mut process: SpinlockGuard<Process>,
  240. level: usize,
  241. start: usize,
  242. len: usize,
  243. value: usize,
  244. ) -> Result<usize> {
  245. let end = start.checked_add(len).ok_or(Overflow)?;
  246.  
  247. let block = Block::<Virt>::from_index(start, end)?;
  248. let buf = process.address_space().check_permission::<u8>(block, PageTableFlags::USER_ACCESSIBLE)?;
  249. let msg = str::from_utf8(buf).map_err(|_|InvalidArgument)?;
  250.  
  251. log::info!(
  252. "{}; value = {}; hex_value = 0x{:X}; pid = {}",
  253. msg, value, value, process.pid()
  254. );
  255.  
  256. return Ok(0);
  257. }
  258.  
  259.  
  260. /// Выполняет системный вызов
  261. /// [`lib::syscall::sched_yield()`](https://sergey-v-galtsev.gitlab.io/labs-description/doc/lib/syscall/fn.sched_yield.html).
  262. ///
  263. /// Перепланирует процесс в конец очереди готовых к исполнению процессов и
  264. /// забирает у него CPU функцией [`Process::sched_yield()`],
  265. /// которая вернёт управление в другой контекст ядра ---
  266. /// в контекст из которого была вызвана функция [`Process::enter_user_mode()`].
  267. /// Текущий контекст исходного процесса --- `context` --- записывает в него,
  268. /// чтобы в дальнейшем в него можно было вернуться через [`Process::enter_user_mode()`].
  269. #[allow(unused_mut)] // TODO: remove before flight.
  270. fn sched_yield(mut process: SpinlockGuard<Process>, context: MiniContext) -> ! {
  271. process.set_context(context);
  272.  
  273. let current_pid = process.pid();
  274.  
  275. Scheduler::enqueue(current_pid);
  276.  
  277. drop(process);
  278.  
  279. Process::sched_yield();
  280. }
  281.  
  282.  
  283. // ANCHOR: exofork
  284. /// Выполняет системный вызов
  285. /// [`lib::syscall::exofork()`](https://sergey-v-galtsev.gitlab.io/labs-description/doc/lib/syscall/fn.exofork.html).
  286. ///
  287. /// Создаёт копию вызывающего процесса `process` и возвращает исходному процессу [`Pid`] копии.
  288. /// Внутри копии возвращает [`Pid::Current`].
  289. /// При этом новый процесс создаётся практически без адресного пространства и не готовый к работе.
  290. /// Поэтому он, в частности, не ставится в очередь планировщика.
  291. /// Текущий контекст исходного процесса --- `context` --- записывает в копию, чтобы в копии
  292. /// вернуться туда же, куда происходит возврат из системного вызова для вызывающего процесса.
  293. #[allow(unused_mut)] // TODO: remove before flight.
  294. fn exofork(mut process: SpinlockGuard<Process>, context: MiniContext) -> Result<usize> {
  295. // ANCHOR_END: exofork
  296. // TODO: your code here.
  297. unimplemented!();
  298. }
  299.  
  300.  
  301. // ANCHOR: map
  302. /// Выполняет системный вызов
  303. /// [`lib::syscall::map(dst_pid, dst_block, flags)`](https://sergey-v-galtsev.gitlab.io/labs-description/doc/lib/syscall/fn.map.html).
  304. ///
  305. /// Отображает в памяти процесса, заданного `dst_pid`, блок страниц размера `dst_size` байт
  306. /// начиная с виртуального адреса `dst_address` с флагами доступа `flags`.
  307. /// Если `dst_address` равен нулю,
  308. /// сам выбирает свободный участок адресного пространства размера `dst_size`.
  309. fn map(
  310. mut process: SpinlockGuard<Process>,
  311. dst_pid: usize,
  312. dst_address: usize,
  313. dst_size: usize,
  314. flags: usize,
  315. ) -> Result<usize> {
  316. // ANCHOR_END: map
  317. //debug!(?dst_address);
  318. if dst_size == 0 {
  319. return Err(InvalidArgument);
  320. }
  321. let dst_block = if dst_address != 0 {
  322. check_block(dst_address, dst_size)?
  323. } else {
  324. if dst_size % Page::SIZE != 0 {
  325. return Err(WrongAlignment);
  326. }
  327. process.address_space().allocate(dst_size, PageTableFlags::USER_ACCESSIBLE)?
  328. };
  329. //debug!(?dst_block);
  330. let flags_option = check_page_flags(flags)?;
  331. if flags_option.is_none() {
  332. return Err(InvalidArgument);
  333. }
  334. let dst_set = lock_dst(process, dst_pid)?;
  335. let mut dst_process = match dst_set {
  336. lock_set::LockSet::Dst { dst } => dst,
  337. lock_set::LockSet::Same { src_dst } => src_dst,
  338. lock_set::LockSet::Different { dst, .. } => dst,
  339. };
  340.  
  341. let address_space = dst_process.address_space();
  342. unsafe {
  343. address_space.map_block(dst_block, flags_option.unwrap())?;
  344. }
  345.  
  346. drop(dst_process);
  347.  
  348. Ok(dst_block.start_address().into_usize())
  349. }
  350.  
  351.  
  352. // ANCHOR: unmap
  353. /// Выполняет системный вызов
  354. /// [`lib::syscall::unmap(dst_pid, dst_block)`](https://sergey-v-galtsev.gitlab.io/labs-description/doc/lib/syscall/fn.unmap.html).
  355. ///
  356. /// Удаляет из виртуальной памяти целевого процесса `dst_pid` блок страниц
  357. /// размера `dst_size` байт начиная с виртуального адреса `dst_address`.
  358. fn unmap(
  359. process: SpinlockGuard<Process>,
  360. dst_pid: usize,
  361. dst_address: usize,
  362. dst_size: usize,
  363. ) -> Result<usize> {
  364. // ANCHOR_END: unmap
  365. let dst_block = check_block(dst_address, dst_size)?;
  366. let dst_set = lock_dst(process, dst_pid)?;
  367. let mut dst_process = match dst_set {
  368. lock_set::LockSet::Dst { dst } => dst,
  369. lock_set::LockSet::Same { src_dst } => src_dst,
  370. lock_set::LockSet::Different { dst, .. } => dst,
  371. };
  372.  
  373. let address_space = dst_process.address_space();
  374. unsafe {
  375. address_space.unmap_block(dst_block)?;
  376. }
  377.  
  378. Ok(dst_address)
  379. }
  380.  
  381.  
  382. // ANCHOR: copy_mapping
  383. /// Выполняет системный вызов
  384. /// [`lib::syscall::copy_mapping(dst_pid, src_block, dst_block, flags)`](https://sergey-v-galtsev.gitlab.io/labs-description/doc/lib/syscall/fn.copy_mapping.html).
  385. ///
  386. /// Создаёт копию отображения виртуальной памяти из вызывающего процесса `process`
  387. /// в процесс, заданный `dst_pid`.
  388. /// Исходный диапазон начинается с виртуального адреса `src_address`,
  389. /// целевой --- с виртуального адреса `dst_address`.
  390. /// Размер диапазона --- `dst_size` байт.
  391. ///
  392. /// В целевом процессе диапазон должен быть отображён с флагами:
  393. /// - `flags`, если `flags != 0`.
  394. /// - такими же, как в исходном диапазоне, если `flags == 0`.
  395. ///
  396. /// Не допускает целевое отображение с более широким набором флагов, чем исходное.
  397. /// После выполнения у процессов появляется область
  398. /// [разделяемой памяти](https://en.wikipedia.org/wiki/Shared_memory).
  399. fn copy_mapping(
  400. mut process: SpinlockGuard<Process>,
  401. dst_pid: usize,
  402. src_address: usize,
  403. dst_address: usize,
  404. dst_size: usize,
  405. flags: usize,
  406. ) -> Result<usize> {
  407. let pte_flags = PageTableFlags::from_bits(flags).ok_or(InvalidArgument)?;
  408.  
  409. let mut src_block = check_block(src_address, dst_size)?;
  410. let mut dst_block = check_block(dst_address, dst_size)?;
  411.  
  412. if src_block.count() != dst_block.count() {
  413. return Err(InvalidArgument);
  414. }
  415.  
  416. let flags_option = check_page_flags(flags)?;
  417.  
  418. for page in src_block {
  419. check_frame(&mut process, page, pte_flags)?;
  420. }
  421.  
  422. let dst_set = lock_src_dst(process, dst_pid)?;
  423. match dst_set {
  424. lock_set::LockSet::Same { mut src_dst } => {
  425. let mut allocator = src_dst.address_space().allocator(pte_flags);
  426. let intersection = src_block.intersection(dst_block);
  427. if intersection.is_empty() {
  428. unsafe {
  429. allocator.copy_mapping(src_block, dst_block, flags_option)?;
  430. }
  431. return Ok(dst_size);
  432. }
  433. if intersection == src_block {
  434. unsafe {
  435. allocator.copy_mapping(src_block, dst_block, flags_option)?;
  436. }
  437. return Ok(dst_size);
  438. }
  439. assert!(intersection.count() < src_block.count());
  440. let tail_count = src_block.count() - intersection.count();
  441. if src_address < dst_address {
  442. let src_tail = src_block.tail(tail_count).unwrap();
  443. let dst_tail = dst_block.tail(tail_count).unwrap();
  444. unsafe {
  445. allocator.copy_mapping(src_tail, dst_tail, flags_option)?;
  446. }
  447. } else {
  448. src_block.tail(intersection.count());
  449. dst_block.tail(intersection.count());
  450. unsafe {
  451. allocator.copy_mapping(src_block, dst_block, flags_option)?;
  452. }
  453. }
  454. return Ok(dst_size);
  455. },
  456. lock_set::LockSet::Different { mut dst, mut src } => {
  457. let dst_address_space = dst.address_space();
  458. let dst_beg = dst_block.start_address();
  459. let dst_end = dst_block.end_address().unwrap();
  460. let addr_block = Block::new(dst_beg, dst_end)?;
  461. if dst_address_space
  462. .check_permission::<u8>(addr_block, PageTableFlags::USER_ACCESSIBLE)
  463. .is_ok()
  464. {
  465. return Err(PermissionDenied);
  466. }
  467.  
  468. for (src_page, dst_page) in src_block.into_iter().zip(dst_block) {
  469. let src_pte = check_frame(&mut src, src_page, pte_flags).unwrap();
  470. unsafe {
  471. dst_address_space.map_page_to_frame(
  472. dst_page,
  473. src_pte.frame().unwrap(),
  474. flags_option.unwrap_or(src_pte.flags()),
  475. )?;
  476. }
  477. }
  478.  
  479. return Ok(dst_size);
  480. },
  481. _ => panic!("Unexpected lock set"),
  482. };
  483. }
  484.  
  485. /// Проверяет, что заданный блок виртуальных страниц `block` отображён в
  486. /// адресное пространство процесса `process` с корректно заданными флагами `flags`.
  487. /// Возвращает вектор физических фреймов, в которые отображены эти страницы.
  488. /// См. также [`check_frame()`].
  489. fn check_frames<'a>(
  490. process: &'a SpinlockGuard<Process>,
  491. block: Block<Page>,
  492. flags: PageTableFlags,
  493. ) -> Result<Vec<PageTableEntry, MemoryAllocator<'a>>> {
  494. unimplemented!();
  495. // let mut retval = Vec::new_in(process.allocator(PageTableFlags::all()));
  496. // for page in block {
  497. // retval.push(check_frame(process, page, flags)?);
  498. // }
  499.  
  500. // return Ok(retval);
  501. }
  502.  
  503.  
  504. /// Выполняет отображение `src_ptes` в `dst_pages`
  505. /// в адресное пространство процесса `process`.
  506. ///
  507. /// В целевом процессе диапазон должен быть отображён с флагами:
  508. /// - `flags`, если `flags` --- [`Some`].
  509. /// - такими же, как в исходном диапазоне, если `flags` --- [`None`].
  510. ///
  511. /// Количества элементов в `src_ptes` и `dst_pages` должны совпадать.
  512. fn map_pages_to_frames(
  513. process: &SpinlockGuard<Process>,
  514. src_ptes: Vec<PageTableEntry, MemoryAllocator>,
  515. dst_pages: Block<Page>,
  516. flags: Option<PageTableFlags>,
  517. ) -> Result<()> {
  518. assert!(src_ptes.len() == dst_pages.count());
  519.  
  520. let mut address_space = process.lock_address_space();
  521. for (pte, dst_page) in src_ptes.into_iter().zip(dst_pages.into_iter()) {
  522. let effective_flags = match flags {
  523. Some(f) => {
  524. if !pte.flags().contains(f) {
  525. return Err(PermissionDenied);
  526. }
  527. f
  528. },
  529. None => pte.flags(),
  530. };
  531. unsafe {
  532. address_space.map_page_to_frame(dst_page, pte.frame()?, effective_flags)?;
  533. }
  534. }
  535. return Ok(());
  536. }
  537.  
  538.  
  539. // ANCHOR: set_state
  540. /// Выполняет системный вызов
  541. /// [`lib::syscall::set_state(dst_pid, state)`](https://sergey-v-galtsev.gitlab.io/labs-description/doc/lib/syscall/fn.set_state.html).
  542. ///
  543. /// Переводит целевой процесс, заданный идентификатором `dst_pid`, в заданное состояние `state`.
  544. /// Ставит его в очередь планировщика в случае [`State::Runnable`].
  545. fn set_state(process: SpinlockGuard<Process>, dst_pid: usize, state: usize) -> Result<usize> {
  546. // ANCHOR_END: set_state
  547. // TODO: your code here.
  548. unimplemented!();
  549. }
  550.  
  551.  
  552. // ANCHOR: set_trap_handler
  553. /// Выполняет системный вызов
  554. /// [`lib::syscall::set_trap_handler(dst_pid, trap_handler, trap_stack)`](https://sergey-v-galtsev.gitlab.io/labs-description/doc/lib/syscall/fn.set_trap_handler.html).
  555. ///
  556. /// Устанавливает для целевого процесса, заданного идентификатором `dst_pid`,
  557. /// пользовательский обработчик прерывания с виртуальным адресом `rip` и стеком,
  558. /// который задаётся блоком виртуальных адресов начиная с `stack_address` и размера `stack_size`.
  559. /// Стек может быть не выровнен по границе страниц.
  560. fn set_trap_handler(
  561. process: SpinlockGuard<Process>,
  562. dst_pid: usize,
  563. rip: usize,
  564. stack_address: usize,
  565. stack_size: usize,
  566. ) -> Result<usize> {
  567. // ANCHOR_END: set_trap_handler
  568. // TODO: your code here.
  569. unimplemented!();
  570. }
  571.  
  572.  
  573. /// Проверяет, что `address` и `size` задают корректно выровненный диапазон страниц,
  574. /// целиком лежащий внутри одной из
  575. /// [двух непрерывных половин](https://en.wikipedia.org/wiki/X86-64#Virtual_address_space_details)
  576. /// адресного пространства.
  577. /// Возвращает блок соответствующих виртуальных страниц.
  578. fn check_block(address: usize, size: usize) -> Result<Block<Page>> {
  579. let start = Virt::new(address)?;
  580. let end = Virt::new(address.checked_add(size).ok_or(Overflow)?)?;
  581. if start.is_lower_half() != end.is_lower_half() {
  582. return Err(InvalidArgument);
  583. }
  584.  
  585. let addr_block = Block::new(start, end)?;
  586. let page_block = addr_block.enclosing();
  587. if page_block.start_address() != addr_block.start_address() ||
  588. page_block.end_address() != addr_block.end_address()
  589. {
  590. return Err(WrongAlignment);
  591. }
  592.  
  593. if !memory::is_user_block(page_block) {
  594. return Err(PermissionDenied);
  595. }
  596.  
  597. Ok(page_block)
  598. }
  599.  
  600.  
  601. /// Проверяет, что заданная виртуальная страница `page` отображена в
  602. /// адресное пространство процесса `process` с заданными флагами `flags`.
  603. /// Флаги [`PageTableFlags::COPY_ON_WRITE`] и [`PageTableFlags::WRITABLE`]
  604. /// при проверке считаются эквивалентными,
  605. /// а флаг [`PageTableFlags::USER_ACCESSIBLE`] --- обязательно включённым.
  606. /// Возвращает копию [`PageTableEntry`], с физическим фреймом,
  607. /// в который она отображена, и флагами исходного отображения.
  608. ///
  609. /// Возвращает ошибки:
  610. /// - [`Error::NoPage`] если страница `page` не отображена.
  611. /// - [`Error::PermissionDenied`] если страница отображена,
  612. /// но не со всеми запрошенными флагами.
  613. fn check_frame(
  614. process: &mut SpinlockGuard<Process>,
  615. page: Page,
  616. flags: PageTableFlags,
  617. ) -> Result<PageTableEntry> {
  618. let address_space = process.address_space();
  619. let path = address_space.mapping().path(page.address());
  620. let pte = path.get().map_err(|_| NoPage)?;
  621. if !pte.present() {
  622. return Err(NoPage);
  623. }
  624. if !pte.flags().contains(PageTableFlags::USER_ACCESSIBLE) {
  625. return Err(PermissionDenied);
  626. }
  627. if !pte.flags().contains(flags) {
  628. return Err(PermissionDenied);
  629. }
  630.  
  631. Ok(*pte)
  632. }
  633.  
  634.  
  635.  
  636. /// Проверяет, что `flags` задаёт валидный набор флагов отображения страниц пользователя.
  637. ///
  638. /// Возвращает:
  639. /// - [`None`], если `flags == 0`.
  640. /// - Входные `flags` в виде [`PageTableFlags`], если `flags != 0`.
  641. ///
  642. /// Возвращает ошибки:
  643. /// - [`Error::InvalidArgument`], если во `flags` установлен бит,
  644. /// не соответствующий никакому флагу [`PageTableFlags`].
  645. /// - [`Error::PermissionDenied`], если `flags != 0` и
  646. /// в них не включён [`PageTableFlags::USER_ACCESSIBLE`].
  647. fn check_page_flags(flags: usize) -> Result<Option<PageTableFlags>> {
  648. if flags == 0 {
  649. return Ok(None);
  650. }
  651. let result = PageTableFlags::from_bits(flags);
  652. if result.is_none() {
  653. return Err(InvalidArgument);
  654. }
  655. if !result.unwrap().contains(PageTableFlags::USER_ACCESSIBLE) {
  656. return Err(PermissionDenied);
  657. }
  658.  
  659. Ok(result)
  660. }
  661.  
  662.  
  663. /// Работа с блокировкой одного процесса или парой блокировок двух разных процессов.
  664. mod lock_set {
  665. use duplicate::duplicate_item;
  666.  
  667. use ku::{
  668. error::{
  669. Error::{NoProcess, PermissionDenied},
  670. Result,
  671. },
  672. process::Pid,
  673. sync::spinlock::SpinlockGuard,
  674. };
  675. use tracing::debug;
  676.  
  677. use super::super::{Process, Table};
  678.  
  679.  
  680. /// Проверяет, что процесс `src` имеет право модифицировать целевой процесс,
  681. /// заданный своим идентификатором `dst_pid`.
  682. /// Целевой процесс может совпадать с `src`.
  683. ///
  684. /// Модифицировать можно:
  685. /// - Либо самого себя, задавая [`Pid::Current`] или явно собственный идентификатор [`Pid::Id`].
  686. /// - Либо свой непосредственно дочерний процесс, задавая его идентификатор.
  687. ///
  688. /// Возвращает блокировку на процесс `dst`.
  689. pub(super) fn lock_dst(src: SpinlockGuard<Process>, dst_pid: usize) -> Result<LockSet> {
  690. LockSet::new(src, dst_pid, ProcessSet::Dst)
  691. }
  692.  
  693.  
  694. /// Проверяет, что процесс `src` имеет право модифицировать целевой процесс,
  695. /// заданный своим идентификатором `dst_pid`.
  696. /// Целевой процесс может совпадать с `src`.
  697. ///
  698. /// Модифицировать можно:
  699. /// - Либо самого себя, задавая [`Pid::Current`] или явно собственный идентификатор [`Pid::Id`].
  700. /// - Либо свой непосредственно дочерний процесс, задавая его идентификатор.
  701. ///
  702. /// Возвращает:
  703. /// - Исходную блокировку на `src`, если `dst_pid` задаёт тот же процесс.
  704. /// - Блокировки на процессы `src` и `dst`, если это разные процессы.
  705. ///
  706. /// Захватывает блокировки в правильном порядке для избежания
  707. /// [взаимоблокировки](https://en.wikipedia.org/wiki/Deadlock).
  708. pub(super) fn lock_src_dst(src: SpinlockGuard<Process>, dst_pid: usize) -> Result<LockSet> {
  709. LockSet::new(src, dst_pid, ProcessSet::SrcDst)
  710. }
  711.  
  712.  
  713. #[derive(Debug)]
  714. /// Блокировка одного процесса или пара блокировок двух разных процессов.
  715. pub(super) enum LockSet<'a> {
  716. /// Пара блокировок двух разных процессов.
  717. Different {
  718. /// Процесс, над которым совершается действие системного вызова.
  719. dst: SpinlockGuard<'a, Process>,
  720.  
  721. /// Процесс, запустивший системный вызов.
  722. src: SpinlockGuard<'a, Process>,
  723. },
  724.  
  725. /// Блокировка только процесса, над которым совершается действие системного вызова.
  726. /// Используется когда не нужна блокировка на процесс, запустивший системный вызов.
  727. Dst {
  728. /// Процесс, над которым совершается действие системного вызова.
  729. dst: SpinlockGuard<'a, Process>,
  730. },
  731.  
  732. /// Блокировка одного процесса, который и запустил системный вызов
  733. /// и одновременно является целевым процессом для этого системного вызова.
  734. Same {
  735. /// Процесс, запустивший системный вызов на себя же.
  736. src_dst: SpinlockGuard<'a, Process>,
  737. },
  738. }
  739.  
  740.  
  741. impl<'a> LockSet<'a> {
  742. // ANCHOR: lock_set
  743. /// Проверяет, что процесс `src` имеет право модифицировать целевой процесс,
  744. /// заданный своим идентификатором `dst_pid`.
  745. /// Целевой процесс может совпадать с `src`.
  746. ///
  747. /// Модифицировать можно:
  748. /// - Либо самого себя, задавая [`Pid::Current`] или явно собственный идентификатор [`Pid::Id`].
  749. /// - Либо свой непосредственно дочерний процесс, задавая его идентификатор.
  750. ///
  751. /// Возвращает:
  752. /// - Исходную блокировку на `src`, если `dst_pid` задаёт тот же процесс.
  753. /// - Блокировку на процесс `dst`, если `process_set == ProcessSet::Dst`.
  754. /// - Блокировки на процессы `src` и `dst`, если это разные процессы.
  755. ///
  756. /// Захватывает блокировки в правильном порядке для избежания
  757. /// [взаимоблокировки](https://en.wikipedia.org/wiki/Deadlock).
  758. fn new(
  759. src: SpinlockGuard<Process>,
  760. dst_pid: usize,
  761. process_set: ProcessSet,
  762. ) -> Result<LockSet<'_>> {
  763. let dst = Pid::from_usize(dst_pid)?;
  764.  
  765. match process_set {
  766. ProcessSet::Dst => {
  767. if src.pid().into_usize() == dst_pid {
  768. return Ok(LockSet::Dst { dst: src });
  769. }
  770.  
  771. if dst == Pid::Current {
  772. return Ok(LockSet::Dst { dst: src });
  773. }
  774.  
  775. let dst_process = Table::get(dst)?;
  776. if dst_process.parent() != Some(src.pid()) && dst != src.pid() && dst != Pid::Current {
  777. return Err(PermissionDenied);
  778. }
  779.  
  780. return Ok(LockSet::Dst { dst: dst_process });
  781. },
  782. ProcessSet::SrcDst => {
  783. if src.pid().into_usize() == dst_pid {
  784. return Ok(LockSet::Same { src_dst: src });
  785. }
  786.  
  787. if dst == Pid::Current {
  788. return Ok(LockSet::Same { src_dst: src });
  789. }
  790.  
  791. let dst_process = Table::get(dst)?;
  792. if dst_process.parent() != Some(src.pid()) && dst != src.pid() && dst != Pid::Current {
  793. return Err(PermissionDenied);
  794. }
  795. return Ok(LockSet::Different { dst: dst_process, src: src });
  796.  
  797. },
  798. }
  799. }
  800.  
  801.  
  802. /// Возвращает процесс, над которым совершается действие системного вызова.
  803. #[allow(clippy::needless_arbitrary_self_type)]
  804. #[duplicate_item(
  805. dst_accessor reference(type);
  806. [dst] [&'b type];
  807. [dst_mut] [&'b mut type];
  808. )]
  809. pub(super) fn dst_accessor<'b>(
  810. self: reference([Self]),
  811. ) -> reference([SpinlockGuard<'a, Process>]) {
  812. match self {
  813. LockSet::Same { src_dst } => src_dst,
  814. LockSet::Different { dst, .. } => dst,
  815. LockSet::Dst { dst } => dst,
  816. }
  817. }
  818.  
  819.  
  820. /// Возвращает процесс, запустивший системный вызов.
  821. ///
  822. /// # Panics
  823. ///
  824. /// Паникует, если изначально блокировка захватывалась только на целевой процесс.
  825. #[allow(clippy::needless_arbitrary_self_type)]
  826. #[allow(dead_code)]
  827. #[duplicate_item(
  828. src_accessor reference(type);
  829. [src] [&'b type];
  830. [src_mut] [&'b mut type];
  831. )]
  832. pub(super) fn src_accessor<'b>(
  833. self: reference([Self]),
  834. ) -> reference([SpinlockGuard<'a, Process>]) {
  835. match self {
  836. LockSet::Same { src_dst } => src_dst,
  837. LockSet::Different { src, .. } => src,
  838. LockSet::Dst { .. } => panic!("only destination process is locked"),
  839. }
  840. }
  841.  
  842.  
  843. /// Возвращает `true`, если `src` и `dst` --- это один и тот же процесс.
  844. ///
  845. /// # Panics
  846. ///
  847. /// Паникует, если изначально блокировка захватывалась только на целевой процесс.
  848. #[allow(dead_code)]
  849. pub(super) fn is_same(&self) -> bool {
  850. match self {
  851. LockSet::Same { .. } => true,
  852. LockSet::Different { .. } => false,
  853. LockSet::Dst { .. } => panic!("only destination process is locked"),
  854. }
  855. }
  856. }
  857.  
  858.  
  859. #[derive(Clone, Copy, Debug, PartialEq, Eq)]
  860. /// Указывает какой набор процессов блокировать.
  861. enum ProcessSet {
  862. /// Блокировать только процесс, над которым совершается действие системного вызова.
  863. Dst,
  864.  
  865. /// Блокировать оба процесса ---
  866. /// и процесс, запустивший системный вызов,
  867. /// и процесс, над которым совершается действие системного вызова.
  868. SrcDst,
  869. }
  870. }
  871.  
  872.  
  873. #[doc(hidden)]
  874. pub mod test_scaffolding {
  875. use ku::{process::MiniContext, sync::spinlock::SpinlockGuard};
  876.  
  877. use crate::error::Result;
  878.  
  879. use super::super::Process;
  880.  
  881.  
  882. pub fn log_value(
  883. process: SpinlockGuard<Process>,
  884. level: usize,
  885. start: usize,
  886. len: usize,
  887. value: usize,
  888. ) -> Result<usize> {
  889. super::log_value(process, level, start, len, value)
  890. }
  891.  
  892.  
  893. pub fn exofork(process: SpinlockGuard<Process>) -> Result<usize> {
  894. super::exofork(process, MiniContext::default())
  895. }
  896.  
  897.  
  898. pub fn map(
  899. process: SpinlockGuard<Process>,
  900. dst_pid: usize,
  901. dst_address: usize,
  902. dst_size: usize,
  903. flags: usize,
  904. ) -> Result<usize> {
  905. super::map(process, dst_pid, dst_address, dst_size, flags)
  906. }
  907.  
  908.  
  909. pub fn unmap(
  910. process: SpinlockGuard<Process>,
  911. dst_pid: usize,
  912. dst_address: usize,
  913. dst_size: usize,
  914. ) -> Result<usize> {
  915. super::unmap(process, dst_pid, dst_address, dst_size)
  916. }
  917.  
  918.  
  919. pub fn copy_mapping(
  920. process: SpinlockGuard<Process>,
  921. dst_pid: usize,
  922. src_address: usize,
  923. dst_address: usize,
  924. dst_size: usize,
  925. flags: usize,
  926. ) -> Result<usize> {
  927. super::copy_mapping(process, dst_pid, src_address, dst_address, dst_size, flags)
  928. }
  929.  
  930.  
  931. pub fn set_state(
  932. process: SpinlockGuard<Process>,
  933. dst_pid: usize,
  934. state: usize,
  935. ) -> Result<usize> {
  936. super::set_state(process, dst_pid, state)
  937. }
  938. }
  939.  
Advertisement
Add Comment
Please, Sign In to add comment