Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.arch > #111375 > unrolled thread

Constant Stack Canaries

Started byRobert Finch <robfi680@gmail.com>
First post2025-03-30 08:16 -0400
Last post2025-04-02 00:43 -0500
Articles 20 on this page of 62 — 7 participants

Back to article view | Back to comp.arch


Contents

  Constant Stack Canaries Robert Finch <robfi680@gmail.com> - 2025-03-30 08:16 -0400
    Re: Constant Stack Canaries BGB <cr88192@gmail.com> - 2025-03-30 12:47 -0500
      Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-03-30 20:14 +0000
        Re: Constant Stack Canaries Robert Finch <robfi680@gmail.com> - 2025-03-30 21:26 -0400
        Re: Constant Stack Canaries BGB <cr88192@gmail.com> - 2025-03-31 01:34 -0500
        Re: Constant Stack Canaries Stephen Fuld <sfuld@alumni.cmu.edu.invalid> - 2025-03-31 09:04 -0700
          Re: Constant Stack Canaries BGB <cr88192@gmail.com> - 2025-03-31 12:17 -0500
            Re: Constant Stack Canaries Stephen Fuld <sfuld@alumni.cmu.edu.invalid> - 2025-03-31 10:57 -0700
            Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-03-31 18:07 +0000
              Re: Constant Stack Canaries BGB <cr88192@gmail.com> - 2025-03-31 13:56 -0500
                Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-03-31 20:52 +0000
                  Re: Constant Stack Canaries Robert Finch <robfi680@gmail.com> - 2025-04-01 00:58 -0400
                    Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-01 18:51 +0000
                      Re: Constant Stack Canaries Robert Finch <robfi680@gmail.com> - 2025-04-01 18:06 -0400
                        Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-01 23:24 +0000
                          Re: Constant Stack Canaries Robert Finch <robfi680@gmail.com> - 2025-04-01 20:07 -0400
                            Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-02 01:47 +0000
                            Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-04 21:07 +0000
                    Re: Constant Stack Canaries BGB <cr88192@gmail.com> - 2025-04-01 16:21 -0500
                      Re: Constant Stack Canaries Robert Finch <robfi680@gmail.com> - 2025-04-01 18:19 -0400
                        Re: Constant Stack Canaries BGB <cr88192@gmail.com> - 2025-04-01 23:04 -0500
                  Re: Constant Stack Canaries BGB <cr88192@gmail.com> - 2025-04-01 14:34 -0500
                    Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-01 23:21 +0000
                      Re: Constant Stack Canaries Stefan Monnier <monnier@iro.umontreal.ca> - 2025-04-01 22:55 -0400
                        Re: Constant Stack Canaries BGB <cr88192@gmail.com> - 2025-04-01 23:19 -0500
                          Re: Constant Stack Canaries Stefan Monnier <monnier@iro.umontreal.ca> - 2025-04-03 10:09 -0400
                            Re: Constant Stack Canaries BGB <cr88192@gmail.com> - 2025-04-03 12:22 -0500
                              Re: Constant Stack Canaries Robert Finch <robfi680@gmail.com> - 2025-04-03 23:49 -0400
                                Re: Constant Stack Canaries BGB <cr88192@gmail.com> - 2025-04-04 12:41 -0500
                                Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-04 21:13 +0000
                                  Re: Constant Stack Canaries Robert Finch <robfi680@gmail.com> - 2025-04-04 23:45 -0400
                                    Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-05 16:37 +0000
                                      Re: Constant Stack Canaries scott@slp53.sl.home (Scott Lurndal) - 2025-04-05 18:31 +0000
                                        Re: Constant Stack Canaries Robert Finch <robfi680@gmail.com> - 2025-04-05 17:57 -0400
                                          Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-05 23:11 +0000
                                          Re: Constant Stack Canaries scott@slp53.sl.home (Scott Lurndal) - 2025-04-06 14:21 +0000
                                            Re: Constant Stack Canaries Robert Finch <robfi680@gmail.com> - 2025-04-06 15:01 -0400
                                              Re: Constant Stack Canaries scott@slp53.sl.home (Scott Lurndal) - 2025-04-07 14:04 +0000
                                        Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-05 23:06 +0000
                                          Re: Constant Stack Canaries scott@slp53.sl.home (Scott Lurndal) - 2025-04-06 14:32 +0000
                                            Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-07 00:51 +0000
                                              Re: Constant Stack Canaries scott@slp53.sl.home (Scott Lurndal) - 2025-04-07 14:09 +0000
                                                Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-09 00:23 +0000
                                                Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-15 00:43 +0000
                                                  Re: Constant Stack Canaries scott@slp53.sl.home (Scott Lurndal) - 2025-04-15 14:02 +0000
                                                    Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-15 20:46 +0000
                                                      Re: Constant Stack Canaries scott@slp53.sl.home (Scott Lurndal) - 2025-04-16 14:07 +0000
                                                        Re: Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-16 21:13 +0000
                                                          Virtualization layers (was: Constant Stack Canaries) Stefan Monnier <monnier@iro.umontreal.ca> - 2025-04-16 17:48 -0400
                                                            Re: Virtualization layers mitchalsup@aol.com (MitchAlsup1) - 2025-04-16 22:12 +0000
                                                            Re: Virtualization layers (was: Constant Stack Canaries) scott@slp53.sl.home (Scott Lurndal) - 2025-04-17 00:49 +0000
                                                          Re: Constant Stack Canaries Stephen Fuld <sfuld@alumni.cmu.edu.invalid> - 2025-04-16 15:26 -0700
                                                            Re: Constant Stack Canaries scott@slp53.sl.home (Scott Lurndal) - 2025-04-17 00:57 +0000
                                                              Re: virtualization, Constant Stack Canaries John Levine <johnl@taugh.com> - 2025-04-17 01:04 +0000
                                                                Re: virtualization, Constant Stack Canaries Stefan Monnier <monnier@iro.umontreal.ca> - 2025-04-16 21:07 -0400
                                                                Re: virtualization, Constant Stack Canaries Stephen Fuld <sfuld@alumni.cmu.edu.invalid> - 2025-04-16 23:30 -0700
                                                                Re: virtualization, Constant Stack Canaries scott@slp53.sl.home (Scott Lurndal) - 2025-04-17 13:32 +0000
                                                                Re: virtualization, Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-17 18:22 +0000
                                                                  Re: virtualization, Constant Stack Canaries scott@slp53.sl.home (Scott Lurndal) - 2025-04-17 20:10 +0000
                                                                    Re: virtualization, Constant Stack Canaries mitchalsup@aol.com (MitchAlsup1) - 2025-04-17 21:45 +0000
                                                          Re: Constant Stack Canaries scott@slp53.sl.home (Scott Lurndal) - 2025-04-17 00:47 +0000
                      Re: Constant Stack Canaries BGB <cr88192@gmail.com> - 2025-04-02 00:43 -0500

Page 2 of 4 — ← Prev page 1 [2] 3 4  Next page →


#111410

