VM entry (vmlaunch) with invalid control field - linux

I am learning Intel VMX with a Linux based VMM.
I found 'vmlaunch' instruction failed with vm instruction error of 7.
I checked Intel's SDM, it means 'VM entry with invalid control field'.
I double checked the VM_entry_control, VM_exit_control, VM_exec_control, but could NOT find anything wrong.
I am using EPTP for VM execution (VM is in real mode).
Below is the control fields, and VMX capabilities.
Host CPU info is as follows.
Linux kernel is 3.10, and 4.4.0.
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 63
model name : Intel(R) Xeon(R) CPU E5-2620 v3 # 2.40GHz
stepping : 2
microcode : 0x37
cpu MHz : 2391.223
cache size : 15360 KB
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
<pre>
0x0000001F = control_VMX_pin_based
0xA50061F2 = control_VMX_cpu_based
0x00000082 = control_VMX_proc2_based
0x00000000 = control_exception_bitmap
0x00000000 = control_pagefault_errorcode_mask
0xFFFFFFFF = control_pagefault_errorcode_match
0x00000002 = control_CR3_target_count
0x00036FFB = control_VM_exit_controls
0x000011FB = control_VM_entry_controls
0x00000000 = control_VM_entry_interruption_information
0x00000000 = control_VM_entry_exception_errorcode
0x00000000 = control_VM_entry_instruction_length
0x0000000000000020 = control_CR0_mask
0x0000000000002000 = control_CR4_mask
0x0000000000000020 = control_CR0_shadow
0x0000000000002000 = control_CR4_shadow
0x0000000000000000 = control_CR3_target0
0x0000000124FCE000 = control_CR3_target1
0x0000000000000000 = control_CR3_target2
0x0000000000000000 = control_CR3_target3
Host VMX capabilities are as follows,
VMX-Capability Model-Specific Registers
00D8100000000001 = IA32_VMX_BASIC_MSR
0000003F00000016 = IA32_VMX_PINBASED_CTLS_MSR
FFF9FFFE0401E172 = IA32_VMX_PROCBASED_CTLS_MSR
0033FFFF00036DFF = IA32_VMX_EXIT_CTLS_MSR
0000B3FF000011FF = IA32_VMX_ENTRY_CTLS_MSR
00000000000401E0 = IA32_VMX_MISC_MSR
0000000080000021 = IA32_VMX_CR0_FIXED0_MSR
00000000FFFFFFFF = IA32_VMX_CR0_FIXED1_MSR
0000000000002000 = IA32_VMX_CR4_FIXED0_MSR
00000000000427FF = IA32_VMX_CR4_FIXED1_MSR
000000000000005A = IA32_VMX_VMCS_ENUM_MSR
000000EE00000000 = IA32_VMX_PROCBASED_CTLS2
00000F0106114041 = IA32_VMX_EPT_VPID_CAP
0000003F00000016 = IA32_VMX_TRUE_PINBASED_CTLS
FFF9FFFE04006172 = IA32_VMX_TRUE_PROCBASED_CTLS
0033FFFF00036DFB = IA32_VMX_TRUE_EXIT_CTLS
0000B3FF000011FB = IA32_VMX_TRUE_ENTRY_CTLS

I don’t see anything wrong in the fields you provided, but there are more checks on fields you haven’t listed. For example, Use MSR bitmap is 1, but you don’t show the value of the MSR bitmap address.
You should go through all the checks in section 26.2.1.
I suggest also looking at any checks related to unrestricted-guest. It is recommended that you set the controls to save and restore EFER in the exit and entry controls.

By checking the VMCS fields, i found the invalid control came from the EPTP.
In that CPU, it does NOT support 'dirty/access' bit to be 1 in EPTP (bit 6).
After set that bit to 0, there is NO 'invalid control fields' error.

Related

The device tree header verification error was encountered during uboot startup

