From 85d4cfdeb77fc113dfa996479b788761a22d29f5 Mon Sep 17 00:00:00 2001 From: Zhang Junyang Date: Sun, 24 Dec 2023 21:47:16 +0800 Subject: [PATCH] Do mapping in the wrapper --- Cargo.lock | 52 +++-- Cargo.toml | 1 - framework/aster-frame/build.rs | 61 ------ .../aster-frame/src/arch/x86/boot/boot.S | 35 ++-- .../src/arch/x86/boot/linux_boot/mod.rs | 4 +- .../src/arch/x86/boot/multiboot/mod.rs | 4 +- .../src/arch/x86/boot/multiboot2/mod.rs | 4 +- .../libs/boot-wrapper/wrapper/src/loader.rs | 4 +- .../wrapper/src/x86/amd64_efi/efi.rs | 69 +++++- .../libs/boot-wrapper/wrapper/src/x86/mod.rs | 1 + .../boot-wrapper/wrapper/src/x86/paging.rs | 198 ++++++++++++++++++ rust-toolchain.toml | 2 +- 12 files changed, 322 insertions(+), 113 deletions(-) delete mode 100644 framework/aster-frame/build.rs create mode 100644 framework/libs/boot-wrapper/wrapper/src/x86/paging.rs diff --git a/Cargo.lock b/Cargo.lock index 114ece2e..e601ae63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -129,6 +129,31 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "aster-boot-wrapper" +version = "0.1.0" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "linux_boot_params", + "log", + "uart_16550", + "uefi", + "uefi-services", + "x86_64", + "xmas-elf 0.8.0", +] + +[[package]] +name = "aster-boot-wrapper-builder" +version = "0.1.0" +dependencies = [ + "bitflags 1.3.2", + "bytemuck", + "serde", + "xmas-elf 0.9.1", +] + [[package]] name = "aster-console" version = "0.1.0" @@ -159,6 +184,7 @@ dependencies = [ "intrusive-collections", "ktest", "lazy_static", + "linux_boot_params", "log", "multiboot2", "pod", @@ -173,14 +199,6 @@ dependencies = [ "x86_64", ] -[[package]] -name = "aster-frame-x86-boot-linux-setup" -version = "0.1.0" -dependencies = [ - "uart_16550", - "xmas-elf", -] - [[package]] name = "aster-framebuffer" version = "0.1.0" @@ -250,10 +268,10 @@ name = "aster-runner" version = "0.1.0" dependencies = [ "anyhow", + "aster-boot-wrapper-builder", "clap", - "glob", "rand", - "xmas-elf", + "xmas-elf 0.8.0", ] [[package]] @@ -299,7 +317,7 @@ dependencies = [ "typeflags-util", "virtio-input-decoder", "vte", - "xmas-elf", + "xmas-elf 0.8.0", ] [[package]] @@ -353,7 +371,7 @@ dependencies = [ [[package]] name = "asterinas" -version = "0.2.2" +version = "0.2.3" dependencies = [ "aster-frame", "aster-framebuffer", @@ -956,16 +974,6 @@ dependencies = [ "rle-decode-fast", ] -[[package]] -name = "linux-boot-wrapper-builder" -version = "0.1.0" -dependencies = [ - "bitflags 1.3.2", - "bytemuck", - "serde", - "xmas-elf 0.9.1", -] - [[package]] name = "linux_boot_params" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 03a433b9..fb4286d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,6 @@ panic = "unwind" members = [ "runner", "framework/aster-frame", - "framework/aster-frame/src/arch/x86/boot/linux_boot/setup", "framework/libs/align_ext", "framework/libs/boot-wrapper/builder", "framework/libs/boot-wrapper/linux-boot-params", diff --git a/framework/aster-frame/build.rs b/framework/aster-frame/build.rs deleted file mode 100644 index 6bd57bc3..00000000 --- a/framework/aster-frame/build.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::{ - error::Error, - io::Write, - path::{Path, PathBuf}, -}; - -fn main() -> Result<(), Box> { - let source_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); - let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); - build_linux_setup_header(&source_dir, &out_dir)?; - Ok(()) -} - -fn build_linux_setup_header( - source_dir: &Path, - out_dir: &Path, -) -> Result<(), Box> { - // Build the setup header to ELF. - let setup_crate_dir = source_dir - .join("src") - .join("arch") - .join("x86") - .join("boot") - .join("linux_boot") - .join("setup"); - let target_json = setup_crate_dir.join("x86_64-i386_protected_mode.json"); - - println!( - "cargo:rerun-if-changed={}", - setup_crate_dir.to_str().unwrap() - ); - - let cargo = std::env::var("CARGO").unwrap(); - let mut cmd = std::process::Command::new(cargo); - cmd.arg("install").arg("aster-frame-x86-boot-linux-setup"); - cmd.arg("--debug"); - cmd.arg("--locked"); - cmd.arg("--path").arg(setup_crate_dir.to_str().unwrap()); - cmd.arg("--target").arg(target_json.as_os_str()); - cmd.arg("-Zbuild-std=core,compiler_builtins"); - cmd.arg("-Zbuild-std-features=compiler-builtins-mem"); - // Specify the installation root. - cmd.arg("--root").arg(out_dir.as_os_str()); - // Specify the build target directory to avoid cargo running - // into a deadlock reading the workspace files. - cmd.arg("--target-dir").arg(out_dir.as_os_str()); - cmd.env_remove("RUSTFLAGS"); - cmd.env_remove("CARGO_ENCODED_RUSTFLAGS"); - let output = cmd.output()?; - if !output.status.success() { - std::io::stdout().write_all(&output.stdout).unwrap(); - std::io::stderr().write_all(&output.stderr).unwrap(); - return Err(format!( - "Failed to build linux x86 setup header:\n\tcommand `{:?}`\n\treturned {}", - cmd, output.status - ) - .into()); - } - - Ok(()) -} diff --git a/framework/aster-frame/src/arch/x86/boot/boot.S b/framework/aster-frame/src/arch/x86/boot/boot.S index 6507924f..4150e70b 100644 --- a/framework/aster-frame/src/arch/x86/boot/boot.S +++ b/framework/aster-frame/src/arch/x86/boot/boot.S @@ -4,12 +4,13 @@ .section ".boot", "awx" .code32 -// With the 32-bit entry types we should go through a common paging and machine -// state setup routine. Thus we make a mark of protocol used in each entrypoint +// With every entry types we could go through common paging or machine +// state setup routines. Thus we make a mark of protocol used in each entrypoint // on the stack. ENTRYTYPE_MULTIBOOT = 1 ENTRYTYPE_MULTIBOOT2 = 2 ENTRYTYPE_LINUX_32 = 3 +ENTRYTYPE_LINUX_64 = 4 MULTIBOOT_ENTRY_MAGIC = 0x2BADB002 MULTIBOOT2_ENTRY_MAGIC = 0x36D76289 @@ -39,14 +40,13 @@ __linux32_boot: .org 0x200 .global __linux64_boot_tag __linux64_boot_tag: - // We switch back to 32-bit mode to call the 32-bit entry point. - lgdt [boot_gdtr] - mov eax, 0xb002b002 // magic for boot_params - mov ebx, esi // struct boot_params * - sub rsp, 8 - mov dword ptr [rsp], offset __linux32_boot - mov dword ptr [rsp + 4], 24 - retf + // Set the kernel call stack. + lea rsp, [boot_stack_top] + push rsi // boot_params ptr from the loader + push ENTRYTYPE_LINUX_64 + + // Here RSP/RIP are still using low address. + jmp long_mode_in_low_address // The multiboot & multiboot2 entry point. .code32 @@ -274,6 +274,7 @@ gdt_end: // The page tables and the stack .align 4096 +.global boot_page_table_start boot_page_table_start: boot_pml4: .skip 4096 @@ -296,6 +297,7 @@ boot_pt_32g: .skip 4096 * 512 boot_page_table_end: +.global boot_stack_top boot_stack_bottom: .skip 0x40000 boot_stack_top: @@ -335,21 +337,22 @@ long_mode: cmp rax, ENTRYTYPE_MULTIBOOT2 je entry_type_multiboot2 cmp rax, ENTRYTYPE_LINUX_32 - je entry_type_linux_32 + je entry_type_linux + cmp rax, ENTRYTYPE_LINUX_64 + je entry_type_linux // Unreachable! jmp halt -.extern __linux64_boot +.extern __linux_boot .extern __multiboot_entry .extern __multiboot2_entry -entry_type_linux_32: +entry_type_linux: pop rdi // boot_params ptr - // Clear the frame pointer to stop backtracing here. xor rbp, rbp - lea rax, [rip + __linux64_boot] // jump into Rust code + lea rax, [rip + __linux_boot] // jump into Rust code call rax jmp halt @@ -357,7 +360,6 @@ entry_type_multiboot: pop rsi // the address of multiboot info pop rdi // multiboot magic - // Clear the frame pointer to stop backtracing here. xor rbp, rbp lea rax, [rip + __multiboot_entry] // jump into Rust code @@ -368,7 +370,6 @@ entry_type_multiboot2: pop rsi // the address of multiboot info pop rdi // multiboot magic - // Clear the frame pointer to stop backtracing here. xor rbp, rbp lea rax, [rip + __multiboot2_entry] // jump into Rust code diff --git a/framework/aster-frame/src/arch/x86/boot/linux_boot/mod.rs b/framework/aster-frame/src/arch/x86/boot/linux_boot/mod.rs index 58d57779..62159c1e 100644 --- a/framework/aster-frame/src/arch/x86/boot/linux_boot/mod.rs +++ b/framework/aster-frame/src/arch/x86/boot/linux_boot/mod.rs @@ -138,9 +138,9 @@ fn init_memory_regions(memory_regions: &'static Once>) { memory_regions.call_once(|| non_overlapping_regions_from(regions.as_ref())); } -/// The entry point of Rust code called by the Linux 64-bit boot compatible bootloader. +/// The entry point of of the Rust code portion of Asterinas. #[no_mangle] -unsafe extern "sysv64" fn __linux64_boot(params_ptr: *const BootParams) -> ! { +unsafe extern "sysv64" fn __linux_boot(params_ptr: *const BootParams) -> ! { let params = *params_ptr; assert_eq!({ params.hdr.header }, LINUX_BOOT_HEADER_MAGIC); BOOT_PARAMS.call_once(|| params); diff --git a/framework/aster-frame/src/arch/x86/boot/multiboot/mod.rs b/framework/aster-frame/src/arch/x86/boot/multiboot/mod.rs index fb6652d6..3a27a515 100644 --- a/framework/aster-frame/src/arch/x86/boot/multiboot/mod.rs +++ b/framework/aster-frame/src/arch/x86/boot/multiboot/mod.rs @@ -5,9 +5,7 @@ use spin::Once; use crate::{ boot::{ kcmdline::KCmdlineArg, - memory_region::{ - non_overlapping_regions_from, MemoryRegion, MemoryRegionType, - }, + memory_region::{non_overlapping_regions_from, MemoryRegion, MemoryRegionType}, BootloaderAcpiArg, BootloaderFramebufferArg, }, config::PHYS_OFFSET, diff --git a/framework/aster-frame/src/arch/x86/boot/multiboot2/mod.rs b/framework/aster-frame/src/arch/x86/boot/multiboot2/mod.rs index 685b12b1..ff8f9b19 100644 --- a/framework/aster-frame/src/arch/x86/boot/multiboot2/mod.rs +++ b/framework/aster-frame/src/arch/x86/boot/multiboot2/mod.rs @@ -6,9 +6,7 @@ use multiboot2::{BootInformation, BootInformationHeader, MemoryAreaType}; use crate::boot::{ kcmdline::KCmdlineArg, - memory_region::{ - non_overlapping_regions_from, MemoryRegion, MemoryRegionType, - }, + memory_region::{non_overlapping_regions_from, MemoryRegion, MemoryRegionType}, BootloaderAcpiArg, BootloaderFramebufferArg, }; use spin::Once; diff --git a/framework/libs/boot-wrapper/wrapper/src/loader.rs b/framework/libs/boot-wrapper/wrapper/src/loader.rs index fde67445..167a2ec1 100644 --- a/framework/libs/boot-wrapper/wrapper/src/loader.rs +++ b/framework/libs/boot-wrapper/wrapper/src/loader.rs @@ -18,7 +18,9 @@ pub fn load_elf(file: &[u8]) { for ph in elf.program_iter() { let ProgramHeader::Ph64(program) = ph else { - panic!("[setup] Unexpected program header type! Asterinas should be 64-bit ELF binary."); + panic!( + "[setup] Unexpected program header type! Asterinas should be 64-bit ELF binary." + ); }; if program.get_type().unwrap() == xmas_elf::program::Type::Load { load_segment(&elf, program); diff --git a/framework/libs/boot-wrapper/wrapper/src/x86/amd64_efi/efi.rs b/framework/libs/boot-wrapper/wrapper/src/x86/amd64_efi/efi.rs index 91364d5c..21eafb82 100644 --- a/framework/libs/boot-wrapper/wrapper/src/x86/amd64_efi/efi.rs +++ b/framework/libs/boot-wrapper/wrapper/src/x86/amd64_efi/efi.rs @@ -6,6 +6,8 @@ use uefi::{ use linux_boot_params::BootParams; +use crate::x86::paging::{Ia32eFlags, PageNumber, PageTableCreator}; + #[export_name = "efi_stub_entry"] extern "sysv64" fn efi_stub_entry(handle: Handle, mut system_table: SystemTable) -> ! { unsafe { @@ -100,7 +102,12 @@ fn efi_phase_runtime( let e820_table = &mut boot_params.e820_table; let mut e820_entries = 0usize; for md in memory_map.entries() { - if e820_entries >= e820_table.len() || e820_entries >= 128 { + if e820_entries >= e820_table.len() || e820_entries >= 127 { + unsafe { + crate::console::print_str( + "[EFI stub] Warning: number of E820 entries exceeded 128!\n", + ); + } break; } e820_table[e820_entries] = linux_boot_params::BootE820Entry { @@ -120,6 +127,64 @@ fn efi_phase_runtime( } boot_params.e820_entries = e820_entries as u8; + unsafe { + crate::console::print_str("[EFI stub] Setting up the page table.\n"); + } + + // Make a new linear page table. The linear page table will be stored at + // 0x4000000, hoping that the firmware will not use this area. + let mut creator = unsafe { + PageTableCreator::new( + PageNumber::from_addr(0x4000000), + PageNumber::from_addr(0x8000000), + ) + }; + // Map the following regions: + // - 0x0: identity map the first 4GiB; + // - 0xffff8000_00000000: linear map 4GiB to low 4 GiB; + // - 0xffffffff_80000000: linear map 2GiB to low 2 GiB; + // - 0xffff8008_00000000: linear map 1GiB to 0x00000008_00000000. + let flags = Ia32eFlags::PRESENT | Ia32eFlags::WRITABLE; + for i in 0..4 * 1024 * 1024 * 1024 / 4096 { + let from_vpn = PageNumber::from_addr(i * 4096); + let from_vpn2 = PageNumber::from_addr(i * 4096 + 0xffff8000_00000000); + let to_low_pfn = PageNumber::from_addr(i * 4096); + creator.map(from_vpn, to_low_pfn, flags); + creator.map(from_vpn2, to_low_pfn, flags); + } + for i in 0..2 * 1024 * 1024 * 1024 / 4096 { + let from_vpn = PageNumber::from_addr(i * 4096 + 0xffffffff_80000000); + let to_low_pfn = PageNumber::from_addr(i * 4096); + creator.map(from_vpn, to_low_pfn, flags); + } + for i in 0..1024 * 1024 * 1024 / 4096 { + let from_vpn = PageNumber::from_addr(i * 4096 + 0xffff8008_00000000); + let to_pfn = PageNumber::from_addr(i * 4096 + 0x00000008_00000000); + creator.map(from_vpn, to_pfn, flags); + } + // Mark this as reserved in e820 table. + e820_table[e820_entries] = linux_boot_params::BootE820Entry { + addr: 0x4000000, + size: creator.nr_frames_used() as u64 * 4096, + typ: linux_boot_params::E820Type::Reserved, + }; + e820_entries += 1; + boot_params.e820_entries = e820_entries as u8; + + #[cfg(feature = "debug_print")] + unsafe { + crate::console::print_str("[EFI stub] Activating the new page table.\n"); + } + + unsafe { + creator.activate(x86_64::registers::control::Cr3Flags::PAGE_LEVEL_CACHE_DISABLE); + } + + #[cfg(feature = "debug_print")] + unsafe { + crate::console::print_str("[EFI stub] Page table activated.\n"); + } + unsafe { use crate::console::{print_hex, print_str}; print_str("[EFI stub] Entering Asterinas entrypoint at "); @@ -127,5 +192,5 @@ fn efi_phase_runtime( print_str("\n"); } - unsafe { super::call_aster_entrypoint(super::ASTER_ENTRY_POINT, boot_params_ptr as u64) } + unsafe { super::call_aster_entrypoint(super::ASTER_ENTRY_POINT as u64, boot_params_ptr as u64) } } diff --git a/framework/libs/boot-wrapper/wrapper/src/x86/mod.rs b/framework/libs/boot-wrapper/wrapper/src/x86/mod.rs index 6e66f05f..61f33008 100644 --- a/framework/libs/boot-wrapper/wrapper/src/x86/mod.rs +++ b/framework/libs/boot-wrapper/wrapper/src/x86/mod.rs @@ -8,4 +8,5 @@ cfg_if::cfg_if! { } } +pub mod paging; pub mod relocation; diff --git a/framework/libs/boot-wrapper/wrapper/src/x86/paging.rs b/framework/libs/boot-wrapper/wrapper/src/x86/paging.rs new file mode 100644 index 00000000..b11559c7 --- /dev/null +++ b/framework/libs/boot-wrapper/wrapper/src/x86/paging.rs @@ -0,0 +1,198 @@ +//! This module provides abstraction over the Intel IA32E paging mechanism. And +//! offers method to create linear page tables. +//! +//! Notebly, the 4-level page table has a paging structure named as follows: +//! - Level-4: Page Map Level 4 (PML4), or "the root page table"; +//! - Level-3: Page Directory Pointer Table (PDPT); +//! - Level-2: Page Directory (PD); +//! - Level-1: Page Table (PT). +//! We sometimes use "level-n" page table to refer to the page table described +//! above, avoiding the use of complicated names in the Intel manual. + +use x86_64::structures::paging::PhysFrame; + +const TABLE_ENTRY_COUNT: usize = 512; + +bitflags::bitflags! { + #[derive(Clone, Copy)] + pub struct Ia32eFlags: u64 { + const PRESENT = 1 << 0; + const WRITABLE = 1 << 1; + const USER = 1 << 2; + const WRITE_THROUGH = 1 << 3; + const NO_CACHE = 1 << 4; + const ACCESSED = 1 << 5; + const DIRTY = 1 << 6; + const HUGE = 1 << 7; + const GLOBAL = 1 << 8; + const NO_EXECUTE = 1 << 63; + } +} + +pub struct Ia32eEntry(u64); + +/// The table in the IA32E paging specification that occupies a physical page frame. +pub struct Ia32eTable([Ia32eEntry; TABLE_ENTRY_COUNT]); + +/// A page number. It could be either a physical page number or a virtual page number. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct PageNumber(u64); + +fn is_4k_page_aligned(addr: u64) -> bool { + addr & 0xfff == 0 +} + +impl PageNumber { + /// Creates a new page number from the given address. + pub fn from_addr(addr: u64) -> Self { + assert!(is_4k_page_aligned(addr)); + Self(addr >> 12) + } + /// Returns the address of the page. + pub fn addr(&self) -> u64 { + self.0 << 12 + } + /// Get the physical page frame as slice. + /// + /// # Safety + /// The caller must ensure that the page number is a physical page number and + /// it is identically mapped when running the code. + unsafe fn get_page_frame(&self) -> &'static mut [u8] { + core::slice::from_raw_parts_mut(self.addr() as *mut u8, 4096) + } +} + +impl core::ops::Add for PageNumber { + type Output = Self; + fn add(self, rhs: usize) -> Self::Output { + Self(self.0 + rhs as u64) + } +} + +impl core::ops::AddAssign for PageNumber { + fn add_assign(&mut self, rhs: usize) { + self.0 += rhs as u64; + } +} + +impl core::ops::Sub for PageNumber { + type Output = u64; + fn sub(self, rhs: PageNumber) -> Self::Output { + self.0 - rhs.0 + } +} + +/// A creator for a page table. +/// +/// It allocates page frames from the given physical memory range. And the first +/// page frame is always used for the PML4 table (root page table). +pub struct PageTableCreator { + first_pfn: PageNumber, + next_pfn: PageNumber, + end_pfn: PageNumber, +} + +/// Fills the given slice with the given value. +/// +/// TODO: use `Slice::fill` instead. But it currently will fail with "invalid opcode". +unsafe fn memset(dst: &mut [u8], val: u8) { + core::arch::asm!( + "rep stosb", + inout("rcx") dst.len() => _, + inout("rdi") dst.as_mut_ptr() => _, + in("al") val, + options(nostack), + ); +} + +impl PageTableCreator { + /// Creates a new page table creator. + /// + /// The input physical memory range must be at least 4 page frames. New + /// mappings will be written into the given physical memory range. + /// + /// # Safety + /// The caller must ensure that the given physical memory range is valid. + pub unsafe fn new(first_pfn: PageNumber, end_pfn: PageNumber) -> Self { + assert!(end_pfn - first_pfn >= 4); + // Clear the first page for the PML4 table. + memset(first_pfn.get_page_frame(), 0); + Self { + first_pfn, + next_pfn: first_pfn + 1, + end_pfn, + } + } + + fn allocate(&mut self) -> PageNumber { + assert!(self.next_pfn < self.end_pfn); + let pfn = self.next_pfn; + self.next_pfn += 1; + unsafe { + memset(pfn.get_page_frame(), 0); + } + pfn + } + + pub fn map(&mut self, from: PageNumber, to: PageNumber, flags: Ia32eFlags) { + let pml4 = unsafe { &mut *(self.first_pfn.addr() as *mut Ia32eTable) }; + let pml4e = pml4.index(4, from.addr()); + if !pml4e.flags().contains(Ia32eFlags::PRESENT) { + let pdpt_pfn = self.allocate(); + pml4e.update(pdpt_pfn.addr(), flags); + } + let pdpt = unsafe { &mut *(pml4e.paddr() as *mut Ia32eTable) }; + let pdpte = pdpt.index(3, from.addr()); + if !pdpte.flags().contains(Ia32eFlags::PRESENT) { + let pd_pfn = self.allocate(); + pdpte.update(pd_pfn.addr(), flags); + } + let pd = unsafe { &mut *(pdpte.paddr() as *mut Ia32eTable) }; + let pde = pd.index(2, from.addr()); + if !pde.flags().contains(Ia32eFlags::PRESENT) { + let pt_pfn = self.allocate(); + pde.update(pt_pfn.addr(), flags); + } + let pt = unsafe { &mut *(pde.paddr() as *mut Ia32eTable) }; + let pte = pt.index(1, from.addr()); + pte.update(to.addr(), flags); + } + + pub fn nr_frames_used(&self) -> usize { + (self.next_pfn - self.first_pfn).try_into().unwrap() + } + + /// Activates the created page table. + /// + /// # Safety + /// The caller must ensure that the page table is valid. + pub unsafe fn activate(&self, flags: x86_64::registers::control::Cr3Flags) { + x86_64::registers::control::Cr3::write( + PhysFrame::from_start_address(x86_64::PhysAddr::new(self.first_pfn.addr())).unwrap(), + flags, + ); + } +} + +impl Ia32eTable { + fn index(&mut self, level: usize, va: u64) -> &mut Ia32eEntry { + debug_assert!((1..=5).contains(&level)); + let index = va as usize >> (12 + 9 * (level - 1)) & (TABLE_ENTRY_COUNT - 1); + &mut self.0[index] + } +} + +impl Ia32eEntry { + /// 51:12 + const PHYS_ADDR_MASK: u64 = 0xF_FFFF_FFFF_F000; + + fn paddr(&self) -> u64 { + self.0 & Self::PHYS_ADDR_MASK + } + fn flags(&self) -> Ia32eFlags { + Ia32eFlags::from_bits_truncate(self.0) + } + fn update(&mut self, paddr: u64, flags: Ia32eFlags) { + self.0 = (paddr & Self::PHYS_ADDR_MASK) | flags.bits(); + } +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 8b21d77f..437cf4be 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-12-22" +channel = "nightly-2023-12-01" components = ["rust-src", "rustc-dev", "llvm-tools-preview"]