FromBGB <cr88192@gmail.com>
Date2025-04-01 23:04 -0500
Message-ID<vsid3u$sput$1@dont-email.me>
In reply to#111404
On 4/1/2025 5:19 PM, Robert Finch wrote:
> On 2025-04-01 5:21 p.m., BGB wrote:
>> On 3/31/2025 11:58 PM, Robert Finch wrote:
>>> On 2025-03-31 4:52 p.m., MitchAlsup1 wrote:
>>>> On Mon, 31 Mar 2025 18:56:32 +0000, BGB wrote:
>>>>
>>>>> On 3/31/2025 1:07 PM, MitchAlsup1 wrote:
>>>> -------------
>>>>>>> Another option being if it could be a feature of a Load/Store 
>>>>>>> Multiple.
>>>>>>>
>>>>>>> Say, LDM/STM:
>>>>>>>    6b Hi (Upper bound of register to save)
>>>>>>>    6b Lo (Lower bound of registers to save)
>>>>>>>    1b LR (Flag to save Link Register)
>>>>>>>    1b GP (Flag to save Global Pointer)
>>>>>>>    1b SK (Flag to generate a canary)
>>>
>>> Q+3 uses a bitmap of register selection with four more bits selecting 
>>> overlapping groups. It can work with up to 17 registers.
>>>
>>
>> OK.
>>
>> If I did LDM/STM style ops, not sure which strategy I would take.
>>
>> The possibility of using a 96-bit encoding with an Imm64 holding a 
>> bit- mask of all the registers makes some sense...
>>
>>
>>>>>>
>>>>>> ENTER and EXIT have 2 of those flags--but also note use of SP and CSP
>>>>>> are implicit.
>>>>>>
>>>>>>> Likely (STM):
>>>>>>>    Pushes LR first (if bit set);
>>>>>>>    Pushes GP second (if bit set);
>>>>>>>    Pushes registers in range (if Hi>=Lo);
>>>>>>>    Pushes stack canary (if bit set).
>>>>>>
>>>>>> EXIT uses its 3rd flag used when doing longjump() and THROW()
>>>>>> so as to pop the call-stack but not actually RET from the stack
>>>>>> walker.
>>>>>>
>>>>>
>>>>> OK.
>>>>>
>>>>> I guess one could debate whether an LDM could treat the Load-LR as 
>>>>> "Load
>>>>> LR" or "Load address and Branch", and/or have separate flags (Load 
>>>>> LR vs
>>>>> Load PC, with Load PC meaning to branch).
>>>>>
>>>>>
>>>>> Other ABIs may not have as much reason to save/restore the Global
>>>>> Pointer all the time. But, in my case, it is being used as the primary
>>>>> way of accessing globals, and each binary image has its own address
>>>>> range here.
>>>>
>>>> I use constants to access globals.
>>>> These comes in 32-bit and 64-bit flavors.
>>>>
>>>>> PC-Rel not being used as PC-Rel doesn't allow for multiple process
>>>>> instances of a given loaded binary within a shared address space.
>>>>
>>>> As long as the relative distance is the same, it does.
>>>>
>>>>> Vs, say, for PIE ELF binaries where it is needed to load a new copy 
>>>>> for
>>>>> each process instance because of this (well, excluding an FDPIC style
>>>>> ABI, but seemingly still no one seems to have bothered adding FDPIC
>>>>> support in GCC or friends for RV64 based targets, ...).
>>>>>
>>>>> Well, granted, because Linux and similar tend to load every new 
>>>>> process
>>>>> into its own address space and/or use CoW.
>>>>
>>>> CoW and execl()
>>>>
>>>> --------------
>>>>>>> Other ISAs use a flag bit for each register, but this is less viable
>>>>>>> with an ISA with a larger number of registers, well, unless one 
>>>>>>> uses a
>>>>>>> 64 or 96 bit LDM/STM encoding (possible). Merit though would be not
>>>>>>> needing multiple LDM's / STM's to deal with a discontinuous register
>>>>>>> range.
>>>>>>
>>>>>> To quote Trevor Smith:: "Why would anyone want to do that" ??
>>>>>>
>>>>>
>>>>> Discontinuous register ranges:
>>>>> Because pretty much no ABI's put all of the callee save registers in a
>>>>> contiguous range.
>>>>>
>>>>> Granted, I guess if someone were designing an ISA and ABI clean, they
>>>>> could make all of the argument registers and callee save registers
>>>>> contiguous.
>>>>>
>>>>> Say:
>>>>>    R0..R3: Special
>>>>>    R4..R15: Scratch
>>>>>    R16..R31: Argument
>>>>>    R32..R63: Callee Save
>>>>> ....
>>>>>
>>>>> But, invariably, someone will want "compressed" instructions with a
>>>>> subset of the registers, and one can't just have these only having
>>>>> access to argument registers.
>>>>
>>>> Brian had little trouble using My 66000 ABI which does have contiguous
>>>> register groupings.
>>>>
>>>>>>> Well, also excluding the possibility where the LDM/STM is 
>>>>>>> essentially
>>>>>>> just a function call (say, if beyond certain number of registers 
>>>>>>> are to
>>>>>>> be saved/restored, the compiler generates a call to a save/restore
>>>>>>> sequence, which is also generates as-needed). Granted, this is 
>>>>>>> basically
>>>>>>> the strategy used by BGBCC. If multiple functions happen to save/ 
>>>>>>> restore
>>>>>>> the same combination of registers, they get to reuse the prior
>>>>>>> function's save/restore sequence (generally folded off to before the
>>>>>>> function in question).
>>>>>>
>>>>>> Calling a subroutine to perform epilogues is adding to the number of
>>>>>> branches a program executes. Having an instruction like EXIT means
>>>>>> when you know you need to exit, you EXIT you don't branch to the exit
>>>>>> point. Saving instructions.
>>>>>>
>>>>>
>>>>> Prolog needs a call, but epilog can just be a branch, since no need to
>>>>> return back into the function that is returning.
>>>>
>>>> Yes, but this means My 66000 executes 3 fewer transfers of control
>>>> per subroutine than you do. And taken branches add latency.
>>>>
>>>>> Needs to have a lower limit though, as it is not worth it to use a
>>>>> call/branch to save/restore 3 or 4 registers...
>>>>>
>>>>> But, say, 20 registers, it is more worthwhile.
>>>>
>>>> ENTER saves as few as 1 or as many as 32 and remains that 1 single
>>>> instruction. Same for EXIT and exit also performs the RET when LDing
>>>> R0.
>>>>
>>>>>
>>>>>>> Granted, the folding strategy can still do canary values, but 
>>>>>>> doing so
>>>>>>> in the reused portions would limit the range of unique canary values
>>>>>>> (well, unless the canary magic is XOR'ed with SP or something...).
>>>>>>>
>>>> Canary values are in addition to ENTER and EXIT not part of them
>>>> IMHO.
>>>
>>> In Q+3 there are push and pop multiple instructions. I did not want 
>>> to add load and store multiple on top of that. They work great for 
>>> ISRs, but not so great for task switching code. I have the 
>>> instructions pushing or popping up to 17 registers in a group. Groups 
>>> of registers overlap by eight. The instructions can handle all 96 
>>> registers in the machine. ENTER and EXIT are also present.
>>>
>>> It is looking like the context switch code for the OS will take about 
>>> 3000 clock cycles to run. Not wanting to disable interrupts for that 
>>> long, I put a spinlock on the system’s task control block array. But 
>>> I think I have run into an issue. It is the timer ISR that switches 
>>> tasks. Since it is an ISR it pushes a subset of registers that it 
>>> uses and restores them at exit. But when exiting and switching tasks 
>>> it spinlocks on the task control block array. I am not sure this is a 
>>> good thing. As the timer IRQ is fairly high priority. If something 
>>> else locked the TCB array it would deadlock. I guess the context 
>>> switching could be deferred until the app requests some other 
>>> operating system function. But then the issue is what if the app gets 
>>> stuck in an infinite loop, not calling the OS? I suppose I could make 
>>> an OS heartbeat function call a requirement of apps. If the app does 
>>> not do a heartbeat within a reasonable time, it could be terminated.
>>>
>>> Q+3 progresses rapidly. A lot of the stuff in earlier versions was 
>>> removed. The pared down version is a 32-bit machine. Expecting some 
>>> headaches because of the use of condition registers and branch 
>>> registers.
>>>
>>
>> OK.
>>
>> Ironically, I seem to have comparably low task-switch cost...
>> However, each system call is essentially 2 task switches, and it is 
>> still slow enough to negatively effect performance if they happen at 
>> all frequently.
>>
> System calls for Q+ are slightly faster (but not much) than task 
> switches. I just have the system saving state on the stack. I don't 
> bother saving the FP registers or some of the other system registers 
> that the OS controls. So, it is a little bit shorter than the task 
> switch code.
> 
> The only thing that can do a task switch in the system is the time-slicer.
> 

In my case, task switch happens by capturing and restoring all of the 
registers (of which there are 64 main registers, and a few CR's).

No separate FPU or vector registers (the BJX GPR space, and RISC-V X+F 
spaces, being mostly equivalent).

The interrupt handlers only have access to physical addresses, and will 
block all other interrupts when running, so there is a need to get 
quickly from the user-program task to the syscall handler task, and then 
back again once done (though, maybe not immediately, as it may instead 
send the results back to the caller task, and then transfer control to a 
different task).

Timer interrupt can do scheduling, but mostly avoids doing so unless 
there is no other option (TestKern being mostly lacking in mutexes, 
which makes timer-driven preemptive multitasking a bit risky). However, 
usually programs will use system calls often enough that it is possible 
to schedule tasks this way, and generally a system call will not be made 
inside of a critical section.


>> So, say, one needs to try to minimize the number of unnecessary system 
>> calls (say, don't implement "fputs()" by sending 1 byte at a time, ...).
>>
>>
>>
>>
>>
>> Unlike on a modern PC, one generally needs to care more about efficiency.
>>
>> Hence, all the fiddling with low bit-depth graphics formats, and 
>> things like my recent fiddling with 2-bit ADPCM audio.
>>
>> And, online, one is (if anything) more likely to find people 
>> complaining about how old/obsolescent ADPCM is (and/or arguing that 
>> people should store all their sound effects as Ogg/Vorbis or 
>> similar; ...).
>>
>>
> Im not one much for music, although I play the tunes ocassionally. I'm 
> little hard of hearing.

Not so much for music here, but more for storing sound-effects.


I can note I seem to have a form of reverse-slope hearing impairment...

Not a new thing, I have either always been this way, or it has happened 
very slowly.


I can seemingly hear most stuff OK though.
   Except, IRL, I can't hear tuning forks.
     Nor car engines.
       I don't hear the engines.
       I do hear the tires rolling on the ground.
     Nor refrigerators (mostly).
       I sometimes hear the relays when they start/stop,
         or a crackling sound from the radiator coil.
   Using phones sucks hard, can't hear crap...
   Not terribly musically inclined.
     But, instruments don't sound much different from "noise" sounds.

My ability to hear low-frequencies is a bit weird:
   Square or triangle waves, I hear these well;
   Sine waves, weakly, but I hear them in headphones if volume is high.
     If the volume isn't very high, sine waves become silent.
     Seemingly, these are harder to hear IRL.


I seem most sensitive to frequencies between around 2 to 8 kHz. Upper 
end of hearing seems to be around 17 kHz (lower end around 1kHz for pure 
sine waves). The lower ("absolute" limit seems to be around 8Hz, but 
more because at this point, a square wave turns from a "tone" into a 
series of discrete pops, 8-20 Hz being sort of a meta-range between 
being tonal and discrete pops).

Have noted that in YouTube videos where someone is messing with a CRT 
TV, I can still sometimes hear the squeal, particularly if the camera is 
close to the TV. Not seen a CRT IRL in a while though; no obvious sound 
from a VGA CRT monitor though (but, then again, I am using it ATM on an 
old rack server, which sounds kinda like a vacuum cleaner, so might be 
masking it if it is making a noise).


Have noted that I still understand speech fine with a 2-8 kHz bandpass 
(with steep fall-off). I don't understand speech at all with a 2kHz 
low-pass. So, whichever parts I use for intelligibility seem to be 
between 2 and 8kHz. Had noted if I split it into 2-4 or 4-8 kHz bands, 
either works, though individually each has a notably worse quality than 
combined 2-8 kHz.

The 1-2 kHz range can be heard, but doesn't seem to contain much as far 
as intelligibility goes, but its presence or absence does seem to alter 
vowel sounds slightly.

A 1-8 kHz bandpass sounds mostly natural to me. Though, cats seem to 
respond unfavorably to band-passed audio (if cats are neutral to the 
original, but tense up and dig in their claws if I play band-passed 
audio, it seems they hear a difference).


Although, I was using music as test-cases mostly as they can give a 
better idea of the relative audio quality than a short sound effect.

But, for things that are going to be embedded into an EXE or DLL, 
generally these are ideally kept at a few kB or less.


For long form audio, there is more reason to care about audio quality, 
but for something like a notification ding, not as much. Do preferably 
want it to not sound like "broken crap" though. And, if any speech is 
present, ideally it needs to be intelligible.


In terms of being small and "not sounding like crap":
   ADPCM:
     Works well enough, but can't go below 2 bits per sample.
   Delta-Signma:
     1 bit per sample, but sounds horrid much under 64 kHz.


MP3 and Vorbis work well at 96 to 128 kbps, but:
   Are complex and expensive formats to decode;
   Don't give acceptable results much below around 40 kbps.

At lower bitrates, the artifacts from MP3 and Vorbis can become rather 
obnoxious (lots of squealing and whistling and sounds like broken glass 
being shaken in a steel can).

I actually much prefer the sound of ADPCM for low bitrates. Muffled and 
gritty is still preferable to "rattling a steel can full of broken 
glass" (simple loss of quality rather than the addition of other more 
obnoxious artifacts).



 From what I gather, the telephone network used 8kHz as a standard 
sampling rate, with one of several formats:
   u-Law, in the US
   A-Law, in Europe
   4-bit ADPCM, for lower-priority long-distance links;
     When not using u-Law or A-Law.
   2-bit ADPCM, for "overflow" links (*).

*: Apparently, if there were too many long distance calls over a given 
long-distance link, they would drop to a 2-bit ADPCM (running at 16 kbps).

I was testing with 16kHz 2-bit ADPCM, as while both 16kHz 2-bit and 8kHz 
4-bit ADPCM are both 32 kbps, the 16kHz sounds better to me (and 
intelligibility is higher).


Though, if spoken language is not used, it makes sense to drop to 8kHz.
   Using 8kHz as standard is weak as intelligibility is a lot worse.

But, I guess the thinking was "minimum where you can still 'mostly' hear 
what they are saying...".


Even if 8kHz was standard on the telephone network, I can't easily 
understand what anyone is saying over the phone (speech is often very 
muffled and there is often a loud/obnoxious hiss).

Actually, weirdly, actual phone quality is somehow *worse* than my 
experiments with low bitrate ADPCM. Like, the low-bit depth ADPCM mostly 
just sounds "gritty" (without any obvious hiss). Like, the phone adds 
extra levels of badness beyond just any compression issues (probably 
also crappy microphones and speakers, etc, as well).

Using headphones with a phone is "slightly" better, but there is often 
still a rather loud/annoying hiss, even when the sound is coming from an 
artificial source.

Poor quality ADPCM, by itself, does not have this particular issue 
(actually, it almost seems as if the ADPCM somehow "enhances" the audio 
and compensates slightly for the low sample rate, making details easier 
to hear compared with "cleaner" PCM audio versions).


For sound-effects, could drop to 4kHz, but there is fairly significant 
distortion. Like, if you have a notification ding, it doesn't really 
sound like a bell anymore.


So, say (ADPCM modes):
   16kHz 4-bit: Mostly Good, but needs 64 kbps.
   16kHz 2-bit: Slightly muffled, gritty, 32 kbps.
   8kHz 4-bit: More obvious muffling (but not gritty);
   8kHz 2-bit: Muffled and gritty (16 kbps);
   4kHz 4-bit: Serious muffle / distortion, 16 kbps.
   4kHz 2-bit: Muffle + distortion + grit, 8 kbps.

Possible merit of 4kHz 2-bit is that it allows putting a bell sound 
effect in around 500 bytes. Downside is that it is no longer 
particularly recognizable as a bell (and goes more from "ding" to "plong").

At 4 kHz, speech is basically almost entirely unintelligible, but can 
still hear that speech is present (its "shape" can still be heard; but 
words are still recognizable; sort of like the muffling when people are 
talking in a different room, but one can still hear that they are saying 
"something").

At 2 kHz; it is barely recognizable as being speech (it sounds almost 
more like wind). Percussive sounds are still recognizable though (so, 
music is turned into "howling wind with drums").


Early 90s games (such as Doom) mostly used 11 kHz as standard.
   IMHO, 16kHz is a better quality/space tradeoff.
   Where, 22/32/44 can sound better, but may not be worth the overhead.
   Sample rates above 44 kHz are overkill though.

I, personally, can't hear the difference between 44 and 48 kHz audio.
   I suspect anything 48kHz and beyond is likely needless overkill.


>>
>> Then again, I did note that I may need to find some other "quality 
>> metric" for audio, as RMSE isn't really working...
>>
>> At least going by RMSE, the "best" option would be to use 8-bit PCM 
>> and then downsample it.
>>
>> Say, 4kHz 8-bit PCM has a lower RMSE score than 2-bit ADPCM, but 
>> subjectively the 2-bit ADPCM sounds significantly better.
>>
>> Say: for 16kHz, and a test file (using a song here):
>>    PCM8, 16kHz     : 121 (128 kbps)
>>    A-Law, 16kHz    : 284 (128 kbps)
>>    IMA 4bit, 16kHz : 617 (64 kbps)
>>    IMA 2bit, 16kHz : 1692 (32 kbps, *)
>>    ADLQ 2bit, 16kHz: 2000 (32 kbps)
>>    PCM8, 4kHz      : 242  (32 kbps)
>>
>> However, 4kHz PCM8 sounds terrible vs either 2-bit IMA or ADLQ.
>>    Basically sounds muffled, speech is unintelligible.
>>    But, it would be the "best" option if going solely by RMSE.
>>
>> Also A-Law sounds better than PCM8 (at the same sample rate).
>>    Even with the higher RMSE score.
>>
>> Seems like it could be possible to do RMSE on A-Law samples as a 
>> metric, but if anything this is just kicking the can down the road 
>> slightly.
>>
>> Granted, A-Law sounds better than 4-bit IMA, and 4-bit IMA sounds 
>> better than the 2-bit ADPCM's at least...
>>
>>
>> *: Previously it was worse, around 4500, but the RMSE score dropped 
>> after switching it to using a similar encoder strategy to ADLQ, namely 
>> doing a brute-force search over the next 3 samples to find the values 
>> that best approximate the target samples.
>>
>> Though, which is "better", or whether or not even lower RMSE 
>> "improves" quality here, is debatable (the PCM8 numbers clearly throw 
>> using RMSE as a quality metric into question for this case).
>>
>> Ideally I would want some metric that better reflects hearing 
>> perception and is computationally cheap.
>>
>> ...
>>
> 
> 
> 

[toc] | [prev] | [next] | [standalone]


#111397

FromBGB <cr88192@gmail.com>
Date2025-04-01 14:34 -0500
Message-ID<vshf6a$3smcv$1@dont-email.me>
In reply to#111390
On 3/31/2025 3:52 PM, MitchAlsup1 wrote:
> On Mon, 31 Mar 2025 18:56:32 +0000, BGB wrote:
> 
>> On 3/31/2025 1:07 PM, MitchAlsup1 wrote:
> -------------
>>>> Another option being if it could be a feature of a Load/Store Multiple.
>>>>
>>>> Say, LDM/STM:
>>>>    6b Hi (Upper bound of register to save)
>>>>    6b Lo (Lower bound of registers to save)
>>>>    1b LR (Flag to save Link Register)
>>>>    1b GP (Flag to save Global Pointer)
>>>>    1b SK (Flag to generate a canary)
>>>
>>> ENTER and EXIT have 2 of those flags--but also note use of SP and CSP
>>> are implicit.
>>>
>>>> Likely (STM):
>>>>    Pushes LR first (if bit set);
>>>>    Pushes GP second (if bit set);
>>>>    Pushes registers in range (if Hi>=Lo);
>>>>    Pushes stack canary (if bit set).
>>>
>>> EXIT uses its 3rd flag used when doing longjump() and THROW()
>>> so as to pop the call-stack but not actually RET from the stack
>>> walker.
>>>
>>
>> OK.
>>
>> I guess one could debate whether an LDM could treat the Load-LR as "Load
>> LR" or "Load address and Branch", and/or have separate flags (Load LR vs
>> Load PC, with Load PC meaning to branch).
>>
>>
>> Other ABIs may not have as much reason to save/restore the Global
>> Pointer all the time. But, in my case, it is being used as the primary
>> way of accessing globals, and each binary image has its own address
>> range here.
> 
> I use constants to access globals.
> These comes in 32-bit and 64-bit flavors.
> 

Typically 16-bit, most are within a 16-bit range of the Global Pointer.


>> PC-Rel not being used as PC-Rel doesn't allow for multiple process
>> instances of a given loaded binary within a shared address space.
> 
> As long as the relative distance is the same, it does.
> 

Can't happen within a shared address space.

Say, if you load a single copy of a binary at 0x24680000.
Process A and B can't use the same mapping in the same address space, 
with PC-rel globals, as then they would each see the other's globals.

You can't do a duplicate mapping at another address, as this both wastes 
VAS, and also any Abs64 base-relocs or similar would differ.

You also can't CoW the data/bss sections, as this is no longer a shared 
address space.


So, alternative is to use GBR to access globals, with the data/bss 
sections allocated independently of the binary.

This way, multiple processes can share the same mapping at the same 
address for any executable code and constant data, with only the data 
sections needing to be allocated.


Does mean though that one needs to save/restore the global pointer, and 
there is a ritual for reloading it.

EXE's generally assume they are index 0, so:
   MOV.Q (GBR, 0), Rt
   MOV.Q (Rt, 0), GBR
Or, in RV terms:
   LD    X6, 0(X3)
   LD    X3, Disp33(X6)
Or, RV64G:
   LD    X6, 0(X3)
   LUI   X5, DispHi
   ADD   X5  X5, X6
   LD    X3, DispLo(X5)


For DLL's, the index is fixed up with a base-reloc (for each loaded 
DLL), so basically the same idea. Typically a Disp33 is used here to 
allow for a potentially large/unknown number of loaded DLL's. Thus far, 
a global numbering scheme is used.