I have a problem when using orangepi3.
I have an image that can be used under normal circumstances,
but the following problem occasionally occurs.
Once this problem occurs, the image burned in this time can no longer be used, and only the burned image can be reproduced
The following errors are reported during uboot startup.
Hit any key to stop autoboot: 0
no mmc device at slot 0
mmc2(part 0) is current device
2512 bytes read in 5 ms (490.2 KiB/s)
## Executing script at 43100000
U-boot loaded from SD
Boot script loaded from mmc
** Bad device mmc 0 **
** File not found /boot/dtb/sunxi/sun50i-h6-orangepi3.dtb **
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
8247895 bytes read in 404 ms (19.5 MiB/s)
19425352 bytes read in 945 ms (19.6 MiB/s)
but i am sure this file is exists;
Because when this error exists, I enter uboot and print the device tree. It can print correctly, but executing the command boot will still report this error.
And I checked the file system afterwards and found that the file exists in the path
.
I checked the uboot source code and found this error in the function fdt_check_header
int fdt_check_header(const void *fdt)
{
if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
/* Unfinished sequential-write blob */
if (fdt_size_dt_struct(fdt) == 0)
return -FDT_ERR_BADSTATE;
} else {
return -FDT_ERR_BADMAGIC;
}
return 0;
}
But in uboot init_sequence_f exe reserve_fdt also have the verification of the device tree header,and the verification has passed.
but in uboot autoboot_command run_command_list cmd_list an error occurred in the device tree header checked.resulting in failure to enter the kernel correctly.
Before entering FDT_ check_ I added a print function before the header function
Before entering the function fdt_check_header() I add a print like following in reserve_fdt()
static int reserve_fdt(void)
{
/*
* If the device tree is sitting immediate above our image then we
* must relocate it. If it is embedded in the data section, then it
* will be relocated with other data.
*/
if (gd->fdt_blob) {
pr_msg("reserve_fdt fdt_check_headeris %d\n",fdt_magic(gd->fdt_blob));
if(fdt_check_header(gd->fdt_blob) != 0)
{
pr_msg("fdt header check error\n");
return -1;
}
//reserve memory for expand dtb ,because cmd_fdt will update the base dtb
gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);
fdt_set_totalsize((void*)gd->fdt_blob,gd->fdt_size);
gd->start_addr_sp -= gd->fdt_size * 2;
gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);
debug("Reserving %lu Bytes for FDT at: %08lx\n",
gd->fdt_size, gd->start_addr_sp);
}
return 0;
}
And in function fdt_valid() add too;
static int fdt_valid(struct fdt_header **blobp)
{
const void *blob = *blobp;
int err;
if (blob == NULL) {
printf ("The address of the fdt is invalid (NULL).\n");
return 0;
}
printf("fdt_valid fdt_check_header is %d\n",fdt_magic(blob));
err = fdt_check_header(blob);
if (err == 0)
return 1; /* valid */
if (err < 0) {
printf("libfdt fdt_check_header(): %s", fdt_strerror(err));
/*
* Be more informative on bad version.
*/
if (err == -FDT_ERR_BADVERSION) {
if (fdt_version(blob) <
FDT_FIRST_SUPPORTED_VERSION) {
printf (" - too old, fdt %d < %d",
fdt_version(blob),
FDT_FIRST_SUPPORTED_VERSION);
}
if (fdt_last_comp_version(blob) >
FDT_LAST_SUPPORTED_VERSION) {
printf (" - too new, fdt %d > %d",
fdt_version(blob),
FDT_LAST_SUPPORTED_VERSION);
}
}
printf("\n");
*blobp = NULL;
return 0;
}
return 1;
}
Then,when the error occurs,the log is as follows:
U-Boot 2014.07-orangepi (Oct 29 2021 - 09:07:58) Xunlong Software
[1.947]uboot commit : b65841975dcb31f64a2c69344f60db12b98791ae
[1.947]secure enable bit: 0
[1.947]normal mode: with secure monitor
I2C: ready
[1.949]pmbus: ready
[1.949][ARISC] :arisc initialize
[1.975][ARISC] :arisc para ok
[SCP] :sunxi-arisc driver begin startup 2
[SCP] :arisc version: []
[SCP] :sunxi-arisc driver v1.10 is starting
[1.987][ARISC] :sunxi-arisc driver startup succeeded
[1.989]PMU: AXP806
[1.989]PMU: AXP806 found
[1.989]bat_vol=0, ratio=0
[1.989]set pc_bias(1) bias:1800
[1.989]set pg_bias(5) bias:1800
[1.989]set power on vol to default
[1.989]dcdca_vol = 1000, onoff=1
[1.993]aldo2_vol = 3300, onoff=1
[1.998]bldo3_vol = 1800, onoff=1
[2.002]cldo2_vol = 3300, onoff=1
[2.006]cldo3_vol = 3300, onoff=1
[2.010]find power_sply to end
[2.010]cant find pll setting(1320M) from pll table,use default(408M)
[2.012]PMU: cpux 408 Mhz,AXI=204 Mhz
[2.013]PLL6=600 Mhz,AHB1=200 Mhz, APB1=100Mhz MBus=400Mhz
[2.017]DRAM: 1 GiB
[2.019]reserve_fdt fdt_check_headeris -804389139
[2.026]fdt addr: 0x79ccb0e0
[2.026]gd->fdt_size: 0x1a6c0
[2.030]Relocation Offset is: 34e03000
[2.095]gic: sec monitor mode
[2.095]line:180 func:check_ir_boot_recovery start
[2.095]ir boot recovery not used
[2.095][key recovery] no use
[2.096][box standby] read rtc = 0x0
[2.096][box standby] start_type = 0x1
[2.096][box standby] to kernel
[2.096]workmode = 0,storage type = 2
[2.098]MMC: 2
SUNXI SD/MMC: 2
[mmc]: [0-60|61]
[mmc]: [0-51|52]
[mmc]: [7-48|42]
[mmc]: [0-11|12] [26-29|4] [34-50|17]
[mmc]: [0-48|49] [54-56|3] [58-63|6]
[mmc]: [0-26|27] [54-63|10]
[mmc]: [0-58|59]
[mmc]: [6-51|46] [53-58|6]
[mmc]: [1-7|7] [9-56|48]
[mmc]: [1-26|26]
Normal
[6.618]MMC: 2
SUNXI SD/MMC: 2, SUNXI SD/MMC: 2
[6.624]sunxi flash init ok
[6.624]hdmi hdcp not enable!
Using default environment
[6.625]inter uboot shell
Hit any key to stop autoboot: 0
no mmc device at slot 0
mmc2(part 0) is current device
2512 bytes read in 5 ms (490.2 KiB/s)
## Executing script at 43100000
U-boot loaded from SD
Boot script loaded from mmc
** Bad device mmc 0 **
**** File not found /boot/dtb/sunxi/sun50i-h6-orangepi3.dtb **
fdt_valid fdt_check_header is -1271711085
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
fdt_valid fdt_check_header is -1271711085
libfdt fdt_check_header(): FDT_ERR_BADMAGIC**
8247895 bytes read in 404 ms (19.5 MiB/s)
19425352 bytes read in 945 ms (19.6 MiB/s)
## Booting kernel from Legacy Image at 41000000 ...
Image Name:
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 19425288 Bytes = 18.5 MiB
Load Address: 41000000
Entry Point: 41000000
Verifying Checksum ... OK
## Loading init Ramdisk from Legacy Image at 43300000 ...
Image Name: uInitrd
Image Type: ARM Linux RAMDisk Image (gzip compressed)
Data Size: 8247831 Bytes = 7.9 MiB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Loading Kernel Image ... OK
reserving fdt memory region: addr=40020000 size=800
reserving fdt memory region: addr=48000000 size=1000000
reserving fdt memory region: addr=48100000 size=4000
reserving fdt memory region: addr=48104000 size=1000
reserving fdt memory region: addr=48105000 size=1000
reserving fdt memory region: addr=79ccb0e0 size=18f20
Loading Ramdisk to 49822000, end 49fffa17 ... OK
Using Device Tree in place at 44000000, end 4401d6bf
[8.736]disp_ioctl, display not init yet
[8.736]disp_ioctl, display not init yet
Starting kernel ...
INFO: BL3-1: Next image address = 0x41000000
INFO: BL3-1: Next image spsr = 0x3c5
WARNING: Unimplemented Standard Service Call: 0xc0000026
and the number fdt_check_headeris -804389139 id normol;
This why?
Why is the verification still correct in the front, but an error occurs in the back?
Have you ever encountered this problem? Or can you give me some advice? Thanks!
Are the report logs same when each reboot ?
If same, the DTB in hardware storage is fine.
And you should be concerned about memory overwriting between two fdt_magic function calls.
You're on 2014.07 which is missing both support for modern ext4 filesystem images as well as the warning / refusal to mount modern ext4 filesystem images that have features enabled by default that show symptoms such as "file I know exists, I can see it in Linux, are not found". Please upgrade to current U-Boot.