Where, (GBR+0) gives the address of a table of global pointers for every 
loaded binary (can be assumed read-only from userland).


Generally, this is needed if:
   Function may be called from outside of the current binary and:
     Accesses global variables;
     And/or, calls local functions.


Though, still generally lower average-case overhead than the strategy 
typically used by FDPIC, which would handle this reload process on the 
caller side...
   SD    X3, Disp(SP)
   LD    X3, 8(X18)
   LD    X6, 0(X18)
   JALR  X1, 0(X6)
   LD    X3, Disp(SP)

With generally every function pointer existing as a pair with the actual 
function pointer, and its associated global pointer.

Though, caller side handling does arguably avoid the need to perform 
relocs for the table index.

Though, seemingly no one wants to add FDPIC for RV64G, seeing it mostly 
as a 32-bit microcontroller thing.


For normal PIE though, absent CoW, it is necessary to load a new copy of 
the binary each time a new process instance is created.


>> Vs, say, for PIE ELF binaries where it is needed to load a new copy for
>> each process instance because of this (well, excluding an FDPIC style
>> ABI, but seemingly still no one seems to have bothered adding FDPIC
>> support in GCC or friends for RV64 based targets, ...).
>>
>> Well, granted, because Linux and similar tend to load every new process
>> into its own address space and/or use CoW.
> 
> CoW and execl()
> 

Though, execl() effectively replaces the current process.

IMHO, a "CreateProcess()" style abstraction makes more sense than fork+exec.

Though, one tricky way to handle it is:
   vfork: effectively spawns a thread in the same address space as the 
caller, with a provisional PID, and semi-copied stack;
   exec: Creates a new process copying the PID and file-descriptors;
     Internally uses CreateProcess;
     Temporary thread disappears once exec is called.

True "fork()" is more of an issue though...

The true "fork()" semantics are not possible on single-address-space or 
NoMMU systems. Nor fully emulated in things like Cygwin IIRC.

Though, the usual alternative is to give them "vfork()" semantics, and 
things will probably explode if they do anything other than call exec or 
similar.


> --------------
>>>> Other ISAs use a flag bit for each register, but this is less viable
>>>> with an ISA with a larger number of registers, well, unless one uses a
>>>> 64 or 96 bit LDM/STM encoding (possible). Merit though would be not
>>>> needing multiple LDM's / STM's to deal with a discontinuous register
>>>> range.
>>>
>>> To quote Trevor Smith:: "Why would anyone want to do that" ??
>>>
>>
>> Discontinuous register ranges:
>> Because pretty much no ABI's put all of the callee save registers in a
>> contiguous range.
>>
>> Granted, I guess if someone were designing an ISA and ABI clean, they
>> could make all of the argument registers and callee save registers
>> contiguous.
>>
>> Say:
>>    R0..R3: Special
>>    R4..R15: Scratch
>>    R16..R31: Argument
>>    R32..R63: Callee Save
>> ....
>>
>> But, invariably, someone will want "compressed" instructions with a
>> subset of the registers, and one can't just have these only having
>> access to argument registers.
> 
> Brian had little trouble using My 66000 ABI which does have contiguous
> register groupings.
> 

But, My66000 also isn't like, "Hey, how about 16-bit ops with 3 or 4 bit 
register numbers".

Not sure the thinking behind the RV ABI.


In the BJX ABI, the layout directly grew out of the SH ABI mapping, 
effectively just mirroring the original SH layout 4 times for 64 registers.

The SH layout was contiguous, at least for 16 registers, though a 
mirrored layout is no longer contiguous.

The RV ABI is not contiguous, but at least still less chaotic than the 
x86-64 ABIs.


>>>> Well, also excluding the possibility where the LDM/STM is essentially
>>>> just a function call (say, if beyond certain number of registers are to
>>>> be saved/restored, the compiler generates a call to a save/restore
>>>> sequence, which is also generates as-needed). Granted, this is 
>>>> basically
>>>> the strategy used by BGBCC. If multiple functions happen to save/ 
>>>> restore
>>>> the same combination of registers, they get to reuse the prior
>>>> function's save/restore sequence (generally folded off to before the
>>>> function in question).
>>>
>>> Calling a subroutine to perform epilogues is adding to the number of
>>> branches a program executes. Having an instruction like EXIT means
>>> when you know you need to exit, you EXIT you don't branch to the exit
>>> point. Saving instructions.
>>>
>>
>> Prolog needs a call, but epilog can just be a branch, since no need to
>> return back into the function that is returning.
> 
> Yes, but this means My 66000 executes 3 fewer transfers of control
> per subroutine than you do. And taken branches add latency.
> 

Granted.

Each predicted branch adds 2 cycles.


>> Needs to have a lower limit though, as it is not worth it to use a
>> call/branch to save/restore 3 or 4 registers...
>>
>> But, say, 20 registers, it is more worthwhile.
> 
> ENTER saves as few as 1 or as many as 32 and remains that 1 single
> instruction. Same for EXIT and exit also performs the RET when LDing
> R0.
> 

Granted.

My strategy isn't perfect:
   Non-zero branching overheads, when the feature is used;
   Per-function load/store slides in prolog/epilog, when not used.

Then, the heuristic mostly becomes one of when it is better to use the 
inline strategy (load/store slide), or to fold them off and use 
calls/branches.

Does technically also work for RISC-V though (though seemingly GCC 
always uses inline save/restore, but also the RV ABI has fewer registers).


>>
>>>> Granted, the folding strategy can still do canary values, but doing so
>>>> in the reused portions would limit the range of unique canary values
>>>> (well, unless the canary magic is XOR'ed with SP or something...).
>>>>
> Canary values are in addition to ENTER and EXIT not part of them
> IMHO.

OK.


It sorta made sense to treat canary values as part of the process of 
saving/restoring the registers, since their main purpose is to protect 
the saved registers, and particularly the saved PC.

Granted, canary values are not a perfect strategy.
They can provide some added resistance against buffer overflow exploits 
if the value can be made unknown to the attacker.

This means, ideally:
   Unique to each function, and does not repeat across builds.
     But, by itself, insufficient if a single build is used.
   Is mangled in some other way to avoid repeats.
     Say, XOR'ing with SP and also ASLR'ing the SP.

But, yeah, if the canary value is, say:
(SP XOR Magic) with SP being ASLR'ed, it offers at least some added 
protection.

[toc] | [prev] | [next] | [standalone]


#111405

Frommitchalsup@aol.com (MitchAlsup1)
Date2025-04-01 23:21 +0000
Message-ID<21397906a7a77c2d43191fdaab98a3c9@www.novabbs.org>
In reply to#111397
On Tue, 1 Apr 2025 19:34:10 +0000, BGB wrote:

> On 3/31/2025 3:52 PM, MitchAlsup1 wrote:
>> On Mon, 31 Mar 2025 18:56:32 +0000, BGB wrote:
---------------------
>>> PC-Rel not being used as PC-Rel doesn't allow for multiple process
>>> instances of a given loaded binary within a shared address space.
>>
>> As long as the relative distance is the same, it does.
>>
>
> Can't happen within a shared address space.
>
> Say, if you load a single copy of a binary at 0x24680000.
> Process A and B can't use the same mapping in the same address space,
> with PC-rel globals, as then they would each see the other's globals.

Say I load a copy of the binary text at 0x24680000 and its data at
0x35900000 for a distance of 0x11280000 into the address space of
a process.

Then I load another copy at 0x44680000 and its data at 55900000
into the address space of a different process.

PC-rel addressing works in both cases--because the distance (-rel)
remains the same,

and the MMU can translate the code to the same physical, and map
each area of data individually.

Different virtual addresses, same code physical address, different
data virtual and physical addresses.

> You can't do a duplicate mapping at another address, as this both wastes
> VAS, and also any Abs64 base-relocs or similar would differ.

A 64-bit VAS is a wasteable address space, whereas a 48-bit VAS is not.

> You also can't CoW the data/bss sections, as this is no longer a shared
> address space.

You are trying to "get at" something here, but I can't see it (yet).

>
> So, alternative is to use GBR to access globals, with the data/bss
> sections allocated independently of the binary.
>
> This way, multiple processes can share the same mapping at the same
> address for any executable code and constant data, with only the data
> sections needing to be allocated.
>
>
> Does mean though that one needs to save/restore the global pointer, and
> there is a ritual for reloading it.
>
> EXE's generally assume they are index 0, so:
>    MOV.Q (GBR, 0), Rt
>    MOV.Q (Rt, 0), GBR
> Or, in RV terms:
>    LD    X6, 0(X3)
>    LD    X3, Disp33(X6)
> Or, RV64G:
>    LD    X6, 0(X3)
>    LUI   X5, DispHi
>    ADD   X5  X5, X6
>    LD    X3, DispLo(X5)
>
>
> For DLL's, the index is fixed up with a base-reloc (for each loaded
> DLL), so basically the same idea. Typically a Disp33 is used here to
> allow for a potentially large/unknown number of loaded DLL's. Thus far,
> a global numbering scheme is used.
>
> Where, (GBR+0) gives the address of a table of global pointers for every
> loaded binary (can be assumed read-only from userland).
>
>
> Generally, this is needed if:
>    Function may be called from outside of the current binary and:
>      Accesses global variables;
>      And/or, calls local functions.

I just use 32-bit of 64-bit displacement constants. Does not matter
how control arrived at this subroutine, it accesses its data as the
linker resolved addresses--without wasting a register.