DDR52 mode switching with device tree

I am trying to switch to DDR52 mode using the device tree for eMMC.
I am using arasan,sdhci-5.1 controller and linux kernel 5.2.
I have tried switching to other modes such as HS200(mmc-hs200-1_8v) and HS400(mmc-hs400-1_8v) using device-tree properties and this is working fine. However, there is not much info on how to switch to DDR52 mode in the device tree binding nodes.
Reference:
[1]https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/mmc/arasan%2Csdhci.txt
[2]https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/mmc/mmc.txt
mmc#11000000 {
compatible = "arasan,sdhci-5.1";
status = "okay";
interrupts = <0x0 0x11 0x4>;
reg = <0x0 0x11000000 0x0 0x100>;
clock-names = "clk_xin", "clk_ahb";
clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
phys = <0x7>;
phy-names = "phy_arasan";
assigned-clocks = <&cru SCLK_EMMC>;
clock-output-names = "emmc_cardclock";
supports-cqe;
arasan,soc-ctl-syscon = <&grf>;
};
The eMMC is detected accordingly for HS200 and HS400. But will need info on how to configure to DDR52 in the device-tree.

How do I use pwm-beeper module in Linux Kernel?

I have set my PWM driven beeper up as per the Linux device tree documentation. I see that this results in an extra input device in /sys/class/input:
root:/sys/class/input/input0# ls
capabilities device event0 id modalias name phys power properties subsystem uevent uniq
root:/sys/class/input/input0# cat name
pwm-beeper
However, I don't see anything related to the duty cycle, polarity etc to actually control the beeper. Perhaps I am very mistaken about pwm-beeper as it is clearly created as an input device. Please help!
[update]
Changes in my dts:
pwm15: dmtimer-pwm#15 {
compatible = "ti,omap-dmtimer-pwm";
ti,timers = <&timer15>;
#pwm-cells = <3>;
};
beeper: pwm-beeper {
compatible = "pwm-beeper";
pwms = <&pwm15 0 5000>;
volume-levels = <0 8 20 40 500>;
default-volume-level = <4>;
};
Relevant dmesg:
[ 6.716560] OF: /pwm-beeper: arguments longer than property
[ 6.716566] of_pwm_get(): can't parse "pwms" property
[ 6.716574] pwm-beeper pwm-beeper: Failed to request PWM device:
-22
[ 6.716590] pwm-beeper: probe of pwm-beeper failed with error -22
I am utterly confused because there is just so little info about this device driver mainlined in Linux!
can you post snippet of DT block you have added?
try this block
pwm-beeper {
compatible = "pwm-beeper";
pwms = <&pwm4 0 5000>;
volume-levels = <0 8 20 40 500>;
default-volume-level = <4>;
};
Update 1
TLDR; either reduce you #pwm-cells to 2
Or add one more field i.e. third field to list
like
pwms = <&pwm4 0 5000 1>;
phandle1: node1 {
#list-cells = <2>;
}
phandle2: node2 {
#list-cells = <1>;
}
node3 {
list = <&phandle1 1 2 &phandle2 3>;
}
here notice list has #list-cells differant
phadle1 has 2
phadle2 has 1
so accordingly list has entries.
This will work
whats you linux version ? can you test it on latest stable ?