>
> Though, still generally lower average-case overhead than the strategy
> typically used by FDPIC, which would handle this reload process on the
> caller side...
>    SD    X3, Disp(SP)
>    LD    X3, 8(X18)
>    LD    X6, 0(X18)
>    JALR  X1, 0(X6)
>    LD    X3, Disp(SP)

This is just::

     CALX    [IP,,#GOT[funct_num]-.]

In the 32-bit linking mode this is a 2 word instruction, in the 64-bit
linking mode it is a 3 word instruction.
----------------
>
> Though, execl() effectively replaces the current process.
>
> IMHO, a "CreateProcess()" style abstraction makes more sense than
> fork+exec.

You are 40 years late on that.

---------------
>>>
>>> But, invariably, someone will want "compressed" instructions with a
>>> subset of the registers, and one can't just have these only having
>>> access to argument registers.
>>
>> Brian had little trouble using My 66000 ABI which does have contiguous
>> register groupings.
>>
>
> But, My66000 also isn't like, "Hey, how about 16-bit ops with 3 or 4 bit
> register numbers".
>
> Not sure the thinking behind the RV ABI.

If RISC-V removed its 16-bit instructions, there is room in its ISA
to put my entire ISA along with all the non-compressed RISC-V inst-
ructions.

---------------
>>>
>>> Prolog needs a call, but epilog can just be a branch, since no need to
>>> return back into the function that is returning.
>>
>> Yes, but this means My 66000 executes 3 fewer transfers of control
>> per subroutine than you do. And taken branches add latency.
>>
>
> Granted.
>
> Each predicted branch adds 2 cycles.

So, you loose 6 cycles on just under ½ of all subroutine calls,
while also executing 2-5 instructions manipulating your global
pointer.

>
>>> Needs to have a lower limit though, as it is not worth it to use a
>>> call/branch to save/restore 3 or 4 registers...
>>>
>>> But, say, 20 registers, it is more worthwhile.
>>
>> ENTER saves as few as 1 or as many as 32 and remains that 1 single
>> instruction. Same for EXIT and exit also performs the RET when LDing
>> R0.
>>
>
> Granted.
>
> My strategy isn't perfect:
>    Non-zero branching overheads, when the feature is used;
>    Per-function load/store slides in prolog/epilog, when not used.
>
> Then, the heuristic mostly becomes one of when it is better to use the
> inline strategy (load/store slide), or to fold them off and use
> calls/branches.

My solution gets rid of the delimma:
a) the call code is always smaller
b) the call code never takes more cycles

In addition, there is a straightforward way to elide the STs of ENTER
when the memory unit is still executing the previous EXIT.

> Does technically also work for RISC-V though (though seemingly GCC
> always uses inline save/restore, but also the RV ABI has fewer
> registers).

[toc] | [prev] | [next] | [standalone]


#111409

FromStefan Monnier <monnier@iro.umontreal.ca>
Date2025-04-01 22:55 -0400
Message-ID<jwv4iz75l6k.fsf-monnier+comp.arch@gnu.org>
In reply to#111405
>> Say, if you load a single copy of a binary at 0x24680000.
>> Process A and B can't use the same mapping in the same address space,
>> with PC-rel globals, as then they would each see the other's globals.
>
> Say I load a copy of the binary text at 0x24680000 and its data at
> 0x35900000 for a distance of 0x11280000 into the address space of
> a process.
>
> Then I load another copy at 0x44680000 and its data at 55900000
> into the address space of a different process.

But then if thread A (whose state is stored at 0x35900000) sends to
thread B (whose state is at 55900000) a closure whose code points
somewhere inside 0x24680000, it will end up using the state of thread
A instead of the state of the current thread.


        Stefan

[toc] | [prev] | [next] | [standalone]


#111411

FromBGB <cr88192@gmail.com>
Date2025-04-01 23:19 -0500
Message-ID<vsidun$sput$2@dont-email.me>
In reply to#111409
On 4/1/2025 9:55 PM, Stefan Monnier wrote:
>>> Say, if you load a single copy of a binary at 0x24680000.
>>> Process A and B can't use the same mapping in the same address space,
>>> with PC-rel globals, as then they would each see the other's globals.
>>
>> Say I load a copy of the binary text at 0x24680000 and its data at
>> 0x35900000 for a distance of 0x11280000 into the address space of
>> a process.
>>
>> Then I load another copy at 0x44680000 and its data at 55900000
>> into the address space of a different process.
> 
> But then if thread A (whose state is stored at 0x35900000) sends to
> thread B (whose state is at 55900000) a closure whose code points
> somewhere inside 0x24680000, it will end up using the state of thread
> A instead of the state of the current thread.
> 

Generally, threads and processes are seen as different...

But, yeah, passing lambdas between processes is theoretically possible 
in this scheme, but not advised.

If done, any pointers captured by the lambda would likely point to the 
originating process, but if called with a GBR from the new process, any 
global variables would either be mapped to the corresponding DLL index 
in the new process, or NULL (if a DLL that was not loaded in the new 
process), or  possibly a random address if it was from the main EXE and 
the EXE's differ...


But, yeah, inter-process function pointers aren't really a thing, and 
should not be a thing.

The eventual plan is to disallow them in the memory protection scheme, 
but enforcing memory access based the ACL based memory protection is 
still on the TODO list (it was only very recently that stuff is actually 
running in a proper usermode and so can't just stomp all over the 
kernel's memory...).

But... Yeah, the kernel and program are still hanging out in the same 
VAS, along with every other running program...

[toc] | [prev] | [next] | [standalone]


#111419

FromStefan Monnier <monnier@iro.umontreal.ca>
Date2025-04-03 10:09 -0400
Message-ID<jwvtt752vg1.fsf-monnier+comp.arch@gnu.org>
In reply to#111411
BGB [2025-04-01 23:19:11] wrote:
> But, yeah, inter-process function pointers aren't really a thing, and should
> not be a thing.

AFAIK, this point was brought in the context of a shared address space
(I assumed it was some kind of SASOS situation, but the same thing
happens with per-thread data inside a POSIX-style process).
Function pointers are perfectly normal and common in data (even tho they
may often be implicit, e.g. within the method table of objects), and the
whole point of sharing an address space is to be able to exchange data.


        Stefan

[toc] | [prev] | [next] | [standalone]


#111423

FromBGB <cr88192@gmail.com>
Date2025-04-03 12:22 -0500
Message-ID<vsmg8a$16gr3$1@dont-email.me>
In reply to#111419
On 4/3/2025 9:09 AM, Stefan Monnier wrote:
> BGB [2025-04-01 23:19:11] wrote:
>> But, yeah, inter-process function pointers aren't really a thing, and should
>> not be a thing.
> 
> AFAIK, this point was brought in the context of a shared address space
> (I assumed it was some kind of SASOS situation, but the same thing
> happens with per-thread data inside a POSIX-style process).
> Function pointers are perfectly normal and common in data (even tho they
> may often be implicit, e.g. within the method table of objects), and the
> whole point of sharing an address space is to be able to exchange data.
> 

Or, to allow for NOMMU operation, or reduce costs by not having context 
switches result in as large of numbers of TLB misses.

Also makes the kernel simpler as it doesn't need to deal with each 
process having its own address space.


Some data sharing is used for IPC, but directly sharing function 
pointers between processes, or local memory (stack, malloc, etc), is not 
allowed.


Though, things may change later, there is a plan to more to separate 
global/local address ranges. Likely things like code will remain in the 
shared range, and program data will be in the local range.

> 
>          Stefan

[toc] | [prev] | [next] | [standalone]


#111428

FromRobert Finch <robfi680@gmail.com>
Date2025-04-03 23:49 -0400
Message-ID<vsnksc$2fkk9$1@dont-email.me>
In reply to#111423
On 2025-04-03 1:22 p.m., BGB wrote:
> On 4/3/2025 9:09 AM, Stefan Monnier wrote:
>> BGB [2025-04-01 23:19:11] wrote:
>>> But, yeah, inter-process function pointers aren't really a thing, and 
>>> should
>>> not be a thing.
>>
>> AFAIK, this point was brought in the context of a shared address space
>> (I assumed it was some kind of SASOS situation, but the same thing
>> happens with per-thread data inside a POSIX-style process).
>> Function pointers are perfectly normal and common in data (even tho they
>> may often be implicit, e.g. within the method table of objects), and the
>> whole point of sharing an address space is to be able to exchange data.
>>
> 
> Or, to allow for NOMMU operation, or reduce costs by not having context 
> switches result in as large of numbers of TLB misses.
> 
> Also makes the kernel simpler as it doesn't need to deal with each 
> process having its own address space.

Have you seen the MPRV bit in RISCV? Allows memory ops to execute using 
the previous mode / address space. The bit just has to be set, then do 
the memory op, then reset the bit. Makes it easy to access data using 
the process address space.
> 
> 
> Some data sharing is used for IPC, but directly sharing function 
> pointers between processes, or local memory (stack, malloc, etc), is not 
> allowed.
> 
> 
> Though, things may change later, there is a plan to more to separate 
> global/local address ranges. Likely things like code will remain in the 
> shared range, and program data will be in the local range.
>
Thinking of having a CPU local address space in Q+ to store vars for 
that particular CPU. It looks like only a small RAM is required. I guess 
it would be hardware thread local storage. May place the RAM in the CPU 
itself.

>>
>>          Stefan
> 

[toc] | [prev] | [next] | [standalone]


#111431

FromBGB <cr88192@gmail.com>
Date2025-04-04 12:41 -0500
Message-ID<vsp5ng$2to$1@dont-email.me>
In reply to#111428
On 4/3/2025 10:49 PM, Robert Finch wrote:
> On 2025-04-03 1:22 p.m., BGB wrote:
>> On 4/3/2025 9:09 AM, Stefan Monnier wrote:
>>> BGB [2025-04-01 23:19:11] wrote:
>>>> But, yeah, inter-process function pointers aren't really a thing, 
>>>> and should
>>>> not be a thing.
>>>
>>> AFAIK, this point was brought in the context of a shared address space
>>> (I assumed it was some kind of SASOS situation, but the same thing
>>> happens with per-thread data inside a POSIX-style process).
>>> Function pointers are perfectly normal and common in data (even tho they
>>> may often be implicit, e.g. within the method table of objects), and the
>>> whole point of sharing an address space is to be able to exchange data.
>>>
>>
>> Or, to allow for NOMMU operation, or reduce costs by not having 
>> context switches result in as large of numbers of TLB misses.
>>
>> Also makes the kernel simpler as it doesn't need to deal with each 
>> process having its own address space.
> 
> Have you seen the MPRV bit in RISCV? Allows memory ops to execute using 
> the previous mode / address space. The bit just has to be set, then do 
> the memory op, then reset the bit. Makes it easy to access data using 
> the process address space.

I am not aware of this one. If it is in the privileged spec or similar, 
may have missed it.

Thus far, my core doesn't implement that much of the RV privileged spec, 
mostly just the userland ISA. If I wanted to run an RV OS, it is 
debatable if it would make more sense to try to mimic a hardware 
interface it understands, or have the "firmware" manage the real HW 
interfaces, and then fake the rest in software.


>>
>>
>> Some data sharing is used for IPC, but directly sharing function 
>> pointers between processes, or local memory (stack, malloc, etc), is 
>> not allowed.
>>
>>
>> Though, things may change later, there is a plan to more to separate 
>> global/local address ranges. Likely things like code will remain in 
>> the shared range, and program data will be in the local range.
>>
> Thinking of having a CPU local address space in Q+ to store vars for 
> that particular CPU. It looks like only a small RAM is required. I guess 
> it would be hardware thread local storage. May place the RAM in the CPU 
> itself.
> 

I am aware of at least a few CPU's that have banked register sets that 
may be backed to memory addresses (with the CPU itself evicting 
registers on context switch).

I have not done so.

I had considered the possibility of 4 rings each with their own set of 
registers. This could make things like interrupts and system calls 
cheaper, but (ironically) using this would make context switching more 
expensive.

An intermediate option could be a special RAM area for a "task cache", 
say, 8 or 16K, and then have a "Task Cache Miss" interrupt for cases 
where one tries to switch to a task's register bank that isn't in the 
cache. While a this would have a high cost (for a task cache miss), if 
the cache is bigger than the number of currently running tasks, it could 
still work out ahead.

But, better for performance would be if the task-cache were RAM backed 
and the HW spills and reloads from RAM (then, one could have maybe 64K 
or 256K or more for task register banks; probably enough for a decent 
number of active PIDs).



Though naive, "always save and restore all the registers to RAM" seems 
to have a fairly reasonable cost (and the among the lowest "actual 
task-switch cost", aside from the possibility of "let hardware lazily 
spill and reload register banks from main RAM", which could potentially 
be lower).


The main "bad" cost of switching between processes being the storm of 
TLB misses that would happen if not using a shared address space 
(granted, there are "global pages"). In my design, there are not true 
global pages, rather pages that are "global" within an ASID group (if 
the low 10 bits of the page's ASID are 0, it is assumed global within 
this group, whereas non-zero values are ASID specific; and the high 6 
bits of the ASID gives the group, where pages are not global between 
groups).

Though, my existing OS, still being single address space, doesn't make 
use of this. The idea is that ASID will be tied to PID.

As how to best scale this past 1024 PIDs is unclear, likely the ASID 
will be modulo-1024, and needing to reassign a previously assigned ASID 
to a new PID would require a TLB flush.


>>>
>>>          Stefan
>>
> 

[toc] | [prev] | [next] | [standalone]


#111433

Frommitchalsup@aol.com (MitchAlsup1)
Date2025-04-04 21:13 +0000
Message-ID<6a77fabdb64f59e4497ef3353d747441@www.novabbs.org>
In reply to#111428
On Fri, 4 Apr 2025 3:49:31 +0000, Robert Finch wrote:

> On 2025-04-03 1:22 p.m., BGB wrote:
-------------------
>>
>> Or, to allow for NOMMU operation, or reduce costs by not having context
>> switches result in as large of numbers of TLB misses.
>>
>> Also makes the kernel simpler as it doesn't need to deal with each
>> process having its own address space.
>
> Have you seen the MPRV bit in RISCV? Allows memory ops to execute using
> the previous mode / address space. The bit just has to be set, then do
> the memory op, then reset the bit. Makes it easy to access data using
> the process address space.

Let us postulate you are running in RISC-V HyperVisor on core[j]
and you want to write into GuestOS VAS and into application VAS
more or less simultaneously.

Seems to me like you need a MPRV to be more than a single bit
so it could index which layer of the SW stack's VAS it needs
to touch.

[toc] | [prev] | [next] | [standalone]


#111435

FromRobert Finch <robfi680@gmail.com>
Date2025-04-04 23:45 -0400
Message-ID<vsq91i$18k1q$1@dont-email.me>
In reply to#111433
On 2025-04-04 5:13 p.m., MitchAlsup1 wrote:
> On Fri, 4 Apr 2025 3:49:31 +0000, Robert Finch wrote:
> 
>> On 2025-04-03 1:22 p.m., BGB wrote:
> -------------------
>>>
>>> Or, to allow for NOMMU operation, or reduce costs by not having context
>>> switches result in as large of numbers of TLB misses.
>>>
>>> Also makes the kernel simpler as it doesn't need to deal with each
>>> process having its own address space.
>>
>> Have you seen the MPRV bit in RISCV? Allows memory ops to execute using
>> the previous mode / address space. The bit just has to be set, then do
>> the memory op, then reset the bit. Makes it easy to access data using
>> the process address space.
> 
> Let us postulate you are running in RISC-V HyperVisor on core[j]
> and you want to write into GuestOS VAS and into application VAS
> more or less simultaneously.
> 
Would not writing to the GuestOs VAS and the application VAS be the 
result of separate system calls? Or does the hypervisor take over for 
the GuestOS?

> Seems to me like you need a MPRV to be more than a single bit
> so it could index which layer of the SW stack's VAS it needs
> to touch.

So, there is a need to be able to go back two or three levels? I suppose 
it could also be done by manipulating the stack, although adding an 
extra bit may be easier. How often does it happen?

[toc] | [prev] | [next] | [standalone]


#111436

Frommitchalsup@aol.com (MitchAlsup1)
Date2025-04-05 16:37 +0000
Message-ID<760b3834d1202502f5f63e52b51cfdc8@www.novabbs.org>
In reply to#111435
On Sat, 5 Apr 2025 3:45:51 +0000, Robert Finch wrote:

> On 2025-04-04 5:13 p.m., MitchAlsup1 wrote:
>> On Fri, 4 Apr 2025 3:49:31 +0000, Robert Finch wrote:
>>
>>> On 2025-04-03 1:22 p.m., BGB wrote:
>> -------------------
>>>>
>>>> Or, to allow for NOMMU operation, or reduce costs by not having context
>>>> switches result in as large of numbers of TLB misses.
>>>>
>>>> Also makes the kernel simpler as it doesn't need to deal with each
>>>> process having its own address space.
>>>
>>> Have you seen the MPRV bit in RISCV? Allows memory ops to execute using
>>> the previous mode / address space. The bit just has to be set, then do
>>> the memory op, then reset the bit. Makes it easy to access data using
>>> the process address space.
>>
>> Let us postulate you are running in RISC-V HyperVisor on core[j]
>> and you want to write into GuestOS VAS and into application VAS
>> more or less simultaneously.
>>
> Would not writing to the GuestOs VAS and the application VAS be the
> result of separate system calls? Or does the hypervisor take over for
> the GuestOS?

Application has a 64-bit VAS
GusetOS has a 64-bit VAS
HyprVisor has a 64-bit VAS
and so does
Securte has a 64-bit VAS

So, we are in HV and we need to write to guestOS and to Application
but we have only 1-bit of distinction.

And this has nothing to do with system calls it has to do with
accessing (rather simultaneously) any of the 4 VASs.

>> Seems to me like you need a MPRV to be more than a single bit
>> so it could index which layer of the SW stack's VAS it needs
>> to touch.
>
> So, there is a need to be able to go back two or three levels? I suppose
> it could also be done by manipulating the stack, although adding an
> extra bit may be easier. How often does it happen?

I have no idea, and I suspect GuestOS people don't either.

[toc] | [prev] | [next] | [standalone]


#111437

Fromscott@slp53.sl.home (Scott Lurndal)
Date2025-04-05 18:31 +0000
Message-ID<kGeIP.467285$d51.395138@fx46.iad>
In reply to#111436
mitchalsup@aol.com (MitchAlsup1) writes:
>On Sat, 5 Apr 2025 3:45:51 +0000, Robert Finch wrote:
>

>> Would not writing to the GuestOs VAS and the application VAS be the
>> result of separate system calls? Or does the hypervisor take over for
>> the GuestOS?
>
>Application has a 64-bit VAS
>GusetOS has a 64-bit VAS
>HyprVisor has a 64-bit VAS
>and so does
>Securte has a 64-bit VAS
>
>So, we are in HV and we need to write to guestOS and to Application
>but we have only 1-bit of distinction.

On ARM64, when the HV needs to write to guest user VA or guest PA,
the SMMU provides an interface the processor can use to translate
the guest VA or Guest PA to the corresponding system physical address.
Of course, there is a race if the guest OS changes the underlying
translation tables during the upcall to the hypervisor or secure
monitor, although that would be a bug in the guest were it so to do,
since the guest explicitly requested the action from the higher
privilege level (e.g. HV).

Arm does have a set of load/store "user" instructions that translate
addresses using the unprivileged (application) translation tables.  There's
also a processor state bit (UAO - User Access Override) that can
be set to force those instructions to use the permissions associated
with the current processor privilege level.

Note that there is a push by all vendors to include support
for guest 'privacy', such that the hypervisor has no direct
access to memory owned by the guest, or where the the guest
memory is encrypted using a key the hypervisor or secure monitor
don't have access to.

[toc] | [prev] | [next] | [standalone]


#111438

FromRobert Finch <robfi680@gmail.com>
Date2025-04-05 17:57 -0400
Message-ID<vss913$3b1ga$1@dont-email.me>
In reply to#111437
On 2025-04-05 2:31 p.m., Scott Lurndal wrote:
> mitchalsup@aol.com (MitchAlsup1) writes:
>> On Sat, 5 Apr 2025 3:45:51 +0000, Robert Finch wrote:
>>
> 
>>> Would not writing to the GuestOs VAS and the application VAS be the
>>> result of separate system calls? Or does the hypervisor take over for
>>> the GuestOS?
>>
>> Application has a 64-bit VAS
>> GusetOS has a 64-bit VAS
>> HyprVisor has a 64-bit VAS
>> and so does
>> Securte has a 64-bit VAS
>>
>> So, we are in HV and we need to write to guestOS and to Application
>> but we have only 1-bit of distinction.
> 
> On ARM64, when the HV needs to write to guest user VA or guest PA,
> the SMMU provides an interface the processor can use to translate
> the guest VA or Guest PA to the corresponding system physical address.
> Of course, there is a race if the guest OS changes the underlying
> translation tables during the upcall to the hypervisor or secure
> monitor, although that would be a bug in the guest were it so to do,
> since the guest explicitly requested the action from the higher
> privilege level (e.g. HV).
> 
> Arm does have a set of load/store "user" instructions that translate
> addresses using the unprivileged (application) translation tables.  There's
> also a processor state bit (UAO - User Access Override) that can
> be set to force those instructions to use the permissions associated
> with the current processor privilege level.
> 
> Note that there is a push by all vendors to include support
> for guest 'privacy', such that the hypervisor has no direct
> access to memory owned by the guest, or where the the guest
> memory is encrypted using a key the hypervisor or secure monitor
> don't have access to.
> 
Okay,

I was interpreting RISCV specs wrong. They have three bits dedicated to 
this. 1 is an on/off and the other two are the mode to use. I am left 
wondering how it is determined which mode to use. If the hypervisor is 
passed a pointer to a VAS variable in a register, how does it know that 
the pointer is for the supervisor or the user/app? It's why I assumed it 
found the mode from the stack. Those two select bits have to set 
somehow. It seems like extra code to access the right address space.
I got the thought to use the three bits a bit differently.
111 = use current mode
110 = use mode from stack
100 = debug? mode
011 = secure (machine) mode
010 = hypervisor mode
001 = supervisor mode
000 = user/app mode
I was just using inline code to select the proper address space. But if 
it is necessary to dig around to figure the mode, it may turn into a 
subroutine call.


[toc] | [prev] | [next] | [standalone]


#111440

Frommitchalsup@aol.com (MitchAlsup1)
Date2025-04-05 23:11 +0000
Message-ID<7ea7be2799c9dac8cef1c4b9c33922b7@www.novabbs.org>
In reply to#111438
On Sat, 5 Apr 2025 21:57:50 +0000, Robert Finch wrote:

> On 2025-04-05 2:31 p.m., Scott Lurndal wrote:
>> mitchalsup@aol.com (MitchAlsup1) writes:
>>> On Sat, 5 Apr 2025 3:45:51 +0000, Robert Finch wrote:
>>>
>>
>>>> Would not writing to the GuestOs VAS and the application VAS be the
>>>> result of separate system calls? Or does the hypervisor take over for
>>>> the GuestOS?
>>>
>>> Application has a 64-bit VAS
>>> GusetOS has a 64-bit VAS
>>> HyprVisor has a 64-bit VAS
>>> and so does
>>> Securte has a 64-bit VAS
>>>
>>> So, we are in HV and we need to write to guestOS and to Application
>>> but we have only 1-bit of distinction.
>>
>> On ARM64, when the HV needs to write to guest user VA or guest PA,
>> the SMMU provides an interface the processor can use to translate
>> the guest VA or Guest PA to the corresponding system physical address.
>> Of course, there is a race if the guest OS changes the underlying
>> translation tables during the upcall to the hypervisor or secure
>> monitor, although that would be a bug in the guest were it so to do,
>> since the guest explicitly requested the action from the higher
>> privilege level (e.g. HV).
>>
>> Arm does have a set of load/store "user" instructions that translate
>> addresses using the unprivileged (application) translation tables.
>> There's
>> also a processor state bit (UAO - User Access Override) that can
>> be set to force those instructions to use the permissions associated
>> with the current processor privilege level.
>>
>> Note that there is a push by all vendors to include support
>> for guest 'privacy', such that the hypervisor has no direct
>> access to memory owned by the guest, or where the the guest
>> memory is encrypted using a key the hypervisor or secure monitor
>> don't have access to.
>>
> Okay,
>
> I was interpreting RISCV specs wrong. They have three bits dedicated to
> this. 1 is an on/off and the other two are the mode to use. I am left
> wondering how it is determined which mode to use. If the hypervisor is
> passed a pointer to a VAS variable in a register, how does it know that
> the pointer is for the supervisor or the user/app?

More interesting the the concept that there are multiple HVs that
have been virtualized--in this case the sender of the address may
think it has HV privilege but is currently operating as if it only
has GuestOS privilege. ...

>                                                    It's why I assumed it
> found the mode from the stack. Those two select bits have to set
> somehow. It seems like extra code to access the right address space.
> I got the thought to use the three bits a bit differently.
> 111 = use current mode
> 110 = use mode from stack
> 100 = debug? mode
> 011 = secure (machine) mode
> 010 = hypervisor mode
> 001 = supervisor mode
> 000 = user/app mode
> I was just using inline code to select the proper address space. But if
> it is necessary to dig around to figure the mode, it may turn into a
> subroutine call.

All the machines I have used/designed/programmed in the past use 000
as highest privilege and 111 as lowest.

[toc] | [prev] | [next] | [standalone]


#111441

Fromscott@slp53.sl.home (Scott Lurndal)
Date2025-04-06 14:21 +0000
Message-ID<G5wIP.1525956$eNx6.852360@fx14.iad>
In reply to#111438
Robert Finch <robfi680@gmail.com> writes:
>On 2025-04-05 2:31 p.m., Scott Lurndal wrote:
>> mitchalsup@aol.com (MitchAlsup1) writes:
>>> On Sat, 5 Apr 2025 3:45:51 +0000, Robert Finch wrote:
>>>
>> 
>>>> Would not writing to the GuestOs VAS and the application VAS be the
>>>> result of separate system calls? Or does the hypervisor take over for
>>>> the GuestOS?
>>>
>>> Application has a 64-bit VAS
>>> GusetOS has a 64-bit VAS
>>> HyprVisor has a 64-bit VAS
>>> and so does
>>> Securte has a 64-bit VAS
>>>
>>> So, we are in HV and we need to write to guestOS and to Application
>>> but we have only 1-bit of distinction.
>> 
>> On ARM64, when the HV needs to write to guest user VA or guest PA,
>> the SMMU provides an interface the processor can use to translate
>> the guest VA or Guest PA to the corresponding system physical address.
>> Of course, there is a race if the guest OS changes the underlying
>> translation tables during the upcall to the hypervisor or secure
>> monitor, although that would be a bug in the guest were it so to do,
>> since the guest explicitly requested the action from the higher
>> privilege level (e.g. HV).
>> 
>> Arm does have a set of load/store "user" instructions that translate
>> addresses using the unprivileged (application) translation tables.  There's
>> also a processor state bit (UAO - User Access Override) that can
>> be set to force those instructions to use the permissions associated
>> with the current processor privilege level.
>> 
>> Note that there is a push by all vendors to include support
>> for guest 'privacy', such that the hypervisor has no direct
>> access to memory owned by the guest, or where the the guest
>> memory is encrypted using a key the hypervisor or secure monitor
>> don't have access to.
>> 
>Okay,
>
>I was interpreting RISCV specs wrong. They have three bits dedicated to 
>this. 1 is an on/off and the other two are the mode to use. I am left 
>wondering how it is determined which mode to use. If the hypervisor is 
>passed a pointer to a VAS variable in a register, how does it know that 
>the pointer is for the supervisor or the user/app?

When the exception (in this case an upcall to a more privileged
regime) occurs, the saved state register/stack word should contain the prior
privilege level.   The hypervisor will know from that whether
the upcall was from the guest OS or a guest Application.

Note that on ARM, there are restrictions on upcalls to
more privileged regimes - generally a particular regime
can only upcall the next higher privileged regime, so
the user app can only upcall the GuestOS,  the guest OS can only
upcall the HV and the HV is the only regime that can
upcall the secure monitor.

> It's why I assumed it 
>found the mode from the stack. Those two select bits have to set 
>somehow. It seems like extra code to access the right address space.'

I haven't spent much time with RISC-V, but surely the processor
has a state register that stores the current mode, and which
must be preserved over exceptions/upcalls, which would require
that they be recorded in an exception syndrome register for
restoration when the upcall returns.

[toc] | [prev] | [next] | [standalone]


#111443

FromRobert Finch <robfi680@gmail.com>
Date2025-04-06 15:01 -0400
Message-ID<vsuj2d$1lvvs$1@dont-email.me>
In reply to#111441
On 2025-04-06 10:21 a.m., Scott Lurndal wrote:
> Robert Finch <robfi680@gmail.com> writes:
>> On 2025-04-05 2:31 p.m., Scott Lurndal wrote:
>>> mitchalsup@aol.com (MitchAlsup1) writes:
>>>> On Sat, 5 Apr 2025 3:45:51 +0000, Robert Finch wrote:
>>>>
>>>
>>>>> Would not writing to the GuestOs VAS and the application VAS be the
>>>>> result of separate system calls? Or does the hypervisor take over for
>>>>> the GuestOS?
>>>>
>>>> Application has a 64-bit VAS
>>>> GusetOS has a 64-bit VAS
>>>> HyprVisor has a 64-bit VAS
>>>> and so does
>>>> Securte has a 64-bit VAS
>>>>
>>>> So, we are in HV and we need to write to guestOS and to Application
>>>> but we have only 1-bit of distinction.
>>>
>>> On ARM64, when the HV needs to write to guest user VA or guest PA,
>>> the SMMU provides an interface the processor can use to translate
>>> the guest VA or Guest PA to the corresponding system physical address.
>>> Of course, there is a race if the guest OS changes the underlying
>>> translation tables during the upcall to the hypervisor or secure
>>> monitor, although that would be a bug in the guest were it so to do,
>>> since the guest explicitly requested the action from the higher
>>> privilege level (e.g. HV).
>>>
>>> Arm does have a set of load/store "user" instructions that translate
>>> addresses using the unprivileged (application) translation tables.  There's
>>> also a processor state bit (UAO - User Access Override) that can
>>> be set to force those instructions to use the permissions associated
>>> with the current processor privilege level.
>>>
>>> Note that there is a push by all vendors to include support
>>> for guest 'privacy', such that the hypervisor has no direct
>>> access to memory owned by the guest, or where the the guest
>>> memory is encrypted using a key the hypervisor or secure monitor
>>> don't have access to.
>>>
>> Okay,
>>
>> I was interpreting RISCV specs wrong. They have three bits dedicated to
>> this. 1 is an on/off and the other two are the mode to use. I am left
>> wondering how it is determined which mode to use. If the hypervisor is
>> passed a pointer to a VAS variable in a register, how does it know that
>> the pointer is for the supervisor or the user/app?
> 
> When the exception (in this case an upcall to a more privileged
> regime) occurs, the saved state register/stack word should contain the prior
> privilege level.   The hypervisor will know from that whether
> the upcall was from the guest OS or a guest Application.
> 
Yes, Q+ works that way, I think RISCV does as well. Q+ stacks the PC and 
SR on an internal stack which is basically a shift register. The TOS is 
visible as a CR. The mode is state saved in the SR. Interrupts and 
exceptions do not have to store the state in memory. The far end of the 
stack is hard coded to do a reset if the stack underflows.

> Note that on ARM, there are restrictions on upcalls to
> more privileged regimes - generally a particular regime
> can only upcall the next higher privileged regime, so
> the user app can only upcall the GuestOS,  the guest OS can only
> upcall the HV and the HV is the only regime that can
> upcall the secure monitor.
> 
Allows two directional virtualization I think. Q+ has all exceptions and 
interrupts going to the secure monitor, which can then delegate it back 
to a lower level.

>> It's why I assumed it
>> found the mode from the stack. Those two select bits have to set
>> somehow. It seems like extra code to access the right address space.'
> 
> I haven't spent much time with RISC-V, but surely the processor
> has a state register that stores the current mode, and which
> must be preserved over exceptions/upcalls, which would require
> that they be recorded in an exception syndrome register for
> restoration when the upcall returns.
> 

[toc] | [prev] | [next] | [standalone]


#111445

Fromscott@slp53.sl.home (Scott Lurndal)
Date2025-04-07 14:04 +0000
Message-ID<VXQIP.1475757$SZca.567496@fx13.iad>
In reply to#111443
Robert Finch <robfi680@gmail.com> writes:
>On 2025-04-06 10:21 a.m., Scott Lurndal wrote:

>> Note that on ARM, there are restrictions on upcalls to
>> more privileged regimes - generally a particular regime
>> can only upcall the next higher privileged regime, so
>> the user app can only upcall the GuestOS,  the guest OS can only
>> upcall the HV and the HV is the only regime that can
>> upcall the secure monitor.
>> 
>Allows two directional virtualization I think. Q+ has all exceptions and 
>interrupts going to the secure monitor, which can then delegate it back 
>to a lower level.

If that adds latency to the interrupt handler, that will not
be a positive benefit.

[toc] | [prev] | [next] | [standalone]


#111439

Frommitchalsup@aol.com (MitchAlsup1)
Date2025-04-05 23:06 +0000
Message-ID<ee644124d3b2562986842766af421577@www.novabbs.org>
In reply to#111437
On Sat, 5 Apr 2025 18:31:44 +0000, Scott Lurndal wrote:

> mitchalsup@aol.com (MitchAlsup1) writes:
>>On Sat, 5 Apr 2025 3:45:51 +0000, Robert Finch wrote:
>>
>
>>> Would not writing to the GuestOs VAS and the application VAS be the
>>> result of separate system calls? Or does the hypervisor take over for
>>> the GuestOS?
>>
>>Application has a 64-bit VAS
>>GusetOS has a 64-bit VAS
>>HyprVisor has a 64-bit VAS
>>and so does
>>Securte has a 64-bit VAS
>>
>>So, we are in HV and we need to write to guestOS and to Application
>>but we have only 1-bit of distinction.
>
> On ARM64, when the HV needs to write to guest user VA or guest PA,
> the SMMU provides an interface the processor can use to translate
> the guest VA or Guest PA to the corresponding system physical address.
> Of course, there is a race if the guest OS changes the underlying
> translation tables during the upcall to the hypervisor or secure
> monitor, although that would be a bug in the guest were it so to do,
> since the guest explicitly requested the action from the higher
> privilege level (e.g. HV).
>
> Arm does have a set of load/store "user" instructions that translate
> addresses using the unprivileged (application) translation tables.

When Secure Monitor executes a "user" instructions which layer
of the SW stack is accessed:: {HV, SV, User} ??

Is this 1-layer down the stack, or all layers down the stack ??

> There's
> also a processor state bit (UAO - User Access Override) that can
> be set to force those instructions to use the permissions associated
> with the current processor privilege level.

That is how My 66000 MMU is defined--higher privilege layers
have R/W access to the next lower privilege layer--without
doing anything other than a typical LD or ST instruction.

I/O MMU has similar issues to solve in that a device can Read
write-execute only memory and write read-execute only memory.

> Note that there is a push by all vendors to include support
> for guest 'privacy', such that the hypervisor has no direct
> access to memory owned by the guest, or where the the guest
> memory is encrypted using a key the hypervisor or secure monitor
> don't have access to.

I call these "paranoid" applications--generally requiring no
privilege, but they don't want GuestOS of HyperVisor to look
at their data and at the same time, they want GuestOS or HV
to perform I/O to said data--so some devices have a effective
privilege above that of the driver commanding them.

I understand the reasons and rational.

[toc] | [prev] | [next] | [standalone]


#111442

Fromscott@slp53.sl.home (Scott Lurndal)
Date2025-04-06 14:32 +0000
Message-ID<fgwIP.1525957$eNx6.1219389@fx14.iad>
In reply to#111439
mitchalsup@aol.com (MitchAlsup1) writes:
>On Sat, 5 Apr 2025 18:31:44 +0000, Scott Lurndal wrote:
>

>> Arm does have a set of load/store "user" instructions that translate
>> addresses using the unprivileged (application) translation tables.
>
>When Secure Monitor executes a "user" instructions which layer
>of the SW stack is accessed:: {HV, SV, User} ?

The Secure Monitor will never execute a user instruction.  If
it does, it will act as any other load/store executed by the
secure monitor.

The "user" instructions are only used by a bare-metal OS
or a guest OS to access user application address spaces.

>
>Is this 1-layer down the stack, or all layers down the stack ??

One layer down, and only the least privileged non-user level.

>
>> There's
>> also a processor state bit (UAO - User Access Override) that can
>> be set to force those instructions to use the permissions associated
>> with the current processor privilege level.
>
>That is how My 66000 MMU is defined--higher privilege layers
>have R/W access to the next lower privilege layer--without
>doing anything other than a typical LD or ST instruction.

That presumes a shared address space between the privilege
levels - which is common for the OS and user-modes.   It's
not common (or particularly useful[*]) at any other privilege level.

[*] A primary goal must be to avoid privilege level
    upcalls as much as possible.


>
>I/O MMU has similar issues to solve in that a device can Read
>write-execute only memory and write read-execute only memory.

By the time the IOMMU translates the inbound address, it is
a physical machine address, so I don't see any issue here.
And in the ARM case, the IOMMU translation tables are identical
to the processor translation tables in format and can actually
share some or all of the tables between the core(s) and the IOMMU.

Note that for various reasons, the IOMMU translation tables
may cover only a portion of the target address space at any particular
privilege level.

>
>> Note that there is a push by all vendors to include support
>> for guest 'privacy', such that the hypervisor has no direct
>> access to memory owned by the guest, or where the the guest
>> memory is encrypted using a key the hypervisor or secure monitor
>> don't have access to.
>
>I call these "paranoid" applications--generally requiring no
>privilege, but they don't want GuestOS of HyperVisor to look
>at their data and at the same time, they want GuestOS or HV
>to perform I/O to said data--so some devices have a effective
>privilege above that of the driver commanding them.
>
>I understand the reasons and rational.

The primary reason is for encrypted video decoding where
the decoded video is fed directly to the graphics processor
and the end-user cannot intercept the decrypted video stream.  Closing
the barn door after the horse has left, but c'est la vie.

[toc] | [prev] | [next] | [standalone]


Page 2 of 4 — ← Prev page 1 [2] 3 4  Next page →

Back to top | Article view | comp.arch


csiph-web