Linux kernel does not see all components on my at91sam9g20 board

I am working with a Stamp9g20 embedded chip. It is based on the Atmel at91sam9g20 platform. For a client I need to upgrade the kernel to a newer version. After a bit of research, I landed on the Linux4SAM pages and their additional yocto layer, complete with a 4.14 kernel!
However, when I compile that kernel, I don't see all of my devices, for example, I can write onto the NAND memory and mount an USB device, but I cannot see nor mount any mmc/mci devices. I have tried checking how the Stamp9g20 really differs from the AT91SAM9G20EK, but I couldn't find a definitive clue to an answer there.
The Linux4SAM repo supports slightly different versions of the AT91SAM9 family, but I got it working for the 4.14 kernel, using the at91sam9g20ek.dts as an input for the board. Had to add my machine to the compatible machine list, so it will compile for the 9g20 versions as well.
COMPATIBLE_MACHINE += 'at91sam9g20ek'
and my machine.conf looks like:
##Name: ATMEL AT91SAM9G20EK
##DESCRIPTION: Machine configuration for Atmel's evaluation board
#
# define SOC_FAMILY (we are the family of ...)
SOC_FAMILY = "atsam9"
# Add arm926ejs to the DEFAULTTUNE, so it will be selected in our environment
DEFAULTTUNE = "arm926ejs"
# http://lists.openembedded.org/pipermail/openembedded-core/2019-January/277527.html
#TUNE_CCARGS .= "${#bb.utils.contains('TUNE_FEATURES', 'armv5', ' -march=armv5t${ARMPKGSFX_DSP}', '', d)}"
TUNE_CCARGS = "${#bb.utils.contains('TUNE_FEATURES', 'armv5', ' -march=armv5t${ARMPKGSFX_DSP}', '', d)}"
# We rely on the generic meta-atmel layer
require conf/machine/include/at91sam9.inc
MACHINE_FEATURES = "apm ext2 ext3 ext4 usbhost usbgadget vfat jffs2"
# This device tree is available in the kernel
KERNEL_DEVICETREE = " \
at91sam9g20ek.dtb \
"
# Create filesystems tar.gz and jffs2
IMAGE_FSTYPES += " tar.gz jffs2 tar"
# UNTESTED IMAGES (both bootstrap and uboot)
UBOOT_MACHINE ?= "at91sam9g20ek_nandflash_defconfig"
UBOOT_ENTRYPOINT = "0x20008000"
UBOOT_LOADADDRESS = "0x20008000"
AT91BOOTSTRAP_MACHINE ?= "at91sam9g20ek"
When the kernel launches, it shows that it registers a device driver onto the address 0xffff8000, but it doesn't see a block device.
bus: 'mmc': add driver mmcblk
bus: 'sdio': add driver sdio_uart
bus: 'platform': add driver atmel_mci
bus: 'platform': driver_probe_device: matched device fffa8000.mmc with driver atmel_mci
bus: 'platform': really_probe: probing driver atmel_mci with device fffa8000.mmc
atmel_mci fffa8000.mmc: no init pinctrl state
atmel_mci fffa8000.mmc: version: 0x210
atmel_mci fffa8000.mmc: using PDC
device: 'mmc0': device_add
atmel_mci fffa8000.mmc: Atmel MCI controller at 0xfffa8000 irq 30, 1 slots
driver: 'atmel_mci': driver_bound: bound to device 'fffa8000.mmc'
bus: 'platform': really_probe: bound device fffa8000.mmc to driver atmel_mci
I have tried this board with the 2.6.x version where it works as expected.
How can I make the block device mmcblk available in the system? Do I need to change the .dts (currently I am using the at91sam9g20ek.dts as a template with a minor change to the NAND memory). Or what can I do to get more information as to why the kernel doesn't interact with the mmc device?
Also, if I compare the source code from before the dts structure, I don't see significant differences in the mcc part of the code:
https://elixir.bootlin.com/linux/v3.6.9/source/arch/arm/mach-at91/board-sam9g20ek.c
https://elixir.bootlin.com/linux/v3.6.9/source/arch/arm/mach-at91/board-stamp9g20.c
The only difference I found,
at91sam9g20ek board:
.slot_b = 1, /* Only one slot so use slot B */
stamp9g20 board:
.slot_b = 0,
so I tried changing the reg<> property in the dts to 1, but to no avail...
Found it! All I had to do was change the mmc slot (was 1) in the dts to slot 0:
--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
## -39,8 +39,8 ##
};
- mmc0_slot1 {
- pinctrl_board_mmc0_slot1: mmc0_slot1-board {
+ mmc0_slot0 {
+ pinctrl_board_mmc0_slot0: mmc0_slot0-board {
atmel,pins =
<AT91_PIOC 9 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>; /* PC9 gpio CD pin pull up and deglitch */
};
## -90,15 +90,14 ##
mmc0: mmc#fffa8000 {
pinctrl-0 = <
- &pinctrl_board_mmc0_slot1
+ &pinctrl_board_mmc0_slot0
&pinctrl_mmc0_clk
- &pinctrl_mmc0_slot1_cmd_dat0
- &pinctrl_mmc0_slot1_dat1_3>;
+ &pinctrl_mmc0_slot0_cmd_dat0
+ &pinctrl_mmc0_slot0_dat1_3>;
status = "okay";
- slot#1 {
- reg = <1>;
+ slot#0 {
+ reg = <0>;
bus-width = <4>;
- cd-gpios = <&pioC 9 GPIO_ACTIVE_HIGH>;
};
};

can't get the mouse move event from /dev/input/event*

I can't get the mouse move event when using the evtest tools to test the input events .
I just get three mouse events:
left click event: type = EV_KEY, code = 272 (LeftBtn), value=1/0
right click event: type = EV_KEY, code = 273 (RightBtn), value = 1/0
mouse wheel event: type = EV_REL, code = 8 (Wheel), value = -1
No mouse move event. So where my mouse move event and how to capture it?
ps: Tested on Ubuntu 11.04 and Gentoo in VirtualBox-4 with virtualBox-addition installed.
If not on an embedded linux system I prefer to use the input-utils tools rather than evtest (and if I'm on Android I use cat /proc/bus/input/devices and getevent )
Install input-utils via:
$ sudo apt-get install input-utils
List all my input devices
$ sudo lsinput
/dev/input/event0
bustype : BUS_HOST
vendor : 0x0
product : 0x5
version : 0
name : "Lid Switch"
..
..
phys : "isa0060/serio1/input0"
bits ev : EV_SYN EV_KEY EV_ABS
/dev/input/event12
bustype : BUS_I8042
vendor : 0x2
product : 0xa
version : 0
name : "TPPS/2 IBM TrackPoint"
phys : "synaptics-pt/serio0/input0"
bits ev : EV_SYN EV_KEY EV_REL
Then I read events on my laptop's trackpoint (don't forget to move the it around after starting input-events)
$ sudo input-events 12
/dev/input/event12
bustype : BUS_I8042
vendor : 0x2
product : 0xa
version : 0
name : "TPPS/2 IBM TrackPoint"
phys : "synaptics-pt/serio0/input0"
bits ev : EV_SYN EV_KEY EV_REL
waiting for events
16:43:46.516075: EV_REL REL_Y -1
16:43:46.516090: EV_SYN code=0 value=0
16:43:46.539642: EV_REL REL_X -1
16:43:46.539656: EV_REL REL_Y -1
16:43:46.539660: EV_SYN code=0 value=0
16:43:46.704385: EV_REL REL_Y -1
16:43:46.704401: EV_SYN code=0 value=0
Have you tried actually moving the mouse rather than evtest?
I don't get anything on /dev/input/event* when I move my mouse but do on /dev/input/by-path/platform-i8042-serio-1-event-mouse. I also don't get anything when I use /dev/input/by-path/platform-i8042-serio-1-event-mouse and move the mouse across Synergy, I have to physically move the mouse.
Sach

Resources